Add a utility script for listing and manipulating feeds

Signed-off-by: Rex Keen <rex.keen@ni.com>
Signed-off-by: Alejandro del Castillo <alejandro.delcastillo@ni.com>
This commit is contained in:
Rex Keen
2019-11-04 15:28:49 -06:00
committed by Alejandro del Castillo
parent 104e32b042
commit a53d53bb7e
2 changed files with 743 additions and 0 deletions

568
opkg-feed Executable file
View File

@@ -0,0 +1,568 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0-only
printUsage()
{
cat << EOF
opkg-feed action [--conf-dir=PATH] [-h|--help] [action-options]
ACTIONS
list
List software feeds as they appear in the configuration file(s).
add <feedName>
Add a new software feed.
Feeds are enabled and not trusted by default.
modify <feedName>
Modify an existing software feed.
Values not modified will not be changed.
remove <feedName>
Remove an existing software feed.
ACTION OPTIONS
list option(s):
[--key-value]
add option(s):
--uri=LOCATION [--clobber] [--enabled=ENABLED] [--source-type=TYPE]
[--trusted=TRUSTED]
modify option(s):
[--clobber] [--enabled=ENABLED] [--name=NAME] [--source-type=TYPE]
[--trusted=TRUSTED] [--uri=LOCATION]
OPTIONS
--clobber
Allow an existing feed to be overwritten.
--conf-dir=PATH
PATH to the opkg configuration directory.
PATH may be relative. Symlinks will be followed.
Default: "/etc/opkg"
--enabled=ENABLED
Enabled state of the feed.
Disabled feeds remain on the system but are ignored by opkg.
ENABLED may be "1" or "0".
Default: "1"
-h|--help
Display help information and exit.
--key-value
Print feed information in the "key=value" style.
Feeds are separated by empty lines.
--name=NAME
Name of the feed.
Will not overwrite an existing feed unless --clobber is specified.
--source-type=TYPE
Refers to how the repository list is stored.
TYPE may be "src", "src/gz", "dist", or "dist/gz".
Default: "src/gz"
--trusted=TRUSTED
Trusted state of the feed.
Trusted feeds will not be cryptographically verified by opkg to be a
safe and secure source of packages. A system administrator may have
reason to trust the feed regardless.
TRUSTED may be "1" or "0".
Default: "0"
--uri=LOCATION
LOCATION of the feed, such as "https://..." or "file://...".
EXIT STATUS
0 No error; command ran to completion
3 Invalid argument
4 The named feed was not found
5 The named feed already exists
EOF
}
# ------------------------------------------------------------------------------
# Globals
# ------------------------------------------------------------------------------
declare -r S_OK=0
declare -r E_GENERIC_ERROR=1
declare -r E_INVALID_ARG=3
declare -r E_FEED_NOT_FOUND=4
declare -r E_FEED_ALREADY_EXISTS=5
declare -r IE_GREP_MATCH=0
declare -r IE_GREP_NO_MATCH=1
declare -r SPACE_PATTERN='\s'
declare -r DOUBLE_QUOTE_PATTERN='"'
declare -A ARGS
declare -A DECOMP_FEED
# ------------------------------------------------------------------------------
# Utility functions
# ------------------------------------------------------------------------------
allEmpty()
{
for arg in "$@" ; do
if [ -n "$arg" ] ; then
return $E_GENERIC_ERROR
fi
done
return $S_OK
}
escapeChars()
{
local string=$1
local chars=$2
for (( index=0 ; index<${#1} ; index++ )) ; do
char="${string:$index:1}"
case $char in
[$chars])
echo -n "\\$char"
;;
*)
echo -n "$char"
;;
esac
done
}
escapeRegex()
{
# Escape the \ here for the consumer
echo "$( escapeChars "$1" '[\\^$.|?*+(){}' )"
}
parseBool()
{
if [[ "$1" =~ ^[10]$ ]] ; then
echo "$1"
fi
}
# ------------------------------------------------------------------------------
# Action helpers
# ------------------------------------------------------------------------------
createFeedLineRegex()
{
local feedName="$( escapeRegex "$1" )"
# The regex constructed here was derived from the regex in opkglib's opkg_conf.c at
# https://urldefense.com/v3/__https://git.yoctoproject.org/cgit/cgit.cgi/opkg/tree/libopkg/opkg_conf.c__;!fqWJcnlTkjM!9i4Onh9iVJK9m0kcWmZI6WKisWsX5nNe__ZqOSr7If-Hh6WGsOE9HNr9-6dNcgwHL6GfEg$
# Disabled marker
enabledPattern='^#?\s*';
# Source type capture groups (1, 2, 3)
# 1 = full source type with any quotes
# 2 = source type without quotes if quoted
# 3 = source type if unquoted
sourceTypePattern='("([^"]*)"|(\S+))\s+';
# Feed name capture groups (4, 5, 6)
# 4 = full feed name with any quotes
# 5 = feed name without quotes if quoted
# 6 = feed name if unquoted
namePattern='("([^"]*)"|(\S*))\s+';
if [ -n "$feedName" ] ; then
namePattern="(\"$feedName\"|$feedName)\\s+";
fi
# Feed URI capture groups (7, 8, 9)
# 7 = full URI with any quotes
# 8 = URI without quotes if quoted
# 9 = URI if unquoted
uriPattern='("([^"]*)"|(\S*))\s*';
# Feed option capture groups (10, 11)
# 10 = options with brackets
# 11 = options without brackets
optionsPattern='(\[([^]]+)\])?\s*';
# Feed "extra" capture group (12)
# 12 = unused extra field
extraPattern='(\S+)?\s*';
# Trailing garbage capture group (13)
# 13 = if non-empty, opkg will complain about and ignore the feed entry
garbagePattern='(.*)?\s*';
echo "$enabledPattern$sourceTypePattern$namePattern$uriPattern$optionsPattern$extraPattern$garbagePattern"
}
decomposeFeedLine()
{
local feedLine="$1"
local feedRegex=$( createFeedLineRegex )
for key in "${!DECOMP_FEED[@]}" ; do
unset DECOMP_FEED["$key"]
done
if ! [[ "$feedLine" =~ $feedRegex ]] ; then
return $E_GENERIC_ERROR
fi
# Ignore feed lines with trailing garbage
if [ -n "${BASH_REMATCH[13]}" ] ; then
return $E_GENERIC_ERROR
fi
DECOMP_FEED[enabled]='1'
if [[ "${feedLine::1}" == '#' ]] ; then
DECOMP_FEED[enabled]='0'
fi
local sourceTypeQuoted="${BASH_REMATCH[2]}"
local sourceTypeUnquoted="${BASH_REMATCH[3]}"
DECOMP_FEED[source-type]="${sourceTypeQuoted:-$sourceTypeUnquoted}"
local nameQuoted="${BASH_REMATCH[5]}"
local nameUnquoted="${BASH_REMATCH[6]}"
DECOMP_FEED[name]="${nameQuoted:-$nameUnquoted}"
local uriQuoted="${BASH_REMATCH[8]}"
local uriUnquoted="${BASH_REMATCH[9]}"
DECOMP_FEED[uri]="${uriQuoted:-$uriUnquoted}"
local options="${BASH_REMATCH[11]}"
for option in $options ; do
if [[ "$option" == 'trusted=yes' ]] ; then
DECOMP_FEED[trusted]='1'
fi
done
DECOMP_FEED[extra]="${BASH_REMATCH[12]}"
local sourceTypeRegex='^(src|dist)(/gz)?$'
if [[ "${DECOMP_FEED[source-type]}" =~ $sourceTypeRegex ]] ; then
return $S_OK
fi
return $E_GENERIC_ERROR
}
formatFeedLine()
{
local enabled="$1"
local sourceType="$2"
local name="$3"
local uri="$4"
local trusted="$5"
local extra="$6"
if [[ "$name" =~ $SPACE_PATTERN ]] ; then
name="\"$name\""
fi
if [[ "$uri" =~ $SPACE_PATTERN ]] ; then
uri="\"$uri\""
fi
local options=
if [[ "$trusted" == '1' ]] ; then
options='[trusted=yes]'
fi
if [[ "$enabled" == '0' ]] ; then
echo -n '# '
fi
echo -n "$sourceType $name $uri"
if [ -n "$options" ] ; then
echo -n " $options"
fi
if [ -n "$extra" ] ; then
echo -n " $extra"
fi
}
feedExists()
{
if [ -z "$1" ] ; then
return $E_GENERIC_ERROR
fi
local feedRegex="$( createFeedLineRegex "$1" )"
grep --perl-regexp --only-matching --no-filename "$feedRegex" "${ARGS[confDir]}"/*.conf &>/dev/null
if [[ "$?" == "$IE_GREP_MATCH" ]] ; then
return $S_OK
fi
return $E_GENERIC_ERROR
}
# ------------------------------------------------------------------------------
# Actions
# ------------------------------------------------------------------------------
listFeeds()
{
for filePath in "${ARGS[confDir]}"/*.conf ; do
if [ -f "$filePath" ] ; then
while IFS='' read -r line || [ -n "$line" ] ; do
if decomposeFeedLine "$line" ; then
if [[ "${ARGS[kv]}" == '1' ]] ; then
for key in "${!DECOMP_FEED[@]}" ; do
local value=${DECOMP_FEED["$key"]}
if [ -n "$value" ] ; then
echo "$key=$value"
fi
done
echo ''
else
echo "$line"
fi
fi
done < "$filePath"
fi
done
}
addFeed()
{
if [ -z "${ARGS[name]}" ] || [ -z "${ARGS[uri]}" ] ; then
return $E_INVALID_ARG
fi
if feedExists "${ARGS[name]}" ; then
if [[ "${ARGS[clobber]}" != '1' ]] ; then
return $E_FEED_ALREADY_EXISTS
else
modifyFeed
return $?
fi
fi
local fileName=$( echo "${ARGS[name]}" | sed 's/[^a-zA-Z0-9_=+-]//g' )
local feedLine=$( formatFeedLine \
"${ARGS[enabled]:-1}" \
"${ARGS[source-type]:-src/gz}" \
"${ARGS[name]}" \
"${ARGS[uri]}" \
"${ARGS[trusted]:-0}" \
'' )
printf '%s\n' "$feedLine" >> "${ARGS[confDir]}/${fileName:-misc-feeds}.conf"
return $S_OK
}
modifyFeed()
{
if [ -z "${ARGS[name]}" ] ; then
return $E_INVALID_ARG
fi
if ! feedExists "${ARGS[name]}" ; then
return $E_FEED_NOT_FOUND
fi
if allEmpty "${ARGS[newName]}" "${ARGS[source-type]}" "${ARGS[uri]}" "${ARGS[enabled]}" "${ARGS[trusted]}" ; then
return $E_INVALID_ARG
fi
if [[ "${ARGS[newName]}" != "${ARGS[name]}" ]] && feedExists "${ARGS[newName]}" ; then
if [[ "${ARGS[clobber]}" != '1' ]] ; then
return $E_FEED_ALREADY_EXISTS
else
removeFeed "${ARGS[newName]}"
fi
fi
local feedRegex
feedRegex=$( createFeedLineRegex "${ARGS[name]}" )
local matchingFeed=$( grep --perl-regexp --only-matching --no-filename "$feedRegex" "${ARGS[confDir]}"/*.conf )
if ! decomposeFeedLine "$matchingFeed" ; then
return $E_GENERIC_ERROR
fi
local feedLine=$( formatFeedLine \
"${ARGS[enabled]:-${DECOMP_FEED[enabled]}}" \
"${ARGS[source-type]:-${DECOMP_FEED[source-type]}}" \
"${ARGS[newName]:-${DECOMP_FEED[name]}}" \
"${ARGS[uri]:-${DECOMP_FEED[uri]}}" \
"${ARGS[trusted]:-${DECOMP_FEED[trusted]}}" \
"${DECOMP_FEED[extra]}" )
feedLine=$( escapeRegex "$feedLine" )
local delim=$( printf '\007' )
if ! sed --regexp-extended --in-place "s${delim}$feedRegex${delim}$feedLine${delim}" "${ARGS[confDir]}"/*.conf ; then
return $E_GENERIC_ERROR
fi
return $S_OK
}
removeFeed()
{
if [ -z "$1" ] ; then
return $E_INVALID_ARG
fi
local feedRegex=$( createFeedLineRegex "$1" )
grep --perl-regexp --only-matching --no-filename "$feedRegex" "${ARGS[confDir]}"/*.conf &>/dev/null
local ret=$?
if [[ "$ret" == "$IE_GREP_NO_MATCH" ]] ; then
return $E_FEED_NOT_FOUND
elif [[ "$ret" != "$IE_GREP_MATCH" ]] ; then
return $E_GENERIC_ERROR
fi
local delim=$( printf '\007' )
if ! sed --regexp-extended --in-place "\\${delim}$feedRegex${delim}d" "${ARGS[confDir]}"/*.conf ; then
return $E_GENERIC_ERROR
fi
find "${ARGS[confDir]}" -size 0c -exec rm -f {} +
return $S_OK
}
# ------------------------------------------------------------------------------
# Argument processing
# ------------------------------------------------------------------------------
parseArguments()
{
local longOptions="$1"',conf-dir:,help'
local shortOptions='h'
shift
local opts
opts=$( getopt -ql "$longOptions" -- "$shortOptions" "$@" ) || exit 3
eval set -- "$opts"
ARGS[confDir]="/etc/opkg"
while true; do
case "$1" in
--clobber)
ARGS[clobber]='1'
shift
;;
--conf-dir)
ARGS[confDir]="$2"
shift 2
;;
--enabled)
ARGS[enabled]="$( parseBool "$2" )"
if [ -z "${ARGS[enabled]}" ] ; then
exit $E_INVALID_ARG
fi
shift 2
;;
-h|--help)
printUsage
exit $S_OK
;;
--key-value)
ARGS[kv]='1'
shift
;;
--name)
ARGS[newName]="$2"
if [[ "${ARGS[newName]}" =~ $DOUBLE_QUOTE_PATTERN ]] ; then
exit $E_INVALID_ARG
fi
shift 2
;;
--source-type)
ARGS[source-type]="$2"
case "${ARGS[source-type]}" in
src|src/gz|dist|dist/gz)
;;
*)
exit $E_INVALID_ARG
;;
esac
shift 2
;;
--trusted)
ARGS[trusted]="$( parseBool "$2" )"
if [ -z "${ARGS[trusted]}" ] ; then
exit $E_INVALID_ARG
fi
shift 2
;;
--uri)
ARGS[uri]="$2"
if [[ "${ARGS[uri]}" =~ $DOUBLE_QUOTE_PATTERN ]] ; then
exit $E_INVALID_ARG
fi
shift 2
;;
--)
shift
break
;;
*)
exit $E_INVALID_ARG
esac
done
}
# ------------------------------------------------------------------------------
# main()
# ------------------------------------------------------------------------------
if [ -z "$1" ] ; then
printUsage
exit $E_INVALID_ARG
fi
# Disable history expansion
set +H
case "$1" in
list)
shift
parseArguments 'key-value' "$@"
listFeeds
;;
add)
ARGS[name]="$2"
if [[ "${ARGS[name]}" =~ $DOUBLE_QUOTE_PATTERN ]] ; then
exit $E_INVALID_ARG
fi
shift 2
parseArguments 'clobber,enabled:,source-type:,trusted:,uri:' "$@"
addFeed
;;
modify)
ARGS[name]="$2"
if [[ "${ARGS[name]}" =~ $DOUBLE_QUOTE_PATTERN ]] ; then
exit $E_INVALID_ARG
fi
shift 2
parseArguments 'clobber,enabled:,name:,source-type:,trusted:,uri:' "$@"
modifyFeed
;;
remove)
parseArguments '' "$@"
if [[ "$2" =~ $DOUBLE_QUOTE_PATTERN ]] ; then
exit $E_INVALID_ARG
fi
removeFeed "$2"
;;
help)
printUsage
exit $S_OK
;;
*)
parseArguments '' "$@"
exit $E_INVALID_ARG
;;
esac
exit $?

175
tests/testOpkgFeedManagement.sh Executable file
View File

@@ -0,0 +1,175 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0-only
# -----------------------------------------------------------------------------
# Globals
# -----------------------------------------------------------------------------
declare -r S_OK=0
declare -r E_GENERIC_ERROR=1
declare -r E_INVALID_ARG=3
declare -r E_FEED_NOT_FOUND=4
declare -r E_FEED_ALREADY_EXISTS=5
declare -r CONF_DIR="/tmp/opkgFeedTest"
declare -r DEFAULT_OPKG_FEED_PATH="../opkg-feed"
# -----------------------------------------------------------------------------
# Utility functions
# -----------------------------------------------------------------------------
assertExitCode()
{
local command="$1"
local exitCode="$2"
eval $command --conf-dir $CONF_DIR &>/dev/null
local ret=$?
if [[ "$ret" != "$exitCode" ]] ; then
echo "ERROR: \"$command\" returned $ret instead of $exitCode"
exit 1
fi
}
assertExpectedFeedCount()
{
local expectedFeedCount="$1"
local actualFeedCount=$( "$OPKG_FEED" list --conf-dir "$CONF_DIR" | wc -l )
if [[ "$expectedFeedCount" != "$actualFeedCount" ]] ; then
echo "ERROR: expected $expectedFeedCount feeds but found $actualFeedCount"
exit 1
fi
}
# -----------------------------------------------------------------------------
# Tests
# -----------------------------------------------------------------------------
# Test the script as people would generally use it
happyPathTest()
{
assertExitCode "$OPKG_FEED" $E_INVALID_ARG
assertExitCode "$OPKG_FEED"' help' $S_OK
assertExitCode "$OPKG_FEED"' -h' $S_OK
assertExitCode "$OPKG_FEED"' --help' $S_OK
assertExitCode "$OPKG_FEED"' list' $S_OK
assertExitCode "$OPKG_FEED"' list -h' $S_OK
assertExitCode "$OPKG_FEED"' list --help' $S_OK
assertExitCode "$OPKG_FEED"' list --key-value' $S_OK
assertExitCode "$OPKG_FEED"' add' $E_INVALID_ARG
assertExitCode "$OPKG_FEED"' add feedNameWithoutUri' $E_INVALID_ARG
assertExitCode "$OPKG_FEED"' add feedNameWith\"Double\"Quotes\" --uri https://urldefense.com/v3/__http://somehost.com/somedir__;!fqWJcnlTkjM!9i4Onh9iVJK9m0kcWmZI6WKisWsX5nNe__ZqOSr7If-Hh6WGsOE9HNr9-6dNcgzfoNDzRA$ ' $E_INVALID_ARG
assertExitCode "$OPKG_FEED"' add someFeed --uri https://urldefense.com/v3/__http://some*5C*22host*5C*22.com/somedir__;JSUlJQ!fqWJcnlTkjM!9i4Onh9iVJK9m0kcWmZI6WKisWsX5nNe__ZqOSr7If-Hh6WGsOE9HNr9-6dNcgw4XgAKxQ$ ' $E_INVALID_ARG
assertExitCode "$OPKG_FEED"' add someFeed --uri https://urldefense.com/v3/__http://somehost.com/somedir__;!fqWJcnlTkjM!9i4Onh9iVJK9m0kcWmZI6WKisWsX5nNe__ZqOSr7If-Hh6WGsOE9HNr9-6dNcgzfoNDzRA$ ' $S_OK
assertExitCode "$OPKG_FEED"' add someFeed --uri https://urldefense.com/v3/__http://somehost.com/somedir__;!fqWJcnlTkjM!9i4Onh9iVJK9m0kcWmZI6WKisWsX5nNe__ZqOSr7If-Hh6WGsOE9HNr9-6dNcgzfoNDzRA$ ' $E_FEED_ALREADY_EXISTS
assertExitCode "$OPKG_FEED"' add someFeed --uri https://urldefense.com/v3/__http://someotherhost.com/someotherdir__;!fqWJcnlTkjM!9i4Onh9iVJK9m0kcWmZI6WKisWsX5nNe__ZqOSr7If-Hh6WGsOE9HNr9-6dNcgxMT4RvEg$ --clobber' $S_OK
assertExitCode "$OPKG_FEED"' add someFeed --uri https://urldefense.com/v3/__http://someotherhost.com/someotherdir__;!fqWJcnlTkjM!9i4Onh9iVJK9m0kcWmZI6WKisWsX5nNe__ZqOSr7If-Hh6WGsOE9HNr9-6dNcgxMT4RvEg$ --clobber --name addDoesNotAllowRename' $E_INVALID_ARG
# The addition of --conf-dir <dir> means "--conf-dir" is treated as the feed name
assertExitCode "$OPKG_FEED"' modify' $E_FEED_NOT_FOUND
assertExitCode "$OPKG_FEED"' modify missingFeed' $E_FEED_NOT_FOUND
assertExitCode "$OPKG_FEED"' modify missingFeed --clobber' $E_FEED_NOT_FOUND
assertExitCode "$OPKG_FEED"' modify missingFeed --uri https://urldefense.com/v3/__http://missinghost.com/missingdir__;!fqWJcnlTkjM!9i4Onh9iVJK9m0kcWmZI6WKisWsX5nNe__ZqOSr7If-Hh6WGsOE9HNr9-6dNcgxJuwE9EQ$ ' $E_FEED_NOT_FOUND
assertExitCode "$OPKG_FEED"' modify someFeed' $E_INVALID_ARG
assertExitCode "$OPKG_FEED"' modify someFeed --name feedNameWith\"Double\"Quotes\"' $E_INVALID_ARG
assertExitCode "$OPKG_FEED"' modify someFeed --uri https://urldefense.com/v3/__http://somehost.com/somedir__;!fqWJcnlTkjM!9i4Onh9iVJK9m0kcWmZI6WKisWsX5nNe__ZqOSr7If-Hh6WGsOE9HNr9-6dNcgzfoNDzRA$ ' $S_OK
assertExitCode "$OPKG_FEED"' modify someFeed --enabled sometimes' $E_INVALID_ARG
assertExitCode "$OPKG_FEED"' modify someFeed --enabled 0' $S_OK
assertExitCode "$OPKG_FEED"' modify someFeed --enabled 1' $S_OK
assertExitCode "$OPKG_FEED"' modify someFeed --source-type blah' $E_INVALID_ARG
assertExitCode "$OPKG_FEED"' modify someFeed --source-type src' $S_OK
assertExitCode "$OPKG_FEED"' modify someFeed --source-type src/gz' $S_OK
assertExitCode "$OPKG_FEED"' modify someFeed --source-type dist' $S_OK
assertExitCode "$OPKG_FEED"' modify someFeed --source-type dist/gz' $S_OK
assertExitCode "$OPKG_FEED"' modify someFeed --trusted maybe' $E_INVALID_ARG
assertExitCode "$OPKG_FEED"' modify someFeed --trusted 1' $S_OK
assertExitCode "$OPKG_FEED"' modify someFeed --trusted 0' $S_OK
assertExitCode "$OPKG_FEED"' modify someFeed --name someFeed' $S_OK
assertExitCode "$OPKG_FEED"' modify someFeed --name anotherFeed' $S_OK
assertExitCode "$OPKG_FEED"' modify someFeed --uri https://urldefense.com/v3/__http://anotherhost.com/anotherdir__;!fqWJcnlTkjM!9i4Onh9iVJK9m0kcWmZI6WKisWsX5nNe__ZqOSr7If-Hh6WGsOE9HNr9-6dNcgzL7t9Bhw$ ' $E_FEED_NOT_FOUND
assertExitCode "$OPKG_FEED"' add someFeed --uri https://urldefense.com/v3/__http://somehost.com/somedir__;!fqWJcnlTkjM!9i4Onh9iVJK9m0kcWmZI6WKisWsX5nNe__ZqOSr7If-Hh6WGsOE9HNr9-6dNcgzfoNDzRA$ ' $S_OK
assertExitCode "$OPKG_FEED"' modify someFeed --name anotherFeed --enabled 0 --trusted 1' $E_FEED_ALREADY_EXISTS
assertExitCode "$OPKG_FEED"' modify someFeed --name anotherFeed --enabled 0 --trusted 1 --clobber' $S_OK
# The addition of --conf-dir <dir> means "--conf-dir" is treated as the feed name
assertExitCode "$OPKG_FEED"' remove' $E_FEED_NOT_FOUND
assertExitCode "$OPKG_FEED"' remove feedNameWith\"Double\"Quotes\"' $E_INVALID_ARG
assertExitCode "$OPKG_FEED"' remove someFeed' $E_FEED_NOT_FOUND
assertExitCode "$OPKG_FEED"' remove missingFeed' $E_FEED_NOT_FOUND
assertExitCode "$OPKG_FEED"' remove anotherFeed' $S_OK
}
# Test regex metacharacters and shell escaping
dirtyTest()
{
# Disable history expansion
set +H
local initialFeedCount=$( "$OPKG_FEED" list --conf-dir "$CONF_DIR" | wc -l )
local withAdditionalFeedCount
(( withAdditionalFeedCount = initialFeedCount + 1 ))
# Use the same string for both the name and URI for coverage
local testFeedNamesAndUris=( \
'test' \
'testtest' \
'test \n ][][ ' \
'test \n\s ][][ $' \
'test test \n ][][ ' \
'test test \n ]\[\s][ %$^#$' \
"#^?#\$%()%\\(@\`#\$')file:///what(!_%%5C$#'(~%7B%7D%7D:%5C$'%5C$%5C$%5C$" \
)
for string in "${testFeedNamesAndUris[@]}" ; do
"$OPKG_FEED" add "$string" --uri "$string" --conf-dir "$CONF_DIR" &> /dev/null
local ret=$?
if [[ "$ret" != '0' ]] ; then
echo "ERROR: add \"$string\" failed with $ret"
exit $ret
fi
assertExpectedFeedCount "$withAdditionalFeedCount"
"$OPKG_FEED" modify "$string" --name "$string asdf" --enabled 0 --conf-dir "$CONF_DIR" &> /dev/null
ret=$?
if [[ "$ret" != '0' ]] ; then
echo "ERROR: modify \"$string\" failed with $ret"
exit $ret
fi
assertExpectedFeedCount "$withAdditionalFeedCount"
"$OPKG_FEED" remove "$string asdf" --conf-dir "$CONF_DIR" &> /dev/null
ret=$?
if [[ "$ret" != '0' ]] ; then
echo "ERROR: remove \"$string\" failed with $ret"
exit $ret
fi
assertExpectedFeedCount "$initialFeedCount"
done
set -H
}
# -----------------------------------------------------------------------------
# main()
# -----------------------------------------------------------------------------
mkdir -p "$CONF_DIR"
export OPKG_FEED=${OPKG_FEED_PATH:-${DEFAULT_OPKG_FEED_PATH}}
echo "Testing opkg-feed script '$OPKG_FEED'"
happyPathTest
dirtyTest
if ! rmdir "$CONF_DIR" ; then
exit 1
fi
echo "OK!"
exit 0