Последняя активность 1 month ago

Версия 69c6a11d502d99f3d2128b40733b44b8931dd64b

brut.sh Исходник
1#!/bin/sh
2# Brutal Router for Unix Tools - https://brut.sh
3set -eu
4
5
6# Find ourselves
7OLDENV="$(export -p)"
8SELF="$(realpath "$0")"
9NAME="${0##*/}"
10PROGRAM_NAME="${SELF##*/}"
11ROOT="${SELF%/*/*}"
12
13
14# Set up the environment
15LIB="$ROOT/lib/$NAME"
16LIBEXEC="$ROOT/libexec"
17SHARE="$ROOT/share/$NAME"
18VENDOR="$SHARE/vendor"
19
20PATH="$LIB:$LIBEXEC:$VENDOR:$PATH"
21export SELF
22
23USAGE="<COMMAND>"
24unset VERSION
25
26
27# ---
28# Define shared helpers
29
30error() {
31 NAME="${1##*/}"
32 shift
33
34 printf "%s: " "$(invocation)"
35 printf "%s\n" "$@"
36 return 1
37} >&2
38
39usage() {
40 if [ $# -eq 0 ]; then
41 set -- "$NAME" "${USAGE:-}" "commands: $(flatten commands)"
42 fi
43
44 NAME="${1##*/}"
45 shift
46
47 printf "usage: %s " "$(invocation)"
48 printf "%s\n" "$@"
49 return 1
50} >&2
51
52version() {
53 printf "%s %s\n" "$PROGRAM_NAME" "$VERSION"
54}
55
56# ---
57
58commands() {
59 executables | sed -e "s/^.*\/$NAME-//" | sort
60}
61
62executables() {
63 for ns in $(namespaces "$NAME-"); do
64 set -- "$@" \! -name "$ns-*"
65 done
66
67 searchpath -name "$NAME-*" "$@" | awk -F / '!a[$NF]++'
68}
69
70flatten() {
71 "$@" | { tr "\n" " "; printf "\n"; }
72}
73
74invocation() {
75 { printf "%s\n" "$PROGRAM_NAME"; namespaces; } \
76 | sort -r | awk -v name="$NAME" \
77 'index(name, $0 "-") == 1 { name = $0 " " substr(name, length($0) + 2) }
78 END { print name }'
79}
80
81namespaces() {
82 searchpath -type l -name "${1:-$PROGRAM_NAME-}*" \
83 -exec sh -c '[ "$0" = "$(realpath "$1")" ] 2>/dev/null' "$SELF" {} \; \
84 | sed -e "s/^.*\///" | sort -u
85}
86
87resolve() {
88 case "${1:-}" in
89 *-* ) executables -name "$NAME-$1" ;;
90 ?* ) searchpath -name "$NAME-$1" | head -n 1
91 esac | grep .
92}
93
94searchpath() {
95 { IFS=:
96 dirs=
97 set -- \) -o -prune "$@"
98 for dir in $PATH; do
99 [ -d "$dir" ] || continue
100 set -- -o -path "$dir" "$@"
101 dirs="$dirs:$dir"
102 done
103 set -- ${dirs#:} \( \! -name '*' "$@"
104 unset IFS dir dirs
105 } 2>/dev/null
106
107 find -H "$@" 2>/dev/null \
108 \( -perm -001 -o -perm -010 -o -perm -100 \) \
109 \( -type f -o -type l \) \
110 \! -name "?*--?*" \
111 -print || true
112}
113
114unenv() {
115 exec env -i sh -euc 'eval "$1"; shift; exec "$@"' "$0" "$OLDENV" "$@"
116}
117
118# ---
119
120
121# Load _init.sh, if it exists
122if [ -r "$LIB"/_init.sh ]; then
123 . "$LIB"/_init.sh
124fi
125
126
127# Rewrite `--version` to `--- version`
128if [ $# -eq 1 ] && [ -n "${VERSION:-}" ] && [ "$1" = "--version" ]; then
129 set -- --- version
130fi
131
132
133# When invoked as `--- <COMMAND> ...`, run that command and exit
134if [ "${1:-}" = "---" ]; then
135 [ $# -gt 1 ] || usage
136 shift
137 "$@"
138 exit
139fi
140
141
142# Scan the argument list to find the command name
143COMMAND=
144args=
145index=0
146
147for arg; do
148 index=$((index+1))
149 case "$arg" in
150 -* ) ;;
151 ?*--?* ) [ -n "$COMMAND" ] || usage ;;
152 * )
153 if [ -z "$COMMAND" ]; then
154 COMMAND="$arg"
155 continue
156 fi
157 esac
158 args="$args"' "${'"$index"'}"'
159done
160
161
162# Match the command name to an executable in the current namespace;
163# if one exists, exec it
164if executable="$(resolve "$COMMAND")"; then
165 eval "set --$args"
166 exec "$executable" "$@"
167fi
168
169
170# No matching executable; load _unhandled.sh, if it exists
171if [ -r "$LIB"/_unhandled.sh ]; then
172 . "$LIB"/_unhandled.sh
173fi
174
175
176# No matching command or no command specified
177if [ -n "$COMMAND" ]; then
178 error "$0" "$COMMAND: command not found" || exit 127
179fi
180
181usage
182