From 4a1a2203ac473b86d65704cab7469d299446b654 Mon Sep 17 00:00:00 2001 From: Rob Vermaas Date: Thu, 26 Apr 2012 09:37:48 +0200 Subject: [PATCH] I should sleep... grmbl --- src/script/nix-prefetch-git | 270 +++++++++++++++++++++++++++++++++++- 1 file changed, 269 insertions(+), 1 deletion(-) diff --git a/src/script/nix-prefetch-git b/src/script/nix-prefetch-git index d89750a9..979aa531 100755 --- a/src/script/nix-prefetch-git +++ b/src/script/nix-prefetch-git @@ -1 +1,269 @@ -You are being redirected. \ No newline at end of file +#! /bin/sh -e + +url=$1 +rev=$2 +expHash=$3 +hashType=$NIX_HASH_ALGO +deepClone=$NIX_PREFETCH_GIT_DEEP_CLONE +leaveDotGit=$NIX_PREFETCH_GIT_LEAVE_DOT_GIT +builder= + +if test -n "$deepClone"; then + deepClone=true +else + deepClone=false +fi + +if test "$leaveDotGit" != 1; then + leaveDotGit= +else + leaveDotGit=true +fi + + +argi=0 +argfun="" +for arg; do + if test -z "$argfun"; then + case $arg in + --out) argfun=set_out;; + --url) argfun=set_url;; + --rev) argfun=set_rev;; + --hash) argfun=set_hashType;; + --deepClone) deepClone=true;; + --no-deepClone) deepClone=false;; + --leave-dotGit) leaveDotGit=true;; + --builder) builder=true;; + *) + argi=$(($argi + 1)) + case $argi in + 1) url=$arg;; + 2) rev=$arg;; + 3) expHash=$arg;; + *) exit 1;; + esac + ;; + esac + else + case $argfun in + set_*) + var=$(echo $argfun | sed 's,^set_,,') + eval $var=$arg + ;; + esac + argfun="" + fi +done + +usage(){ + echo >&2 "syntax: nix-prefetch-git [options] [URL [REVISION [EXPECTED-HASH]]] + +Options: + --out path Path where the output would be stored. + --url url Any url understand by 'git clone'. + --rev ref Any sha1 or references (such as refs/heads/master) + --hash h Expected hash. + --deepClone Clone submodules recursively. + --no-deepClone Do not clone submodules. + --leave-dotGit Keep the .git directories. + --builder Clone as fetchgit does, but url, rev, and out option are mandatory. +" + exit 1 +} + +if test -z "$url"; then + usage +fi + + +init_remote(){ + local url=$1; + git init; + git remote add origin $url; +} + +# Return the reference of an hash if it exists on the remote repository. +ref_from_hash(){ + local hash=$1; + git ls-remote origin | sed -n "\,$hash\t, { s,\(.*\)\t\(.*\),\2,; p; q}" +} + +# Return the hash of a reference if it exists on the remote repository. +hash_from_ref(){ + local ref=$1 + git ls-remote origin | sed -n "\,\t$ref, { s,\(.*\)\t\(.*\),\1,; p; q}" +} + +# Fetch everything and checkout the right sha1 +checkout_hash(){ + local hash="$1"; + local ref="$2"; + + if test -z "$hash"; then + hash=$(hash_from_ref $ref); + fi; + + git fetch ${builder:+--progress} origin || return 1 + git checkout -b fetchgit $hash || return 1 +} + +# Fetch only a branch/tag and checkout it. +checkout_ref(){ + local hash="$1"; + local ref="$2"; + + if "$deepClone"; then + # The caller explicitly asked for a deep clone. Deep clones + # allow "git describe" and similar tools to work. See + # http://thread.gmane.org/gmane.linux.distributions.nixos/3569 + # for a discussion. + return 1 + fi + + if test -z "$ref"; then + ref=$(ref_from_hash $hash); + fi; + + if test -n "$ref"; then + # --depth option is ignored on http repository. + git fetch ${builder:+--progress} --depth 1 origin +"$ref" || return 1 + git checkout -b fetchgit FETCH_HEAD || return 1 + else + return 1; + fi; +} + +# Update submodules +init_submodules(){ + # Add urls into .git/config file + git submodule init + + # list submodule directories and their hashes + git submodule status | + while read l; do + # checkout each submodule + local hash=$(echo $l | sed 's,^-\([0-9a-f]*\) \(.*\)$,\1,'); + local dir=$(echo $l | sed 's,^-\([0-9a-f]*\) \(.*\)$,\2,'); + local url=$(sed -n "\,$dir, { :loop; n; s,^.*url = ,,; T loop; p; q }" .git/config); + + clone "$dir" "$url" "$hash" ""; + done; +} + +clone(){ + local top=$(pwd) + local dir="$1" + local url="$2" + local hash="$3" + local ref="$4" + + cd $dir; + + # Initialize the repository. + init_remote "$url"; + + # Download data from the repository. + checkout_ref "$hash" "$ref" || + checkout_hash "$hash" "$ref" || ( + echo 1>&2 "Unable to checkout $hash$ref from $url."; + exit 1; + ) + + # Checkout linked sources. + init_submodules; + + if [ -z "$builder" -a -f .topdeps ]; then + if tg help 2>&1 > /dev/null + then + echo "populating TopGit branches..." + tg remote --populate origin + else + echo "WARNING: would populate TopGit branches but TopGit is not available" >&2 + echo "WARNING: install TopGit to fix the problem" >&2 + fi + fi + + cd $top; +} + +clone_user_rev() { + local dir="$1" + local url="$2" + local rev="$3" + + # Perform the checkout. + case "$rev" in + HEAD|refs/*) + clone "$dir" "$url" "" "$rev" 1>&2;; + [0-9a-f]*) + if test -z "$(echo $rev | tr -d 0123456789abcdef)"; then + clone "$dir" "$url" "$rev" "" 1>&2; + else + echo 1>&2 "Bad commit hash or bad reference."; + exit 1; + fi;; + "") + clone "$dir" "$url" "" "HEAD" 1>&2;; + esac + + # Allow doing additional processing before .git removal + eval "$NIX_PREFETCH_GIT_CHECKOUT_HOOK" + if test -z "$leaveDotGit"; then + echo "removing \`.git'..." >&2 + find $dir -name .git\* | xargs rm -rf + fi +} + +if test -n "$builder"; then + test -n "$out" -a -n "$url" -a -n "$rev" || usage + mkdir $out + clone_user_rev "$out" "$url" "$rev" +else + if test -z "$hashType"; then + hashType=sha256 + fi + + # If the hash was given, a file with that hash may already be in the + # store. + if test -n "$expHash"; then + finalPath=$(nix-store --print-fixed-path --recursive "$hashType" "$expHash" git-export) + if ! nix-store --check-validity "$finalPath" 2> /dev/null; then + finalPath= + fi + hash=$expHash + 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 test -z "$finalPath"; then + + tmpPath=/tmp/git-checkout-tmp-$$ + tmpFile=$tmpPath/git-export + mkdir $tmpPath $tmpFile + + trap "rm -rf $tmpPath" EXIT + + # Perform the checkout. + clone_user_rev "$tmpFile" "$url" "$rev" + + # Compute the hash. + hash=$(nix-hash --type $hashType $hashFormat $tmpFile) + if ! test -n "$QUIET"; then echo "hash is $hash" >&2; fi + + # Add the downloaded file to the Nix store. + finalPath=$(nix-store --add-fixed --recursive "$hashType" $tmpFile) + + if test -n "$expHash" -a "$expHash" != "$hash"; then + echo "hash mismatch for URL \`$url'" + exit 1 + fi + fi + + if ! test -n "$QUIET"; then echo "path is $finalPath" >&2; fi + + echo $hash + + if test -n "$PRINT_PATH"; then + echo $finalPath + fi +fi