aboutsummaryrefslogtreecommitdiff
path: root/mod/mod-build-force.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'mod/mod-build-force.cxx')
-rw-r--r--mod/mod-build-force.cxx167
1 files changed, 143 insertions, 24 deletions
diff --git a/mod/mod-build-force.cxx b/mod/mod-build-force.cxx
index 72c5fdf..bdae356 100644
--- a/mod/mod-build-force.cxx
+++ b/mod/mod-build-force.cxx
@@ -1,35 +1,41 @@
// file : mod/mod-build-force.cxx -*- C++ -*-
-// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
#include <mod/mod-build-force.hxx>
-#include <algorithm> // replace()
-
#include <odb/database.hxx>
#include <odb/transaction.hxx>
-#include <web/module.hxx>
+#include <web/server/module.hxx>
#include <libbrep/build.hxx>
#include <libbrep/build-odb.hxx>
+#include <libbrep/build-package.hxx>
+#include <libbrep/build-package-odb.hxx>
-#include <mod/options.hxx>
+#include <mod/module-options.hxx>
+#include <mod/tenant-service.hxx>
using namespace std;
-using namespace bbot;
using namespace brep::cli;
using namespace odb::core;
+brep::build_force::
+build_force (const tenant_service_map& tsm)
+ : tenant_service_map_ (tsm)
+{
+}
+
// While currently the user-defined copy constructor is not required (we don't
// need to deep copy nullptr's), it is a good idea to keep the placeholder
// ready for less trivial cases.
//
brep::build_force::
-build_force (const build_force& r)
+build_force (const build_force& r, const tenant_service_map& tsm)
: database_module (r),
build_config_module (r),
- options_ (r.initialized_ ? r.options_ : nullptr)
+ options_ (r.initialized_ ? r.options_ : nullptr),
+ tenant_service_map_ (tsm)
{
}
@@ -116,10 +122,26 @@ handle (request& rq, response& rs)
version package_version (parse_version (params.version (),
"package version"));
- string& config (params.configuration ());
+ target_triplet target;
+
+ try
+ {
+ target = target_triplet (params.target ());
+ }
+ catch (const invalid_argument& e)
+ {
+ throw invalid_argument (string ("invalid target: ") + e.what ());
+ }
+
+ string& target_config (params.target_config ());
+
+ if (target_config.empty ())
+ throw invalid_argument ("no target configuration name");
- if (config.empty ())
- throw invalid_argument ("no configuration name");
+ string& package_config (params.package_config ());
+
+ if (package_config.empty ())
+ throw invalid_argument ("no package configuration name");
string& toolchain_name (params.toolchain_name ());
@@ -130,7 +152,9 @@ handle (request& rq, response& rs)
"toolchain version"));
id = build_id (package_id (move (tenant), move (p), package_version),
- move (config),
+ move (target),
+ move (target_config),
+ move (package_config),
move (toolchain_name),
toolchain_version);
}
@@ -150,42 +174,137 @@ handle (request& rq, response& rs)
// Make sure the build configuration still exists.
//
- if (build_conf_map_->find (id.configuration.c_str ()) ==
- build_conf_map_->end ())
- config_expired ("no configuration");
+ if (target_conf_map_->find (
+ build_target_config_id {id.target,
+ id.target_config_name}) ==
+ target_conf_map_->end ())
+ config_expired ("no target configuration");
// Load the package build configuration (if present), set the force flag and
// update the object's persistent state.
//
+ // If the incomplete package build is being forced to rebuild and the
+ // tenant_service_build_queued callback is associated with the package
+ // tenant, then stash the state, the build object, and the callback pointer
+ // and calculate the hints for the subsequent service `queued` notification.
+ //
+ const tenant_service_build_queued* tsq (nullptr);
+ optional<pair<tenant_service, shared_ptr<build>>> tss;
+ tenant_service_build_queued::build_queued_hints qhs;
+
+ connection_ptr conn (build_db_->connection ());
{
- transaction t (build_db_->begin ());
+ transaction t (conn->begin ());
package_build pb;
+ shared_ptr<build> b;
+
if (!build_db_->query_one<package_build> (
- query<package_build>::build::id == id, pb))
+ query<package_build>::build::id == id, pb) ||
+ (b = move (pb.build))->state == build_state::queued)
config_expired ("no package build");
- shared_ptr<build> b (pb.build);
force_state force (b->state == build_state::built
? force_state::forced
: force_state::forcing);
if (b->force != force)
{
+ // Log the force rebuild with the warning severity, truncating the
+ // reason if too long.
+ //
+ diag_record dr (warn);
+ dr << "force rebuild for ";
+
+ if (!b->tenant.empty ())
+ dr << b->tenant << ' ';
+
+ dr << b->package_name << '/' << b->package_version << ' '
+ << b->target_config_name << '/' << b->target << ' '
+ << b->package_config_name << ' '
+ << b->toolchain_name << '-' << b->toolchain_version
+ << " (state: " << to_string (b->state) << ' ' << to_string (b->force)
+ << "): ";
+
+ if (reason.size () < 50)
+ dr << reason;
+ else
+ dr << string (reason, 0, 50) << "...";
+
b->force = force;
build_db_->update (b);
- l1 ([&]{trace << "force rebuild for "
- << b->tenant << ' '
- << b->package_name << '/' << b->package_version << ' '
- << b->configuration << ' '
- << b->toolchain_name << '-' << b->toolchain_version
- << ": " << reason;});
+ if (force == force_state::forcing)
+ {
+ shared_ptr<build_tenant> t (build_db_->load<build_tenant> (b->tenant));
+
+ if (t->service)
+ {
+ auto i (tenant_service_map_.find (t->service->type));
+
+ if (i != tenant_service_map_.end ())
+ {
+ tsq = dynamic_cast<const tenant_service_build_queued*> (
+ i->second.get ());
+
+ // If we ought to call the
+ // tenant_service_build_queued::build_queued() callback, then also
+ // set the package tenant's queued timestamp to the current time
+ // to prevent the notifications race (see tenant::queued_timestamp
+ // for details).
+ //
+ if (tsq != nullptr)
+ {
+ // Calculate the tenant service hints.
+ //
+ buildable_package_count tpc (
+ build_db_->query_value<buildable_package_count> (
+ query<buildable_package_count>::build_tenant::id == t->id));
+
+ shared_ptr<build_package> p (
+ build_db_->load<build_package> (b->id.package));
+
+ qhs = tenant_service_build_queued::build_queued_hints {
+ tpc == 1, p->configs.size () == 1};
+
+ // Set the package tenant's queued timestamp.
+ //
+ t->queued_timestamp = system_clock::now ();
+ build_db_->update (t);
+
+ tss = make_pair (move (*t->service), move (b));
+ }
+ }
+ }
+ }
}
t.commit ();
}
+ // If the incomplete package build is being forced to rebuild and the
+ // tenant-associated third-party service needs to be notified about the
+ // queued builds, then call the tenant_service_build_queued::build_queued()
+ // callback function and update the service state, if requested.
+ //
+ if (tsq != nullptr)
+ {
+ assert (tss); // Wouldn't be here otherwise.
+
+ const tenant_service& ss (tss->first);
+ build& b (*tss->second);
+
+ vector<build> qbs;
+ qbs.push_back (move (b));
+
+ if (auto f = tsq->build_queued (ss,
+ qbs,
+ build_state::building,
+ qhs,
+ log_writer_))
+ update_tenant_service_state (conn, qbs.back ().tenant, f);
+ }
+
// We have all the data, so don't buffer the response content.
//
ostream& os (rs.content (200, "text/plain;charset=utf-8", false));