[filesystem] Relative Draft Proposal RFC
There have been requests for a Filesystem library relative function for at least ten years. The requested functionality seems simple - given two paths with a common prefix, return the non-common suffix portion of one of the paths such that it is relative to the other path. In terms of the Filesystem library, path p("/a/b/c"); path base("/a/b"); path rel = relative(p, base); // the requested function cout << rel << endl; // outputs "c" assert(absolute(rel, base) == p); If that was all there was to it, the Filesystem library would have had a relative function years ago. Critical issues: Clashing requirements, symlinks, directory placeholders (dot, dot-dot), user-expectations, corner cases. A paper by Jamie Allsop, Additions to Filesystem supporting Relative Paths, is what broke my mental logjam. Much of [my proposal] is based directly on Jamie's analysis and proposal. The weakly_canonical function and aspects of the semantic specifications are my contributions. Mistakes, of course, are mine. The full proposal is at http://boostorg.github.io/filesystem/relative_proposal.html A preliminary implementation is available in the feature/relative2 branch of the Boost Filesystem Git repository. See github.com/boostorg/filesystem/tree/feature/relative2 The overall plan is to get feedback from boost developers, then merge to develop for boost 1.60, then propose to the C++ committee for addition to the Filesystem TS. Comments welcome. If you are one of the many people who have requested "relative" functionality, does this proposal meet your needs? If not, why? Thanks, --Beman
On 20/08/2015 02:55, Beman Dawes wrote:
The full proposal is at http://boostorg.github.io/filesystem/relative_proposal.html
A preliminary implementation is available in the feature/relative2 branch of the Boost Filesystem Git repository. See github.com/boostorg/filesystem/tree/feature/relative2 http://github.com/boostorg/filesystem/tree/feature/relative2
The overall plan is to get feedback from boost developers, then merge to develop for boost 1.60, then propose to the C++ committee for addition to the Filesystem TS.
Comments welcome. If you are one of the many people who have requested "relative" functionality, does this proposal meet your needs? If not, why?
Looks good so far. (I've only looked at the proposal document, not the code.) There's a few things that strike me as curious (I'm sure there are reasons for them though): 1. Why is the normal form for "/some/path/" equal to "/some/path/." instead of "/some/path"? Doesn't that violate the "no redundant current directory elements" rule? (I assume it's related to the root path being weird, but maybe it would be better to make the root path an exception rather than cluttering the general case?) 2. For relative(path), it appears to be unspecified (at least in the example assertions) what happens when unrelated paths are used. I would expect the following: path("/a/b/c").relative("/d/e/f") == path("../../../a/b/c") path("/a/b/c").relative("d/e/f") == path() or exception path("a/b/c").relative("/d/e/f") == path() or exception path("a/b/c").relative("d/e/f") == path() or exception (Arguably the second might not be an error -- provided the first path is absolute [which isn't true for the above on Windows] then it could return the first path without modification; this would still technically be a valid path but it wouldn't be a relative one, which is why I think an error is more appropriate.) 3. "Throws: As specified in Error reporting." I assume this refers to some other document, as it does not appear to refer to anything in this one. Also it seems odd that this clause is omitted on the earlier functions.
Gavin Lambert
On 20/08/2015 02:55, Beman Dawes wrote:
The full proposal is at http://boostorg.github.io/filesystem/relative_proposal.html ... Looks good so far. (I've only looked at the proposal document, not the code.)
There's a few things that strike me as curious (I'm sure there are reasons for them though):
1. Why is the normal form for "/some/path/" equal to "/some/path/." instead of "/some/path"? Doesn't that violate the "no redundant current directory elements" rule? (I assume it's related to the root path being weird, but maybe it would be better to make the root path an exception rather than cluttering the general case?)
In theory, the filesystem library has to work for operating systems other than POSIX and Windows, and some legacy system use different syntax for directories vs files. So a trailing "/" is significant on such systems because it signifies a path to a directory rather than a path to a file. Since iteration doesn't return the directory separator, a trailing "." gets added to signify a directory. In practice, all operating systems now supply a way to work with POSIX format paths. So I guess some of the rules could be simplified. I'll give that some thought.
2. For relative(path), it appears to be unspecified (at least in the example assertions) what happens when unrelated paths are used. I would expect the following: path("/a/b/c").relative("/d/e/f") == path("../../../a/b/c")
That's correct.
path("/a/b/c").relative("d/e/f") == path() or exception path("a/b/c").relative("/d/e/f") == path() or exception path("a/b/c").relative("d/e/f") == path() or exception
They are all unrelated, so return path().
(Arguably the second might not be an error -- provided the first path is absolute [which isn't true for the above on Windows] then it could return the first path without modification; this would still technically be a valid path but it wouldn't be a relative one, which is why I think an error is more appropriate.)
These are all lexically relative, so do not throw (except if out of memory).
3. "Throws: As specified in Error reporting." I assume this refers to some other document, as it does not appear to refer to anything in this one. Also it seems odd that this clause is omitted on the earlier functions.
Yes, that refers to another section of the doc this proposal is updating. That sentence is typically present for operational functions that may run into I/O and other errors when they access the actual file system, but not for functions that do not access the actual file system. Thanks, --Beman
On 19/08/15 15:55, Beman Dawes wrote:
A paper by Jamie Allsop, Additions to Filesystem supporting Relative Paths, is what broke my mental logjam. Much of [my proposal] is based directly on Jamie's analysis and proposal. The weakly_canonical function
My earlier post missed that this was on the users list also. Here is the missing link to the original paper: https://github.com/ja11sop/std-filesystem-relative/blob/master/papers/D0011.... and here: https://github.com/ja11sop/std-filesystem-relative Jamie
and aspects of the semantic specifications are my contributions. Mistakes, of course, are mine.
That would be cool. Our use: we develop a data acquisition application, which stores its per project data in a directory. We would like to keep everything under that directory relative to that directory, so that users just can copy that project directory and all still works. So we have mild requirements already full filled by the first line of the draft. For me it wouldn't be a problem if many corner cases can't be covered. If they are documented it's already ok, because I think that the main use case would be sufficient for most users.
On 22 Aug 2015 at 7:09, gast128 wrote:
That would be cool. Our use: we develop a data acquisition application, which stores its per project data in a directory. We would like to keep everything under that directory relative to that directory, so that users just can copy that project directory and all still works. So we have mild requirements already full filled by the first line of the draft. For me it wouldn't be a problem if many corner cases can't be covered. If they are documented it's already ok, because I think that the main use case would be sufficient for most users.
You may be interested that proposed Boost.AFIO (review starting any time now) allows users to arbitrarily rename a directory containing open files while the program is running. This an alternative way of solving relative paths: start by opening a handle to the file or directory you wish to use as a base for all further relative path operations. This method has the advantage of being invariant to filesystem changes, but obviously is rather more expensive than simple string manipulation. Niall -- ned Productions Limited Consulting http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/
Ok thx, I will have a look at it. Atm the number of Boost libraries grows harder than I can keep track of. (snipped previous message due to gmane's message: "There's much more quoted text in your article than new. Prune quoted stuff.")
The current version of the Boost proposal is at http://boostorg.github.io/ filesystem/relative_proposal.html Changes include: * Changed the lexical functions from member to non-member, and prefixed names with "lexically_" to disambiguate. For rationale, see http://boostorg.github.io/filesystem/relative_proposal.html#Add-lexical-func... * Added the proximate functions as described in Jamie Allsop's http://github.com/ja11sop/std-filesystem-relative/blob/master/papers/D0011.m... * Cleaned up weakly_canonical standardese. As far as the C++ File System TS is concerned, Jamie and I are in discussions about combining our efforts into a single proposal. I'll give it another day or so to see if any more comments come in, then plan to merge feature/relative2 to develop. --Beman
participants (5)
-
Beman Dawes
-
gast128
-
Gavin Lambert
-
Jamie Allsop
-
Niall Douglas