185 lines
4.8 KiB
Plaintext
185 lines
4.8 KiB
Plaintext
|
|
#!/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 <NAME> Symbolic store path name to use for the result."
|
|||
|
|
echo " --repo <REPOSITORY> URL for the Darcs repository."
|
|||
|
|
echo " --tag <REGEXP> Clone specified by tag matching a regular expression."
|
|||
|
|
echo " --context <FILENAME> Clone specified by context file."
|
|||
|
|
echo " --darcs-hash <HASH> Clone specified by hash. WARN: hash order is fickle by design."
|
|||
|
|
echo " --hash <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 <<EOF
|
|||
|
|
{
|
|||
|
|
"repository": $(json_escape "$repository"),
|
|||
|
|
EOF
|
|||
|
|
if [ -n "$tag" ]; then cat <<EOF
|
|||
|
|
"tag": "$(json_escape "$tag")",
|
|||
|
|
EOF
|
|||
|
|
elif [ -n "$darcs_hash" ]; then cat <<EOF
|
|||
|
|
"darcs-hash": $(json_escape "$darcs_hash"),
|
|||
|
|
EOF
|
|||
|
|
fi; if [ -n "$weak_hash" ]; then cat <<EOF
|
|||
|
|
"weak-hash": $(json_escape "$weak_hash"),
|
|||
|
|
EOF
|
|||
|
|
fi; if [ -s "$final_context" ]; then cat <<EOF
|
|||
|
|
"context": $(json_escape "$final_context"),
|
|||
|
|
EOF
|
|||
|
|
fi; cat <<EOF
|
|||
|
|
"path": "$final_path",
|
|||
|
|
$(json_escape "$hash_algo"): $(json_escape "$hash"),
|
|||
|
|
"hash": "$(nix-hash --to-sri --type "$hash_algo" "$hash")"
|
|||
|
|
}
|
|||
|
|
EOF
|
|||
|
|
# vim: noet ci pi sts=0
|