From a46b2d4fb7dee11fcc508c6871b86d9bff8d01ae Mon Sep 17 00:00:00 2001 From: Robin Candau Date: Sun, 28 Apr 2024 12:39:20 +0200 Subject: feat(repo): add repo clean command to remove untracked files This introduces the `pkgctl repo clean` command which removes every untracked files from local package repositories (via `git clean`). The usage is as simple as `pkgctl repo clean [OPTION] [PATH]` (where "[PATH]" can be equal to a wildcard "*"). Component: pkgctl repo clean --- contrib/completion/bash/devtools.in | 7 +++ contrib/completion/zsh/_devtools.in | 8 +++ doc/man/pkgctl-repo-clean.1.asciidoc | 40 ++++++++++++ doc/man/pkgctl-repo.1.asciidoc | 4 ++ src/lib/repo.sh | 10 +++ src/lib/repo/clean.sh | 114 +++++++++++++++++++++++++++++++++++ 6 files changed, 183 insertions(+) create mode 100644 doc/man/pkgctl-repo-clean.1.asciidoc create mode 100644 src/lib/repo/clean.sh diff --git a/contrib/completion/bash/devtools.in b/contrib/completion/bash/devtools.in index 5125ceb..136beef 100644 --- a/contrib/completion/bash/devtools.in +++ b/contrib/completion/bash/devtools.in @@ -292,6 +292,7 @@ _pkgctl_aur_drop_from_repo_opts() { _filedir -d; } _pkgctl_repo_cmds=( + clean clone configure create @@ -317,6 +318,12 @@ _pkgctl_repo_clone_args__jobs_opts() { :; } _pkgctl_repo_clone_args_j_opts() { _pkgctl_repo_clone_args__jobs_opts; } _pkgctl_repo_clone_opts() { _devtools_completions_all_packages; } +_pkgctl_repo_clean_args=( + -i --interactive + -n --dry-run + -h --help +) +_pkgctl_repo_clean_opts() { _filedir -d; } _pkgctl_repo_configure_args=( --protocol diff --git a/contrib/completion/zsh/_devtools.in b/contrib/completion/zsh/_devtools.in index 48ff373..65d7895 100644 --- a/contrib/completion/zsh/_devtools.in +++ b/contrib/completion/zsh/_devtools.in @@ -114,6 +114,7 @@ _pkgctl_aur_drop_from_repo_args=( _pkgctl_repo_cmds=( "pkgctl repo command" + "clean[Remove untracked files from the working tree]" "clone[Clone a package repository]" "configure[Configure a clone according to distro specs]" "create[Create a new GitLab package repository]" @@ -128,6 +129,13 @@ _pkgctl_repo_switch_args=( '*:git_dir:_files -/' ) +_pkgctl_repo_clean_args=( + '(-i --interactive)'{-i,--interactive}'[Show what would be done and clean files interactively]' + '(-n --dry-run)'{-n,--dry-run}"[Don't remove anything, just show what would be done]" + '(-h --help)'{-h,--help}'[Display usage]' + '*:git_dir:_files -/' +) + _pkgctl_repo_clone_args=( '(-m --maintainer=)'{-m,--maintainer=}'[Clone all packages of the named maintainer]:maintainer:' '--protocol[Clone the repository over https]:proto:(https)' diff --git a/doc/man/pkgctl-repo-clean.1.asciidoc b/doc/man/pkgctl-repo-clean.1.asciidoc new file mode 100644 index 0000000..b39693c --- /dev/null +++ b/doc/man/pkgctl-repo-clean.1.asciidoc @@ -0,0 +1,40 @@ +pkgctl-repo-clean(1) +==================== + +Name +---- + +pkgctl-repo-clean - Remove untracked files from the working tree + +Synopsis +-------- + +pkgctl repo clean [OPTION] [PATH]... + +Description +----------- + +Cleans the working tree by recursively removing files that are not under +version control, starting from the current directory. + +Files unknown to Git as well as ignored files are removed. This can, for +example, be useful to remove all build products. + +Options +------- + +*-i, --interactive*:: + Show what would be done and clean files interactively + +*-n, --dry-run*:: + Don't actually remove anything, just show what would be done + +*-h, --help*:: + Show a help text + +See Also +-------- + +git-clean(1) + +include::include/footer.asciidoc[] diff --git a/doc/man/pkgctl-repo.1.asciidoc b/doc/man/pkgctl-repo.1.asciidoc index 3d0f3f1..c1fd298 100644 --- a/doc/man/pkgctl-repo.1.asciidoc +++ b/doc/man/pkgctl-repo.1.asciidoc @@ -32,6 +32,9 @@ Options Subcommands ----------- +pkgctl repo clean:: + Remove untracked files from the working tree + pkgctl repo clone:: Clone a package repository @@ -50,6 +53,7 @@ pkgctl repo web:: See Also -------- +pkgctl-repo-clean(1) pkgctl-repo-clone(1) pkgctl-repo-configure(1) pkgctl-repo-create(1) diff --git a/src/lib/repo.sh b/src/lib/repo.sh index 9f545e9..8f8dd0a 100644 --- a/src/lib/repo.sh +++ b/src/lib/repo.sh @@ -27,6 +27,7 @@ pkgctl_repo_usage() { without SSH access using read-only HTTPS. COMMANDS + clean Remove untracked files from the working tree clone Clone a package repository configure Configure a clone according to distro specs create Create a new GitLab package repository @@ -37,6 +38,7 @@ pkgctl_repo_usage() { -h, --help Show this help text EXAMPLES + $ ${COMMAND} clean --interactive * $ ${COMMAND} clone libfoo linux libbar $ ${COMMAND} clone --maintainer mynickname $ ${COMMAND} configure * @@ -59,6 +61,14 @@ pkgctl_repo() { pkgctl_repo_usage exit 0 ;; + clean) + _DEVTOOLS_COMMAND+=" $1" + shift + # shellcheck source=src/lib/repo/clean.sh + source "${_DEVTOOLS_LIBRARY_DIR}"/lib/repo/clean.sh + pkgctl_repo_clean "$@" + exit 0 + ;; clone) _DEVTOOLS_COMMAND+=" $1" shift diff --git a/src/lib/repo/clean.sh b/src/lib/repo/clean.sh new file mode 100644 index 0000000..bb8980e --- /dev/null +++ b/src/lib/repo/clean.sh @@ -0,0 +1,114 @@ +#!/bin/bash +# +# SPDX-License-Identifier: GPL-3.0-or-later + +[[ -z ${DEVTOOLS_INCLUDE_REPO_CLEAN_SH:-} ]] || return 0 +DEVTOOLS_INCLUDE_REPO_CLEAN_SH=1 + +_DEVTOOLS_LIBRARY_DIR=${_DEVTOOLS_LIBRARY_DIR:-@pkgdatadir@} +# shellcheck source=src/lib/common.sh +source "${_DEVTOOLS_LIBRARY_DIR}"/lib/common.sh + +source /usr/share/makepkg/util/message.sh + +set -eo pipefail + + +pkgctl_repo_clean_usage() { + local -r COMMAND=${_DEVTOOLS_COMMAND:-${BASH_SOURCE[0]##*/}} + cat <<- _EOF_ + Usage: ${COMMAND} [OPTION] [PATH]... + + Cleans the working tree by recursively removing files that are not under + version control, starting from the current directory. + + Files unknown to Git as well as ignored files are removed. This can, for + example, be useful to remove all build products. + + OPTIONS + -i, --interactive Show what would be done and clean files interactively + -n, --dry-run Don't remove anything, just show what would be done + -h, --help Show this help text + + EXAMPLES + $ ${COMMAND} libfoo linux libbar + $ ${COMMAND} --interactive libfoo linux libbar + $ ${COMMAND} --dry-run * +_EOF_ +} + +pkgctl_repo_clean() { + # options + local git_clean_options=() + local paths + + local path pkgbase + + while (( $# )); do + case $1 in + -i|--interactive) + git_clean_options+=("$1") + shift + ;; + -n|--dry-run) + git_clean_options+=("$1") + shift + ;; + -h|--help) + pkgctl_repo_clean_usage + exit 0 + ;; + --) + shift + break + ;; + -*) + die "invalid argument: %s" "$1" + ;; + *) + paths=("$@") + break + ;; + esac + done + + # check if invoked without any path from within a packaging repo + if (( ${#paths[@]} == 0 )); then + paths=(".") + fi + + # print message about the work chunk + printf "🗑️ Removing untracked files from %s working trees\n" "${BOLD}${#paths[@]}${ALL_OFF}" + + for path in "${paths[@]}"; do + # skip paths that are not directories + if [[ ! -d "${path}" ]]; then + continue + fi + + if [[ ! -f "${path}/PKGBUILD" ]]; then + msg_error "Not a package repository: ${path}" + continue + fi + + if [[ ! -d "${path}/.git" ]]; then + msg_error "Not a Git repository: ${path}" + continue + fi + + pkgbase=$(basename "$(realpath "${path}")") + pkgbase=${pkgbase%.git} + + # run dry mode to see if git would clean any files + if [[ ! $(git -C "${path}" clean -x -d --dry-run 2>&1) ]]; then + continue + fi + + # git clean untracked files + msg_success "Cleaning ${BOLD}${pkgbase}${ALL_OFF}" + if ! git -C "${path}" clean -x -d --force "${git_clean_options[@]}"; then + msg_error "Failed to remove untracked files" + fi + echo + done +} -- cgit v1.2.3-70-g09d2