aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bpkg-rep/buildfile10
-rw-r--r--bpkg-rep/package-archive.bash.in167
-rw-r--r--build/export.build3
-rw-r--r--manifest1
-rw-r--r--repositories.manifest4
-rw-r--r--tests/.gitignore1
-rw-r--r--tests/build/root.build6
-rw-r--r--tests/buildfile4
-rw-r--r--tests/package-archive/buildfile8
-rw-r--r--tests/package-archive/driver.in20
-rw-r--r--tests/package-archive/libhello-0.1.0+1.tar.gzbin0 -> 3045 bytes
-rw-r--r--tests/package-archive/libhello-0.1.0.tar.gzbin0 -> 3033 bytes
-rw-r--r--tests/package-archive/testscript127
-rw-r--r--tests/publish/buildfile8
-rw-r--r--tests/publish/testscript (renamed from tests/publish.testscript)2
15 files changed, 353 insertions, 8 deletions
diff --git a/bpkg-rep/buildfile b/bpkg-rep/buildfile
index 6f84fd1..9177409 100644
--- a/bpkg-rep/buildfile
+++ b/bpkg-rep/buildfile
@@ -1,8 +1,16 @@
# file : bpkg-rep/buildfile
# license : MIT; see accompanying LICENSE file
-./: exe{bpkg-rep-publish}
+import mods = libbutl.bash%bash{manifest-parser}
+
+./: exe{bpkg-rep-publish} bash{package-archive}
exe{bpkg-rep-publish}: in{publish} bash{utility}
+# Public modules.
+#
+bash{package-archive}: in{package-archive} $mods
+
+# Private modules.
+#
bash{utility}: in{utility}
diff --git a/bpkg-rep/package-archive.bash.in b/bpkg-rep/package-archive.bash.in
new file mode 100644
index 0000000..3669a1b
--- /dev/null
+++ b/bpkg-rep/package-archive.bash.in
@@ -0,0 +1,167 @@
+# file : bpkg-rep/package-archive.bash.in
+# license : MIT; see accompanying LICENSE file
+
+# Utility functions useful for managing package archives.
+
+if [ "$bpkg_rep_package_archive" ]; then
+ return 0
+else
+ bpkg_rep_package_archive=true
+fi
+
+@import libbutl/manifest-parser@
+
+# We expect the user to set the bpkg_rep_bpkg variable to the bpkg program
+# path.
+#
+if [ ! -v bpkg_rep_bpkg ]; then
+ echo "error: variable bpkg_rep_bpkg is not set" >&2
+ exit 1
+fi
+
+# Extract the package information from a package archive and print it in the
+# '<name> <version> <project>' form, where the project field is empty if the
+# project value is not specified in the manifest.
+#
+function bpkg_rep_pkg_verify_archive () # <path>
+{
+ # We can't use the process substitution for input redirect here, since such
+ # a process failure is not trapped. Thus, read the manifest file into a
+ # variable and parse it afterwards, which is probably ok since package
+ # manifests are normally not too big.
+ #
+ # Note that alternatively we could use the process substitution for running
+ # bpkg, treat the name value absence as indication of a failure, and exit
+ # with non-zero status if that's the case. Feels a bit hackish though.
+ #
+ local m
+ m="$("$bpkg_rep_bpkg" pkg-verify --manifest "$1")"
+
+ butl_manifest_parser_start <<<"$m"
+
+ local name=
+ local version=
+ local project=
+
+ local n v
+ while IFS=: read -ru "$butl_manifest_parser_ofd" -d '' n v; do
+ case "$n" in
+ name) name="$v" ;;
+ version) version="$v" ;;
+ project) project="$v" ;;
+ esac
+ done
+
+ butl_manifest_parser_finish
+
+ echo -n "$name $version $project"
+}
+
+# Search for package archives in a directory using the package name and
+# version pattern and printing their paths newline-separated. If the version
+# argument is '*', then print archives for all package versions. Otherwise if
+# the version contains the trailing '*', then print archives for all revisions
+# of the specified version and for the exact version otherwise. For example:
+#
+# bpkg_rep_pkg_find_archives foo '*' dir/
+# bpkg_rep_pkg_find_archives foo '1.0*' dir/
+# bpkg_rep_pkg_find_archives foo '1.0' dir/
+#
+# Note that the resulting archive paths include the specified directory as a
+# prefix.
+#
+# NOTE: this function can be called with overriden IFS.
+#
+function bpkg_rep_pkg_find_archives () # <name> <version> <dir>
+{
+ IFS=$' \t\n' bpkg_rep_pkg_find_archives_impl "$@"
+}
+
+function bpkg_rep_pkg_find_archives_impl ()
+{
+ local nam="$1"
+ local ver="$2"
+ local dir="$3"
+
+ local r=""
+
+ if [ -d "$dir" ]; then
+ local vr # Version with the revision stripped, if search for revisions.
+ local np # File name pattern for archives search.
+
+ if [ "$ver" != "*" -a "${ver: -1}" == "*" ]; then # <version>*
+ vr="$(sed -n -re 's%^(\+?[^+]+)(\+[0-9]+)?\*$%\1%p' <<<"$ver")"
+ np="$nam-$vr*.*" # foo-1.0*.*, etc.
+ else # * or <version>
+ np="$nam-$ver.*" # foo-*.*, foo-1.0.*, etc.
+ fi
+
+ # Go through the potentially matching archives (for example, for 'foo'
+ # '1.2.3+2*': foo-1.2.3.tar.gz, foo-1.2.3+1.tar.gz, foo-1.2.30.tar.gz,
+ # etc) and return those which package name and version match properly.
+ #
+ local f
+ while read f; do
+ local p
+ p=($(bpkg_rep_pkg_verify_archive "$f"))
+
+ local n="${p[0]}"
+ local v="${p[1]}"
+
+ if [[ "$n" == "$nam" &&
+ ( "$ver" == "*" || \
+ "$v" == "$ver" || \
+ ( -n "$vr" && "$v" =~ ^"$vr"(\+[0-9]+)?$ )) ]]; then
+
+ if [ -n "$r" ]; then
+ r="$r"$'\n'"$f"
+ else
+ r="$f"
+ fi
+ fi
+ done < <(find "$dir" -type f -name "$np")
+ fi
+
+ if [ -n "$r" ]; then
+ echo -n "$r"
+ fi
+}
+
+# Search for a package archive in a directory using a file name pattern. If
+# the archive is found, then print the package information in the
+# '<name>\n<version>\n<project>\n<path>' form, where the project field is
+# empty if the project value is not specified in the manifest.
+#
+# Note that if there are multiple archives matching the pattern, then it is
+# unspecified which one is picked.
+#
+# NOTE: this function can be called with overriden IFS.
+#
+function bpkg_rep_pkg_find_archive () # <pattern> <dir>
+{
+ IFS=$' \t\n' bpkg_rep_pkg_find_archive_impl "$@"
+}
+
+function bpkg_rep_pkg_find_archive_impl ()
+{
+ local pat="$1"
+ local dir="$2"
+
+ if [ -d "$dir" ]; then
+ local f
+
+ # We could probably use -print -quit but this is not portable (NetBSD
+ # needs -exit instead of -quit).
+ #
+ f="$(find "$dir" -type f -name "$pat" | head -n 1)"
+
+ if [ -n "$f" ]; then
+
+ local p
+ p=($(bpkg_rep_pkg_verify_archive "$f"))
+
+ printf "${p[0]}\n${p[1]}\n${p[2]}\n$f"
+ return
+ fi
+ fi
+}
diff --git a/build/export.build b/build/export.build
index 6c09e3e..1ac1b48 100644
--- a/build/export.build
+++ b/build/export.build
@@ -9,5 +9,6 @@ $out_root/
switch $import.target
{
case exe{bpkg-rep-publish}
- export $out_root/bpkg-rep/exe{bpkg-rep-publish}
+ case bash{package-archive}
+ export $out_root/bpkg-rep/$import.target
}
diff --git a/manifest b/manifest
index f06deed..496e8bf 100644
--- a/manifest
+++ b/manifest
@@ -19,3 +19,4 @@ requires: bash >= 4.3
depends: * build2 >= 0.13.0
depends: * bpkg >= 0.13.0
depends: bpkg [0.14.0-a.0.1 0.14.0-a.1)
+depends: libbutl.bash [0.14.0-a.0.1 0.14.0-a.1)
diff --git a/repositories.manifest b/repositories.manifest
index b78709d..6fc6dd2 100644
--- a/repositories.manifest
+++ b/repositories.manifest
@@ -4,3 +4,7 @@ summary: bpkg repository management utilities repository
:
role: prerequisite
location: ../bpkg.git##HEAD
+
+:
+role: prerequisite
+location: ../libbutl.bash.git##HEAD
diff --git a/tests/.gitignore b/tests/.gitignore
index 35ec43f..2e508a9 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -1,2 +1,3 @@
+driver
test/
test-*/
diff --git a/tests/build/root.build b/tests/build/root.build
index 1472384..c3d4252 100644
--- a/tests/build/root.build
+++ b/tests/build/root.build
@@ -1,6 +1,8 @@
# file : tests/build/root.build
# license : MIT; see accompanying LICENSE file
-# Setup the utilities that we are testing.
+using bash
+
+# Every exe{} in this subproject is by default a test.
#
-import publish = bpkg-rep%exe{bpkg-rep-publish}
+exe{*}: test = true
diff --git a/tests/buildfile b/tests/buildfile
index 0beb40f..556ed55 100644
--- a/tests/buildfile
+++ b/tests/buildfile
@@ -1,6 +1,4 @@
# file : tests/buildfile
# license : MIT; see accompanying LICENSE file
-./: testscript{*} $publish
-
-testscript{publish}@./: test = $publish
+./: {*/ -build/}
diff --git a/tests/package-archive/buildfile b/tests/package-archive/buildfile
new file mode 100644
index 0000000..a8ff42b
--- /dev/null
+++ b/tests/package-archive/buildfile
@@ -0,0 +1,8 @@
+# file : tests/package-archive/buildfile
+# license : MIT; see accompanying LICENSE file
+
+import mods = bpkg-rep%bash{package-archive}
+
+./: exe{driver} file{*.tar.gz}
+
+exe{driver}: in{driver} $mods testscript
diff --git a/tests/package-archive/driver.in b/tests/package-archive/driver.in
new file mode 100644
index 0000000..d760a1e
--- /dev/null
+++ b/tests/package-archive/driver.in
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+
+# file : tests/package-archive/driver.in
+# license : MIT; see accompanying LICENSE file
+
+# bpkg utility path.
+#
+bpkg_rep_bpkg=bpkg
+
+trap "{ exit 1; }" ERR
+set -o errtrace # Trap ERR in functions.
+
+@import bpkg-rep/package-archive@
+
+# Call the function passed on the command line.
+#
+# Note that we reset IFS to make sure that the function being tested is not
+# affected by its value set by the caller.
+#
+IFS= "$@"
diff --git a/tests/package-archive/libhello-0.1.0+1.tar.gz b/tests/package-archive/libhello-0.1.0+1.tar.gz
new file mode 100644
index 0000000..8d6bde9
--- /dev/null
+++ b/tests/package-archive/libhello-0.1.0+1.tar.gz
Binary files differ
diff --git a/tests/package-archive/libhello-0.1.0.tar.gz b/tests/package-archive/libhello-0.1.0.tar.gz
new file mode 100644
index 0000000..604a536
--- /dev/null
+++ b/tests/package-archive/libhello-0.1.0.tar.gz
Binary files differ
diff --git a/tests/package-archive/testscript b/tests/package-archive/testscript
new file mode 100644
index 0000000..6124d4a
--- /dev/null
+++ b/tests/package-archive/testscript
@@ -0,0 +1,127 @@
+# file : tests/package-archive/testscript
+# license : MIT; see accompanying LICENSE file
+
+# Note that searching for packages directly in $src_base is a bad idea, since
+# removing testscript working directories while testing in source makes the
+# find utility to fail with the 'no such file or directory' error. Thus, we
+# clone the archives into the test working directories and search there.
+#
+clone_arcs = \
+ cp $src_base/libhello-0.1.0.tar.gz $src_base/libhello-0.1.0+1.tar.gz ./
+
+: pkg-verify-archive
+:
+{
+ test.arguments += bpkg_rep_pkg_verify_archive
+
+ : non-existing-archive
+ :
+ $* libhello-0.1.0.tar.gz 2>>EOE != 0
+ error: archive file 'libhello-0.1.0.tar.gz' does not exist
+ EOE
+
+ : success
+ :
+ $* $src_base/libhello-0.1.0.tar.gz >:'libhello 0.1.0 hello'
+}
+
+: pkg-find-archives
+:
+{
+ test.arguments += bpkg_rep_pkg_find_archives
+
+ : none
+ :
+ {
+ $clone_arcs;
+
+ $* 'libhello' '0.2.0' $~
+ }
+
+ : package
+ :
+ {
+ $clone_arcs;
+
+ $* 'libhello' '*' $~ >>:/~"%EOO%"
+ %\(
+ $~/libhello-0.1.0.tar.gz
+ $~/libhello-0.1.0+1.tar.gz
+ %|
+ $~/libhello-0.1.0+1.tar.gz
+ $~/libhello-0.1.0.tar.gz
+ %\)
+ EOO
+ }
+
+ : package-version
+ :
+ {
+ $clone_arcs;
+
+ $* 'libhello' '0.1.0' $~ >:/"$~/libhello-0.1.0.tar.gz"
+ }
+
+ : package-revision
+ :
+ {
+ $clone_arcs;
+
+ $* 'libhello' '0.1.0+1' $~ >:/"$~/libhello-0.1.0+1.tar.gz"
+ }
+
+ : package-revisions1
+ :
+ {
+ $clone_arcs;
+
+ $* 'libhello' '0.1.0*' $~ >>:/~"%EOO%"
+ %\(
+ $~/libhello-0.1.0.tar.gz
+ $~/libhello-0.1.0+1.tar.gz
+ %|
+ $~/libhello-0.1.0+1.tar.gz
+ $~/libhello-0.1.0.tar.gz
+ %\)
+ EOO
+ }
+
+ : package-revisions2
+ :
+ {
+ $clone_arcs;
+
+ $* 'libhello' '0.1.0+2*' $~ >>:/~"%EOO%"
+ %\(
+ $~/libhello-0.1.0.tar.gz
+ $~/libhello-0.1.0+1.tar.gz
+ %|
+ $~/libhello-0.1.0+1.tar.gz
+ $~/libhello-0.1.0.tar.gz
+ %\)
+ EOO
+ }
+}
+
+: pkg-find-archive
+:
+{
+ test.arguments += bpkg_rep_pkg_find_archive
+
+ : non-existent
+ :
+ $* 'libhello-0.1.0.*' $~
+
+ : existing
+ :
+ {
+ $clone_arcs;
+
+ $* 'libhello-0.1.0.*' $~ >>:/"EOO"
+ libhello
+ 0.1.0
+ hello
+ $~/libhello-0.1.0.tar.gz
+ EOO
+ }
+}
diff --git a/tests/publish/buildfile b/tests/publish/buildfile
new file mode 100644
index 0000000..4cc1bd0
--- /dev/null
+++ b/tests/publish/buildfile
@@ -0,0 +1,8 @@
+# file : tests/publish/buildfile
+# license : MIT; see accompanying LICENSE file
+
+import publish = bpkg-rep%exe{bpkg-rep-publish}
+
+./: testscript $publish
+
+testscript@./: test = $publish
diff --git a/tests/publish.testscript b/tests/publish/testscript
index f11a171..2d3fb4c 100644
--- a/tests/publish.testscript
+++ b/tests/publish/testscript
@@ -1,4 +1,4 @@
-# file : tests/publish.testscript
+# file : tests/publish/testscript
# license : MIT; see accompanying LICENSE file
: args