#!/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 <