A Makefile => Makefile +2 -0
@@ 0,0 1,2 @@
+check:
+ shellcheck tm* lib.sh
M lib.sh => lib.sh +22 -18
@@ 1,4 1,7 @@
-unset CDPATH
+#!/bin/sh -eu
+# ^ for shellcheck
+
+export CDPATH=""
abort() {
printf "%s\n" "$@" >&2
@@ 13,22 16,21 @@ isignored() {
! [ -f "$TM_IGNORE" ] && return 1
IFS='
'
- if [ -d "$1" ]; then
- cd -- "$1"
- path="$PWD"
- else
- cd -- "$(dirname -- "$1")"
- path="$PWD/$(basename -- "$1")"
- fi
- cd - >/dev/null
- cd -- "$TM_WS"
- len="$(pwd | wc -c)"
- cd - >/dev/null
+ path="$( (
+ if [ -d "$1" ]; then
+ cd -- "$1" || exit
+ printf "%s" "$PWD"
+ else
+ cd -- "$(dirname -- "$1")" || exit
+ printf "%s" "$PWD/$(basename -- "$1")"
+ fi
+ ))"
+ len="$( ( cd -- "$TM_WS" && pwd | wc -c) )"
path="$(printf "%s" "$path" | cut -c"$((len + 1))-" 2>/dev/null)"
- for line in $(cat "$TM_IGNORE"); do
+ while IFS= read -r line; do
[ "z$(ch 1 "$line")" = "z#" ] && continue
- printf "$path\n" | grep -Eq "$line" && return 0
- done
+ printf "%s\n" "$path" | grep -Eq "$line" && return 0
+ done <"$TM_IGNORE"
return 1
}
@@ 67,8 69,10 @@ export TM_IGNORE="${TM_IGNORE:-$TM_WS/.tmignore}"
TMPDIR="${TMPDIR:-/tmp}"
tmpname=0
-while ! mkdir -- "$TMPDIR/tm.$((++tmpname))" 2>/dev/null; do :; done
+while ! mkdir -- "$TMPDIR/tm.$((tmpname))" 2>/dev/null; do
+ tmpname="$((tmpname+1))"
+done
TMPDIR="$TMPDIR/tm.$tmpname"
-trap "rm -rf '$TMPDIR'; exit" INT
-trap "rm -rf '$TMPDIR'" EXIT
+trap 'rm -rf "$TMPDIR"; exit' INT
+trap 'rm -rf "$TMPDIR"' EXIT
M tm-cat => tm-cat +1 -0
@@ 1,5 1,6 @@
#!/bin/sh -eu
+# shellcheck source=./lib.sh
. "$(dirname -- "$0")/lib.sh"
if [ $# -ne 1 ]; then
abort "usage: tm cat <ref>"
M tm-commit => tm-commit +7 -1
@@ 1,5 1,6 @@
#!/bin/sh
+# shellcheck source=./lib.sh
. "$(dirname -- "$0")/lib.sh"
while getopts p: opt; do
case "$opt" in
@@ 18,5 19,10 @@ tm resolve-ref HEAD >/dev/null 2>/dev/null && : "${parents=-p HEAD}"
[ $# -gt 1 ] && abort "usage: tm commit [-p <parent>]... [<file>|<directory>]"
tree="$(tm insert "${1:-.}")" || abort "failed to insert ${1:-.}"
-commit="$(tm commit-tree $parents "$tree")" || abort "failed to commit $tree"
+set -f
+# This \o/ is \o/ really \o/ really \o/ dumb
+# shellcheck disable=SC2086
+set -- $parents
+set +f
+commit="$(tm commit-tree "$@" "$tree")" || abort "failed to commit $tree"
exec tm update-ref index "$commit" >/dev/null
M tm-commit-tree => tm-commit-tree +1 -0
@@ 1,5 1,6 @@
#!/bin/sh -eu
+# shellcheck source=./lib.sh
. "$(dirname -- "$0")/lib.sh"
usage() {
abort "usage: tm commit-tree [-p <parent>]... <tree>"
M tm-init => tm-init +1 -0
@@ 1,6 1,7 @@
#!/bin/sh -eu
export TM_DIR="${TM_DIR:-$PWD/.tm}"
+# shellcheck source=./lib.sh
. "$(dirname -- "$0")/lib.sh"
[ $# -ne 0 ] && abort "usage: tm init"
[ -z "${TM_AUTHOR:-}" ] && abort "error: TM_AUTHOR unset"
M tm-insert => tm-insert +11 -5
@@ 4,6 4,7 @@ usage() {
abort "usage: tm insert [-t <type>] [<file>|<directory>]"
}
+# shellcheck source=./lib.sh
. "$(dirname -- "$0")/lib.sh"
type=default
@@ 37,8 38,14 @@ tree)
[ $# -eq 1 ] && cd "$1"
IFS='
'
- for file in $(ls -A); do
- mode="$(ls -lA | postfix " $file" | cut -f1 -d' ')"
+ # TODO: replace this with a find -type d followed by a find -type f
+ for file in ..?* .[!.]* *; do
+ [ ! -e "$file" ] && continue
+ nf="$((8 + $(printf "%s" "$file" | awk '{print NF}')))"
+ # We need to use ls -l to get the file mode; the only other way to get
+ # it is with pax, and pax isn't even packaged on Alpine
+ # shellcheck disable=SC2012
+ mode="$(ls -lA | awk -v nf="$nf" '{if (NF = nf) print $0}' | postfix " $file" | cut -f1 -d' ')"
case "$(ch 1 "$mode")" in
b|c|l|p)
abort "error: non-regular file %s\n" "$file"
@@ 53,9 60,8 @@ tree)
[ "z$(ch 8 "$mode")" = "zr" ] && m="$((m + 4))"
[ "z$(ch 9 "$mode")" = "zw" ] && m="$((m + 2))"
[ "z$(ch 10 "$mode")" = "zx" ] && m="$((m + 1))"
- set +e
- hash="$(tm insert -- "$file")" && printf "%s %s %s\n" "$m" "$hash" "$file" >>"$tmp"
- set -e
+ hash="$(tm insert -- "$file")" || true \
+ && printf "%s %s %s\n" "$m" "$hash" "$file" >>"$tmp"
done
;;
commit)
M tm-next => tm-next +2 -1
@@ 1,9 1,10 @@
#!/bin/sh
+# shellcheck source=./lib.sh
. "$(dirname -- "$0")/lib.sh"
[ $# -gt 1 ] && abort "usage: tm next [<ref>]"
new="$(tm resolve-ref "${1:-index}")" || exit 1
-for ref in $(ls "$TM_DIR/refs/"); do
+for ref in "$TM_DIR/refs/"*; do
[ "z$ref" = "zHEAD" ] && continue
# XXX: is this the right thing to do?
[ "z$ref" = "zindex" ] && continue
M tm-object-type => tm-object-type +1 -0
@@ 1,5 1,6 @@
#!/bin/sh
+# shellcheck source=./lib.sh
. "$(dirname -- "$0")/lib.sh"
[ $# -eq 1 ] || abort "usage: tm object-type <ref>"
M tm-read-commit => tm-read-commit +1 -0
@@ 1,5 1,6 @@
#!/bin/sh
+# shellcheck source=./lib.sh
. "$(dirname -- "$0")/lib.sh"
mode=t
while getopts tpacdsb opt; do
M tm-resolve-path => tm-resolve-path +1 -0
@@ 1,5 1,6 @@
#!/bin/sh -eu
+# shellcheck source=./lib.sh
. "$(dirname -- "$0")/lib.sh"
field=2
M tm-resolve-ref => tm-resolve-ref +9 -5
@@ 1,5 1,6 @@
#!/bin/sh -eu
+# shellcheck source=./lib.sh
. "$(dirname -- "$0")/lib.sh"
if [ $# -ne 1 ]; then
abort "usage: tm resolve-ref <ref>"
@@ 7,10 8,13 @@ fi
# TODO: ref~X, ref^X
if [ -f "$TM_DIR/refs/$1" ]; then
- tm resolve-ref "$(cat "$TM_DIR/refs/$1")"
-elif [ "$(echo "$TM_DIR/objects/$1"* | awk '{print NF}')" -eq 1 ] \
- && [ -f "$TM_DIR/objects/$1"* ]; then
- printf "%s\n" "$(basename "$TM_DIR/objects/$1"*)"
+ tm resolve-ref "$(cat -- "$TM_DIR/refs/$1")"
else
- abort "error: invalid ref $1"
+ short="$1"
+ set -- "$TM_DIR/objects/$short"*
+ if [ $# -eq 1 ] && [ -f "$1" ]; then
+ printf "%s\n" "$(basename -- "$1")"
+ else
+ abort "error: invalid ref $short"
+ fi
fi
M tm-update-ref => tm-update-ref +1 -0
@@ 1,5 1,6 @@
#!/bin/sh -eu
+# shellcheck source=./lib.sh
. "$(dirname -- "$0")/lib.sh"
[ $# -ne 2 ] && abort "usage: tm update-ref <refname> <ref>"
[ -f "$TM_DIR/refs/$1" ] || printf "creating ref %s\n" "$1"
M tm-update-tree => tm-update-tree +1 -0
@@ 18,6 18,7 @@ done
shift "$((OPTIND - 1))"
+# shellcheck source=./lib.sh
. "$(dirname -- "$0")/lib.sh"
[ $# -ne 3 ] && usage