NixOS / nixpkgs

Nix Packages collection & NixOS
MIT License
17.99k stars 14.01k forks source link

No way to install/use a specific package version? #9682

Closed novaluke closed 9 years ago

novaluke commented 9 years ago

July 2020 update

This issue is coming up on 5 years old at this point, and has gotten quite lengthy. While the issue may still be relevant, not all of the comments in this thread will be. It has been suggested that you may find it more valuable to skip to the bottom of the thread in order to get a read on the current state of things, rather than working through it from start to finish.

Here's the original post:


It provides . . . side-by-side installation of multiple versions of a package . . . (From the Nix page)

I can't seem to find any way to install a specific package version, though - it seems like when installing a package you just get whatever is current in the channel you've subscribed to. If there's no way to request a specific package version, how is it possible to have "side-by-side installation of multiple versions"?

_(Note: I understand that some packages occasionally have more than one version available in the current state of the channel and can be accessed via eg. package-name_1.2.3, but this seems to be the rare exception and still doesn't allow specifying a specific version, just a choice from a few available versions.)_


Potential use cases:

Solving dependency/Cabal hell: I found Nix through Haskell, where a lot of people offer it as a solution to "Cabal hell". However, if I can only install one version of a package via Nix, I can't solve the situation where I am working on two different projects with two different and incompatible dependency requirements.

Testing against multiple versions of dependencies: Say I'm writing a library, for which I originally depended on foo-1.0.0. A year later I'm making updates and I want to use expand the upper bound of that dependency so that users aren't restricted to an old version of the dependency. I install foo-1.5.0, make a bunch of updates, verify that it works, but then want to double-check that everything still works with foo-1.0.0, because if the new changes don't work with it I'll have to change the lower bound of the dependency, potentially causing problems for users. However, not being able to specify to Nix that I want foo-1.0.0, I can't test against foo-1.0.0 and can only state the dependency as foo == 1.5.0, instead of the more permissible (and usable) foo >= 1.0.0 && foo <= 1.5.0.

Sharing build/development environments:

Nix makes it trivial to set up and share build environments for your projects (From the Nix page)

I've seen people say that the ability to share build/development environments across the team solves the "Well it works on my machine" problem. However, if I send the environment (via default.nix/shell.nix etc.) to another developer to get them up to speed with the project, they may end up installing different versions of packages than me, since the packages channel may have progressed since I last installed/updated my packages. Now we're not on the same page any more and those subtle (and painful) differences and bugs can creep back in.

Deploying to servers/CI/etc: In a similar vein to sharing development environments, it would be great to be able to use Nix to standardize the environment across all our develop/build/test/deploy phases/environments. However, since the channel could change at any point between these phases and we're not able to specify specific package versions, this isn't possible. For example, take the case where the project is deployed across multiple servers. Being in the cloud, they're ephemeral, so when one breaks for some reason it's destroyed and replaced with a new, healthy version. Except that the new version has to be brought up so speed and installs the project via Nix. Since the channel has been updated since the other servers were last updated, the new server is now running in a different environment and introduces potentially problematic inconsistencies to the system.


Now, these are all hypothetical - I don't actually have experience in any of these use cases but if my understanding is correct I can see them potentially cropping up. However, I can find no mention anywhere (despite very exhaustive searching) of anyone concerned about locking down package versions or installing specific versions when using Nix. If I'm the only one, perhaps I'm missing something fundamental here and barking up the wrong tree?

I just can't see how Nix can deliver the benefits everyone says it does without giving users a way to specify specific package versions - is there really no way to do this, or am I misunderstanding the whole system?

jb55 commented 5 years ago

@novoxudonoser Flakes should solve many of the concerns raised in this thread.

lazamar commented 4 years ago

Finding what older versions are available

I've found that pinning the revision hash solves the problem of how to use an older package version, but leaves the question of how to find the revision that contains the version I want.

If the current version of a package is broken I want to use the previous one, but I found no way other than going through nixpkgs' git history to find what revision had the package version I wanted.

To solve that I wrote a tool to search all versions of a package that were ever available in a channel, what revision they can be found in, and what command to use to install them https://lazamar.co.uk/nix-versions/

vcunat commented 4 years ago

Such tools can be useful, but note that if a package is broken in nixpkgs... we typically don't want to leave it that way. Moreover, if there's good motivation, we do keep multiple versions in nixpkgs (say, llvm has many).

EDIT: flakes were linked above already :-/

loafofpiecrust commented 4 years ago

My impression after reading through this thread, learning about both Flakes and the search tool from @lazamar above, is that we can only use specific revisions of a nixpkgs channel to provide dependencies, but there's still no standard for specifying an individual package version. So if I need to use packages A, B, and C all pinned to specific versions I have to pull them from three different nixpkgs revisions? It seems like flakes solve reproducibility in providing a lock file but don't let me say "actually I need to use rand#0.7.2". This is a fundamental feature in other package managers like cargo and even the accursed pip, and I feel like I must be misunderstanding that it's not present in nix. Anything I'm missing?

knedlsepp commented 4 years ago

Anything I'm missing?

From what I understand is that often arbitrary versions of packages just don't always work perfectly with each other. That's why I think flakes doesn't even try to tackle that problem. Instead we just try to get a convenient tool for reproducing the same software as defined on other machines and rely on nixpkgs being a curated set of libraries whose versions are "known to work" with each other.

loafofpiecrust commented 4 years ago

rely on nixpkgs being a curated set of libraries whose versions are "known to work" with each other.

This makes sense to me. I guess it just feels odd that, for example, if I want to mostly use the 20.03 channel but pin Firefox to version 73, I have to pick myself a version of nixpkgs that had it. There are likely a bunch of revisions that include it. Do I pick the first or last commit that had it? I'm choosing a point in history for the whole build of Firefox. One side effect being that this prevents my Firefox 73 from using new patch versions of its dependencies (if it uses eg. ~1.2.0). If it did, that would break exact binary consistency, but controlling package versions with semver ranges is more powerful for the user AFAICT and gives you more insight into what you're actually installing.

jeff-hykin commented 4 years ago

The Answer to the Original Issue

(Can @mayhewluke or one of the nix maintainers add a version of this answer to the top? Because I just wasted 2.5 hours reading and attempting to understand this whole thread, when all I needed was @lazamar's criminally underrated comment)


Step 0: Find the Version you Want

Find (almost) all versions of a package using lazamar's absolutely amazing online tool

For example:

I wanted ruby 2.5 so I searched for ruby and found: Name Version Hash
ruby 2.5.5 67912138ea79c9690418e3c6fc524c4b06a396ad



Step 1: Install that version using its Hash

(I only know this because because clicking the hash on @lazamar's site explains it)

To install that ruby 2.5.5 version globally I ran

nix-env --install ruby -f https://github.com/NixOS/nixpkgs-channels/archive/67912138ea79c9690418e3c6fc524c4b06a396ad.tar.gz

To use that version of ruby in a nix-shell run

nix-shell -p ruby -I nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/67912138ea79c9690418e3c6fc524c4b06a396ad.tar.gz

To require/use that version of ruby in a nix-script run

let
     pkgs = import (builtins.fetchGit {
         # Descriptive name to make the store path easier to identify                
         name = "my-old-revision";                                                 
         url = "https://github.com/nixos/nixpkgs-channels/";                       
         ref = "refs/heads/nixpkgs-unstable";                     
         rev = "67912138ea79c9690418e3c6fc524c4b06a396ad";                                           
     }) {};                                                                           

     myPkg = pkgs.ruby
in
...

jeff-hykin commented 4 years ago

Why is this search functionality not built into Nix?

(probably should open up a new issue for this^ question)

Because (AFAIK) Nix hasn't created a standard way for packages to notate a version within their name, @lazamar's method is still somewhat of a workaround. As @thomastjeffery points out

If I want a package that is a certain version, I need to find out what content-address to get it from.

Right now, that involves scouring Github for the name of a package that corresponds to the version I want. Let alone the fact that there are multiple nonstandard ways to do this, I shouldn't be doing it in the first place. I'd rather add the version string to my name search.

The version string is there, but it's hard to find. It's either ignored, appended to the package name with underscores instead of dots, or something else entirely. Because the version string isn't explicitly used by Nix, it isn't required, and there is no standard way to use or provide it.

Why is this thread filled with discussions of:

I really don't know

novaluke commented 4 years ago

@jeff-hykin I've been uninvolved in this thread for almost 5 years now (for some reason your post was the first I got a notification for :confused:), and there's apparently been a lot of discussion since I last checked in. As a result, I'm too out of touch with the issue to be qualified to make a call as to what solution should be suggested (if any).

I have, however, updated the original post with a suggestion to check out the latest comments, so others don't have to slog through these ~60 comments like you did. Does that sound like a reasonable compromise?

jeff-hykin commented 4 years ago

Looks good to me, thank you for doing that! @mayhewluke

novaluke commented 4 years ago

You're welcome @jeff-hykin! Happy to help.

thomastjeffery commented 4 years ago

Thanks for the synopsis, @jeff-hykin!

Why is this thread filled with discussions of...

This thread (as I saw it) was originally about a usability issue that exists in Nix.

Some people quickly pointed out elegant (from a certain perspective) workarounds to that issue, like pinning.

Some even pointed out that the Nix philosophy (as they understood it) is at its core incompatible with version numbering.

At this point, there should probably be a new issue created and discussion made about how to integrate the reality of software versioning with Nix's UI, implementation, or the Nix philosophy itself.

As I see it, this issue is a usability one, so any workarounds ought to (at the very least) be obvious and well-documented to the casual Nix user.

As it is, the simple act of installing a specific version of a package confronts the casual user with a need to understand the design and implementation of Nix, and choose a confusing (no matter how elegant) solution. Users should never be led to a GitHub issue in order to know how to use their package manager.

I don't think I'm qualified to lead this discussion, but seeing as I was contributing to this discussion nearly 3 years ago, people are still stumbling into this thread, and I haven't really seen a solution...

Here is the new issue: #93327

jeff-hykin commented 4 years ago

Thanks for the explanation and kicking off the new issue @thomastjeffery, I appreciate it!

nixos-discourse commented 2 years ago

This issue has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/nix-shell-p-python37-pkgs-pytest-fails/22533/4

nixos-discourse commented 1 year ago

This issue has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/best-practice-for-pinning-version-of-individual-packages/6194/7