From 1086aee53f8a96ecf221e68ed8e3765f458fc19c Mon Sep 17 00:00:00 2001 From: eveeifyeve <88671402+Eveeifyeve@users.noreply.github.com> Date: Tue, 1 Oct 2024 11:11:20 +1000 Subject: [PATCH] bun: init configHook and fetchDeps; bun 1.1.43 -> 1.2.0; bun: switch to finalAttrs from rec bun: switch to finalAttrs from rec Could speed up hydra? bun: added hook tests and improve passthru for hooks --- .../javascript.section.md | 128 ++++++++++++- doc/redirects.json | 12 ++ .../bu/bun/fetch-deps/bun-config-hook.sh | 50 +++++ pkgs/by-name/bu/bun/fetch-deps/default.nix | 100 ++++++++++ pkgs/by-name/bu/bun/package.nix | 171 +++++++++++------- pkgs/by-name/bu/bun/test-app.nix | 40 ++++ 6 files changed, 431 insertions(+), 70 deletions(-) create mode 100644 pkgs/by-name/bu/bun/fetch-deps/bun-config-hook.sh create mode 100644 pkgs/by-name/bu/bun/fetch-deps/default.nix create mode 100644 pkgs/by-name/bu/bun/test-app.nix diff --git a/doc/languages-frameworks/javascript.section.md b/doc/languages-frameworks/javascript.section.md index 9acfd4181108a5..80032b31da062c 100644 --- a/doc/languages-frameworks/javascript.section.md +++ b/doc/languages-frameworks/javascript.section.md @@ -514,7 +514,8 @@ set `prePnpmInstall` to the right commands to run. For example: ```nix prePnpmInstall = '' - pnpm config set dedupe-peer-dependants false + +pnpm config set dedupe-peer-dependants false ''; pnpmDeps = pnpm.fetchDeps { inherit (finalAttrs) prePnpmInstall; @@ -525,6 +526,131 @@ pnpmDeps = pnpm.fetchDeps { In this example, `prePnpmInstall` will be run by both `pnpm.configHook` and by the `pnpm.fetchDeps` builder. +### Bun {#javascript-bun} + +Bun based projects use a `bun.lock` file instead of a `package-lock.json` to pin dependencies. Nixpkgs provides a hooks below to for install dependacies via `bun.configHook` which configuates the project to install via the use of `bunDeps` before building the project. + +```nix +{ + stdenv, + bun +}: + +stdenv.mkDerivation (finalAttrs: { + pname = "foo"; + version = "0-unstable-1980-01-01"; + + src = ...; + + nativeBuildInputs = [ + bun.configHook + ]; + + bunDeps = bun.fetchDeps { + inherit (finalAttrs) pname version src; + hash = "..."; + }; +}) + +``` + +`bun.configHook` supports additional flags to `bun install` via `bunInstallFlags` + +```nix +{ + bun, +}: + +stdenv.mkDerivation (finalAttrs: { + pname = "foo"; + version = "0-unstable-1980-01-01"; + + src = ...; + + bunInstallFlags = [ "--shamefully-hoist" ]; + + bunDeps = bun.fetchDeps { + inherit (finalAttrs) bunInstallFlags; + }; +}) +``` + + +#### Dealing with `sourceRoot` {#javascript-bun-sourceRoot} + +If the bun project is in a subdirectory, you can just define `sourceRoot` or `setSourceRoot` for `fetchDeps`. +If `sourceRoot` is different between the parent derivation and `fetchDeps`, you will have to set `bunRoot` to effectively be the same location as it is in `fetchDeps`. + +Assuming the following directory structure, we can define `sourceRoot` and `pnpmRoot` as follows: + +``` +. +├── frontend +│   ├── ... +│   ├── package.json +│   └── bun.lock +└── ... +``` + +```nix + ... + bunDeps = bun.fetchDeps { + ... + sourceRoot = "${finalAttrs.src.name}/frontend"; + }; + + # by default the working directory is the extracted source + bunRoot = "frontend"; +``` + +#### Bun workspaces {#javascript-bun-workspaces} + +If you need to use a Bun workspace for your project, then set `bunWorkspaces = [ "" "" ]`, etc, in your `bun.fetchDeps` call, +which will make Bun only install dependencies for those workspace packages. + +For example: + +```nix +... +bunWorkspaces = [ "@astrojs/language-server" ]; +bunDeps = bun.fetchDeps { + inherit (finalAttrs) pnpmWorkspaces; + ... +} +``` + +The above would make `bun.fetchDeps` call only install dependencies for the `@astrojs/language-server` workspace package. +Note that you do not need to set `sourceRoot` to make this work. + +Usually in such cases, you'd want to use `bun --filter= build` to build your project, as `npmHooks.npmBuildHook` probably won't work. A `buildPhase` based on the following example will probably fit most workspace projects: + +```nix +buildPhase = '' + runHook preBuild + + bun --filter=@astrojs/language-server build + + runHook postBuild +''; +``` + +#### Additional PNPM Commands and settings {#javascript-bun-extraCommands} + +If you require setting an additional Bun configuration setting (such as `--dry-run` or similar), +set `preBunInstall` to the right commands to run. For example: + +```nix +preBunInstall = '' + --dry-run +''; +pnpmDeps = pnpm.fetchDeps { + inherit (finalAttrs) preBunInstall; + ... +}; +``` + +In this example, `preBunInstall` will be run by both `bun.configHook` and by the `bun.fetchDeps` builder. + ### Yarn {#javascript-yarn} Yarn based projects use a `yarn.lock` file instead of a `package-lock.json` to pin dependencies. Nixpkgs provides the Nix function `fetchYarnDeps` which fetches an offline cache suitable for running `yarn install` before building the project. In addition, Nixpkgs provides the hooks: diff --git a/doc/redirects.json b/doc/redirects.json index 254e6ceb6fc6e3..bebe4df66fcaf3 100644 --- a/doc/redirects.json +++ b/doc/redirects.json @@ -3055,6 +3055,18 @@ "javascript-pnpm-extraCommands": [ "index.html#javascript-pnpm-extraCommands" ], + "javascript-bun": [ + "index.html#javascript-bun" + ], + "javascript-bun-sourceRoot": [ + "index.html#javascript-bun-sourceRoot" + ], + "javascript-bun-workspaces": [ + "index.html#javascript-bun-workspaces" + ], + "javascript-bun-extraCommands": [ + "index.html#javascript-bun-extraCommands" + ], "javascript-yarn": [ "index.html#javascript-yarn" ], diff --git a/pkgs/by-name/bu/bun/fetch-deps/bun-config-hook.sh b/pkgs/by-name/bu/bun/fetch-deps/bun-config-hook.sh new file mode 100644 index 00000000000000..b5c5df27ebbd8d --- /dev/null +++ b/pkgs/by-name/bu/bun/fetch-deps/bun-config-hook.sh @@ -0,0 +1,50 @@ +# shellcheck shell=bash + +bunConfigHook() { + echo "Executing bunConfigHook" + + if [ -n "${bunRoot-}" ]; then + pushd "$bunRoot" + fi + + if [ -z "${bunDeps-}" ]; then + echo "Error: 'bunDeps' must be set when using bunConfigHook." + exit 1 + fi + + echo "Configuring bun store" + + export HOME=$(mktemp -d) + export BUN_INSTALL_CACHE_DIR=$(mktemp -d) + + cp -Tr "$bunDeps" "$BUN_INSTALL_CACHE_DIR" + chmod -R +w "$BUN_INSTALL_CACHE_DIR" + + echo "Installing dependencies" + if [[ -n "$bunWorkspaces" ]]; then + local IFS=" " + for ws in $bunWorkspaces; do + bunInstallFlags+=("--filter=$ws") + done + fi + + runHook preBunInstall + + bun install \ + --offline \ + --ignore-scripts \ + "${bunInstallFlags[@]}" \ + --frozen-lockfile + + echo "Patching scripts" + + patchShebangs node_modules/{*,.*} + + if [ -n "${bunRoot-}" ]; then + popd + fi + + echo "Finished bunConfigHook" +} + +postConfigureHooks+=(pnpmConfigHook) diff --git a/pkgs/by-name/bu/bun/fetch-deps/default.nix b/pkgs/by-name/bu/bun/fetch-deps/default.nix new file mode 100644 index 00000000000000..1de162b80109ad --- /dev/null +++ b/pkgs/by-name/bu/bun/fetch-deps/default.nix @@ -0,0 +1,100 @@ +{ + lib, + stdenvNoCC, + callPackage, + jq, + moreutils, + cacert, + makeSetupHook, + bun, + yq, +}: + +{ + fetchDeps = + { + hash ? "", + pname, + bunWorkspaces ? [ ], + preBunInstall ? "", + bunInstallFlags ? [ ], + ... + }@args: + let + args' = builtins.removeAttrs args [ + "hash" + "pname" + ]; + hash' = + if hash != "" then + { outputHash = hash; } + else + { + outputHash = ""; + outputHashAlgo = "sha256"; + }; + + filterFlags = lib.map (package: "--filter=${package}") bunWorkspaces; + in + stdenvNoCC.mkDerivation ( + finalAttrs: + ( + args' + // { + name = "${pname}-bun-deps"; + + nativeBuildInputs = [ + cacert + jq + moreutils + bun + ]; + + installPhase = '' + runHook preInstall + + lockfileVersion="$(jq -r .lockfileVersion bun.lock)" + if [[ ''${lockfileVersion:0:1} -gt ${lib.versions.major bun.version} ]]; then + echo "ERROR: lockfileVersion $lockfileVersion in bun.lock is too new for the provided bun version ${lib.versions.major bun.version}!" + exit 1 + fi + + export HOME=$(mktemp -d) + export BUN_INSTALL_CACHE_DIR = $out + + ${preBunInstall} + + bun install \ + --force \ + ${lib.escapeShellArgs filterFlags} \ + ${lib.escapeShellArgs bunInstallFlags} \ + --frozen-lockfile + + runHook postInstall + ''; + + fixupPhase = '' + runHook preFixup + + # Remove timestamp and sort the json files + # rm -rf $out/v3/tmp + # for f in $(find $out -name "*.json"); do + # jq --sort-keys "del(.. | .checkedAt?)" $f | sponge $f + # done + + runHook postFixup + ''; + + dontConfigure = true; + dontBuild = true; + outputHashMode = "recursive"; + } + // hash' + ) + ); + + configHook = makeSetupHook { + name = "bun-config-hook"; + propagatedBuildInputs = [ bun ]; + } ./bun-config-hook.sh; +} diff --git a/pkgs/by-name/bu/bun/package.nix b/pkgs/by-name/bu/bun/package.nix index 5de7c2a9e83895..ddd87d3b43cf9e 100644 --- a/pkgs/by-name/bu/bun/package.nix +++ b/pkgs/by-name/bu/bun/package.nix @@ -1,31 +1,42 @@ -{ lib -, stdenvNoCC -, fetchurl -, autoPatchelfHook -, unzip -, installShellFiles -, makeWrapper -, openssl -, writeShellScript -, curl -, jq -, common-updater-scripts -, darwin +{ + lib, + stdenvNoCC, + fetchurl, + autoPatchelfHook, + unzip, + installShellFiles, + makeWrapper, + openssl, + writeShellScript, + curl, + jq, + common-updater-scripts, + darwin, + callPackage, + callPackages, }: -stdenvNoCC.mkDerivation rec { - version = "1.1.43"; +stdenvNoCC.mkDerivation (finalAttrs: { + version = "1.2.0"; pname = "bun"; - src = passthru.sources.${stdenvNoCC.hostPlatform.system} or (throw "Unsupported system: ${stdenvNoCC.hostPlatform.system}"); + src = + finalAttrs.passthru.sources.${stdenvNoCC.hostPlatform.system} + or (throw "Unsupported system: ${stdenvNoCC.hostPlatform.system}"); - sourceRoot = { - aarch64-darwin = "bun-darwin-aarch64"; - x86_64-darwin = "bun-darwin-x64-baseline"; - }.${stdenvNoCC.hostPlatform.system} or null; + sourceRoot = + { + aarch64-darwin = "bun-darwin-aarch64"; + x86_64-darwin = "bun-darwin-x64-baseline"; + } + .${stdenvNoCC.hostPlatform.system} or null; strictDeps = true; - nativeBuildInputs = [ unzip installShellFiles makeWrapper ] ++ lib.optionals stdenvNoCC.hostPlatform.isLinux [ autoPatchelfHook ]; + nativeBuildInputs = [ + unzip + installShellFiles + makeWrapper + ] ++ lib.optionals stdenvNoCC.hostPlatform.isLinux [ autoPatchelfHook ]; buildInputs = [ openssl ]; dontConfigure = true; @@ -40,7 +51,7 @@ stdenvNoCC.mkDerivation rec { runHook postInstall ''; - postPhases = [ "postPatchelf"]; + postPhases = [ "postPatchelf" ]; postPatchelf = lib.optionalString stdenvNoCC.hostPlatform.isDarwin '' wrapProgram $out/bin/bun \ @@ -51,56 +62,70 @@ stdenvNoCC.mkDerivation rec { # 2. Is not correctly detected even on macOS 15+, where it is available through Rosetta # # The baseline builds are no longer an option because they too now require avx support. - + lib.optionalString - ( - stdenvNoCC.buildPlatform.canExecute stdenvNoCC.hostPlatform - && !(stdenvNoCC.hostPlatform.isDarwin && stdenvNoCC.hostPlatform.isx86_64) - ) - '' - completions_dir=$(mktemp -d) + + + lib.optionalString + ( + stdenvNoCC.buildPlatform.canExecute stdenvNoCC.hostPlatform + && !(stdenvNoCC.hostPlatform.isDarwin && stdenvNoCC.hostPlatform.isx86_64) + ) + '' + completions_dir=$(mktemp -d) - SHELL="bash" $out/bin/bun completions $completions_dir - SHELL="zsh" $out/bin/bun completions $completions_dir - SHELL="fish" $out/bin/bun completions $completions_dir + SHELL="bash" $out/bin/bun completions $completions_dir + SHELL="zsh" $out/bin/bun completions $completions_dir + SHELL="fish" $out/bin/bun completions $completions_dir - installShellCompletion --name bun \ - --bash $completions_dir/bun.completion.bash \ - --zsh $completions_dir/_bun \ - --fish $completions_dir/bun.fish - ''; + installShellCompletion --name bun \ + --bash $completions_dir/bun.completion.bash \ + --zsh $completions_dir/_bun \ + --fish $completions_dir/bun.fish + ''; - passthru = { - sources = { - "aarch64-darwin" = fetchurl { - url = "https://github.com/oven-sh/bun/releases/download/bun-v${version}/bun-darwin-aarch64.zip"; - hash = "sha256-3sbiB84OHnxm7bSAL6eu+EKeOUQZvWqlqCGuXDCuoBE="; - }; - "aarch64-linux" = fetchurl { - url = "https://github.com/oven-sh/bun/releases/download/bun-v${version}/bun-linux-aarch64.zip"; - hash = "sha256-SjI5u1jhmsRMRDqpANuhqyz3YCCiWzz1XJxG5IZharM="; + passthru = + { + sources = { + "aarch64-darwin" = fetchurl { + url = "https://github.com/oven-sh/bun/releases/download/bun-v${finalAttrs.version}/bun-darwin-aarch64.zip"; + hash = "sha256-+nIXPLIiDQDi0mUP79wLWze/2Lsz2NZxtQ77QJwvV0U="; + }; + "aarch64-linux" = fetchurl { + url = "https://github.com/oven-sh/bun/releases/download/bun-v${finalAttrs.version}/bun-linux-aarch64.zip"; + hash = "sha256-aF6IlwQM+qNtxkoz6EGevUqQa9A2v5DIz8vj1oBE1c8="; + }; + "x86_64-darwin" = fetchurl { + url = "https://github.com/oven-sh/bun/releases/download/bun-v${finalAttrs.version}/bun-darwin-x64-baseline.zip"; + hash = "sha256-6Yad3YhRz4IjK20uFdirUpazKAvNmtP55yMZgsMZXco="; + }; + "x86_64-linux" = fetchurl { + url = "https://github.com/oven-sh/bun/releases/download/bun-v${finalAttrs.version}/bun-linux-x64.zip"; + hash = "sha256-B0fpcBILE6HaU0G3UaXwrxd4vYr9cLXEWPr/+VzppFM="; + }; }; - "x86_64-darwin" = fetchurl { - url = "https://github.com/oven-sh/bun/releases/download/bun-v${version}/bun-darwin-x64-baseline.zip"; - hash = "sha256-q2vBAlBJ7FRowGje7F50MUdgDrOmeyG0xHYC1nRpETY="; - }; - "x86_64-linux" = fetchurl { - url = "https://github.com/oven-sh/bun/releases/download/bun-v${version}/bun-linux-x64.zip"; - hash = "sha256-j5iqhwkVV2R9wjxlwyBrFO6QLI4n0CA9qhIAstH6PCE="; + updateScript = writeShellScript "update-bun" '' + set -o errexit + export PATH="${ + lib.makeBinPath [ + curl + jq + common-updater-scripts + ] + }" + NEW_VERSION=$(curl --silent https://api.github.com/repos/oven-sh/bun/releases/latest | jq '.tag_name | ltrimstr("bun-v")' --raw-output) + if [[ "${finalAttrs.version}" = "$NEW_VERSION" ]]; then + echo "The new version same as the old version." + exit 0 + fi + for platform in ${lib.escapeShellArgs finalAttrs.meta.platforms}; do + update-source-version "bun" "$NEW_VERSION" --ignore-same-version --source-key="sources.$platform" + done + ''; + tests = { + hook = callPackage ./test-app.nix { bun = finalAttrs.finalPackage; }; }; + + # see ./doc/langauges-frameworks/javascript.section.md + inherit (callPackages ./fetch-deps { bun = finalAttrs.finalPackage; }) fetchDeps configHook; }; - updateScript = writeShellScript "update-bun" '' - set -o errexit - export PATH="${lib.makeBinPath [ curl jq common-updater-scripts ]}" - NEW_VERSION=$(curl --silent https://api.github.com/repos/oven-sh/bun/releases/latest | jq '.tag_name | ltrimstr("bun-v")' --raw-output) - if [[ "${version}" = "$NEW_VERSION" ]]; then - echo "The new version same as the old version." - exit 0 - fi - for platform in ${lib.escapeShellArgs meta.platforms}; do - update-source-version "bun" "$NEW_VERSION" --ignore-same-version --source-key="sources.$platform" - done - ''; - }; meta = with lib; { homepage = "https://bun.sh"; changelog = "https://bun.sh/blog/bun-v${version}"; @@ -114,8 +139,16 @@ stdenvNoCC.mkDerivation rec { lgpl21Only # javascriptcore and webkit ]; mainProgram = "bun"; - maintainers = with maintainers; [ DAlperin jk thilobillerbeck cdmistman coffeeispower diogomdp ]; - platforms = builtins.attrNames passthru.sources; + maintainers = with maintainers; [ + DAlperin + jk + thilobillerbeck + cdmistman + coffeeispower + diogomdp + eveeifyeve + ]; + platforms = builtins.attrNames finalAttrs.passthru.sources; # Broken for Musl at 2024-01-13, tracking issue: # https://github.com/NixOS/nixpkgs/issues/280716 broken = stdenvNoCC.hostPlatform.isMusl; @@ -123,4 +156,4 @@ stdenvNoCC.mkDerivation rec { # Hangs when run via Rosetta 2 on Apple Silicon hydraPlatforms = lib.lists.remove "x86_64-darwin" lib.platforms.all; }; -} +}) diff --git a/pkgs/by-name/bu/bun/test-app.nix b/pkgs/by-name/bu/bun/test-app.nix new file mode 100644 index 00000000000000..668ac512468693 --- /dev/null +++ b/pkgs/by-name/bu/bun/test-app.nix @@ -0,0 +1,40 @@ +{ + lib, + stdenv, + bun, +}: +stdenv.mkDerivation (finalAttrs: { + pname = "test-app"; + inherit (bun) version src; + + bunDeps = bun.fetchDeps { + inherit (finalAttrs) pname version src; + hash = lib.fakeHash; + }; + + nativeBuildInputs = [ + bun.configHook + ]; + + + buildAndTestSubdir = "bench/postgres"; + + # No one should be actually running this, so lets save some time + buildType = "debug"; + doCheck = false; + + installPhase = '' + runHook preInstall + + mkdir -p $out/bin + cp -R ./* $out + + makeBinaryWrapper ${bun}/bin/bun $out/bin/test-app \ + --prefix PATH : ${lib.makeBinPath [ bun ]} \ + --add-flags "run --prefer-offline --no-install --cwd $out ./index.mjs" + + runHook postInstall + ''; + + inherit (bun) meta; +})