Skip to content

Commit

Permalink
fix: Stdin with forbidden character
Browse files Browse the repository at this point in the history
Implementation relies on nested `sed` command. When stdin contains
default delimiter, substitutions returns error.
  • Loading branch information
macie committed Feb 6, 2024
1 parent 5687529 commit 5b57ea9
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 26 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,19 @@ cat result

For more information, see [ARG_MAX, maximum length of arguments for a new process](https://www.in-ulm.de/~mascheck/various/argmax/).

### unknown option to `s'

`smallstache` uses special character to separate key-value pairs in substitution
command (default: `|`). When value contains this character, `smallstache` will
throw an error similar to:

```
sed: -e expression #1, char 24: unknown option to `s'
```

In such case, you should use another character as a delimiter, for example:
`smallstache -d _`.

## License

[MIT](./LICENSE) ([explanation in simple words](https://tldrlegal.com/license/mit-license))
34 changes: 30 additions & 4 deletions smallstache
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,31 @@


# following line is used by `make cli-release`
smallstache_version=24.1
smallstache_version=24.02

smallstache_delimiter='|'
smallstache_verbosity_level=0

# parse flags
for arg in "$@"; do
case "$arg" in
-d)
shift
case "$1" in
-*)
echo 'smallstache: missing delimiter. See "smallstache -h" for help' >&2
exit 64
;;
*)
if [ "${#1}" -ne 1 ]; then
echo 'smallstache: invalid delimiter. See "smallstache -h" for help' >&2
exit 64
fi
smallstache_delimiter="$1"
shift
;;
esac
;;
-h|--help)
if [ "$#" -gt 1 ]; then
echo 'smallstache: invalid arguments. See "smallstache -h" for help' >&2
Expand All @@ -28,11 +46,13 @@ for arg in "$@"; do
smallstache [-h | --help] [-v | --version]
Options:
-d CHAR Use CHAR as a regex delimiter (default: `|`).
-h, --help Show this help and exit.
-v, --version Show version number and exit.
--verbose Print debugging messages.
Value from stdin KEY=VALUE pairs substitutes `{{KEY}}` in TEMPLATE_FILE.
Stdin cannot contain CHAR delimiter.
EOF
exit 0
;;
Expand Down Expand Up @@ -77,11 +97,17 @@ case "$#" in
;;
esac

smallstache_template=$1

# transform each stdin line in form `KEY=VALUE` into `s|{{ *KEY *}}|VALUE|g; `
smallstache_regex=$(sed 's_\([^=]*\)=\(.*\)_s|{{ *\1 *}}|\2|g; _g')
smallstache_sed_regex="s_\([^=]*\)=\(.*\)_s${smallstache_delimiter}{{ *\1 *}}${smallstache_delimiter}\2${smallstache_delimiter}g; _g"
if ! smallstache_sed_command=$(sed "${smallstache_sed_regex}" 2>/dev/null); then
printf 'smallstache: key contains delimiter character "%s". Change delimiter with "smallstache -d CHAR"\n' "${smallstache_delimiter}" >&2
exit 64
fi
if [ "${smallstache_verbosity_level}" -gt 0 ]; then
echo '# Sed commands to be used on template file' >&2
echo "${smallstache_regex}" >&2
echo "${smallstache_sed_command}" >&2
fi

sed -e "${smallstache_regex}" "$1"
sed -e "${smallstache_sed_command}" "${smallstache_template}"
60 changes: 38 additions & 22 deletions tests/test_data.sh
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#!/bin/sh

beforeAll() {
FIXTURES=$(mktemp -d -t 'smallstache_testXXXXXX')
FIXTURES=$(mktemp -d -t 'smallstache_testXXXXXX')
}

afterEach() {
rm -R "${FIXTURES:-/tmp/smallstache}"/* 2>/dev/null
rm -R "${FIXTURES:-/tmp/smallstache}"/* 2>/dev/null
}

afterAll() {
Expand All @@ -17,54 +17,70 @@ afterAll() {
#

test_text() {
echo "Do {{ who }} feel {{ how }}?" >"${FIXTURES}/template"
printf "who=I\nhow=lucky\n" >"${FIXTURES}/data"
echo "Do I feel lucky?" >"${FIXTURES}/want"
echo "Do {{ who }} feel {{ how }}?" >"${FIXTURES}/template"
printf "who=I\nhow=lucky\n" >"${FIXTURES}/data"
echo "Do I feel lucky?" >"${FIXTURES}/want"

<"${FIXTURES}/data" ./smallstache "${FIXTURES}/template" >"${FIXTURES}/got"
<"${FIXTURES}/data" ./smallstache "${FIXTURES}/template" >"${FIXTURES}/got"

diff "${FIXTURES}/want" "${FIXTURES}/got" >&2
diff "${FIXTURES}/want" "${FIXTURES}/got" >&2
}

test_number() {
echo "e^{{ exp }} = {{ product }}" >"${FIXTURES}/template"
printf "exp=0\nproduct=1.001\n" >"${FIXTURES}/data"
echo "e^0 = 1.001" >"${FIXTURES}/want"
echo "e^{{ exp }} = {{ product }}" >"${FIXTURES}/template"
printf "exp=0\nproduct=1.001\n" >"${FIXTURES}/data"
echo "e^0 = 1.001" >"${FIXTURES}/want"

<"${FIXTURES}/data" ./smallstache "${FIXTURES}/template" >"${FIXTURES}/got"
<"${FIXTURES}/data" ./smallstache "${FIXTURES}/template" >"${FIXTURES}/got"

diff "${FIXTURES}/want" "${FIXTURES}/got" >&2
diff "${FIXTURES}/want" "${FIXTURES}/got" >&2
}

test_partial() {
echo "{{ sth }} ipsum {{ else }} sit {{ what }}" >"${FIXTURES}/template"
printf "sth=Lorem\n" >"${FIXTURES}/data"
echo "Lorem ipsum {{ else }} sit {{ what }}" >"${FIXTURES}/want"
echo "{{ sth }} ipsum {{ else }} sit {{ what }}" >"${FIXTURES}/template"
printf "sth=Lorem\n" >"${FIXTURES}/data"
echo "Lorem ipsum {{ else }} sit {{ what }}" >"${FIXTURES}/want"

<"${FIXTURES}/data" ./smallstache "${FIXTURES}/template" >"${FIXTURES}/got"
<"${FIXTURES}/data" ./smallstache "${FIXTURES}/template" >"${FIXTURES}/got"

diff "${FIXTURES}/want" "${FIXTURES}/got" >&2
diff "${FIXTURES}/want" "${FIXTURES}/got" >&2
}

test_multiline() {
cat >"${FIXTURES}/template" <<-'EOF'
cat >"${FIXTURES}/template" <<-'EOF'
Numbah {{ day_no }} day of Christmas
My tutu gave to me
{{ gifts }}
EOF
cat >"${FIXTURES}/data" <<-'EOF'
cat >"${FIXTURES}/data" <<-'EOF'
day_no=three
gifts=3 dried squid\n2 coconuts and\nOne mynah bird in one papaya tree
EOF
cat >"${FIXTURES}/want" <<-'EOF'
cat >"${FIXTURES}/want" <<-'EOF'
Numbah three day of Christmas
My tutu gave to me
3 dried squid
2 coconuts and
One mynah bird in one papaya tree
EOF

<"${FIXTURES}/data" ./smallstache "${FIXTURES}/template" >"${FIXTURES}/got"
<"${FIXTURES}/data" ./smallstache "${FIXTURES}/template" >"${FIXTURES}/got"

diff "${FIXTURES}/want" "${FIXTURES}/got" >&2
diff "${FIXTURES}/want" "${FIXTURES}/got" >&2
}

test_delimiter_in_key() {
echo '{{ ke_y }}' >"${FIXTURES}/template"
echo "ke_y=value" | ./smallstache -d _ "${FIXTURES}/template" 2>"${FIXTURES}/error_msg"

test $? -eq 64
test -s "${FIXTURES}/error_msg"
}

test_delimiter_in_value() {
echo '{{ key }}' >"${FIXTURES}/template"
echo "key=val|ue" | ./smallstache "${FIXTURES}/template" 2>"${FIXTURES}/error_msg"

test $? -eq 1
test -s "${FIXTURES}/error_msg"
}
7 changes: 7 additions & 0 deletions tests/test_usage.sh
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ test_verbose() {
diff "${FIXTURES}/empty_file" "${FIXTURES}/got"
}

test_invalid_delimiter() {
./smallstache -d __ 2>"${FIXTURES}/error_msg"

test $? -eq 64
test -s "${FIXTURES}/error_msg"
}

test_no_args() {
./smallstache 2>"${FIXTURES}/error_msg"

Expand Down

0 comments on commit 5b57ea9

Please sign in to comment.