From 3cb429833951a2e541ac699195d6fe4e94f7b118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C2=B7=F0=90=91=91=F0=90=91=B4=F0=90=91=95=F0=90=91=91?= =?UTF-8?q?=F0=90=91=A9=F0=90=91=A4?= Date: Wed, 3 Sep 2025 18:19:35 +0700 Subject: [PATCH] nix-prefetch-darcs: init --- .../fetchdarcs/nix-prefetch-darcs | 184 ++++++++++++++++++ .../nix-prefetch-scripts/default.nix | 7 + 2 files changed, 191 insertions(+) create mode 100755 pkgs/build-support/fetchdarcs/nix-prefetch-darcs diff --git a/pkgs/build-support/fetchdarcs/nix-prefetch-darcs b/pkgs/build-support/fetchdarcs/nix-prefetch-darcs new file mode 100755 index 000000000000..85b132210232 --- /dev/null +++ b/pkgs/build-support/fetchdarcs/nix-prefetch-darcs @@ -0,0 +1,184 @@ +#!/bin/sh +set -eu + +quiet= +name="fetchdarcs" +repository= +tag= +context= +darcs_hash= +exp_hash= + +usage() { + echo "Usage: nix-prefetch-darcs [options] [REPOSITORY] [FILENAME [EXPECTED-HASH]]" + echo + echo "Options:" + echo " --quiet Suppress most error messages." + echo " --name Symbolic store path name to use for the result." + echo " --repo URL for the Darcs repository." + echo " --tag Clone specified by tag matching a regular expression." + echo " --context Clone specified by context file." + echo " --darcs-hash Clone specified by hash. WARN: hash order is fickle by design." + echo " --hash Expected hash." + echo " --help Show this help message." +} + +# Argument parsing +while [ $# -gt 0 ]; do + case "$1" in + --quiet) + quiet=1; shift 1 ;; + --name) + name="$2"; shift 2 ;; + --repository) + repository="$2"; shift 2 ;; + --tag) + tag="$2"; shift 2 ;; + --context) + context="$2"; shift 2 ;; + --darcs-hash) + darcs_hash="$2"; shift 2 ;; + --hash) + exp_hash="$2"; shift 2 ;; + --help) + usage; exit 0 ;; + *) + # Positional arguments + if [ -z "$repository" ]; then + repository="$1" + shift + elif [ -z "$context" ]; then + context="$1" + shift + elif [ -z "$exp_hash" ]; then + exp_hash="$1" + shift + else + echo "Error: Too many arguments" >&2 + usage + exit 1 + fi + ;; + esac +done + +if [ -z "$repository" ]; then + echo "Error: URL for repository is required." >&2 + echo >&2 + usage + exit 1 +fi + +state_flag_count=0 +[ -n "$tag" ] && state_flag_count=$(( state_flag_count + 1 )) +[ -n "$context" ] && state_flag_count=$(( state_flag_count + 1 )) +[ -n "$darcs_hash" ] && state_flag_count=$(( state_flag_count + 1 )) + +if [ "$state_flag_count" -gt 1 ]; then + echo "Error: no more than 1 of --tag, --context, --darcs-hash flags can be set. $state_flag_count were set." >&2 + echo >&2 + usage + exit 1 +elif [ -n "$context" ]; then + if [ ! -s "$context" ]; then + echo "Error: context file must be readable & non-empty @ “$context”" >&2 + echo >&2 + usage + exit 1 + else + context="$(realpath "$context")" + fi +fi + +weak_hash= +hash= +hash_algo="${NIX_HASH_ALGO:-"sha256"}" +hash_format="${hashFormat:-"--base32"}" +final_path= +final_context= + +# If the hash was given, a file with that hash may already be in the +# store. +if [ -n "$exp_hash" ]; then + final_path=$(nix-store --print-fixed-path --recursive "$hash_algo" "$exp_hash" "$name") + if ! nix-store --check-validity "$final_path" 2> /dev/null; then + final_path="" + fi + hash="$exp_hash" +fi + +# If we don’t know the hash or a path with that hash doesn’t exist, +# download the file and add it to the store. +if [ -z "$final_path" ]; then + tmp_clone="$(realpath ${quiet:+--quiet} "$(mktemp ${quiet:+--quiet} -d --tmpdir darcs-clone-tmp-XXXXXXXX)")" + trap "rm -rf \"$tmp_clone\"" EXIT + + clone_args="--lazy" + if [ -n "$quiet" ]; then + clone_args="$clone_args --quiet" + fi + if [ -n "$tag" ]; then + clone_args="$clone_args --tag=$tag" + elif [ -n "$context" ]; then + clone_args="$clone_args --context=$context" + elif [ -n "$darcs_hash" ]; then + clone_args="$clone_args --to-hash=$darcs_hash" + fi + + cd "$tmp_clone" + # Do not print Darcs progress to stdout (else stdout isn’t parsable JSON) + if [ -t 1 ]; then + darcs clone $clone_args "$repository" "$name" >/dev/tty + else + darcs clone $clone_args "$repository" "$name" >/dev/null + fi + cd "$tmp_clone/$name" + # Will put the current Darcs context into the store. + new_context="$tmp_clone/${name}-context.txt" + darcs log --context > "$new_context" + final_context="$(nix-store --add-fixed "$hash_algo" "$new_context")" + # Darcs has a weak hash using the XOR of the patch hashes which is useful + # for other scripts + # https://darcs.net/Internals/Hashes + weak_hash="$(darcs show repo | grep '^ *Weak Hash:' | cut -d: -f2- | tr -d "[:space:]")" + cd - >/dev/null + rm -rf "$tmp_clone/$name/_darcs" + + hash="$(nix-hash --type "$hash_algo" "$hash_format" "$tmp_clone/$name")" + final_path=$(nix-store --add-fixed --recursive "$hash_algo" "$tmp_clone/$name") + + if [ -n "$exp_hash" ] && [ "$exp_hash" != "$hash" ]; then + echo "Hash mismatch for “$repository”" >&2 + echo "Expected: $exp_hash" >&2 + echo "Got: $hash" >&2 + exit 1 + fi +fi + +json_escape() { + printf '%s' "$1" | jq -Rs . +} + +cat <