summary refs log tree commit diff
path: root/bin
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--bin/.gitignore1
-rw-r--r--bin/Makefile1
-rw-r--r--bin/README.74
-rw-r--r--bin/git-import.sh113
-rw-r--r--bin/man1/git-import.149
5 files changed, 167 insertions, 1 deletions
diff --git a/bin/.gitignore b/bin/.gitignore
index 42269bac..d1e9cb1d 100644
--- a/bin/.gitignore
+++ b/bin/.gitignore
@@ -12,6 +12,7 @@ enc
 ever
 freecell
 git-comment
+git-import
 glitch
 hilex
 htagml
diff --git a/bin/Makefile b/bin/Makefile
index bb1535d6..428ce7ee 100644
--- a/bin/Makefile
+++ b/bin/Makefile
@@ -15,6 +15,7 @@ BINS += dehtml
 BINS += dtch
 BINS += enc
 BINS += git-comment
+BINS += git-import
 BINS += glitch
 BINS += hilex
 BINS += htagml
diff --git a/bin/README.7 b/bin/README.7
index 100e183e..9987a0da 100644
--- a/bin/README.7
+++ b/bin/README.7
@@ -1,4 +1,4 @@
-.Dd June  2, 2022
+.Dd September 11, 2023
 .Dt BIN 7
 .Os "Causal Agency"
 .
@@ -36,6 +36,8 @@ watch files
 patience game
 .It Xr git-comment 1
 add commit comments
+.It Xr git-import 1
+import tarballs into git
 .It Xr glitch 1
 PNG glitcher
 .It Xr hilex 1
diff --git a/bin/git-import.sh b/bin/git-import.sh
new file mode 100644
index 00000000..0bec2c25
--- /dev/null
+++ b/bin/git-import.sh
@@ -0,0 +1,113 @@
+#!/bin/sh
+set -eu
+
+: ${CURL:=curl}
+
+die() {
+	echo "$0: $*" >&2
+	exit 1
+}
+
+strip=1
+message=
+
+OPTS_SPEC="\
+git import [<options>] <branch> <file>
+--
+m,message=! create a commit with the specified message
+p,strip= remove the specified number of leading path elements
+"
+eval "$(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@")"
+
+while [ $# -gt 0 ]; do
+	opt=$1
+	shift
+	case "$opt" in
+		(-m) message=$1; shift;;
+		(-p) strip=$1; shift;;
+		(--no-strip) strip=0;;
+		(--) break;;
+	esac
+done
+[ $# -gt 0 ] || die "branch name required"
+[ $# -gt 1 ] || die "file or url required"
+branch=$1
+tarball=$2
+: ${message:="Import ${tarball##*/}"}
+
+check_index() {
+	if ! git diff-index --quiet HEAD; then
+		die "working tree has modifications"
+	fi
+}
+
+check_head() {
+	local head full
+	head=$(git rev-parse --symbolic-full-name HEAD)
+	full=$(git rev-parse --verify --quiet --symbolic-full-name "$1") || return 0
+	if [ "$full" = "$head" ]; then
+		die "branch (${full}) cannot be HEAD (${head})"
+	fi
+}
+
+extract_tarball() {
+	local url strip tarball tmpdir
+	url=$1
+	strip=$2
+	if test -f "$url"; then
+		tarball=$url
+	else
+		tarball=$(mktemp)
+		trap 'rm -f "$tarball"' EXIT
+		$CURL -L -o "$tarball" "$url"
+	fi
+	tmpdir=$(mktemp -d)
+	tar -x -f "$tarball" -C "$tmpdir" --strip-components "$strip"
+	echo "$tmpdir"
+}
+
+create_tree() {
+	local root fullpath path blob mode tree
+	root=$1
+	git read-tree --empty
+	find "$root" -type f | while read -r fullpath; do
+		path=${fullpath#${root}/}
+		blob=$(git hash-object -w --path "$path" "$fullpath")
+		mode=100644
+		if test -L "$fullpath"; then
+			mode=120000
+		elif test -x "$fullpath"; then
+			mode=100755
+		fi
+		git update-index --add --cacheinfo "$mode,$blob,$path"
+	done
+	tree=$(git write-tree)
+	git read-tree HEAD
+	echo "$tree"
+}
+
+create_commit() {
+	local parent tree message
+	parent=$1
+	tree=$2
+	message=$3
+	git commit-tree ${parent:+-p ${parent}} -m "$message" "$tree"
+}
+
+update_branch() {
+	local branch parent commit
+	branch=$1
+	parent=$2
+	commit=$3
+	git update-ref "refs/heads/$branch" "$commit" "$parent"
+}
+
+check_index
+check_head "$branch"
+root=$(extract_tarball "$tarball" "$strip")
+tree=$(create_tree "$root")
+rm -fr "$root"
+parent=$(git rev-parse --verify --quiet "$branch" || :)
+commit=$(create_commit "$parent" "$tree" "$message")
+update_branch "$branch" "$parent" "$commit"
+git --no-pager show --stat "$commit"
diff --git a/bin/man1/git-import.1 b/bin/man1/git-import.1
new file mode 100644
index 00000000..31d224e1
--- /dev/null
+++ b/bin/man1/git-import.1
@@ -0,0 +1,49 @@
+.Dd September 11, 2023
+.Dt GIT-IMPORT 1
+.Os
+.
+.Sh NAME
+.Nm git-import
+.Nd import a tarball into git
+.
+.Sh SYNOPSIS
+.Nm
+.Op Fl m Ar message
+.Op Fl p Ar count
+.Ar branch
+.Ar file
+.
+.Sh DESCRIPTION
+.Nm
+imports a tarball
+as a new commit on
+a git branch.
+If
+.Ar branch
+does not exist,
+it will be created.
+If
+.Ar file
+is a URL,
+it will be fetched with
+.Xr curl 1 .
+.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl m Ar message , Fl \-message Ar message
+Set the commit message.
+.It Fl p Ar count , Fl \-strip Ar count
+Remove the specified number
+of leading path elements.
+The default is 1.
+.El
+.
+.Sh ENVIRONMENT
+.Bl -tag -width Ds
+.It Ev CURL
+The path to
+.Xr curl 1 ,
+used to fetch the tarball
+from a URL.
+.El