diff --git a/src/envmon.sh b/src/envmon.sh new file mode 100644 index 0000000..40c2f1e --- /dev/null +++ b/src/envmon.sh @@ -0,0 +1,98 @@ +#!/bin/bash +# Environment monitor +# +# Copyright (C) 2014 Mike Gerwitz +# +# This file is part of pkgsh. +# +# pkgsh is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# It is highly recommended that you monitor a clean environment (e.g. using +# `env -i`) to avoid as much overhead as possible. +## + +[ -z $__PKGSH_INC_ENVMON ] || return +__PKGSH_INC_ENVMON=1 + +declare -A __pkgsh_envmon_env=() + + +## +# Map environment to a callback +# +# For each environment variable, $callback will be invoked with two +# arguments: the variable name and its value. +# +_pkgsh-envmon-env-map() +{ + local -r callback="$1" + local var= val= + + while read -d $'\0' env; do + var="${env%%=*}" + val="${env#*=}" + + "$callback" "$var" "$val" + done < <( env -0 ) +} + + +## +# Prepares the environment monitor for use +# +_pkgsh-envmon-init() +{ + _pkgsh-envmon-env-map __pkgsh-envmon-envload +} + + +## +# Load the provided variable name and value into the cache +# +# This produces a local copy of the environment in memory, which can be used +# to check against a later environment state for changes. +# +__pkgsh-envmon-envload() +{ + local -r var="$1" val="$2" + __pkgsh_envmon_env[$var]="$val" +} + + +## +# Output null-byte-delimited names and values of variables added to the +# environment since the last diff and update the environment cache +# +_pkgsh-envmon-diff-adds() +{ + _pkgsh-envmon-env-map __pkgsh-envmon-dodiff-adds +} + + +## +# Output provided value with terminating null byte if $name does not exist +# in the environment cache, then immediately add $name to the cache +__pkgsh-envmon-dodiff-adds() +{ + local -r var="$1" val="$2" + + # ignore if it already exists (FIXME: this will fail if the in-memory + # value is empty) + [ -z "${__pkgsh_envmon_env[$var]}" ] || return 0 + + # output the difference and immediately add to the environment in memory + echo -ne "$var=$val\000" + __pkgsh_envmon_env[$var]="$val" +} + diff --git a/test/envmon/test-diff-adds.sh b/test/envmon/test-diff-adds.sh new file mode 100644 index 0000000..401fa3f --- /dev/null +++ b/test/envmon/test-diff-adds.sh @@ -0,0 +1,50 @@ +#!/bin/bash +# Tests monitoring for environment additions +# +# Copyright (C) 2014 Mike Gerwitz +# +# This file is part of pkgsh. +# +# pkgsh is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Tests monitoring the environment for variable additions +## + +source src/envmon.sh + +# initialize to the current state of the environment +_pkgsh-envmon-init + +# add two variables to the environment (note that one contains newlines to +# ensure that they do not cause problems) +export foo=a bar=newline$'\n'test +declare -A found=() + +# perform env addition diff +while read -d $'\0' env; do + var="${env%%=*}" + val="${env#*=}" + + found[$var]="$val" +done < <( _pkgsh-envmon-diff-adds ) + +# ensure each was found +for name in foo bar; do + eval chk="\$$name" + assert "${found[$name]}" == "$chk" +done + +# ensure that no others were found +assert "${#found[@]}" -eq 2 +