Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: os: convenience function for one-off Root operations #73168

Open
neild opened this issue Apr 4, 2025 · 1 comment
Open

proposal: os: convenience function for one-off Root operations #73168

neild opened this issue Apr 4, 2025 · 1 comment
Labels
LibraryProposal Issues describing a requested change to the Go standard library or x/ libraries, but not to a tool Proposal
Milestone

Comments

@neild
Copy link
Contributor

neild commented Apr 4, 2025

I propose adding the following function:

package os

// InRoot returns a Root that operates on the named directory.
//
// The directory is opened anew at the start of every operation on the Root.
// If the directory cannot be opened, the operation returns an error.
// The directory is closed after every operation. Calling Close on the Root does nothing.
//
// InRoot may be used for one-off operations rooted in a directory.
// For example:
//
//    // Remove name in dir.
//    err := os.InRoot(dir).Remove(name)
func InRoot(name string) *Root

os.Root (#67002) supports performing filesystem operations within the context of some directory.

Performing a single operation in a Root is substantially more verbose than doing so outside of one. Compare:

f, err := os.Create(filepath.Join(base, name))
root, err := os.OpenRoot(base)
if err != nil {
  return err
}
defer root.Close()
f, err := root.Create(name)

If the Root will be reused for many operations, the additional overhead of opening and closing it is not so significant. For a single operation, however, it's enough to be annoying.

We have an os.OpenInRoot convenience function for opening files, but this covers only one operation. We could add similar functions for other operations (os.CreateInRoot, os.RemoveInRoot, etc.), but that would be a lot of new functions.

This has come up in the context of #73126, which proposes adding Root.ReadFile and Root.WriteFile methods: #73126 (comment) asks if we can have top-level convenience functions as well, since opening and closing the root for short operations is inconvenient.

I've also had this raised in a Google-internal discussion: We have a linter which recommends using the github.com/google/safeopen package for certain operations (recommending, for example, that os.Create(filepath.Join(a, b)) could be safeopen.CreateBeneath(a, b)). We're reluctant to change the linter to recommend os.Root in cases where a one-liner becomes several lines opening and closing a Root.

The InRoot function allows performing operations in a root with slightly less verbosity than the non-rooted equivalent using filepath.Join. To continue the above example:

f, err := os.InRoot(base).Create(name)
@gopherbot gopherbot added this to the Proposal milestone Apr 4, 2025
@gabyhelp
Copy link

gabyhelp commented Apr 4, 2025

Related Documentation

(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)

@gabyhelp gabyhelp added the LibraryProposal Issues describing a requested change to the Go standard library or x/ libraries, but not to a tool label Apr 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
LibraryProposal Issues describing a requested change to the Go standard library or x/ libraries, but not to a tool Proposal
Projects
None yet
Development

No branches or pull requests

3 participants