summary refs log tree commit diff
path: root/pkgs/build-support/fetchzip/nix-prefetch-zip
blob: 76255ab36747e2d6ce6bda0e8e0560742221bb74 (plain) (blame)
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#! /bin/sh -e

usage(){
    echo  >&2 "syntax: nix-prefetch-zip [OPTIONS] [URL [EXPECTED-HASH]]

Options:
      --url         url    The url of the archive to fetch.
      --name        name   The name to use for the store path (defaults to \`basename \$url\`).
      --hash        hash   The hash of unpacked archive.
      --hash-type   type   Use the specified cryptographic hash algorithm, which can be one of md5, sha1, and sha256.
      --leave-root         Keep the root directory of the archive.
      --help               Show this help text.
"
    exit 1
}


argi=0
argfun=""
for arg; do
  if test -z "$argfun"; then
    case $arg in
      --url) argfun=set_url;;
      --name) argfun=set_name;;
      --hash) argfun=set_expHash;;
      --hash-type) argfun=set_hashType;;
      --leave-root) leaveRoot=true;;
      --help) usage;;
      *) argi=$(($argi + 1))
         case $argi in
           1) url=$arg;;
           2) rev=$arg;;
           3) expHash=$arg;;
           *) echo "Unexpected argument: $arg" >&2
              usage
              ;;
         esac
         ;;
    esac
  else
    case $argfun in
      set_*)
        var=$(echo $argfun | sed 's,^set_,,')
        eval "$var=\$arg"
        ;;
    esac
    argfun=""
  fi
done

if [ -z "$url" ]; then
  echo "Error: No --url flag given" >&2
  usage
fi

if [ -z "$name" ]; then
  name=$(basename "$url")
fi

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

hashFormat="--base32"

tmp=$(mktemp -d 2>/dev/null || mktemp -d -t "$$")
trap "rm -rf '$tmp'" EXIT

unpackDir=$tmp/unpacked/$name
mkdir -p $unpackDir
downloadedFile=$tmp/$name

unpackFile() {
  local curSrc="$1"

  case "$curSrc" in
    *.tar.xz | *.tar.lzma)
      # Don't rely on tar knowing about .xz.
      xz -d < $curSrc | tar xf -
      ;;
    *.tar | *.tar.* | *.tgz | *.tbz2)
      # GNU tar can automatically select the decompression method
      # (info "(tar) gzip").
      tar xf $curSrc
      ;;
    *.zip)
      unzip -qq $curSrc
      ;;
    *)
      echo "source archive $curSrc has unknown type" >&2
      exit 1
      ;;
  esac
}

# 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" "$name")
  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
  curl="curl \
   --location --max-redirs 20 \
   --disable-epsv \
   --insecure"

  if ! $curl --fail "$url" --output "$downloadedFile"; then
    echo "error: could not download $url" >&2
    exit 1
  fi

  cd $unpackDir
  unpackFile "$downloadedFile"

  # FIXME: handle zip files that contain a single regular file.
  if [ -z "$leaveRoot" ]; then
    shopt -s dotglob
    if [ $(ls -d $unpackDir/* | wc -l) != 1 ]; then
      echo "error: zip file must contain a single directory."
      exit 1
    fi
    fn=$(cd "$unpackDir" && echo *)
    mv $unpackDir/$fn/* "$unpackDir/"
    rmdir "$unpackDir/$fn"
  fi

  # Compute the hash.
  hash=$(nix-hash --type $hashType $hashFormat $unpackDir)
  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" $unpackDir)

  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