From 8763cd2b8232c470770bbd36e05eb4eac3e1f9cd Mon Sep 17 00:00:00 2001 From: 0x1eef <0x1eef@protonmail.com> Date: Sun, 19 Mar 2023 02:31:25 -0300 Subject: [PATCH] Add support for incremental updates The 'portzap install' command would always install the entire ports tree, whether for the first time or on a subsequent update where copying the entire tree isn't neccessary. This change is an attempt at only copying ports that have been modified in some way. Rather than dealing with modifications file by file, a port that is found to have modifications has its entire directory copied. This makes life easier but is a bit slower. --- README.md | 9 +++-- bin/portzap | 59 ++++++++++++++++-------------- libexec/portzap/functions/fs.sh | 24 ++++++++++++ libexec/portzap/functions/git.sh | 11 ++++++ libexec/portzap/functions/perms.sh | 21 +++++++++++ 5 files changed, 93 insertions(+), 31 deletions(-) create mode 100755 libexec/portzap/functions/fs.sh create mode 100644 libexec/portzap/functions/git.sh create mode 100644 libexec/portzap/functions/perms.sh diff --git a/README.md b/README.md index 7862081..e6d7085 100644 --- a/README.md +++ b/README.md @@ -5,19 +5,20 @@ portzap is a utility for staying up to date with the The utility stores a transient copy of the ports tree in `/home/_portzap/ports/`. The transient copy can be created, and updated by an unprivileged user account who is a member of the `_portzap` group. The transient copy can then be installed -into the `/usr/ports` directory by root. +into the `/usr/ports/` directory by root. ## Usage * `portzap clone`
- This command clones HardenedBSD's ports tree into `/home/_portzap/ports`. + This command clones HardenedBSD's ports tree into `/home/_portzap/ports/`. * `portzap pull`
- This command pulls updates into `/home/_portzap/ports`. + This command pulls updates into `/home/_portzap/ports/`. * `portzap install`
This command should be run as root.
- The command installs `/home/_portzap/ports` into `/usr/ports`. + The command installs `/home/_portzap/ports/` into `/usr/ports/`.
+ After the first installation, future installations try to save time by being incremental. ## Sources diff --git a/bin/portzap b/bin/portzap index 9531b89..7a8ce29 100755 --- a/bin/portzap +++ b/bin/portzap @@ -6,6 +6,7 @@ # Configuration ports_url="https://git.hardenedbsd.org/hardenedbsd/ports.git" ports_dir="/usr/ports/" +portzap_rev="$ports_dir/.portzap_last_rev" portzap_dir="/home/_portzap/ports" libexec_dir=$(realpath $(dirname $0)/../libexec/portzap/) @@ -17,6 +18,9 @@ pull_mask=007 ## # Utils +. $libexec_dir/functions/perms.sh +. $libexec_dir/functions/fs.sh +. $libexec_dir/functions/git.sh exit_on_missing_deps() { deps=$1 for dep in $deps; do @@ -28,24 +32,6 @@ exit_on_missing_deps() { done } -has_portzap_access() { - groups=$(id -Gn) - in_group=1 - for g in $groups; do - if [ $g = "_portzap" ]; - then - in_group=0 - fi - done - return $in_group -} - -user_is_not_root() { - user_id=$(id -u) - result=$(test $user_id -ne "0") - return $result -} - ## # Commands help() { @@ -98,16 +84,35 @@ install() { exit 1 fi + echo "Please wait..." cd $portzap_dir - find -s . -maxdepth 1 -type f \ - \( -not -name ".gitignore" \) \ - \( -not -name ".arcconfig" \) \ - -exec $libexec_dir/install-file $ports_dir {} + - find -s . -maxdepth 1 -type d \ - \( -not -name "." \) \ - \( -not -name ".git" \) \ - \( -not -name ".hooks" \) \ - -exec $libexec_dir/install-directory $ports_dir $libexec_dir {} + + if [ -e "$portzap_rev" ]; then + rev=$(cat $portzap_rev) + port_dirs=$(modified_ports $rev) + rm_files=$(git diff --name-only --diff-filter=D $rev..HEAD) + for file in $rm_files; do + rm $ports_dir/$file + done + for dir in $port_dirs; do + if [ -f "$dir" ]; then + $libexec_dir/install-file $ports_dir $dir + else + $libexec_dir/install-directory $ports_dir $libexec_dir $dir + fi + done + else + find -s . -maxdepth 1 -type f \ + \( -not -name ".gitignore" \) \ + \( -not -name ".arcconfig" \) \ + -exec $libexec_dir/install-file $ports_dir {} + + find -s . -maxdepth 1 -type d \ + \( -not -name "." \) \ + \( -not -name ".git" \) \ + \( -not -name ".hooks" \) \ + -exec $libexec_dir/install-directory $ports_dir $libexec_dir {} + + fi + echo $(git rev-parse HEAD) > $portzap_rev + echo "Done." } case $1 in diff --git a/libexec/portzap/functions/fs.sh b/libexec/portzap/functions/fs.sh new file mode 100755 index 0000000..db4d188 --- /dev/null +++ b/libexec/portzap/functions/fs.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +## +# Returns the depth of a path +port_depth() { + p=$1 + result=$(echo $p | tr '/' '\n' | grep . | wc -l) + return $result +} + +## +# Returns the entry point for a port relative to /usr/ports +# (eg: ./ftp/curl/) +port_dirname() { + p=$1 + port_depth "$p" + depth=$? + if [ $depth -gt 2 ]; then + p=$(dirname $p) + port_dirname "$p" + else + echo $p + fi +} diff --git a/libexec/portzap/functions/git.sh b/libexec/portzap/functions/git.sh new file mode 100644 index 0000000..79715f1 --- /dev/null +++ b/libexec/portzap/functions/git.sh @@ -0,0 +1,11 @@ +## +# Returns a list of new, and modified files between two points / commits. +modified_ports() { + rev=$1 + files=$(git diff --name-only --diff-filter=AM $rev..HEAD) + for file in $files; do + dirs="$dirs $(port_dirname $file)" + done + dirs=$(echo $dirs | tr ' ' '\n' | uniq) + echo $dirs +} diff --git a/libexec/portzap/functions/perms.sh b/libexec/portzap/functions/perms.sh new file mode 100644 index 0000000..2ba718e --- /dev/null +++ b/libexec/portzap/functions/perms.sh @@ -0,0 +1,21 @@ +## +# Returns true when current user is in _portzap group +has_portzap_access() { + groups=$(id -Gn) + in_group=1 + for g in $groups; do + if [ $g = "_portzap" ]; + then + in_group=0 + fi + done + return $in_group +} + +## +# Returns true when current user is root +user_is_not_root() { + user_id=$(id -u) + result=$(test $user_id -ne "0") + return $result +}