summaryrefslogtreecommitdiffstats
path: root/bin/prefetch
blob: a87dd18999d9707472491bf5e165ddeea7be5aeb (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
#! /bin/sh
#
# usage: prefetch repo_name out_link
#
# Make the specified repository available as out_link.
#
set -euf

repo_name=$1
out_link=$2

if test "$repo_name" != nixpkgs; then
  echo "prefetch: cannot fetch $repo_name, yet" >&2
  exit -1
fi

git_rev=$(nixos-query nixpkgs.rev)
git_url=$(nixos-query nixpkgs.url)
dirty=$(nixos-query nixpkgs.dirty)

case $dirty in true)
  ln -snf "$git_url" "$out_link"
  echo "prefetch: using $git_url as it is" >&2
  exit
esac

# Put all bases in the same place as out_link.
# Notice how out_link must not clash with cache_dir and work_dir.
cache_base=$(dirname "$out_link")
work_base=$(dirname "$out_link")

# cache_dir points to a (maybe non-existent) directory, where a shared cache of
# the repository should be maintained.  The shared cache is used to create
# multiple working trees of the repository.
cache_dir=$cache_base/$(echo "$git_url" | urlencode)

# work_dir points to a (maybe non-existent) directory, where a specific
# revision of the repository is checked out.
work_dir=$work_base/$(echo "$git_rev" | urlencode)

cache_git() {
  git --git-dir="$cache_dir" "$@"
}

work_git() {
  git -C "$work_dir" "$@"
}

is_up_to_date() {
  test -d "$cache_dir" &&
  test -d "$work_dir" &&
  test "$(cache_git rev-parse --verify "$git_rev")" = "$git_rev" &&
  test "$(work_git rev-parse --verify HEAD)" = "$git_rev"
}

# Notice how the remote name "origin" has been chosen arbitrarily, but must be
# kept in sync with the default value of nixpkgs.rev.
if ! is_up_to_date; then
  if ! test -d "$cache_dir"; then
    mkdir -p "$cache_dir"
    cache_git init --bare
  fi
  if ! cache_git_url=$(cache_git config remote.origin.url); then
    cache_git remote add origin "$git_url"
  elif test "$cache_git_url" != "$git_url"; then
    cache_git remote set-url origin "$git_url"
  fi
  cache_git fetch origin
  if ! test -d "$work_dir"; then
    git clone -n --shared "$cache_dir" "$work_dir"
  fi
  commit_name=$(cache_git rev-parse --verify "$git_rev")
  work_git checkout "$commit_name" -- "$(readlink -f "$work_dir")"
  work_git checkout -q "$commit_name"
  work_git submodule init
  work_git submodule update
fi
work_git clean -dxf

# Relative links are nicer, and actually we know that work_dir and out_link are
# the same.  But, for robustness, check anyway.. :)
if test "$(dirname "$work_dir")" = "$(dirname "$out_link")"; then
  ln -snf "$(basename "$work_dir")" "$out_link"
else
  ln -snf "$work_dir" "$out_link"
fi

echo "prefetch: using $git_url $(work_git log --oneline -n1)" >&2