aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2018-07-24 00:16:49 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2018-07-27 14:33:01 +0300
commitdfa77ad7a2b7bbbd5ca836bbea4050dc524ff220 (patch)
treed9e7e5d72b7acfcebae358a1e215cb3c5171e63e
parent7407647bf6c73c1b128749ed788d53b5f174b4be (diff)
Add brep-submit script
-rw-r--r--INSTALL3
-rw-r--r--brep/submit/.gitignore1
-rw-r--r--brep/submit/buildfile8
-rw-r--r--brep/submit/submit.in176
-rw-r--r--build/root.build2
-rw-r--r--manifest1
-rw-r--r--mod/mod-submit.cxx28
-rw-r--r--mod/options.cli17
-rw-r--r--repositories.manifest4
9 files changed, 229 insertions, 11 deletions
diff --git a/INSTALL b/INSTALL
index 4bfb9cd..b978c7d 100644
--- a/INSTALL
+++ b/INSTALL
@@ -240,6 +240,9 @@ example:
$ cp install/share/brep/www/submit.xhtml config/
$ edit config/submit.xhtml # Add custom form fields, adjust CSS style, etc.
+For an example of the submission handler see the brep/submit/submit.in bash
+script.
+
Here we assume you have setup an appropriate Apache2 virtual server. Open the
corresponding Apache2 .conf file and add the following inside VirtualHost (you
can also find this fragment in install/share/brep/etc/brep-apache2.conf):
diff --git a/brep/submit/.gitignore b/brep/submit/.gitignore
new file mode 100644
index 0000000..b49e361
--- /dev/null
+++ b/brep/submit/.gitignore
@@ -0,0 +1 @@
+brep-submit
diff --git a/brep/submit/buildfile b/brep/submit/buildfile
new file mode 100644
index 0000000..48cf676
--- /dev/null
+++ b/brep/submit/buildfile
@@ -0,0 +1,8 @@
+# file : brep/submit/buildfile
+# copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
+# license : MIT; see accompanying LICENSE file
+
+import mods = libbutl.bash%bash{manifest-parser}
+import mods += libbutl.bash%bash{manifest-serializer}
+
+exe{brep-submit}: in{submit} $mods
diff --git a/brep/submit/submit.in b/brep/submit/submit.in
new file mode 100644
index 0000000..fcc6a3f
--- /dev/null
+++ b/brep/submit/submit.in
@@ -0,0 +1,176 @@
+#!/usr/bin/env bash
+
+# file : brep/submit/submit.in
+# copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
+# license : MIT; see accompanying LICENSE file
+
+# Package submission handler example.
+#
+# Validate the package archive located in the specified submission directory
+# extracting and parsing the package manifest. Remove the submission directory
+# if simulating. Write the submission result manifest to stdout.
+#
+usage="usage: $0 <dir>"
+
+trap "{ exit 1; }" ERR
+set -o errtrace # Trap ERR in functions.
+
+@import libbutl/manifest-parser@
+@import libbutl/manifest-serializer@
+
+# Diagnostics.
+#
+self="$(basename $0)"
+verbose= # true
+
+# Result reference (assigned later).
+#
+reference=
+
+# Normally the brep module's log record looks like this:
+#
+# [Mon Jul 23 17:48:46.945079 2018] [brep:error] [pid 123:tid 456] [brep::submit::init]: error description
+#
+# We will use the (almost) same format for our diagnostics (redirected to the
+# Apache's error_log) so it can easily be attributed to the brep module.
+#
+function info () # <severity> <text>
+{
+ local severity="$1"
+ shift
+
+ # Note: %N is Linux-specific.
+ #
+ local ts
+ if ! ts="$(date +"%a %b %d %H:%M:%S.%6N %Y")"; then
+ ts=
+ fi
+
+ echo "[$ts] [brep:$severity] [ref $reference] [$self]: $*" 1>&2;
+}
+
+function error () { info "error" "$*"; exit 1; }
+function trace () { if [ "$verbose" ]; then info "info" "$*"; fi }
+
+dir="${1%/}"
+
+if [ -z "$dir" ]; then
+ error "$usage"
+fi
+
+if [ ! -d "$dir" ]; then
+ fail "'$dir' does not exist or is not a directory"
+fi
+
+reference="$(basename $dir)"
+
+# Parse the submission request manifest and obtain the archive path as well
+# as the simulate value.
+#
+trace "parsing $dir/request.manifest"
+butl_manifest_parser_start "$dir/request.manifest"
+
+archive=
+simulate=
+
+while IFS=: read -ru "$butl_manifest_parser_ofd" -d '' n v; do
+ case "$n" in
+ archive) archive="$v" ;;
+ simulate) simulate="$v" ;;
+ esac
+done
+
+butl_manifest_parser_finish
+
+if [ -z "$archive" ]; then
+ error "archive manifest value expected"
+fi
+
+# Serialize one manifest name/value pair.
+#
+function serialize () # <name> <value>
+{
+ printf "%s:%s\0" "$1" "$2" >&"$butl_manifest_serializer_ifd"
+}
+
+# Serialize the submission result manifest to stdout.
+#
+function result_manifest () # <status> <message> [<reference>]
+{
+ local sts="$1"
+ local msg="$2"
+ local ref="$3"
+
+ trace "serializing result manifest"
+ butl_manifest_serializer_start
+
+ serialize "" "1" # Start of manifest.
+ serialize "status" "$sts"
+ serialize "message" "$msg"
+
+ if [ -n "$ref" ]; then
+ serialize "reference" "$ref"
+ fi
+
+ butl_manifest_serializer_finish
+}
+
+if [ -n "$simulate" -a "$simulate" != "success" ]; then
+ trace "invalid simulate manifest value '$simulate'"
+ result_manifest 400 "invalid simulate manifest value"
+ exit 0
+fi
+
+# Verify the archive is a valid bpkg package and extract its manifest file.
+#
+# Should we remove the submission directory with an invalid package? Probably
+# it's better to leave it for potential investigation. Note that we can always
+# grep for such directories based on the result.manifest file they contain.
+#
+manifest="$dir/package.manifest"
+
+if ! bpkg pkg-verify --manifest "$dir/$archive" >"$manifest" 2>/dev/null; then
+ trace "$dir/$archive is not a valid package"
+ result_manifest 400 "archive is not a valid package (run bpkg pkg-verify for details)"
+ exit 0
+fi
+
+# Parse the package manifest and obtain the package name and version.
+#
+trace "parsing $manifest"
+butl_manifest_parser_start "$manifest"
+
+name=
+version=
+project=
+
+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
+
+if [ -z "$name" ]; then
+ error "name manifest values expected"
+fi
+
+if [ -z "$version" ]; then
+ error "version manifest values expected"
+fi
+
+if [ -z "$project" ]; then
+ project="$name"
+fi
+
+if [ -n "$simulate" ]; then
+ rm -r "$dir"
+ trace "$name/$version submission is simulated"
+else
+ trace "$name/$version submission is queued"
+fi
+
+result_manifest 200 "$name/$version submission is queued" "$reference"
diff --git a/build/root.build b/build/root.build
index 6019a22..63e4c69 100644
--- a/build/root.build
+++ b/build/root.build
@@ -25,6 +25,8 @@ cxx.coptions += -Wno-unknown-pragmas
#
using? cli
+using bash
+
# All exe{} in tests/ are, well, tests. Also don't link whole archives
# by default there.
#
diff --git a/manifest b/manifest
index f98e235..861f53d 100644
--- a/manifest
+++ b/manifest
@@ -30,3 +30,4 @@ depends: libodb-pgsql [2.5.0-b.8.1 2.5.0-b.9)
depends: libbutl [0.8.0-a.0.1 0.8.0-a.1)
depends: libbpkg [0.8.0-a.0.1 0.8.0-a.1)
depends: libbbot [0.8.0-a.0.1 0.8.0-a.1)
+depends: libbutl.bash [0.8.0-a.0.1 0.8.0-a.1)
diff --git a/mod/mod-submit.cxx b/mod/mod-submit.cxx
index 6dbb4ec..5bc00a1 100644
--- a/mod/mod-submit.cxx
+++ b/mod/mod-submit.cxx
@@ -139,7 +139,7 @@ handle (request& rq, response& rs)
serializer s (rs.content (status, "text/manifest;charset=utf-8"),
"response");
- s.next ("", "1"); // Start of manifest.
+ s.next ("", "1"); // Start of manifest.
s.next ("status", to_string (status));
s.next ("message", message);
@@ -152,8 +152,9 @@ handle (request& rq, response& rs)
auto respond_error = [&rs] (status_code status = 500) -> bool
{
- rs.content (status, "text/plain;charset=utf-8") << "unable to handle "
- << "submission" << endl;
+ rs.content (status, "text/plain;charset=utf-8")
+ << "submission handling failed" << endl;
+
return true;
};
@@ -226,6 +227,23 @@ handle (request& rq, response& rs)
return respond_manifest (400, "invalid parameter");
}
+ const string& simulate (params.simulate ());
+
+ if (simulate == "internal-error-text")
+ return respond_error ();
+ else if (simulate == "internal-error-html")
+ {
+ const string title ("Internal Error");
+ xml::serializer s (rs.content (500), title);
+
+ s << HTML
+ << HEAD << TITLE << title << ~TITLE << ~HEAD
+ << BODY << "submission handling failed" << ~BODY
+ << ~HTML;
+
+ return true;
+ }
+
const string& archive (params.archive ());
const string& sha256sum (params.sha256sum ());
@@ -266,7 +284,7 @@ handle (request& rq, response& rs)
string ac (sha256sum, 0, 12);
dir_path dd (options_->submit_data () / dir_path (ac));
- if (dir_exists (dd))
+ if (dir_exists (dd) || simulate == "duplicate-archive")
return respond_manifest (409, "duplicate submission");
// Create the temporary submission directory.
@@ -662,7 +680,7 @@ handle (request& rq, response& rs)
// web server error log is monitored and the email sending failure will be
// noticed.
//
- if (options_->submit_email_specified () && !params.simulate ())
+ if (options_->submit_email_specified () && simulate.empty ())
try
{
// Redirect the diagnostics to the web server error log.
diff --git a/mod/options.cli b/mod/options.cli
index 66f19b1..f939b52 100644
--- a/mod/options.cli
+++ b/mod/options.cli
@@ -643,14 +643,19 @@ namespace brep
//
string sha256sum;
- // Simulate submission. Tells the submission handler not to publish the
- // package but to respond as if it does.
+ // Submission simulation. The presence of this parameter instructs the
+ // submission service to simulate various outcomes of the submission
+ // process without actually performing any externally visible actions
+ // (e.g., publishing the package, notifying the submitter, etc).
//
- // Note that the package submission email (see submit-email
- // configuration option for details) is not sent for the simulated
- // submission.
+ // Pre-defined simulation outcome values are 'internal-error-text',
+ // 'internal-error-html', 'duplicate-archive', and 'success'. The
+ // handler program may recognize additional outcomes.
//
- bool simulate;
+ // Note that the package submission email (see submit-email for details)
+ // is not sent for the simulated submissions.
+ //
+ string simulate;
};
}
}
diff --git a/repositories.manifest b/repositories.manifest
index a066920..300bd3c 100644
--- a/repositories.manifest
+++ b/repositories.manifest
@@ -15,6 +15,10 @@ location: ../libbbot.git##HEAD
:
role: prerequisite
+location: ../libbutl.bash.git##HEAD
+
+:
+role: prerequisite
location: https://git.build2.org/packaging/libapr/libapr1.git##HEAD
: