summaryrefslogtreecommitdiffstats
path: root/bin/prefetch
diff options
context:
space:
mode:
Diffstat (limited to 'bin/prefetch')
-rwxr-xr-xbin/prefetch88
1 files changed, 88 insertions, 0 deletions
diff --git a/bin/prefetch b/bin/prefetch
new file mode 100755
index 00000000..a87dd189
--- /dev/null
+++ b/bin/prefetch
@@ -0,0 +1,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