From dfa77ad7a2b7bbbd5ca836bbea4050dc524ff220 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Tue, 24 Jul 2018 00:16:49 +0300 Subject: Add brep-submit script --- INSTALL | 3 + brep/submit/.gitignore | 1 + brep/submit/buildfile | 8 +++ brep/submit/submit.in | 176 +++++++++++++++++++++++++++++++++++++++++++++++++ build/root.build | 2 + manifest | 1 + mod/mod-submit.cxx | 28 ++++++-- mod/options.cli | 17 +++-- repositories.manifest | 4 ++ 9 files changed, 229 insertions(+), 11 deletions(-) create mode 100644 brep/submit/.gitignore create mode 100644 brep/submit/buildfile create mode 100644 brep/submit/submit.in 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 " + +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 () # +{ + 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 () # +{ + printf "%s:%s\0" "$1" "$2" >&"$butl_manifest_serializer_ifd" +} + +# Serialize the submission result manifest to stdout. +# +function result_manifest () # [] +{ + 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 : -- cgit v1.1