SPS · log · files · refs · tags · releases · people · languages · GitHub · commit
d2c1429
sget: rebuild when a cached package's definition digest changes.
Parents
Stat
DESIGN.md | 5 +++++ bin/mkpkg | 9 ++++++--- bin/sget | 43 ++++++++++++++++++++++++++++++++++++------- lib/package.awk | 8 ++++++-- tests/test_build.sh | 5 ++++- tests/test_dependencies.sh | 7 +++++-- tests/test_highlevel.sh | 9 +++++++++ 7 files changed, 71 insertions(+), 15 deletions(-)
Diff
diff --git a/DESIGN.md b/DESIGN.md
index f9e92b5..4ad8cbb 100644
--- a/DESIGN.md
+++ b/DESIGN.md
@@ -143,12 +143,17 @@ etc/...
```text
format 1
+definition_sha256 VALUE
name VALUE
version VALUE
release VALUE
arch VALUE
```
+`definition_sha256` binds a built artifact to the indexed recipe and its
+support files. `sget` rebuilds a cached artifact when this digest is absent or
+does not match, even when name, version, and release are unchanged.
+
`.SPS/files` is a sorted list of normalized payload paths. Directory entries
end in `/`.
diff --git a/bin/mkpkg b/bin/mkpkg
index 4a80419..477b5cd 100755
--- a/bin/mkpkg
+++ b/bin/mkpkg
@@ -246,7 +246,7 @@ command -v mktemp >/dev/null 2>&1 || die "mktemp is required"
recipe_dir=$(CDPATH= cd "$(dirname "$recipe")" 2>/dev/null && pwd) ||
die "cannot enter recipe directory"
recipe_file=$recipe_dir/$(basename "$recipe")
-sps_definition_sha256 "$recipe_file" >/dev/null ||
+definition_sha256=$(sps_definition_sha256 "$recipe_file") ||
die_status 4 "invalid package definition support inputs"
default_arch=${SPS_ARCH:-}
if [ -z "$default_arch" ]; then
@@ -957,8 +957,11 @@ meta=$stage_dir/.SPS/meta
files=$stage_dir/.SPS/files
file_hashes=$stage_dir/.SPS/hashes
-awk -F '\t' '
-BEGIN { print "format\t1" }
+awk -F '\t' -v definition_sha256="$definition_sha256" '
+BEGIN {
+ print "format\t1"
+ print "definition_sha256\t" definition_sha256
+}
$1 == "name" || $1 == "version" || $1 == "release" || $1 == "arch" ||
$1 == "description" {
scalar[$1] = $0
diff --git a/bin/sget b/bin/sget
index ba372f9..a45b904 100755
--- a/bin/sget
+++ b/bin/sget
@@ -222,6 +222,7 @@ sget_verify_artifact_identity()
sget_verify_version=$3
sget_verify_release=$4
sget_verify_arch=$5
+ sget_verify_definition=${6-}
case $sget_verify_archive in
*.tar.gz|*.tgz)
@@ -254,7 +255,15 @@ sget_verify_artifact_identity()
[ "$1" = "$sget_verify_name" ] &&
[ "$2" = "$sget_verify_version" ] &&
[ "$3" = "$sget_verify_release" ] &&
- [ "$4" = "$sget_verify_arch" ]
+ [ "$4" = "$sget_verify_arch" ] || return 1
+
+ [ -n "$sget_verify_definition" ] || return 0
+ sget_verify_cached_definition=$(printf '%s\n' "$sget_verify_meta" |
+ awk -v sps_action=meta-get -v sps_key_name=definition_sha256 \
+ -v sps_program=sget -f "$SPS_LIBDIR/package.awk" 2>/dev/null) ||
+ return 2
+ [ "$sget_verify_cached_definition" = "$sget_verify_definition" ] ||
+ return 2
}
# Set by the upgrade path.
@@ -462,12 +471,31 @@ sget_install()
fi
done
if [ -n "$sget_artifact" ]; then
+ sget_cache_status=0
sget_verify_artifact_identity "$sget_artifact" "$sget_package" \
- "$sget_version" "$sget_release" "$sget_arch" ||
- sps_die "$SPS_EX_PACKAGE" "cached artifact identity is invalid for '$sget_package': $sget_artifact"
- sget_note "binary cache hit"
- printf '%s: using cached %s\n' "$sps_prog" "${sget_artifact##*/}"
- else
+ "$sget_version" "$sget_release" "$sget_arch" \
+ "$sget_recipe_hash" || sget_cache_status=$?
+ case $sget_cache_status in
+ 0)
+ sget_note "binary cache hit"
+ printf '%s: using cached %s\n' \
+ "$sps_prog" "${sget_artifact##*/}"
+ ;;
+ 2)
+ printf '%s: discarding stale cached %s\n' \
+ "$sps_prog" "${sget_artifact##*/}"
+ rm -f "$sget_artifact" ||
+ sps_die "$SPS_EX_PERMISSION" \
+ "cannot replace stale cache artifact: $sget_artifact"
+ sget_artifact=
+ ;;
+ *)
+ sps_die "$SPS_EX_PACKAGE" \
+ "cached artifact identity is invalid for '$sget_package': $sget_artifact"
+ ;;
+ esac
+ fi
+ if [ -z "$sget_artifact" ]; then
sget_note "binary cache miss"
sget_note "building $sget_recipe_dir"
sget_artifact_file=$sget_work/artifact-$sget_package
@@ -497,7 +525,8 @@ sget_install()
[ -f "$sget_artifact" ] ||
sps_die "$SPS_EX_BUILD" "mkpkg artifact for '$sget_package' is missing: $sget_artifact"
sget_verify_artifact_identity "$sget_artifact" "$sget_package" \
- "$sget_version" "$sget_release" "$sget_arch" ||
+ "$sget_version" "$sget_release" "$sget_arch" \
+ "$sget_recipe_hash" ||
sps_die "$SPS_EX_PACKAGE" "mkpkg produced the wrong package identity for '$sget_package'"
fi
diff --git a/lib/package.awk b/lib/package.awk
index f2fa1bd..f66b84c 100644
--- a/lib/package.awk
+++ b/lib/package.awk
@@ -57,13 +57,17 @@ function sps_meta_line(line, pos, key, value, controls) {
sps_meta_count[key]++
if (!(key in sps_meta_first))
sps_meta_first[key] = value
- if ((key == "format" || key == "name" || key == "version" ||
- key == "release" || key == "arch") && sps_meta_count[key] > 1) {
+ if ((key == "format" || key == "definition_sha256" || key == "name" ||
+ key == "version" || key == "release" || key == "arch") &&
+ sps_meta_count[key] > 1) {
sps_diag("duplicate metadata key '" key "'")
return 1
}
if (key == "format" && value != "1")
sps_diag("unsupported package format '" value "'")
+ if (key == "definition_sha256" &&
+ (value !~ /^[0123456789abcdef]+$/ || length(value) != 64))
+ sps_diag("invalid package definition digest")
if (key == "name" && !sps_valid_name(value))
sps_diag("invalid package name '" value "'")
if ((key == "version" || key == "release") &&
diff --git a/tests/test_build.sh b/tests/test_build.sh
index bba6721..6ae05cb 100755
--- a/tests/test_build.sh
+++ b/tests/test_build.sh
@@ -84,7 +84,10 @@ $1 == "name" && $2 == "hello-sps" { name = 1 }
$1 == "version" && $2 == "1.0" { version = 1 }
$1 == "release" && $2 == "1" { release = 1 }
$1 == "arch" && $2 == "any" { arch = 1 }
-END { exit !(format && name && version && release && arch) }
+$1 == "definition_sha256" && $2 ~ /^[0-9a-f]+$/ && length($2) == 64 {
+ definition = 1
+}
+END { exit !(format && name && version && release && arch && definition) }
' "$tmp/extract/.SPS/meta" || fail "package metadata is incomplete"
cat >"$tmp/expected-files" <<'EOF'
diff --git a/tests/test_dependencies.sh b/tests/test_dependencies.sh
index 1cbe8f3..b4a4cfc 100755
--- a/tests/test_dependencies.sh
+++ b/tests/test_dependencies.sh
@@ -167,6 +167,7 @@ contains "$(cat "$tmp/explicit.out")" 'explicit'
cat > "$tmp/fakebin/mkpkg" <<'EOF_FAKE_MKPKG'
#!/bin/sh
+. "$SPS_LIBDIR/common.sh"
printf "mkpkg\t%s\n" "$PWD" >> "$TEST_LOG"
artifact_file=
recipe=recipe
@@ -200,10 +201,12 @@ version=$(awk '$1=="version" {print $2; exit}' "$recipe")
release=$(awk '$1=="release" {print $2; exit}' "$recipe")
arch=$(awk '$1=="arch" {print $2; exit}' "$recipe")
[ -n "$arch" ] || arch=$(uname -m)
+definition_sha256=$(sps_definition_sha256 "$recipe") || exit 4
work=$PWD/.fakepkg.$$
mkdir -p "$work/.SPS"
-printf "format\t1\nname\t%s\nversion\t%s\nrelease\t%s\narch\t%s\n" \
- "$name" "$version" "$release" "$arch" > "$work/.SPS/meta"
+printf "format\t1\ndefinition_sha256\t%s\nname\t%s\nversion\t%s\nrelease\t%s\narch\t%s\n" \
+ "$definition_sha256" "$name" "$version" "$release" "$arch" \
+ > "$work/.SPS/meta"
: > "$work/.SPS/files"
: > "$work/.SPS/hashes"
artifact=$PWD/$name-$version-$release-$arch.pkg.tar
diff --git a/tests/test_highlevel.sh b/tests/test_highlevel.sh
index c501e4a..2dc8d5f 100755
--- a/tests/test_highlevel.sh
+++ b/tests/test_highlevel.sh
@@ -73,6 +73,15 @@ sget upgrade >"$tmp/upgrade.out"
reinstall=$(sget install --reinstall app)
contains "$reinstall" 'using cached app-1.0-1-any.pkg.tar'
+# A cache filename is not enough to prove that an artifact matches the
+# current recipe/support tree. Rebuild an unchanged version when its package
+# definition changes, rather than reusing a stale library from an earlier
+# live-setup attempt.
+printf '%s\n' '# definition changed without a release bump' >>"$repo/app/recipe"
+src update >/dev/null
+reinstall=$(sget install --reinstall app)
+contains "$reinstall" 'discarding stale cached app-1.0-1-any.pkg.tar'
+
# Do not trust the cache filename. A different valid package under this name
# must be rejected before pkin sees it.
app_cache=$(find "$cache/packages" -type f -name 'app-1.0-1-any.pkg.tar*' | head -1)