dist.sh (5957B)
1 #!/bin/sh 2 # Build the source tarball, or check one. Driven by "make dist" and 3 # "make distcheck"; see those targets in the top-level Makefile. 4 # 5 # ./scripts/dist.sh write ./kych-<version>.tar.gz 6 # ./scripts/dist.sh --check unpack that tarball and build, test and 7 # install the tree it contains 8 # 9 # The tarball has to carry three things that a plain "git archive" does not: 10 # 11 # * the swiyu-verifier/upstream submodule, which is a separate upstream and 12 # is not part of the superproject's tree object; 13 # * .version, so that a build from the tarball does not need git (this is 14 # what scripts/get_version.sh reads when there is no .git); 15 # * the pre-built man pages, so that a build from the tarball does not need 16 # sphinx either. 17 # 18 set -eu 19 20 top_dir=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd) 21 cd "$top_dir" 22 23 # Keep this in step with debian/stamp-version.sh, which derives the Debian 24 # version the same way: scripts/get_version.sh is "git describe --tags" with 25 # the leading "v" stripped, and falls back to the commit count when no tag is 26 # reachable from HEAD. 27 resolve_version() { 28 version=$(./scripts/get_version.sh) 29 case "$version" in 30 [0-9]*) ;; 31 *) 32 if [ -e .git ]; then 33 version="0.0.0-$(git rev-list --count HEAD)-g$(git rev-parse --short=8 HEAD)" 34 # get_version.sh cached the bogus value; do not ship it. 35 rm -f .version 36 else 37 echo "$0: no git tag and no git repository; cannot derive a version" >&2 38 exit 1 39 fi 40 ;; 41 esac 42 echo "$version" 43 } 44 45 make_dist() { 46 if [ ! -e .git ]; then 47 echo "$0: not a git checkout; 'make dist' builds the tarball from git" >&2 48 exit 1 49 fi 50 51 version=$(resolve_version) 52 tarball="kych-$version.tar.gz" 53 dist_dir="kych-$version" 54 55 # The tarball is built from HEAD, not from the working tree, so anything 56 # uncommitted silently will not be in it. That is the usual surprise with 57 # git-archive-based dist rules, hence the warning. 58 if ! git diff-index --quiet HEAD -- 2>/dev/null; then 59 echo "$0: WARNING: the working tree has uncommitted changes;" \ 60 "the tarball is built from HEAD and will not contain them" >&2 61 fi 62 63 # Without it the tarball cannot build the swiyu-verifier package, which is 64 # half of what this source tree produces. 65 if [ ! -f swiyu-verifier/upstream/pom.xml ]; then 66 echo "$0: swiyu-verifier/upstream is not checked out: run ./bootstrap" >&2 67 exit 1 68 fi 69 70 staging=$(mktemp -d) 71 trap 'rm -rf "$staging"' EXIT INT TERM 72 mkdir "$staging/$dist_dir" 73 74 echo "dist: exporting HEAD" 75 git archive --format=tar HEAD | tar -x -C "$staging/$dist_dir" 76 77 # $sm_path is the submodule's path relative to the top of the tree, which 78 # is exactly the prefix it needs inside the tarball. 79 echo "dist: exporting submodules" 80 export KYCH_DIST_ROOT="$staging/$dist_dir" 81 git submodule foreach --quiet \ 82 'git archive --format=tar --prefix="$sm_path/" HEAD | 83 tar -x -C "$KYCH_DIST_ROOT"' 84 85 echo "$version" > "$staging/$dist_dir/.version" 86 87 # Only the pages themselves: the output directory also holds sphinx's 88 # .doctrees cache and the stamp file the Makefile uses. 89 pages=$(find doc/man -maxdepth 1 -name '*.[15]' -print 2>/dev/null || true) 90 if [ -n "$pages" ]; then 91 echo "dist: including the pre-built man pages" 92 mkdir -p "$staging/$dist_dir/doc/man" 93 for page in $pages; do 94 cp "$page" "$staging/$dist_dir/doc/man/" 95 done 96 else 97 echo "$0: WARNING: no man pages in doc/man; a build from the tarball" \ 98 "will need python3-sphinx. Run 'make man' first." >&2 99 fi 100 101 # Reproducible-ish: a fixed owner and sort order, and the commit's own 102 # timestamp, so that two dist runs from the same commit agree. 103 rm -f "$tarball" 104 tar -c -z -f "$tarball" \ 105 --numeric-owner --owner=0 --group=0 --sort=name \ 106 --mtime="@$(git log -1 --format=%ct)" \ 107 -C "$staging" "$dist_dir" 108 109 rm -rf "$staging" 110 trap - EXIT INT TERM 111 echo "dist: wrote $tarball ($(du -h "$tarball" | cut -f1))" 112 } 113 114 check_dist() { 115 version=$(resolve_version) 116 tarball="kych-$version.tar.gz" 117 dist_dir="kych-$version" 118 119 if [ ! -f "$tarball" ]; then 120 echo "$0: $tarball does not exist; run 'make dist' first" >&2 121 exit 1 122 fi 123 124 # The verifier is a 300 MB Maven download and a Java build of a foreign 125 # upstream; checking the tarball does not need it, and a build host without 126 # a JDK 25 could not do it anyway. Set this to "yes" to include it. 127 verifier_flag=--disable-verifier 128 if [ "${KYCH_DISTCHECK_VERIFIER:-no}" = yes ]; then 129 verifier_flag=--enable-verifier 130 fi 131 132 work=$(mktemp -d) 133 trap 'rm -rf "$work"' EXIT INT TERM 134 135 echo "distcheck: unpacking $tarball" 136 tar -x -z -f "$tarball" -C "$work" 137 test -d "$work/$dist_dir" || { 138 echo "$0: $tarball does not unpack into $dist_dir" >&2 139 exit 1 140 } 141 142 # Built from a tree with no .git, which is the point: it proves the tarball 143 # is self-contained, down to the version in .version. 144 test ! -e "$work/$dist_dir/.git" || { 145 echo "$0: the tarball contains a .git directory" >&2 146 exit 1 147 } 148 149 inst="$work/_inst" 150 echo "distcheck: configure, build, check, install" 151 ( 152 cd "$work/$dist_dir" 153 ./configure --prefix="$inst" "$verifier_flag" 154 make 155 make check 156 make install 157 make installcheck 158 ) 159 160 rm -rf "$work" 161 trap - EXIT INT TERM 162 echo "distcheck: $tarball is complete and builds, tests and installs cleanly" 163 } 164 165 case "${1:---dist}" in 166 --dist) make_dist ;; 167 --check) check_dist ;; 168 *) 169 echo "usage: $0 [--dist|--check]" >&2 170 exit 1 171 ;; 172 esac