aboutsummaryrefslogtreecommitdiff
path: root/load
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2016-03-07 19:11:31 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2016-03-09 16:22:06 +0300
commited0dd177c63bb7758e8633ffe26de2a8bc315d1b (patch)
tree0d4c9b987ef79a96e1509bceb98e8d254bd99669 /load
parentb72424fca7a6af6ff7921101c450850fef875152 (diff)
Display sha256sum on the package version details page
Diffstat (limited to 'load')
-rw-r--r--load/buildfile3
-rw-r--r--load/load.cli37
-rw-r--r--load/load.cxx172
3 files changed, 139 insertions, 73 deletions
diff --git a/load/buildfile b/load/buildfile
index 6b72dae..333c091 100644
--- a/load/buildfile
+++ b/load/buildfile
@@ -15,6 +15,7 @@ exe{brep-load}: \
../brep/lib{brep} $libs
cli.options += -I $src_root --include-with-brackets --include-prefix load \
---guard-prefix LOAD
+--guard-prefix LOAD --generate-specifier --page-usage print_ --ansi-color \
+--long-usage
{hxx ixx cxx}{load-options}: cli{load}
diff --git a/load/load.cli b/load/load.cli
index 751d1bd..5c30c14 100644
--- a/load/load.cli
+++ b/load/load.cli
@@ -2,6 +2,7 @@
// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
+include <vector>;
include <string>;
include <cstdint>; // uint16_t
@@ -21,9 +22,9 @@ include <cstdint>; // uint16_t
\h|DESCRIPTION|
\cb{brep-load} reads the list of repositories from the specified
- configuration <file>, fetches their manifest files, and loads the repository
- and package information into the database, suitable for consumption by the
- \cb{brep} web module.
+ configuration <file>, fetches their manifest files, and loads the
+ repository and package information into the database, suitable for
+ consumption by the \cb{brep} web module.
Note that \cb{brep-load} expects the database schema to have already been
created using \l{brep-migrate(1)}."
@@ -67,6 +68,36 @@ class options
"Database port number. If not specified, the default port is used."
}
+ std::string --pager // String to allow empty value.
+ {
+ "<path>",
+ "The pager program to be used to show long text. Commonly used pager
+ programs are \cb{less} and \cb{more}. You can also specify additional
+ options that should be passed to the pager program with
+ \cb{--pager-option}. If an empty string is specified as the pager
+ program, then no pager will be used. If the pager program is not
+ explicitly specified, then \cb{brep-load} will try to use \cb{less}. If
+ it is not available, then no pager will be used."
+ }
+
+ std::vector<std::string> --pager-option
+ {
+ "<opt>",
+ "Additional option to be passed to the pager program. See \cb{--pager}
+ for more information on the pager program. Repeat this option to
+ specify multiple pager options."
+ }
+
bool --help {"Print usage information and exit."}
bool --version {"Print version and exit."}
};
+
+"\h|EXIT STATUS|
+
+\cb{0} Successful termination.
+
+\cb{1} \cb{brep-load} or \l{brep-migrate(1)} instance is running. Try
+ again.
+
+\cb{2} Fatal error.
+"
diff --git a/load/load.cxx b/load/load.cxx
index b4dcd11..7556449 100644
--- a/load/load.cxx
+++ b/load/load.cxx
@@ -2,7 +2,6 @@
// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
-#include <sstream>
#include <fstream>
#include <iostream>
#include <algorithm> // find(), find_if()
@@ -14,6 +13,7 @@
#include <odb/pgsql/database.hxx>
+#include <butl/pager>
#include <butl/filesystem>
#include <bpkg/manifest-parser> // manifest_parsing
@@ -34,15 +34,12 @@ using namespace butl;
using namespace bpkg;
using namespace brep;
-static void
-usage (ostream& os)
-{
- os << "Usage: brep-load [options] <file>" << endl
- << "File lists internal repositories." << endl
- << "Options:" << endl;
+// Operation failed, diagnostics has already been issued.
+//
+struct failed: std::exception {};
- options::print_usage (os);
-}
+static const char* help_info (
+ " info: run 'brep-load --help' for more information");
static inline bool
space (char c) noexcept
@@ -75,7 +72,10 @@ load_repositories (path p)
ifstream ifs (p.string ());
if (!ifs.is_open ())
- throw ifstream::failure (p.string () + ": unable to open");
+ {
+ cerr << "error: unable to open " << p << " in read mode" << endl;
+ throw failed ();
+ }
ifs.exceptions (ifstream::badbit);
@@ -108,11 +108,13 @@ load_repositories (path p)
auto pb (i); // Location begin.
skip (false); // Find end of location.
- auto bad_line ([&p, l, &pb, &b](const string& d) {
- ostringstream os;
- os << p << ':' << l << ':' << pb - b + 1 << ": error: " << d;
- throw runtime_error (os.str ());
- });
+ auto bad_line = [&p, l, &pb, &b](const string& d)
+ {
+ cerr << p << ':' << l << ':' << pb - b + 1 << ": error: " << d
+ << endl;
+
+ throw failed ();
+ };
repository_location location;
@@ -186,7 +188,8 @@ load_repositories (path p)
}
catch (const ifstream::failure&)
{
- throw ifstream::failure (p.string () + ": io failure");
+ cerr << "error: unable to read " << p << endl;
+ throw failed ();
}
return repos;
@@ -208,7 +211,8 @@ changed (const internal_repositories& repos, database& db)
db.find<repository> (r.location.canonical_name ()));
if (pr == nullptr || r.location.string () != pr->location.string () ||
- r.display_name != pr->display_name || r.local_path != pr->local_path ||
+ r.display_name != pr->display_name ||
+ r.local_path != pr->local_path ||
file_mtime (r.packages_path ()) != pr->packages_timestamp ||
file_mtime (r.repositories_path ()) != pr->repositories_timestamp ||
!pr->internal)
@@ -224,8 +228,8 @@ changed (const internal_repositories& repos, database& db)
//
return
!db.query<repository> (
- query::internal && !query::name.in_range (names.begin (), names.end ())).
- empty ();
+ query::internal &&
+ !query::name.in_range (names.begin (), names.end ())).empty ();
}
static timestamp
@@ -233,7 +237,10 @@ manifest_stream (const path& p, ifstream& f)
{
f.open (p.string ());
if (!f.is_open ())
- throw ifstream::failure (p.string () + ": unable to open");
+ {
+ cerr << "error: unable to open " << p << " in read mode" << endl;
+ throw failed ();
+ }
f.exceptions (ifstream::badbit | ifstream::failbit);
return file_mtime (p);
@@ -268,7 +275,13 @@ load_packages (const shared_ptr<repository>& rp, database& db)
for (auto& pm: pkm)
{
- shared_ptr<package> p (db.find<package> (package_id (pm.name, pm.version)));
+ shared_ptr<package> p (
+ db.find<package> (package_id (pm.name, pm.version)));
+
+ // sha256sum should always be present if the package manifest comes from
+ // the 'packages' file.
+ //
+ assert (pm.sha256sum);
if (p == nullptr)
{
@@ -338,6 +351,7 @@ load_packages (const shared_ptr<repository>& rp, database& db)
move (ds),
move (pm.requirements),
move (pm.location),
+ move (pm.sha256sum),
rp);
}
else
@@ -349,16 +363,19 @@ load_packages (const shared_ptr<repository>& rp, database& db)
}
else
{
- // @@ Need to ensure that the same packages coming from different
- // repositories are equal. Probably will invent hashsum at some point
- // for this purpose.
- //
-
// As soon as internal repositories get loaded first, the internal
// package can duplicate an internal package only.
//
assert (!rp->internal || p->internal ());
+ if (rp->internal && pm.sha256sum != p->sha256sum)
+ cerr << "warning: sha256sum mismatch for package " << p->id.name
+ << " " << p->version << endl
+ << " info: " << p->internal_repository.load ()->location
+ << " has " << *p->sha256sum << endl
+ << " info: " << rp->location << " has " << *pm.sha256sum
+ << endl;
+
p->other_repositories.push_back (rp);
db.update (p);
}
@@ -402,7 +419,8 @@ load_repositories (const shared_ptr<repository>& rp, database& db)
for (auto& rm: rpm)
{
- if (rm.effective_role () == repository_role::prerequisite && !rp->internal)
+ if (rm.effective_role () == repository_role::prerequisite &&
+ !rp->internal)
continue; // Ignore the external repository prerequisite entry.
if (rm.effective_role () == repository_role::base)
@@ -449,12 +467,12 @@ load_repositories (const shared_ptr<repository>& rp, database& db)
auto bad_location (
[&rp, &rm]()
{
- ostringstream o;
- o << "invalid location '" << rm.location.string ()
- << "' of the prerequisite repository for internal "
- "repository '" << rp->location.string () << "'";
+ cerr << "error: invalid prerequisite repository location "
+ << rm.location << endl
+ << " info: base (internal) repository location is "
+ << rp->location << endl;
- throw runtime_error (o.str ());
+ throw failed ();
});
try
@@ -508,12 +526,12 @@ load_repositories (const shared_ptr<repository>& rp, database& db)
}
catch (const invalid_path&)
{
- ostringstream o;
- o << "can't normalize local path'" << lp.string ()
- << "' of the prerequisite repository for internal "
- "repository '" << rp->location.string () << "'";
+ cerr << "error: can't normalize prerequisite repository local path '"
+ << lp << "'" << endl
+ << " info: base (internal) repository location is "
+ << rp->location << endl;
- throw runtime_error (o.str ());
+ throw failed ();
}
}
@@ -536,7 +554,8 @@ find (const lazy_shared_ptr<repository>& r,
assert (r != nullptr);
const auto& o (p.other_repositories);
- if (r == p.internal_repository || find (o.begin (), o.end (), r) != o.end ())
+ if (r == p.internal_repository ||
+ find (o.begin (), o.end (), r) != o.end ())
return true;
auto rp (r.load ());
@@ -629,17 +648,18 @@ resolve_dependencies (package& p, database& db)
if (d.package.object_id ().version.empty ())
{
- ostringstream o;
- o << "can't resolve dependency " << d << " of the package "
- << p.id.name << " " << p.version.string ()
- << " (" << p.internal_repository.load ()->name << ")";
+ cerr << "error: can't resolve dependency " << d << " of the package "
+ << p.id.name << " " << p.version << endl
+ << " info: repository "
+ << p.internal_repository.load ()->location
+ << " appears to be broken" << endl;
// Practically it is enough to resolve at least one dependency
// alternative to build a package. Meanwhile here we consider an error
// specifying in the manifest file an alternative which can't be
// resolved.
//
- throw runtime_error (o.str ());
+ throw failed ();
}
}
}
@@ -650,14 +670,15 @@ resolve_dependencies (package& p, database& db)
using package_ids = vector<package_id>;
// Ensure the package dependency chain do not contain the package id. Throw
-// runtime_error otherwise. Continue the chain with the package id and call
-// itself recursively for each prerequisite of the package. Should be called
-// once per internal package.
+// failed otherwise. Continue the chain with the package id and call itself
+// recursively for each prerequisite of the package. Should be called once per
+// internal package.
//
// @@ This should probably be eventually moved to bpkg.
//
static void
-detect_dependency_cycle (const package_id& id, package_ids& chain, database& db)
+detect_dependency_cycle (
+ const package_id& id, package_ids& chain, database& db)
{
// Package of one version depending on the same package of another version
// is something obscure. So the comparison is made up to a package name.
@@ -667,11 +688,10 @@ detect_dependency_cycle (const package_id& id, package_ids& chain, database& db)
if (i != chain.end ())
{
- ostringstream o;
- o << "package dependency cycle: ";
+ cerr << "error: package dependency cycle: ";
auto prn (
- [&o, &db](const package_id& id)
+ [&db](const package_id& id)
{
shared_ptr<package> p (db.load<package> (id));
assert (p->internal () || !p->other_repositories.empty ());
@@ -681,17 +701,18 @@ detect_dependency_cycle (const package_id& id, package_ids& chain, database& db)
? p->internal_repository.load ()
: p->other_repositories[0].load ());
- o << id.name << " " << p->version.string () << " (" << r->name << ")";
+ cerr << id.name << " " << p->version << " (" << r->name << ")";
});
for (; i != chain.end (); ++i)
{
prn (*i);
- o << " -> ";
+ cerr << " -> ";
}
prn (id);
- throw runtime_error (o.str ());
+ cerr << endl;
+ throw failed ();
}
chain.push_back (id);
@@ -731,22 +752,30 @@ try
//
if (ops.help ())
{
- usage (cout);
- return 0;
+ pager p ("brep-load help",
+ false,
+ ops.pager_specified () ? &ops.pager () : nullptr,
+ &ops.pager_option ());
+
+ print_usage (p.stream ());
+
+ // If the pager failed, assume it has issued some diagnostics.
+ //
+ return p.wait () ? 0 : 2;
}
if (argc < 2)
{
- cerr << "<file> argument not provided" << endl;
- usage (cerr);
- return 1;
+ cerr << "error: configuration file path argument expected" << endl
+ << help_info << endl;
+ return 2;
}
if (argc > 2)
{
- cerr << "unexpected argument encountered" << endl;
- usage (cerr);
- return 1;
+ cerr << "error: unexpected argument encountered" << endl
+ << help_info << endl;
+ return 2;
}
odb::pgsql::database db (ops.db_user (),
@@ -766,8 +795,9 @@ try
//
if (schema_catalog::current_version (db) != db.schema_version ())
{
- cerr << "database schema differs from the current one" << endl;
- return 1;
+ cerr << "error: database schema differs from the current one" << endl
+ << " info: use brep-migrate to migrate the database" << endl;
+ return 2;
}
// Load the description of all the internal repositories from the
@@ -827,22 +857,26 @@ try
}
t.commit ();
+ return 0;
}
catch (const database_locked&)
{
cerr << "brep-load or brep-migrate instance is running" << endl;
- return 2;
+ return 1;
}
catch (const cli::exception& e)
{
- cerr << e << endl;
- usage (cerr);
- return 1;
+ cerr << "error: " << e << endl << help_info << endl;
+ return 2;
+}
+catch (const failed&)
+{
+ return 2; // Diagnostics has already been issued.
}
// Fully qualified to avoid ambiguity with odb exception.
//
catch (const std::exception& e)
{
- cerr << e.what () << endl;
- return 1;
+ cerr << "error: " << e.what () << endl;
+ return 2;
}