[prev in list] [next in list] [prev in thread] [next in thread] 

List:       buildroot
Subject:    [Buildroot] [RFC PATCH] system: introduce rootfs prune support
From:       James Knight <james.d.knight () live ! com>
Date:       2023-04-30 19:53:25
Message-ID: SN4P221MB0682FFDFA1E4FB65D998ABE5A0699 () SN4P221MB0682 ! NAMP221 ! PROD ! OUTLOOK ! COM
[Download RAW message or body]

The following introduces the option `BR2_ROOTFS_PRUNE`, to allow users
to provide lists of directories and files that should be pruned from the
file system after a build. This is to provide a simpler means of
defining and cleaning up paths, instead of manually creating removal
logic inside a post-build script.

Users will now be able to define a file of entries to remove and
register this file as part of a board's configuration. More than one
file can be provided. Each line in a file will represent a file or
directory that should be removed. Wildcard values are supported for file
entries when attempting to remove a group of entries from a folder.
Comments are also supported in these files, allowing users to document
reasons for desiring board-specific removals. Sanity checks exists to
help prevent users from accidentally removing files outside of the
target directory.

Signed-off-by: James Knight <james.d.knight@live.com>
---
The goal of this patch is to provide an easy way for users to define
files to prune from the target file system after a build. Typically,
projects wanting to prune would have some sort of logic inside a
post-build script. Managing support to clear out select directories/
files is not always trivial, especially when wanting to do some wildcard
patterns on files to remove. Buildroot provides nice device table and
user table definition files, and having a file with entries of paths to
remove seems like a nice way to manage such an action. Projects
performing this type of pruning could have some library logic to support
a "prune" function to do this, but it would be nice if Buildroot
provides this support out-of-box (opinion).

These changes would also need to include some manual updates. Held off
this work if this feature is not something desired.
---
 Makefile              |   6 +++
 support/scripts/prune | 122 ++++++++++++++++++++++++++++++++++++++++++
 system/Config.in      |  10 ++++
 3 files changed, 138 insertions(+)
 create mode 100755 support/scripts/prune

diff --git a/Makefile b/Makefile
index 95959daab2296a5e1c19a36b0a9d356175aeba81..44d9a44b1ad6a423999341ccd4a576ae87adc671 100644
--- a/Makefile
+++ b/Makefile
@@ -794,6 +794,12 @@ endif # merged /usr
 	$(Q)$(if $(STAGING_DIR_FILES_LISTS), \
 		cat $(STAGING_DIR_FILES_LISTS)) > $(BUILD_DIR)/packages-file-list-staging.txt
 
+	$(foreach s, $(call qstrip,$(BR2_ROOTFS_PRUNE)), \
+		@$(call MESSAGE,"Pruning $(s)")$(sep) \
+		$(Q)$(TOPDIR)/support/scripts/prune $(TARGET_DIR) $(s) \
+		$(if $(wildcard $(BUILD_DIR)/.br2-pruned),--ignore-missing)$(sep))
+	@touch $(BUILD_DIR)/.br2-pruned
+
 	$(foreach s, $(call qstrip,$(BR2_ROOTFS_POST_BUILD_SCRIPT)), \
 		@$(call MESSAGE,"Executing post-build script $(s)")$(sep) \
 		$(Q)$(EXTRA_ENV) $(s) $(TARGET_DIR) $(call qstrip,$(BR2_ROOTFS_POST_SCRIPT_ARGS))$(sep))
diff --git a/support/scripts/prune b/support/scripts/prune
new file mode 100755
index 0000000000000000000000000000000000000000..aaafdd378631199e465e3b768662e7ce4fcc463c
--- /dev/null
+++ b/support/scripts/prune
@@ -0,0 +1,122 @@
+#!/usr/bin/env bash
+#
+# This script accepts a target directory and multiple "prune files". Each
+# prune file will be parsed for lines which indicate paths to be removed from
+# the target directory. An example prune file list is as follows:
+#
+#  etc/libfoo.d/03-checks.sh
+#  usr/bin/test-libfoo
+#  usr/lib/libfootest.*
+#  # always ensure opt is empty
+#  opt/
+#
+# This script will not prune outside of the target directory.
+
+dry_run=false
+files=()
+ignore_missing=false
+target=
+vflag=false
+while [[ $# -gt 0 ]]; do
+    case $1 in
+    --dry-run) dry_run=true ;;
+    --ignore-missing) ignore_missing=true ;;
+    --verbose) vflag=true ;;
+    -*)
+        echo "unknown argument: $1"
+        exit 1
+        ;;
+    *)
+        if [ -z "$target" ]; then
+            target="$1"
+        else
+            files+=("$1")
+        fi
+        ;;
+    esac
+
+    shift
+done
+
+function msg() {
+    echo "(prune) $1"
+}
+function verbose() {
+    $vflag && echo "(prune-verbose) $1"
+}
+
+target=$(realpath "$target" 2>/dev/null)
+verbose "target: $target"
+
+if [ ! -d "$target" ] ; then
+    echo "Error: invalid target $target"
+    exit 1
+elif [ ${#files[@]} -eq 0 ]; then
+    echo "Error: no prune files provided"
+    exit 1
+fi
+
+# extract all prune entries from the provided files
+for f in "${files[@]}"; do
+    if [ ! -f "$f" ]; then
+        msg "Error: missing prune file: $f"
+        exit 1
+    fi
+
+    verbose "processing file: $f"
+    while IFS= read -r entry; do
+        # trim and ignore empty lines and comments
+        entry="${entry#"${entry%%[![:space:]]*}"}"
+        entry="${entry%"${entry##*[![:space:]]}"}"
+        [[ -z "$entry" || $entry == "#"* ]] && continue
+
+        verbose "processing entry: $entry"
+        is_dir=
+        [[ "$entry" == *"/" ]] && is_dir=1
+        path=$(realpath -m "$target/$entry")
+
+        # fail if the entry matches the target or leaves the target
+        if [[ $path == "$target" ]] || [[ "$path" != "$target"* ]]; then
+            msg "Error: invalid entry: $entry"
+            exit 1
+        fi
+
+        paths=("$path")
+
+        # if this is not a directory with a wildcard hint, look for any
+        # files on this path matching the wildcard
+        if [[ $is_dir -eq 0 ]]; then
+            basename=${path##*/}
+            if [[ "$basename" == *"*"* ]]; then
+                dirname=${path%/*}
+                verbose "finding files in ($basename): $dirname"
+                paths=()
+                while read -r -d $'\0'; do
+                    verbose "found: $REPLY"
+                    paths+=("$REPLY")
+                done < <(find "$dirname" -maxdepth 1 -name "$basename" \
+                    -print0 2>/dev/null)
+
+                if [ ${#paths[@]} -eq 0 ] && ! $ignore_missing; then
+                    msg "missing: $path"
+                fi
+            fi
+        fi
+
+        # process paths to remove
+        for p in "${paths[@]}"; do
+            if [ -e "$p" ]; then
+                if $dry_run; then
+                    msg "removed (dryrun): $p"
+                elif rm -rf "$p"; then
+                    msg "removed: $p"
+                else
+                    msg "failed to remove: $p"
+                    exit 1
+                fi
+            elif ! $ignore_missing; then
+                msg "missing: $p"
+            fi
+        done
+    done <"$f"
+done
diff --git a/system/Config.in b/system/Config.in
index 1ca7690ea3ba7de72618d4597dfe19abdfc68cb8..14125a50e7b17080201c91207408997b7f9dde56 100644
--- a/system/Config.in
+++ b/system/Config.in
@@ -587,6 +587,16 @@ config BR2_ROOTFS_OVERLAY
 	  They are copied as-is into the rootfs, excluding files ending
 	  with ~ and .git, .svn and .hg directories.
 
+config BR2_ROOTFS_PRUNE
+	string "Root filesystem prune entries"
+	default ""
+	help
+	  Specify a list of files which contain prune entries of files
+	  or directories that should be removed from the root
+	  filesystem. This occurs after the build is finished and any
+	  configured overlays are applied, but before the post build
+	  script is triggered.
+
 config BR2_ROOTFS_PRE_BUILD_SCRIPT
 	string "Custom scripts to run before commencing the build"
 	default ""
-- 
2.40.1.windows.1

_______________________________________________
buildroot mailing list
buildroot@buildroot.org
https://lists.buildroot.org/mailman/listinfo/buildroot
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic