-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdot-slash-make.sh
146 lines (131 loc) · 4.72 KB
/
dot-slash-make.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# SPDX-License-Identifier: Unlicense
# v0.1.0-pre
# shellcheck shell=sh
#
# This file is part of dot-slash-make https://codeberg.org/jntesteves/dot-slash-make
# Do NOT make changes to this file, your commands go in the ./make file
#
echo() (IFS=' ' && printf '%s\n' "$*")
log_error() (IFS=' ' && printf 'ERROR %s\n' "$*" >&2)
log_warn() (IFS=' ' && printf 'WARN %s\n' "$*" >&2)
log_info() (IFS=' ' && printf '%s\n' "$*")
log_debug() { :; } && [ "$MAKE_DEBUG" ] && log_debug() (IFS=' ' && printf 'DEBUG %s\n' "$*")
log_trace() { :; } && case "$MAKE_DEBUG" in *trace*) log_trace() (IFS=' ' && printf 'TRACE %s\n' "$*") ;; esac
abort() {
__abort__status=${2:-$?}
log_error "$1" || :
exit "$__abort__status"
}
# Run command in a sub-shell, abort on error
run() {
log_info "$@"
("$@") || abort "${0}: [target: ${__target}] Error ${?}"
}
# Run command in a sub-shell, ignore returned status code
run_() {
log_info "$@"
("$@") || log_warn "${0}: [target: ${__target}] Error ${?} (ignored)"
}
# Use indirection to dynamically assign a variable from argument NAME=VALUE
assign_variable() {
case "${1%%=*}" in *[!_a-zA-Z0-9]* | [!_a-zA-Z]*) return 2 ;; esac
eval "${1%%=*}"='${1#*=}'
}
# Check if the given name was provided as an argument in the CLI
__dsm__is_in_cli_parameters_list() (
log_trace "dot-slash-make: [__dsm__is_in_cli_parameters_list] var_name='${1}' __dsm__cli_parameters_list='${__dsm__cli_parameters_list}'"
for arg in $(list_from "$__dsm__cli_parameters_list"); do
[ "$1" = "$arg" ] && return 0
done
return 1
)
__dsm__set_variable_cli_override() {
__dsm__var_name="${2%%=*}"
if [ "$1" ] && __dsm__is_in_cli_parameters_list "$__dsm__var_name"; then
log_debug "dot-slash-make: [${1}] '${__dsm__var_name}' overridden by command line argument"
return 0
fi
assign_variable "$2" || abort "${0}:${1:+" [$1]"} Invalid parameter name '${__dsm__var_name}'"
[ "$1" ] || __dsm__cli_parameters_list="${__dsm__cli_parameters_list}${__dsm__var_name} "
eval "log_debug \"dot-slash-make: [${1:-__dsm__set_variable_cli_override}] ${__dsm__var_name}=\$${__dsm__var_name}\""
}
# Set variable from argument NAME=VALUE, only if it was not overridden by an argument on the CLI
param() { __dsm__set_variable_cli_override param "$@"; }
# Test if any of the arguments is itself a list according to the current value of IFS
is_list() (
for item in "$@"; do
case "$item" in *["$IFS"]*) return 0 ;; esac
done
return 1
)
list_length() { printf '%s' "$#"; }
# Test if lists should have a trailing field separator in the current shell (most do, zsh differs)
# shellcheck disable=SC2086
__list__is_terminated() { __l=x${IFS%"${IFS#?}"} && [ "$(list_length $__l)" -eq 1 ]; }
# Turn arguments into a list of items separated by IFS
list() (
if is_list "$@"; then
printf 'list error: list items cannot be lists\n' >&2
return 1
fi
lt=
__list__is_terminated && lt=${IFS%"${IFS#?}"}
[ "$#" -eq 0 ] || printf '%s' "${*}${lt}"
)
# $(list_from text [separator]): Turn text into a list splitting at each occurrence of separator
# If separator isn't provided the default value of IFS is used (space|tab|line-feed)
list_from() (
set -f # Disable globbing
str=$1
__list__is_terminated || case "$1" in *["$2"]) str="${1%?}" ;; esac
outer_ifs=$IFS
IFS=${2:-' ''
'}
# shellcheck disable=SC2086
IFS=$outer_ifs list $str
)
# Use pattern to format each subsequent argument, return a list separated by IFS
fmt() {
__pattern=$1
shift || {
printf 'fmt error: a format pattern must be provided\n' >&2
return 1
}
# shellcheck disable=SC2059
if [ "$#" -gt 0 ]; then list_from "$(printf "${__pattern}${IFS%"${IFS#?}"}" "$@")" "${IFS%"${IFS#?}"}"; fi
}
# Perform tilde- and pathname-expansion (globbing) on arguments
# Similar behavior as the wildcard function in GNU Make
wildcard() (
outer_ifs=$IFS
IFS=
buffer=
for pattern in "$@"; do
case "$pattern" in
'~') pattern=$HOME ;;
'~'/*) pattern="${HOME}${pattern#'~'}" ;;
esac
set +f # Enable globbing
for file in $pattern; do
set -f
# shellcheck disable=SC2086
[ -e "$file" ] && { buffer=$(IFS=$outer_ifs && list $buffer "$file") || return; }
done
done
printf '%s' "$buffer"
)
list_targets() { list_from "$__dsm__targets"; }
set -f # Disable globbing (aka pathname expansion)
IFS=$(printf '\037') # Use ASCII 0x1F as field separator for "quasi-lossless" lists
__dsm__cli_parameters_list=
__dsm__targets=
__target=
for __dsm__arg in "$@"; do
case "$__dsm__arg" in
[_a-zA-Z]*=*) [ "$DSM_SKIP_CLI_VARIABLES" ] || __dsm__set_variable_cli_override '' "$__dsm__arg" ;;
-*) [ "$DSM_SKIP_CLI_OPTIONS" ] || abort "${0}: invalid option '${__dsm__arg}'" ;;
*) __dsm__targets="${__dsm__targets}${__dsm__arg} " ;;
esac
done
[ "$__dsm__targets" ] || __dsm__targets=-
log_debug "dot-slash-make: targets list: '${__dsm__targets}'"