From 7cec1026913a3aa266435ab8e8afa1baffaa9b88 Mon Sep 17 00:00:00 2001 From: Jan Lindemann Date: Wed, 16 Sep 2026 12:19:18 +0200 Subject: [PATCH 1/2] scm.sh ls-files: Honor -f in Git repositories In CVS, the -f option keeps directory entries out of scm.sh ls-file's listing; in Git, it's a silent no-op. Notably symlinks are not excluded despite -f. Implement -f for git with a mode filter on git ls-files -s output: only 100644 and 100755 entries are listed, so the option means the same thing in both code paths. For Git, this actually means a behaviour change which needs to be fixed: The dist archive targets tar-files and cpio-files in make/list-files.mk and the scm_files() helper in scripts/pkg.sh then may no longer pass it to get unchanged behaviour. The targets list-files and list-text-files keep it, so the text-files cache now matches its documented regular-files-only membership. Assisted-by: unsloth/Qwen3.8-27B-GGUF:Q4_K_M with pi.dev v0.85.1 Signed-off-by: Jan Lindemann --- make/defs.mk | 2 +- make/list-files.mk | 4 ++-- scripts/pkg.sh | 2 +- scripts/scm.sh | 12 +++++++++++- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/make/defs.mk b/make/defs.mk index 7e778b07..b5d38455 100644 --- a/make/defs.mk +++ b/make/defs.mk @@ -113,7 +113,7 @@ reverse = $(if $(wordlist 2,2,$(1)),$(call reverse,$(wordli make_subdirs = set -e; for D in $(SUBDIRS) ; do make -C $$D ; done make_subdirs_target = set -e; for D in $(SUBDIRS) ; do make -C $$D $@; done install_local_cfg = $(INSTALL) -p -o $(CFGOWNER) -g $(CFGGROUP) -m $(CFGMODE) $< $@ -cvs_files = sh $(JWB_SCRIPT_DIR)/scm.sh ls-files -f +cvs_files = sh $(JWB_SCRIPT_DIR)/scm.sh ls-files add_flavour_prefix = $(SED) "s/\([^ ][^ ]*\) *\([<>=]*\) *\([^ ]*\)/$(FLAVOUR_PREFIX)\1 \2 \3/g" beautify_lib_path = $(SED) 's/:/\n + /g' find_files = $(wildcard $(addsuffix /$(1),$(patsubst :, ,$(2)))) diff --git a/make/list-files.mk b/make/list-files.mk index 681c5724..ff9b6dd5 100644 --- a/make/list-files.mk +++ b/make/list-files.mk @@ -10,9 +10,9 @@ list-text-files echo-text-files: $(Q)$(LIST_VCS_FILES) -ft tar-files: - $(Q)$(LIST_VCS_FILES) $(TOPDIR) -f | xargs tar -C $(TOPDIR) -cf - + $(Q)$(LIST_VCS_FILES) $(TOPDIR) | xargs tar -C $(TOPDIR) -cf - cpio-files: - $(Q)$(LIST_VCS_FILES) $(TOPDIR) -f | cpio --directory=$(TOPDIR) -o -H newc + $(Q)$(LIST_VCS_FILES) $(TOPDIR) | cpio --directory=$(TOPDIR) -o -H newc endif # ifndef LIST_FILES_MK_INCLUDED diff --git a/scripts/pkg.sh b/scripts/pkg.sh index 39adaf3b..38ff7c35 100644 --- a/scripts/pkg.sh +++ b/scripts/pkg.sh @@ -101,7 +101,7 @@ scm_files() { ( cd $TOPDIR - /bin/bash $JWB_SCRIPT_DIR/scm.sh ls-files -f "$@" + /bin/bash $JWB_SCRIPT_DIR/scm.sh ls-files "$@" ) } diff --git a/scripts/scm.sh b/scripts/scm.sh index 5dfbf80e..c359b489 100644 --- a/scripts/scm.sh +++ b/scripts/scm.sh @@ -121,7 +121,17 @@ cmd_ls_files() local opts="$git_ls_files_opts" git --version | grep -q "version *1" && opt_no_submodules=1 [ "$opt_no_submodules" = 1 ] || opts="$opts --recurse-submodules" - git ls-files --recurse-submodules $opts $1 + if [ "$opt_only_regular_files" != 1 ]; then + git ls-files --recurse-submodules $opts $1 + else + local entry meta + while IFS= read -r -d '' entry; do + meta=${entry%%$'\t'*} + case ${meta%% *} in + 100644|100755) output "${entry#*$'\t'}" ;; + esac + done < <(git ls-files -s -z --recurse-submodules $opts $1) + fi if [ "$include_vcs_files" = 1 -a -d .git ]; then output_find .git fi -- 2.55.0 From f7389516426687fa67e1926d5ef15d9f9d7d74bf Mon Sep 17 00:00:00 2001 From: Jan Lindemann Date: Wed, 16 Sep 2026 13:05:53 +0200 Subject: [PATCH 2/2] calculate_hash(): Derive hash from VCS file ids The source hash is an md5sum over all versioned files in the working tree. md5sum follows symlinks, so a project with links to files outside the tree may produce different hashes depending on files outside the repo. Compute the hash over the VCS file ids instead. Add a -s option to scm.sh ls-files that lists each versioned file together with its content id. The listing is sorted by path rather than by id, so an entry keeps its position when its content changes. For Git repos, git ls-tree -r HEAD reports the blob of a symlink's target string and the pinned commit of a submodule, so the resulting hash depends only on the committed tree, never on the working tree or on the machine. calculate_hash() and the HASH variable in make/pkg-dist.mk feed the id listing, minus the release metadata files, directly to md5sum. calculate_hash() fails loudly when the pipeline fails, with its callers refusing to proceed on an empty result. The scheme change invalidates the stored HASH values, so every project gets one more release the first time it runs against the new code, and the hashes are stable again afterwards. Signed-off-by: Jan Lindemann Assisted-by: unsloth/Qwen3.8-27B-GGUF:Q4_K_M with pi.dev v0.85.1 --- make/pkg-dist.mk | 4 ++-- scripts/pkg.sh | 14 ++++++++++---- scripts/scm.sh | 33 ++++++++++++++++++++++++++++++++- 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/make/pkg-dist.mk b/make/pkg-dist.mk index 879bfc54..c5dee869 100644 --- a/make/pkg-dist.mk +++ b/make/pkg-dist.mk @@ -25,9 +25,9 @@ RELEASES_FILE = $(TOPDIR)/RELEASES$(FLAVOUR_SUFFIX) RELEASES ?= $(shell $(PKG_SH_EXE) version \ -p $(OS_NAME_VERSION)/$(PKG_ARCH) $(RELEASES_FILE) read | $(SED) 's/-dev//') PKG_CHECK_VCS_SYNC_BEFORE_RELEASE ?= true -HASH = $(shell $(cvs_files) -z | \ +HASH = $(shell $(cvs_files) -s -z | \ grep -vz "CHANGES\|VERSION\|HASH\|MD5SUMS\|RELEASES" | \ - xargs -0 md5sum | md5sum | $(SED) 's/ .*//') + md5sum | $(SED) 's/ .*//') LOCAL_REPO ?= /srv/dav/pub/local/packages/suse/$(OS_NAME_VERSION) PACKAGE_VCS_FILES ?= false diff --git a/scripts/pkg.sh b/scripts/pkg.sh index 38ff7c35..31cf398d 100644 --- a/scripts/pkg.sh +++ b/scripts/pkg.sh @@ -107,12 +107,16 @@ scm_files() calculate_hash() { - ( + local h + h=`( + set -o pipefail cd $TOPDIR - scm_files -z | \ + scm_files -s -z | \ grep -vz "CHANGES\|VERSION\|HASH\|MD5SUMS\|RELEASES" | \ - xargs -0 md5sum | md5sum | sed 's/ .*//' - ) + md5sum | sed 's/ .*//' + )` || fatal "failed to calculate source hash" + [ -n "$h" ] || fatal "failed to calculate source hash" + echo $h } check_scm() @@ -180,6 +184,7 @@ check_next_version() return fi local h=`calculate_hash` + [ -n "$h" ] || fatal "failed to calculate source hash" if [ ! -f $TOPDIR/HASH ]; then echo "+ $PKG_PROJECT has no HASH file, needs release" >&2 echo $v @@ -602,6 +607,7 @@ upload_pkg() local p local v=`read_map $TOPDIR/VERSION | sed 's/-dev//'` local h=`calculate_hash` + [ -n "$h" ] || fatal "failed to calculate source hash" case $PKG_FORMAT in rpm) server=pkg.janware.com diff --git a/scripts/scm.sh b/scripts/scm.sh index c359b489..ca482409 100644 --- a/scripts/scm.sh +++ b/scripts/scm.sh @@ -150,7 +150,33 @@ cmd_ls_files() list_dirents_git $1 } - set -- `getopt fnzta "$@"` + list_dirents_git_ids() + { + local entry meta mode sha + while IFS= read -r -d '' entry; do + meta=${entry%%$'\t'*} + mode=${meta%% *} + sha=${meta##* } + [ "$opt_no_submodules" = 1 ] && [ "$mode" = 160000 ] && continue + [ "$opt_only_regular_files" = 1 ] && [ "$mode" != 100644 ] && [ "$mode" != 100755 ] && continue + output "$sha ${entry#*$'\t'}" + done < <(git ls-tree -r -z HEAD "$1") + } + + list_dirents_ids() + { + if [ -d $1/CVS ]; then + echo "failed to list file ids in $(realpath $1): $scm has no file ids" >&2 + exit 1 + fi + git -C $1 status >/dev/null 2>&1 || { + echo "failed to list file ids in $(realpath $1): no VCS" >&2 + exit 1 + } + list_dirents_git_ids $1 + } + + set -- `getopt fnzsta "$@"` while [ "$1" != -- ]; do case $1 in @@ -160,6 +186,9 @@ cmd_ls_files() -n) opt_no_submodules=1 ;; + -s) + show_ids=1 + ;; -z) zero_terminate=1 git_ls_files_opts="$git_ls_files_opts -z" @@ -181,6 +210,8 @@ cmd_ls_files() if [ "$text_files" ]; then list_dirents . | sort $opt_sort | xargs file -N | grep ":.*text" | cut -d: -f1 + elif [ "$show_ids" = 1 ]; then + list_dirents_ids . | sort $opt_sort -k2 else list_dirents . | sort $opt_sort fi -- 2.55.0