Skip to content

Commit 922f348

Browse files
committed
debian-iso: add autoupdate script
Because we want to spend less time working out how to update our upstream dependencies, add a script that can automatically determine the latest debian ISO, and automatically make a commit to upgrade to it. This is as simple as the following command: $ ./bump-debian-iso.sh auto It includes a basic general-purpose bazel code modification tool that should help us make these kinds of autoupdate scripts in general.
1 parent 0579eb4 commit 922f348

File tree

3 files changed

+143
-4
lines changed

3 files changed

+143
-4
lines changed

tools/bump-debian-iso.sh

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#!/bin/bash
2+
set -euo pipefail
3+
4+
cd "$(dirname "$0")"
5+
6+
VERSION="${1:-}"
7+
TARGET="../platform/spire/debian-iso/deps.bzl"
8+
9+
if [ "$VERSION" = "" ]
10+
then
11+
echo "usage: $0 20190702+deb10u3 [or other new version]" 1>&2
12+
echo "usage: $0 auto" 1>&2
13+
echo 1>&2
14+
echo "this command will try to update debian-iso/deps.bzl and then make a commit" 1>&2
15+
exit 1
16+
fi
17+
18+
## discover the latest version, if relevant
19+
20+
if [ "$VERSION" = "auto" ]
21+
then
22+
# yes, this is a HTTP fetch, and in theory could be MITM'd, but if the version number is
23+
# invalid, debian-iso-checksum.sh will just fail later.
24+
VERSION="$(curl -s http://debian.csail.mit.edu/debian/dists/buster/Release |
25+
grep -E "^ [0-9a-f]{64} [ 0-9]+ main/installer-amd64/[0-9]+[+][0-9a-z]+/images/SHA256SUMS$" |
26+
sed 's|^[^/]*/installer-amd64/\([^/]*\)/.*|\1|g')"
27+
fi
28+
29+
## make sure the git state is clean enough for us
30+
31+
if ! git diff --quiet "${TARGET}" || ! git diff --cached --quiet "${TARGET}"
32+
then
33+
echo "cannot update ${TARGET} automatically; it has already been modified" 1>&2
34+
exit 1
35+
fi
36+
37+
## make the change
38+
39+
./debian-iso-checksum.sh "${VERSION}" | ./update-defs.py "${TARGET}"
40+
41+
## make the commit
42+
43+
if git diff --quiet "${TARGET}"
44+
then
45+
echo "no commit to make; files did not change" 1>&2
46+
exit 1
47+
fi
48+
49+
git commit -e -v "${TARGET}" -m "debian-iso: bump version to $VERSION" -m "This commit was automatically created with bump-debian-iso.sh."

tools/debian-checksum.sh tools/debian-iso-checksum.sh

+10-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
#!/bin/bash
22
set -e -u
33

4-
VERSION="20190702+deb10u2"
4+
VERSION="${1:-}"
55
RELEASE="buster"
66

7+
if [ "$VERSION" = "" ]
8+
then
9+
echo "usage: debian-iso-checksum.sh <version>" 1>&2
10+
exit 1
11+
fi
12+
713
echo "finding hash for release ${RELEASE} version ${VERSION}:" >&2
814

915
WORK=$(mktemp -d)
@@ -29,6 +35,6 @@ echo >&2
2935
echo "new version block:" >&2
3036

3137
echo >&2
32-
echo "VERSION = '${VERSION}'"
33-
echo "RELEASE = '${RELEASE}'"
34-
echo "MINI_ISO_HASH = '$(grep './netboot/mini.iso' SHA256SUMS | cut -d " " -f 1)'"
38+
echo "VERSION = \"${VERSION}\""
39+
echo "RELEASE = \"${RELEASE}\""
40+
echo "MINI_ISO_HASH = \"$(grep './netboot/mini.iso' SHA256SUMS | cut -d " " -f 1)\""

tools/update-defs.py

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#!/usr/bin/env python3
2+
"""
3+
update-defs: change a set of Bazel variable declarations in a particular file.
4+
5+
For example, if a file named `debian-iso/deps.bzl` had the following lines in the middle:
6+
7+
VERSION = '20190702+deb10u2'
8+
RELEASE = 'buster'
9+
MINI_ISO_HASH = 'fa713fb9ab7853de6aefe6b83c58bcdba19ef79a0310de84d40dd2754a9539d7'
10+
11+
And you ran the following command with the following input:
12+
13+
$ ./update-defs.py debian-iso/deps.bzl
14+
VERSION = '20190702+deb10u3'
15+
RELEASE = 'buster'
16+
MINI_ISO_HASH = '26b6f6f6bcb24c4e59b965d4a2a6c44af5d79381b9230d69a7d4db415ddcb4cd'
17+
18+
Then those three lines (and only those lines) would be updated in `deps.bzl`.
19+
"""
20+
21+
import re
22+
import sys
23+
24+
25+
def is_valid_identifier(text):
26+
return bool(re.match("^[A-Z0-9_]+$", text))
27+
28+
29+
def get_match(line):
30+
if "=" in line:
31+
match = line.split("=",1)[0].strip()
32+
if is_valid_identifier(match):
33+
return match
34+
35+
36+
def parse_changes(changes):
37+
mapping = {}
38+
for line in changes.split("\n"):
39+
if not line: continue
40+
match = get_match(line)
41+
if match is None:
42+
raise ValueError("could not parse change line: %s" % repr(line))
43+
if match in mapping:
44+
raise KeyError("duplicate input mapping: %s" % match)
45+
mapping[match] = line
46+
return mapping
47+
48+
49+
def apply_changes(line, lookup, used):
50+
match = get_match(line)
51+
if match is not None and match in lookup:
52+
used[match] += 1
53+
line = lookup[match]
54+
print("=>", line)
55+
return line
56+
57+
58+
def perform_changes(filename, changes):
59+
with open(filename, "r") as f:
60+
lines = f.read().split("\n")
61+
lookup = parse_changes(changes)
62+
used = {var: 0 for var in lookup}
63+
lines = [apply_changes(line, lookup, used) for line in lines]
64+
for var, usedcount in used.items():
65+
if usedcount < 1:
66+
raise ValueError("did not use requested change: %s was not used" % (repr(var)))
67+
elif usedcount > 1:
68+
raise ValueError("used requested change multiple times: %s was used %d times" % (repr(var), usedcount))
69+
with open(filename, "w") as f:
70+
f.write("\n".join(lines))
71+
print()
72+
print("updated", len(lookup), "entries")
73+
74+
75+
def main(argv):
76+
if len(argv) != 2:
77+
print("usage: %s <target file>", file=sys.stderr)
78+
sys.exit(1)
79+
changes = sys.stdin.read()
80+
perform_changes(sys.argv[1], changes)
81+
82+
83+
if __name__ == "__main__":
84+
main(sys.argv)

0 commit comments

Comments
 (0)