diff --git a/.gitignore b/.gitignore index 0e493b3..dfe7d36 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,6 @@ features work __pycache__ result +nixie/output/nix-wrapped.sh.in +src/docs +src/**/*.sh diff --git a/builder/default.nix b/builder/default.nix deleted file mode 100644 index fc8beab..0000000 --- a/builder/default.nix +++ /dev/null @@ -1,37 +0,0 @@ -{ lib, python3Packages, fetchPypi, nix-index, nix, ... }: - -let - nixie_ver = "2025.02-a1"; - pzp = python3Packages.buildPythonPackage rec { - pname = "pzp"; - version = "0.0.22"; - - src = fetchPypi { - inherit pname version; - sha256 = "sha256-RPx0nnB9+cC/n7eOX0hF21TxM/yEkGy/akRnqV/YN8E="; - }; - - doCheck = false; - }; -in python3Packages.buildPythonApplication { - pname = "nixie"; - version = nixie_ver; - - src = "${../.}/builder"; - format = "pyproject"; - - nativeBuildInputs = with python3Packages; - [ setuptools - ]; - - propagatedBuildInputs = with python3Packages; - [ click - rich - click-option-group - python-dotenv - pzp - gitpython - nix-index - nix - ]; -} diff --git a/builder/nixie/output/nix-wrapped.sh.in b/builder/nixie/output/nix-wrapped.sh.in deleted file mode 100644 index 342fc24..0000000 --- a/builder/nixie/output/nix-wrapped.sh.in +++ /dev/null @@ -1,595 +0,0 @@ -#!/usr/bin/env bash -# vim: ts=2 sw=2 fdm=marker fmr={,} fdl=0 -# Nixie (c) Karim Vergnes -# Licensed under GNU GPLv2 -# Required commands: -# - tar (with gzip support) -# - rm, mv, tail, uname, env, chmod, mkdir, tee, cut, tr (coreutils) -# - git -# - kill -# - one of wget, curl or python3 (with SSL support) -# - sh with source and declare -a -# Requirements for building binaries locally: -# - A C and C++ compiler toolchain -# - pkg-config -# - GNU Make -# - flex + bison -# - perl - -[[ "$0" == */* ]] || { >&2 echo "ERROR: This script must be run from an absolute or relative path."; exit 1; } - -SYSTEM="$(uname -s).$(uname -m)" -if [[ "$0" == /* ]] -then - THIS_SCRIPT="$0" -elif readlink "$0" >&/dev/null -then - RL=$(readlink "$0") - if [[ "$RL" == /* ]] - then - THIS_SCRIPT="$RL" - else - THIS_SCRIPT="$PWD/$RL" - fi -else - THIS_SCRIPT="$PWD/$0" -fi -PWD_SAVE=$PWD -REPO_ROOT="$(git -C "${THIS_SCRIPT%/*}" rev-parse --show-toplevel 2>/dev/null || { >&2 echo "WARNING: Failed to find current Git repository, using script parent directory."; echo "${THIS_SCRIPT%/*}"; })" - -if [[ "$SYSTEM" =~ Darwin ]] -then - DLL_EXT="dylib" - USER_STORE="$HOME/Library/Nix" -else - DLL_EXT="so" - USER_STORE="$HOME/.local/share/nix/root" -fi - -if [[ "$XDG_CACHE_HOME" != "" ]] -then - USER_CACHE="$XDG_CACHE_HOME" -elif [[ "$SYSTEM" =~ Darwin ]] -then - USER_CACHE="$HOME/Library/Caches" -else - USER_CACHE="$HOME/.cache" -fi - -##### UTILITY FUNCTIONS ##### - -# Output an error message to stderr then nuke ourselves -_bail() { - tput rmcup - >&2 echo $@ - >&2 echo "This script can be rebuilt using the nixie tool" - kill -ABRT $$ -} - -# Pull a file or directory from the resource tarball linked into this -# script. Useful for semi-offline or completely offline operation. -_untar() { - { - { read -r M - while ! [[ "$M" =~ ^-----BEGIN\ ARCHIVE\ SECTION----- ]] - do read -r M - done - gzip -d -c 2>/dev/null - } < "$THIS_SCRIPT" - if ! [[ $? =~ ^[02]$ ]] - then - # The resource tarball is required since it contains the feature - # attributes for this script. We bail out since there is no - # situation where tar failing would bode well. - _bail "Could not find or decompress resource archive." - fi - } | tar -x "$@" -} - -# Check that a command is available, and if not, add it to the list of missing -# commands to print at the end -declare -a MISSING_CMDS -MISSING_TRIG=0 -_avail() { - which $1 >&/dev/null || { MISSING_TRIG=1; MISSING_CMDS=($MISSING_CMDS "$1"); } -} - -# Print the list of missing commands and return 1, if any commands are missing -_avail_end() { - if [[ $MISSING_TRIG == 1 ]] - then - tput rmcup - >&2 echo "ERROR: The following commands are missing:" - for cmd in "${MISSING_CMDS[@]}" - do - >&2 echo "- $cmd" - done - >&2 echo "Use your distribution's package manager to install them, then try again." - return 1 - else - return 0 - fi -} - -# Best-attempt script for downloading files. We first try wget, then cURL, -# then Python 3. -_dl() { - if which wget >&/dev/null - then - wget "$1" -O"$2" || { rm "$2"; return 1; } - elif which curl >&/dev/null - then - curl -f -L "$1" -o "$2" - elif which python3 >&/dev/null - then - python3 <&2 echo "One of 'wget', 'curl' or 'python3' is required to download files." - >&2 echo "Install one of these then try again." - return 1 - fi -} - - -##### NIX BUILDERS ##### - -# Download script wrapper to retrieve files from the source derivation this -# script was built with. Requires SOURCE_CACHE to be the host name for a -# Cachix-compatible HTTPS host (i.e. with endpoint /serve/xxx-hash/path) -_pull_source() { - [[ -d $2 ]] || - ( - cd "$USER_CACHE" - _untar "sources/$1" - mv "$1" "$2" - ) || ( - cd "$USER_CACHE" - _dl "https://$SOURCE_CACHE/serve/$SOURCE_DERIVATION/$1.tar.gz" "$1.tar.gz" - gzip -d -c "$1.tar.gz" | tar x - mv "$1" "$2" - rm "$1.tar.gz" - ) -} - -# Idem for static Nix binaries -_pull_nix_bin() { - ( - cd "$USER_CACHE" - _untar "$1" - mv "$1" "$2" - ) || ( - _dl "https://$SOURCE_CACHE/serve/$NIX_BINS_DERIVATION/$1" "$2" - ) -} - -_find_or_build_openssl () { - pkg-config libcrypto && return 0 - - echo -ne "\033]0;Building Nix: libcrypto (1/8)\007" - _pull_source "openssl" "$source_root/openssl" - cd "$source_root/openssl" - chmod +x ./config - - # Did you know? The OpenSSL Makefile doesn't include generated headers to - # build deps! No one knows how to write a good Makefile nowadays. - ./config && { - for hdr in $(grep ".*\\.h:" Makefile | cut -f 1 -d :) - do - make $hdr - done - } && - make libcrypto.$DLL_EXT - - cp ./libcrypto.* "$USER_CACHE/nix-lib/" - - export OPENSSL_LIBS="$USER_CACHE/nix-lib" - export OPENSSL_CFLAGS="-I$source_root/openssl/include" -} - -_find_or_build_autoconf () { - libname="$1" - varname="$2" - - echo -ne "\033]0;Building Nix: $libname ($nth/8)\007" - pkg-config $libname && return 0 - - _pull_source "$libname" "$source_root/$libname" - cd "$source_root/$libname" - ./configure && make - - cp ./$libpath/.libs/* "$USER_CACHE/nix-lib/" - - eval "export ${varname}_LIBS=$USER_CACHE/nix-lib" - eval "export ${varname}_CFLAGS=-I$source_root/$libname/$incpfx/include" -} - -_find_or_build_lowdown () { - pkg-config lowdown && return 0 - - echo -ne "\033]0;Building Nix: lowdown (4/8)\007" - _pull_source "lowdown" "$source_root/lowdown" - cd "$source_root/lowdown" - ./configure && make - - if [[ "$SYSTEM" =~ Darwin ]] - then - # macOS' clang doesn't support the GCC-esque --soname, and the library - # output name would be wrong anyway. - cc -shared -o liblowdown.1.dylib *.o - fi - - cp ./liblowdown.* "$USER_CACHE/nix-lib/" - - export LOWDOWN_LIBS="$USER_CACHE/nix-lib" - export LOWDOWN_CFLAGS="-I$source_root/lowdown" -} - -_find_or_build_nlohmann_json () { - pkg-config nlohmann_json && return 0 - - echo -ne "\033]0;Building Nix: nlohmann_json (3/8)\007" - _pull_source "nlohmann_json" "$source_root/nlohmann_json" - - export NLOHMANN_JSON_LIBS="$source_root/nlohmann_json/single_include" - export NLOHMANN_JSON_CFLAGS="-I$source_root/nlohmann_json/single_include" -} - -_find_or_build_boost () { - boost_libs=(atomic chrono container context system thread) - for lb in ${boost_libs[@]} - do - [[ -f /usr/lib/libboost_$lb* ]] || \ - [[ -f /usr/local/lib/libboost_$lb* ]] || boost_not_found=1 && break - [[ -f /usr/include/boost/$lb ]] || \ - [[ -f /usr/local/include/boost/$lb ]] || boost_not_found=1 && break - done - - [[ $boost_not_found == 1 ]] || return 0 - - echo -ne "\033]0;Building Nix: boost (2/8)\007" - _pull_source "boost" "$source_root/boost" - cd "$source_root/boost" - ./bootstrap.sh && ./b2 --with-system --with-thread --with-context --with-container --with-chrono --static - - export BOOST_ROOT="$source_root/boost" -} - -# Check that we have the required dependencies to build Nix locally, then -# do so. -_try_build_nix() { - source_root="$REPO_ROOT/.nixie/sources" - mkdir -p $source_root - - _avail cc - _avail pkg-config - _avail make - _avail flex - _avail bison - _avail perl - _avail python3 - _avail_end || return 1; - - _find_or_build_openssl - _find_or_build_boost - _find_or_build_nlohmann_json - _find_or_build_lowdown - libpath= incpfx=c nth=5\ - _find_or_build_autoconf libbrotlicommon LIBBROTLI - libpath=src/libsodium incpfx=src/libsodium nth=6\ - _find_or_build_autoconf libsodium SODIUM - libpath=src incpfx= nth=7\ - _find_or_build_autoconf libeditline EDITLINE - - echo -ne "\033]0;Building Nix (8/8)\007" - _pull_source "nix" "$source_root/nix" - - cd "$source_root/nix" - - # Populate macOS SDK paths - if [[ "$SYSTEM" =~ Darwin ]] - then - macos_sdk="$(xcrun --show-sdk-path)" - [[ -d $macos_sdk ]] || _bail "The macOS SDK from Xcode or CommandLineTools is required to build Nix." - - export LIBCURL_LIBS=$macos_sdk/usr/lib - export LIBCURL_CFLAGS=$macos_sdk/usr/include - export LIBARCHIVE_LIBS=$macos_sdk/usr/lib - export LIBARCHIVE_CFLAGS=$macos_sdk/usr/include - export OPENSSL_LIBS=$macos_sdk/usr/lib - export OPENSSL_CFLAGS=$macos_sdk/usr/include - fi - - python3 -m venv --system-site-packages "${sources_root}/nix/venv" - py3="${source_root}/nix/venv/bin/python3" - $py3 -m pip install meson ninja - - meson="${source_root}/nix/venv/bin/meson" - - mkdir build && cd build \ - && $meson setup -Dlibstore:seccomp-sandboxing=disabled \ - -Dlibcmd:readline-flavor=editline \ - -Dlibexpr:gc=disabled \ - -Dlibutil:cpuid=disabled \ - -Ddoc-gen=false \ - -Dunit-tests=false \ - -Dbindings=false \ - && $py3 -m ninja - - mv src/nix/nix "$USER_CACHE/nix-static" -} - -# Try a set of strategies to obtain a statically built Nix binary -_get_nix() { - # Acquiring Nix produces a lot of output, so we use alt-buffer. - tput smcup - echo -ne "\033]0;Building Nix...\007" - - __teardown() { tput rmcup; echo -ne "\033]0;\007"; } - - # And we set a trap to exit alt-buffer on ^C cause we're no savages. - trap "__teardown; exit 1" SIGKILL SIGTERM SIGINT SIGABRT - - if [[ $SYSTEM =~ Darwin ]] && ! [[ -f $USER_CACHE/nix-lib/libfakedir.dylib ]] - then - # Retrieve fakedir - mkdir -p "$USER_CACHE/nix-lib" - _pull_nix_bin "libfakedir.dylib" "$USER_CACHE/nix-lib/libfakedir.dylib" - fi - - # Check if the binary already exists - [[ -f "$USER_CACHE/nix-static" ]] \ - && { __teardown; return 0; } - - # Look in our sources for prebuilt binary - _pull_nix_bin "nix.$SYSTEM" "$USER_CACHE/nix-static" \ - && { __teardown; return 0; } - - # Build Nix locally from source - _try_build_nix 2>&1 | tee nix-build.log \ - && { __teardown; return 0; } - - # Everything failed, bail out - __teardown - return 1 -} - - -##### RUNNER SCRIPTS - -_macos_workaround_nix () { - CMDNAME="$1" - shift 1 - mkdir -p $USER_STORE/nix - - [[ -f "$USER_CACHE/nix-lib/libfakedir.dylib" ]] || _bail "libfakedir.dylib missing, cannot proceed." - - : ${NIX_SSL_CERT_FILE:=/etc/ssl/cert.pem} - export NIX_SSL_CERT_FILE - - # We must ensure fakedir gets propagated into spawned executables as well - # so we unfortunately need to disengage the sandbox entirely. - _NIX_TEST_NO_SANDBOX=1 \ - DYLD_INSERT_LIBRARIES="$USER_CACHE/nix-lib/libfakedir.dylib" \ - DYLD_LIBRARY_PATH="$USER_CACHE/nix-lib" \ - FAKEDIR_PATTERN=/nix \ - FAKEDIR_TARGET=$USER_STORE/nix \ - exec -a "$CMDNAME" "$USER_CACHE/nix-static" "$@" -} - -_catch_nixie_args() { - __help() { : "Show this help and exit." - - >&2 echo "Nix wrapper script, generated by Nixie $NIXIE_VERSION" - >&2 echo - >&2 echo "Available --nixie- options:" - for func in $(declare -F | cut -d' ' -f 3 | grep __) - do - # String between : and ; in function readout is the help tooltip - fdesc="$(declare -f $func | cut -d':' -f 2 -s | head -n 1 | cut -d';' -f 1 | tr -d '"')" - >&2 printf " --nixie-%s\e[30G%s\n" "${func##__}" "$fdesc" - done - exit 0 - } - - __print-config() { : "Print this script's configuration" - - _untar -O features - exit 0 - } - - __extract() { : "Unpack the resources archive in nixie/" - - mkdir -p nixie && cd nixie && _untar - exit 0 - } - - __cleanup() { : "Delete local Nix build files" - - >&2 echo "Removing local Nix channels and build files..." - chmod -R +wx $REPO_ROOT/.nixie && rm -rf $REPO_ROOT/.nixie - >&2 echo "Removing user Nix store..." - chmod -R +wx $USER_STORE && rm -rf $USER_STORE - >&2 echo "Removing retrieved Nix binaries..." - rm -rf $USER_CACHE/nix-static $USER_CACHE/nix-lib - exit 0 - } - - __ignore-system() { : "Do not use system-wide Nix" - - >&2 echo "WARNING: Ignoring system-wide Nix for testing purposes." - >&2 echo "Re-run without the --nixie-ignore-system flag to import the single-user" - >&2 echo "Nix store into the system store." - nosystem=1 - } - - for ((i = 0; i < ${#CMDL_ARGS[@]}; ++i)) - do - arg="${CMDL_ARGS[$i]}" - if [[ $arg =~ ^--nixie-(.*)$ ]] - then - # Drop nixie option from real command line - unset CMDL_ARGS[$i] - if declare -F __${BASH_REMATCH[1]} >&/dev/null - then - __${BASH_REMATCH[1]} - else - >&2 echo "No such option: $arg. Run '$1 --nixie-help' for available options." - exit 1 - fi - fi - done -} - - -##### ENTRY POINT ##### - -# Check for required commands -_avail tar -_avail gzip -_avail uname -_avail_end || exit 1 - -# Load feature attributes of our resource tarball -eval "$(_untar -O features || _bail "The resource archive is missing or malformed.")" - -# Running without a specified sources derivation is not supported, even if sources -# are shipped offline. -[[ "$SOURCE_CACHE" != "" ]] || [[ "$SOURCE_DERIVATION" != "" ]] || [[ "$NIX_BINS_DERIVATION" != "" ]] \ - || _bail "The features file in the resource archive is missing or malformed." - -mkdir -p "$REPO_ROOT/.nixie" - -declare -a EXTRA_ARGS - -declare -a CMDL_ARGS=("$@") - -NIXCMD="nix" - -# Parse --nixie-* args -nosystem=0 -_catch_nixie_args "$0" - -# Unpack builtin Nix channels for channel-oriented commands -if [[ "$0" =~ nix-(shell|build|env)$ ]] -then - if (( $(stat -c %W "$REPO_ROOT/.nixie/channels" 2>/dev/null || echo 0) < $(stat -c %W "$THIS_SCRIPT" ) )) - then - >&2 echo "Unpacking Nix channels, hang tight..." - (cd $REPO_ROOT/.nixie; _untar "channels" 2>/dev/null) - fi - export NIX_PATH="$REPO_ROOT/.nixie/channels:$NIX_PATH" -fi - - -# Emulate nix-shell interpreter behavior -if [[ "$0" =~ nix-shell$ ]] && [[ -f "$1" ]] && ! [[ "$1" =~ .nix$ ]] -then - { - read - IFS=' ' read -a nix_shell_args - - # There is a possibility that argv[1] is a Nix file. - # Bail if there's no second line shebang. - [[ "${nix_shell_args[0]}" =~ ^#! ]] || break - - nix_shell_args=("${nix_shell_args[@]:1}") - [[ "${nix_shell_args[0]}" == "nix-shell" ]] && nix_shell_args=("${nix_shell_args[@]:1}") - - for i in "${!nix_shell_args[@]}" - do - [[ "${nix_shell_args[$i]}" == "-i" ]] && { - nix_shell_args[$i]="--command" - nix_shell_args[$((i+1))]="${nix_shell_args[$((i+1))]} $*" - } && break - done - - # Overwrite shell arguments with real interpreter - CMDL_ARGS=("${nix_shell_args[@]}") - } < "$1" -fi - -# Command substitution feature -if [[ "$0" =~ nix$ ]] || [[ "$0" =~ nix-(shell|build|env|channel|hash|instantiate|store|collect-garbage)$ ]] -then - NIXCMD="$0" -elif [[ -f "$REPO_ROOT/flake.nix" ]] -then - # Try to run named command from flake develop - NIXCMD="nix" - CMDL_ARGS=("develop" "$REPO_ROOT" "-c" "${0##*/}" "$@") -elif [[ -f "$REPO_ROOT/shell.nix" ]] -then - # Try to run named command from shell - NIXCMD="nix-shell" - CMDL_ARGS=("$REPO_ROOT/shell.nix" "--command" "${0##*/}$(printf ' %q' "$@")") -fi - -# Check for alternate OpenSSL/LibreSSL certificate paths (fixes #6) -[[ -f "/etc/pki/tls/certs/ca-bundle.crt" ]] && : ${NIX_SSL_CERT_FILE:="/etc/pki/tls/certs/ca-bundle.crt"} -[[ "$NIX_SSL_CERT_FILE" != "" ]] && export NIX_SSL_CERT_FILE - - -# Apply experimental features if listed -[[ "$EXTRA_FEATURES" != "" ]] && EXTRA_ARGS+=("--extra-experimental-features" "$EXTRA_FEATURES") - -# Apply extra substituters and their signing keys (e.g. cachix) if listed -[[ "$EXTRA_SUBSTITUTERS" != "" ]] && EXTRA_ARGS+=("--extra-substituters" "$EXTRA_SUBSTITUTERS") && nix_daemon_warn=1 -[[ "$EXTRA_TRUSTED_PUBLIC_KEYS" != "" ]] && EXTRA_ARGS+=("--extra-trusted-public-keys" "$EXTRA_TRUSTED_PUBLIC_KEYS") && nix_daemon_warn=1 - - -if [[ $nix_daemon_warn == 1 ]] && \ - pgrep nix-daemon >/dev/null 2>&1 && \ - ! grep "trusted-users\s*=.*$(whoami 2>/dev/null)" /etc/nix/nix.conf >/dev/null 2>&1 -then - >&2 echo "This nix wrapper script specifies additional binary caches," - >&2 echo "but you are running on a multi-user install as an untrusted user." - >&2 echo "Cache substitution may not work until you add yourself to" - >&2 echo "the trusted-users entry in /etc/nix/nix.conf." -fi - -if [[ $nosystem != 1 ]] && [[ -d /nix/store ]] && which nix >&/dev/null -then - # Here, we check that the user just installed Nix proper on their system, - # so we migrate paths away from their home to avoid duplicates. - if [[ -d $USER_STORE/nix/store ]] - then - >&2 echo "Migrating Nix store to system-wide install..." - nix copy --from $USER_STORE --all --no-check-sigs &&\ - chmod -R +wx $USER_STORE && rm -rf $USER_STORE - fi - - exec -a "$NIXCMD" nix "${EXTRA_ARGS[@]}" "${CMDL_ARGS[@]}" -else - if _get_nix && chmod +x "$USER_CACHE/nix-static" - then - # This is required if the Nix binary was built locally. - # It is highly unlikely that the user has static copies of all the - # libraries required by Nix, so it's easier to build a shared binary. - # After all, this binary isn't meant to leave its host machine. - export LD_LIBRARY_PATH="$USER_CACHE/nix-lib:$LD_LIBRARY_PATH" - - if [[ "$SYSTEM" =~ Darwin ]] - then - # wow apple thanks - _macos_workaround_nix "$NIXCMD" "${EXTRA_ARGS[@]}" "${CMDL_ARGS[@]}" - else - # Workaround for ascendant symlinks - mkdir -p $HOME/.local/share/nix/root - exec -a "$NIXCMD" "$USER_CACHE/nix-static" \ - --store "$(readlink -f $HOME/.local/share/nix/root)" \ - "${EXTRA_ARGS[@]}" "${CMDL_ARGS[@]}" - fi - else - >&2 echo "Failed to obtain Nix. Check your internet connection." - exit 1 - fi -fi - -# Prevent overrun into resource tarball -exit 1 -cat < {} }: let - builder = pkgs.callPackage ./builder {}; + builder = pkgs.callPackage ./. {}; in pkgs.mkShell { name = "nixie"; diff --git a/sources/00-brotli-add-automake.patch b/sources/00-brotli-add-automake.patch index 40bb6e6..531c6ca 100644 --- a/sources/00-brotli-add-automake.patch +++ b/sources/00-brotli-add-automake.patch @@ -108,7 +108,7 @@ new file mode 100755 index 0000000..d4325b2 --- /dev/null +++ b/bootstrap -@@ -0,0 +1,36 @@ +@@ -0,0 +1,32 @@ +#!/bin/sh -e + +REQUIRED='is required, but not installed.' @@ -127,18 +127,14 @@ index 0000000..d4325b2 +mkdir m4 2>/dev/null +fi + -+BROTLI_ABI_HEX=`sed -n 's/#define BROTLI_ABI_VERSION 0x//p' c/common/version.h` -+BROTLI_ABI_INT=`echo "ibase=16;$BROTLI_ABI_HEX" | bc` -+BROTLI_ABI_CURRENT=`echo "scale=0;$BROTLI_ABI_INT / 16777216" | bc` -+BROTLI_ABI_REVISION=`echo "scale=0;$BROTLI_ABI_INT / 4096 % 4096" | bc` -+BROTLI_ABI_AGE=`echo "scale=0;$BROTLI_ABI_INT % 4096" | bc` ++BROTLI_ABI_CURRENT=`sed -n 's/#define BROTLI_ABI_CURRENT //p' c/common/version.h` ++BROTLI_ABI_REVISION=`sed -n 's/#define BROTLI_ABI_REVISION //p' c/common/version.h` ++BROTLI_ABI_AGE=`sed -n 's/#define BROTLI_ABI_AGE //p' c/common/version.h` +BROTLI_ABI_INFO="$BROTLI_ABI_CURRENT:$BROTLI_ABI_REVISION:$BROTLI_ABI_AGE" + -+BROTLI_VERSION_HEX=`sed -n 's/#define BROTLI_VERSION 0x//p' c/common/version.h` -+BROTLI_VERSION_INT=`echo "ibase=16;$BROTLI_VERSION_HEX" | bc` -+BROTLI_VERSION_MAJOR=`echo "scale=0;$BROTLI_VERSION_INT / 16777216" | bc` -+BROTLI_VERSION_MINOR=`echo "scale=0;$BROTLI_VERSION_INT / 4096 % 4096" | bc` -+BROTLI_VERSION_PATCH=`echo "scale=0;$BROTLI_VERSION_INT % 4096" | bc` ++BROTLI_VERSION_MAJOR=`sed -n 's/#define BROTLI_VERSION_MAJOR //p' c/common/version.h` ++BROTLI_VERSION_MINOR=`sed -n 's/#define BROTLI_VERSION_MINOR //p' c/common/version.h` ++BROTLI_VERSION_PATCH=`sed -n 's/#define BROTLI_VERSION_PATCH //p' c/common/version.h` +BROTLI_VERSION="$BROTLI_VERSION_MAJOR.$BROTLI_VERSION_MINOR.$BROTLI_VERSION_PATCH" + +sed -i.bak "$SED_ERE" "s/[0-9]+:[0-9]+:[0-9]+/$BROTLI_ABI_INFO/" Makefile.am diff --git a/sources/Makefile b/sources/Makefile index 6a9c75c..1eda23d 100644 --- a/sources/Makefile +++ b/sources/Makefile @@ -7,11 +7,11 @@ TAR := tar WORKDIR := work WGET := wget -BOOST_VER := 1.81.0 +BOOST_VER := 1.87.0 BOOST_ARCHIVE := $(WORKDIR)/boost.tar.bz2 -BOOST_ADD_HEADERS = core,utility,io,system,thread,context,lexical_cast,config,format,coroutine2,container,chrono,atomic,predef,move,assert,detail,type_traits,intrusive,mpl,date_time,bind,align,preprocessor,ratio,exception,smart_ptr,numeric,functional,container_hash,describe,tuple,iterator,function,integer,type_index,algorithm,range,concept,optional -BOOST_ADD_MODULES = system,thread,context,format,coroutine2,container,chrono,atomic,optional +BOOST_ADD_HEADERS = core,utility,io,system,thread,context,lexical_cast,config,format,coroutine,container,chrono,atomic,predef,move,assert,detail,type_traits,intrusive,mpl,date_time,bind,align,preprocessor,ratio,exception,smart_ptr,numeric,functional,container_hash,describe,tuple,iterator,function,integer,type_index,algorithm,range,concept,optional,mp11 +BOOST_ADD_MODULES = assert,static_assert,throw_exception,integer,type_traits,move,mpl,ratio,variant2,mp11,winapi,typeof,utility,intrusive,pool,smart_ptr,exception,system,predef,thread,context,format,coroutine,container,chrono,atomic,optional boost-shaved.tar.gz: $(BOOST_ARCHIVE) @mkdir -p $(WORKDIR) diff --git a/sources/brotli-gen-sources-list.sh b/sources/brotli-gen-sources-list.sh new file mode 100644 index 0000000..6da3123 --- /dev/null +++ b/sources/brotli-gen-sources-list.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +echo "BROTLI_CLI_C = " c/tools/*.c +echo "BROTLI_COMMON_C = " c/common/*.c +echo "BROTLI_COMMON_H = " c/common/*.h +echo "BROTLI_DEC_C = " c/dec/*.c +echo "BROTLI_DEC_H = " c/dec/*.h +echo "BROTLI_ENC_C = " c/enc/*.c +echo "BROTLI_ENC_H = " c/enc/*.h +echo "BROTLI_INCLUDE = " c/include/brotli/*.h diff --git a/sources/default.nix b/sources/default.nix index 747cc13..a3f443a 100644 --- a/sources/default.nix +++ b/sources/default.nix @@ -1,12 +1,15 @@ { stdenv, boost, openssl, lowdown, nlohmann_json, brotli, libsodium, editline -, gnutar, coreutils, findutils, python3, nix -, meson, automake, autoconf-archive, autoconf, m4, bc, libtool, pkg-config, ... }: +, gnutar, coreutils, findutils, python3, nix, libarchive +, automake, autoconf-archive, autoconf, m4, bc, libtool, pkg-config +# External source for Nix +, nix-source ? nix.src +, ... }: let - mkConfiguredSrc = { pkg, confScript, patches ? [], dest?pkg.pname }: + mkConfiguredSrc = { pkg, confScript, src ? pkg.src, patches ? pkg.patches, dest ? pkg.pname }: stdenv.mkDerivation { - inherit (pkg) version src; - inherit dest patches; + inherit (pkg) version; + inherit dest patches src; pname = "${pkg.pname}-configured-sources"; configurePhase = confScript; @@ -19,7 +22,6 @@ let bc libtool pkg-config - meson ]; dontBuild = true; @@ -33,6 +35,7 @@ let nix_configured_src = mkConfiguredSrc { pkg = nix; + src = nix-source; confScript = '' mkdir -p $out cp -r . $out/nix @@ -47,9 +50,16 @@ let brotli_configured_src = mkConfiguredSrc { pkg = brotli; patches = [ ./00-brotli-add-automake.patch ]; - confScript = "true"; + confScript = '' + sh ${./brotli-gen-sources-list.sh} > ./scripts/sources.lst + ./bootstrap + ''; dest = "libbrotlicommon"; }; + libarchive_configured_src = mkConfiguredSrc + { pkg = libarchive; + confScript = "./build/autogen.sh"; + }; srcs_simple = [ openssl @@ -63,6 +73,7 @@ let [ nix_configured_src editline_configured_src brotli_configured_src + libarchive_configured_src ]; in stdenv.mkDerivation { name = "nixie-sources"; diff --git a/src/builders.ab b/src/builders.ab new file mode 100644 index 0000000..425deee --- /dev/null +++ b/src/builders.ab @@ -0,0 +1,78 @@ +// Nixie © Karim Vergnes +// Licensed under GNU GPLv2 +// Functions to build Nix and its dependencies from source + +import { dir_exists, dir_create } from "std/fs" +import { env_var_set } from "std/env" + +import { set_title } from "./term.ab" +import { check_deps, bail } from "./common.ab" +import { pull_source_file, pull_binary } from "./resources.ab" +import { get_osname, get_cache_root } from "./platform.ab" + +import { get_source_root } from "./builders/common.ab" + +import { build_openssl } from "./builders/openssl.ab" +import { build_lowdown } from "./builders/lowdown.ab" +import { build_nlohmann_json } from "./builders/nlohmann_json.ab" +import { build_boost } from "./builders/boost.ab" +import { build_autoconf_dep } from "./builders/autoconf.ab" +import { build_nix } from "./builders/nix.ab" + +/// Export libraries found inside the macOS SDK for building Nix +/// +/// TODO: is this still required with Meson? +fun darwin_export_sdk() +{ + // Calling xcrun should prompt the user to install the macOS SDK. + let sdk_path = trust $xcrun --show-sdk-path$ + + if not dir_exists(sdk_path): + bail("The macOS SDK from Xcode or CommandLineTools is required to build Nix.") + + let sdk_libs = "{sdk_path}/usr/lib" + let sdk_cflags = "-I{sdk_path}/usr/include" + + trust env_var_set("LIBCURL_LIBS", sdk_libs) + trust env_var_set("LIBCURL_CFLAGS", sdk_cflags) + trust env_var_set("LIBARCHIVE_LIBS", sdk_libs) + trust env_var_set("LIBARCHIVE_CFLAGS", sdk_cflags) + trust env_var_set("OPENSSL_LIBS", sdk_libs) + trust env_var_set("OPENSSL_CFLAGS", sdk_cflags) + + trust $export LIBCURL_LIBS LIBCURL_CFLAGS \ + LIBARCHIVE_LIBS LIBARCHIVE_CFLAGS \ + OPENSSL_LIBS OPENSSL_CFLAGS$ +} + +/// Build Nix and its dependencies locally, then place it in the expected location +/// in the user's cache directory. +/// +/// This process **requires**, among other things, `pkg-config` due to it being +/// the only detection method for many dependencies in Meson. +pub fun try_build_nix() +{ + let cache_root = get_cache_root() + + check_deps(["cc", "c++", "pkg-config", "make", "flex", "bison", "perl"]) + failed { bail("Missing required dependencies to build from source.") } + + if get_osname() == "Darwin": + darwin_export_sdk() + + trust env_var_set("step_total", "9") + + dir_create(get_source_root()) + dir_create("{cache_root}/nix-deps/lib/pkgconfig") + + build_openssl()? + build_boost()? + build_nlohmann_json()? + build_lowdown()? + // pkgconf name include prefix + build_autoconf_dep("libbrotlicommon", "c/include")? + build_autoconf_dep("libsodium", "src/libsodium/include")? + build_autoconf_dep("libeditline", "include")? + build_autoconf_dep("libarchive", "libarchive")? + build_nix()? +} diff --git a/src/builders/autoconf.ab b/src/builders/autoconf.ab new file mode 100644 index 0000000..b0a1e2d --- /dev/null +++ b/src/builders/autoconf.ab @@ -0,0 +1,52 @@ +// Nixie © Karim Vergnes +// Licensed under GNU GPLv2 +// Build script for Autoconf-based dependencies + +import { env_var_set } from "std/env" + +import { pull_source_file } from "../resources.ab" +import { get_cache_root } from "../platform.ab" + +import { pkg_exists, step_title, get_source_root } from "./common.ab" + +/// Build a dependency which uses Autoconf as its build system. +/// +/// ### Arguments: +/// - `lib_name`: The library to check for with `pkg-config` +/// - `inc_prefix`: Where in the source tree the build headers are found +pub fun build_autoconf_dep(lib_name: Text, inc_prefix: Text = ""): Null? +{ + let source_root = get_source_root() + let cache_root = get_cache_root() + + let my_source = "{source_root}/{lib_name}" + + step_title(lib_name) + + if pkg_exists(lib_name): + return null + + pull_source_file(lib_name, my_source)? + + $( unset C_INCLUDE_PATH CPLUS_INCLUDE_PATH \ + && cd {my_source} \ + && ./configure --prefix={cache_root}/nix-deps \ + && make && make install )$? +} + +main(cmdl) +{ + if len(cmdl) < 5 { + echo "Usage: ./autoconf.sh " + echo "" + echo "See builders/autoconf.ab and builders.ab for more info" + exit 1 + } + + let lib_name = cmdl[1] + let inc_prefix = cmdl[2] + + trust env_var_set("_NIXIE_TESTING_SKIP_TARBALL", "1") + trust env_var_set("step_total", "1") + build_autoconf_dep(lib_name, inc_prefix)? +} diff --git a/src/builders/boost.ab b/src/builders/boost.ab new file mode 100644 index 0000000..da268bd --- /dev/null +++ b/src/builders/boost.ab @@ -0,0 +1,72 @@ +// Nixie © Karim Vergnes +// Licensed under GNU GPLv2 +// Builder for the Boost C++ framework + +import { file_exists, dir_exists } from "std/fs" +import { env_var_set } from "std/env" + +import { pull_source_file } from "../resources.ab" + +import { pkg_exists, step_title, get_source_root } from "./common.ab" + +const modules = ["predef", "chrono", "container", "context", "coroutine", "system", "thread"] + +/// Check that the Boost modules we need exist on the system. +/// +/// Boost does not provide a pkg-config package, nor a config program. +/// This means we have to do the information-gathering the old way, by +/// looking through /usr and /usr/local manually. +fun find_boost_libs(libs: [Text]): Bool +{ + for lib in libs { + let libname = "libboost_{lib}*" + if not ( file_exists("/usr/lib/{libname}") + or file_exists("/usr/local/lib/{libname}")): + return false + if not ( dir_exists("/usr/include/boost/{lib}") + or dir_exists("/usr/local/include/boost/{lib}")): + return false + } + + return true +} + +/// This function runs within the source directory, in a subshell. +fun build_boost_inner() +{ + let args = [ "variant=release", "link=static", "--stagedir=." ] + + for mod in modules { + args += [ "--with-{mod}" ] + } + + $./bootstrap.sh$? + $./b2 "{args}"$? +} + +/// This is the core function for the Boost builder. +/// +/// It exports the `BOOST_ROOT` variable. +pub fun build_boost() +{ + let source_root = get_source_root() + + step_title("boost") + + if find_boost_libs(["atomic"] + modules): + return 0 + + pull_source_file("boost", "{source_root}/boost")? + + $(cd {source_root}/boost && {nameof build_boost_inner})$? + + trust env_var_set("BOOST_ROOT", "{source_root}/boost") + trust $export BOOST_ROOT$ +} + +main(cmdl) +{ + trust env_var_set("_NIXIE_TESTING_SKIP_TARBALL", "1") + trust env_var_set("step_total", "1") + build_boost()? +} diff --git a/src/builders/common.ab b/src/builders/common.ab new file mode 100644 index 0000000..caeec57 --- /dev/null +++ b/src/builders/common.ab @@ -0,0 +1,41 @@ +// Nixie © Karim Vergnes +// Licensed under GNU GPLv2 +// Common functions for source-based builders + +import { env_var_get } from "std/env" +import { dir_create } from "std/fs" + +import { set_title } from "../term.ab" +import { get_repo_root } from "../platform.ab" + +let step_current = 1 + +/// Invoke `pkg-config` to assert that a given dependency exists on the system. +pub fun pkg_exists(package: Text): Bool +{ + $pkg-config {package}$ failed { + return false + } + + return true +} + +/// Change the terminal title to a build step, and increments the step counter. +pub fun step_title(name: Text): Null +{ + let step_total = trust env_var_get("step_total") + + trust $clear$ + + set_title("Building Nix: {name} ({step_current}/{step_total})") + + step_current += 1 +} + +/// Obtain the base directory where source packages are extracted. +pub fun get_source_root(): Text +{ + let repo_root = get_repo_root() + + return "{repo_root}/.nixie/sources" +} diff --git a/src/builders/lowdown.ab b/src/builders/lowdown.ab new file mode 100644 index 0000000..5b34812 --- /dev/null +++ b/src/builders/lowdown.ab @@ -0,0 +1,54 @@ +// Nixie © Karim Vergnes +// Licensed under GNU GPLv2 +// Builder for the lowdown Markdown library + +import { env_var_set } from "std/env" + +import { pull_source_file } from "../resources.ab" +import { get_osname, get_cache_root } from "../platform.ab" + +import { pkg_exists, step_title, get_source_root } from "./common.ab" + +/// Workaround for the default Makefile not building a shared library on macOS. +fun macos_build_post() +{ + $cc -shared -o liblowdown.1.dylib *.o$? +} + +/// This function runs within the source directory, in a subshell. +fun build_lowdown_inner() +{ + let cache_root = get_cache_root() + + $./configure PREFIX={cache_root}/nix-deps$? + $make$? + + if get_osname() == "Darwin": + macos_build_post()? + $make install_shared$? +} + +/// This is the core function for the Lowdown builder. +/// +/// It exports the `LOWDOWN_LIBS` and `LOWDOWN_CFLAGS` variables. +pub fun build_lowdown() +{ + let source_root = get_source_root() + let cache_root = get_cache_root() + + step_title("lowdown") + + if pkg_exists("lowdown"): + return 0 + + pull_source_file("lowdown", "{source_root}/lowdown")? + + $(cd {source_root}/lowdown && {nameof build_lowdown_inner})$? +} + +main(cmdl) +{ + trust env_var_set("_NIXIE_TESTING_SKIP_TARBALL", "1") + trust env_var_set("step_total", "1") + build_lowdown()? +} diff --git a/src/builders/nix.ab b/src/builders/nix.ab new file mode 100644 index 0000000..effbe46 --- /dev/null +++ b/src/builders/nix.ab @@ -0,0 +1,65 @@ +// Nixie © Karim Vergnes +// Licensed under GNU GPLv2 +// Builder for the Nix package manager itself + +import { env_var_set } from "std/env" +import { file_exists, dir_exists, dir_create } from "std/fs" + +import { pull_source_file } from "../resources.ab" +import { get_cache_root } from "../platform.ab" + +import { step_title, get_source_root } from "./common.ab" + +/// This function runs within the source directory, in a subshell. +fun build_nix_inner() +{ + let source_root = get_source_root() + let venv = "{source_root}/nix/venv" + + $mkdir build && cd build$? + + ${venv}/bin/meson setup -Dlibstore:seccomp-sandboxing=disabled \ + -Dlibcmd:readline-flavor=editline \ + -Dlibexpr:gc=disabled \ + -Dlibutil:cpuid=disabled \ + -Ddoc-gen=false \ + -Dunit-tests=false \ + -Dbindings=false \ + ..$? + + ${venv}/bin/ninja$? +} + +/// This is the core function for the final Nix builder. +/// +/// It produces a Nix executable in the `{cache_root}/nix-static` location, +/// where the Nix runner expects it. +pub fun build_nix() +{ + let source_root = get_source_root() + let cache_root = get_cache_root() + + let venv = "{source_root}/nix/venv" + + step_title("nix") + + pull_source_file("nix", "{source_root}/nix")? + + $python3 -m venv --system-site-packages "{venv}"$? + + trust $export LIBRARY_PATH={cache_root}/nix-deps/lib:\$LIBRARY_PATH$ + trust $export PKG_CONFIG_PATH={cache_root}/nix-deps/lib/pkgconfig:{cache_root}/nix-deps/share/pkgconfig:\$PKG_CONFIG_PATH$ + + ${venv}/bin/pip install meson ninja$? + + $(cd {source_root}/nix && {nameof build_nix_inner})$? + + trust mv "{source_root}/nix/src/nix/nix" "{cache_root}/nix-static" +} + +main(cmdl) +{ + trust env_var_set("_nixie_testing_skip_tarball", "1") + trust env_var_set("step_total", "1") + build_nix()? +} diff --git a/src/builders/nlohmann_json.ab b/src/builders/nlohmann_json.ab new file mode 100644 index 0000000..a8082ca --- /dev/null +++ b/src/builders/nlohmann_json.ab @@ -0,0 +1,40 @@ +// Nixie © Karim Vergnes +// Licensed under GNU GPLv2 +// Builder for NLohmann's JSON library + +import { env_var_set } from "std/env" +import { file_write } from "std/fs" + +import { pull_source_file } from "../resources.ab" +import { get_cache_root } from "../platform.ab" + +import { pkg_exists, step_title, get_source_root } from "./common.ab" + +/// This is the core function for the NLohmann JSON library. +pub fun build_nlohmann_json() +{ + let source_root = get_source_root() + let cache_root = get_cache_root() + + step_title("nlohmann_json") + + if pkg_exists("nlohmann_json"): + return 0 + + pull_source_file("nlohmann_json", "{source_root}/nlohmann_json")? + + let version = trust $grep "^version:" {source_root}/nlohmann_json/wsjcpp.yml | cut -d '"' -f 2 | cut -d 'v' -f 2$ + + file_write("{cache_root}/nix-deps/lib/pkgconfig/nlohmann_json.pc", +"Name: nlohmann_json +Version: {version} +Description: JSON for Modern C++ +Cflags: -I{source_root}/nlohmann_json/include")? +} + +main(cmdl) +{ + trust env_var_set("_NIXIE_TESTING_SKIP_TARBALL", "1") + trust env_var_set("step_total", "1") + build_nlohmann_json()? +} diff --git a/src/builders/openssl.ab b/src/builders/openssl.ab new file mode 100644 index 0000000..409fd7e --- /dev/null +++ b/src/builders/openssl.ab @@ -0,0 +1,73 @@ +// Nixie © Karim Vergnes +// Licensed under GNU GPLv2 +// Builder for OpenSSL + +import { env_var_test, env_var_set } from "std/env" +import { split_lines } from "std/text" + +import { pull_source_file } from "../resources.ab" +import { get_dll_ext, get_cache_root } from "../platform.ab" + +import { pkg_exists, step_title, get_source_root } from "./common.ab" + +/// Scans through and builds generated headers required for building OpenSSL. +/// +/// For some reason the OpenSSL Makefile does not specify dependencies to those +/// targets, meaning we cannot simply `make libcrypto.so`. +fun make_headers() +{ + for header in split_lines(trust $grep ".*\\.h:" ./Makefile | cut -f 1 -d :$) { + $make {header}$? + } +} + +/// This function runs within the source directory, in a subshell. +fun build_openssl_inner() +{ + let dll_ext = get_dll_ext() + let cache_root = get_cache_root() + + trust $chmod +x ./config$ + + $./config$? + make_headers()? + $make libcrypto.{dll_ext} libcrypto.pc$? + + // Building libssl is: + // - hard + // - broken + // - a very bad idea anyway + // so we're performing the install ourselves + trust $cp ./libcrypto.* {cache_root}/nix-deps/lib/$ + trust $cp ./libcrypto.pc {cache_root}/nix-deps/lib/pkgconfig$ + trust $cp -r ./include {cache_root}/nix-deps/$ +} + +/// This is the core function for the OpenSSL builder. +/// +/// It exports the `OPENSSL_LIBS` and `OPENSSL_CFLAGS` variables. +pub fun build_openssl() +{ + let source_root = get_source_root() + let cache_root = get_cache_root() + + step_title("libcrypto") + + if pkg_exists("libcrypto"): + return 0 + if env_var_test("OPENSSL_LIBS") and env_var_test("OPENSSL_CFLAGS"): + return 0 + + pull_source_file("openssl", "{source_root}/openssl")? + + // Using a subshell ensures we aren't cd elsewhere on failure + $(cd {source_root}/openssl && {nameof build_openssl_inner})$? +} + +main(cmdl) +{ + trust env_var_set("_NIXIE_TESTING_SKIP_TARBALL", "1") + trust env_var_set("step_total", "1") + build_openssl()? +} + diff --git a/src/cli.ab b/src/cli.ab new file mode 100644 index 0000000..a66bbd3 --- /dev/null +++ b/src/cli.ab @@ -0,0 +1,117 @@ +// Nixie © Karim Vergnes +// Licensed under GNU GPLv2 +// Command line options parser + +import { array_remove_at } from "std/array" +import { starts_with, slice } from "std/text" +import { echo_error, echo_warning, env_var_get, env_var_set } from "std/env" +import { dir_create } from "std/fs" + +import { untar } from "./common.ab" +import { get_nix_root, get_cache_root, get_repo_root } from "./platform.ab" + +fun cmd_help() +{ + let NIXIE_VERSION = trust env_var_get("NIXIE_VERSION") + + echo "Nix wrapper script, generated by Nixie {NIXIE_VERSION}" + echo "" + echo "Available --nixie- options:" + + echo " --nixie-help Show this help message and exit." + echo " --nixie-print-config Print this script's configuration." + echo " --nixie-extract Unpack the resources archive into nixie/" + echo " --nixie-cleanup Delete local Nix build files" + echo " --nixie-ignore-system Behave as if Nix was not installed." + + exit 0 +} + +fun cmd_print_config() +{ + echo trust untar("features", true) + exit 0 +} + +fun cmd_extract() +{ + dir_create("nixie") + cd "nixie" + trust untar("") + exit 0 +} + +fun cmd_cleanup() +{ + let nix_root = get_nix_root() + let cache_root = get_cache_root() + let repo_root = get_repo_root() + + echo "Removing local Nix channels and build files..." + trust $chmod -R +wx {repo_root}/.nixie 2>/dev/null$ + trust $rm -rf {repo_root}/.nixie$ + + echo "Removing user Nix store..." + trust $chmod -R +wx {nix_root} 2>/dev/null$ + trust $rm -rf {nix_root}$ + + echo "Removing retrieved Nix binaries..." + trust $rm -rf {cache_root}/nix-static {cache_root}/nix-lib {cache_root}/nix-deps$ + + exit 0 +} + +fun opt_ignore_system() +{ + echo_warning("Ignoring system-wide Nix for testing purposes.") + echo_warning("Re-run without the --nixie-ignore-system flag to import the single-user") + echo_warning("Nix store into the system store.") + trust env_var_set("nosystem", "1") +} + +fun opt_no_precompiled() +{ + echo_warning("Ignoring precompiled binaries for testing purposes.") + echo_warning("This implies --nixie-ignore-system.") + trust env_var_set("nobins", "1") + trust env_var_set("nosystem", "1") +} + +fun notfound(cmd) +{ + let self = trust env_var_get("0") + + echo_error("No such option: --nixie-{cmd}. Run '{self} --nixie-help' for available options.") +} + +fun eval_cmd(cmd) +{ + if { + cmd == "help": cmd_help() + cmd == "print-config": cmd_print_config() + cmd == "extract": cmd_extract() + cmd == "cleanup": cmd_cleanup() + cmd == "ignore-system": opt_ignore_system() + cmd == "no-precompiled": opt_no_precompiled() + else: notfound(cmd) + } +} + +/// Parse and remove options in the form `--nixie-[option]` from the arguments +/// list. +pub fun catch_args(ref args: []): Null +{ + let local_args = args + + args = [Text] + + for arg in local_args { + let cmd = "" + if starts_with(arg, "--nixie-") { + cmd = slice(arg, len("--nixie-")) + eval_cmd(cmd) + } else { + args += [arg] + } + } +} diff --git a/src/common.ab b/src/common.ab new file mode 100644 index 0000000..2a9f7f4 --- /dev/null +++ b/src/common.ab @@ -0,0 +1,149 @@ +// Nixie © Karim Vergnes +// Licensed under GNU GPLv2 +// Common utility functions + +import { echo_error, env_var_get, is_command } from "std/env" +import { starts_with, text_contains, parse_number } from "std/text" + +import { exit_alt_buffer, set_title } from "./term.ab" + +let SELF = "" + +let me = trust env_var_get("0") + +// Quick shenanigan to get real path without readlink -f *sideyes macOS* +if text_contains(me, "/") { + if not starts_with(me, "/") { + let PWD = trust env_var_get("PWD") + let rl = $readlink {me}$ failed { + SELF = "{PWD}/{me}" + } + + // This second pass checks if the result of readlink is relative + if { + rl == "": SELF = SELF + not starts_with(rl, "/"): SELF = "{PWD}/{rl}" + else: SELF = rl + } + } +} else { + echo_error("This script must be run from an absolute or relative path.") +} + +/// Checks that the left-hand path exists and is newer than the right-hand path. +/// False otherwise. +pub fun exists_newer(left: Text, right: Text): Bool +{ + let left_time = parse_number(trust $stat -c %W {left}$) failed { + return false // Untrustworthy stat, assume worst + } + let right_time = parse_number(trust $stat -c %W {right}$) failed { + return false + } + + return left_time >= right_time +} + +/// Exit alt-buffer, quit script, kill ourselves. At this point something has gone +/// catastrophically wrong and the script MUST stop. +/// +/// ### Arguments: +/// - `message`: Message to print as we error out +/// - `archive`: `true` if the issue is related to the attached archive. +/// Default is `false`. +pub fun bail(message: Text, archive: Bool = false): Null +{ + exit_alt_buffer() + set_title() // Clear terminal title back to default + + echo_error(message, 0) + if archive { + echo_error("This script can be rebuilt using the nixie tool.", 0) + } + + exit 1 + trust $kill -ABRT \$\$$ +} + +/// Retrieve the resolved, absolute path to the wrapper script. +pub fun get_self(): Text +{ + return SELF +} + +/// Reads and uncompresses to a temporary file, the attached resource archive +/// at the end of the script. +fun dump_archive(): Text +{ + let dest = trust $mktemp -t nixie_XXXXXXXX.tar$ + + // This block seeks to the archive marker, then zcats everything afterwards + // to the tmpfile in dest + $cat {SELF} | ( + read -r M + while ! [[ "\$M" =~ ^-----BEGIN\ ARCHIVE\ SECTION----- ]] + do read -r M || return 1 + done + gzip -d -c 2>/dev/null > {dest} + )$ failed { + // gzip exits with 2 IFF it sees trailing garbage, which our alt-buf + // attempt at hiding the tarball technically is + if status != 2 { + bail("Could not find the script's resource archive.", true) + } + } + + return dest +} + +/// Extract a file or directory from the attached resource archive at the end +/// of the script. +/// +/// ### Arguments +/// - `member`: The plaintext path to the file or folder to be extracted, relative +/// to the archive root. Passed as-is to `tar`. +/// - `dump`: If `true`, output the contents of the extracted file to standard +/// output. Adds the `-O` option to `tar`. +pub fun untar(member: Text, dump: Bool = false): Text? +{ + let archive = dump_archive() + let tar_cmd = "tar -x {member} -f {archive}" + + if dump { + tar_cmd = "tar -x -O {member} -f {archive}" + } + + let tar_out = ${tar_cmd}$ failed { + let tar_status = status + trust $rm {archive}$ + fail tar_status + } + + trust $rm {archive}$ + + return tar_out +} + +/// Checks that a list of commands are available at runtime. +/// +/// This function prints out the list of missing commands, and a message to +/// instruct the user to install them. +pub fun check_deps(deps: []): Null? +{ + let missing = [ Text ] + + for dep in deps { + if not is_command(dep) { + missing += [ dep ] + } + } + + if len(missing) > 0 { + echo_error("The following commands are missing:", 0) + for cmd in missing { + echo_error("- {cmd}", 0) + } + echo_error("Use your distribution's package manager to install them, then try again.", 0) + fail 1 + } +} diff --git a/src/main.ab b/src/main.ab new file mode 100644 index 0000000..9956eb2 --- /dev/null +++ b/src/main.ab @@ -0,0 +1,76 @@ +// Nixie © Karim Vergnes +// Licensed under GNU GPLv2 +// Entry point for script logic + +let SOURCE_CACHE = "" +let SOURCE_DERIVATION = "" +let NIX_BINS_DERIVATION = "" + +let EXTRA_FEATURES = "" +let EXTRA_SUBSTITUTERS = "" +let EXTRA_TRUSTED_PUBLIC_KEYS = "" + +let NIXIE_VERSION = "" + +let args = [Text] + +import { env_var_get, env_var_set } from "std/env" +import { array_shift } from "std/array" +import { file_exists } from "std/fs" + +import { bail, untar, check_deps } from "./common.ab" +import { get_osname } from "./platform.ab" +import { catch_args } from "./cli.ab" +import { launch_nix } from "./nix.ab" + +check_deps(["tar", "gzip", "uname"]) failed { + exit 1 +} + +/// Populate environment variables from the features file in the archive. +/// Also sets variables local to this module, which is not much use until +/// [amber-lang/amber#671](https://github.com/amber-lang/amber/issues/671) is +/// implemented. Checks that the variables exist, I guess. +/// +/// Could be moved to `common.ab` +fun load_features(): Null +{ + let envfile = untar("features", true) failed { + bail("The resource archive is missing or malformed.", true) + } + + $eval {envfile}$ failed { + bail("The environment file in the resource archive is malformed.", true) + } + + SOURCE_CACHE = trust env_var_get("SOURCE_CACHE") + SOURCE_DERIVATION = trust env_var_get("SOURCE_DERIVATION") + NIX_BINS_DERIVATION = trust env_var_get("NIX_BINS_DERIVATION") + + EXTRA_FEATURES = trust env_var_get("EXTRA_FEATURES") + EXTRA_SUBSTITUTERS = trust env_var_get("EXTRA_SUBSTITUTERS") + EXTRA_TRUSTED_PUBLIC_KEYS = trust env_var_get("EXTRA_TRUSTED_PUBLIC_KEYS") + + NIXIE_VERSION = trust env_var_get("NIXIE_VERSION") +} + +main(cmdl) +{ + // In Amber, cmdl is read-only, but catch_args needs read-write + args = cmdl + + load_features() + catch_args(args) + + let self = array_shift(args) + + // Check for alternate OpenSSL/LibreSSL certificate paths (fixes #6) + if { + file_exists("/etc/pki/tls/certs/ca-bundle.crt"): + trust env_var_set("NIX_SSL_CERT_FILE", "/etc/pki/tls/certs/ca-bundle.crt") + get_osname() == "Darwin": + trust env_var_set("NIX_SSL_CERT_FILE", "/etc/ssl/cert.pem") + } + + launch_nix(self, args) +} diff --git a/src/nix.ab b/src/nix.ab new file mode 100644 index 0000000..aa566aa --- /dev/null +++ b/src/nix.ab @@ -0,0 +1,308 @@ +// Nixie © Karim Vergnes +// Licensed under GNU GPLv2 +// Final-step Nix invocation methods + +import { file_exists, dir_exists, dir_create } from "std/fs" +import { env_var_test, env_var_set, env_var_get } from "std/env" +import { split, slice, starts_with, ends_with } from "std/text" +import { array_last, array_shift } from "std/array" + +import { enter_alt_buffer, set_title, teardown } from "./term.ab" +import { bail, untar, exists_newer, get_self } from "./common.ab" +import { get_osname, get_system, get_cache_root + , get_nix_root, get_repo_root } from "./platform.ab" +import { pull_binary } from "./resources.ab" +import { try_build_nix } from "./builders.ab" + +/// Determine whether Nix is installed system-wide. Nixie can launch the +/// system-wide Nix when it is available, using the script's bundled options. +/// +/// This is the predicate for that behavior. +fun is_nix_installed(): Bool +{ + // --nixie-ignore-system flag set + if env_var_test("nosystem"): return false + + // Simple enough heuristic. In the future, might also check for the `nix` + // command, but that would create a ternary situation where Nixie's static + // Nix would need to use the system store. + if dir_exists("/nix/store"): return true + + return false +} + +/// Attempt to retrieve the static Nix binary by all known methods. +/// +/// This function will first try to extract or download a static executable +/// for the current system, and if it fails, a local build from source will be +/// attempted. +/// +/// **NOTE**: On macOS, this function is also responsible for downloading +/// `libfakedir.dylib`. +fun get_nix() +{ + let cache_root = get_cache_root() + let osname = get_osname() + let system = get_system() + + let nix_path = "{cache_root}/nix-static" + let fakedir_path = "{cache_root}/nix-deps/lib/libfakedir.dylib" + + enter_alt_buffer() + set_title("Building Nix...") + + // Cleanly exit alt-buffer if hit with ^C + trust $trap "{nameof teardown}; exit 1" SIGKILL SIGTERM SIGINT SIGABRT$ + + // Unpack fakedir as needed + if osname == "Darwin" and not file_exists(fakedir_path) { + dir_create("{cache_root}/nix-deps/lib") + pull_binary("libfakedir.dylib", fakedir_path) failed { + teardown(true) + fail 1 + } + } + + // Update it if applicable + if osname == "Darwin" and not exists_newer(fakedir_path, get_self()): + trust pull_binary("libfakedir.dylib", fakedir_path) + + // We already have static Nix + if file_exists(nix_path) { + teardown() + return 0 + } + + if env_var_test("nobins") { + try_build_nix() failed { + teardown(true) + fail 1 + } + } + + // Try to extract or download Nix + pull_binary("nix.{system}", nix_path) failed { + try_build_nix() failed { + teardown(true) + fail 1 + } + } + + trust $chmod +x {nix_path}$ + + teardown() + return 0 +} + +/// Move the contents of the user Nix store into the system Nix store. +/// +/// This reduces occupied storage space in the event that the user installed +/// Nix system-wide between uses of our script. +fun migrate_nix_store() +{ + let nix_root = "" + + nix_root = $readlink -f {get_nix_root()}$ failed { + nix_root = get_nix_root() + } + + if not dir_exists("{nix_root}/nix/store"): + return 0 + + echo "Migrating Nix store to system-wide install..." + trust $nix copy --from {nix_root} --all --no-check-sigs$ + if status == 0 { + trust $chmod -R +wx {nix_root} && rm -rf {nix_root}$ + } +} + +/// Provide a list of extra arguments for bundled Nix channels, after +/// extracting said channels from the bundled archive. +fun unpack_channels() +{ + let repo_root = get_repo_root() + + if exists_newer("{repo_root}/.nixie/channels", get_self()) { + let NIX_PATH = trust env_var_get("NIX_PATH") + trust env_var_set("NIX_PATH", "{repo_root}/.nixie/channels:{NIX_PATH}") + trust $export NIX_PATH$ + return 0 + } + echo "Unpacking Nix channels, hang tight..." + + dir_create("{repo_root}/.nixie") + untar("channels -C {repo_root}/.nixie") failed { + // Leave an empty directory to trip the time check above + trust $mkdir {repo_root}/.nixie/channels$ + } +} + +/// Provide a list of extra arguments depending on the script's features +/// and the runtime environment. +fun populate_extras(): [Text] +{ + let args = [Text] + + let EXTRA_FEATURES = trust env_var_get("EXTRA_FEATURES") + let EXTRA_SUBSTITUTERS = trust env_var_get("EXTRA_SUBSTITUTERS") + let EXTRA_TRUSTED_PUBLIC_KEYS = trust env_var_get("EXTRA_TRUSTED_PUBLIC_KEYS") + + let nix_root = get_nix_root() + + if EXTRA_FEATURES != "": + args += [ "--extra-experimental-features", EXTRA_FEATURES ] + + if EXTRA_SUBSTITUTERS != "": + args += [ "--extra-substituters", EXTRA_SUBSTITUTERS ] + + if EXTRA_TRUSTED_PUBLIC_KEYS != "": + args += [ "--extra-trusted-public-keys", EXTRA_TRUSTED_PUBLIC_KEYS ] + + if get_osname() != "Darwin" and not is_nix_installed(): + args += [ "--store", trust $readlink -f {nix_root}$ ] + + return args +} + +/// Launch Nix with the proper environment variables for fakedir and OpenSSL. +/// +/// This is required because macOS has no namespacing facility, and Nix will +/// not attempt to use the system-wide CA bundle by default. This function +/// addresses both issues. +/// +/// **This function does not return.** +fun launch_darwin_workaround(name: Text, nix_path: Text, args: [Text]): Null +{ + let cache_root = get_cache_root() + let nix_root = get_nix_root() + + let fakedir_path = "{cache_root}/nix-deps/lib/libfakedir.dylib" + + trust env_var_set("FAKEDIR_PATTERN", "/nix") + trust env_var_set("FAKEDIR_TARGET", "{nix_root}/nix") + + trust $export FAKEDIR_PATTERN FAKEDIR_TARGET$ + + // We need to ensure fakedir gets propagated into child processes as well. + // Unfortunately, this requires us to disable the Nix sandbox entirely. + trust $ _NIX_TEST_NO_SANDBOX=1 \ + DYLD_INSERT_LIBRARIES="{fakedir_path}" \ + DYLD_LIBRARY_PATH="{cache_root}/nix-deps/lib" \ + exec -a {name} {nix_path} "{args}"$ +} + +/// Launch the command referred to by name from within a Nix shell. +/// +/// This allows our script to be used as an alias for developer utilities. +/// +/// ### Arguments: +/// - `nix_path`: Path to the Nix executable to use (local or installed) +/// - `cmd`: The name our script was called as +/// - `extras`: Internal options to append to the Nix command line +/// - `args`: Command line options to pass to the command +fun launch_shell_command(nix_path: Text, cmd: Text, extras: [Text], args: [Text]): Null +{ + let repo_root = get_repo_root() + let pwd = trust env_var_get("PWD") + let name = "nix-shell" + let shell_cmd = [ "{repo_root}/shell.nix", "--command", "{cmd} {args}" ] + + if file_exists("{pwd}/flake.nix") { + name = "nix" + shell_cmd = [ "develop", pwd, "-c", cmd ] + args + } else: if file_exists("{repo_root}/flake.nix") { + name = "nix" + shell_cmd = [ "develop", repo_root, "-c", cmd ] + args + } else: if file_exists("{pwd}/shell.nix") { + shell_cmd = [ "{pwd}/shell.nix", "--command", "{cmd} {args}" ] + } + + if get_osname() == "Darwin" and not is_nix_installed(): + launch_darwin_workaround(name, nix_path, extras + shell_cmd) + else: + trust $exec -a {name} {nix_path} "{extras}" "{shell_cmd}"$ +} + +/// Launch Nix with options pulled from a file's contents. +/// +/// This allows our script to be used as an interpreter, the same way +/// Nix proper would. +/// +/// ### Arguments: +/// - `nix_path`: Path to the Nix executable to use (local or installed) +/// - `file`: The filename to interpret with Nix +/// - `extras`: Internal options to append to the Nix command line +/// - `args`: Command line options to pass to the interpreted file +fun launch_nix_shebang(nix_path: Text, file: Text, extras: [Text], args: [Text]): Null +{ + let shebang = "" + for i, line in lines(file) { + if i == 1 { + shebang = line + break + } + } + + // No second shebang, not our business. + if not starts_with(shebang, "#!"): + return null + let bang_args = split(slice(shebang, 2), " ") + let name = array_shift(bang_args) + + // Find and inject script options into --command + for i, arg in bang_args { + if arg == "-i" { + bang_args[i] = "--command" + bang_args[i+1] = "{bang_args[i+1]} {file} {args}" + break + } + } + + if get_osname() == "Darwin" and not is_nix_installed(): + launch_darwin_workaround(name, nix_path, extras + bang_args) + else: + trust $exec -a {name} {nix_path} "{extras}" "{bang_args}"$ +} + +/// Launch Nix as a regular CLI. +/// +/// **This function does not return.** +pub fun launch_nix(self: Text, args: [Text]): Null +{ + let cache_root = get_cache_root() + let nix_root = get_nix_root() + + let nix_path = "{cache_root}/nix-static" + + let extras = populate_extras() + let name = array_last(split(self, "/")) + + if starts_with(name, "nix-"): + trust unpack_channels() + + if is_nix_installed() { + migrate_nix_store() + nix_path = "nix" + } else { + get_nix() failed { + bail("Failed to obtain Nix. Check your internet connection.") + } + } + + trust $export NIX_SSL_CERT_FILE$ + + if file_exists(args[0]) and not ends_with(args[0], ".nix") { + let args_shebang = args + array_shift(args_shebang) + launch_nix_shebang(nix_path, args[0], extras, args_shebang) + } + + if not starts_with(name, "nix") { + launch_shell_command(nix_path, name, extras, args) + } + + if get_osname() == "Darwin" and not is_nix_installed(): + launch_darwin_workaround(name, nix_path, extras + args) + else: + trust $exec -a {name} {nix_path} "{extras}" "{args}"$ +} diff --git a/src/platform.ab b/src/platform.ab new file mode 100644 index 0000000..82a028e --- /dev/null +++ b/src/platform.ab @@ -0,0 +1,86 @@ +// Nixie © Karim Vergnes +// Licensed under GNU GPLv2 +// Environment-specific data retrieval utilities + +import { env_var_get, echo_warning } from "std/env" +import { split, join } from "std/text" +import { array_pop } from "std/array" + +import { get_self } from "./common.ab" + +/// Return the current operating system, as reported by `uname -s`. +pub fun get_osname(): Text +{ + return trust $uname -s$ +} + +/// Return the current machine architecture, as reported by `uname -s`. +pub fun get_machine(): Text +{ + let machine = trust $uname -m$ + + // Normalize to Linux 'aarch64' name + if machine == "arm64": + return "aarch64" + return machine +} + +/// Return the combined system-string, in the format `osname.machine`. +/// +/// See [`get_osname()`](#get_osname) and [`get_machine()`](#get_machine) above. +pub fun get_system(): Text +{ + let osname = get_osname() + let machine = get_machine() + + return "{osname}.{machine}" +} + +/// Return the extension for dynamic libraries on the current system. +pub fun get_dll_ext(): Text +{ + let osname = get_osname() + if { + osname == "Darwin": return "dylib" + else: return "so" + } +} + +/// Return the path to the user-mode root for the Nix store. +pub fun get_nix_root(): Text +{ + let userhome = trust env_var_get("HOME") + let osname = get_osname() + if { + osname == "Darwin": return "{userhome}/Library/Nix" + else: return "{userhome}/.local/share/nix/root" + } +} + +/// Return the path to the user's cache directory on the current system. +pub fun get_cache_root(): Text +{ + let userhome = trust env_var_get("HOME") + let osname = get_osname() + if { + osname == "Darwin": return "{userhome}/Library/Caches" + else: return "{userhome}/.cache" + } +} + +/// Return the path to the root of the Git repository the script is located in. +/// +/// Falls back to returning the script's parent directory if not in a repository, +/// or if `git` is unavailable. +pub fun get_repo_root(): Text +{ + let self_a = split(get_self(), "/") + array_pop(self_a) + + let self_dir = "/" + join(self_a, "/") + + return $git -C {self_dir} rev-parse --show-toplevel$ failed { + echo_warning("Failed to find current Git repository, using script parent directory.") + return self_dir + } +} diff --git a/src/resources.ab b/src/resources.ab new file mode 100644 index 0000000..65cc3b1 --- /dev/null +++ b/src/resources.ab @@ -0,0 +1,98 @@ +// Nixie © Karim Vergnes +// Licensed under GNU GPLv2 +// Resource retrieval from tarball or Cachix + +import { file_download } from "std/http" +import { file_exists } from "std/fs" +import { env_var_get, env_var_test } from "std/env" + +import { untar } from "./common.ab" + +fun cachix_url(derivation: Text, member: Text): Text +{ + let SOURCE_CACHE = trust env_var_get("SOURCE_CACHE") + + return "https://{SOURCE_CACHE}/serve/{derivation}/{member}" +} + +/// Unpack a known source code package into the requested target directory. +/// +/// This function will try the following methods, in order: +/// - Extract from the embedded tarball +/// - Pull tarball from directory marked by `_NIXIE_TESTING_SOURCES_DIR` +/// - Download tarball from known Cachix URL +/// +/// ### Arguments: +/// - `member`: The name of the source package to unpack +/// - `dest`: The target directory to move the package contents into +pub fun pull_source_file(member: Text, dest: Text): Null? +{ + let SOURCE_DERIVATION = trust env_var_get("SOURCE_DERIVATION") + + let where = "" + let my_status = 1 + + // This allows individual builders' entry points to not fail + if not env_var_test("_NIXIE_TESTING_SKIP_TARBALL") { + where = trust untar("sources/{member}") + my_status = status + } + + if env_var_test("_NIXIE_TESTING_SOURCES_DIR") and my_status != 0 { + let srcdir = trust env_var_get("_NIXIE_TESTING_SOURCES_DIR") + let tmpd = trust $mktemp -t -d nixie_{member}_XXXXXXXX$ + + if file_exists("{srcdir}/{member}.tar.gz") { + trust $gzip -d -c {srcdir}/{member}.tar.gz | tar -x -C {tmpd}$ + my_status = status + where = "{tmpd}/{member}" + } else { + my_status = 1 + } + } + + if my_status != 0 { + let tmpf = trust $mktemp -t nixie_src_XXXXXXXX.tgz$ + let tmpd = trust $mktemp -t -d nixie_{member}_XXXXXXXX$ + + if not file_download(cachix_url(SOURCE_DERIVATION, "{member}.tar.gz"), tmpf): + fail 1 + + $gzip -d -c {tmpf} | tar -x -C {tmpd}$? + + trust $rm -f {tmpf}$ + where = "{tmpd}/{member}" + } + + // Our build method means source dirs accumulate state, we're better off + // throwing them away. + trust $rm -rf {dest}$ + trust mv where dest +} + +/// Retrieve a known precompiled file and move it to the requested target. +/// +/// This function will try the following methods, in order: +/// - Extract from the embedded tarball +/// - Download file from known Cachix URL +/// +/// ### Arguments: +/// - `member`: The filename of the file to retrieve +/// - `dest`: The target filename to move the file into +pub fun pull_binary(member: Text, dest: Text): Null? +{ + let NIX_BINS_DERIVATION = trust env_var_get("NIX_BINS_DERIVATION") + + let where = trust untar(member) + if status != 0 { + let tmpf = trust $mktemp -t nixie_{member}_XXXXXXXX$ + + if not file_download(cachix_url(NIX_BINS_DERIVATION, member), tmpf) { + fail 1 + } + + where = tmpf + } + + trust mv where dest +} diff --git a/src/term.ab b/src/term.ab new file mode 100644 index 0000000..dca184b --- /dev/null +++ b/src/term.ab @@ -0,0 +1,68 @@ +// Nixie © Karim Vergnes +// Licensed under GNU GPLv2 +// Utilities to manipulate Xterm features + +import { env_var_get, env_var_test } from "std/env" +import { starts_with } from "std/text" + +let tsl = trust $tput tsl$ +let fsl = trust $tput fsl$ +let smcup = trust $tput smcup$ +let rmcup = trust $tput rmcup$ + +let TERM = trust env_var_get("TERM") + +fun can_set_title(): Bool +{ + let has_statusline = true + + $tput hs$ failed { + // For some reason, default xterm won't communicate statusline. + // We need to set TERM=xterm+sl to get the info. + if starts_with(TERM, "xterm") { + trust $TERM=xterm+sl tput hs$ + if status == 0 { + tsl = trust $TERM=xterm+sl tput tsl$ + fsl = trust $TERM=xterm+sl tput fsl$ + } else { + has_statusline = false + } + } else { + has_statusline = false + } + } + + return has_statusline +} + +/// Set the title for the current window, if possible. +/// +/// Does nothing otherwise. +pub fun set_title(title: Text = ""): Null +{ + if can_set_title(): + echo tsl + title + fsl +} + +/// Create and enter an alt-buffer in the terminal. +pub fun enter_alt_buffer(): Null +{ + echo smcup +} + +/// Close the alt-buffer in the terminal. +pub fun exit_alt_buffer(): Null +{ + echo rmcup +} + +/// Shorthand to exit alt-buffer and clear terminal title. +pub fun teardown(failure: Bool = false): Null +{ + if failure { + echo "Press any key to continue..." + trust $read -n 1$ + } + set_title() + exit_alt_buffer() +} diff --git a/static-bins/default.nix b/static-bins/default.nix index d311517..fc3b6ec 100644 --- a/static-bins/default.nix +++ b/static-bins/default.nix @@ -1,7 +1,7 @@ { nixpkgs ? # Nixpkgs import (from flake) -, nix-source ? builtins.fetchGit "https://github.com/nixos/nix" +, nix-source ? builtins.fetchGit "https://github.com/nixos/nix" # Nix packages source , fakedir ? builtins.fetchGit "https://github.com/thesola10/fakedir"