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.
This commit is contained in:
0x1eef 2023-03-19 02:31:25 -03:00 committed by Robert
parent 62dda8940b
commit 8763cd2b82
5 changed files with 93 additions and 31 deletions

View file

@ -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 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 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 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 ## Usage
* `portzap clone` <br> * `portzap clone` <br>
This command clones HardenedBSD's ports tree into `/home/_portzap/ports`. This command clones HardenedBSD's ports tree into `/home/_portzap/ports/`.
* `portzap pull` <br> * `portzap pull` <br>
This command pulls updates into `/home/_portzap/ports`. This command pulls updates into `/home/_portzap/ports/`.
* `portzap install` <br> * `portzap install` <br>
This command should be run as root. <br> This command should be run as root. <br>
The command installs `/home/_portzap/ports` into `/usr/ports`. The command installs `/home/_portzap/ports/` into `/usr/ports/`. <br>
After the first installation, future installations try to save time by being incremental.
## Sources ## Sources

View file

@ -6,6 +6,7 @@
# Configuration # Configuration
ports_url="https://git.hardenedbsd.org/hardenedbsd/ports.git" ports_url="https://git.hardenedbsd.org/hardenedbsd/ports.git"
ports_dir="/usr/ports/" ports_dir="/usr/ports/"
portzap_rev="$ports_dir/.portzap_last_rev"
portzap_dir="/home/_portzap/ports" portzap_dir="/home/_portzap/ports"
libexec_dir=$(realpath $(dirname $0)/../libexec/portzap/) libexec_dir=$(realpath $(dirname $0)/../libexec/portzap/)
@ -17,6 +18,9 @@ pull_mask=007
## ##
# Utils # Utils
. $libexec_dir/functions/perms.sh
. $libexec_dir/functions/fs.sh
. $libexec_dir/functions/git.sh
exit_on_missing_deps() { exit_on_missing_deps() {
deps=$1 deps=$1
for dep in $deps; do for dep in $deps; do
@ -28,24 +32,6 @@ exit_on_missing_deps() {
done 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 # Commands
help() { help() {
@ -98,16 +84,35 @@ install() {
exit 1 exit 1
fi fi
echo "Please wait..."
cd $portzap_dir cd $portzap_dir
find -s . -maxdepth 1 -type f \ if [ -e "$portzap_rev" ]; then
\( -not -name ".gitignore" \) \ rev=$(cat $portzap_rev)
\( -not -name ".arcconfig" \) \ port_dirs=$(modified_ports $rev)
-exec $libexec_dir/install-file $ports_dir {} + rm_files=$(git diff --name-only --diff-filter=D $rev..HEAD)
find -s . -maxdepth 1 -type d \ for file in $rm_files; do
\( -not -name "." \) \ rm $ports_dir/$file
\( -not -name ".git" \) \ done
\( -not -name ".hooks" \) \ for dir in $port_dirs; do
-exec $libexec_dir/install-directory $ports_dir $libexec_dir {} + 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 case $1 in

24
libexec/portzap/functions/fs.sh Executable file
View file

@ -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
}

View file

@ -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
}

View file

@ -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
}