-
Notifications
You must be signed in to change notification settings - Fork 368
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
Fully revertible environment updates #5417
Conversation
a5b6e1c
to
1a7657e
Compare
Yes !! Finally \o/ This is a long-time need and looks awesome. Two remarks:
|
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.
Thanks! All good on the idea.
Just some code comments, and a more general one: it's better to use OpamFilneame;
and OpamSystem
instead of Filename
and Unix
directly from the client.
09284a1
to
44f49a4
Compare
44f49a4
to
830a311
Compare
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.
These two lines don't seem to be needed anymore (their use was reverted in the last commit)
The tests on Windows fail with:
|
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.
I reworked it, so i can't review anymore
Previously, OPAM_SWITCH_PREFIX provides a best-effort for reverting the environment variable updates made by opam. This works for most cases, but it relies on switches having a consistent `setenv` fields and on packages not using `setenv` fields as otherwise updates will be lost. For example, if package `foo.1` includes `setenv: [FOO = "bar"]` then `opam install foo.1` will cause `FOO = "bar"` to be added to `environment`. However, `opam remove foo.1` then removes this line, meaning that the next `opam env` will not revert `FOO=bar` from the environment, since the `environment` file no longer contains the update. An additional variable is now introduced, and used in `opam env` and `opam exec`. The precise list of environment updates are stored in a file in `/tmp/opam-last-env/` and the precise location of the file is stored in `OPAM_LAST_ENV`. On Unix, these files should be automatically reaped at reboot; on Windows, files older than the system uptime are automatically pruned. When finding the list of updates which need to be reverted, opam first checks to see if `OPAM_LAST_ENV` points to a parseable file, falling back to the existing `OPAM_SWITCH_PREFIX` mechanism, if required. Hashing is used both to ensure that terminals with different active switches do not interfere with other and also to share the environment files between identical sessions. With this mechanism, `opam env --revert` always succeeds and packages are free to use `setenv`.
OPAM_LAST_ENV means that it's no longer necessary to limit setenv to compiler packages.
Thanks! |
This PR builds on the solution to #3411 in #3413. There are two bug-fixes in this PR, but as they operate on the same code, I've submitted them as one.
The first - which is the original problem in #3411 - is what happens when you rename a local switch. At present, this behaviour is seen:
PATH
should begin/tmp/foo/_opam/bin:
. If rename the switch:PATH
still begins/tmp/foo/_opam/bin:
instead of/tmp/bar/_opam/bin
. The issue here is two-fold:environment
file needs regeneratingopam env --readonly
The fix in #3413 ensured that
OPAM_SWITCH_PREFIX
is always correct, as this allows the environment updates to be correctly reverted. At that time, further fixes were somewhat academic, as the moving a local switch of course breaks OCaml. With - hopefully - relocatable OCaml around the corner, moving local switches is a less academic problem, and so the first commits in this PR address this issue. The first commit is an alteration so that theenvironment
instead of being written with a lock can be written atomically without a lock.The next commit removes the
--readonly
flag from the env_hooks. The problem at present is that regenerating theenvironment
file can take a noticeable amount of time, which can cause delays returning the prompt. It seems to be much better to trust that the only changeopam env
can ever make is to theenvironment
file, and allow the hooks to update it if necessary.Armed with those changes, the third commit then causes the
environment
file to be regenerated if it has been moved. This is trivially detected by ensuring thatOPAM_SWITCH_PREFIX
in theenvironment
file is correct.Finally,
opam exec
had inconsistent behaviour w.r.t.opam env
, and the next commit unifies the behaviour ofopam env
andopam exec
when theenvironment
file is missing or needs regenerating.The next commit addresses a shortcoming of
setenv
that so far has been brushed away with lint warning 56. If one creates a packagefoo.1
withsetenv: FOO = "bar"
and then:then
bar
will be displayed (andopam install
will saveFOO=bar
to theenvironment
file). If one now issues:then opam will still display
FOO=bar
. The reason for this is thatopam remove
dutifully updates theenvironment
file and removes theFOO=bar
update from it.opam env
must first revert existing environment changes, which it does by locating theenvironment
file viaOPAM_SWITCH_PREFIX
. This of course now says nothing aboutFOO
and soFOO
is - incorrectly - left alone.For this reason, warning 56 has discouraged the use of
setenv
outside packages flaggedcompiler
. This issue doesn't exist as long as the base environment variables defined by compiler packages are the same.The forthcoming Windows packages need to be put Visual Studio configuration into the switch settings via environment variables, which is where this arose from. If the Visual Studio configuration package is uninstalled, then it leaves behind a considerable number of updates to the environment which should instead be reverted.
The same issue can arise without Windows if a switch is removed with other terminals open which had run
eval $(opam env)
for them - in this case,OPAM_SWITCH_PREFIX
points to a non-existent directory, which means that theenvironment
cannot be reverted.The fix I've implemented here is to add an additional environment variable to the environment
OPAM_LAST_ENV
and have this point to a file in/tmp
which contains the actual environment variables. If for whatever this can't be written, thenOPAM_LAST_ENV
is not set, and the existing mechanisms are used. We rely on the fact/tmp
is cleared out reboot to clean-up old files and use hashing both to allow sharing of the environment file caches and also co-existence of terminals with different switches set. Windows doesn't ever clear out its TEMP directory automatically, so some garbage collection code is added to clean up any files which are older than the system's uptime.Note that this paves the way for accurate reverting of
FOO = "bar"
, but I have not implemented that (yet). This could also be used to differentiate variables which should be unset vs empty.Test for
foo.1
package with asetenv
- reverts correctly onopam env
Writing to a directory in the opam root instead of
/tmp
(with hoovering done inopam clean
instead)queued on 5476