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