devops-works / binenv

One binary to rule them all. Manage all those pesky binaries (kubectl, helm, terraform, ...) easily.
MIT License
366 stars 44 forks source link

Feature request: Freeze a distribution version globally #247

Open zatricky opened 4 months ago

zatricky commented 4 months ago

I've found that some packages are needed to be held back but there is no way to do a simple upgrade of all other packages without clobbering those packages into the too-new versions. To allow this, system package managers usually use some kind of version pinning. Some require you to edit a config file - but some use a command, such as apt's apt-mark hold <pkgname>.

I'm not sure what the best implementation plan would be - but I can at least think of two ways this might be done. This is also assuming there isn't already a way to do this that I haven't noticed from the documentation:

a) Extend the .binenv.lock functionality to search for a file in $HOME/.config/binenv/ as a fallback when a .binenv.lock file does not already exist in the current project folder. Then use the lock file functionality to pin versions when running the binenv upgrade command rather than only using it at runtime.

b) Make a separate option/parameter to record global version pins, much like the apt example above: binenv hold <pkg> <pkgversion>. This would save the pins in a meaningful location (such as $HOME/.config/binenv/). Upgrades would then keep the package on the "held back" version but, unlike suggestion a) above, it would ignore .binenv.lock files.

In both scenarios I would suggest a warning to remind the user their upgrade is keeping a "held back" version.

For some users, using the existing per-project freeze functionality would work - but in my case I have many projects that need to use the same version of a package. It is actually less of a burden on me to globally uninstall the package, run the upgrade, then reinstall the "correct" package version again every time I do updates.

leucos commented 4 months ago

hello @zatricky

Not sure I understand well, since package can already be "pinned" in .binenv.lock already when using the = specifier.

I guess you are aware that .binenv.lock files are search upwards until the home dir is reached.

For instance, assume a project is located in /home/zatricky/projects/work/fooproject, binenv will look for .lock files in:

However, note that the search stops when the first .binenv.lock is found.

Now, if you need a specific binary (let's call it "stickyone") to never be upgraded, may be the easiest way is to omit it from your project's .binenv.lock and, for instance, add it to a .binenv.lock in /home/zatricky/projects/work/.

This way you control the stickyone version when you're in /home/zatricky/projects/work/, and all other binaries when in /home/zatricky/projects/work/fooproject/.

Would that work ?

Also, note that "upgrading" a binary does not uninstall other versions.

zatricky commented 4 months ago

@leucos that certainly helps, thanks.

In this case the packages were being installed in the system rather than for just the user, which complicated things unnecessarily. I'll try out a .binenv.lock file in $HOME and feedback.

zatricky commented 4 months ago

I've discussed the issue with my team and we're going to try work something out using the home folder. However we also realised that if you are outside of the home folder that it will not use the config from $HOME/.binenv.lock. A kludge workaround, which I'm surprised works, is to have root create a /.binenv.lock file in the system root folder (or any parent folder of the folder you know you will be working in, such as /mnt/projects/.binenv.lock.

I suppose what this issue would be asking for is that the behaviour of this functionality be more predictable even when faced with these edge cases. Please let me know if I should edit the original Issue post.

leucos commented 4 months ago

Mmm, yes it works since the binenv code assumes that it should stop at $HOME. If you're outside $HOME it will happily iterate to /.

The function at work for this should probably be changed https://github.com/devops-works/binenv/blob/develop/internal/app/app.go#L994 . I am pretty sure it is buggy for now, and yes, the behaviour is not very clear.

May be we could start writing the specifications of what we want below ?

Something like:

To guess which version to use for binary b, the process is the following:

Any thoughts ?

zatricky commented 4 months ago

What you've put down makes sense. Of note is the last item in the listed process: "if nothing is found, use the default version". What I'm mostly trying to clarify is a standard way to define that default version (possibly even system-wide). The original issue came about where the root user was doing the installing and updating, from the context of the applications being wholly unavailable (or very very old) via the system's regular package manager. The "default version" was simply the latest version root had provided to the system.

My only issue with the final .binenv.lock location being in $HOME is that it isn't really a standard place for modern config file placement - but it is already usable there and it's "okay" as-is. In theory you could say the "correct" place for the final default configs would be in locations such as $HOME/.config/binenv/ and finally /etc/binenv/.

I hope this adds enough context.

For me, for now, the "workaround" is sufficient - but I also feel it would be worth adding these paths for future users. It is of course entirely up to the Dev(s) maintaining binenv on if this type of improvement is worth it.

leucos commented 1 week ago

Yes sure but I would not consider .binenv.lock being configuration. We should regard it as a context, just like direnv or autoenv.

By default version I mean latest version sorry.

The process is the following (I overlooked env vars last time):