commit 78d1971703286fbc4e52271353375e49f7cec80f Author: yafox Date: Wed Nov 25 05:55:49 2020 +0000 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6fe33ed --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +pkg/** diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..bd8c239 --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright 2020 "yafox" + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README b/README new file mode 100644 index 0000000..2db919d --- /dev/null +++ b/README @@ -0,0 +1,53 @@ +# versions + +58 SLOC. + +`versions` checks a url, applies a couple regular expressions, sorts the results +using `vercmp` and `shsort`, and returns a sorted list of version numbers for +any package it knows about. + +written for lix-os maintainers to check for new versions of packages. depending +on how the package's versions are presented, it may only return a few of the +most recent version numbers for the package, or it may return the entire version +history. + +because parsing and sorting versions using POSIX-compliant shell script can be a +_very_ slow operation, it caches the results of previous sorting operations and +only recomputes the sorted version list if it appears the list of versions at +the package url has changed. + +all package configuration and cache files are kept in subdirectories of the +`pkg` directory. + +each package's `url` file is tab-delimited. it is formatted as follows: + +`
		`
+
+- `` is a url which contains a list of versions.
+
+- `
` is the pattern up to which the content at `url` will be
+	discarded before beginning to look for matches for `version regex`.
+
+- `` is the pattern after which the content at `url` will be
+    discarded before beginning to look for matches for `version regex`.
+
+- `` is a pattern containing a subgroup matching the version
+   strings `versions` should return.  there are some default version regexes
+   defined in versions.sh.  any of these can be referenced in the package's
+   file as a shell variable.
+
+
+## dependencies
+
+vercmp and shsort.
+
+
+## usage
+
+`./versions.sh  [timeout]`
+
+`` is a package name corresponding to a subdirectory in `pkg`.
+
+`[timeout]` is the number of seconds curl will spend trying to get each url
+listed in the package's `urls` list file before moving on to the next line.  if
+all urls time out, `versions` fails with an error message.
diff --git a/lib/log.sh b/lib/log.sh
new file mode 100644
index 0000000..5f3800c
--- /dev/null
+++ b/lib/log.sh
@@ -0,0 +1,16 @@
+# if _colors is not already set, if this is running on an interactive
+# terminal (as opposed to in a script), if tput is installed, and if tput
+# knows some color codes, then set _colors to 'yes'.
+{  [ -z "$_colors" ] \
+&& [ -t 1 ] \
+&& [ "$(tput colors 2>/dev/null)" -ge 8 ] \
+&& _colors="yes"; } || true # suppress error codes
+
+_clr="$({ [ "$_colors" = 'yes' ] && tput sgr0; } || echo '')"
+_blu="$({ [ "$_colors" = 'yes' ] && tput setaf 6; } || echo '')"
+_ylw="$({ [ "$_colors" = 'yes' ] && tput setaf 3; } || echo '')"
+_red="$({ [ "$_colors" = 'yes' ] && tput setaf 1; } || echo '')"
+
+log() { echo "$_blu[LOG]$_clr $@"; }
+wrn() { echo "$_ylw[WRN]$_clr $@" >&2; }
+err() { echo "$_red[ERR]$_clr $@" >&2; exit 1; }
diff --git a/sloc.sh b/sloc.sh
new file mode 100755
index 0000000..1ea7b20
--- /dev/null
+++ b/sloc.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+# find all *.sh files not under `pkg` that are not symbolic links, strip all
+# trailing whitespace, then all leading whitespace, then all lines starting
+# with '#', then all empty lines. then count the remaining lines.
+
+find . -name "*.sh" ! -path "**/pkg/**" ! -type l \
+| xargs sed 's/[[:space:]]*$//g; s/^[[:space:]]*//g; s/^#.*$//g; /^$/d' \
+| wc -l - \
+| cut -d' ' -f1
+
+# note that this script's ELOC is also included in the count.
diff --git a/versions.sh b/versions.sh
new file mode 100755
index 0000000..33fa208
--- /dev/null
+++ b/versions.sh
@@ -0,0 +1,64 @@
+#!/bin/sh -e
+
+VERSIONSROOT="$(dirname "$(readlink -f "$0")")"
+which vercmp >/dev/null || { echo "vercmp not found!" >&2 && exit 1; }
+
+[ -n "$1" ] \
+|| { echo "usage: $(basename $0) [-c|-r]  [timeout]" && exit 0; }
+
+. "$VERSIONSROOT/lib/log.sh"
+
+[ "$1" != "-c" ] || { shift; cached="yes"; }
+[ "$1" != "-r" ] || { shift; reparse="yes"; }
+
+[ -d "$VERSIONSROOT/pkg/$1" ] || err "unrecognized package: $1"
+[ -f "$VERSIONSROOT/pkg/$1/url" ] || err "no 'url' file for $1"
+
+name="$1"
+timeout=${2:-5}
+
+{ vercmp formats | grep -q "^$name\$"; } \
+&& fmt="$name" \
+|| fmt="default"
+
+cleanup() { [ -f "$temp" ] && rm "$temp"; }
+trap cleanup EXIT
+
+temp="$(mktemp)"
+
+while read -r line; do
+    url="$(echo "$line" | cut -f1)"
+    pre="$(echo "$line" | cut -f2)"
+    pst="$(echo "$line" | cut -f3)"
+    rex="$(echo "$line" | cut -f4)"
+
+    if [ "$cached" ]; then
+        cache="$(ls -ct $VERSIONSROOT/pkg/$name/*.cache | head -n1)"
+        [ -f "$cache" ] || { echo "[ERR] no cache for $name!" >&2 && exit 1; }
+
+        cat "$cache"
+        exit 0
+    fi
+
+    # extract the text between the pre and post regexes on the target webpage.
+    { curl --compressed -m $timeout -L -s $url || { echo "url failed" >&2 && continue; }; } \
+    | awk "sub(/^.*$pre/,\"\"){echo=1} /$pst/{echo=0} echo" \
+    > $temp
+
+    cache="$VERSIONSROOT/pkg/$name/$(md5sum $temp | awk '{print $1}').cache"
+
+    if [ ! -f "$cache" ] || [ "$reparse" ]; then
+        oldcaches="$(ls $VERSIONSROOT/pkg/$name/*.cache 2>/dev/null || true)"
+        [ ! "$oldcaches" ] || rm "$oldcaches"
+        perl -n -e "/$rex/ && print \"\$1\\n\"" $temp > "$cache.unsorted"
+
+        cat "$cache.unsorted" | shsort -r "vercmp -f $fmt" > "$cache"
+        rm "$cache.unsorted"
+    fi
+
+    cat "$cache"
+    exit 0
+
+done < "$VERSIONSROOT/pkg/$name/url"
+
+err "unable to fetch versions for $1"