From ddf8c2b62fa09eb765afc0c093d0d8908f7b69e4 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Sat, 10 Oct 2015 17:48:03 +0200 Subject: Complete build command --- bpkg/pkg-fetch.cxx | 337 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 198 insertions(+), 139 deletions(-) (limited to 'bpkg/pkg-fetch.cxx') diff --git a/bpkg/pkg-fetch.cxx b/bpkg/pkg-fetch.cxx index fe8eca7..d2b0674 100644 --- a/bpkg/pkg-fetch.cxx +++ b/bpkg/pkg-fetch.cxx @@ -23,190 +23,249 @@ using namespace butl; namespace bpkg { - void - pkg_fetch (const pkg_fetch_options& o, cli::scanner& args) + + static shared_ptr + pkg_fetch (dir_path c, + transaction& t, + string n, + version v, + path a, + repository_location rl, + bool purge) { tracer trace ("pkg_fetch"); - dir_path c (o.directory ()); - level4 ([&]{trace << "configuration: " << c;}); - - database db (open (c, trace)); - transaction t (db.begin ()); - session s; + database& db (t.database ()); + tracer_guard tg (db, trace); - path a; - auto_rm arm; - bool purge; - repository_location rl; - shared_ptr sp; - - // Check if the package already exists in this configuration and - // diagnose all the illegal cases. We want to do this as soon as - // the package name is known which happens at different times - // depending on whether we are dealing with an existing archive - // or fetching one. + // Make the archive and configuration paths absolute and normalized. + // If the archive is inside the configuration, use the relative path. + // This way we can move the configuration around. // - auto check = [&o, &c, &db] (const string& n) - -> shared_ptr - { - shared_ptr p (db.find (n)); - - if (p != nullptr) - { - bool s (p->state == package_state::fetched || - p->state == package_state::unpacked); - - if (!o.replace () || !s) - { - diag_record dr (fail); - - dr << "package " << n << " already exists in configuration " << c << - info << "version: " << p->version << ", state: " << p->state; - - if (s) // Suitable state for replace? - dr << info << "use 'pkg-fetch --replace|-r' to replace"; - } - } + c.complete ().normalize (); + a.complete ().normalize (); - return p; - }; + if (a.sub (c)) + a = a.leaf (c); - if (o.existing ()) + shared_ptr p (db.find (n)); + if (p != nullptr) { - if (!args.more ()) - fail << "archive path argument expected" << - info << "run 'bpkg help pkg-fetch' for more information"; - - a = path (args.next ()); - - if (!exists (a)) - fail << "archive file '" << a << "' does not exist"; + // Clean up the source directory and archive of the package we are + // replacing. Once this is done, there is no going back. If things + // go badly, we can't simply abort the transaction. + // + pkg_purge_fs (c, t, p); - purge = o.purge (); + p->version = move (v); + p->state = package_state::fetched; + p->repository = move (rl); + p->archive = move (a); + p->purge_archive = purge; - // Use the special root repository as the repository of this - // package. - // - rl = repository_location (); + db.update (p); } else { - if (!args.more ()) - fail << "package name/version argument expected" << - info << "run 'bpkg help pkg-fetch' for more information"; - - const char* arg (args.next ()); - string n (parse_package_name (arg)); - version v (parse_package_version (arg)); - - if (v.empty ()) - fail << "package version expected" << - info << "run 'bpkg help pkg-fetch' for more information"; - - // Check/diagnose an already existing package. + // Add the package to the configuration. // - sp = check (n); + p.reset (new selected_package { + move (n), + move (v), + package_state::fetched, + move (rl), + move (a), + purge, + nullopt, // No source directory yet. + false, + nullopt, // No output directory yet. + {}}); // No prerequisites captured yet. - if (db.query_value () == 0) - fail << "configuration " << c << " has no repositories" << - info << "use 'bpkg rep-add' to add a repository"; + db.persist (p); + } - if (db.query_value () == 0) - fail << "configuration " << c << " has no available packages" << - info << "use 'bpkg rep-fetch' to fetch available packages list"; + t.commit (); + return p; + } - shared_ptr ap ( - db.find (available_package_id (n, v))); + // Check if the package already exists in this configuration and + // diagnose all the illegal cases. We want to do this as soon as + // the package name is known which happens at different times + // depending on whether we are dealing with an existing archive + // or fetching one. + // + static void + pkg_fetch_check (const dir_path& c, + transaction& t, + const string& n, + bool replace) + { + tracer trace ("pkg_fetch_check"); - if (ap == nullptr) - fail << "package " << n << " " << v << " is not available"; + database& db (t.database ()); + tracer_guard tg (db, trace); - // Pick a repository. Preferring a local one over the remotes seems - // like a sensible thing to do. - // - const package_location* pl (&ap->locations.front ()); + if (shared_ptr p = db.find (n)) + { + bool s (p->state == package_state::fetched || + p->state == package_state::unpacked); - for (const package_location& l: ap->locations) + if (!replace || !s) { - if (!l.repository.load ()->location.remote ()) - { - pl = &l; - break; - } - } + diag_record dr (fail); - if (verb > 1) - text << "fetching " << pl->location.leaf () << " " - << "from " << pl->repository->name; + dr << "package " << n << " already exists in configuration " << c << + info << "version: " << p->version << ", state: " << p->state; - rl = pl->repository->location; - a = fetch_archive (o, rl, pl->location, c); - arm = auto_rm (a); - purge = true; + if (s) // Suitable state for replace? + dr << info << "use 'pkg-fetch --replace|-r' to replace"; + } } + } - level4 ([&]{trace << "package archive: " << a << ", purge: " << purge;}); + shared_ptr + pkg_fetch (const common_options& co, + const dir_path& c, + transaction& t, + path a, + bool replace, + bool purge) + { + tracer trace ("pkg_fetch"); + + if (!exists (a)) + fail << "archive file '" << a << "' does not exist"; + + level4 ([&]{trace << "archive: " << a << ", purge: " << purge;}); // Verify archive is a package and get its manifest. // - package_manifest m (pkg_verify (o, a)); + package_manifest m (pkg_verify (co, a)); level4 ([&]{trace << m.name << " " << m.version;}); // Check/diagnose an already existing package. // - if (o.existing ()) - sp = check (m.name); + pkg_fetch_check (c, t, m.name, replace); - // Make the archive and configuration paths absolute and normalized. - // If the archive is inside the configuration, use the relative path. - // This way we can move the configuration around. + // Use the special root repository as the repository of this + // package. // - c.complete ().normalize (); - a.complete ().normalize (); + return pkg_fetch (c, + t, + move (m.name), + move (m.version), + move (a), + repository_location (), + purge); + } - if (a.sub (c)) - a = a.leaf (c); + shared_ptr + pkg_fetch (const common_options& co, + const dir_path& c, + transaction& t, + string n, + version v, + bool replace) + { + tracer trace ("pkg_fetch"); + + database& db (t.database ()); + tracer_guard tg (db, trace); + + // Check/diagnose an already existing package. + // + pkg_fetch_check (c, t, n, replace); + + if (db.query_value () == 0) + fail << "configuration " << c << " has no repositories" << + info << "use 'bpkg rep-add' to add a repository"; + + if (db.query_value () == 0) + fail << "configuration " << c << " has no available packages" << + info << "use 'bpkg rep-fetch' to fetch available packages list"; + + shared_ptr ap ( + db.find (available_package_id (n, v))); + + if (ap == nullptr) + fail << "package " << n << " " << v << " is not available"; - if (sp != nullptr) + // Pick a repository. Preferring a local one over the remotes seems + // like a sensible thing to do. + // + const package_location* pl (&ap->locations.front ()); + + for (const package_location& l: ap->locations) { - // Clean up the source directory and archive of the package we are - // replacing. Once this is done, there is no going back. If things - // go badly, we can't simply abort the transaction. - // - pkg_purge_fs (c, t, sp); + if (!l.repository.load ()->location.remote ()) + { + pl = &l; + break; + } + } + + if (verb > 1) + text << "fetching " << pl->location.leaf () << " " + << "from " << pl->repository->name; + + path a (fetch_archive (co, pl->repository->location, pl->location, c)); + auto_rm arm (a); + + shared_ptr p ( + pkg_fetch (c, + t, + move (n), + move (v), + move (a), + pl->repository->location, + true)); // Purge. + + arm.cancel (); + return p; + } + + void + pkg_fetch (const pkg_fetch_options& o, cli::scanner& args) + { + tracer trace ("pkg_fetch"); + + dir_path c (o.directory ()); + level4 ([&]{trace << "configuration: " << c;}); + + database db (open (c, trace)); + transaction t (db.begin ()); + session s; - sp->version = move (m.version); - sp->state = package_state::fetched; - sp->repository = move (rl); - sp->archive = move (a); - sp->purge_archive = purge; + shared_ptr p; + + // pkg_fetch() in both cases commits the transaction. + // + if (o.existing ()) + { + if (!args.more ()) + fail << "archive path argument expected" << + info << "run 'bpkg help pkg-fetch' for more information"; - db.update (sp); + p = pkg_fetch (o, c, t, path (args.next ()), o.replace (), o.purge ()); } else { - // Add the package to the configuration. - // - sp.reset (new selected_package { - move (m.name), - move (m.version), - package_state::fetched, - move (rl), - move (a), - purge, - nullopt, // No source directory yet. - false, - nullopt, // No output directory yet. - {}}); // No prerequisites captured yet. + if (!args.more ()) + fail << "package name/version argument expected" << + info << "run 'bpkg help pkg-fetch' for more information"; - db.persist (sp); - } + const char* arg (args.next ()); + string n (parse_package_name (arg)); + version v (parse_package_version (arg)); - t.commit (); - arm.cancel (); + if (v.empty ()) + fail << "package version expected" << + info << "run 'bpkg help pkg-fetch' for more information"; + + p = pkg_fetch (o, c, t, move (n), move (v), o.replace ()); + } if (verb) - text << "fetched " << sp->name << " " << sp->version; + text << "fetched " << p->name << " " << p->version; } } -- cgit v1.1