summary refs log tree commit diff
path: root/bin/git-import.sh
diff options
context:
space:
mode:
Diffstat (limited to 'bin/git-import.sh')
-rw-r--r--bin/git-import.sh113
1 files changed, 113 insertions, 0 deletions
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"