From fe6d9f5730d08a7abaee597cc9e608bafd5902b9 Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Fri, 1 Dec 2023 19:02:05 -0600 Subject: [PATCH 01/19] add flake to repo --- flake.nix | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 flake.nix diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..91c1a42 --- /dev/null +++ b/flake.nix @@ -0,0 +1,21 @@ +{ + description = "Harmony GitHub collaboration tool"; + + inputs = { + nixpkgs.url = "https://github.com/nixos/nixpkgs"; + }; + + outputs = { self, nixpkgs }: + let + lib = nixpkgs.lib; + forAllSystems = lib.genAttrs lib.systems.flakeExposed; + in + { + packages = forAllSystems (system: + { + harmony = import ./default.nix { inherit system; }; + default = self.packages.${system}.harmony; + } + ); + }; +} From b9625ec645c598f662578183495bce9c60594ae8 Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Fri, 1 Dec 2023 19:07:12 -0600 Subject: [PATCH 02/19] default.nix file --- default.nix | 3 +++ flake.nix | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 default.nix diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..3d16604 --- /dev/null +++ b/default.nix @@ -0,0 +1,3 @@ +{ stdenv }: +stdenv.mkDerivation { +} diff --git a/flake.nix b/flake.nix index 91c1a42..0c6b592 100644 --- a/flake.nix +++ b/flake.nix @@ -13,7 +13,9 @@ { packages = forAllSystems (system: { - harmony = import ./default.nix { inherit system; }; + harmony = with nixpkgs.legacyPackages.${system}.default; + callPackage ./default.nix {}; + default = self.packages.${system}.harmony; } ); From b36a3e97f2674d90049b2426e418be3d6c0d9700 Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Fri, 1 Dec 2023 19:22:38 -0600 Subject: [PATCH 03/19] generate lockfile. add beginning of derivation. update version check script. --- default.nix | 4 ++++ flake.lock | 26 ++++++++++++++++++++++++++ flake.nix | 4 ++-- version-check.sh | 5 +++-- 4 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 flake.lock diff --git a/default.nix b/default.nix index 3d16604..0076832 100644 --- a/default.nix +++ b/default.nix @@ -1,3 +1,7 @@ { stdenv }: stdenv.mkDerivation { + pname = "harmony"; + version = "2.6.1"; + + src = ./.; } diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..fa8157a --- /dev/null +++ b/flake.lock @@ -0,0 +1,26 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1701476910, + "narHash": "sha256-ji5EgVv1tF2TkvYoBjgJyTK1ejmgCN0rsiN+1hLeYUE=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "9657d650935e9d16dbb463473b525333afa892a6", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix index 0c6b592..1d11a93 100644 --- a/flake.nix +++ b/flake.nix @@ -2,7 +2,7 @@ description = "Harmony GitHub collaboration tool"; inputs = { - nixpkgs.url = "https://github.com/nixos/nixpkgs"; + nixpkgs.url = github:NixOS/nixpkgs; }; outputs = { self, nixpkgs }: @@ -13,7 +13,7 @@ { packages = forAllSystems (system: { - harmony = with nixpkgs.legacyPackages.${system}.default; + harmony = with nixpkgs.legacyPackages.${system}; callPackage ./default.nix {}; default = self.packages.${system}.harmony; diff --git a/version-check.sh b/version-check.sh index 2d196a5..6cebc52 100755 --- a/version-check.sh +++ b/version-check.sh @@ -3,11 +3,12 @@ pkgversion="$(cat harmony.ipkg | sed -n 's/version = \(.*\)/\1/p')" idrversion="$(cat src/AppVersion.idr | sed -n 's/appVersion = "\(.*\)"/\1/p')" npmversion="$(cat package.json | jq -r .version)" +nixversion="$(cat default.nix | sed -n 's/.*version = "\(.*\)";/\1/p')" -if [ "$pkgversion" == "$npmversion" ] && [ "$pkgversion" == "$idrversion" ]; then +if [ "$pkgversion" == "$npmversion" ] && [ "$pkgversion" == "$idrversion" ] && [ "$pkgversion" == "$nixversion" ]; then exit 0 else - echo "Idris package manifest version (${pkgversion}), in-source version (${idrversion}) and NPM package version (${npmversion}) do not agree!" + echo "Idris package manifest version (${pkgversion}), in-source version (${idrversion}), NPM package version (${npmversion}), and Nix version (${nixversion}) do not agree!" exit 1 fi From 3c5bd6be660e97816aa14aeb74f69da9d9058d27 Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Fri, 1 Dec 2023 19:34:15 -0600 Subject: [PATCH 04/19] upate Makefile to run first step of a nix build --- Makefile | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b0deea8..259f06c 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ idris2-version = $(shell $(idris2) --version | sed -En 's/Idris 2, version ([^-] idris2-build = $(shell $(idris2) --version | sed -En 's/Idris 2, version [^-]+(.*)/\1/p') idris2-minor-version = $(shell echo ${idris2-version} | sed -En 's/0\.(.*)\../\1/p') -.PHONY: all build install package publish clean version +.PHONY: all build nix-build install package publish clean version all: build @@ -35,6 +35,12 @@ build: node_modules depends/idris-adds-${idris-adds-version} harmony: build +node2nix ?= nix run nixpkgs\#node2nix + +nix-build: + ${MAKE} clean + $(node2nix) -- --composition node2nix.nix -l + version: @(if [[ "${v}" == '' ]]; then echo "please set the 'v' variable."; exit 1; fi) sed -I '' "s/version = .*/version = ${v}/" ./harmony.ipkg From b48653413b5a3578d1d1d156d2c45942cf13bfac Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Fri, 1 Dec 2023 19:36:46 -0600 Subject: [PATCH 05/19] commit output of node2nix --- node-env.nix | 689 ++++++++++++++++++++++++++++++++++++++++++++++ node-packages.nix | 41 +++ node2nix.nix | 17 ++ 3 files changed, 747 insertions(+) create mode 100644 node-env.nix create mode 100644 node-packages.nix create mode 100644 node2nix.nix diff --git a/node-env.nix b/node-env.nix new file mode 100644 index 0000000..bc1e366 --- /dev/null +++ b/node-env.nix @@ -0,0 +1,689 @@ +# This file originates from node2nix + +{lib, stdenv, nodejs, python2, pkgs, libtool, runCommand, writeTextFile, writeShellScript}: + +let + # Workaround to cope with utillinux in Nixpkgs 20.09 and util-linux in Nixpkgs master + utillinux = if pkgs ? utillinux then pkgs.utillinux else pkgs.util-linux; + + python = if nodejs ? python then nodejs.python else python2; + + # Create a tar wrapper that filters all the 'Ignoring unknown extended header keyword' noise + tarWrapper = runCommand "tarWrapper" {} '' + mkdir -p $out/bin + + cat > $out/bin/tar <> $out/nix-support/hydra-build-products + ''; + }; + + # Common shell logic + installPackage = writeShellScript "install-package" '' + installPackage() { + local packageName=$1 src=$2 + + local strippedName + + local DIR=$PWD + cd $TMPDIR + + unpackFile $src + + # Make the base dir in which the target dependency resides first + mkdir -p "$(dirname "$DIR/$packageName")" + + if [ -f "$src" ] + then + # Figure out what directory has been unpacked + packageDir="$(find . -maxdepth 1 -type d | tail -1)" + + # Restore write permissions to make building work + find "$packageDir" -type d -exec chmod u+x {} \; + chmod -R u+w "$packageDir" + + # Move the extracted tarball into the output folder + mv "$packageDir" "$DIR/$packageName" + elif [ -d "$src" ] + then + # Get a stripped name (without hash) of the source directory. + # On old nixpkgs it's already set internally. + if [ -z "$strippedName" ] + then + strippedName="$(stripHash $src)" + fi + + # Restore write permissions to make building work + chmod -R u+w "$strippedName" + + # Move the extracted directory into the output folder + mv "$strippedName" "$DIR/$packageName" + fi + + # Change to the package directory to install dependencies + cd "$DIR/$packageName" + } + ''; + + # Bundle the dependencies of the package + # + # Only include dependencies if they don't exist. They may also be bundled in the package. + includeDependencies = {dependencies}: + lib.optionalString (dependencies != []) ( + '' + mkdir -p node_modules + cd node_modules + '' + + (lib.concatMapStrings (dependency: + '' + if [ ! -e "${dependency.packageName}" ]; then + ${composePackage dependency} + fi + '' + ) dependencies) + + '' + cd .. + '' + ); + + # Recursively composes the dependencies of a package + composePackage = { name, packageName, src, dependencies ? [], ... }@args: + builtins.addErrorContext "while evaluating node package '${packageName}'" '' + installPackage "${packageName}" "${src}" + ${includeDependencies { inherit dependencies; }} + cd .. + ${lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."} + ''; + + pinpointDependencies = {dependencies, production}: + let + pinpointDependenciesFromPackageJSON = writeTextFile { + name = "pinpointDependencies.js"; + text = '' + var fs = require('fs'); + var path = require('path'); + + function resolveDependencyVersion(location, name) { + if(location == process.env['NIX_STORE']) { + return null; + } else { + var dependencyPackageJSON = path.join(location, "node_modules", name, "package.json"); + + if(fs.existsSync(dependencyPackageJSON)) { + var dependencyPackageObj = JSON.parse(fs.readFileSync(dependencyPackageJSON)); + + if(dependencyPackageObj.name == name) { + return dependencyPackageObj.version; + } + } else { + return resolveDependencyVersion(path.resolve(location, ".."), name); + } + } + } + + function replaceDependencies(dependencies) { + if(typeof dependencies == "object" && dependencies !== null) { + for(var dependency in dependencies) { + var resolvedVersion = resolveDependencyVersion(process.cwd(), dependency); + + if(resolvedVersion === null) { + process.stderr.write("WARNING: cannot pinpoint dependency: "+dependency+", context: "+process.cwd()+"\n"); + } else { + dependencies[dependency] = resolvedVersion; + } + } + } + } + + /* Read the package.json configuration */ + var packageObj = JSON.parse(fs.readFileSync('./package.json')); + + /* Pinpoint all dependencies */ + replaceDependencies(packageObj.dependencies); + if(process.argv[2] == "development") { + replaceDependencies(packageObj.devDependencies); + } + else { + packageObj.devDependencies = {}; + } + replaceDependencies(packageObj.optionalDependencies); + replaceDependencies(packageObj.peerDependencies); + + /* Write the fixed package.json file */ + fs.writeFileSync("package.json", JSON.stringify(packageObj, null, 2)); + ''; + }; + in + '' + node ${pinpointDependenciesFromPackageJSON} ${if production then "production" else "development"} + + ${lib.optionalString (dependencies != []) + '' + if [ -d node_modules ] + then + cd node_modules + ${lib.concatMapStrings (dependency: pinpointDependenciesOfPackage dependency) dependencies} + cd .. + fi + ''} + ''; + + # Recursively traverses all dependencies of a package and pinpoints all + # dependencies in the package.json file to the versions that are actually + # being used. + + pinpointDependenciesOfPackage = { packageName, dependencies ? [], production ? true, ... }@args: + '' + if [ -d "${packageName}" ] + then + cd "${packageName}" + ${pinpointDependencies { inherit dependencies production; }} + cd .. + ${lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."} + fi + ''; + + # Extract the Node.js source code which is used to compile packages with + # native bindings + nodeSources = runCommand "node-sources" {} '' + tar --no-same-owner --no-same-permissions -xf ${nodejs.src} + mv node-* $out + ''; + + # Script that adds _integrity fields to all package.json files to prevent NPM from consulting the cache (that is empty) + addIntegrityFieldsScript = writeTextFile { + name = "addintegrityfields.js"; + text = '' + var fs = require('fs'); + var path = require('path'); + + function augmentDependencies(baseDir, dependencies) { + for(var dependencyName in dependencies) { + var dependency = dependencies[dependencyName]; + + // Open package.json and augment metadata fields + var packageJSONDir = path.join(baseDir, "node_modules", dependencyName); + var packageJSONPath = path.join(packageJSONDir, "package.json"); + + if(fs.existsSync(packageJSONPath)) { // Only augment packages that exist. Sometimes we may have production installs in which development dependencies can be ignored + console.log("Adding metadata fields to: "+packageJSONPath); + var packageObj = JSON.parse(fs.readFileSync(packageJSONPath)); + + if(dependency.integrity) { + packageObj["_integrity"] = dependency.integrity; + } else { + packageObj["_integrity"] = "sha1-000000000000000000000000000="; // When no _integrity string has been provided (e.g. by Git dependencies), add a dummy one. It does not seem to harm and it bypasses downloads. + } + + if(dependency.resolved) { + packageObj["_resolved"] = dependency.resolved; // Adopt the resolved property if one has been provided + } else { + packageObj["_resolved"] = dependency.version; // Set the resolved version to the version identifier. This prevents NPM from cloning Git repositories. + } + + if(dependency.from !== undefined) { // Adopt from property if one has been provided + packageObj["_from"] = dependency.from; + } + + fs.writeFileSync(packageJSONPath, JSON.stringify(packageObj, null, 2)); + } + + // Augment transitive dependencies + if(dependency.dependencies !== undefined) { + augmentDependencies(packageJSONDir, dependency.dependencies); + } + } + } + + if(fs.existsSync("./package-lock.json")) { + var packageLock = JSON.parse(fs.readFileSync("./package-lock.json")); + + if(![1, 2].includes(packageLock.lockfileVersion)) { + process.stderr.write("Sorry, I only understand lock file versions 1 and 2!\n"); + process.exit(1); + } + + if(packageLock.dependencies !== undefined) { + augmentDependencies(".", packageLock.dependencies); + } + } + ''; + }; + + # Reconstructs a package-lock file from the node_modules/ folder structure and package.json files with dummy sha1 hashes + reconstructPackageLock = writeTextFile { + name = "reconstructpackagelock.js"; + text = '' + var fs = require('fs'); + var path = require('path'); + + var packageObj = JSON.parse(fs.readFileSync("package.json")); + + var lockObj = { + name: packageObj.name, + version: packageObj.version, + lockfileVersion: 2, + requires: true, + packages: { + "": { + name: packageObj.name, + version: packageObj.version, + license: packageObj.license, + bin: packageObj.bin, + dependencies: packageObj.dependencies, + engines: packageObj.engines, + optionalDependencies: packageObj.optionalDependencies + } + }, + dependencies: {} + }; + + function augmentPackageJSON(filePath, packages, dependencies) { + var packageJSON = path.join(filePath, "package.json"); + if(fs.existsSync(packageJSON)) { + var packageObj = JSON.parse(fs.readFileSync(packageJSON)); + packages[filePath] = { + version: packageObj.version, + integrity: "sha1-000000000000000000000000000=", + dependencies: packageObj.dependencies, + engines: packageObj.engines, + optionalDependencies: packageObj.optionalDependencies + }; + dependencies[packageObj.name] = { + version: packageObj.version, + integrity: "sha1-000000000000000000000000000=", + dependencies: {} + }; + processDependencies(path.join(filePath, "node_modules"), packages, dependencies[packageObj.name].dependencies); + } + } + + function processDependencies(dir, packages, dependencies) { + if(fs.existsSync(dir)) { + var files = fs.readdirSync(dir); + + files.forEach(function(entry) { + var filePath = path.join(dir, entry); + var stats = fs.statSync(filePath); + + if(stats.isDirectory()) { + if(entry.substr(0, 1) == "@") { + // When we encounter a namespace folder, augment all packages belonging to the scope + var pkgFiles = fs.readdirSync(filePath); + + pkgFiles.forEach(function(entry) { + if(stats.isDirectory()) { + var pkgFilePath = path.join(filePath, entry); + augmentPackageJSON(pkgFilePath, packages, dependencies); + } + }); + } else { + augmentPackageJSON(filePath, packages, dependencies); + } + } + }); + } + } + + processDependencies("node_modules", lockObj.packages, lockObj.dependencies); + + fs.writeFileSync("package-lock.json", JSON.stringify(lockObj, null, 2)); + ''; + }; + + # Script that links bins defined in package.json to the node_modules bin directory + # NPM does not do this for top-level packages itself anymore as of v7 + linkBinsScript = writeTextFile { + name = "linkbins.js"; + text = '' + var fs = require('fs'); + var path = require('path'); + + var packageObj = JSON.parse(fs.readFileSync("package.json")); + + var nodeModules = Array(packageObj.name.split("/").length).fill("..").join(path.sep); + + if(packageObj.bin !== undefined) { + fs.mkdirSync(path.join(nodeModules, ".bin")) + + if(typeof packageObj.bin == "object") { + Object.keys(packageObj.bin).forEach(function(exe) { + if(fs.existsSync(packageObj.bin[exe])) { + console.log("linking bin '" + exe + "'"); + fs.symlinkSync( + path.join("..", packageObj.name, packageObj.bin[exe]), + path.join(nodeModules, ".bin", exe) + ); + } + else { + console.log("skipping non-existent bin '" + exe + "'"); + } + }) + } + else { + if(fs.existsSync(packageObj.bin)) { + console.log("linking bin '" + packageObj.bin + "'"); + fs.symlinkSync( + path.join("..", packageObj.name, packageObj.bin), + path.join(nodeModules, ".bin", packageObj.name.split("/").pop()) + ); + } + else { + console.log("skipping non-existent bin '" + packageObj.bin + "'"); + } + } + } + else if(packageObj.directories !== undefined && packageObj.directories.bin !== undefined) { + fs.mkdirSync(path.join(nodeModules, ".bin")) + + fs.readdirSync(packageObj.directories.bin).forEach(function(exe) { + if(fs.existsSync(path.join(packageObj.directories.bin, exe))) { + console.log("linking bin '" + exe + "'"); + fs.symlinkSync( + path.join("..", packageObj.name, packageObj.directories.bin, exe), + path.join(nodeModules, ".bin", exe) + ); + } + else { + console.log("skipping non-existent bin '" + exe + "'"); + } + }) + } + ''; + }; + + prepareAndInvokeNPM = {packageName, bypassCache, reconstructLock, npmFlags, production}: + let + forceOfflineFlag = if bypassCache then "--offline" else "--registry http://www.example.com"; + in + '' + # Pinpoint the versions of all dependencies to the ones that are actually being used + echo "pinpointing versions of dependencies..." + source $pinpointDependenciesScriptPath + + # Patch the shebangs of the bundled modules to prevent them from + # calling executables outside the Nix store as much as possible + patchShebangs . + + # Deploy the Node.js package by running npm install. Since the + # dependencies have been provided already by ourselves, it should not + # attempt to install them again, which is good, because we want to make + # it Nix's responsibility. If it needs to install any dependencies + # anyway (e.g. because the dependency parameters are + # incomplete/incorrect), it fails. + # + # The other responsibilities of NPM are kept -- version checks, build + # steps, postprocessing etc. + + export HOME=$TMPDIR + cd "${packageName}" + runHook preRebuild + + ${lib.optionalString bypassCache '' + ${lib.optionalString reconstructLock '' + if [ -f package-lock.json ] + then + echo "WARNING: Reconstruct lock option enabled, but a lock file already exists!" + echo "This will most likely result in version mismatches! We will remove the lock file and regenerate it!" + rm package-lock.json + else + echo "No package-lock.json file found, reconstructing..." + fi + + node ${reconstructPackageLock} + ''} + + node ${addIntegrityFieldsScript} + ''} + + npm ${forceOfflineFlag} --nodedir=${nodeSources} ${npmFlags} ${lib.optionalString production "--production"} rebuild + + runHook postRebuild + + if [ "''${dontNpmInstall-}" != "1" ] + then + # NPM tries to download packages even when they already exist if npm-shrinkwrap is used. + rm -f npm-shrinkwrap.json + + npm ${forceOfflineFlag} --nodedir=${nodeSources} --no-bin-links --ignore-scripts ${npmFlags} ${lib.optionalString production "--production"} install + fi + + # Link executables defined in package.json + node ${linkBinsScript} + ''; + + # Builds and composes an NPM package including all its dependencies + buildNodePackage = + { name + , packageName + , version ? null + , dependencies ? [] + , buildInputs ? [] + , production ? true + , npmFlags ? "" + , dontNpmInstall ? false + , bypassCache ? false + , reconstructLock ? false + , preRebuild ? "" + , dontStrip ? true + , unpackPhase ? "true" + , buildPhase ? "true" + , meta ? {} + , ... }@args: + + let + extraArgs = removeAttrs args [ "name" "dependencies" "buildInputs" "dontStrip" "dontNpmInstall" "preRebuild" "unpackPhase" "buildPhase" "meta" ]; + in + stdenv.mkDerivation ({ + name = "${name}${if version == null then "" else "-${version}"}"; + buildInputs = [ tarWrapper python nodejs ] + ++ lib.optional (stdenv.isLinux) utillinux + ++ lib.optional (stdenv.isDarwin) libtool + ++ buildInputs; + + inherit nodejs; + + inherit dontStrip; # Stripping may fail a build for some package deployments + inherit dontNpmInstall preRebuild unpackPhase buildPhase; + + compositionScript = composePackage args; + pinpointDependenciesScript = pinpointDependenciesOfPackage args; + + passAsFile = [ "compositionScript" "pinpointDependenciesScript" ]; + + installPhase = '' + source ${installPackage} + + # Create and enter a root node_modules/ folder + mkdir -p $out/lib/node_modules + cd $out/lib/node_modules + + # Compose the package and all its dependencies + source $compositionScriptPath + + ${prepareAndInvokeNPM { inherit packageName bypassCache reconstructLock npmFlags production; }} + + # Create symlink to the deployed executable folder, if applicable + if [ -d "$out/lib/node_modules/.bin" ] + then + ln -s $out/lib/node_modules/.bin $out/bin + + # Fixup all executables + ls $out/bin/* | while read i + do + file="$(readlink -f "$i")" + chmod u+rwx "$file" + if isScript "$file" + then + sed -i 's/\r$//' "$file" # convert crlf to lf + fi + done + fi + + # Create symlinks to the deployed manual page folders, if applicable + if [ -d "$out/lib/node_modules/${packageName}/man" ] + then + mkdir -p $out/share + for dir in "$out/lib/node_modules/${packageName}/man/"* + do + mkdir -p $out/share/man/$(basename "$dir") + for page in "$dir"/* + do + ln -s $page $out/share/man/$(basename "$dir") + done + done + fi + + # Run post install hook, if provided + runHook postInstall + ''; + + meta = { + # default to Node.js' platforms + platforms = nodejs.meta.platforms; + } // meta; + } // extraArgs); + + # Builds a node environment (a node_modules folder and a set of binaries) + buildNodeDependencies = + { name + , packageName + , version ? null + , src + , dependencies ? [] + , buildInputs ? [] + , production ? true + , npmFlags ? "" + , dontNpmInstall ? false + , bypassCache ? false + , reconstructLock ? false + , dontStrip ? true + , unpackPhase ? "true" + , buildPhase ? "true" + , ... }@args: + + let + extraArgs = removeAttrs args [ "name" "dependencies" "buildInputs" ]; + in + stdenv.mkDerivation ({ + name = "node-dependencies-${name}${if version == null then "" else "-${version}"}"; + + buildInputs = [ tarWrapper python nodejs ] + ++ lib.optional (stdenv.isLinux) utillinux + ++ lib.optional (stdenv.isDarwin) libtool + ++ buildInputs; + + inherit dontStrip; # Stripping may fail a build for some package deployments + inherit dontNpmInstall unpackPhase buildPhase; + + includeScript = includeDependencies { inherit dependencies; }; + pinpointDependenciesScript = pinpointDependenciesOfPackage args; + + passAsFile = [ "includeScript" "pinpointDependenciesScript" ]; + + installPhase = '' + source ${installPackage} + + mkdir -p $out/${packageName} + cd $out/${packageName} + + source $includeScriptPath + + # Create fake package.json to make the npm commands work properly + cp ${src}/package.json . + chmod 644 package.json + ${lib.optionalString bypassCache '' + if [ -f ${src}/package-lock.json ] + then + cp ${src}/package-lock.json . + chmod 644 package-lock.json + fi + ''} + + # Go to the parent folder to make sure that all packages are pinpointed + cd .. + ${lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."} + + ${prepareAndInvokeNPM { inherit packageName bypassCache reconstructLock npmFlags production; }} + + # Expose the executables that were installed + cd .. + ${lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."} + + mv ${packageName} lib + ln -s $out/lib/node_modules/.bin $out/bin + ''; + } // extraArgs); + + # Builds a development shell + buildNodeShell = + { name + , packageName + , version ? null + , src + , dependencies ? [] + , buildInputs ? [] + , production ? true + , npmFlags ? "" + , dontNpmInstall ? false + , bypassCache ? false + , reconstructLock ? false + , dontStrip ? true + , unpackPhase ? "true" + , buildPhase ? "true" + , ... }@args: + + let + nodeDependencies = buildNodeDependencies args; + extraArgs = removeAttrs args [ "name" "dependencies" "buildInputs" "dontStrip" "dontNpmInstall" "unpackPhase" "buildPhase" ]; + in + stdenv.mkDerivation ({ + name = "node-shell-${name}${if version == null then "" else "-${version}"}"; + + buildInputs = [ python nodejs ] ++ lib.optional (stdenv.isLinux) utillinux ++ buildInputs; + buildCommand = '' + mkdir -p $out/bin + cat > $out/bin/shell < { + inherit system; + }, system ? builtins.currentSystem, nodejs ? pkgs."nodejs_14"}: + +let + nodeEnv = import ./node-env.nix { + inherit (pkgs) stdenv lib python2 runCommand writeTextFile writeShellScript; + inherit pkgs nodejs; + libtool = if pkgs.stdenv.isDarwin then pkgs.darwin.cctools else null; + }; +in +import ./node-packages.nix { + inherit (pkgs) fetchurl nix-gitignore stdenv lib fetchgit; + inherit nodeEnv; +} From f5d89b696e61824ea275aab6eed0f65e3de86671 Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Fri, 1 Dec 2023 22:02:48 -0600 Subject: [PATCH 06/19] get things all the way through the build process --- .gitignore | 1 + Makefile | 16 +- default.nix | 36 ++- node-packages.nix | 766 +++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 813 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 07ac58e..7a6e930 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ harmony-npm.tar.gz .*.swp *.idr~ +result diff --git a/Makefile b/Makefile index 259f06c..ac10481 100644 --- a/Makefile +++ b/Makefile @@ -13,17 +13,26 @@ all: build depends/idris-adds-${idris-adds-version}: mkdir -p depends/idris-adds-${idris-adds-version} mkdir -p build/deps +ifeq ($(IDRIS_ADDS_SRC),) cd build/deps && \ git clone https://github.com/mattpolzin/idris-adds.git && \ cd idris-adds && \ git checkout ${idris-adds-version} && \ make && \ cp -R ./build/ttc/* ../../../depends/idris-adds-${idris-adds-version}/ +else + cd build/deps && \ + cp -R $(IDRIS_ADDS_SRC) ./idris-adds && \ + chmod -R +rw ./idris-adds && \ + cd idris-adds && \ + make && \ + cp -R ./build/ttc/* ../../../depends/idris-adds-${idris-adds-version}/ +endif -node_modules: +./node_modules/: package.json npm install -build: node_modules depends/idris-adds-${idris-adds-version} +build: ./node_modules/ depends/idris-adds-${idris-adds-version} IDRIS2_DATA=./support $(idris2) --build harmony.ipkg @if [[ ${idris2-minor-version} -gt 6 ]] || [[ "${idris2-build}" != '' ]]; then \ cp ./build/exec/harmony ./harmony; \ @@ -39,7 +48,8 @@ node2nix ?= nix run nixpkgs\#node2nix nix-build: ${MAKE} clean - $(node2nix) -- --composition node2nix.nix -l + $(node2nix) -- --composition node2nix.nix # -l # <- can't use -l for lockfile because lockfile version 3 not supported yet. + nix build . version: @(if [[ "${v}" == '' ]]; then echo "please set the 'v' variable."; exit 1; fi) diff --git a/default.nix b/default.nix index 0076832..212ddc1 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,41 @@ -{ stdenv }: +{ stdenv, callPackage, fetchFromGitHub, idris2 }: +let + nodeDependencies = (callPackage ./node2nix.nix {}).nodeDependencies; + idrisAddsVersion = "0.3.0"; + idrisAddsSrc = fetchFromGitHub { + owner = "mattpolzin"; + repo = "idris-adds"; + rev = "${idrisAddsVersion}"; + hash = "sha256-OSu381nUNZqFJs4HzmMxGda60k7xsa1GulQq7kU/R2o="; + }; +in stdenv.mkDerivation { pname = "harmony"; version = "2.6.1"; + buildInputs = [ idris2 ]; + src = ./.; + + buildPhase = '' + runHook preBuild + + ln -s ${nodeDependencies}/lib/node_modules ./node_modules + export PATH="${nodeDependencies}/bin:$PATH" + export IDRIS_ADDS_SRC="${idrisAddsSrc}" + + make build + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + mkdir -p $out/bin + cp harmony $out/bin/ + + runHook postInstall + ''; + } diff --git a/node-packages.nix b/node-packages.nix index 097a3d0..9f8c161 100644 --- a/node-packages.nix +++ b/node-packages.nix @@ -3,12 +3,774 @@ {nodeEnv, fetchurl, fetchgit, nix-gitignore, stdenv, lib, globalBuildInputs ? []}: let - sources = {}; + sources = { + "@kwsites/file-exists-1.1.1" = { + name = "_at_kwsites_slash_file-exists"; + packageName = "@kwsites/file-exists"; + version = "1.1.1"; + src = fetchurl { + url = "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz"; + sha512 = "m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw=="; + }; + }; + "@kwsites/promise-deferred-1.1.1" = { + name = "_at_kwsites_slash_promise-deferred"; + packageName = "@kwsites/promise-deferred"; + version = "1.1.1"; + src = fetchurl { + url = "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz"; + sha512 = "GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw=="; + }; + }; + "@octokit/app-13.1.8" = { + name = "_at_octokit_slash_app"; + packageName = "@octokit/app"; + version = "13.1.8"; + src = fetchurl { + url = "https://registry.npmjs.org/@octokit/app/-/app-13.1.8.tgz"; + sha512 = "bCncePMguVyFpdBbnceFKfmPOuUD94T189GuQ0l00ZcQ+mX4hyPqnaWJlsXE2HSdA71eV7p8GPDZ+ErplTkzow=="; + }; + }; + "@octokit/auth-app-4.0.13" = { + name = "_at_octokit_slash_auth-app"; + packageName = "@octokit/auth-app"; + version = "4.0.13"; + src = fetchurl { + url = "https://registry.npmjs.org/@octokit/auth-app/-/auth-app-4.0.13.tgz"; + sha512 = "NBQkmR/Zsc+8fWcVIFrwDgNXS7f4XDrkd9LHdi9DPQw1NdGHLviLzRO2ZBwTtepnwHXW5VTrVU9eFGijMUqllg=="; + }; + }; + "@octokit/auth-oauth-app-5.0.6" = { + name = "_at_octokit_slash_auth-oauth-app"; + packageName = "@octokit/auth-oauth-app"; + version = "5.0.6"; + src = fetchurl { + url = "https://registry.npmjs.org/@octokit/auth-oauth-app/-/auth-oauth-app-5.0.6.tgz"; + sha512 = "SxyfIBfeFcWd9Z/m1xa4LENTQ3l1y6Nrg31k2Dcb1jS5ov7pmwMJZ6OGX8q3K9slRgVpeAjNA1ipOAMHkieqyw=="; + }; + }; + "@octokit/auth-oauth-device-4.0.5" = { + name = "_at_octokit_slash_auth-oauth-device"; + packageName = "@octokit/auth-oauth-device"; + version = "4.0.5"; + src = fetchurl { + url = "https://registry.npmjs.org/@octokit/auth-oauth-device/-/auth-oauth-device-4.0.5.tgz"; + sha512 = "XyhoWRTzf2ZX0aZ52a6Ew5S5VBAfwwx1QnC2Np6Et3MWQpZjlREIcbcvVZtkNuXp6Z9EeiSLSDUqm3C+aMEHzQ=="; + }; + }; + "@octokit/auth-oauth-user-2.1.2" = { + name = "_at_octokit_slash_auth-oauth-user"; + packageName = "@octokit/auth-oauth-user"; + version = "2.1.2"; + src = fetchurl { + url = "https://registry.npmjs.org/@octokit/auth-oauth-user/-/auth-oauth-user-2.1.2.tgz"; + sha512 = "kkRqNmFe7s5GQcojE3nSlF+AzYPpPv7kvP/xYEnE57584pixaFBH8Vovt+w5Y3E4zWUEOxjdLItmBTFAWECPAg=="; + }; + }; + "@octokit/auth-token-3.0.4" = { + name = "_at_octokit_slash_auth-token"; + packageName = "@octokit/auth-token"; + version = "3.0.4"; + src = fetchurl { + url = "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.4.tgz"; + sha512 = "TWFX7cZF2LXoCvdmJWY7XVPi74aSY0+FfBZNSXEXFkMpjcqsQwDSYVv5FhRFaI0V1ECnwbz4j59T/G+rXNWaIQ=="; + }; + }; + "@octokit/auth-unauthenticated-3.0.5" = { + name = "_at_octokit_slash_auth-unauthenticated"; + packageName = "@octokit/auth-unauthenticated"; + version = "3.0.5"; + src = fetchurl { + url = "https://registry.npmjs.org/@octokit/auth-unauthenticated/-/auth-unauthenticated-3.0.5.tgz"; + sha512 = "yH2GPFcjrTvDWPwJWWCh0tPPtTL5SMgivgKPA+6v/XmYN6hGQkAto8JtZibSKOpf8ipmeYhLNWQ2UgW0GYILCw=="; + }; + }; + "@octokit/core-4.2.4" = { + name = "_at_octokit_slash_core"; + packageName = "@octokit/core"; + version = "4.2.4"; + src = fetchurl { + url = "https://registry.npmjs.org/@octokit/core/-/core-4.2.4.tgz"; + sha512 = "rYKilwgzQ7/imScn3M9/pFfUf4I1AZEH3KhyJmtPdE2zfaXAn2mFfUy4FbKewzc2We5y/LlKLj36fWJLKC2SIQ=="; + }; + }; + "@octokit/endpoint-7.0.6" = { + name = "_at_octokit_slash_endpoint"; + packageName = "@octokit/endpoint"; + version = "7.0.6"; + src = fetchurl { + url = "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.6.tgz"; + sha512 = "5L4fseVRUsDFGR00tMWD/Trdeeihn999rTMGRMC1G/Ldi1uWlWJzI98H4Iak5DB/RVvQuyMYKqSK/R6mbSOQyg=="; + }; + }; + "@octokit/graphql-5.0.6" = { + name = "_at_octokit_slash_graphql"; + packageName = "@octokit/graphql"; + version = "5.0.6"; + src = fetchurl { + url = "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.6.tgz"; + sha512 = "Fxyxdy/JH0MnIB5h+UQ3yCoh1FG4kWXfFKkpWqjZHw/p+Kc8Y44Hu/kCgNBT6nU1shNumEchmW/sUO1JuQnPcw=="; + }; + }; + "@octokit/oauth-app-4.2.4" = { + name = "_at_octokit_slash_oauth-app"; + packageName = "@octokit/oauth-app"; + version = "4.2.4"; + src = fetchurl { + url = "https://registry.npmjs.org/@octokit/oauth-app/-/oauth-app-4.2.4.tgz"; + sha512 = "iuOVFrmm5ZKNavRtYu5bZTtmlKLc5uVgpqTfMEqYYf2OkieV6VdxKZAb5qLVdEPL8LU2lMWcGpavPBV835cgoA=="; + }; + }; + "@octokit/oauth-authorization-url-5.0.0" = { + name = "_at_octokit_slash_oauth-authorization-url"; + packageName = "@octokit/oauth-authorization-url"; + version = "5.0.0"; + src = fetchurl { + url = "https://registry.npmjs.org/@octokit/oauth-authorization-url/-/oauth-authorization-url-5.0.0.tgz"; + sha512 = "y1WhN+ERDZTh0qZ4SR+zotgsQUE1ysKnvBt1hvDRB2WRzYtVKQjn97HEPzoehh66Fj9LwNdlZh+p6TJatT0zzg=="; + }; + }; + "@octokit/oauth-methods-2.0.6" = { + name = "_at_octokit_slash_oauth-methods"; + packageName = "@octokit/oauth-methods"; + version = "2.0.6"; + src = fetchurl { + url = "https://registry.npmjs.org/@octokit/oauth-methods/-/oauth-methods-2.0.6.tgz"; + sha512 = "l9Uml2iGN2aTWLZcm8hV+neBiFXAQ9+3sKiQe/sgumHlL6HDg0AQ8/l16xX/5jJvfxueqTW5CWbzd0MjnlfHZw=="; + }; + }; + "@octokit/openapi-types-18.1.1" = { + name = "_at_octokit_slash_openapi-types"; + packageName = "@octokit/openapi-types"; + version = "18.1.1"; + src = fetchurl { + url = "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-18.1.1.tgz"; + sha512 = "VRaeH8nCDtF5aXWnjPuEMIYf1itK/s3JYyJcWFJT8X9pSNnBtriDf7wlEWsGuhPLl4QIH4xM8fqTXDwJ3Mu6sw=="; + }; + }; + "@octokit/plugin-paginate-rest-6.1.2" = { + name = "_at_octokit_slash_plugin-paginate-rest"; + packageName = "@octokit/plugin-paginate-rest"; + version = "6.1.2"; + src = fetchurl { + url = "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-6.1.2.tgz"; + sha512 = "qhrmtQeHU/IivxucOV1bbI/xZyC/iOBhclokv7Sut5vnejAIAEXVcGQeRpQlU39E0WwK9lNvJHphHri/DB6lbQ=="; + }; + }; + "@octokit/plugin-rest-endpoint-methods-7.2.3" = { + name = "_at_octokit_slash_plugin-rest-endpoint-methods"; + packageName = "@octokit/plugin-rest-endpoint-methods"; + version = "7.2.3"; + src = fetchurl { + url = "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-7.2.3.tgz"; + sha512 = "I5Gml6kTAkzVlN7KCtjOM+Ruwe/rQppp0QU372K1GP7kNOYEKe8Xn5BW4sE62JAHdwpq95OQK/qGNyKQMUzVgA=="; + }; + }; + "@octokit/plugin-retry-4.1.6" = { + name = "_at_octokit_slash_plugin-retry"; + packageName = "@octokit/plugin-retry"; + version = "4.1.6"; + src = fetchurl { + url = "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-4.1.6.tgz"; + sha512 = "obkYzIgEC75r8+9Pnfiiqy3y/x1bc3QLE5B7qvv9wi9Kj0R5tGQFC6QMBg1154WQ9lAVypuQDGyp3hNpp15gQQ=="; + }; + }; + "@octokit/plugin-throttling-5.2.3" = { + name = "_at_octokit_slash_plugin-throttling"; + packageName = "@octokit/plugin-throttling"; + version = "5.2.3"; + src = fetchurl { + url = "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-5.2.3.tgz"; + sha512 = "C9CFg9mrf6cugneKiaI841iG8DOv6P5XXkjmiNNut+swePxQ7RWEdAZRp5rJoE1hjsIqiYcKa/ZkOQ+ujPI39Q=="; + }; + }; + "@octokit/request-6.2.8" = { + name = "_at_octokit_slash_request"; + packageName = "@octokit/request"; + version = "6.2.8"; + src = fetchurl { + url = "https://registry.npmjs.org/@octokit/request/-/request-6.2.8.tgz"; + sha512 = "ow4+pkVQ+6XVVsekSYBzJC0VTVvh/FCTUUgTsboGq+DTeWdyIFV8WSCdo0RIxk6wSkBTHqIK1mYuY7nOBXOchw=="; + }; + }; + "@octokit/request-error-3.0.3" = { + name = "_at_octokit_slash_request-error"; + packageName = "@octokit/request-error"; + version = "3.0.3"; + src = fetchurl { + url = "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.3.tgz"; + sha512 = "crqw3V5Iy2uOU5Np+8M/YexTlT8zxCfI+qu+LxUB7SZpje4Qmx3mub5DfEKSO8Ylyk0aogi6TYdf6kxzh2BguQ=="; + }; + }; + "@octokit/tsconfig-1.0.2" = { + name = "_at_octokit_slash_tsconfig"; + packageName = "@octokit/tsconfig"; + version = "1.0.2"; + src = fetchurl { + url = "https://registry.npmjs.org/@octokit/tsconfig/-/tsconfig-1.0.2.tgz"; + sha512 = "I0vDR0rdtP8p2lGMzvsJzbhdOWy405HcGovrspJ8RRibHnyRgggUSNO5AIox5LmqiwmatHKYsvj6VGFHkqS7lA=="; + }; + }; + "@octokit/types-10.0.0" = { + name = "_at_octokit_slash_types"; + packageName = "@octokit/types"; + version = "10.0.0"; + src = fetchurl { + url = "https://registry.npmjs.org/@octokit/types/-/types-10.0.0.tgz"; + sha512 = "Vm8IddVmhCgU1fxC1eyinpwqzXPEYu0NrYzD3YZjlGjyftdLBTeqNblRC0jmJmgxbJIsQlyogVeGnrNaaMVzIg=="; + }; + }; + "@octokit/types-9.3.2" = { + name = "_at_octokit_slash_types"; + packageName = "@octokit/types"; + version = "9.3.2"; + src = fetchurl { + url = "https://registry.npmjs.org/@octokit/types/-/types-9.3.2.tgz"; + sha512 = "D4iHGTdAnEEVsB8fl95m1hiz7D5YiRdQ9b/OEb3BYRVwbLsGHcRVPz+u+BgRLNk0Q0/4iZCBqDN96j2XNxfXrA=="; + }; + }; + "@octokit/webhooks-10.9.2" = { + name = "_at_octokit_slash_webhooks"; + packageName = "@octokit/webhooks"; + version = "10.9.2"; + src = fetchurl { + url = "https://registry.npmjs.org/@octokit/webhooks/-/webhooks-10.9.2.tgz"; + sha512 = "hFVF/szz4l/Y/GQdKxNmQjUke0XJXK986p+ucIlubTGVPVtVtup5G1jarQfvCMBs9Fvlf9dvH8K83E4lefmofQ=="; + }; + }; + "@octokit/webhooks-methods-3.0.3" = { + name = "_at_octokit_slash_webhooks-methods"; + packageName = "@octokit/webhooks-methods"; + version = "3.0.3"; + src = fetchurl { + url = "https://registry.npmjs.org/@octokit/webhooks-methods/-/webhooks-methods-3.0.3.tgz"; + sha512 = "2vM+DCNTJ5vL62O5LagMru6XnYhV4fJslK+5YUkTa6rWlW2S+Tqs1lF9Wr9OGqHfVwpBj3TeztWfVON/eUoW1Q=="; + }; + }; + "@octokit/webhooks-types-6.11.0" = { + name = "_at_octokit_slash_webhooks-types"; + packageName = "@octokit/webhooks-types"; + version = "6.11.0"; + src = fetchurl { + url = "https://registry.npmjs.org/@octokit/webhooks-types/-/webhooks-types-6.11.0.tgz"; + sha512 = "AanzbulOHljrku1NGfafxdpTCfw2ENaWzH01N2vqQM+cUFbk868Cgh0xylz0JIM9BoKbfI++bdD6EYX0Q/UTEw=="; + }; + }; + "@types/aws-lambda-8.10.130" = { + name = "_at_types_slash_aws-lambda"; + packageName = "@types/aws-lambda"; + version = "8.10.130"; + src = fetchurl { + url = "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.130.tgz"; + sha512 = "HxTfLeGvD1wTJqIGwcBCpNmHKenja+We1e0cuzeIDFfbEj3ixnlTInyPR/81zAe0Ss/Ip12rFK6XNeMLVucOSg=="; + }; + }; + "@types/btoa-lite-1.0.2" = { + name = "_at_types_slash_btoa-lite"; + packageName = "@types/btoa-lite"; + version = "1.0.2"; + src = fetchurl { + url = "https://registry.npmjs.org/@types/btoa-lite/-/btoa-lite-1.0.2.tgz"; + sha512 = "ZYbcE2x7yrvNFJiU7xJGrpF/ihpkM7zKgw8bha3LNJSesvTtUNxbpzaT7WXBIryf6jovisrxTBvymxMeLLj1Mg=="; + }; + }; + "@types/jsonwebtoken-9.0.5" = { + name = "_at_types_slash_jsonwebtoken"; + packageName = "@types/jsonwebtoken"; + version = "9.0.5"; + src = fetchurl { + url = "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.5.tgz"; + sha512 = "VRLSGzik+Unrup6BsouBeHsf4d1hOEgYWTm/7Nmw1sXoN1+tRly/Gy/po3yeahnP4jfnQWWAhQAqcNfH7ngOkA=="; + }; + }; + "@types/node-20.10.2" = { + name = "_at_types_slash_node"; + packageName = "@types/node"; + version = "20.10.2"; + src = fetchurl { + url = "https://registry.npmjs.org/@types/node/-/node-20.10.2.tgz"; + sha512 = "37MXfxkb0vuIlRKHNxwCkb60PNBpR94u4efQuN4JgIAm66zfCDXGSAFCef9XUWFovX2R1ok6Z7MHhtdVXXkkIw=="; + }; + }; + "aggregate-error-3.1.0" = { + name = "aggregate-error"; + packageName = "aggregate-error"; + version = "3.1.0"; + src = fetchurl { + url = "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz"; + sha512 = "4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA=="; + }; + }; + "before-after-hook-2.2.3" = { + name = "before-after-hook"; + packageName = "before-after-hook"; + version = "2.2.3"; + src = fetchurl { + url = "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz"; + sha512 = "NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="; + }; + }; + "bottleneck-2.19.5" = { + name = "bottleneck"; + packageName = "bottleneck"; + version = "2.19.5"; + src = fetchurl { + url = "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz"; + sha512 = "VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw=="; + }; + }; + "btoa-lite-1.0.0" = { + name = "btoa-lite"; + packageName = "btoa-lite"; + version = "1.0.0"; + src = fetchurl { + url = "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz"; + sha512 = "gvW7InbIyF8AicrqWoptdW08pUxuhq8BEgowNajy9RhiE86fmGAGl+bLKo6oB8QP0CkqHLowfN0oJdKC/J6LbA=="; + }; + }; + "buffer-equal-constant-time-1.0.1" = { + name = "buffer-equal-constant-time"; + packageName = "buffer-equal-constant-time"; + version = "1.0.1"; + src = fetchurl { + url = "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz"; + sha512 = "zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="; + }; + }; + "clean-stack-2.2.0" = { + name = "clean-stack"; + packageName = "clean-stack"; + version = "2.2.0"; + src = fetchurl { + url = "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz"; + sha512 = "4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A=="; + }; + }; + "debug-4.3.4" = { + name = "debug"; + packageName = "debug"; + version = "4.3.4"; + src = fetchurl { + url = "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz"; + sha512 = "PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ=="; + }; + }; + "deprecation-2.3.1" = { + name = "deprecation"; + packageName = "deprecation"; + version = "2.3.1"; + src = fetchurl { + url = "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz"; + sha512 = "xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="; + }; + }; + "ecdsa-sig-formatter-1.0.11" = { + name = "ecdsa-sig-formatter"; + packageName = "ecdsa-sig-formatter"; + version = "1.0.11"; + src = fetchurl { + url = "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz"; + sha512 = "nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="; + }; + }; + "encoding-0.1.13" = { + name = "encoding"; + packageName = "encoding"; + version = "0.1.13"; + src = fetchurl { + url = "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz"; + sha512 = "ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A=="; + }; + }; + "fromentries-1.3.2" = { + name = "fromentries"; + packageName = "fromentries"; + version = "1.3.2"; + src = fetchurl { + url = "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz"; + sha512 = "cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg=="; + }; + }; + "iconv-lite-0.6.3" = { + name = "iconv-lite"; + packageName = "iconv-lite"; + version = "0.6.3"; + src = fetchurl { + url = "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz"; + sha512 = "4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="; + }; + }; + "indent-string-4.0.0" = { + name = "indent-string"; + packageName = "indent-string"; + version = "4.0.0"; + src = fetchurl { + url = "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz"; + sha512 = "EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="; + }; + }; + "is-plain-object-5.0.0" = { + name = "is-plain-object"; + packageName = "is-plain-object"; + version = "5.0.0"; + src = fetchurl { + url = "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz"; + sha512 = "VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="; + }; + }; + "jsonwebtoken-9.0.2" = { + name = "jsonwebtoken"; + packageName = "jsonwebtoken"; + version = "9.0.2"; + src = fetchurl { + url = "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz"; + sha512 = "PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ=="; + }; + }; + "jwa-1.4.1" = { + name = "jwa"; + packageName = "jwa"; + version = "1.4.1"; + src = fetchurl { + url = "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz"; + sha512 = "qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA=="; + }; + }; + "jws-3.2.2" = { + name = "jws"; + packageName = "jws"; + version = "3.2.2"; + src = fetchurl { + url = "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz"; + sha512 = "YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA=="; + }; + }; + "lodash.includes-4.3.0" = { + name = "lodash.includes"; + packageName = "lodash.includes"; + version = "4.3.0"; + src = fetchurl { + url = "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz"; + sha512 = "W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w=="; + }; + }; + "lodash.isboolean-3.0.3" = { + name = "lodash.isboolean"; + packageName = "lodash.isboolean"; + version = "3.0.3"; + src = fetchurl { + url = "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz"; + sha512 = "Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg=="; + }; + }; + "lodash.isinteger-4.0.4" = { + name = "lodash.isinteger"; + packageName = "lodash.isinteger"; + version = "4.0.4"; + src = fetchurl { + url = "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz"; + sha512 = "DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA=="; + }; + }; + "lodash.isnumber-3.0.3" = { + name = "lodash.isnumber"; + packageName = "lodash.isnumber"; + version = "3.0.3"; + src = fetchurl { + url = "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz"; + sha512 = "QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw=="; + }; + }; + "lodash.isplainobject-4.0.6" = { + name = "lodash.isplainobject"; + packageName = "lodash.isplainobject"; + version = "4.0.6"; + src = fetchurl { + url = "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz"; + sha512 = "oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="; + }; + }; + "lodash.isstring-4.0.1" = { + name = "lodash.isstring"; + packageName = "lodash.isstring"; + version = "4.0.1"; + src = fetchurl { + url = "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz"; + sha512 = "0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw=="; + }; + }; + "lodash.once-4.1.1" = { + name = "lodash.once"; + packageName = "lodash.once"; + version = "4.1.1"; + src = fetchurl { + url = "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz"; + sha512 = "Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="; + }; + }; + "lru-cache-6.0.0" = { + name = "lru-cache"; + packageName = "lru-cache"; + version = "6.0.0"; + src = fetchurl { + url = "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz"; + sha512 = "Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="; + }; + }; + "lru-cache-9.1.2" = { + name = "lru-cache"; + packageName = "lru-cache"; + version = "9.1.2"; + src = fetchurl { + url = "https://registry.npmjs.org/lru-cache/-/lru-cache-9.1.2.tgz"; + sha512 = "ERJq3FOzJTxBbFjZ7iDs+NiK4VI9Wz+RdrrAB8dio1oV+YvdPzUEE4QNiT2VD51DkIbCYRUUzCRkssXCHqSnKQ=="; + }; + }; + "ms-2.1.2" = { + name = "ms"; + packageName = "ms"; + version = "2.1.2"; + src = fetchurl { + url = "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"; + sha512 = "sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="; + }; + }; + "ms-2.1.3" = { + name = "ms"; + packageName = "ms"; + version = "2.1.3"; + src = fetchurl { + url = "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"; + sha512 = "6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="; + }; + }; + "node-fetch-2.7.0" = { + name = "node-fetch"; + packageName = "node-fetch"; + version = "2.7.0"; + src = fetchurl { + url = "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz"; + sha512 = "c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="; + }; + }; + "octokit-2.1.0" = { + name = "octokit"; + packageName = "octokit"; + version = "2.1.0"; + src = fetchurl { + url = "https://registry.npmjs.org/octokit/-/octokit-2.1.0.tgz"; + sha512 = "Pxi6uKTjBRZWgAwsw1NgHdRlL+QASCN35OYS7X79o7PtBME0CLXEroZmPtEwlWZbPTP+iDbEy2wCbSOgm0uGIQ=="; + }; + }; + "once-1.4.0" = { + name = "once"; + packageName = "once"; + version = "1.4.0"; + src = fetchurl { + url = "https://registry.npmjs.org/once/-/once-1.4.0.tgz"; + sha512 = "lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="; + }; + }; + "safe-buffer-5.2.1" = { + name = "safe-buffer"; + packageName = "safe-buffer"; + version = "5.2.1"; + src = fetchurl { + url = "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz"; + sha512 = "rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="; + }; + }; + "safer-buffer-2.1.2" = { + name = "safer-buffer"; + packageName = "safer-buffer"; + version = "2.1.2"; + src = fetchurl { + url = "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz"; + sha512 = "YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="; + }; + }; + "semver-7.5.4" = { + name = "semver"; + packageName = "semver"; + version = "7.5.4"; + src = fetchurl { + url = "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz"; + sha512 = "1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA=="; + }; + }; + "simple-git-3.21.0" = { + name = "simple-git"; + packageName = "simple-git"; + version = "3.21.0"; + src = fetchurl { + url = "https://registry.npmjs.org/simple-git/-/simple-git-3.21.0.tgz"; + sha512 = "oTzw9248AF5bDTMk9MrxsRzEzivMlY+DWH0yWS4VYpMhNLhDWnN06pCtaUyPnqv/FpsdeNmRqmZugMABHRPdDA=="; + }; + }; + "tr46-0.0.3" = { + name = "tr46"; + packageName = "tr46"; + version = "0.0.3"; + src = fetchurl { + url = "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz"; + sha512 = "N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="; + }; + }; + "undici-types-5.26.5" = { + name = "undici-types"; + packageName = "undici-types"; + version = "5.26.5"; + src = fetchurl { + url = "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz"; + sha512 = "JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="; + }; + }; + "universal-github-app-jwt-1.1.1" = { + name = "universal-github-app-jwt"; + packageName = "universal-github-app-jwt"; + version = "1.1.1"; + src = fetchurl { + url = "https://registry.npmjs.org/universal-github-app-jwt/-/universal-github-app-jwt-1.1.1.tgz"; + sha512 = "G33RTLrIBMFmlDV4u4CBF7dh71eWwykck4XgaxaIVeZKOYZRAAxvcGMRFTUclVY6xoUPQvO4Ne5wKGxYm/Yy9w=="; + }; + }; + "universal-user-agent-6.0.1" = { + name = "universal-user-agent"; + packageName = "universal-user-agent"; + version = "6.0.1"; + src = fetchurl { + url = "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz"; + sha512 = "yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="; + }; + }; + "webidl-conversions-3.0.1" = { + name = "webidl-conversions"; + packageName = "webidl-conversions"; + version = "3.0.1"; + src = fetchurl { + url = "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz"; + sha512 = "2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="; + }; + }; + "whatwg-url-5.0.0" = { + name = "whatwg-url"; + packageName = "whatwg-url"; + version = "5.0.0"; + src = fetchurl { + url = "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz"; + sha512 = "saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="; + }; + }; + "wrappy-1.0.2" = { + name = "wrappy"; + packageName = "wrappy"; + version = "1.0.2"; + src = fetchurl { + url = "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"; + sha512 = "l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="; + }; + }; + "yallist-4.0.0" = { + name = "yallist"; + packageName = "yallist"; + version = "4.0.0"; + src = fetchurl { + url = "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz"; + sha512 = "3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="; + }; + }; + }; args = { name = "_at_mattpolzin_slash_harmony"; packageName = "@mattpolzin/harmony"; version = "2.6.1"; src = ./.; + dependencies = [ + sources."@kwsites/file-exists-1.1.1" + sources."@kwsites/promise-deferred-1.1.1" + sources."@octokit/app-13.1.8" + sources."@octokit/auth-app-4.0.13" + sources."@octokit/auth-oauth-app-5.0.6" + sources."@octokit/auth-oauth-device-4.0.5" + sources."@octokit/auth-oauth-user-2.1.2" + sources."@octokit/auth-token-3.0.4" + sources."@octokit/auth-unauthenticated-3.0.5" + sources."@octokit/core-4.2.4" + sources."@octokit/endpoint-7.0.6" + sources."@octokit/graphql-5.0.6" + sources."@octokit/oauth-app-4.2.4" + sources."@octokit/oauth-authorization-url-5.0.0" + sources."@octokit/oauth-methods-2.0.6" + sources."@octokit/openapi-types-18.1.1" + sources."@octokit/plugin-paginate-rest-6.1.2" + (sources."@octokit/plugin-rest-endpoint-methods-7.2.3" // { + dependencies = [ + sources."@octokit/types-10.0.0" + ]; + }) + sources."@octokit/plugin-retry-4.1.6" + sources."@octokit/plugin-throttling-5.2.3" + sources."@octokit/request-6.2.8" + sources."@octokit/request-error-3.0.3" + sources."@octokit/tsconfig-1.0.2" + sources."@octokit/types-9.3.2" + sources."@octokit/webhooks-10.9.2" + sources."@octokit/webhooks-methods-3.0.3" + sources."@octokit/webhooks-types-6.11.0" + sources."@types/aws-lambda-8.10.130" + sources."@types/btoa-lite-1.0.2" + sources."@types/jsonwebtoken-9.0.5" + sources."@types/node-20.10.2" + sources."aggregate-error-3.1.0" + sources."before-after-hook-2.2.3" + sources."bottleneck-2.19.5" + sources."btoa-lite-1.0.0" + sources."buffer-equal-constant-time-1.0.1" + sources."clean-stack-2.2.0" + (sources."debug-4.3.4" // { + dependencies = [ + sources."ms-2.1.2" + ]; + }) + sources."deprecation-2.3.1" + sources."ecdsa-sig-formatter-1.0.11" + sources."encoding-0.1.13" + sources."fromentries-1.3.2" + sources."iconv-lite-0.6.3" + sources."indent-string-4.0.0" + sources."is-plain-object-5.0.0" + sources."jsonwebtoken-9.0.2" + sources."jwa-1.4.1" + sources."jws-3.2.2" + sources."lodash.includes-4.3.0" + sources."lodash.isboolean-3.0.3" + sources."lodash.isinteger-4.0.4" + sources."lodash.isnumber-3.0.3" + sources."lodash.isplainobject-4.0.6" + sources."lodash.isstring-4.0.1" + sources."lodash.once-4.1.1" + sources."lru-cache-9.1.2" + sources."ms-2.1.3" + sources."node-fetch-2.7.0" + sources."octokit-2.1.0" + sources."once-1.4.0" + sources."safe-buffer-5.2.1" + sources."safer-buffer-2.1.2" + (sources."semver-7.5.4" // { + dependencies = [ + sources."lru-cache-6.0.0" + ]; + }) + sources."simple-git-3.21.0" + sources."tr46-0.0.3" + sources."undici-types-5.26.5" + sources."universal-github-app-jwt-1.1.1" + sources."universal-user-agent-6.0.1" + sources."webidl-conversions-3.0.1" + sources."whatwg-url-5.0.0" + sources."wrappy-1.0.2" + sources."yallist-4.0.0" + ]; buildInputs = globalBuildInputs; meta = { description = "Instill harmony between GitHub collaborators."; @@ -17,7 +779,7 @@ let }; production = true; bypassCache = true; - reconstructLock = false; + reconstructLock = true; }; in { From c017ccfed9fc70e4d6fe1a6fbd392ed366d558a2 Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Fri, 1 Dec 2023 23:20:06 -0600 Subject: [PATCH 07/19] final tweaks to get that working --- Makefile | 2 +- default.nix | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index ac10481..837e14c 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ build: ./node_modules/ depends/idris-adds-${idris-adds-version} @if [[ ${idris2-minor-version} -gt 6 ]] || [[ "${idris2-build}" != '' ]]; then \ cp ./build/exec/harmony ./harmony; \ else \ - echo "#!/usr/bin/env node\n" > ./harmony; \ + echo "#!/usr/bin/env node" > ./harmony; \ cat ./build/exec/harmony >> ./harmony; \ fi @chmod +x ./harmony diff --git a/default.nix b/default.nix index 212ddc1..d0eb0dc 100644 --- a/default.nix +++ b/default.nix @@ -1,6 +1,6 @@ -{ stdenv, callPackage, fetchFromGitHub, idris2 }: +{ stdenv, lib, callPackage, fetchFromGitHub, idris2, makeWrapper, nodejs }: let - nodeDependencies = (callPackage ./node2nix.nix {}).nodeDependencies; + nodeDependencies = (callPackage ./node2nix.nix { inherit nodejs; }).nodeDependencies; idrisAddsVersion = "0.3.0"; idrisAddsSrc = fetchFromGitHub { owner = "mattpolzin"; @@ -13,7 +13,8 @@ stdenv.mkDerivation { pname = "harmony"; version = "2.6.1"; - buildInputs = [ idris2 ]; + nativeBuildInputs = [ idris2 makeWrapper ]; + buildInputs = [ nodejs ]; src = ./.; @@ -35,6 +36,10 @@ stdenv.mkDerivation { mkdir -p $out/bin cp harmony $out/bin/ + wrapProgram $out/bin/harmony \ + --prefix PATH : ${lib.makeBinPath [ nodeDependencies ]} \ + --prefix NODE_PATH : ${nodeDependencies}/lib/node_modules + runHook postInstall ''; From edaeb9e77d6f668b2e8604694ac2df4cd30b3795 Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Fri, 1 Dec 2023 23:28:11 -0600 Subject: [PATCH 08/19] Add Nix Flake to README --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index fb27965..5291eba 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,18 @@ You can install Harmony via npm directly by running `npm install -g @mattpolzin/ ### GitHub Release You can install any Harmony release by downloading the `harmony-npm.tar.gz` file from the GitHub Release page, unzipping it, and running `npm install --global`. +### Nix Flake +You can add Harmony to your Flake inputs as follows: +```nix + inputs = { + ... + harmony.url = "github:mattpolzin/harmony"; + harmony.inputs.nixpkgs.follows = "nixpkgs"; + }; +``` + +Then in your outputs, being Harmony into a package install list as `harmony.packages..harmony`. + ### From Source The build script assumes a HEAD build of Idris 2 is installed on your system. For an alternative, see the [Docker Build](#docker-build) instructions below. From 4a1612dfd4075caf4847f5dedfdc181def5c82c8 Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Fri, 1 Dec 2023 23:36:15 -0600 Subject: [PATCH 09/19] Add README note about running with Nix directly --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5291eba..4137b2c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,10 @@ Harmony is a small tool that helps teams keep GitHub reviews running smoothly. I ## Dependencies ### Runtime -Running Harmony only requires NodeJS 14+ (and a local installation of `git`). +Running Harmony requires NodeJS 14+ (and a local installation of `git`) or alternatively Nix with flakes enabled. + +If you'd like to try Harmony out without even "installing" it and you have Nix installed with flakes enabled, you can run it as `nix run github:mattpolzin/harmony`. + ### Build time Building the latest commits of Harmony requires a HEAD build of the Idris 2 compiler. Each release page also indicates the version of Idris 2 that particular release will build against. From 2d65269c3ac06b760320d41abf80926bb86f8abb Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Sat, 2 Dec 2023 08:48:18 -0600 Subject: [PATCH 10/19] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4137b2c..e384e0b 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ You can add Harmony to your Flake inputs as follows: }; ``` -Then in your outputs, being Harmony into a package install list as `harmony.packages..harmony`. +Then, in your outputs, bring Harmony into a package install list as `harmony.packages..harmony`. ### From Source The build script assumes a HEAD build of Idris 2 is installed on your system. For an alternative, see the [Docker Build](#docker-build) instructions below. From 057d53f2b14c5ffeaebee8c3a56960f512b3cabe Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Tue, 5 Dec 2023 20:10:09 -0600 Subject: [PATCH 11/19] Add missing support for updating the version in the nix derivation along with everywhere else. --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 837e14c..dc7a6e0 100644 --- a/Makefile +++ b/Makefile @@ -56,6 +56,7 @@ version: sed -I '' "s/version = .*/version = ${v}/" ./harmony.ipkg sed -I '' "s/appVersion = \".*\"/appVersion = \"${v}\"/" ./src/AppVersion.idr sed -I '' "s/\"version\": \".*\"/\"version\": \"${v}\"/" ./package.json + sed -I '' "s/version = \".*\";/version = \"${v}\";/" ./default.nix package: build ./version-check.sh From 5df5a591203455c987873403cb74a68644c372db Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Tue, 5 Dec 2023 20:14:20 -0600 Subject: [PATCH 12/19] Add nix build CI workflow --- .github/workflows/nix.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/nix.yml diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml new file mode 100644 index 0000000..8898941 --- /dev/null +++ b/.github/workflows/nix.yml @@ -0,0 +1,26 @@ + +name: Nix + +on: + push: + branches: + - main + pull_request: + schedule: + - cron: '0 1 * * *' + + +jobs: + nix-build-unstable: + runs-on: ubuntu-latest + + steps: + - name: Install Nix + uses: cachix/install-nix-action@v22 + with: + nix_path: nixpkgs=channel:nixos-unstable + - name: Checkout + uses: actions/checkout@v3 + - name: Build + run: nix build + From 5159edb897e6c6d42d1db624ae0f7231156fac46 Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Tue, 5 Dec 2023 20:21:55 -0600 Subject: [PATCH 13/19] Update version of install nix action --- .github/workflows/nix.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index 8898941..3dd3b0c 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -16,7 +16,7 @@ jobs: steps: - name: Install Nix - uses: cachix/install-nix-action@v22 + uses: cachix/install-nix-action@v24 with: nix_path: nixpkgs=channel:nixos-unstable - name: Checkout From a1b5f62f6c8e9a4c9d405bc5b324d7f1fe332e95 Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Tue, 5 Dec 2023 20:47:05 -0600 Subject: [PATCH 14/19] skip over draft PRs when recommending a PR to contribute a review to --- src/Commands.idr | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Commands.idr b/src/Commands.idr index 9e88935..dbc4400 100644 --- a/src/Commands.idr +++ b/src/Commands.idr @@ -300,6 +300,7 @@ contribute : Config => Git => Octokit => -> Promise () contribute @{config} args = do openPrs <- listPullRequests config.org config.repo (Just Open) 100 + let nonDraftPrs = filter (not . isDraft) openPrs myLogin <- login <$> getSelf let newIgnorePRNums = ignorePRNums args config' <- @@ -308,7 +309,7 @@ contribute @{config} args = do else addIgnoredPRs config newIgnorePRNums let skip = fromMaybe 0 (head' $ mapMaybe skipArg args) let checkout = find (\case Checkout => True; _ => False) args - let notMine = filter (not . isAuthor myLogin) openPrs + let notMine = filter (not . isAuthor myLogin) nonDraftPrs let notIgnored = filter (isNotIgnored config') notMine let parted = partition (isRequestedReviewer myLogin) notIgnored let (requestedOfMe, others) = (mapHom $ sortBy (compare `on` .createdAt)) parted From 497e36ec8f94dd5e6c50537319d2e8791152ac21 Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Tue, 5 Dec 2023 20:48:28 -0600 Subject: [PATCH 15/19] bump patch version --- default.nix | 2 +- harmony.ipkg | 2 +- package.json | 2 +- src/AppVersion.idr | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/default.nix b/default.nix index d0eb0dc..95abff3 100644 --- a/default.nix +++ b/default.nix @@ -11,7 +11,7 @@ let in stdenv.mkDerivation { pname = "harmony"; - version = "2.6.1"; + version = "2.6.2"; nativeBuildInputs = [ idris2 makeWrapper ]; buildInputs = [ nodejs ]; diff --git a/harmony.ipkg b/harmony.ipkg index b4cf699..ebb5f6a 100644 --- a/harmony.ipkg +++ b/harmony.ipkg @@ -1,5 +1,5 @@ package harmony -version = 2.6.1 +version = 2.6.2 authors = "Mathew Polzin" license = "MIT" -- brief = diff --git a/package.json b/package.json index 7e9aa9f..b612bd4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@mattpolzin/harmony", - "version": "2.6.1", + "version": "2.6.2", "publishConfig": { "access": "public" }, diff --git a/src/AppVersion.idr b/src/AppVersion.idr index 9eabb3e..f537dcd 100644 --- a/src/AppVersion.idr +++ b/src/AppVersion.idr @@ -4,7 +4,7 @@ module AppVersion export appVersion : String -appVersion = "2.6.1" +appVersion = "2.6.2" export printVersion : HasIO io => io () From 831ad0d1ba1e7c9f748d31ffdc912410ce4c7205 Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Tue, 5 Dec 2023 20:49:19 -0600 Subject: [PATCH 16/19] mention drafts in description of contribute command --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e384e0b..aede82a 100644 --- a/README.md +++ b/README.md @@ -170,7 +170,7 @@ harmony assign web +carl001 +emmaham ``` ### Contribute -Running `harmony contribute` will print the URI of the oldest PR waiting for your review. If you are not requested for review on any PRs, Harmony will suggest a PR that you are not assigned to. +Running `harmony contribute` will print the URI of the oldest non-draft PR waiting for your review. If you are not requested for review on any PRs, Harmony will suggest a PR that you are not assigned to. You can skip PRs and retrieve the next-oldest one by passing a dash followed by the number to skip (e.g. `-2` to skip the two oldest waiting PRs). From b70e4318d0e9b65291c6355bad64e41845dfcc19 Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Wed, 6 Dec 2023 09:42:10 -0600 Subject: [PATCH 17/19] Add screenshot of reflect command --- README.md | 2 ++ docs/images/reflect.png | Bin 0 -> 34787 bytes 2 files changed, 2 insertions(+) create mode 100644 docs/images/reflect.png diff --git a/README.md b/README.md index aede82a..5803676 100644 --- a/README.md +++ b/README.md @@ -212,6 +212,8 @@ Running `harmony whoami` will print information about the currently configured a ### Reflect Running `harmony reflect` will show a summary of your review requests and authored pull requests. +![Reflect Screenshot](./docs/images/reflect.png) + ### List Running `harmony list ` will list the members of the given GitHub Team. diff --git a/docs/images/reflect.png b/docs/images/reflect.png new file mode 100644 index 0000000000000000000000000000000000000000..c97f657b0d737ba846222e58f93434a8882aca57 GIT binary patch literal 34787 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

|Jdo&i~2aohI~U1;d4K>Y1y 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 literal 0 HcmV?d00001 From a9148359998120f8c3f9df955ec01db7c4f9492e Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Wed, 6 Dec 2023 09:43:57 -0600 Subject: [PATCH 18/19] update node lockfile --- package-lock.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 00ba771..cf4e886 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@mattpolzin/harmony", - "version": "2.6.1", + "version": "2.6.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@mattpolzin/harmony", - "version": "2.6.1", + "version": "2.6.2", "license": "MIT", "dependencies": { "octokit": "^2.0.10", From 35b471e9f9f61b6dfac62e2697a6710228f6fabf Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Wed, 6 Dec 2023 10:07:52 -0600 Subject: [PATCH 19/19] Update README.md --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5803676..9421cf6 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ # Harmony Harmony is a small tool that helps teams keep GitHub reviews running smoothly. It takes the work out of picking someone from a pool of developers to review a new PR. Harmony does this by heuristically determining who on a particular GitHub Team has the least current/recent review workload. +Harmony offers a heuristic for PR assignments that is different than GitHub's round robin or weighted algorithms, but Harmony can also work well even if your team uses GitHub's automatic PR assignments ([see below](#deferring-to-github)). + ## Dependencies ### Runtime Running Harmony requires NodeJS 14+ (and a local installation of `git`) or alternatively Nix with flakes enabled. @@ -145,14 +147,15 @@ If `harmony config assignUsers` is `True` (defualt) then harmony will pick someo You can also require that specific additional users (on top of the one Harmony will pick for you) are assigned to the PR. You do this by specifying those users' logins prefixed with '+' as arguments to Harmony. +You can optionally apply any number of labels to the PR at the same time as assigning reviewers by prefixing the labels with '#'. + +#### Deferring to GitHub If your team has GitHub set up to auto-assign individuals when a team is requested for review, you probably want to tell harmony not to also pick someone using its heuristics. You can run the following `config` commands to tell harmony to assign a team but not also pick an individual from that team: ```shell harmony config assignTeams true harmony config assignUsers false ``` -You can optionally apply any number of labels to the PR at the same time as assigning reviewers by prefixing the labels with '#'. - #### Examples Assign the most available reviewer from the "developers" GitHub Team: ```shell