diff options
Diffstat (limited to 'examples/tools')
| -rwxr-xr-x | examples/tools/clone.sh | 24 | ||||
| -rw-r--r-- | examples/tools/clone.toml | 2 | ||||
| -rwxr-xr-x | examples/tools/test-clone.sh | 35 |
3 files changed, 45 insertions, 16 deletions
diff --git a/examples/tools/clone.sh b/examples/tools/clone.sh index e4051fc..f08b932 100755 --- a/examples/tools/clone.sh +++ b/examples/tools/clone.sh @@ -15,8 +15,9 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # -# clone.sh <url> [to] [update]: clone into <root>/<folder>/<repo>, the folder -# chosen by host from the clone-hosts map (github.com -> GITHUB, ...). An +# clone.sh <url> [to] [update]: clone into <root>/<folder>/<owner>-<repo> (just +# <repo> when the URL has no owner, or when owner and repo are the same), the +# folder chosen by host from the clone-hosts map (github.com -> GITHUB, ...). An # unknown host stops and says which folder to offer; passing that folder as # <to> clones there and remembers the mapping. <update>=1 pulls an existing # clone instead. Check: test-clone.sh. @@ -56,12 +57,22 @@ host=${host%%:*} path=${path%/} repo=${path##*/} repo=${repo%.git} +# The segment before the repo is the owner; a nested group keeps only its last +# segment. No slash at all means no owner. +if [ "${path%/*}" = "$path" ]; then + owner="" +else + owner=${path%/*} + owner=${owner##*/} +fi -# Both names land in a path, so neither may escape the tree. +# Every name lands in a path, so none may escape the tree. [[ $host =~ ^[A-Za-z0-9][A-Za-z0-9.-]*$ ]] || { echo "bad host: $host" >&2; exit 1; } [[ $repo =~ ^[A-Za-z0-9][A-Za-z0-9._-]*$ ]] || { echo "bad repository name: $repo" >&2; exit 1; } +[ -z "$owner" ] || [[ $owner =~ ^[A-Za-z0-9][A-Za-z0-9._-]*$ ]] || + { echo "bad owner name: $owner" >&2; exit 1; } # host -> folder, one tab-separated pair per line, seeded once. Appending the # approved folder is how a new host is remembered, so the next clone of that @@ -80,14 +91,17 @@ if [ -n "$to" ]; then folder=$to fi +name=$repo +[ -z "$owner" ] || [ "$owner" = "$repo" ] || name=$owner-$repo + if [ -z "$folder" ]; then label=${host%.*} label=$(printf '%s' "$label" | tr '[:lower:]' '[:upper:]') - echo "no folder for host $host; ask the user: create $label/ and clone $repo there? if yes, call again with to=$label" + echo "no folder for host $host; ask the user: create $label/ and clone $name there? if yes, call again with to=$label" exit 0 fi -target=$root/$folder/$repo +target=$root/$folder/$name # Never clone over an existing folder, and never under another name: offer an # update instead. ff-only so a diverged clone is reported, not merged. diff --git a/examples/tools/clone.toml b/examples/tools/clone.toml index 0862165..4e479fd 100644 --- a/examples/tools/clone.toml +++ b/examples/tools/clone.toml @@ -1,4 +1,4 @@ -description = "Clone a public git repository into the user's project tree. The folder comes from the host: github.com -> GITHUB, gitlab.com -> GITLAB, forge.slackware.nl -> FORGE, plus hosts remembered from earlier clones. Call it with url and nothing else; when the host is known and the repo is not there yet it clones straight away. If it answers that the host has no folder, or that the repo is already cloned, it did nothing: ask the user exactly as that answer says, then call again with the to or update it names. Never clone a repo under a different name when it is already there; offer to update it." +description = "Clone a public git repository into the user's project tree. The folder comes from the host: github.com -> GITHUB, gitlab.com -> GITLAB, forge.slackware.nl -> FORGE, plus hosts remembered from earlier clones. The repository lands in its owner's name, e.g. https://github.com/evgen2571/wallpapers goes to GITHUB/evgen2571-wallpapers (just the repo name when the URL has no owner or owner and repo are the same). Call it with url and nothing else; when the host is known and the repo is not there yet it clones straight away. If it answers that the host has no folder, or that the repo is already cloned, it did nothing: ask the user exactly as that answer says, then call again with the to or update it names. Never clone a repo under a different name when it is already there; offer to update it." command = ["clone.sh", "{url}", "{to}", "{update}"] timeout = 300 diff --git a/examples/tools/test-clone.sh b/examples/tools/test-clone.sh index d84a157..ff45b6d 100755 --- a/examples/tools/test-clone.sh +++ b/examples/tools/test-clone.sh @@ -45,33 +45,48 @@ contains() { case "$2" in *"$3"*) ;; *) echo "FAIL $1: '$2' lacks '$3'"; fail=1 count() { grep -cF -- "$1" "$GIT_LOG" || true; } mapcount() { grep -cF -- "$1" "$CLONE_MAP" || true; } -# Known host, clean copy: seeded map, straight clone, no question. +# Known host, clean copy: seeded map, straight clone, no question. Owner and +# repo both go in the target folder name. out=$("$here/clone.sh" https://github.com/a/b.git) -check "github clone" "$out" "cloned https://github.com/a/b.git into $CLONE_ROOT/GITHUB/b" +check "github clone" "$out" "cloned https://github.com/a/b.git into $CLONE_ROOT/GITHUB/a-b" check "seed" "$(cat "$CLONE_MAP")" \ "$(printf '%s\t%s\n' github.com GITHUB gitlab.com GITLAB forge.slackware.nl FORGE)" -check "clone argv" "$(count "clone -- https://github.com/a/b.git $CLONE_ROOT/GITHUB/b")" "1" +check "clone argv" "$(count "clone -- https://github.com/a/b.git $CLONE_ROOT/GITHUB/a-b")" "1" # Trailing slash and .git are not part of the repo name. out=$("$here/clone.sh" https://gitlab.com/a/c.git/) -check "gitlab repo" "$out" "cloned https://gitlab.com/a/c.git into $CLONE_ROOT/GITLAB/c" +check "gitlab repo" "$out" "cloned https://gitlab.com/a/c.git into $CLONE_ROOT/GITLAB/a-c" + +# A self-named repo is not doubled (firefly-iii/firefly-iii -> firefly-iii). +out=$("$here/clone.sh" https://github.com/firefly-iii/firefly-iii.git) +check "self-named" "$out" \ + "cloned https://github.com/firefly-iii/firefly-iii.git into $CLONE_ROOT/GITHUB/firefly-iii" + +# No owner in the URL: the plain repo name. +out=$("$here/clone.sh" git@github.com:solo.git) +check "no owner" "$out" "cloned git@github.com:solo.git into $CLONE_ROOT/GITHUB/solo" + +# A nested group keeps only its last segment as the owner. +out=$("$here/clone.sh" https://gitlab.com/group/sub/thing.git) +check "subgroup" "$out" \ + "cloned https://gitlab.com/group/sub/thing.git into $CLONE_ROOT/GITLAB/sub-thing" # Unknown host: ask, do nothing, name the folder to offer. out=$("$here/clone.sh" https://codeberg.org/a/d) contains "unknown asks" "$out" "no folder for host codeberg.org" contains "unknown label" "$out" "to=CODEBERG" -check "unknown no clone" "$(count "$CLONE_ROOT/CODEBERG/d")" "0" +check "unknown no clone" "$(count "$CLONE_ROOT/CODEBERG/a-d")" "0" # Approved folder: clone there and remember it. out=$("$here/clone.sh" https://codeberg.org/a/d CODEBERG) -check "approved clone" "$out" "cloned https://codeberg.org/a/d into $CLONE_ROOT/CODEBERG/d" +check "approved clone" "$out" "cloned https://codeberg.org/a/d into $CLONE_ROOT/CODEBERG/a-d" check "remembered" "$(mapcount 'codeberg.org')" "1" check "remembered pair" "$(grep -F 'codeberg.org' "$CLONE_MAP")" \ "$(printf 'codeberg.org\tCODEBERG')" # Next clone of that host asks nothing. out=$("$here/clone.sh" https://codeberg.org/a/e) -check "remembered clone" "$out" "cloned https://codeberg.org/a/e into $CLONE_ROOT/CODEBERG/e" +check "remembered clone" "$out" "cloned https://codeberg.org/a/e into $CLONE_ROOT/CODEBERG/a-e" # Re-approving the same folder does not duplicate the map line. "$here/clone.sh" https://codeberg.org/a/f CODEBERG >/dev/null @@ -79,11 +94,11 @@ check "no duplicate map line" "$(mapcount 'codeberg.org')" "1" # Already cloned: ask, do not clone again; update pulls. out=$("$here/clone.sh" https://github.com/a/b.git) -contains "already asks" "$out" "already cloned at $CLONE_ROOT/GITHUB/b" +contains "already asks" "$out" "already cloned at $CLONE_ROOT/GITHUB/a-b" check "already no reclone" "$(count "clone -- https://github.com/a/b.git")" "1" out=$("$here/clone.sh" https://github.com/a/b.git "" 1) -contains "update says" "$out" "updated $CLONE_ROOT/GITHUB/b" -check "update argv" "$(count "-C $CLONE_ROOT/GITHUB/b pull --ff-only")" "1" +contains "update says" "$out" "updated $CLONE_ROOT/GITHUB/a-b" +check "update argv" "$(count "-C $CLONE_ROOT/GITHUB/a-b pull --ff-only")" "1" # Bad input is refused before anything is created. "$here/clone.sh" "" >/dev/null 2>&1; check "empty url" "$?" "1" |
