aboutsummaryrefslogtreecommitdiff
path: root/scripts/nix-prefetch-url.in
blob: ad4cfa30b2b95983e85acc69b1c3008a5fdd4e55 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#! @shell@ -e

url=$1
expHash=$2

# needed to make it work on NixOS
export PATH=$PATH:@coreutils@

hashType=$NIX_HASH_ALGO
if test -z "$hashType"; then
    hashType=sha256
fi

hashFormat=
if test "$hashType" != "md5"; then
    hashFormat=--base32
fi

if test -z "$url"; then
    echo "syntax: nix-prefetch-url URL [EXPECTED-HASH]" >&2
    exit 1
fi

name=$(basename "$url")
if test -z "$name"; then echo "invalid url"; exit 1; fi


# If the hash was given, a file with that hash may already be in the
# store.
if test -n "$expHash"; then
    finalPath=$(@bindir@/nix-store --print-fixed-path "$hashType" "$expHash" "$name")
    if ! @bindir@/nix-store --check-validity "$finalPath" 2> /dev/null; then
        finalPath=
    fi
    hash=$expHash
fi


mkTempDir() {
    local i=0
    while true; do
        if test -z "$TMPDIR"; then TMPDIR=/tmp; fi
        tmpPath=$TMPDIR/nix-prefetch-url-$$-$i
        if mkdir "$tmpPath"; then break; fi
        # !!! to bad we can't check for ENOENT in mkdir, so this check
        # is slightly racy (it bombs out if somebody just removed
        # $tmpPath...).
        if ! test -e "$tmpPath"; then exit 1; fi
        i=$((i + 1))
    done
    trap removeTempDir EXIT SIGINT SIGQUIT
}

removeTempDir() {
    if test -n "$tmpPath"; then
        rm -rf "$tmpPath" || true
    fi
}


doDownload() {
    @curl@ $cacheFlags --fail -# --location --max-redirs 20 --disable-epsv \
        --cookie-jar $tmpPath/cookies "$url" -o $tmpFile
}


# If we don't know the hash or a file with that hash doesn't exist,
# download the file and add it to the store.
if test -z "$finalPath"; then

    mkTempDir
    tmpFile=$tmpPath/$name

    # Optionally do timestamp-based caching of the download.
    # Actually, the only thing that we cache in $NIX_DOWNLOAD_CACHE is
    # the hash and the timestamp of the file at $url.  The caching of
    # the file *contents* is done in Nix store, where it can be
    # garbage-collected independently.
    if test -n "$NIX_DOWNLOAD_CACHE"; then
        echo -n "$url" > $tmpPath/url
        urlHash=$(nix-hash --type sha256 --base32 --flat $tmpPath/url)
        echo "$url" > "$NIX_DOWNLOAD_CACHE/$urlHash.url"
        cachedHashFN="$NIX_DOWNLOAD_CACHE/$urlHash.$hashType"
        cachedTimestampFN="$NIX_DOWNLOAD_CACHE/$urlHash.stamp"
        cacheFlags="--remote-time"
        if test -e "$cachedTimestampFN" -a -e "$cachedHashFN"; then
            # Only download the file if it is newer than the cached version.
            cacheFlags="$cacheFlags --time-cond $cachedTimestampFN"
        fi
    fi

    # Perform the download.
    doDownload

    if test -n "$NIX_DOWNLOAD_CACHE" -a ! -e $tmpFile; then
        # Curl didn't create $tmpFile, so apparently there's no newer
        # file on the server.
        hash=$(cat $cachedHashFN)
        finalPath=$(@bindir@/nix-store --print-fixed-path "$hashType" "$hash" "$name") 
        if ! @bindir@/nix-store --check-validity "$finalPath" 2> /dev/null; then
            echo "cached contents of \`$url' disappeared, redownloading..." >&2
            finalPath=
            cacheFlags="--remote-time"
            doDownload
        fi
    fi

    if test -z "$finalPath"; then

        # Compute the hash.
        hash=$(@bindir@/nix-hash --type "$hashType" $hashFormat --flat $tmpFile)
        if ! test -n "$QUIET"; then echo "hash is $hash" >&2; fi

        if test -n "$NIX_DOWNLOAD_CACHE"; then
            echo $hash > $cachedHashFN
            touch -r $tmpFile $cachedTimestampFN
        fi

        # Add the downloaded file to the Nix store.
        finalPath=$(@bindir@/nix-store --add-fixed "$hashType" $tmpFile)

        if test -n "$expHash" -a "$expHash" != "$hash"; then
            echo "hash mismatch for URL \`$url'" >&2
            exit 1
        fi
        
    fi
fi


if ! test -n "$QUIET"; then echo "path is $finalPath" >&2; fi

echo $hash

if test -n "$PRINT_PATH"; then
    echo $finalPath
fi