-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Be more XDG-compliant when searching for init.ml
#12624
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
Conversation
MisterDA
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe Tag_cons can be used? Otherwise it's a nice to great support for xdg-dirs and a Windows equivalent.
|
Updated - I also hopefully pushed a fix to the symbol checker which should make AppVeyor pass 🏌️♂️ |
|
I went through all the code and everything semeed very reasonable to me but Regarding the new libraries that need to be linked with, I was wondering The comment in "On Unix, the computation of this list is more easily computed in OCaml" In |
Actually I took a look at this PR before it was submitted. But I intend to do a more formal review soon-ish. Thanks for the ping! |
|
Should we adopt that algorithm in dune's xdg library as well? |
|
Nicolás Ojeda Bär (2023/10/12 12:27 -0700):
Actually I took a look at this PR before it was submitted.
Oh I didn't know, sorry!
But I intend to do a more formal review soon-ish. Thanks for the ping!
A quite unintnetional ping though. Thanks a lot for your help on that
one!
And by the way: I find the explanations given in the PR description
about the ordeer in which directories are searched fo very high quality
and totally ready to be transferred in the manual as the associated task
suggests.
|
8fcd6cc to
4b0fb2a
Compare
Assuming it's approved, yes please 🙂 I think what Dune's doing right now is already a compatible subset of what's proposed here. |
a00b20e to
704bb47
Compare
I should have made that explicit in the comments that @nojb had a look at this branch before the PR was opened, but also that I didn't intend to merge it without his full review, too 🙂
Fixed
I've expressly split the two of them up - partly because the lists are different already and partly because there is no reason that they have to be the same.
It is indeed a frankenstein mix of two sentences - fixed, thanks!
I pushed an alternate form, and added an additional clarifying example of the strangeness of the Windows splitting requirements.
Thank you :) |
|
So is that to say that the same algorithm will be implemented in two
different places (the compiler and Dune)?
Wouldn't it be worht trying to find a way to make sure the algorithm is
shared, or do we want to have two versions of it because one may _want_
them to be different from each other?
|
|
David Allsopp (2023/10/13 08:06 -0700):
I should have made that explicit in the comments that @nojb had a look
at this branch before the PR was opened,
No problem! :)
but also that I didn't intend
to merge it without his full review, too 🙂
I had no worries at all of that kind.:)
> Regarding the new libraries that need to be linked with, I was wondering whether we could avoid repeating their names between the Mingw and MSVC cases. I think it's certainly possible to achieve this but it's probably not for this PR.
I've expressly split the two of them up - partly because the lists are
different already
Oh, I must have overlooked the differenes, sorry. To me the lists looked
similar, likely because my reading was too shallow.
and partly because there is no reason that they have to be the same.
OK got it.
> In `toplevel/toploop.mli`, regarding the documentation comment for `split_path`: I was wondering wether writing `PATH` rather than `path` wouldn't make it clearer that we talk about the content of a PATH-style environment variable, rather than just a file path. I do realise `PATH` is not a valid identifier, so perhaps my suggestion is to clarify the link with the PATH-style environment varialbe, no matter how this clarification occurs.
I pushed an alternate form, and added an additional clarifying example
of the strangeness of the Windows splitting requirements.
Thanks!
|
I think it's more that they're following the same convention/specification than algorithm - I'm not sure there's much actual code to share per se. |
nojb
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Documentation needs to be added though (manual & man pages).
| let[@tail_mod_cons] rec parse segment_begin terminator i = | ||
| if i >= len then | ||
| (* Done - return the last entry *) | ||
| [get_contents (add_segment segment_begin i)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to confirm: in the case of PATH=foo; we want the result of this function to be ["foo";""]? What are the semantics of "" in PATH, is it the current directory?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For XDG, it's moot - the first thing we do is filter the result for absolute paths (and Filename.is_relative "" = true, naturally). POSIX explicitly notes that an initial or final colon (or two consecutive colons) cause the current directory to be included in PATH, yes. On Windows, the CRT skips them, but that's an implementation detail - the interpretation of PATH is always that the current directory is searched first.
| On Windows, entries are separated by semicolons. Sections of entries may be | ||
| double-quoted (which allows semicolons in filenames to be quoted). The | ||
| double-quote characters are stripped (i.e. [f"o"o = foo]; also | ||
| [split_path "foo\";\";bar" = ["foo;"; "bar"]) *) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For my own curiosity, where is this quoting behaviour documented?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It turns out I'd forgotten where I learned it from, so having had to search both the Internet and my memory, I added a comment! Amusingly, the comment in getpath.cpp is very clearly from OS/2 (i.e. 1988 or 1989)! 😂
| let default = | ||
| if Sys.win32 then | ||
| match Lazy.force windows_xdg_defaults with | ||
| | dir::_ -> Some dir |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add a comment that the first entry corresponds to %LOCALAPPDATA%?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea - done!
704bb47 to
48cb37c
Compare
|
Thanks, @nojb! I've pushed a rebase addressing hopefully all the technical suggestions - I will shortly push the documentation updates. |
48cb37c to
09268f3
Compare
|
Updates to the manual and man-page now pushed. |
|
This looks good to go to me. cc @jonahbeckford: could you take a quick look at the specification in the PR description and confirm that it looks OK to you too? Thanks! |
|
Yes, the specification looks great. +1 |
|
@dra27 is this ready to merge from your side? |
|
All good to go, I think, yes - I even got to "learn" some troff 😈 |
|
Merged, thanks! |
This is a possible alternate implementation for extending the toplevel's use of XDG when searching for
init.mlfor better Windows support, originally outlined in #12364 (comment).The fundamental problem here arises from a Windows configuration subtlety added a while ago in Windows 2000. For Windows users, there are two kinds of user configuration - roaming (typically stored in
AppData\Roamingin a user's profile directory and intended to be synchronised between machines) and local (typically stored inAppData\Localin a user's profile directory and for that specific machine only). For the OCaml toplevel, it is not possible to define which one a user may want (indeed, it's quite plausible that a user might want to load configuration from both!).This PR seeks to solve the problem on Windows by adopting more of the XDG Base Directory Specification on all platforms, and then doing an appropriate translation of the XDG defaults for Windows. At present, the toplevel only inspects
$XDG_CONFIG_HOME, but XDG also provides$XDG_CONFIG_DIRS.For Unix, the toplevel now reads the first startup file of:
.ocamlinitin the current directory$XDG_CONFIG_HOME/ocaml/init.mlif$XDG_CONFIG_HOMEis an absolute path$HOME/.config/ocaml/init.mlonly if$XDG_CONFIG_HOMEis unset, empty or a non-absolute path and$HOMEis non-emptyocaml/init.mlunder any of the absolute paths in the:-separated list$XDG_CONFIG_DIRS/etc/xdg/ocaml/init.mlonly if$XDG_CONFIG_DIRSis unset, or contains no absolute paths$HOME/.ocamlinit, if$HOMEis non-emptyFor Windows, we use the XDG environment variables, but with the following tweaks:
$HOME/.config(case 3), we use the location of FOLDERID_LocalAppData returned by SHGetKnownFolderPath$XDG_CONFIG_DIRSas:-separated, we use the same rules as for splitting thePathenvironment variable on Windows (;-separated; double-quoted sub-strings treated as literals)/etc/xdg(case 5), we use the following three locations from SHGetKnownFolderPath:C:\Users\userid\AppData\LocalC:\Users\userid\AppData\RoamingC:\ProgramDataThere is a subtle tweak to the Windows default for
$XDG_CONFIG_DIRS(noted in the code as well), which is intended to cater for the not inconceivable scenario where a Windows user has$XDG_CONFIG_HOMEset in Cygwin (e.g. to/home/userid/.config) and then starts a native Windowsocaml.exe(which is likely not to find anything in\home\userid\.configon the current drive). The tweak is thatFOLDERID_LocalAppDatais both the default for$XDG_CONFIG_HOMEand also the first entry in the default for$XDG_CONFIG_DIRS.The hope is that what previously would have been Windows-specific workarounds are now merely platform-specific defaults for a cross-platform solution. Incidentally, various other libraries propose alternate defaults for macOS, but there seems to be even less agreement on what those should be than there is for Windows, so I've left grasping that nettle for another day by just leaving macOS treated as Unix.
For the OCaml toplevel, the first located
init.mlis the only one which matters (cf. last paragraph of XDG BDS); naturally, nothing prevents a user from configuring theirinit.mlfiles such thatinit.mlfrom further locations is loaded. In particular, for Windows users, that means that a user could choose to callToploop.use_silentlyfrom withininit.mlinAppData\Localto source theinit.mlinAppData\Roamingshould they so desire!Notes on the implementation:
"-quote rules. Although it's technically only necessary to double-quote semicolon characters (which are not common in directory names!), it's really quite commonplace to see spaces double-quoted.SHGetKnownFolderPathis a tricky function to wrap (theFOLDERID_values are bulky and numerous, so not really wanted in a static array, etc.). I elected for what I hope is a simpler approach with a C primitive that just returns an empty list on Unix and returns the three values needed on Windows. It's much less code, at the cost of a slightly odd-looking primitive. Pedantically, the Unix version of it could construct["/etc/xdg"]in C code 🤷♂Toploop.find_ocamlinitis very noisy - it's probably easiest just to re-review the entire function in terms of the specification above.TODO