lib: add user_homedir and sponge functions

This commit is contained in:
Andrew Dunham 2021-07-13 19:04:49 -04:00
parent e0d5017c98
commit a67fa4f250
2 changed files with 102 additions and 0 deletions

59
lib
View file

@ -80,3 +80,62 @@ epochseconds() {
# TODO(andrew-d): break down and verify the math here # TODO(andrew-d): break down and verify the math here
echo $(( $(TZ=GMT0 date +"((%Y-1600)*365+(%Y-1600)/4-(%Y-1600)/100+(%Y-1600)/400+1%j-1000-135140)*86400+(1%H-100)*3600+(1%M-100)*60+(1%S-100)") )) echo $(( $(TZ=GMT0 date +"((%Y-1600)*365+(%Y-1600)/4-(%Y-1600)/100+(%Y-1600)/400+1%j-1000-135140)*86400+(1%H-100)*3600+(1%M-100)*60+(1%S-100)") ))
} }
# user_homedir returns the home directory for the provided user
user_homedir() {
local user="$1"
awk \
-v u="$user" \
-v FS=':' \
'$1==u {print $6}' \
/etc/passwd
}
# sponge acts like sponge(1) from moreutils, but is portable.
#
# It "soaks up" all input from stdin before writing it to the specified output;
# helpful for modifying a file in-place with a utility that does not support
# it.
sponge() {
local append=false
while getopts 'a' opt; do
case $opt in
a) append=true ;;
*) echo "unknown option: $opt" >&2; exit 1;;
esac
done
shift "$(( OPTIND - 1 ))"
local outfile="$1"
local tmpfile
tmpfile="$(mktemp "$(dirname "$outfile")/tmp-sponge.XXXXXXXX")" &&
cat >"$tmpfile" &&
if "$append"; then
cat "$tmpfile" >>"$outfile"
else
if [ -f "$outfile" ]; then
# NOTE: the stat() call here isn't exactly portable, but both GNU
# coreutils and busybox support it, so close enough? Let's
# double-check that it returns something sensible just to be sure.
local oldperms
oldperms="$(stat -c '%a' "$outfile")"
if [ "${#oldperms}" = "3" ] && [ -z "$(echo "$oldperms" | tr -d '0-9')" ]; then
chmod "$oldperms" "$tmpfile"
else
printf "warning (bad: %s): not setting permssions on: %s\n" "${oldperms}" "$outfile" >&2
fi
fi
if [ -f "$outfile" ]; then
mv "$tmpfile" "$outfile"
elif [ -n "$outfile" ] && [ ! -e "$outfile" ]; then
cat "$tmpfile" >"$outfile"
else
cat "$tmpfile"
fi
fi &&
rm -f "$tmpfile"
}

View file

@ -95,5 +95,48 @@ testEpochseconds() {
assertEquals "" "$(epochseconds | tr -d '[0-9]')" assertEquals "" "$(epochseconds | tr -d '[0-9]')"
} }
testUserHomedir() {
assertEquals "$HOME" "$(user_homedir "$USER")"
}
testSponge() {
for i in $(seq 1 10000); do
echo "i am a test line of length 30" >> "$TEST_TMPDIR/largefile.txt"
echo "i am a neat line of length 30" >> "$TEST_TMPDIR/expected.txt"
done
# Modify the file; if we don't sponge, this will probably overwrite things
# and won't work.
cat "$TEST_TMPDIR/largefile.txt" | \
sed 's/test/neat/g' | \
sponge "$TEST_TMPDIR/largefile.txt"
# The files should be equal (currently, we just compare CRCs)
assertEquals "$(cksum < "$TEST_TMPDIR/largefile.txt")" "$(cksum < "$TEST_TMPDIR/expected.txt")"
}
testSponge_Permissions() {
echo "i am the input file" > "$TEST_TMPDIR/input.txt"
echo "i am the output file" > "$TEST_TMPDIR/output.txt"
# Set a strange permission on the output file that we will replicate.
chmod 0741 "$TEST_TMPDIR/output.txt"
cat "$TEST_TMPDIR/input.txt" | sponge "$TEST_TMPDIR/output.txt"
# The files should be equal
assertEquals "$(cat "$TEST_TMPDIR/input.txt")" "$(cat "$TEST_TMPDIR/output.txt")"
assertEquals "741" "$(stat -c '%a' "$TEST_TMPDIR/output.txt")"
}
testSponge_Append() {
echo "one" > "$TEST_TMPDIR/input.txt"
echo "two" > "$TEST_TMPDIR/output.txt"
cat "$TEST_TMPDIR/input.txt" | sponge -a "$TEST_TMPDIR/output.txt"
assertEquals "$(printf 'two\none\n')" "$(cat "$TEST_TMPDIR/output.txt")"
}
# Load shUnit2 # Load shUnit2
. ./shunit2 . ./shunit2