From 35359f038f571dc46de3d14af72a2bc911fb0a24 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Wed, 18 Mar 2020 22:17:49 +0300 Subject: Implement brep-monitor --- mod/.gitignore | 2 +- mod/build-config-module.cxx | 236 +---------- mod/build-config-module.hxx | 40 +- mod/build-config.cxx | 249 +++++++++++ mod/build-config.hxx | 45 ++ mod/build.cxx | 2 +- mod/buildfile | 31 +- mod/database-module.cxx | 2 +- mod/database-module.hxx | 2 +- mod/mod-build-configs.cxx | 7 +- mod/mod-build-configs.hxx | 2 +- mod/mod-build-force.cxx | 4 +- mod/mod-build-force.hxx | 2 +- mod/mod-build-log.cxx | 4 +- mod/mod-build-log.hxx | 2 +- mod/mod-build-result.cxx | 7 +- mod/mod-build-result.hxx | 2 +- mod/mod-build-task.cxx | 22 +- mod/mod-build-task.hxx | 2 +- mod/mod-builds.cxx | 37 +- mod/mod-builds.hxx | 2 +- mod/mod-ci.cxx | 11 +- mod/mod-ci.hxx | 4 +- mod/mod-package-details.cxx | 9 +- mod/mod-package-details.hxx | 2 +- mod/mod-package-version-details.cxx | 9 +- mod/mod-package-version-details.hxx | 2 +- mod/mod-packages.cxx | 9 +- mod/mod-packages.hxx | 2 +- mod/mod-repository-details.cxx | 9 +- mod/mod-repository-details.hxx | 2 +- mod/mod-repository-root.cxx | 4 +- mod/mod-repository-root.hxx | 2 +- mod/mod-submit.cxx | 7 +- mod/mod-submit.hxx | 4 +- mod/module.cli | 811 ++++++++++++++++++++++++++++++++++++ mod/module.cxx | 6 +- mod/module.hxx | 4 +- mod/options.cli | 811 ------------------------------------ mod/page.cxx | 7 +- mod/page.hxx | 2 +- mod/services.cxx | 2 +- mod/types-parsers.cxx | 2 +- mod/types-parsers.hxx | 2 +- 44 files changed, 1235 insertions(+), 1190 deletions(-) create mode 100644 mod/build-config.cxx create mode 100644 mod/build-config.hxx create mode 100644 mod/module.cli delete mode 100644 mod/options.cli (limited to 'mod') diff --git a/mod/.gitignore b/mod/.gitignore index c6e608b..6b64ad0 100644 --- a/mod/.gitignore +++ b/mod/.gitignore @@ -1 +1 @@ -options.?xx +*-options.?xx diff --git a/mod/build-config-module.cxx b/mod/build-config-module.cxx index b1818b7..831cb78 100644 --- a/mod/build-config-module.cxx +++ b/mod/build-config-module.cxx @@ -9,10 +9,9 @@ #include #include -#include // throw_generic_error(), alpha(), etc. +#include // throw_generic_error() #include #include // dir_iterator, dir_entry -#include namespace brep { @@ -157,184 +156,6 @@ namespace brep build_conf_map_ = make_shared (move (conf_map)); } - // The default underlying class set expression (see below). - // - static const build_class_expr default_ucs_expr ( - {"default"}, '+', "Default."); - - bool build_config_module:: - exclude (const small_vector& exprs, - const vector& constrs, - const build_config& cfg, - string* reason) const - { - // Save the first sentence of the reason, lower-case the first letter if - // the beginning looks like a word (all subsequent characters until a - // whitespace are lower-case letters). - // - auto sanitize = [] (const string& reason) - { - string r (reason.substr (0, reason.find ('.'))); - - char c (r[0]); // Can be '\0'. - if (alpha (c) && c == ucase (c)) - { - bool word (true); - - for (size_t i (1); - i != r.size () && (c = r[i]) != ' ' && c != '\t' && c != '\n'; - ++i) - { - // Is not a word if contains a non-letter or an upper-case letter. - // - if (!alpha (c) || c == ucase (c)) - { - word = false; - break; - } - } - - if (word) - r[0] = lcase (r[0]); - } - - return r; - }; - - // First, match the configuration against the package underlying build - // class set and expressions. - // - bool m (false); - - // Match the configuration against an expression, updating the match - // result. - // - // We will use a comment of the first encountered excluding expression - // (changing the result from true to false) or non-including one (leaving - // the false result) as an exclusion reason. - // - auto match = [&cfg, &m, reason, &sanitize, this] - (const build_class_expr& e) - { - bool pm (m); - e.match (cfg.classes, build_conf_->class_inheritance_map, m); - - if (reason != nullptr) - { - // Reset the reason which, if saved, makes no sense anymore. - // - if (m) - { - reason->clear (); - } - else if (reason->empty () && - // - // Exclusion. - // - (pm || - // - // Non-inclusion. Make sure that the build class expression - // is empty or starts with an addition (+...). - // - e.expr.empty () || - e.expr.front ().operation == '+')) - { - *reason = sanitize (e.comment); - } - } - }; - - // Determine the underlying class set. Note that in the future we can - // potentially extend the underlying set with special classes. - // - const build_class_expr* ucs ( - !exprs.empty () && !exprs.front ().underlying_classes.empty () - ? &exprs.front () - : nullptr); - - // Note that the combined package build configuration class expression can - // be represented as the underlying class set used as a starting set for - // the original expressions and a restricting set, simultaneously. For - // example, for the expression: - // - // default legacy : -msvc - // - // the resulting expression will be: - // - // +( +default +legacy ) -msvc &( +default +legacy ) - // - // Let's, however, optimize it a bit based on the following facts: - // - // - If the underlying class set expression (+default +legacy in the above - // example) evaluates to false, then the resulting expression also - // evaluates to false due to the trailing '&' operation. Thus, we don't - // need to evaluate further if that's the case. - // - // - On the other hand, if the underlying class set expression evaluates - // to true, then we don't need to apply the trailing '&' operation as it - // cannot affect the result. - // - const build_class_expr& ucs_expr ( - ucs != nullptr - ? build_class_expr (ucs->underlying_classes, '+', ucs->comment) - : default_ucs_expr); - - match (ucs_expr); - - if (m) - { - for (const build_class_expr& e: exprs) - match (e); - } - - // Exclude the configuration if it doesn't match the compound expression. - // - if (!m) - return true; - - // Now check if the configuration is excluded/included via the patterns. - // - // To implement matching of absent name components with wildcard-only - // pattern components we are going to convert names to paths (see - // dash_components_to_path() for details). - // - // And if any of the build-{include,exclude} values (which is legal) or - // the build configuration name/target (illegal) are invalid paths, then - // we assume no match. - // - if (!constrs.empty ()) - try - { - path cn (dash_components_to_path (cfg.name)); - path tg (dash_components_to_path (cfg.target.string ())); - - for (const build_constraint& c: constrs) - { - if (path_match (cn, - dash_components_to_path (c.config), - dir_path () /* start */, - path_match_flags::match_absent) && - (!c.target || - path_match (tg, - dash_components_to_path (*c.target), - dir_path () /* start */, - path_match_flags::match_absent))) - { - if (!c.exclusion) - return false; - - if (reason != nullptr) - *reason = sanitize (c.comment); - - return true; - } - } - } - catch (const invalid_path&) {} - - return false; - } - bool build_config_module:: belongs (const bbot::build_config& cfg, const char* cls) const { @@ -360,59 +181,4 @@ namespace brep return false; } - - path build_config_module:: - dash_components_to_path (const string& pattern) - { - string r; - size_t nstar (0); - for (const path_pattern_term& pt: path_pattern_iterator (pattern)) - { - switch (pt.type) - { - case path_pattern_term_type::star: - { - // Replace ** with */**/* and skip all the remaining stars that may - // follow in this sequence. - // - if (nstar == 0) - r += "*"; - else if (nstar == 1) - r += "/**/*"; // The first star is already copied. - - break; - } - case path_pattern_term_type::literal: - { - // Replace '-' with '/' and fall through otherwise. - // - if (get_literal (pt) == '-') - { - r += '/'; - break; - } - } - // Fall through. - default: - { - r.append (pt.begin, pt.end); // Copy the pattern term as is. - } - } - - nstar = pt.star () ? nstar + 1 : 0; - } - - // Append the trailing slash to match the resulting paths as directories. - // This is required for the trailing /* we could append to match absent - // directory path components (see path_match_flags::match_absent for - // details). - // - // Note that valid dash components may not contain a trailing dash. - // Anyway, any extra trailing slashes will be ignored by the path - // constructor. - // - r += '/'; - - return path (move (r)); - } } diff --git a/mod/build-config-module.hxx b/mod/build-config-module.hxx index 4b23056..04fd5b1 100644 --- a/mod/build-config-module.hxx +++ b/mod/build-config-module.hxx @@ -5,7 +5,6 @@ #define MOD_BUILD_CONFIG_MODULE_HXX #include -#include // find() #include // compare_c_string @@ -16,8 +15,8 @@ #include #include -#include -#include +#include +#include // Base class for modules that utilize the build controller configuration. // @@ -39,17 +38,18 @@ namespace brep void init (const options::build&); - // Return true if the specified build configuration is excluded by a - // package based on its underlying build class set, build class - // expressions, and build constraints, potentially extending the - // underlying set with the special classes. Set the exclusion reason if - // requested. - // bool - exclude (const small_vector&, - const vector&, - const bbot::build_config&, - string* reason = nullptr) const; + exclude (const small_vector& exprs, + const vector& constrs, + const bbot::build_config& cfg, + string* reason = nullptr) const + { + return brep::exclude (exprs, + constrs, + cfg, + build_conf_->class_inheritance_map, + reason); + } // Check if the configuration belongs to the specified class. // @@ -62,20 +62,6 @@ namespace brep return belongs (cfg, cls.c_str ()); } - // Convert dash-separated components (target, build configuration name, - // machine name) or a pattern thereof into a path, replacing dashes with - // slashes (directory separators), `**` with `*/**/*`, and appending the - // trailing slash for a subsequent match using the path_match() - // functionality (the idea here is for `linux**` to match `linux-gcc` - // which is quite natural to expect). Throw invalid_path if the resulting - // path is invalid. - // - // Note that the match_absent path match flag must be used for the above - // `**` transformation to work. - // - static path - dash_components_to_path (const string&); - // Configuration/toolchain combination that, in particular, can be used as // a set value. // diff --git a/mod/build-config.cxx b/mod/build-config.cxx new file mode 100644 index 0000000..2d64aec --- /dev/null +++ b/mod/build-config.cxx @@ -0,0 +1,249 @@ +// file : mod/build-config-module.cxx -*- C++ -*- +// license : MIT; see accompanying LICENSE file + +#include + +#include // alpha(), etc. +#include + +namespace brep +{ + using namespace std; + using namespace butl; + using namespace bpkg; + using namespace bbot; + + // The default underlying class set expression (see below). + // + static const build_class_expr default_ucs_expr ( + {"default"}, '+', "Default."); + + bool + exclude (const small_vector& exprs, + const vector& constrs, + const build_config& cfg, + const map& class_inheritance_map, + string* reason) + { + // Save the first sentence of the reason, lower-case the first letter if + // the beginning looks like a word (all subsequent characters until a + // whitespace are lower-case letters). + // + auto sanitize = [] (const string& reason) + { + string r (reason.substr (0, reason.find ('.'))); + + char c (r[0]); // Can be '\0'. + if (alpha (c) && c == ucase (c)) + { + bool word (true); + + for (size_t i (1); + i != r.size () && (c = r[i]) != ' ' && c != '\t' && c != '\n'; + ++i) + { + // Is not a word if contains a non-letter or an upper-case letter. + // + if (!alpha (c) || c == ucase (c)) + { + word = false; + break; + } + } + + if (word) + r[0] = lcase (r[0]); + } + + return r; + }; + + // First, match the configuration against the package underlying build + // class set and expressions. + // + bool m (false); + + // Match the configuration against an expression, updating the match + // result. + // + // We will use a comment of the first encountered excluding expression + // (changing the result from true to false) or non-including one (leaving + // the false result) as an exclusion reason. + // + auto match = [&cfg, &m, reason, &sanitize, &class_inheritance_map] + (const build_class_expr& e) + { + bool pm (m); + e.match (cfg.classes, class_inheritance_map, m); + + if (reason != nullptr) + { + // Reset the reason which, if saved, makes no sense anymore. + // + if (m) + { + reason->clear (); + } + else if (reason->empty () && + // + // Exclusion. + // + (pm || + // + // Non-inclusion. Make sure that the build class expression + // is empty or starts with an addition (+...). + // + e.expr.empty () || + e.expr.front ().operation == '+')) + { + *reason = sanitize (e.comment); + } + } + }; + + // Determine the underlying class set. Note that in the future we can + // potentially extend the underlying set with special classes. + // + const build_class_expr* ucs ( + !exprs.empty () && !exprs.front ().underlying_classes.empty () + ? &exprs.front () + : nullptr); + + // Note that the combined package build configuration class expression can + // be represented as the underlying class set used as a starting set for + // the original expressions and a restricting set, simultaneously. For + // example, for the expression: + // + // default legacy : -msvc + // + // the resulting expression will be: + // + // +( +default +legacy ) -msvc &( +default +legacy ) + // + // Let's, however, optimize it a bit based on the following facts: + // + // - If the underlying class set expression (+default +legacy in the above + // example) evaluates to false, then the resulting expression also + // evaluates to false due to the trailing '&' operation. Thus, we don't + // need to evaluate further if that's the case. + // + // - On the other hand, if the underlying class set expression evaluates + // to true, then we don't need to apply the trailing '&' operation as it + // cannot affect the result. + // + const build_class_expr& ucs_expr ( + ucs != nullptr + ? build_class_expr (ucs->underlying_classes, '+', ucs->comment) + : default_ucs_expr); + + match (ucs_expr); + + if (m) + { + for (const build_class_expr& e: exprs) + match (e); + } + + // Exclude the configuration if it doesn't match the compound expression. + // + if (!m) + return true; + + // Now check if the configuration is excluded/included via the patterns. + // + // To implement matching of absent name components with wildcard-only + // pattern components we are going to convert names to paths (see + // dash_components_to_path() for details). + // + // And if any of the build-{include,exclude} values (which is legal) or + // the build configuration name/target (illegal) are invalid paths, then + // we assume no match. + // + if (!constrs.empty ()) + try + { + path cn (dash_components_to_path (cfg.name)); + path tg (dash_components_to_path (cfg.target.string ())); + + for (const build_constraint& c: constrs) + { + if (path_match (cn, + dash_components_to_path (c.config), + dir_path () /* start */, + path_match_flags::match_absent) && + (!c.target || + path_match (tg, + dash_components_to_path (*c.target), + dir_path () /* start */, + path_match_flags::match_absent))) + { + if (!c.exclusion) + return false; + + if (reason != nullptr) + *reason = sanitize (c.comment); + + return true; + } + } + } + catch (const invalid_path&) {} + + return false; + } + + path + dash_components_to_path (const string& pattern) + { + string r; + size_t nstar (0); + for (const path_pattern_term& pt: path_pattern_iterator (pattern)) + { + switch (pt.type) + { + case path_pattern_term_type::star: + { + // Replace ** with */**/* and skip all the remaining stars that may + // follow in this sequence. + // + if (nstar == 0) + r += "*"; + else if (nstar == 1) + r += "/**/*"; // The first star is already copied. + + break; + } + case path_pattern_term_type::literal: + { + // Replace '-' with '/' and fall through otherwise. + // + if (get_literal (pt) == '-') + { + r += '/'; + break; + } + } + // Fall through. + default: + { + r.append (pt.begin, pt.end); // Copy the pattern term as is. + } + } + + nstar = pt.star () ? nstar + 1 : 0; + } + + // Append the trailing slash to match the resulting paths as directories. + // This is required for the trailing /* we could append to match absent + // directory path components (see path_match_flags::match_absent for + // details). + // + // Note that valid dash components may not contain a trailing dash. + // Anyway, any extra trailing slashes will be ignored by the path + // constructor. + // + r += '/'; + + return path (move (r)); + } +} diff --git a/mod/build-config.hxx b/mod/build-config.hxx new file mode 100644 index 0000000..d5e44ce --- /dev/null +++ b/mod/build-config.hxx @@ -0,0 +1,45 @@ +// file : mod/build-config.hxx -*- C++ -*- +// license : MIT; see accompanying LICENSE file + +#ifndef MOD_BUILD_CONFIG_HXX +#define MOD_BUILD_CONFIG_HXX + +#include + +#include + +#include + +#include +#include + +namespace brep +{ + // Return true if the specified build configuration is excluded by a package + // based on its underlying build class set, build class expressions, and + // build constraints, potentially extending the underlying set with the + // special classes. Set the exclusion reason if requested. + // + bool + exclude (const small_vector&, + const vector&, + const bbot::build_config&, + const std::map& class_inheritance_map, + string* reason = nullptr); + + // Convert dash-separated components (target, build configuration name, + // machine name) or a pattern thereof into a path, replacing dashes with + // slashes (directory separators), `**` with `*/**/*`, and appending the + // trailing slash for a subsequent match using the path_match() + // functionality (the idea here is for `linux**` to match `linux-gcc` which + // is quite natural to expect). Throw invalid_path if the resulting path is + // invalid. + // + // Note that the match_absent path match flag must be used for the above + // `**` transformation to work. + // + path + dash_components_to_path (const string&); +} + +#endif // MOD_BUILD_CONFIG diff --git a/mod/build.cxx b/mod/build.cxx index cdbaa60..5b9d8aa 100644 --- a/mod/build.cxx +++ b/mod/build.cxx @@ -3,7 +3,7 @@ #include -#include +#include #include diff --git a/mod/buildfile b/mod/buildfile index 9300faf..ca46bc4 100644 --- a/mod/buildfile +++ b/mod/buildfile @@ -19,25 +19,38 @@ import libs += libbpkg%lib{bpkg} import libs += libbbot%lib{bbot} include ../libbrep/ -include ../web/ -mod{brep}: {hxx ixx txx cxx}{* -options} \ - {hxx ixx cxx}{ options} \ - ../libbrep/lib{brep} ../web/libus{web} $libs +include ../web/xhtml/ +include ../web/server/ + +./: mod{brep} {libue libus}{mod} + +libu_src = options-types types-parsers build-config + +mod{brep}: {hxx ixx txx cxx}{* -module-options -{$libu_src}} \ + libus{mod} ../libbrep/lib{brep} ../web/server/libus{web-server} \ + $libs + +{libue libus}{mod}: {hxx ixx cxx}{module-options} \ + {hxx ixx txx cxx}{+{$libu_src} } \ + $libs + +libus{mod}: ../web/xhtml/libus{xhtml} +libue{mod}: ../web/xhtml/libue{xhtml} # Generated options parser. # if $cli.configured { - cli.cxx{options}: cli{options} + cli.cxx{module-options}: cli{module} # Set option prefix to the empty value to handle all unknown request # parameters uniformly with a single catch block. # - cli.options += --std c++11 -I $src_root --include-with-brackets \ ---include-prefix mod --guard-prefix MOD --generate-specifier \ ---cxx-prologue "#include " \ ---cli-namespace brep::cli --generate-file-scanner --suppress-usage \ + cli.options += --std c++11 -I $src_root --include-with-brackets \ +--include-prefix mod --guard-prefix MOD --generate-specifier \ +--cxx-prologue "#include " \ +--cli-namespace brep::cli --generate-file-scanner --option-length 38 \ --generate-modifier --generate-description --option-prefix "" # Include the generated cli files into the distribution and don't remove diff --git a/mod/database-module.cxx b/mod/database-module.cxx index 5516730..f598bfd 100644 --- a/mod/database-module.cxx +++ b/mod/database-module.cxx @@ -5,8 +5,8 @@ #include -#include #include +#include namespace brep { diff --git a/mod/database-module.hxx b/mod/database-module.hxx index a41752d..f72ba83 100644 --- a/mod/database-module.hxx +++ b/mod/database-module.hxx @@ -10,7 +10,7 @@ #include #include -#include +#include namespace brep { diff --git a/mod/mod-build-configs.cxx b/mod/mod-build-configs.cxx index 8efc6c9..6731b28 100644 --- a/mod/mod-build-configs.cxx +++ b/mod/mod-build-configs.cxx @@ -7,11 +7,12 @@ #include -#include -#include +#include + +#include #include -#include +#include using namespace std; using namespace bbot; diff --git a/mod/mod-build-configs.hxx b/mod/mod-build-configs.hxx index 333680a..562ac6d 100644 --- a/mod/mod-build-configs.hxx +++ b/mod/mod-build-configs.hxx @@ -8,7 +8,7 @@ #include #include -#include +#include #include namespace brep diff --git a/mod/mod-build-force.cxx b/mod/mod-build-force.cxx index 4dc71c8..bd172e3 100644 --- a/mod/mod-build-force.cxx +++ b/mod/mod-build-force.cxx @@ -8,12 +8,12 @@ #include #include -#include +#include #include #include -#include +#include using namespace std; using namespace bbot; diff --git a/mod/mod-build-force.hxx b/mod/mod-build-force.hxx index 7b6b3b6..22df383 100644 --- a/mod/mod-build-force.hxx +++ b/mod/mod-build-force.hxx @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include diff --git a/mod/mod-build-log.cxx b/mod/mod-build-log.cxx index 16cc965..3032e52 100644 --- a/mod/mod-build-log.cxx +++ b/mod/mod-build-log.cxx @@ -10,12 +10,12 @@ #include // to_stream() -#include +#include #include #include -#include +#include using namespace std; using namespace bbot; diff --git a/mod/mod-build-log.hxx b/mod/mod-build-log.hxx index 9f9d1d9..a2f4e48 100644 --- a/mod/mod-build-log.hxx +++ b/mod/mod-build-log.hxx @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include diff --git a/mod/mod-build-result.cxx b/mod/mod-build-result.cxx index b3467d2..734ea5c 100644 --- a/mod/mod-build-result.cxx +++ b/mod/mod-build-result.cxx @@ -15,15 +15,15 @@ #include -#include +#include #include #include #include #include -#include // *_url() -#include +#include // *_url() +#include using namespace std; using namespace butl; @@ -409,6 +409,7 @@ handle (request& rq, response&) b->results = move (rqm.result.results); b->timestamp = system_clock::now (); + b->completion_timestamp = b->timestamp; build_db_->update (b); diff --git a/mod/mod-build-result.hxx b/mod/mod-build-result.hxx index b3911e1..71a60f9 100644 --- a/mod/mod-build-result.hxx +++ b/mod/mod-build-result.hxx @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include diff --git a/mod/mod-build-task.cxx b/mod/mod-build-task.cxx index c232815..17bc15e 100644 --- a/mod/mod-build-task.cxx +++ b/mod/mod-build-task.cxx @@ -22,14 +22,14 @@ #include #include -#include +#include #include #include #include #include -#include +#include using namespace std; using namespace butl; @@ -384,28 +384,18 @@ handle (request& rq, response& rs) using prep_bld_query = prepared_query; package_id id; - const auto& qv (bld_query::id.package.version); bld_query bq ( - bld_query::id.package.tenant == bld_query::_ref (id.tenant) && - - bld_query::id.package.name == bld_query::_ref (id.name) && - - qv.epoch == bld_query::_ref (id.version.epoch) && - qv.canonical_upstream == - bld_query::_ref (id.version.canonical_upstream) && - qv.canonical_release == - bld_query::_ref (id.version.canonical_release) && - qv.revision == bld_query::_ref (id.version.revision) && + equal (bld_query::id.package, id) && bld_query::id.configuration.in_range (cfg_names.begin (), - cfg_names.end ()) && + cfg_names.end ()) && - bld_query::id.toolchain_name == tqm.toolchain_name && + bld_query::id.toolchain_name == tqm.toolchain_name && compare_version_eq (bld_query::id.toolchain_version, canonical_version (toolchain_version), - true /* revision */) && + true /* revision */) && (bld_query::state == "built" || ((bld_query::force == "forcing" && diff --git a/mod/mod-build-task.hxx b/mod/mod-build-task.hxx index 5f4c14a..7875db1 100644 --- a/mod/mod-build-task.hxx +++ b/mod/mod-build-task.hxx @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include diff --git a/mod/mod-builds.cxx b/mod/mod-builds.cxx index 77ebc05..ab9e93e 100644 --- a/mod/mod-builds.cxx +++ b/mod/mod-builds.cxx @@ -16,9 +16,10 @@ #include // to_result_status(), to_string(result_status) -#include -#include -#include +#include +#include + +#include #include #include @@ -26,7 +27,7 @@ #include #include -#include +#include using namespace std; using namespace butl; @@ -231,7 +232,10 @@ build_query (const brep::cstrings* configs, else { query sq (qb::status == rs); - result_status st (to_result_status(rs)); // May throw invalid_argument. + + // May throw invalid_argument. + // + result_status st (to_result_status (rs)); if (st != result_status::success) { @@ -312,22 +316,6 @@ package_query (const brep::params::builds& params, return q; } -template -static inline query -package_id_eq (const ID& x, const brep::package_id& y) -{ - using query = query; - const auto& qv (x.version); - - return - x.tenant == query::_ref (y.tenant) && - x.name == query::_ref (y.name) && - qv.epoch == query::_ref (y.version.epoch) && - qv.canonical_upstream == query::_ref (y.version.canonical_upstream) && - qv.canonical_release == query::_ref (y.version.canonical_release) && - qv.revision == query::_ref (y.version.revision); -} - static const vector> build_results ({ {"unbuilt", ""}, {"*", "*"}, @@ -821,9 +809,8 @@ handle (request& rq, response& rs) const auto& bid (bld_query::build::id); - bld_query bq ( - package_id_eq (bid.package, id) && - bid.configuration == bld_query::_ref (config) && + bld_query bq (equal (bid.package, id) && + bid.configuration == bld_query::_ref (config) && // Note that the query already constrains configurations via the // configuration name and the tenant via the build package id. @@ -936,7 +923,7 @@ handle (request& rq, response& rs) package_id id; bld_query bq ( - package_id_eq (bld_query::build::id.package, id) && + equal (bld_query::build::id.package, id) && // Note that the query already constrains the tenant via the build // package id. diff --git a/mod/mod-builds.hxx b/mod/mod-builds.hxx index 714b374..0aa7916 100644 --- a/mod/mod-builds.hxx +++ b/mod/mod-builds.hxx @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include diff --git a/mod/mod-ci.cxx b/mod/mod-ci.cxx index 77377eb..d2da93f 100644 --- a/mod/mod-ci.cxx +++ b/mod/mod-ci.cxx @@ -17,11 +17,12 @@ #include #include -#include -#include +#include + +#include #include -#include +#include #include using namespace std; @@ -116,8 +117,8 @@ handle (request& rq, response& rs) // latter case we will always respond with the same neutral message for // security reason, logging the error details. Note that descriptions of // exceptions caught by the web server are returned to the client (see - // web/module.hxx for details), and we want to avoid this when there is a - // danger of exposing sensitive data. + // web/server/module.hxx for details), and we want to avoid this when there + // is a danger of exposing sensitive data. // // Also we will pass through exceptions thrown by the underlying API, unless // we need to handle them or add details for the description, in which case diff --git a/mod/mod-ci.hxx b/mod/mod-ci.hxx index 1228714..431f53b 100644 --- a/mod/mod-ci.hxx +++ b/mod/mod-ci.hxx @@ -4,13 +4,13 @@ #ifndef MOD_MOD_CI_HXX #define MOD_MOD_CI_HXX -#include +#include #include #include #include -#include +#include namespace brep { diff --git a/mod/mod-package-details.cxx b/mod/mod-package-details.cxx index c7973d3..e0bd1ef 100644 --- a/mod/mod-package-details.cxx +++ b/mod/mod-package-details.cxx @@ -9,15 +9,16 @@ #include #include -#include -#include -#include +#include +#include + +#include #include #include #include -#include +#include using namespace odb::core; using namespace brep::cli; diff --git a/mod/mod-package-details.hxx b/mod/mod-package-details.hxx index 16f8c3e..e1b0a9c 100644 --- a/mod/mod-package-details.hxx +++ b/mod/mod-package-details.hxx @@ -7,7 +7,7 @@ #include #include -#include +#include #include namespace brep diff --git a/mod/mod-package-version-details.cxx b/mod/mod-package-version-details.cxx index cde65b0..bfc08b0 100644 --- a/mod/mod-package-version-details.cxx +++ b/mod/mod-package-version-details.cxx @@ -9,9 +9,10 @@ #include #include -#include -#include -#include +#include +#include + +#include #include #include @@ -19,7 +20,7 @@ #include #include -#include +#include using namespace std; using namespace butl; diff --git a/mod/mod-package-version-details.hxx b/mod/mod-package-version-details.hxx index 8d0d373..a88d6c2 100644 --- a/mod/mod-package-version-details.hxx +++ b/mod/mod-package-version-details.hxx @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include diff --git a/mod/mod-packages.cxx b/mod/mod-packages.cxx index 81cf83c..65c7c5b 100644 --- a/mod/mod-packages.cxx +++ b/mod/mod-packages.cxx @@ -10,15 +10,16 @@ #include #include -#include -#include -#include +#include +#include + +#include #include #include #include -#include +#include using namespace odb::core; using namespace brep::cli; diff --git a/mod/mod-packages.hxx b/mod/mod-packages.hxx index d1c4677..611d63c 100644 --- a/mod/mod-packages.hxx +++ b/mod/mod-packages.hxx @@ -7,7 +7,7 @@ #include #include -#include +#include #include namespace brep diff --git a/mod/mod-repository-details.cxx b/mod/mod-repository-details.cxx index 988c445..813b738 100644 --- a/mod/mod-repository-details.cxx +++ b/mod/mod-repository-details.cxx @@ -12,15 +12,16 @@ #include // to_string() -#include -#include -#include +#include +#include + +#include #include #include #include -#include +#include using namespace std; using namespace odb::core; diff --git a/mod/mod-repository-details.hxx b/mod/mod-repository-details.hxx index bd4b3ba..e83831d 100644 --- a/mod/mod-repository-details.hxx +++ b/mod/mod-repository-details.hxx @@ -7,7 +7,7 @@ #include #include -#include +#include #include namespace brep diff --git a/mod/mod-repository-root.cxx b/mod/mod-repository-root.cxx index b6c54b8..02d6c93 100644 --- a/mod/mod-repository-root.cxx +++ b/mod/mod-repository-root.cxx @@ -10,10 +10,10 @@ #include #include // find() -#include +#include #include -#include +#include #include #include diff --git a/mod/mod-repository-root.hxx b/mod/mod-repository-root.hxx index ac4b254..9e28797 100644 --- a/mod/mod-repository-root.hxx +++ b/mod/mod-repository-root.hxx @@ -8,7 +8,7 @@ #include #include -#include +#include namespace brep { diff --git a/mod/mod-submit.cxx b/mod/mod-submit.cxx index 0dea2b7..9c93a36 100644 --- a/mod/mod-submit.cxx +++ b/mod/mod-submit.cxx @@ -14,11 +14,12 @@ #include #include -#include -#include +#include + +#include #include -#include +#include #include using namespace std; diff --git a/mod/mod-submit.hxx b/mod/mod-submit.hxx index 96a60f9..fc5f8d4 100644 --- a/mod/mod-submit.hxx +++ b/mod/mod-submit.hxx @@ -4,13 +4,13 @@ #ifndef MOD_MOD_SUBMIT_HXX #define MOD_MOD_SUBMIT_HXX -#include +#include #include #include #include -#include +#include namespace brep { diff --git a/mod/module.cli b/mod/module.cli new file mode 100644 index 0000000..fa1d2cc --- /dev/null +++ b/mod/module.cli @@ -0,0 +1,811 @@ +// file : mod/options.cli -*- C++ -*- +// license : MIT; see accompanying LICENSE file + +include ; // repository_location + +include ; + +include ; + +include ; + +namespace brep +{ + // Web handler configuration options. + // + namespace options + { + // Option groups. + // + class handler + { + string email + { + "", + "Repository email. This email is used for the \cb{From:} header in + emails send by \cb{brep} (for example, build failure notifications)." + } + + string host + { + "", + "Repository host. It specifies the scheme and the host address (but + not the root path; see \cb{root} below) that will be used whenever + \cb{brep} needs to construct an absolute URL to one of its locations + (for example, a link to a build log that is being send via email)." + } + + dir_path root = "/" + { + "", + "Repository root. That is, this is the part of the URL between the + host name and the start of the repository. For example, root value + '\cb{/pkg}' means the repository URL is \cb{http://example.org/pkg/}. + Specify '\cb{/}' to use the web server root + (\cb{http://example.org/})." + } + + string tenant-name = "tenant" + { + "", + "Name to call the tenant values on web pages. If not specified, then + \cb{tenant} is used." + } + + uint16_t verbosity = 0 + { + "", + "Trace verbosity level. Level 0 disables tracing, which is also the + default." + } + }; + + class openssl_options + { + path openssl = "openssl" + { + "", + "The openssl program to be used for crypto operations. You can also + specify additional options that should be passed to the openssl + program with \cb{openssl-option}. If the openssl program is not + explicitly specified, then \cb{brep} will use \cb{openssl} by + default." + } + + strings openssl-option + { + "", + "Additional option to be passed to the openssl program (see + \cb{openssl} for details). Repeat this option to specify multiple + openssl options." + } + + strings openssl-envvar + { + "[=value]", + "Environment variable to be set (=) or unset (just + ) for the openssl program (see \cb{openssl} for details). + Repeat this option to specify multiple openssl variables. Note + that unspecified variables are inherited from the web server + process. + + You need to at least set the \cb{RANDFILE} environment variable + to change the default location of the openssl program seed file + and maybe also the \cb{OPENSSL_CONF} variable if you would like + to use a custom openssl configuration file." + } + }; + + class package_db + { + string package-db-user + { + "", + "Package database login user name. If not specified, then operating + system (login) name is used. See also \c{package-db-role}." + } + + string package-db-role = "brep" + { + "", + "Package database execution user name. If not empty then the login + user will be switched (with \c{SET ROLE}) to this user prior to + executing any statements. If not specified, then \cb{brep} is used." + } + + string package-db-password + { + "", + "Package database password. If not specified, then login without + password is expected to work." + } + + string package-db-name = "brep_package" + { + "", + "Package database name. If not specified, then \cb{brep_package} is + used by default." + } + + string package-db-host + { + "", + "Package database host name, address, or socket. If not specified, then + connect to \cb{localhost} using the operating system-default + mechanism (Unix-domain socket, etc)." + } + + uint16_t package-db-port = 0 + { + "", + "Package database port number. If not specified, the default port is + used." + } + + size_t package-db-max-connections = 5 + { + "", + "The maximum number of concurrent package database connections per web + server process. If 0, then no limitation is applied. The default is + 5." + } + + size_t package-db-retry = 10 + { + "", + "The maximum number of times to retry package database transactions in + the face of recoverable failures (deadlock, loss of connection, etc). + The default is 10." + } + }; + + class build: openssl_options + { + path build-config + { + "", + "Build configuration file. If not specified, then the package building + functionality will be disabled. If specified, then the build database + must be configured (see \cb{build-db-*}). The \cb{brep} instance + needs to be restarted after modifying for the changes to + take effect." + } + + dir_path build-bot-agent-keys + { + "", + "Directory containing build bot agent public keys. If specified, then + \cb{brep} will perform agent authentication and will reject build + results from unauthenticated ones. If not specified, then build + results are accepted from all agents (which will be a security + risk if the \cb{brep} instance is publicly accessible). + + The directory is expected to contain one PEM-encoded public key + per file with the \cb{.pem} extension. All other files and + subdirectories are ignored. The \cb{brep} instance needs to be + restarted after adding new key files for the changes to take effect." + } + + size_t build-forced-rebuild-timeout = 600 + { + "", + "Time to wait before considering a package for a forced rebuild. Must + be specified in seconds. Default is 10 minutes." + } + + size_t build-normal-rebuild-timeout = 86400 + { + "", + "Time to wait before considering a package for a normal rebuild. Must + be specified in seconds. Default is 24 hours." + } + }; + + class build_db + { + string build-db-user + { + "", + "Build database login user name. If not specified, then operating + system (login) name is used. See also \c{build-db-role}." + } + + string build-db-role = "brep" + { + "", + "Build database execution user name. If not empty then the login + user will be switched (with \c{SET ROLE}) to this user prior to + executing any statements. If not specified, then \cb{brep} is used." + } + + string build-db-password + { + "", + "Build database password. If not specified, then login without + password is expected to work." + } + + string build-db-name = "brep_build" + { + "", + "Build database name. If not specified, then \cb{brep_build} is used + by default." + } + + string build-db-host + { + "", + "Build database host name, address, or socket. If not specified, then + connect to \cb{localhost} using the operating system-default + mechanism (Unix-domain socket, etc)." + } + + uint16_t build-db-port = 0 + { + "", + "Build database port number. If not specified, the default port is + used." + } + + size_t build-db-max-connections = 5 + { + "", + "The maximum number of concurrent build database connections per web + server process. If 0, then no limitation is applied. The default is + 5." + } + + size_t build-db-retry = 10 + { + "", + "The maximum number of times to retry build database transactions in + the face of recoverable failures (deadlock, loss of connection, etc). + The default is 10." + } + }; + + class page + { + web::xhtml::fragment logo + { + "", + "Web page logo. It is displayed in the page header aligned to the left + edge. The value is treated as an XHTML5 fragment." + } + + vector menu; + { + "", + "Web page menu. Each entry is displayed in the page header in the + order specified and aligned to the right edge. A link target that + starts with '\cb{/}' or contains '\cb{:}' is used as is. Otherwise, + it is prefixed with the repository web interface root." + } + }; + + class search + { + uint16_t search-page-entries = 20 + { + "", + "Number of packages per page. The default is 20." + } + + uint16_t search-pages = 5 + { + "", + "Number of pages in navigation (pager). The default is 5." + } + }; + + class package + { + uint16_t package-description = 500 + { + "", + "Number of package description characters to display in brief pages. + The default is 500 (~ 80 characters * 6 lines)." + } + + uint16_t package-changes = 5000; + { + "", + "Number of package changes characters to display in brief pages. The + default is 5000 (~ 80 chars x 60 lines)." + } + }; + + // Handler options. + // + + class packages: search, package_db, page, handler + { + string search-title = "Packages" + { + "", + "Package search page title. It is placed inside XHTML5 + element." + } + }; + + class package_details: package, search, package_db, page, handler + { + }; + + class package_version_details: package, package_db, + build, build_db, + page, + handler + { + }; + + class repository_details: package_db, page, handler + { + }; + + class build_task: build, build_db, handler + { + size_t build-task-request-max-size = 102400 + { + "<bytes>", + "The maximum size of the build task request manifest accepted. Note + that the HTTP POST request body is cached to retry database + transactions in the face of recoverable failures (deadlock, loss of + connection, etc). The default is 100K." + } + + size_t build-result-timeout = 10800 + { + "<seconds>", + "Time to wait before considering the expected task result lost. Must be + specified in seconds. The default is 3 hours." + } + }; + + class build_result: build, package_db, build_db, handler + { + size_t build-result-request-max-size = 10240000 + { + "<bytes>", + "The maximum size of the build result manifest accepted. Note that the + HTTP POST request body is cached to retry database transactions in the + face of recoverable failures (deadlock, loss of connection, etc). The + default is 10M." + } + }; + + class build_log: build, build_db, handler + { + }; + + class build_force: build, build_db, handler + { + }; + + class builds: build, build_db, page, handler + { + uint16_t build-page-entries = 20 + { + "<num>", + "Number of builds per page. The default is 20." + } + + uint16_t build-pages = 5 + { + "<num>", + "Number of pages in navigation (pager). The default is 5." + } + }; + + class build_configs: build, page, handler + { + uint16_t build-config-page-entries = 20 + { + "<num>", + "Number of build configurations per page. The default is 20." + } + + uint16_t build-config-pages = 5 + { + "<num>", + "Number of pages in navigation (pager). The default is 5." + } + }; + + class submit: page, handler + { + dir_path submit-data + { + "<dir>", + "The directory to save final submission data to. If unspecified, the + package submission functionality will be disabled. If specified, + then \cb{submit-temp} must be specified as well. See \l{brep The + \cb{build2} Repository Interface Manual} for more information on + package submission. + + Note that the directory path must be absolute and the directory + itself must exist and have read, write, and execute permissions + granted to the user that runs the web server." + } + + dir_path submit-temp + { + "<dir>", + "The directory to save temporary submission data to. Must be specified + if the package submission functionality is enabled. + + Note that this directory must be on the same filesystem and satisfy + the same requirements as \cb{submit-data}. It is also the user's + responsibility to clean it up after an unclean web server shutdown." + } + + size_t submit-max-size = 10485760 + { + "<bytes>", + "The maximum size of the submission data accepted. Note that currently + the entire submission request is read into memory. The default is + 10M." + } + + path submit-form + { + "<file>", + "The package submission form fragment. If specified, then its contents + are treated as an XHTML5 fragment that is inserted into the <body> + element of the submission page. If unspecified, then no submission + page will be displayed. Note that the file path must be absolute." + } + + string submit-email + { + "<email>", + "The package submission email. If specified, the submission request + and result manifests will be sent to this address. See \l{brep The + \cb{build2} Repository Interface Manual} for more information." + } + + path submit-handler + { + "<path>", + "The handler program to be executed on package submission. The handler + is executed as part of the HTTP request and is passed additional + arguments that can be specified with \cb{submit-handler-argument} + followed by the absolute path to the submission directory. See + \l{brep The \cb{build2} Repository Interface Manual} for more + information. Note that the program path must be absolute." + } + + strings submit-handler-argument + { + "<arg>", + "Additional arguments to be passed to the submission handler program + (see \cb{submit-handler} for details). Repeat this option to specify + multiple arguments." + } + + size_t submit-handler-timeout + { + "<seconds>", + "The submission handler program timeout in seconds. If specified and + the handler does not exit in the allotted time, then it is killed and + its termination is treated as abnormal." + } + }; + + class ci: page, handler + { + dir_path ci-data + { + "<dir>", + "The directory to save CI request data to. If unspecified, the + package CI functionality will be disabled. See \l{brep The + \cb{build2} Repository Interface Manual} for more information on + package CI. + + Note that the directory path must be absolute and the directory + itself must exist and have read, write, and execute permissions + granted to the user that runs the web server." + } + + path ci-form + { + "<file>", + "The package CI form fragment. If specified, then its contents are + treated as an XHTML5 fragment that is inserted into the <body> + element of the CI page. If unspecified, then no CI page will be + displayed. Note that the file path must be absolute." + } + + string ci-email + { + "<email>", + "The package CI email. If specified, the CI request and result + manifests will be sent to this address. See \l{brep The \cb{build2} + Repository Interface Manual} for more information." + } + + path ci-handler + { + "<path>", + "The handler program to be executed on CI request. The handler is + executed as part of the HTTP request and is passed additional + arguments that can be specified with \cb{ci-handler-argument} + followed by the absolute path to the CI request directory. See + \l{brep The \cb{build2} Repository Interface Manual} for more + information. Note that the program path must be absolute." + } + + strings ci-handler-argument + { + "<arg>", + "Additional arguments to be passed to the CI handler program (see + \cb{ci-handler} for details). Repeat this option to specify multiple + arguments." + } + + size_t ci-handler-timeout + { + "<seconds>", + "The CI handler program timeout in seconds. If specified and the + handler does not exit in the allotted time, then it is killed and + its termination is treated as abnormal." + } + }; + + class repository_root: handler + { + string root-global-view = "packages" + { + "<service>", + "The default view to display for the global repository root. The + <service> argument is one of the supported services (\c{packages}, + \c{builds}, \c{submit}, \c{ci}, etc). The default service is + packages." + } + + string root-tenant-view = "packages" + { + "<service>", + "The default view to display for the tenant repository root. The + <service> argument is one of the supported services (\c{packages}, + \c{builds}, \c{submit}, \c{ci}, etc). The default service is + packages." + } + }; + } + + // Web handler HTTP request parameters. + // + namespace params + { + // Use parameters long names in the C++ code, short aliases (if present) + // in HTTP URL. + // + class packages + { + // Display package search result list starting from this page. + // + uint16_t page | p; + + // Package search criteria. + // + // Note that the packages parameter is renamed to '_' by the root + // handler (see the request_proxy class for details). + // + string q | _; + }; + + class package_details + { + // Display package version search result list starting from this page. + // + uint16_t page | p; + + // Package version search criteria. + // + string query | q; + + // Page form. + // + page_form form | f = page_form::brief; + }; + + class package_version_details + { + // Page form. + // + page_form form | f = page_form::brief; + }; + + class repository_details + { + // No parameters so far. + // + }; + + class build_task + { + // Package repository canonical name (note: including pkg: type). + // + vector<string> repository | r; + }; + + class build_result + { + // No parameters so far. + // + }; + + class build_log + { + // No parameters so far. + // + }; + + // All parameters are non-optional. + // + class build_force + { + // Package name. + // + string package | pn; + + // Package version. May not be url-encoded, in which case the plus + // character is considered literally (rather than as the encoded space + // character). In other words, after url-decoding the space character is + // treated the same way as the plus character. + // + // @@ Make it of the version type? Maybe after it get moved to + // libbpkg/types.hxx or at least the second use case appear. + // + string version | pv; + + // Package build configuration. + // + string configuration | cf; + + // Toolchain name. + // + string toolchain_name | tn; + + // Toolchain version. May not be url-encoded (see above). + // + string toolchain_version | tv; + + // Package rebuild reason. Must not be empty. + // + string reason; + }; + + class builds + { + // Display packages build configurations list starting from this page. + // + uint16_t page | p; + + // Package builds query filter options. + // + + // Package name wildcard. An empty value is treated the same way as *. + // + // We used to generate URLs like: + // + // https://cppget.org/?builds&pn=bbot + // + // This looked a bit verbose, so now we produce URLs like: + // + // https://cppget.org/?builds=bbot + // + // To support the already distributed URLs the name_legacy (pn) parameter + // overrides the name (builds) parameter, if present. Note that the + // builds parameter is renamed to '_' by the root handler (see the + // request_proxy class for details). + // + string name | _; + string name_legacy | pn; + + // Package version. If empty or *, then no version constraint is applied. + // Otherwise the build package version must match the value exactly. + // + string version | pv; + + // Package build toolchain in the <name>-<version> form. If *, then no + // toolchain constraint is applied. Otherwise the build toolchain name + // and version must match the value exactly. + // + string toolchain | tc = "*"; + + // Package build configuration name wildcard. An empty value is treated + // the same way as *. + // + string configuration | cf; + + // Package build machine name wildcard. An empty value is treated the + // same way as *. + // + string machine | mn; + + // Package build target wildcard. An empty value is treated the same way + // as *. + // + string target | tg; + + // Package build result. If *, then no build result constraint is + // applied. Otherwise the value is supposed to be the one of the + // following (ordered) statuses: pending, building, success, warning, + // error, abort, abnormal. The first 3 statuses are checked for equality, + // the rest - for being greater or equal. + // + string result | rs = "*"; + }; + + class build_configs + { + // Note that the build-configs parameter is renamed to '_' by the root + // handler (see the request_proxy class for details). + // + string class_name | _ = "all"; + + // Display build configurations list starting from this page. + // + uint16_t page | p; + }; + + // Parameters, except simulate, must either be all present (actual + // submission) or absent (submission form request). + // + // Note also that besides these parameters there can be others. We don't + // recognize their semantics and just save them to the submission request + // manifest. + // + class submit + { + // Package archive file name. Must be <input type="file"/>. + // + // Note that it can potentially be not just a name but a file path and + // in the client's form (e.g., Windows). + // + string archive; + + // Package archive file SHA256 checksum. + // + string sha256sum; + + // Submission simulation outcome. + // + string simulate; + }; + + // Parameters, except simulate, must either be all present (actual CI + // request) or absent (CI form request). + // + // Note also that besides these parameters there can be others. We don't + // recognize their semantics and just save them to the CI request + // manifest. + // + class ci + { + // Package repository location. + // + // Note that the ci parameter is renamed to '_' by the root handler (see + // the request_proxy class for details). + // + bpkg::repository_location repository | _; + + // Package names/versions. + // + strings package; + + // Overrides file name. Must be <input type="file"/>. + // + // Note that we don't really need this name and only check if this + // parameter is specified to detect presence of the upload. + // + string overrides; + + // Submission simulation outcome. + // + string simulate; + }; + } +} diff --git a/mod/module.cxx b/mod/module.cxx index 8f306fd..06799d7 100644 --- a/mod/module.cxx +++ b/mod/module.cxx @@ -10,10 +10,10 @@ #include <cstring> // strchr() #include <functional> // bind() -#include <web/module.hxx> -#include <web/apache/log.hxx> +#include <web/server/module.hxx> +#include <web/server/apache/log.hxx> -#include <mod/options.hxx> +#include <mod/module-options.hxx> using namespace std; using namespace placeholders; // For std::bind's _1, etc. diff --git a/mod/module.hxx b/mod/module.hxx index 2c62166..b3ed67b 100644 --- a/mod/module.hxx +++ b/mod/module.hxx @@ -4,14 +4,14 @@ #ifndef MOD_MODULE_HXX #define MOD_MODULE_HXX -#include <web/module.hxx> +#include <web/server/module.hxx> #include <libbrep/types.hxx> #include <libbrep/utility.hxx> #include <mod/utility.hxx> -#include <mod/options.hxx> #include <mod/diagnostics.hxx> +#include <mod/module-options.hxx> namespace brep { diff --git a/mod/options.cli b/mod/options.cli deleted file mode 100644 index f02d7a6..0000000 --- a/mod/options.cli +++ /dev/null @@ -1,811 +0,0 @@ -// file : mod/options.cli -*- C++ -*- -// license : MIT; see accompanying LICENSE file - -include <libbpkg/manifest.hxx>; // repository_location - -include <web/xhtml-fragment.hxx>; - -include <libbrep/types.hxx>; - -include <mod/options-types.hxx>; - -namespace brep -{ - // Web handler configuration options. - // - namespace options - { - // Option groups. - // - class handler - { - string email - { - "<email>", - "Repository email. This email is used for the \cb{From:} header in - emails send by \cb{brep} (for example, build failure notifications)." - } - - string host - { - "<host>", - "Repository host. It specifies the scheme and the host address (but - not the root path; see \cb{root} below) that will be used whenever - \cb{brep} needs to construct an absolute URL to one of its locations - (for example, a link to a build log that is being send via email)." - } - - dir_path root = "/" - { - "<path>" - "Repository root. That is, this is the part of the URL between the - host name and the start of the repository. For example, root value - '\cb{/pkg}' means the repository URL is \cb{http://example.org/pkg/}. - Specify '\cb{/}' to use the web server root - (\cb{http://example.org/})." - } - - string tenant-name = "tenant" - { - "<name>", - "Name to call the tenant values on web pages. If not specified, then - \cb{tenant} is used." - } - - uint16_t verbosity = 0 - { - "<level>", - "Trace verbosity level. Level 0 disables tracing, which is also the - default." - } - }; - - class openssl_options - { - path openssl = "openssl" - { - "<path>", - "The openssl program to be used for crypto operations. You can also - specify additional options that should be passed to the openssl - program with \cb{openssl-option}. If the openssl program is not - explicitly specified, then \cb{brep} will use \cb{openssl} by - default." - } - - strings openssl-option - { - "<opt>", - "Additional option to be passed to the openssl program (see - \cb{openssl} for details). Repeat this option to specify multiple - openssl options." - } - - strings openssl-envvar - { - "<name>[=value]", - "Environment variable to be set (<name>=<value>) or unset (just - <name>) for the openssl program (see \cb{openssl} for details). - Repeat this option to specify multiple openssl variables. Note - that unspecified variables are inherited from the web server - process. - - You need to at least set the \cb{RANDFILE} environment variable - to change the default location of the openssl program seed file - and maybe also the \cb{OPENSSL_CONF} variable if you would like - to use a custom openssl configuration file." - } - }; - - class package_db - { - string package-db-user - { - "<user>", - "Package database login user name. If not specified, then operating - system (login) name is used. See also \c{package-db-role}." - } - - string package-db-role = "brep" - { - "<user>", - "Package database execution user name. If not empty then the login - user will be switched (with \c{SET ROLE}) to this user prior to - executing any statements. If not specified, then \cb{brep} is used." - } - - string package-db-password - { - "<pass>", - "Package database password. If not specified, then login without - password is expected to work." - } - - string package-db-name = "brep_package" - { - "<name>", - "Package database name. If not specified, then \cb{brep_package} is - used by default." - } - - string package-db-host - { - "<host>", - "Package database host name, address, or socket. If not specified, then - connect to \cb{localhost} using the operating system-default - mechanism (Unix-domain socket, etc)." - } - - uint16_t package-db-port = 0 - { - "<port>", - "Package database port number. If not specified, the default port is - used." - } - - size_t package-db-max-connections = 5 - { - "<num>", - "The maximum number of concurrent package database connections per web - server process. If 0, then no limitation is applied. The default is - 5." - } - - size_t package-db-retry = 10 - { - "<num>", - "The maximum number of times to retry package database transactions in - the face of recoverable failures (deadlock, loss of connection, etc). - The default is 10." - } - }; - - class build: openssl_options - { - path build-config - { - "<buildtab>", - "Build configuration file. If not specified, then the package building - functionality will be disabled. If specified, then the build database - must be configured (see \cb{build-db-*}). The \cb{brep} instance - needs to be restarted after modifying <buildtab> for the changes to - take effect." - } - - dir_path build-bot-agent-keys - { - "<dir>", - "Directory containing build bot agent public keys. If specified, then - \cb{brep} will perform agent authentication and will reject build - results from unauthenticated ones. If not specified, then build - results are accepted from all agents (which will be a security - risk if the \cb{brep} instance is publicly accessible). - - The directory is expected to contain one PEM-encoded public key - per file with the \cb{.pem} extension. All other files and - subdirectories are ignored. The \cb{brep} instance needs to be - restarted after adding new key files for the changes to take effect." - } - - size_t build-forced-rebuild-timeout = 600 - { - "<seconds>", - "Time to wait before considering a package for a forced rebuild. Must - be specified in seconds. Default is 10 minutes." - } - - size_t build-normal-rebuild-timeout = 86400 - { - "<seconds>", - "Time to wait before considering a package for a normal rebuild. Must - be specified in seconds. Default is 24 hours." - } - }; - - class build_db - { - string build-db-user - { - "<user>", - "Build database login user name. If not specified, then operating - system (login) name is used. See also \c{build-db-role}." - } - - string build-db-role = "brep" - { - "<user>", - "Build database execution user name. If not empty then the login - user will be switched (with \c{SET ROLE}) to this user prior to - executing any statements. If not specified, then \cb{brep} is used." - } - - string build-db-password - { - "<pass>", - "Build database password. If not specified, then login without - password is expected to work." - } - - string build-db-name = "brep_build" - { - "<name>", - "Build database name. If not specified, then \cb{brep_build} is used - by default." - } - - string build-db-host - { - "<host>", - "Build database host name, address, or socket. If not specified, then - connect to \cb{localhost} using the operating system-default - mechanism (Unix-domain socket, etc)." - } - - uint16_t build-db-port = 0 - { - "<port>", - "Build database port number. If not specified, the default port is - used." - } - - size_t build-db-max-connections = 5 - { - "<num>", - "The maximum number of concurrent build database connections per web - server process. If 0, then no limitation is applied. The default is - 5." - } - - size_t build-db-retry = 10 - { - "<num>", - "The maximum number of times to retry build database transactions in - the face of recoverable failures (deadlock, loss of connection, etc). - The default is 10." - } - }; - - class page - { - web::xhtml::fragment logo - { - "<xhtml>", - "Web page logo. It is displayed in the page header aligned to the left - edge. The value is treated as an XHTML5 fragment." - } - - vector<page_menu> menu; - { - "<label=link>", - "Web page menu. Each entry is displayed in the page header in the - order specified and aligned to the right edge. A link target that - starts with '\cb{/}' or contains '\cb{:}' is used as is. Otherwise, - it is prefixed with the repository web interface root." - } - }; - - class search - { - uint16_t search-page-entries = 20 - { - "<num>", - "Number of packages per page. The default is 20." - } - - uint16_t search-pages = 5 - { - "<num>", - "Number of pages in navigation (pager). The default is 5." - } - }; - - class package - { - uint16_t package-description = 500 - { - "<len>", - "Number of package description characters to display in brief pages. - The default is 500 (~ 80 characters * 6 lines)." - } - - uint16_t package-changes = 5000; - { - "<len>", - "Number of package changes characters to display in brief pages. The - default is 5000 (~ 80 chars x 60 lines)." - } - }; - - // Handler options. - // - - class packages: search, package_db, page, handler - { - string search-title = "Packages" - { - "<text>", - "Package search page title. It is placed inside XHTML5 <title> - element." - } - }; - - class package_details: package, search, package_db, page, handler - { - }; - - class package_version_details: package, package_db, - build, build_db, - page, - handler - { - }; - - class repository_details: package_db, page, handler - { - }; - - class build_task: build, build_db, handler - { - size_t build-task-request-max-size = 102400 - { - "<bytes>", - "The maximum size of the build task request manifest accepted. Note - that the HTTP POST request body is cached to retry database - transactions in the face of recoverable failures (deadlock, loss of - connection, etc). The default is 100K." - } - - size_t build-result-timeout = 10800 - { - "<seconds>", - "Time to wait before considering the expected task result lost. Must be - specified in seconds. The default is 3 hours." - } - }; - - class build_result: build, package_db, build_db, handler - { - size_t build-result-request-max-size = 10240000 - { - "<bytes>", - "The maximum size of the build result manifest accepted. Note that the - HTTP POST request body is cached to retry database transactions in the - face of recoverable failures (deadlock, loss of connection, etc). The - default is 10M." - } - }; - - class build_log: build, build_db, handler - { - }; - - class build_force: build, build_db, handler - { - }; - - class builds: build, build_db, page, handler - { - uint16_t build-page-entries = 20 - { - "<num>", - "Number of builds per page. The default is 20." - } - - uint16_t build-pages = 5 - { - "<num>", - "Number of pages in navigation (pager). The default is 5." - } - }; - - class build_configs: build, page, handler - { - uint16_t build-config-page-entries = 20 - { - "<num>", - "Number of build configurations per page. The default is 20." - } - - uint16_t build-config-pages = 5 - { - "<num>", - "Number of pages in navigation (pager). The default is 5." - } - }; - - class submit: page, handler - { - dir_path submit-data - { - "<dir>", - "The directory to save final submission data to. If unspecified, the - package submission functionality will be disabled. If specified, - then \cb{submit-temp} must be specified as well. See \l{brep The - \cb{build2} Repository Interface Manual} for more information on - package submission. - - Note that the directory path must be absolute and the directory - itself must exist and have read, write, and execute permissions - granted to the user that runs the web server." - } - - dir_path submit-temp - { - "<dir>", - "The directory to save temporary submission data to. Must be specified - if the package submission functionality is enabled. - - Note that this directory must be on the same filesystem and satisfy - the same requirements as \cb{submit-data}. It is also the user's - responsibility to clean it up after an unclean web server shutdown." - } - - size_t submit-max-size = 10485760 - { - "<bytes>", - "The maximum size of the submission data accepted. Note that currently - the entire submission request is read into memory. The default is - 10M." - } - - path submit-form - { - "<file>", - "The package submission form fragment. If specified, then its contents - are treated as an XHTML5 fragment that is inserted into the <body> - element of the submission page. If unspecified, then no submission - page will be displayed. Note that the file path must be absolute." - } - - string submit-email - { - "<email>", - "The package submission email. If specified, the submission request - and result manifests will be sent to this address. See \l{brep The - \cb{build2} Repository Interface Manual} for more information." - } - - path submit-handler - { - "<path>", - "The handler program to be executed on package submission. The handler - is executed as part of the HTTP request and is passed additional - arguments that can be specified with \cb{submit-handler-argument} - followed by the absolute path to the submission directory. See - \l{brep The \cb{build2} Repository Interface Manual} for more - information. Note that the program path must be absolute." - } - - strings submit-handler-argument - { - "<arg>", - "Additional arguments to be passed to the submission handler program - (see \cb{submit-handler} for details). Repeat this option to specify - multiple arguments." - } - - size_t submit-handler-timeout - { - "<seconds>", - "The submission handler program timeout in seconds. If specified and - the handler does not exit in the allotted time, then it is killed and - its termination is treated as abnormal." - } - }; - - class ci: page, handler - { - dir_path ci-data - { - "<dir>", - "The directory to save CI request data to. If unspecified, the - package CI functionality will be disabled. See \l{brep The - \cb{build2} Repository Interface Manual} for more information on - package CI. - - Note that the directory path must be absolute and the directory - itself must exist and have read, write, and execute permissions - granted to the user that runs the web server." - } - - path ci-form - { - "<file>", - "The package CI form fragment. If specified, then its contents are - treated as an XHTML5 fragment that is inserted into the <body> - element of the CI page. If unspecified, then no CI page will be - displayed. Note that the file path must be absolute." - } - - string ci-email - { - "<email>", - "The package CI email. If specified, the CI request and result - manifests will be sent to this address. See \l{brep The \cb{build2} - Repository Interface Manual} for more information." - } - - path ci-handler - { - "<path>", - "The handler program to be executed on CI request. The handler is - executed as part of the HTTP request and is passed additional - arguments that can be specified with \cb{ci-handler-argument} - followed by the absolute path to the CI request directory. See - \l{brep The \cb{build2} Repository Interface Manual} for more - information. Note that the program path must be absolute." - } - - strings ci-handler-argument - { - "<arg>", - "Additional arguments to be passed to the CI handler program (see - \cb{ci-handler} for details). Repeat this option to specify multiple - arguments." - } - - size_t ci-handler-timeout - { - "<seconds>", - "The CI handler program timeout in seconds. If specified and the - handler does not exit in the allotted time, then it is killed and - its termination is treated as abnormal." - } - }; - - class repository_root: handler - { - string root-global-view = "packages" - { - "<service>", - "The default view to display for the global repository root. The - <service> argument is one of the supported services (\c{packages}, - \c{builds}, \c{submit}, \c{ci}, etc). The default service is - packages." - } - - string root-tenant-view = "packages" - { - "<service>" - "The default view to display for the tenant repository root. The - <service> argument is one of the supported services (\c{packages}, - \c{builds}, \c{submit}, \c{ci}, etc). The default service is - packages." - } - }; - } - - // Web handler HTTP request parameters. - // - namespace params - { - // Use parameters long names in the C++ code, short aliases (if present) - // in HTTP URL. - // - class packages - { - // Display package search result list starting from this page. - // - uint16_t page | p; - - // Package search criteria. - // - // Note that the packages parameter is renamed to '_' by the root - // handler (see the request_proxy class for details). - // - string q | _; - }; - - class package_details - { - // Display package version search result list starting from this page. - // - uint16_t page | p; - - // Package version search criteria. - // - string query | q; - - // Page form. - // - page_form form | f = page_form::brief; - }; - - class package_version_details - { - // Page form. - // - page_form form | f = page_form::brief; - }; - - class repository_details - { - // No parameters so far. - // - }; - - class build_task - { - // Package repository canonical name (note: including pkg: type). - // - vector<string> repository | r; - }; - - class build_result - { - // No parameters so far. - // - }; - - class build_log - { - // No parameters so far. - // - }; - - // All parameters are non-optional. - // - class build_force - { - // Package name. - // - string package | pn; - - // Package version. May not be url-encoded, in which case the plus - // character is considered literally (rather than as the encoded space - // character). In other words, after url-decoding the space character is - // treated the same way as the plus character. - // - // @@ Make it of the version type? Maybe after it get moved to - // libbpkg/types.hxx or at least the second use case appear. - // - string version | pv; - - // Package build configuration. - // - string configuration | cf; - - // Toolchain name. - // - string toolchain_name | tn; - - // Toolchain version. May not be url-encoded (see above). - // - string toolchain_version | tv; - - // Package rebuild reason. Must not be empty. - // - string reason; - }; - - class builds - { - // Display packages build configurations list starting from this page. - // - uint16_t page | p; - - // Package builds query filter options. - // - - // Package name wildcard. An empty value is treated the same way as *. - // - // We used to generate URLs like: - // - // https://cppget.org/?builds&pn=bbot - // - // This looked a bit verbose, so now we produce URLs like: - // - // https://cppget.org/?builds=bbot - // - // To support the already distributed URLs the name_legacy (pn) parameter - // overrides the name (builds) parameter, if present. Note that the - // builds parameter is renamed to '_' by the root handler (see the - // request_proxy class for details). - // - string name | _; - string name_legacy | pn; - - // Package version. If empty or *, then no version constraint is applied. - // Otherwise the build package version must match the value exactly. - // - string version | pv; - - // Package build toolchain in the <name>-<version> form. If *, then no - // toolchain constraint is applied. Otherwise the build toolchain name - // and version must match the value exactly. - // - string toolchain | tc = "*"; - - // Package build configuration name wildcard. An empty value is treated - // the same way as *. - // - string configuration | cf; - - // Package build machine name wildcard. An empty value is treated the - // same way as *. - // - string machine | mn; - - // Package build target wildcard. An empty value is treated the same way - // as *. - // - string target | tg; - - // Package build result. If *, then no build result constraint is - // applied. Otherwise the value is supposed to be the one of the - // following (ordered) statuses: pending, building, success, warning, - // error, abort, abnormal. The first 3 statuses are checked for equality, - // the rest - for being greater or equal. - // - string result | rs = "*"; - }; - - class build_configs - { - // Note that the build-configs parameter is renamed to '_' by the root - // handler (see the request_proxy class for details). - // - string class_name | _ = "all"; - - // Display build configurations list starting from this page. - // - uint16_t page | p; - }; - - // Parameters, except simulate, must either be all present (actual - // submission) or absent (submission form request). - // - // Note also that besides these parameters there can be others. We don't - // recognize their semantics and just save them to the submission request - // manifest. - // - class submit - { - // Package archive file name. Must be <input type="file"/>. - // - // Note that it can potentially be not just a name but a file path and - // in the client's form (e.g., Windows). - // - string archive; - - // Package archive file SHA256 checksum. - // - string sha256sum; - - // Submission simulation outcome. - // - string simulate; - }; - - // Parameters, except simulate, must either be all present (actual CI - // request) or absent (CI form request). - // - // Note also that besides these parameters there can be others. We don't - // recognize their semantics and just save them to the CI request - // manifest. - // - class ci - { - // Package repository location. - // - // Note that the ci parameter is renamed to '_' by the root handler (see - // the request_proxy class for details). - // - bpkg::repository_location repository | _; - - // Package names/versions. - // - strings package; - - // Overrides file name. Must be <input type="file"/>. - // - // Note that we don't really need this name and only check if this - // parameter is specified to detect presence of the upload. - // - string overrides; - - // Submission simulation outcome. - // - string simulate; - }; - } -} diff --git a/mod/page.cxx b/mod/page.cxx index 64e31c0..c7dc403 100644 --- a/mod/page.cxx +++ b/mod/page.cxx @@ -16,9 +16,10 @@ #include <libbutl/url.mxx> -#include <web/xhtml.hxx> -#include <web/xhtml-fragment.hxx> -#include <web/mime-url-encoding.hxx> +#include <web/xhtml/fragment.hxx> +#include <web/xhtml/serialization.hxx> + +#include <web/server/mime-url-encoding.hxx> #include <libbrep/package.hxx> #include <libbrep/package-odb.hxx> diff --git a/mod/page.hxx b/mod/page.hxx index 8c92d10..49d8608 100644 --- a/mod/page.hxx +++ b/mod/page.hxx @@ -8,7 +8,7 @@ #include <libbbot/manifest.hxx> -#include <web/xhtml-fragment.hxx> +#include <web/xhtml/fragment.hxx> #include <libbrep/types.hxx> #include <libbrep/utility.hxx> diff --git a/mod/services.cxx b/mod/services.cxx index 7739011..b17e32e 100644 --- a/mod/services.cxx +++ b/mod/services.cxx @@ -3,7 +3,7 @@ #include <ap_config.h> // AP_MODULE_DECLARE_DATA -#include <web/apache/service.hxx> +#include <web/server/apache/service.hxx> #include <libbrep/types.hxx> #include <libbrep/utility.hxx> diff --git a/mod/types-parsers.cxx b/mod/types-parsers.cxx index 70d77dd..ceaab29 100644 --- a/mod/types-parsers.cxx +++ b/mod/types-parsers.cxx @@ -3,7 +3,7 @@ #include <mod/types-parsers.hxx> -#include <mod/options.hxx> +#include <mod/module-options.hxx> using namespace std; using namespace bpkg; diff --git a/mod/types-parsers.hxx b/mod/types-parsers.hxx index a81ef90..091c868 100644 --- a/mod/types-parsers.hxx +++ b/mod/types-parsers.hxx @@ -9,7 +9,7 @@ #include <libbpkg/manifest.hxx> // repository_location -#include <web/xhtml-fragment.hxx> +#include <web/xhtml/fragment.hxx> #include <libbrep/types.hxx> #include <libbrep/utility.hxx> -- cgit v1.1