aboutsummaryrefslogtreecommitdiff
path: root/mod/mod-package-version-details.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'mod/mod-package-version-details.cxx')
-rw-r--r--mod/mod-package-version-details.cxx268
1 files changed, 237 insertions, 31 deletions
diff --git a/mod/mod-package-version-details.cxx b/mod/mod-package-version-details.cxx
index 3a1ce0a..91923e5 100644
--- a/mod/mod-package-version-details.cxx
+++ b/mod/mod-package-version-details.cxx
@@ -9,6 +9,8 @@
#include <odb/database.hxx>
#include <odb/transaction.hxx>
+#include <libbutl/filesystem.hxx> // dir_iterator, dir_entry
+
#include <web/server/module.hxx>
#include <web/server/mime-url-encoding.hxx>
@@ -47,6 +49,12 @@ init (scanner& s)
options_ = make_shared<options::package_version_details> (
s, unknown_mode::fail, unknown_mode::fail);
+ // Verify that the bindist-url option is specified when necessary.
+ //
+ if (options_->bindist_root_specified () &&
+ !options_->bindist_url_specified ())
+ fail << "bindist-url must be specified if bindist-root is specified";
+
database_module::init (static_cast<const options::package_db&> (*options_),
options_->package_db_retry ());
@@ -181,20 +189,20 @@ handle (request& rq, response& rs)
s << H2 << pkg->summary << ~H2;
- if (const optional<string>& d = pkg->description)
+ if (const optional<typed_text>& d = pkg->package_description
+ ? pkg->package_description
+ : pkg->description)
{
const string id ("description");
const string what (title + " description");
s << (full
- ? DIV_TEXT (*d, *
- pkg->description_type,
+ ? DIV_TEXT (*d,
true /* strip_title */,
id,
what,
error)
: DIV_TEXT (*d,
- *pkg->description_type,
true /* strip_title */,
options_->package_description (),
url (!full, id),
@@ -445,7 +453,10 @@ handle (request& rq, response& rs)
//
// Print test dependencies of the specific type.
//
- auto print_tests = [&pkg, &s, &print_dependency] (test_dependency_type dt)
+ auto print_tests = [&pkg,
+ &s,
+ &print_dependency,
+ full] (test_dependency_type dt)
{
string id;
@@ -484,6 +495,20 @@ handle (request& rq, response& rs)
print_dependency (td);
+ if (td.enable || td.reflect)
+ {
+ if (full)
+ {
+ if (td.enable)
+ s << " ? (" << *td.enable << ')';
+
+ if (td.reflect)
+ s << ' ' << *td.reflect;
+ }
+ else
+ s << " ...";
+ }
+
s << ~SPAN
<< ~TD
<< ~TR;
@@ -509,16 +534,24 @@ handle (request& rq, response& rs)
{
package_db_->load (*pkg, pkg->build_section);
- // If the package has a singe build configuration class expression with
- // exactly one underlying class and the class is none, then we just drop
- // the page builds section altogether.
+ // If all package build configurations has a singe effective build
+ // configuration class expression with exactly one underlying class and
+ // the class is none, then we just drop the page builds section
+ // altogether.
//
- if (pkg->builds.size () == 1)
+ builds = false;
+
+ for (const package_build_config& pc: pkg->build_configs)
{
- const build_class_expr& be (pkg->builds[0]);
+ const build_class_exprs& exprs (pc.effective_builds (pkg->builds));
- builds = be.underlying_classes.size () != 1 ||
- be.underlying_classes[0] != "none";
+ if (exprs.size () != 1 ||
+ exprs[0].underlying_classes.size () != 1 ||
+ exprs[0].underlying_classes[0] != "none")
+ {
+ builds = true;
+ break;
+ }
}
}
@@ -526,12 +559,174 @@ handle (request& rq, response& rs)
t.commit ();
+ // Display the binary distribution packages for this tenant, package, and
+ // version, if present. Print the archive distributions last.
+ //
+ if (options_->bindist_root_specified ())
+ {
+ // Collect all the available package configurations by iterating over the
+ // <distribution> and <os-release> subdirectories and the <package-config>
+ // symlinks in the following filesystem hierarchy:
+ //
+ // [<tenant>/]<distribution>/<os-release>/<project>/<package>/<version>/<package-config>
+ //
+ // Note that it is possible that new directories and symlinks are created
+ // and/or removed while we iterate over the filesystem entries in the
+ // above hierarchy, which may result with system_error exceptions. If that
+ // happens, we just ignore such exceptions, trying to collect what we can.
+ //
+ const dir_path& br (options_->bindist_root ());
+
+ dir_path d (br);
+
+ if (!tenant.empty ())
+ d /= tenant;
+
+ // Note that distribution and os_release are simple paths and the
+ // config_symlink and config_dir are relative to the bindist root
+ // directory.
+ //
+ struct bindist_config
+ {
+ dir_path distribution; // debian, fedora, archive
+ dir_path os_release; // fedora37, windows10
+ path symlink; // .../x86_64, .../x86_64-release
+ dir_path directory; // .../x86_64-2023-05-11T10:13:43Z
+
+ bool
+ operator< (const bindist_config& v)
+ {
+ if (int r = distribution.compare (v.distribution))
+ return distribution.string () == "archive" ? false :
+ v.distribution.string () == "archive" ? true :
+ r < 0;
+
+ if (int r = os_release.compare (v.os_release))
+ return r < 0;
+
+ return symlink < v.symlink;
+ }
+ };
+
+ vector<bindist_config> configs;
+
+ if (dir_exists (d))
+ try
+ {
+ for (const dir_entry& de: dir_iterator (d, dir_iterator::ignore_dangling))
+ {
+ if (de.type () != entry_type::directory)
+ continue;
+
+ // Distribution directory.
+ //
+ dir_path dd (path_cast<dir_path> (de.path ()));
+
+ try
+ {
+ dir_path fdd (d / dd);
+
+ for (const dir_entry& re:
+ dir_iterator (fdd, dir_iterator::ignore_dangling))
+ {
+ if (re.type () != entry_type::directory)
+ continue;
+
+ // OS release directory.
+ //
+ dir_path rd (path_cast<dir_path> (re.path ()));
+
+ // Package version directory.
+ //
+ dir_path vd (fdd /
+ rd /
+ dir_path (pkg->project.string ()) /
+ dir_path (pn.string ()) /
+ dir_path (sver));
+
+ try
+ {
+ for (const dir_entry& ce:
+ dir_iterator (vd, dir_iterator::ignore_dangling))
+ {
+ if (ce.ltype () != entry_type::symlink)
+ continue;
+
+ // Skip the "hidden" symlinks which may potentially be used by
+ // the upload handlers until they expose the finalized upload
+ // directory.
+ //
+ const path& cl (ce.path ());
+ if (cl.string () [0] == '.')
+ continue;
+
+ try
+ {
+ path fcl (vd / cl);
+ dir_path cd (path_cast<dir_path> (followsymlink (fcl)));
+
+ if (cd.sub (br))
+ configs.push_back (
+ bindist_config {dd, rd, fcl.leaf (br), cd.leaf (br)});
+ }
+ catch (const system_error&) {}
+ }
+ }
+ catch (const system_error&) {}
+ }
+ }
+ catch (const system_error&) {}
+ }
+ }
+ catch (const system_error&) {}
+
+ // Sort and print collected package configurations, if any.
+ //
+ if (!configs.empty ())
+ {
+ sort (configs.begin (), configs.end ());
+
+ s << H3 << "Binaries" << ~H3
+ << TABLE(ID="binaries")
+ << TBODY;
+
+ for (const bindist_config& c: configs)
+ {
+ s << TR(CLASS="binaries")
+ << TD << SPAN(CLASS="value") << c.distribution << ~SPAN << ~TD
+ << TD << SPAN(CLASS="value") << c.os_release << ~SPAN << ~TD
+ << TD
+ << SPAN(CLASS="value")
+ << A
+ << HREF
+ << options_->bindist_url () << '/' << c.symlink
+ << ~HREF
+ << c.symlink.leaf ()
+ << ~A
+ << " ("
+ << A
+ << HREF
+ << options_->bindist_url () << '/' << c.directory
+ << ~HREF
+ << "snapshot"
+ << ~A
+ << ")"
+ << ~SPAN
+ << ~TD
+ << ~TR;
+ }
+
+ s << ~TBODY
+ << ~TABLE;
+ }
+ }
+
if (builds)
{
s << H3 << "Builds" << ~H3
<< DIV(ID="builds");
- auto exclude = [&pkg, this] (const build_package_config& pc,
+ auto exclude = [&pkg, this] (const package_build_config& pc,
const build_target_config& tc,
string* rs = nullptr)
{
@@ -547,13 +742,7 @@ handle (request& rq, response& rs)
// Query toolchains seen for the package tenant to produce a list of the
// unbuilt configuration/toolchain combinations.
//
- // Note that it only make sense to print those unbuilt configurations that
- // may still be built. That's why we leave the toolchains list empty if
- // the package tenant is achieved.
- //
vector<pair<string, version>> toolchains;
-
- if (!tn->archived)
{
using query = query<toolchain>;
@@ -564,7 +753,9 @@ handle (request& rq, response& rs)
"ORDER BY" + query::build::id.toolchain_name +
order_by_version_desc (query::build::id.toolchain_version,
false /* first */)))
+ {
toolchains.emplace_back (move (t.name), move (t.version));
+ }
}
// Compose the configuration filtering sub-query and collect unbuilt
@@ -576,13 +767,13 @@ handle (request& rq, response& rs)
query sq (false);
set<config_toolchain> unbuilt_configs;
- for (const build_package_config& pc: pkg->build_configs)
+ for (const package_build_config& pc: pkg->build_configs)
{
for (const auto& bc: *target_conf_map_)
{
const build_target_config& tc (*bc.second);
- if (belongs (tc, "all") && !exclude (pc, tc))
+ if (!belongs (tc, "hidden") && !exclude (pc, tc))
{
const build_target_config_id& id (bc.first);
@@ -611,15 +802,24 @@ handle (request& rq, response& rs)
// Print the package built configurations in the time-descending order.
//
for (auto& b: build_db_->query<build> (
- (query::id.package == pkg->id && sq) +
+ (query::id.package == pkg->id && query::state != "queued" && sq) +
"ORDER BY" + query::timestamp + "DESC"))
{
string ts (butl::to_string (b.timestamp,
"%Y-%m-%d %H:%M:%S %Z",
true /* special */,
true /* local */) +
- " (" + butl::to_string (now - b.timestamp, false) + " ago)");
+ " (" + butl::to_string (now - b.timestamp, false) + " ago");
+
+ if (tn->archived)
+ ts += ", archived";
+
+ ts += ')';
+ // @@ Note that here we also load result logs which we don't need.
+ // Probably we should invent some table view to only load operation
+ // names and statuses.
+ //
if (b.state == build_state::built)
build_db_->load (b, b.results_section);
@@ -686,7 +886,7 @@ handle (request& rq, response& rs)
//
if (!tn->interactive)
{
- for (const build_package_config& pc: pkg->build_configs)
+ for (const package_build_config& pc: pkg->build_configs)
{
for (const auto& tc: *target_conf_)
{
@@ -717,19 +917,25 @@ handle (request& rq, response& rs)
s << ~DIV;
}
- const string& ch (pkg->changes);
-
- if (!ch.empty ())
+ if (const optional<typed_text>& c = pkg->changes)
{
const string id ("changes");
+ const string what (title + " changes");
s << H3 << "Changes" << ~H3
<< (full
- ? PRE_TEXT (ch, id)
- : PRE_TEXT (ch,
+ ? DIV_TEXT (*c,
+ false /* strip_title */,
+ id,
+ what,
+ error)
+ : DIV_TEXT (*c,
+ false /* strip_title */,
options_->package_changes (),
- url (!full, "changes"),
- id));
+ url (!full, id),
+ id,
+ what,
+ error));
}
s << ~DIV