A while ago I started using the approach outlined below, to install spacemacs via home-manager.
When trying to change the version of spacemacs, I discovered that passing nonsensical values of owner, repo and rev to fetchFromGitHub seems to have no effect whatsoever on the result!
On the other hand
changing the length of sha256 leads to an error complaining about the length
not using sources.spacemacs at all, does remove spacemacs from my configuration
I am left perplexed as to why this seems to install spacemacs, even if it has no meaningful information about where to get spacemacs.
home.nix
{ config, pkgs, ... }:
let
sources = (pkgs.callPackage ../sources.nix {});
in
{
home.file.".emacs.d" = sources.spacemacs;
# etc.
}
It’s a fixed-output derivation. As long as sha256 stays the same it will not be rebuilt. Just change any character of sha256 (without changing the length) or use
For fixed-output derivations, on the other hand, the name of the output path only depends on the outputHash* and name attributes, while all other attributes are ignored for the purpose of computing the output path. (The name attribute is included because it is part of the path.)
The name for the derivation resulting from fetchFromGitHub is always “source”.
This is great! Why didn’t I know about this before?
Nope, this doesn’t work. There seems to be some kind of checksum in there … which is why I’m so glad that you pointed out the existence of fakeSha256: coming up with fake SHAs by hand has always been an annoyance!
While we’re on the topic of sha256 what’s the streamlined way of getting the correct SHA?
My approach is to put in a fake one, try to build, wait for the error to appear, and copy the correct SHA from the error message, then rebuild again.
This is pretty annoying, especially if the download is huge: the build failure means the download isn’t cached, so we have to download it all over again.
It’s a hexadecimal number so only 0-9 and a-z are allowed. Other than that I don’t think there are any check digits in there, but I could be wrong. Anyway, I usually edit Nix expressions in Vim, so I just navigate to anywhere within the SHA string and issue vi"r0, which first visually selects everything within quotes and then replaces every character by 0. (An alternative is di"52i0 which first deletes everthing within quotes and then inserts 52 zeros.)
but I can never remember what URL is used by fetchFromGitHub and friends, so I only do this for fetchTarball where I have the URL in the Nix expression.
If you pass --name source as I did here, then using
Additionally, I generated this error by replacing the d at the end of a working SHA with the e that you see there … disproving the hypothesis that changing one character works as a scheme for creating a fake.
My problem with the various Nix prefetch functions has been that it’s less streamlined that just using a fake SHA … except for the dobule download issue.
But you’ve given me an idea for what might be a decent approach:
Stick nix-prefetch-url --unpack --name source https://github.com/syl20bnr/spacemacs/archive/v0.200.13.tar.gz in a comment in my Nix source.
Then bump the version in the code and the comment, and copy-pasta the comment to my shell.
Not ideal, but probably an improvement on what I’m doing now.
Yeah, by default it is a custom base-32 scheme (described in the Nix thesis, p. 89 (or 97 in the PDF)). Newer versions will use base-64 to match SRI format.
This is due to how the binary strings convert to ASCII – you need 256/5 base-32 digits to represent sha-256, so there will be extra 0.8 of base 32 digit that Nix expects to be 0 bits. In your replacement, the extra 1 bit in e compared to d would trespass on that extra space. Right, as Michael notes bellow, e is not a digit in Nix’s base-32 alphabet, the zero bits are only at the start.
If you want some sure change, thanks to endianness, the first base-32 can be just 0 or 1 and you can always replace one for the other.
The base-64 format is easier, you can just replace any but the last digit by any other digit.
Would it be naive to hope that using lib.fakeSha256 will allow me not to care about any of these implementation details and not even notice this transition?
You will notice the transition, as the error might tell you that it expected either "000000000…00000" as sha256 but got something else in base32 or it will tell you that "sha256-AAAAAAA…AAAAA==" was expected when in base64 mode.
Though at the end, just dump whatever you see as actual sha into your expression, and ignore the rest. Nix will figure out on its own what format the hash is in and convert accordingly to its internal representation.
Yes, fine, the dummy value generated by fakeSha256 changing and appearing in the noise, would make me notice that something has changed, but given that this dummy value was always meant to be ignored, I’ll sweep that under the carpet, and classify it under stuff I don’t need to notice.
In short, when the change happens, I won’t have to change my approach to updating the SHAs in any meaningful way. That’s good.
Additionally, I generated this error by replacing the d at the end of a working SHA with the e that you see there … disproving the hypothesis that changing one character works as a scheme for creating a fake.
It actually works, but e is forbidden. Replace with 1, that will work.
This is further evidence that lib.fakeSha256 is the correct approach to this … or the empty strings that @jtojnar mentions, if they become stabilized.
This is further evidence that lib.fakeSha256 is the correct approach to this … or the empty strings that @jtojnar mentions, if they become stabilized.
both lib.fakeSha256 and 0000000000000000000000000000000000000000000000000000000000000000 (64 zeros for base-16) can work, both need documentation, but an experienced person knows anyway that SHA-256 is 64 nibbles.