- 4 mins read
I’ve got a small handful of packages on Nixpkgs that I maintain. When I was starting out, I didn’t really know how to do any of that, and was fortunate enough to have some friends onboard me. In the spirit of giving back, I’ll walk through how I do an update pass today on a simple package, and give some background information on how to make it easy.
I’m a maintainer for the lmstudio package, which wraps the binaries from LM Studio (a friendly GUI/IDE for AI model development work). This workflow is for that package; other packages (especially those used by others or built from source) will probably have different details.
lmstudio-X.Y.Z.W and switch to it.nix-shell maintainers/scripts/update.nix --argstr package lmstudio.lmstudio: X.Y.Z.W -> Q.R.S.T. You ideally only want one commit or other maintainers get mad at you.nix-shell -I nixpkgs=~/projects/nix/nixpkgs -p lmstudio.master branch with the title lmstudio: X.Y.Z.W -> Q.R.S.T and link the changelog. Example here.nixpkgs-review pr --post-result 452412. This will (assuming they’re setup with gh) check out the PR in a sandbox, build it, and give them a chance to run it for manual testing. After, it’ll comment with a summary saying that ye, verily, did the PR build on their machine.Instead of…
$ nix-shell -I ~/projects/nix/nixpkgs -p lmstudio
…you can also use…
$ nix-build -I ~/projects/nix/nixpkgs -A lmstudio
After that, you’d have a result directory symlinked into the nix store:
[crertel@host:~/projects/nix/nixpkgs]$ ls -la result
lrwxrwxrwx 1 crertel users 61 Nov 18 12:31 result -> /nix/store/0rifw0s3frxqk6j14gpjag90wd9d28hn-lmstudio-0.3.31-7
[crertel@host:~/projects/nix/nixpkgs]$ ls -la result/
bin/ share/
[crertel@host:~/projects/nix/nixpkgs]$ ls -la result/bin/
total 100372
dr-xr-xr-x 2 root root 4096 Dec 31 1969 .
dr-xr-xr-x 4 root root 4096 Dec 31 1969 ..
-r-xr-xr-x 1 root root 102767744 Dec 31 1969 lms
lrwxrwxrwx 1 root root 67 Dec 31 1969 lm-studio -> /nix/store/gp0qyqzb4kp8j892sdnjyd8b891mmvck-lmstudio-0.3.31-7-bwrap
Neat, huh? I find that the nix-shell version is a bit easier for iterating and poking around (and it mimics how I normally use nix anyways), but nix-build will be closer to the thing that actually gets the final artifact out.
Before we had a good update script (I think @deftdawg was the one who got this working), we had to manually download and hash releases and update the version numbers; with the script, though, we can just use that one-liner above.
The script is called from packages.nix:
{
lib,
stdenv,
callPackage,
...
}@args:
let
pname = "lmstudio";
version_aarch64-darwin = "0.3.31-7";
hash_aarch64-darwin = "sha256-OyPHKUmZsIU0kc3JxwxdxACSN7hR6gFWjMnGp1x5diQ=";
version_x86_64-linux = "0.3.31-7";
hash_x86_64-linux = "sha256-NeVteQlzygHkwwgLkB5n7meH02WhFE68KkbGRulDiC0=";
meta = {
description = "LM Studio is an easy to use desktop app for experimenting with local and open-source Large Language Models (LLMs)";
homepage = "https://lmstudio.ai/";
license = lib.licenses.unfree;
mainProgram = "lm-studio";
maintainers = with lib.maintainers; [ crertel ];
platforms = [
"x86_64-linux"
"aarch64-darwin"
];
sourceProvenance = with lib.sourceTypes; [ binaryNativeCode ];
broken = stdenv.hostPlatform.isDarwin; # Upstream issue: https://github.com/lmstudio-ai/lmstudio-bug-tracker/issues/347
};
in
if stdenv.hostPlatform.isDarwin then
callPackage ./darwin.nix {
inherit pname meta;
passthru.updateScript = ./update.sh;
version = version_aarch64-darwin;
url =
args.url
or "https://installers.lmstudio.ai/darwin/arm64/${version_aarch64-darwin}/LM-Studio-${version_aarch64-darwin}-arm64.dmg";
hash = args.hash or hash_aarch64-darwin;
}
else
callPackage ./linux.nix {
inherit pname meta;
passthru.updateScript = ./update.sh;
version = version_x86_64-linux;
url =
args.url
or "https://installers.lmstudio.ai/linux/x64/${version_x86_64-linux}/LM-Studio-${version_x86_64-linux}-x64.AppImage";
hash = args.hash or hash_x86_64-linux;
}
Note the passthru.updateScript attribute, which refers to an update.sh. That script looks like:
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p curl common-updater-scripts
set -euo pipefail
for system in "aarch64-darwin darwin/arm64" "x86_64-linux linux/x64"; do
# shellcheck disable=SC2086
set -- ${system} # split string into variables $1 and $2
arch="${1}"
platform="${2}"
url=$(curl -ILs -o /dev/null -w %{url_effective} "https://lmstudio.ai/download/latest/${platform}")
version="$(echo "${url}" | cut -d/ -f6)"
hash=$(nix --extra-experimental-features nix-command hash convert --hash-algo sha256 "$(nix-prefetch-url "${url}")")
update-source-version lmstudio "${version}" "${hash}" --system="${arch}" --version-key="version_${arch}" \
2> >(tee /dev/stderr) | grep -q "nothing to do" && exit
done
What that script does (and your script could do something similar!) is work out the version and hash for the most recent version of this software using some curl magic, and then invoke the update-source-version script. That script will fixup the old package.nix and propose the changes (which is why we have to commit it after).
If you want to learn more about this, some places to check: