2025-11-14 11:22:50 +01:00
|
|
|
#!/bin/bash
|
|
|
|
|
|
|
|
|
|
cmd_mv()
|
|
|
|
|
{
|
|
|
|
|
local from="$1"
|
|
|
|
|
local to="$2"
|
|
|
|
|
case $scm in
|
|
|
|
|
cvs)
|
|
|
|
|
cp "$from" "$to"
|
|
|
|
|
cvs add "$to"
|
|
|
|
|
cvs remove -f "$from"
|
|
|
|
|
;;
|
|
|
|
|
git)
|
|
|
|
|
git mv "$from" "$to"
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd_commit()
|
|
|
|
|
{
|
|
|
|
|
C=''
|
|
|
|
|
for i in "$@"; do
|
|
|
|
|
C="$C \"${i//\"/\\\"}\""
|
|
|
|
|
done
|
|
|
|
|
eval $scm commit "$C"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd_add()
|
|
|
|
|
{
|
|
|
|
|
$scm add "$@"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd_rm()
|
|
|
|
|
{
|
|
|
|
|
case $scm in
|
|
|
|
|
cvs)
|
|
|
|
|
cvs remove "$@"
|
|
|
|
|
;;
|
|
|
|
|
git)
|
|
|
|
|
git rm "$@"
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd_clean()
|
|
|
|
|
{
|
|
|
|
|
case $scm in
|
|
|
|
|
cvs)
|
|
|
|
|
while [ "${1:0:1}" = - ]; do
|
|
|
|
|
shift
|
|
|
|
|
done
|
|
|
|
|
set +e
|
|
|
|
|
local file
|
2026-06-25 21:42:22 +02:00
|
|
|
for file in "$@"; do
|
2025-11-14 11:22:50 +01:00
|
|
|
if ! grep -q "/$file/" CVS/Entries; then
|
|
|
|
|
rm -f $file
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
;;
|
|
|
|
|
git)
|
|
|
|
|
git clean -x "$@"
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd_ls_files()
|
|
|
|
|
{
|
|
|
|
|
filter_deleted()
|
|
|
|
|
{
|
|
|
|
|
local rc_file="$1"
|
|
|
|
|
shift
|
|
|
|
|
local cand
|
|
|
|
|
for cand in "$@"; do
|
|
|
|
|
grep -q "^R ./$cand/" $rc_file && continue
|
|
|
|
|
echo $cand
|
|
|
|
|
done
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-01 11:29:51 +01:00
|
|
|
output_find()
|
|
|
|
|
{
|
|
|
|
|
local find_opts f
|
|
|
|
|
[ "$zero_terminate" = 1 ] && find_opts="-print0"
|
|
|
|
|
find "$@" $find_opts
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-14 11:22:50 +01:00
|
|
|
output()
|
|
|
|
|
{
|
|
|
|
|
if [ "$zero_terminate" = 1 ]; then
|
|
|
|
|
echo -en "$*\x00"
|
|
|
|
|
else
|
|
|
|
|
echo "$*"
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
list_dirents_cvs()
|
|
|
|
|
{
|
|
|
|
|
local dirs=`sed '/^D\// !d; s%^D/%%; s%/.*%%' $1/CVS/Entries`
|
|
|
|
|
dirs="`filter_deleted $1/CVS/Entries $dirs`"
|
|
|
|
|
local cands
|
|
|
|
|
if [ -f $1/CVS/Entries.Log ]; then
|
|
|
|
|
cands="`sed '/^A D\// !d; s%^A D/%%; s%/.*%%' $1/CVS/Entries.Log`"
|
|
|
|
|
dirs="$dirs `filter_deleted $1/CVS/Entries.Log $cands`"
|
|
|
|
|
fi
|
|
|
|
|
local files=`sed '/^\// !d; s%/%%; s%/.*%%; s%^%%' $1/CVS/Entries`
|
|
|
|
|
files="`filter_deleted $1/CVS/Entries $files`"
|
|
|
|
|
local d f
|
|
|
|
|
for f in $files; do
|
|
|
|
|
output "$1/$f"
|
|
|
|
|
done
|
2025-12-01 11:29:51 +01:00
|
|
|
if [ "$include_vcs_files" = 1 -a -d CVS ]; then
|
|
|
|
|
output_find "$1/CVS"
|
|
|
|
|
fi
|
2025-11-14 11:22:50 +01:00
|
|
|
for d in $dirs; do
|
|
|
|
|
[ "$opt_only_regular_files" = 1 ] || output $1/$d
|
|
|
|
|
list_dirents_cvs $1/$d
|
|
|
|
|
done
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
list_dirents_git()
|
|
|
|
|
{
|
|
|
|
|
local opts="$git_ls_files_opts"
|
|
|
|
|
git --version | grep -q "version *1" && opt_no_submodules=1
|
|
|
|
|
[ "$opt_no_submodules" = 1 ] || opts="$opts --recurse-submodules"
|
2026-09-16 12:19:18 +02:00
|
|
|
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
|
2025-12-01 11:29:51 +01:00
|
|
|
if [ "$include_vcs_files" = 1 -a -d .git ]; then
|
|
|
|
|
output_find .git
|
|
|
|
|
fi
|
2025-11-14 11:22:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
list_dirents()
|
|
|
|
|
{
|
|
|
|
|
if [ -d $1/CVS ]; then
|
|
|
|
|
list_dirents_cvs $1
|
|
|
|
|
return
|
|
|
|
|
fi
|
2025-11-17 12:17:04 +01:00
|
|
|
git -C $1 status >/dev/null 2>&1 || {
|
|
|
|
|
echo "failed to list versioned files in $(realpath $1): no VCS" >&2
|
2025-11-14 11:22:50 +01:00
|
|
|
exit 1
|
|
|
|
|
}
|
|
|
|
|
list_dirents_git $1
|
|
|
|
|
}
|
|
|
|
|
|
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 <jan@janware.com>
Assisted-by: unsloth/Qwen3.8-27B-GGUF:Q4_K_M with pi.dev v0.85.1
2026-09-16 13:05:53 +02:00
|
|
|
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 "$@"`
|
2025-11-14 11:22:50 +01:00
|
|
|
|
|
|
|
|
while [ "$1" != -- ]; do
|
|
|
|
|
case $1 in
|
|
|
|
|
-f)
|
|
|
|
|
opt_only_regular_files=1
|
|
|
|
|
;;
|
|
|
|
|
-n)
|
|
|
|
|
opt_no_submodules=1
|
|
|
|
|
;;
|
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 <jan@janware.com>
Assisted-by: unsloth/Qwen3.8-27B-GGUF:Q4_K_M with pi.dev v0.85.1
2026-09-16 13:05:53 +02:00
|
|
|
-s)
|
|
|
|
|
show_ids=1
|
|
|
|
|
;;
|
2025-11-14 11:22:50 +01:00
|
|
|
-z)
|
|
|
|
|
zero_terminate=1
|
|
|
|
|
git_ls_files_opts="$git_ls_files_opts -z"
|
|
|
|
|
opt_sort="$opt_sort -z"
|
|
|
|
|
;;
|
|
|
|
|
-t)
|
|
|
|
|
text_files=1
|
|
|
|
|
;;
|
2025-12-01 11:29:51 +01:00
|
|
|
-a)
|
|
|
|
|
include_vcs_files=1
|
|
|
|
|
;;
|
2025-11-14 11:22:50 +01:00
|
|
|
esac
|
|
|
|
|
shift
|
|
|
|
|
done
|
|
|
|
|
shift
|
|
|
|
|
|
|
|
|
|
proj_dir="$1"
|
|
|
|
|
[ "$proj_dir" ] && cd $proj_dir
|
|
|
|
|
|
|
|
|
|
if [ "$text_files" ]; then
|
|
|
|
|
list_dirents . | sort $opt_sort | xargs file -N | grep ":.*text" | cut -d: -f1
|
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 <jan@janware.com>
Assisted-by: unsloth/Qwen3.8-27B-GGUF:Q4_K_M with pi.dev v0.85.1
2026-09-16 13:05:53 +02:00
|
|
|
elif [ "$show_ids" = 1 ]; then
|
|
|
|
|
list_dirents_ids . | sort $opt_sort -k2
|
2025-11-14 11:22:50 +01:00
|
|
|
else
|
|
|
|
|
list_dirents . | sort $opt_sort
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# ------- here we go
|
|
|
|
|
export LANG=POSIX
|
|
|
|
|
myname=`basename $0`
|
|
|
|
|
cmd=cmd_${1//-/_}
|
|
|
|
|
shift
|
|
|
|
|
if [ -d "CVS" ]; then
|
|
|
|
|
scm=cvs
|
|
|
|
|
else
|
|
|
|
|
scm=git
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
$cmd "$@"
|