aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--INSTALL-DEV12
-rw-r--r--brep/package37
-rw-r--r--brep/package.cxx9
-rw-r--r--brep/package.xml9
-rw-r--r--load/buildfile8
-rw-r--r--load/load.cli26
-rw-r--r--load/load.cxx314
-rw-r--r--load/types-parsers28
-rw-r--r--load/types-parsers.cxx43
-rw-r--r--mod/mod-repository-details.cxx38
-rw-r--r--tests/load/1/math/libexp-1~1.2+1.tar.gzbin0 -> 291 bytes
-rw-r--r--tests/load/1/math/libfoo-1.0.tar.gzbin0 -> 258 bytes
-rw-r--r--tests/load/1/math/libfoo-1.2.4+1.tar.gzbin0 -> 866 bytes
-rw-r--r--tests/load/1/math/libstudxml-1.0.0+1.tar.gzbin0 -> 429 bytes
-rw-r--r--tests/load/1/math/packages78
-rw-r--r--tests/load/1/math/repositories2
-rw-r--r--tests/load/1/stable/libfoo-1.0.tar.gzbin0 -> 258 bytes
-rw-r--r--tests/load/1/stable/libfoo-1.2.2-alpha.1.tar.gzbin0 -> 340 bytes
-rw-r--r--tests/load/1/stable/libfoo-1.2.2.tar.gzbin0 -> 301 bytes
-rw-r--r--tests/load/1/stable/libfoo-1.2.3+4.tar.gzbin0 -> 291 bytes
-rw-r--r--tests/load/1/stable/libfoo-1.2.4.tar.gzbin0 -> 351 bytes
-rw-r--r--tests/load/1/stable/packages50
-rw-r--r--tests/load/1/stable/repositories34
-rw-r--r--tests/load/1/stable/signature13
-rw-r--r--tests/load/cert.pem30
-rwxr-xr-xtests/load/cert.sh17
-rw-r--r--tests/load/driver.cxx163
-rw-r--r--tests/load/key.pem51
-rw-r--r--tests/load/openssl.cnf22
-rw-r--r--tests/load/pkg/1/dev.cppget.org/signed/packages2
-rw-r--r--tests/load/pkg/1/dev.cppget.org/signed/repositories35
-rw-r--r--tests/load/pkg/1/dev.cppget.org/signed/signature13
-rw-r--r--tests/load/pkg/1/dev.cppget.org/unsigned/packages2
-rw-r--r--tests/load/pkg/1/dev.cppget.org/unsigned/repositories3
-rw-r--r--tests/load/r.conf6
-rw-r--r--www/package-version-details-body.css2
-rw-r--r--www/repository-details-body.css20
37 files changed, 876 insertions, 191 deletions
diff --git a/INSTALL-DEV b/INSTALL-DEV
index 751237b..d14dfab 100644
--- a/INSTALL-DEV
+++ b/INSTALL-DEV
@@ -49,7 +49,10 @@ $ sudo tail -f /var/log/postgresql/*.log
All the commands are executed from brep project root.
$ migrate/brep-migrate
-$ load/brep-load tests/load/r.conf # Or some other loader config.
+
+# Or use some other loader config.
+#
+$ load/brep-load --bpkg ../bpkg/bpkg/bpkg tests/load/r.conf
To verify:
@@ -118,6 +121,11 @@ To do a "complete reload" (i.e., recreate database schema, load the repository
data, and reload the Apache2 plugin), execute the following from brep/:
migrate/brep-migrate --recreate
-load/brep-load tests/load/r.conf
+load/brep-load --bpkg ../bpkg/bpkg/bpkg tests/load/r.conf
sudo /etc/init.d/apache2 restart
sudo systemctl restart apache2
+
+Note that if instead need to recreate the whole database (e.g., migration is
+not possible), then one way to do it would be:
+
+psql -d brep -c 'DROP OWNED BY <user>'
diff --git a/brep/package b/brep/package
index d7b87c8..5cfbd45 100644
--- a/brep/package
+++ b/brep/package
@@ -19,9 +19,9 @@
// Used by the data migration entries.
//
-#define LIBBREP_SCHEMA_VERSION_BASE 2
+#define LIBBREP_SCHEMA_VERSION_BASE 3
-#pragma db model version(LIBBREP_SCHEMA_VERSION_BASE, 2, closed)
+#pragma db model version(LIBBREP_SCHEMA_VERSION_BASE, 3, open)
// The uint16_t value range is not fully covered by SMALLINT PostgreSQL type
// to which uint16_t is mapped by default.
@@ -279,15 +279,17 @@ namespace brep
// tricky. Can stick to just a package name until get some clarity on
// "foreign" package resolution.
//
- // 4. As we left just the the package class the dependency resolution come to
+ // 4. As we left just the package class the dependency resolution come to
// finding the best version matching package object. The question is
// if to resolve dependencies on the loading phase or in the WEB interface
// when required. The arguments in favour of doing that during loading
// phase are:
- // * WEB interface get offloaded from a possibly expensive queries
+ //
+ // - WEB interface get offloaded from a possibly expensive queries
// which otherwise have to be executed multiple times for the same
// dependency no matter the result would be the same.
- // * No need to complicate persisted object model with repository
+ //
+ // - No need to complicate persisted object model with repository
// relations otherwise required just for dependency resolution.
//
@@ -349,17 +351,30 @@ namespace brep
#pragma db map type(repository_location) as(string) \
to((?).string ()) from(brep::repository_location (?))
+ #pragma db value
+ class certificate
+ {
+ public:
+ string fingerprint; // SHA256 fingerprint.
+ string name; // CN component of Subject.
+ string organization; // O component of Subject.
+ string email; // email: in Subject Alternative Name.
+ string pem; // PEM representation.
+ };
+
#pragma db object pointer(shared_ptr) session
class repository
{
public:
using email_type = brep::email;
+ using certificate_type = brep::certificate;
// Create internal repository.
//
repository (repository_location,
string display_name,
- dir_path local_path,
+ repository_location cache_location,
+ optional<certificate_type>,
uint16_t priority);
// Create external repository.
@@ -384,10 +399,14 @@ namespace brep
optional<string> summary;
optional<string> description;
- // Non empty for internal repositories and external ones with a filesystem
- // path location.
+ // Location of the repository local cache. Non empty for internal
+ // repositories and external ones with a filesystem path location.
+ //
+ repository_location cache_location;
+
+ // Present only for internal signed repositories.
//
- dir_path local_path;
+ optional<certificate_type> certificate;
// Initialized with timestamp_nonexistent by default.
//
diff --git a/brep/package.cxx b/brep/package.cxx
index d1bbe21..9cf0783 100644
--- a/brep/package.cxx
+++ b/brep/package.cxx
@@ -141,12 +141,17 @@ namespace brep
// repository
//
repository::
- repository (repository_location l, string d, dir_path p, uint16_t r)
+ repository (repository_location l,
+ string d,
+ repository_location h,
+ optional<certificate_type> c,
+ uint16_t r)
: name (l.canonical_name ()),
location (move (l)),
display_name (move (d)),
priority (r),
- local_path (move (p)),
+ cache_location (move (h)),
+ certificate (move (c)),
internal (true)
{
}
diff --git a/brep/package.xml b/brep/package.xml
index 14598a5..98c0f02 100644
--- a/brep/package.xml
+++ b/brep/package.xml
@@ -1,5 +1,5 @@
<changelog xmlns="http://www.codesynthesis.com/xmlns/odb/changelog" database="pgsql" version="1">
- <model version="2">
+ <model version="3">
<table name="repository" kind="object">
<column name="name" type="TEXT" null="false"/>
<column name="location" type="TEXT" null="false"/>
@@ -10,7 +10,12 @@
<column name="email_comment" type="TEXT" null="true"/>
<column name="summary" type="TEXT" null="true"/>
<column name="description" type="TEXT" null="true"/>
- <column name="local_path" type="TEXT" null="false"/>
+ <column name="cache_location" type="TEXT" null="false"/>
+ <column name="certificate_fingerprint" type="TEXT" null="true"/>
+ <column name="certificate_name" type="TEXT" null="true"/>
+ <column name="certificate_organization" type="TEXT" null="true"/>
+ <column name="certificate_email" type="TEXT" null="true"/>
+ <column name="certificate_pem" type="TEXT" null="true"/>
<column name="packages_timestamp" type="BIGINT" null="false"/>
<column name="repositories_timestamp" type="BIGINT" null="false"/>
<column name="internal" type="BOOLEAN" null="false"/>
diff --git a/load/buildfile b/load/buildfile
index 333c091..8cd61fc 100644
--- a/load/buildfile
+++ b/load/buildfile
@@ -9,13 +9,15 @@ import libs += libodb%lib{odb}
include ../brep/
-exe{brep-load}: \
-{ cxx}{ load } \
-{hxx ixx cxx}{ load-options } \
+exe{brep-load}: \
+{ cxx}{ load } \
+{hxx ixx cxx}{ load-options } \
+{hxx cxx}{ types-parsers } \
../brep/lib{brep} $libs
cli.options += -I $src_root --include-with-brackets --include-prefix load \
--guard-prefix LOAD --generate-specifier --page-usage print_ --ansi-color \
+--cxx-prologue "#include <load/types-parsers>" \
--long-usage
{hxx ixx cxx}{load-options}: cli{load}
diff --git a/load/load.cli b/load/load.cli
index c3aeec4..c86df0f 100644
--- a/load/load.cli
+++ b/load/load.cli
@@ -6,6 +6,8 @@ include <vector>;
include <string>;
include <cstdint>; // uint16_t
+include <brep/types>;
+
"\section=1"
"\name=brep-load"
"\summary=load build2 repositories into database"
@@ -27,7 +29,11 @@ include <cstdint>; // uint16_t
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)}."
+ created using \l{brep-migrate(1)}.
+
+ Also note that \cb{brep-load} requires \l{bpkg(1)} to fetch repository
+ information. See \cb{--bpkg} for more information on the package manager
+ program."
}
class options
@@ -68,6 +74,24 @@ class options
"Database port number. If not specified, the default port is used."
}
+ brep::path --bpkg = "bpkg"
+ {
+ "<path>",
+ "The package manager program to be used to fetch repository information.
+ This should be the path to the \cb{bpkg} executable. You can also specify
+ additional options that should be passed to the package manager program
+ with \cb{--bpkg-option}. If the package manager program is not explicitly
+ specified, then \cb{brep-load} will use \cb{bpkg} by default."
+ }
+
+ brep::strings --bpkg-option
+ {
+ "<opt>",
+ "Additional option to be passed to the package manager program. See
+ \cb{--bpkg} for more information on the package manager program. Repeat
+ this option to specify multiple package manager options."
+ }
+
std::string --pager // String to allow empty value.
{
"<path>",
diff --git a/load/load.cxx b/load/load.cxx
index 1a485dd..1f925db 100644
--- a/load/load.cxx
+++ b/load/load.cxx
@@ -2,6 +2,7 @@
// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd
// license : MIT; see accompanying LICENSE file
+#include <cstring> // strncmp()
#include <fstream>
#include <iostream>
#include <algorithm> // find(), find_if()
@@ -15,6 +16,8 @@
#include <odb/pgsql/database.hxx>
#include <butl/pager>
+#include <butl/sha256>
+#include <butl/process>
#include <butl/filesystem>
#include <bpkg/manifest-parser> // manifest_parsing
@@ -37,7 +40,7 @@ using namespace brep;
// Operation failed, diagnostics has already been issued.
//
-struct failed: std::exception {};
+struct failed {};
static const char* help_info (
" info: run 'brep-load --help' for more information");
@@ -52,13 +55,15 @@ struct internal_repository
{
repository_location location;
string display_name;
- dir_path local_path;
+ repository_location cache_location;
+ optional<string> fingerprint;
path
- packages_path () const {return local_path / path ("packages");}
+ packages_path () const {return cache_location.path () / path ("packages");}
path
- repositories_path () const {return local_path / path ("repositories");}
+ repositories_path () const {
+ return cache_location.path () / path ("repositories");}
};
using internal_repositories = vector<internal_repository>;
@@ -93,8 +98,7 @@ load_repositories (path p)
//
auto skip = [&i, &e](bool s = true) -> decltype (i)
{
- for (; i != e && space (*i) == s; ++i)
- ;
+ for (; i != e && space (*i) == s; ++i) ;
return i;
};
@@ -143,36 +147,82 @@ load_repositories (path p)
skip (false); // Find end of display name.
string name (pb, i);
- pb = skip (); // Find begin of filesystem path.
+ repository_location cache_location;
+ optional<string> fingerprint;
- if (pb == e) // For now filesystem path is mandatory.
- bad_line ("no filesystem path found");
+ // Parse options, that have <name>:<value> form. Currently defined
+ // options are cache (mandatory for now) and fingerprint.
+ //
+ while ((pb = skip ()) != e)
+ {
+ skip (false); // Find end of the option (no spaces allowed).
- skip (false); // Find end of filesystem path (no spaces allowed).
+ string nv (pb, i);
+ size_t vp;
- internal_repository r {
- move (location),
- move (name),
- dir_path (string (pb, i))};
+ if (strncmp (nv.c_str (), "cache:", vp = 6) == 0)
+ {
+ if (!cache_location.empty ())
+ bad_line ("cache option redefinition");
+
+ // If the internal repository cache path is relative, then calculate
+ // its absolute path. Such path is considered to be relative to the
+ // configuration file directory path so result is independent from
+ // whichever directory is current for the loader process. Note that
+ // the resulted absolute path should be a valid repository location.
+ //
+ dir_path cache_path = dir_path (string (nv, vp));
+ if (cache_path.relative ())
+ cache_path = p.directory () / cache_path;
+
+ try
+ {
+ cache_location = repository_location (cache_path.string ());
- // If the internal repository local path is relative, then
- // calculate its absolute local path. Such path is considered to be
- // relative to configuration file directory path so result is
- // independent from whichever directory is current for the loader
- // process.
- //
- if (r.local_path.relative ())
- r.local_path = p.directory () / r.local_path;
+ // Created from the absolute path repository location can not be
+ // other than absolute.
+ //
+ assert (cache_location.absolute ());
+ }
+ catch (const invalid_argument&)
+ {
+ bad_line ("invalid cache path");
+ }
+ }
+ else if (strncmp (nv.c_str (), "fingerprint:", vp = 12) == 0)
+ {
+ if (fingerprint)
+ bad_line ("fingerprint option redefinition");
- try
- {
- r.local_path.normalize ();
- }
- catch (const invalid_path&)
- {
- bad_line ("can't normalize local path");
+ fingerprint = string (nv, vp);
+
+ // Sanity check.
+ //
+ if (!fingerprint->empty ())
+ {
+ try
+ {
+ fingerprint_to_sha256 (*fingerprint);
+ }
+ catch (const invalid_argument&)
+ {
+ bad_line ("invalid fingerprint");
+ }
+ }
+ }
+ else
+ bad_line ("invalid option '" + nv + "'");
}
+ if (cache_location.empty ()) // For now cache option is mandatory.
+ bad_line ("no cache option found");
+
+ internal_repository r {
+ move (location),
+ move (name),
+ move (cache_location),
+ move (fingerprint)};
+
if (!file_exists (r.packages_path ()))
bad_line ("'packages' file does not exist");
@@ -213,7 +263,7 @@ changed (const internal_repositories& repos, database& db)
if (pr == nullptr || r.location.string () != pr->location.string () ||
r.display_name != pr->display_name ||
- r.local_path != pr->local_path ||
+ r.cache_location.path () != pr->cache_location.path () ||
file_mtime (r.packages_path ()) != pr->packages_timestamp ||
file_mtime (r.repositories_path ()) != pr->repositories_timestamp ||
!pr->internal)
@@ -233,6 +283,37 @@ changed (const internal_repositories& repos, database& db)
!query::name.in_range (names.begin (), names.end ())).empty ();
}
+// Start 'bpkg rep-info [options] <repository_location>' process.
+//
+static process
+repository_info (const options& lo, const string& rl, const cstrings& options)
+{
+ cstrings args {lo.bpkg ().string ().c_str (), "rep-info"};
+
+ args.insert (args.end (), options.begin (), options.end ());
+
+ for (const string& o: lo.bpkg_option ())
+ args.push_back (o.c_str ());
+
+ args.push_back (rl.c_str ());
+ args.push_back (nullptr);
+
+ try
+ {
+ return process (args.data (), 0, -1, 2);
+ }
+ catch (const process_error& e)
+ {
+ cerr << "error: unable to execute " << args[0] << ": " << e.what ()
+ << endl;
+
+ if (e.child ())
+ exit (1);
+
+ throw failed ();
+ }
+}
+
static timestamp
manifest_stream (const path& p, ifstream& f)
{
@@ -261,13 +342,13 @@ load_packages (const shared_ptr<repository>& rp, database& db)
// Only locally accessible repositories allowed until package manager API is
// ready.
//
- assert (!rp->local_path.empty ());
+ assert (!rp->cache_location.empty ());
package_manifests pkm;
{
ifstream ifs;
- path p (rp->local_path / path ("packages"));
+ path p (rp->cache_location.path () / path ("packages"));
rp->packages_timestamp = manifest_stream (p, ifs);
manifest_parser mp (ifs, p.string ());
@@ -395,7 +476,7 @@ load_repositories (const shared_ptr<repository>& rp, database& db)
// Only locally accessible repositories allowed until package manager API is
// ready.
//
- assert (!rp->local_path.empty ());
+ assert (!rp->cache_location.empty ());
// Repository is already persisted by the load_packages() function call.
//
@@ -405,7 +486,7 @@ load_repositories (const shared_ptr<repository>& rp, database& db)
{
ifstream ifs;
- path p (rp->local_path / path ("repositories"));
+ path p (rp->cache_location.path () / path ("repositories"));
rp->repositories_timestamp = manifest_stream (p, ifs);
manifest_parser mp (ifs, p.string ());
@@ -448,6 +529,26 @@ load_repositories (const shared_ptr<repository>& rp, database& db)
rp->email = move (rm.email);
rp->summary = move (rm.summary);
rp->description = move (rm.description);
+
+ // Mismatch of the repository manifest and the certificate information
+ // can be the result of racing condition.
+ //
+ // @@ Need to address properly while fully moving to the bpkg-based
+ // fetching.
+ // @@ Shouldn't we dedicate a specific exit code for such situations?
+ //
+ if (static_cast<bool> (rm.certificate) !=
+ static_cast<bool> (rp->certificate))
+ {
+ cerr << "error: signing status mismatch for internal repository "
+ << rp->location << endl
+ << " info: try again" << endl;
+
+ throw failed ();
+ }
+
+ if (rm.certificate)
+ rp->certificate->pem = move (*rm.certificate);
}
continue;
@@ -508,23 +609,23 @@ load_repositories (const shared_ptr<repository>& rp, database& db)
pr = make_shared<repository> (move (rl));
// If the prerequsite repository location is a relative path, then
- // calculate its absolute local path.
+ // calculate its cache location.
//
if (rm.location.relative ())
{
- dir_path& lp (pr->local_path);
- lp = rp->local_path / rm.location.path ();
-
try
{
- lp.normalize ();
+ pr->cache_location =
+ repository_location (rm.location, rp->cache_location);
}
- catch (const invalid_path&)
+ catch (const invalid_argument&)
{
- cerr << "error: can't normalize prerequisite repository local path '"
- << lp << "'" << endl
+ cerr << "error: can't obtain cache location for prerequisite "
+ << "repository '" << rm.location << "'" << endl
<< " info: base (internal) repository location is "
- << rp->location << endl;
+ << rp->location << endl
+ << " info: base repository cache location is "
+ << rp->cache_location << endl;
throw failed ();
}
@@ -723,6 +824,122 @@ detect_dependency_cycle (
chain.pop_back ();
}
+// Return the certificate information for a signed repository and nullopt for
+// an unsigned. Note that a repository at the remote location is not trusted
+// unless the certificate fingerprint is provided (which also means it should
+// either be signed or the wildcard fingerprint specified). A local repository
+// location is, instead, trusted by default. If the fingerprint is provided
+// then the repository is authenticated regardless of the location type.
+//
+static optional<certificate>
+certificate_info (const options& lo,
+ const repository_location& rl,
+ const optional<string>& fp)
+{
+ try
+ {
+ cstrings args {
+ "--cert-fingerprint",
+ "--cert-name",
+ "--cert-organization",
+ "--cert-email",
+ "-q"}; // Don't print info messages.
+
+ const char* trust ("--trust-no");
+
+ if (fp)
+ {
+ if (!fp->empty ())
+ {
+ args.push_back ("--trust");
+ args.push_back (fp->c_str ());
+ }
+ else
+ trust = "--trust-yes";
+
+ if (!rl.remote ())
+ {
+ args.push_back ("--auth");
+ args.push_back ("all");
+ }
+ }
+
+ args.push_back (trust);
+
+ process pr (repository_info (lo, rl.string (), args));
+
+ ifdstream is (pr.in_ofd);
+ is.exceptions (ifdstream::failbit | ifdstream::badbit | ifdstream::eofbit);
+
+ try
+ {
+ optional<certificate> cert;
+
+ string fingerprint;
+ getline (is, fingerprint);
+
+ if (!fingerprint.empty ())
+ {
+ cert = certificate ();
+ cert->fingerprint = move (fingerprint);
+ getline (is, cert->name);
+ getline (is, cert->organization);
+ getline (is, cert->email);
+ }
+ else
+ {
+ // Read out empty lines.
+ //
+ string s;
+ getline (is, s); // Name.
+ getline (is, s); // Organization.
+ getline (is, s); // Email.
+ }
+
+ // Check that EOF is successfully reached.
+ //
+ is.exceptions (ifdstream::failbit | ifdstream::badbit);
+ if (is.peek () != ifdstream::traits_type::eof ())
+ throw system_error (EIO, system_category ());
+
+ is.close ();
+
+ if (pr.wait ())
+ return cert;
+
+ // Fall through.
+ //
+ }
+ catch (const system_error&)
+ {
+ // Child input reading error.
+ //
+ is.close ();
+
+ // Child exit status doesn't matter. Just wait for the process
+ // completion and fall through.
+ //
+ pr.wait ();
+ }
+
+ // Assume the child issued diagnostics.
+ //
+ cerr << "error: unable to fetch certificate information for "
+ << rl.canonical_name () << endl;
+
+ // Fall through.
+ }
+ catch (const process_error& e)
+ {
+ cerr << "error: unable to fetch certificate information for "
+ << rl.canonical_name () << ": " << e.what () << endl;
+
+ // Fall through.
+ }
+
+ throw failed ();
+}
+
int
main (int argc, char* argv[])
try
@@ -811,15 +1028,22 @@ try
db.erase_query<repository> ();
// On the first pass over the internal repositories we load their
- // packages.
+ // certificate information and packages.
//
uint16_t priority (1);
for (const auto& ir: irs)
{
+ optional<certificate> cert (
+ certificate_info (
+ ops,
+ !ir.cache_location.empty () ? ir.cache_location : ir.location,
+ ir.fingerprint));
+
shared_ptr<repository> r (
make_shared<repository> (ir.location,
move (ir.display_name),
- move (ir.local_path),
+ move (ir.cache_location),
+ move (cert),
priority++));
load_packages (r, db);
diff --git a/load/types-parsers b/load/types-parsers
new file mode 100644
index 0000000..cfbcd13
--- /dev/null
+++ b/load/types-parsers
@@ -0,0 +1,28 @@
+// file : load/types-parsers -*- C++ -*-
+// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+// CLI parsers, included into the generated source files.
+//
+
+#ifndef BREP_LOAD_TYPES_PARSERS
+#define BREP_LOAD_TYPES_PARSERS
+
+#include <brep/types>
+
+namespace cli
+{
+ class scanner;
+
+ template <typename T>
+ struct parser;
+
+ template <>
+ struct parser<brep::path>
+ {
+ static void
+ parse (brep::path&, bool&, scanner&);
+ };
+}
+
+#endif // BREP_LOAD_TYPES_PARSERS
diff --git a/load/types-parsers.cxx b/load/types-parsers.cxx
new file mode 100644
index 0000000..6c61daf
--- /dev/null
+++ b/load/types-parsers.cxx
@@ -0,0 +1,43 @@
+// file : load/types-parsers.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <load/types-parsers>
+
+#include <load/load-options> // cli namespace
+
+using namespace brep;
+
+namespace cli
+{
+ template <typename T>
+ static void
+ parse_path (T& x, scanner& s)
+ {
+ const char* o (s.next ());
+
+ if (!s.more ())
+ throw missing_value (o);
+
+ const char* v (s.next ());
+
+ try
+ {
+ x = T (v);
+
+ if (x.empty ())
+ throw invalid_value (o, v);
+ }
+ catch (const invalid_path&)
+ {
+ throw invalid_value (o, v);
+ }
+ }
+
+ void parser<path>::
+ parse (path& x, bool& xs, scanner& s)
+ {
+ xs = true;
+ parse_path (x, s);
+ }
+}
diff --git a/mod/mod-repository-details.cxx b/mod/mod-repository-details.cxx
index dffd0df..42e59cb 100644
--- a/mod/mod-repository-details.cxx
+++ b/mod/mod-repository-details.cxx
@@ -111,24 +111,21 @@ handle (request& rq, response& rs)
if (r.summary)
s << H2 << *r.summary << ~H2;
- if (r.description)
- s << P_DESCRIPTION (*r.description);
+ s << P
+ << A(HREF=r.location.string ()) << r.location << ~A << *BR;
if (r.email)
{
const email& e (*r.email);
- s << P
- << A(HREF="mailto:" + e) << e << ~A;
+ s << A(HREF="mailto:" + e) << e << ~A;
if (!e.comment.empty ())
s << " (" << e.comment << ")";
- s << ~P;
+ s << *BR;
}
- s << P << A(HREF=r.location.string ()) << r.location << ~A << ~P;
-
ostringstream o;
butl::to_stream (o,
max (r.packages_timestamp, r.repositories_timestamp),
@@ -136,7 +133,32 @@ handle (request& rq, response& rs)
true,
true);
- s << P << o.str () << ~P;
+ s << o.str ()
+ << ~P;
+
+ if (r.description)
+ s << P_DESCRIPTION (*r.description);
+
+ if (r.certificate)
+ {
+ const certificate& cert (*r.certificate);
+
+ size_t np (cert.name.find (':'));
+ assert (np != string::npos); // Naming scheme should always be present.
+
+ // Mimic the suggested format of the repository description so that the
+ // certificate info looks like just another section. Inside use the
+ // format similar to the bpkg rep-info output.
+ //
+ s << P << "REPOSITORY CERTIFICATE" << ~P
+ << P
+ << "CN=" << cert.name.c_str () + np + 1 << *BR
+ << "O=" << cert.organization << *BR
+ << email (cert.email)
+ << ~P
+ << P(CLASS="certfp") << cert.fingerprint << ~P
+ << PRE(CLASS="certpem") << cert.pem << ~PRE;
+ }
}
t.commit ();
diff --git a/tests/load/1/math/libexp-1~1.2+1.tar.gz b/tests/load/1/math/libexp-1~1.2+1.tar.gz
new file mode 100644
index 0000000..c74e2b9
--- /dev/null
+++ b/tests/load/1/math/libexp-1~1.2+1.tar.gz
Binary files differ
diff --git a/tests/load/1/math/libfoo-1.0.tar.gz b/tests/load/1/math/libfoo-1.0.tar.gz
new file mode 100644
index 0000000..5063f1b
--- /dev/null
+++ b/tests/load/1/math/libfoo-1.0.tar.gz
Binary files differ
diff --git a/tests/load/1/math/libfoo-1.2.4+1.tar.gz b/tests/load/1/math/libfoo-1.2.4+1.tar.gz
new file mode 100644
index 0000000..5210ced
--- /dev/null
+++ b/tests/load/1/math/libfoo-1.2.4+1.tar.gz
Binary files differ
diff --git a/tests/load/1/math/libstudxml-1.0.0+1.tar.gz b/tests/load/1/math/libstudxml-1.0.0+1.tar.gz
new file mode 100644
index 0000000..c351fa5
--- /dev/null
+++ b/tests/load/1/math/libstudxml-1.0.0+1.tar.gz
Binary files differ
diff --git a/tests/load/1/math/packages b/tests/load/1/math/packages
index e8d4410..7d09a03 100644
--- a/tests/load/1/math/packages
+++ b/tests/load/1/math/packages
@@ -1,36 +1,35 @@
: 1
-sha256sum: 1f2b297be1eafd70fe55f179a0cf062baf8405e08b3854600801420132a206b1
-:
-name: libstudxml
-version: 1.0.0+1
-summary: Modern C++ XML API
-license: MIT
-tags: c++, xml, parser, serializer, pull, streaming, modern
-url: http://www.codesynthesis.com/projects/libstudxml/
-email: studxml-users@codesynthesis.com; Public mailing list, posts by\
- non-members are allowed but moderated.
-package-email: boris@codesynthesis.com; Direct email to the author.
-depends: libexpat >= 2.0.0
-depends: libgenx
-location: libstudxml-1.0.0+1.tar.gz
-sha256sum: 05ccba3da34dd0296866027a26b6bacf08cacc80f54516d3b8d8eeccbe31ab93
+sha256sum: 05f690c39da531ea450e8b1f1a2a1314d891c6c5e4e8be5be9c8c2f2ede5e28a
:
name: libexp
version: 1~1.2+1
summary: The exponent
-description: The exponent math function.
license: MIT
tags: c++, exponent
+description: The exponent math function.
url: http://www.exp.com
email: users@exp.com
depends: libmisc
location: libexp-1~1.2+1.tar.gz
-sha256sum: 15ccba3da34dd0296866027a26b6bacf08cacc80f54516d3b8d8eeccbe31ab93
+sha256sum: 6c1869459964c8c780bd63d67e4c0727e583965e7280fd1f31be3f3639206191
+:
+name: libfoo
+version: 1.0
+summary: The Foo Library
+license: MIT
+url: http://www.example.com/foo/
+email: foo-users@example.com
+location: libfoo-1.0.tar.gz
+sha256sum: d8ad319b55fdd19ff24cb0fcf9d61101289569f80b8688884389587cfafa1f1e
:
name: libfoo
version: 1.2.4+1
+priority: high; Critical bug fixes, performance improvement.
summary: The Foo Math Library
-description:\
+license: LGPLv2, MIT; If using with GNU TLS.
+license: BSD; If using with OpenSSL.
+tags: c++, foo, math
+description: \
A modern C++ library with easy to use linear algebra and lot of optimization
tools.
@@ -39,13 +38,17 @@ similar to MATLAB.
Useful for conversion of research code into production environments.
\
-license: LGPLv2, MIT; If using with GNU TLS.
-license: BSD; If using with OpenSSL.
-priority: high; Critical bug fixes, performance improvement.
-tags: c++, foo, math
+changes: \
+1.2.4+1
+ * applied patch for critical bug-219
+ * regenerated documentation
+
+1.2.4
+ * test suite extended significantly
+\
url: http://www.example.com/foo/; Project home page.
-email: foo-users@example.com; Public mailing list. Read FAQ before posting.
package-url: http://www.example.com/foo/pack; Package details.
+email: foo-users@example.com; Public mailing list. Read FAQ before posting.
package-email: pack@example.com; Current packager.
depends: libmisc < 1.1 | libmisc > 2.3.0; Crashes with 1.1.0-2.3.0.
depends: libexp >= 1.0
@@ -55,21 +58,18 @@ requires: c++11
requires: ? ; libc++ standard library if using Clang on Mac OS X.
requires: ? vc++ >= 12.0; Only if using VC++ on Windows.
location: libfoo-1.2.4+1.tar.gz
-sha256sum: 35ccba3da34dd0296866027a26b6bacf08cacc80f54516d3b8d8eeccbe31ab93
-changes:\
-1.2.4+1
- * applied patch for critical bug-219
- * regenerated documentation
-
-1.2.4
- * test suite extended significantly
-\
+sha256sum: 6bf9de8c4647a32dee79ad5e787c10311495e3f6b5727bfd03b2d9dcd6a16eed
:
-name: libfoo
-version: 1.0
-summary: The Foo Lib
+name: libstudxml
+version: 1.0.0+1
+summary: Modern C++ XML API
license: MIT
-url: http://www.example.com/foo/
-email: foo-users@example.com
-location: libfoo-1.0.tar.gz
-sha256sum: 754cba3da34dd0296866027a26b6bacf08cacc80f54516d3b8d8eeccbe31ab93
+tags: c++, xml, parser, serializer, pull, streaming, modern
+url: http://www.codesynthesis.com/projects/libstudxml/
+email: studxml-users@codesynthesis.com; Public mailing list, posts by\
+ non-members are allowed but moderated.
+package-email: boris@codesynthesis.com; Direct email to the author.
+depends: libexpat >= 2.0.0
+depends: libgenx
+location: libstudxml-1.0.0+1.tar.gz
+sha256sum: cfa4b1f89f8e903d48eff1e1d14628c32aa4d126d09b0b056d2cd80f8dc78580
diff --git a/tests/load/1/math/repositories b/tests/load/1/math/repositories
index 20aa30d..6c63820 100644
--- a/tests/load/1/math/repositories
+++ b/tests/load/1/math/repositories
@@ -5,7 +5,7 @@ location: ../misc
:
# Local repository manifest (this repository).
#
-email: repoman@cppget.org
+email: repoman@dev.cppget.org
summary: Math C++ package repository
description: \
This is the awesome C++ package repository full of remarkable algorithms and
diff --git a/tests/load/1/stable/libfoo-1.0.tar.gz b/tests/load/1/stable/libfoo-1.0.tar.gz
new file mode 100644
index 0000000..5063f1b
--- /dev/null
+++ b/tests/load/1/stable/libfoo-1.0.tar.gz
Binary files differ
diff --git a/tests/load/1/stable/libfoo-1.2.2-alpha.1.tar.gz b/tests/load/1/stable/libfoo-1.2.2-alpha.1.tar.gz
new file mode 100644
index 0000000..fb0bfd6
--- /dev/null
+++ b/tests/load/1/stable/libfoo-1.2.2-alpha.1.tar.gz
Binary files differ
diff --git a/tests/load/1/stable/libfoo-1.2.2.tar.gz b/tests/load/1/stable/libfoo-1.2.2.tar.gz
new file mode 100644
index 0000000..a1b80ef
--- /dev/null
+++ b/tests/load/1/stable/libfoo-1.2.2.tar.gz
Binary files differ
diff --git a/tests/load/1/stable/libfoo-1.2.3+4.tar.gz b/tests/load/1/stable/libfoo-1.2.3+4.tar.gz
new file mode 100644
index 0000000..9ef7d64
--- /dev/null
+++ b/tests/load/1/stable/libfoo-1.2.3+4.tar.gz
Binary files differ
diff --git a/tests/load/1/stable/libfoo-1.2.4.tar.gz b/tests/load/1/stable/libfoo-1.2.4.tar.gz
new file mode 100644
index 0000000..dc64431
--- /dev/null
+++ b/tests/load/1/stable/libfoo-1.2.4.tar.gz
Binary files differ
diff --git a/tests/load/1/stable/packages b/tests/load/1/stable/packages
index 9b075a4..f131d97 100644
--- a/tests/load/1/stable/packages
+++ b/tests/load/1/stable/packages
@@ -1,16 +1,27 @@
: 1
-sha256sum: 3f2b297be1eafd70fe55f179a0cf062baf8405e08b3854600801420132a206b1
+sha256sum: 4247ba96ece073e8a205ba7a6554e1968242b8a25dda9d474509da3a5b1068c7
:
name: libfoo
-version: 1.2.3+4
+version: 1.0
+summary: The Foo Library
+license: MIT
+url: http://www.example.com/foo/
+email: foo-users@example.com
+location: libfoo-1.0.tar.gz
+sha256sum: d8ad319b55fdd19ff24cb0fcf9d61101289569f80b8688884389587cfafa1f1e
+:
+name: libfoo
+version: 1.2.2-alpha.1
summary: The Foo library
license: MIT
tags: c++, foo
url: http://www.example.com/foo/
email: foo-users@example.com
-depends: libmisc >= 2.0.0
-location: libfoo-1.2.3+4.tar.gz
-sha256sum: 750cba3da34dd0296866027a26b6bacf08cacc80f54516d3b8d8eeccbe31ab93
+depends: libmisc [0.1 2.0-) | libmisc [2.0 5.0]
+depends: libgenx (0.2 3.0)
+depends: libexpat < 5.2 | libexpat (1 5.1]
+location: libfoo-1.2.2-alpha.1.tar.gz
+sha256sum: 34fc224087bfd9212de4acfbbf5275513ebc57678b5f029546918a62c57d15cb
:
name: libfoo
version: 1.2.2
@@ -22,40 +33,29 @@ email: foo-users@example.com
depends: libbar <= 2.4.0
depends: libexp == 1~1.2
location: libfoo-1.2.2.tar.gz
-sha256sum: 751cba3da34dd0296866027a26b6bacf08cacc80f54516d3b8d8eeccbe31ab93
+sha256sum: b47de1b207ef097c9ecdd560007aeadd3775f4fafb4f96fb983e9685c21f3980
:
name: libfoo
-version: 1.2.2-alpha.1
+version: 1.2.3+4
summary: The Foo library
license: MIT
tags: c++, foo
url: http://www.example.com/foo/
email: foo-users@example.com
-depends: libmisc [0.1 2.0-) | libmisc [2.0 5.0]
-depends: libgenx (0.2 3.0)
-depends: libexpat < 5.2 | libexpat (1 5.1]
-location: libfoo-1.2.2-alpha.1.tar.gz
-sha256sum: 752cba3da34dd0296866027a26b6bacf08cacc80f54516d3b8d8eeccbe31ab93
+depends: libmisc >= 2.0.0
+location: libfoo-1.2.3+4.tar.gz
+sha256sum: 204fb25edf2404e9e88e1bef8b2a444281a807d9087093147a2cc80a1ffba79a
:
name: libfoo
version: 1.2.4
summary: The Foo Library
-description: Very good foo library.
license: MIT; Permissive free software license.
tags: c++, foo
-url: http://www.example.com/foo/
-email: foo-users@example.com
-depends: libmisc >= 2.0.0
+description: Very good foo library.
changes: some changes 1
changes: some changes 2
-location: libfoo-1.2.4.tar.gz
-sha256sum: 753cba3da34dd0296866027a26b6bacf08cacc80f54516d3b8d8eeccbe31ab93
-:
-name: libfoo
-version: 1.0
-summary: The Foo Library
-license: MIT
url: http://www.example.com/foo/
email: foo-users@example.com
-location: libfoo-1.0.tar.gz
-sha256sum: 754cba3da34dd0296866027a26b6bacf08cacc80f54516d3b8d8eeccbe31ab93
+depends: libmisc >= 2.0.0
+location: libfoo-1.2.4.tar.gz
+sha256sum: aa1606323bfc59b70de642629dc5d8318cc5348e3646f90ed89406d975db1e1d
diff --git a/tests/load/1/stable/repositories b/tests/load/1/stable/repositories
index 815a1b5..a97273c 100644
--- a/tests/load/1/stable/repositories
+++ b/tests/load/1/stable/repositories
@@ -9,6 +9,38 @@ location: ../math
:
# Local repository manifest (this repository).
#
-email: repoman@cppget.org; public mailing list
+email: repoman@dev.cppget.org; public mailing list
summary: General C++ package stable repository
description: This is the awesome C++ package repository full of exciting stuff.
+certificate: \
+-----BEGIN CERTIFICATE-----
+MIIFOzCCAyOgAwIBAgIJANKSVz8Ff0f3MA0GCSqGSIb3DQEBCwUAMDcxFzAVBgNV
+BAoMDkNvZGUgU3ludGhlc2lzMRwwGgYDVQQDDBNuYW1lOmRldi5jcHBnZXQub3Jn
+MB4XDTE2MDcwNjE2Mzg1NloXDTE3MDcwNjE2Mzg1NlowNzEXMBUGA1UECgwOQ29k
+ZSBTeW50aGVzaXMxHDAaBgNVBAMME25hbWU6ZGV2LmNwcGdldC5vcmcwggIiMA0G
+CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDK8NqNbQckQpv9B3hBRjnTcpkgKq2e
+1HOFLQJxgS1TS2QfqUTKePpd10LbDgXOhI2iycKCf7Zv/uf3RE+VyQ/BthNUvQ0O
+bWPsEKo+DQOLPjqIaS+u2bmMXzCDjwjufbd9ruPY2PYRTBOsXgTL1+GGIQu0bP5u
+i1mEGn95xuYhEJ4x1UUsVWV0l0D37orV/OaOVffPY3xhlQE++aiXLptof1gzM2D8
+lsQPvWLizrtDAHpiwb4oXQQbifDyeXj+qh7OdIqL10rxZZ/0Q0GqrTOyeSlXuo5i
+C3MdNSlRmWNGqvPwpushFBQec04exXI3AjQZ/DUlMxtDx2xIqQMtaYOQ5iqm9426
+crgrUoXZG/5ePYTCmnSbpZVak9md44inJWqSESTL0+EfWuLdXop0QV7LZrIaV2pV
+BJba0/jiS5mltR/ikiJ7gaP/bbfutJGGfzyk1PrvyehhK/snGUh6Nr0NMHozS+J+
+7QXdSEMjLXbmF5hBsvEfrGub+YSexEEODA34YnBIA453ph4CIo/3nTpDLrm3EkSF
+1jV5vGhg3vzB6v+TIP9MXALm4/NUurn8I643KMoNSS9RCDuiqLnE8V1uCmSP8LR8
+OO7vxlmaM/OfqHehAALgsU/KFT1lgpAfHE2x5YBxT6s407DJJpaPkbHMiCNHScWQ
+5ezqnH0UMNwsawIDAQABo0owSDAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAww
+CgYIKwYBBQUHAwMwHgYDVR0RBBcwFYETaW5mb0BkZXYuY3BwZ2V0Lm9yZzANBgkq
+hkiG9w0BAQsFAAOCAgEAGA83AWQKtVktqPAJwpikLbP+zPAUpQ8C76aFPIYq1u+f
+Sy8koKmklWet/1bQRtYzV7Wa9Gd+OfUjiBSc2zBqKy+9kU0rJsxUjMQayzx5OoOA
+rZHyQGb585XWhdpp/opImYUisCr677YLgJwGUR86ylrSGgCd9YlNyAO13rcmaduu
+smEzKjJtRtZk4FSl9P7DDRZ2oC3lqVNd5oEDGbEaQj5+FL7uiEdQcPYrwxK8kL2z
+uxowough8o9uKLRlirKe/YpiBw+MCsEH+eKX/1cO2upA+vnf0kYrOGLVjv641Feg
+aYLQsSZSv/pPm7AUX25eHYEZOcxRS4YnHmj//OSV/ZquAXvD5jTA/dZrlL/WGBuI
+TUMz9I9RtZHJfxybaEXz3g3EgJMYSBFVoEYTbk7XJrV7cImpJev+uFplGH0zcQqv
+aIgXYmvoAUxo4DixIhZ7E+niBLir9yJCSc2STe9tImtU31UDczohlKm1X2wX8ShW
+K4ugd2FCB9d5THPyeJ0gJg8NiugaucYnuaXbONX2G4Kw/mWpXFJoK6PLiHo6MpRw
+/NPPdNokVDEYPhrqGfwSYhI42KtqKdt+jK1Go4z1blYnqZBYWTnOWPPMimOnx+/S
+XrAdAH187sXX9MAq9TQNmdoz+ua4jqHx44EdfIK2NFEhs1hR8Gt1ZeIjcU3fEO8=
+-----END CERTIFICATE-----
+\ \ No newline at end of file
diff --git a/tests/load/1/stable/signature b/tests/load/1/stable/signature
new file mode 100644
index 0000000..52e81e7
--- /dev/null
+++ b/tests/load/1/stable/signature
@@ -0,0 +1,13 @@
+: 1
+sha256sum: 7d3f516aad9050c8c2ed216f2988264543252d5726097c4c637b8d934146b5e4
+signature: \
+NGF9h4hxiK/zi+zc03KDheGflUYRWJwnGh61+bvro7mio+uapE+JDPYnmo9Jt7RQFjplgM1mNSoK
+ldE99NEH6GH8oViuviGVqS1745IRhaY8M17Xy2P1P4JgeDFPhzs1G9NYl73qM9Ls9Tr2mpqyjW3J
+lQV1EVFF2J8krjTYvd/L8B60XXqZjyXBBMjWOFDvr9SEnsw8mkTvtuE4ky099/5YZ5zW+24TlpTs
+DEcxUq5TudzCLivhoNyeP98yKR3kQvUbz05YLEAeNmXfrlhBnCwva4kST/3N6CE6WDVxwaASTOYV
+OhkjNt/VmVd6ogDGUJ0EG86uCjiohTGjD+SuwRTXB6SHn5vYixMZbyq+u4MbCi3CATBEg88QYDlf
+K8K6bAOkQW9PhORpnp4e/YZfHrTDXCM49ax3p44mCDEQ59Q1hvsfBEVvSWcSAYtmhEYJT8bO4ulf
+Wu8u9gdc+kEMXu/rryhGSNAsrQQGQyov1alMmX+51oL6s0UmPJMTH1NW36bgbLVyT893/zU0TbtY
+jvm8TiW5i6RzjvQTGc2rI9KkVlRyDQ/vNoMTQNl3vmOQIdabWe4VI8dTKu6VwKUJmtwvTrSaBilI
+FsCVJxYYdvZclg79kmU3dcMoPwNFbRBUM724gDYXSO4EkumYDTSqCke98EHT5BPhq/Skvy1JCa0=
+\
diff --git a/tests/load/cert.pem b/tests/load/cert.pem
new file mode 100644
index 0000000..443756a
--- /dev/null
+++ b/tests/load/cert.pem
@@ -0,0 +1,30 @@
+-----BEGIN CERTIFICATE-----
+MIIFOzCCAyOgAwIBAgIJANKSVz8Ff0f3MA0GCSqGSIb3DQEBCwUAMDcxFzAVBgNV
+BAoMDkNvZGUgU3ludGhlc2lzMRwwGgYDVQQDDBNuYW1lOmRldi5jcHBnZXQub3Jn
+MB4XDTE2MDcwNjE2Mzg1NloXDTE3MDcwNjE2Mzg1NlowNzEXMBUGA1UECgwOQ29k
+ZSBTeW50aGVzaXMxHDAaBgNVBAMME25hbWU6ZGV2LmNwcGdldC5vcmcwggIiMA0G
+CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDK8NqNbQckQpv9B3hBRjnTcpkgKq2e
+1HOFLQJxgS1TS2QfqUTKePpd10LbDgXOhI2iycKCf7Zv/uf3RE+VyQ/BthNUvQ0O
+bWPsEKo+DQOLPjqIaS+u2bmMXzCDjwjufbd9ruPY2PYRTBOsXgTL1+GGIQu0bP5u
+i1mEGn95xuYhEJ4x1UUsVWV0l0D37orV/OaOVffPY3xhlQE++aiXLptof1gzM2D8
+lsQPvWLizrtDAHpiwb4oXQQbifDyeXj+qh7OdIqL10rxZZ/0Q0GqrTOyeSlXuo5i
+C3MdNSlRmWNGqvPwpushFBQec04exXI3AjQZ/DUlMxtDx2xIqQMtaYOQ5iqm9426
+crgrUoXZG/5ePYTCmnSbpZVak9md44inJWqSESTL0+EfWuLdXop0QV7LZrIaV2pV
+BJba0/jiS5mltR/ikiJ7gaP/bbfutJGGfzyk1PrvyehhK/snGUh6Nr0NMHozS+J+
+7QXdSEMjLXbmF5hBsvEfrGub+YSexEEODA34YnBIA453ph4CIo/3nTpDLrm3EkSF
+1jV5vGhg3vzB6v+TIP9MXALm4/NUurn8I643KMoNSS9RCDuiqLnE8V1uCmSP8LR8
+OO7vxlmaM/OfqHehAALgsU/KFT1lgpAfHE2x5YBxT6s407DJJpaPkbHMiCNHScWQ
+5ezqnH0UMNwsawIDAQABo0owSDAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAww
+CgYIKwYBBQUHAwMwHgYDVR0RBBcwFYETaW5mb0BkZXYuY3BwZ2V0Lm9yZzANBgkq
+hkiG9w0BAQsFAAOCAgEAGA83AWQKtVktqPAJwpikLbP+zPAUpQ8C76aFPIYq1u+f
+Sy8koKmklWet/1bQRtYzV7Wa9Gd+OfUjiBSc2zBqKy+9kU0rJsxUjMQayzx5OoOA
+rZHyQGb585XWhdpp/opImYUisCr677YLgJwGUR86ylrSGgCd9YlNyAO13rcmaduu
+smEzKjJtRtZk4FSl9P7DDRZ2oC3lqVNd5oEDGbEaQj5+FL7uiEdQcPYrwxK8kL2z
+uxowough8o9uKLRlirKe/YpiBw+MCsEH+eKX/1cO2upA+vnf0kYrOGLVjv641Feg
+aYLQsSZSv/pPm7AUX25eHYEZOcxRS4YnHmj//OSV/ZquAXvD5jTA/dZrlL/WGBuI
+TUMz9I9RtZHJfxybaEXz3g3EgJMYSBFVoEYTbk7XJrV7cImpJev+uFplGH0zcQqv
+aIgXYmvoAUxo4DixIhZ7E+niBLir9yJCSc2STe9tImtU31UDczohlKm1X2wX8ShW
+K4ugd2FCB9d5THPyeJ0gJg8NiugaucYnuaXbONX2G4Kw/mWpXFJoK6PLiHo6MpRw
+/NPPdNokVDEYPhrqGfwSYhI42KtqKdt+jK1Go4z1blYnqZBYWTnOWPPMimOnx+/S
+XrAdAH187sXX9MAq9TQNmdoz+ua4jqHx44EdfIK2NFEhs1hR8Gt1ZeIjcU3fEO8=
+-----END CERTIFICATE-----
diff --git a/tests/load/cert.sh b/tests/load/cert.sh
new file mode 100755
index 0000000..9d052c2
--- /dev/null
+++ b/tests/load/cert.sh
@@ -0,0 +1,17 @@
+#! /bin/sh
+
+# Normally, you don't need to regenerate the private key.
+#
+# openssl genrsa 4096 > key.pem
+
+# Copy cert.pem content to the certificate value of the following manifest
+# files:
+# 1/stable/repositories
+# pkg/1/dev.cppget.org/signed/repositories
+#
+openssl req -x509 -new -key key.pem -days 365 -config openssl.cnf > cert.pem
+
+# To regenerate the packages and signature manifest files run:
+#
+# ../../../bpkg/bpkg/bpkg rep-create 1/stable --key key.pem
+# ../../../bpkg/bpkg/bpkg rep-create pkg/1/dev.cppget.org/signed --key key.pem
diff --git a/tests/load/driver.cxx b/tests/load/driver.cxx
index c2907b6..5f55701 100644
--- a/tests/load/driver.cxx
+++ b/tests/load/driver.cxx
@@ -49,18 +49,49 @@ check_external (const package& p)
int
main (int argc, char* argv[])
{
- if (argc != 7)
+ auto print_usage = [argv]()
{
cerr << "usage: " << argv[0]
- << " <loader_path> --db-host <host> --db-port <port>"
- << " <loader_conf_file>" << endl;
+ << " <loader_path> [loader_options] <loader_conf_file>" << endl;
+ };
+ if (argc < 3)
+ {
+ print_usage ();
+ return 1;
+ }
+
+ string user;
+ string password;
+ string name ("brep");
+ string host;
+ unsigned int port (0);
+ int i (2);
+
+ for (; i < argc - 1; ++i)
+ {
+ string n (argv[i]);
+ if (n == "--db-user")
+ user = argv[++i];
+ else if (n == "--db-password")
+ password = argv[++i];
+ else if (n == "--db-name")
+ name = argv[++i];
+ else if (n == "--db-host")
+ host = argv[++i];
+ else if (n == "--db-port")
+ port = stoul (argv[++i]);
+ }
+
+ if (i != argc - 1)
+ {
+ print_usage ();
return 1;
}
try
{
- path cp (argv[6]);
+ path cp (argv[argc - 1]);
// Make configuration file path absolute to use it's directory as base for
// internal repositories relative local paths.
@@ -85,35 +116,44 @@ main (int argc, char* argv[])
// Check persistent objects validity.
//
odb::pgsql::database db (
- "",
- "",
- "brep",
- argv[3],
- stoul (argv[5]),
+ user,
+ password,
+ name,
+ host,
+ port,
"options='-c default_transaction_isolation=serializable'");
{
session s;
transaction t (db.begin ());
- assert (db.query<repository> ().size () == 5);
+ assert (db.query<repository> ().size () == 7);
assert (db.query<package> ().size () == 16);
- shared_ptr<repository> sr (db.load<repository> ("cppget.org/stable"));
- shared_ptr<repository> mr (db.load<repository> ("cppget.org/math"));
- shared_ptr<repository> cr (db.load<repository> ("cppget.org/misc"));
- shared_ptr<repository> tr (db.load<repository> ("cppget.org/testing"));
- shared_ptr<repository> gr (db.load<repository> ("cppget.org/staging"));
+ shared_ptr<repository> sr (
+ db.load<repository> ("dev.cppget.org/stable"));
+
+ shared_ptr<repository> mr (
+ db.load<repository> ("dev.cppget.org/math"));
+
+ shared_ptr<repository> cr (
+ db.load<repository> ("dev.cppget.org/misc"));
+
+ shared_ptr<repository> tr (
+ db.load<repository> ("dev.cppget.org/testing"));
+
+ shared_ptr<repository> gr (
+ db.load<repository> ("dev.cppget.org/staging"));
// Verify 'stable' repository.
//
- assert (sr->location.canonical_name () == "cppget.org/stable");
+ assert (sr->location.canonical_name () == "dev.cppget.org/stable");
assert (sr->location.string () ==
- "http://pkg.cppget.org/1/stable");
+ "http://dev.cppget.org/1/stable");
assert (sr->display_name == "stable");
assert (sr->priority == 1);
assert (!sr->url);
- assert (sr->email && *sr->email == "repoman@cppget.org" &&
+ assert (sr->email && *sr->email == "repoman@dev.cppget.org" &&
sr->email->comment == "public mailing list");
assert (sr->summary &&
*sr->summary == "General C++ package stable repository");
@@ -122,11 +162,14 @@ main (int argc, char* argv[])
"stuff.");
dir_path srp (cp.directory () / dir_path ("1/stable"));
- assert (sr->local_path == srp.normalize ());
+ assert (sr->cache_location.path () == srp.normalize ());
assert (sr->packages_timestamp == srt);
assert (sr->repositories_timestamp ==
- file_mtime (dir_path (sr->local_path) / path ("repositories")));
+ file_mtime (
+ dir_path (
+ sr->cache_location.path ()) / path ("repositories")));
+
assert (sr->internal);
assert (sr->complements.empty ());
assert (sr->prerequisites.size () == 2);
@@ -166,7 +209,7 @@ main (int argc, char* argv[])
assert (check_location (fpv1));
assert (fpv1->sha256sum && *fpv1->sha256sum ==
- "754cba3da34dd0296866027a26b6bacf08cacc80f54516d3b8d8eeccbe31ab93");
+ "d8ad319b55fdd19ff24cb0fcf9d61101289569f80b8688884389587cfafa1f1e");
// libfoo-1.2.2
//
@@ -219,7 +262,7 @@ main (int argc, char* argv[])
assert (check_location (fpv2));
assert (fpv2->sha256sum && *fpv2->sha256sum ==
- "751cba3da34dd0296866027a26b6bacf08cacc80f54516d3b8d8eeccbe31ab93");
+ "b47de1b207ef097c9ecdd560007aeadd3775f4fafb4f96fb983e9685c21f3980");
// libfoo-1.2.2-alpha.1
//
@@ -288,7 +331,7 @@ main (int argc, char* argv[])
assert (check_location (fpv2a));
assert (fpv2a->sha256sum && *fpv2a->sha256sum ==
- "752cba3da34dd0296866027a26b6bacf08cacc80f54516d3b8d8eeccbe31ab93");
+ "34fc224087bfd9212de4acfbbf5275513ebc57678b5f029546918a62c57d15cb");
// libfoo-1.2.3-4
//
@@ -325,7 +368,7 @@ main (int argc, char* argv[])
assert (check_location (fpv3));
assert (fpv3->sha256sum && *fpv3->sha256sum ==
- "750cba3da34dd0296866027a26b6bacf08cacc80f54516d3b8d8eeccbe31ab93");
+ "204fb25edf2404e9e88e1bef8b2a444281a807d9087093147a2cc80a1ffba79a");
// libfoo-1.2.4
//
@@ -363,29 +406,34 @@ main (int argc, char* argv[])
assert (check_location (fpv4));
assert (fpv4->sha256sum && *fpv4->sha256sum ==
- "753cba3da34dd0296866027a26b6bacf08cacc80f54516d3b8d8eeccbe31ab93");
+ "aa1606323bfc59b70de642629dc5d8318cc5348e3646f90ed89406d975db1e1d");
// Verify 'math' repository.
//
- assert (mr->location.canonical_name () == "cppget.org/math");
+ assert (mr->location.canonical_name () == "dev.cppget.org/math");
assert (mr->location.string () ==
- "http://pkg.cppget.org/1/math");
+ "http://dev.cppget.org/1/math");
assert (mr->display_name == "math");
assert (mr->priority == 2);
assert (!mr->url);
- assert (mr->email && *mr->email == "repoman@cppget.org");
+ assert (mr->email && *mr->email == "repoman@dev.cppget.org");
assert (mr->summary && *mr->summary == "Math C++ package repository");
assert (mr->description && *mr->description ==
"This is the awesome C++ package repository full of remarkable "
"algorithms and\nAPIs.");
dir_path mrp (cp.directory () / dir_path ("1/math"));
- assert (mr->local_path == mrp.normalize ());
+ assert (mr->cache_location.path () == mrp.normalize ());
assert (mr->packages_timestamp ==
- file_mtime (dir_path (mr->local_path) / path ("packages")));
+ file_mtime (
+ dir_path (mr->cache_location.path ()) / path ("packages")));
+
assert (mr->repositories_timestamp ==
- file_mtime (dir_path (mr->local_path) / path ("repositories")));
+ file_mtime (
+ dir_path (
+ mr->cache_location.path ()) / path ("repositories")));
+
assert (mr->internal);
assert (mr->complements.empty ());
@@ -437,7 +485,7 @@ main (int argc, char* argv[])
assert (check_location (xpv));
assert (xpv->sha256sum && *xpv->sha256sum ==
- "05ccba3da34dd0296866027a26b6bacf08cacc80f54516d3b8d8eeccbe31ab93");
+ "cfa4b1f89f8e903d48eff1e1d14628c32aa4d126d09b0b056d2cd80f8dc78580");
// Verify libfoo package versions.
//
@@ -546,7 +594,7 @@ main (int argc, char* argv[])
assert (check_location (fpv5));
assert (fpv5->sha256sum && *fpv5->sha256sum ==
- "35ccba3da34dd0296866027a26b6bacf08cacc80f54516d3b8d8eeccbe31ab93");
+ "6bf9de8c4647a32dee79ad5e787c10311495e3f6b5727bfd03b2d9dcd6a16eed");
// Verify libexp package version.
//
@@ -582,13 +630,13 @@ main (int argc, char* argv[])
assert (check_location (epv));
assert (epv->sha256sum && *epv->sha256sum ==
- "15ccba3da34dd0296866027a26b6bacf08cacc80f54516d3b8d8eeccbe31ab93");
+ "6c1869459964c8c780bd63d67e4c0727e583965e7280fd1f31be3f3639206191");
// Verify 'misc' repository.
//
- assert (cr->location.canonical_name () == "cppget.org/misc");
+ assert (cr->location.canonical_name () == "dev.cppget.org/misc");
assert (cr->location.string () ==
- "http://pkg.cppget.org/1/misc");
+ "http://dev.cppget.org/1/misc");
assert (cr->display_name.empty ());
assert (cr->priority == 0);
assert (cr->url && *cr->url == "http://misc.cppget.org/");
@@ -597,12 +645,17 @@ main (int argc, char* argv[])
assert (!cr->description);
dir_path crp (cp.directory () / dir_path ("1/misc"));
- assert (cr->local_path == crp.normalize ());
+ assert (cr->cache_location.path () == crp.normalize ());
assert (cr->packages_timestamp ==
- file_mtime (dir_path (cr->local_path) / path ("packages")));
+ file_mtime (
+ dir_path (cr->cache_location.path ()) / path ("packages")));
+
assert (cr->repositories_timestamp ==
- file_mtime (dir_path (cr->local_path) / path ("repositories")));
+ file_mtime (
+ dir_path (
+ cr->cache_location.path ()) / path ("repositories")));
+
assert (!cr->internal);
assert (cr->prerequisites.empty ());
assert (cr->complements.size () == 1);
@@ -644,9 +697,9 @@ main (int argc, char* argv[])
// Verify 'testing' repository.
//
- assert (tr->location.canonical_name () == "cppget.org/testing");
+ assert (tr->location.canonical_name () == "dev.cppget.org/testing");
assert (tr->location.string () ==
- "http://pkg.cppget.org/1/testing");
+ "http://dev.cppget.org/1/testing");
assert (tr->display_name.empty ());
assert (tr->priority == 0);
assert (tr->url && *tr->url == "http://test.cppget.org/hello/");
@@ -655,12 +708,17 @@ main (int argc, char* argv[])
assert (!tr->description);
dir_path trp (cp.directory () / dir_path ("1/testing"));
- assert (tr->local_path == trp.normalize ());
+ assert (tr->cache_location.path () == trp.normalize ());
assert (tr->packages_timestamp ==
- file_mtime (dir_path (tr->local_path) / path ("packages")));
+ file_mtime (
+ dir_path (tr->cache_location.path ()) / path ("packages")));
+
assert (tr->repositories_timestamp ==
- file_mtime (dir_path (tr->local_path) / path ("repositories")));
+ file_mtime (
+ dir_path (
+ tr->cache_location.path ()) / path ("repositories")));
+
assert (!tr->internal);
assert (tr->prerequisites.empty ());
assert (tr->complements.size () == 1);
@@ -690,23 +748,28 @@ main (int argc, char* argv[])
// Verify 'staging' repository.
//
- assert (gr->location.canonical_name () == "cppget.org/staging");
+ assert (gr->location.canonical_name () == "dev.cppget.org/staging");
assert (gr->location.string () ==
- "http://pkg.cppget.org/1/staging");
+ "http://dev.cppget.org/1/staging");
assert (gr->display_name.empty ());
assert (gr->priority == 0);
- assert (gr->url && *gr->url == "http://cppget.org/");
+ assert (gr->url && *gr->url == "http://dev.cppget.org/");
assert (!gr->email);
assert (!gr->summary);
assert (!gr->description);
dir_path grp (cp.directory () / dir_path ("1/staging"));
- assert (gr->local_path == grp.normalize ());
+ assert (gr->cache_location.path () == grp.normalize ());
assert (gr->packages_timestamp ==
- file_mtime (dir_path (gr->local_path) / path ("packages")));
+ file_mtime (
+ dir_path (gr->cache_location.path ()) / path ("packages")));
+
assert (gr->repositories_timestamp ==
- file_mtime (dir_path (gr->local_path) / path ("repositories")));
+ file_mtime (
+ dir_path (
+ gr->cache_location.path ()) / path ("repositories")));
+
assert (!gr->internal);
assert (gr->prerequisites.empty ());
assert (gr->complements.empty ());
diff --git a/tests/load/key.pem b/tests/load/key.pem
new file mode 100644
index 0000000..c997a12
--- /dev/null
+++ b/tests/load/key.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+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
+-----END RSA PRIVATE KEY-----
diff --git a/tests/load/openssl.cnf b/tests/load/openssl.cnf
new file mode 100644
index 0000000..0ad12ee
--- /dev/null
+++ b/tests/load/openssl.cnf
@@ -0,0 +1,22 @@
+repository = dev.cppget.org
+company = Code Synthesis
+email = info@dev.cppget.org
+
+
+[ req ]
+
+distinguished_name = req_distinguished_name
+x509_extensions = v3_req
+prompt = no
+utf8 = yes
+
+[ req_distinguished_name ]
+
+O = $company
+CN = name:$repository
+
+[ v3_req ]
+
+keyUsage = critical,digitalSignature
+extendedKeyUsage = critical,codeSigning
+subjectAltName = email:$email
diff --git a/tests/load/pkg/1/dev.cppget.org/signed/packages b/tests/load/pkg/1/dev.cppget.org/signed/packages
new file mode 100644
index 0000000..47d180e
--- /dev/null
+++ b/tests/load/pkg/1/dev.cppget.org/signed/packages
@@ -0,0 +1,2 @@
+: 1
+sha256sum: b7aeafe86ec575c43ad86a94548e6105e4af196e43225bcd4b4f38d3661af1d5
diff --git a/tests/load/pkg/1/dev.cppget.org/signed/repositories b/tests/load/pkg/1/dev.cppget.org/signed/repositories
new file mode 100644
index 0000000..79228c5
--- /dev/null
+++ b/tests/load/pkg/1/dev.cppget.org/signed/repositories
@@ -0,0 +1,35 @@
+: 1
+# Local repository manifest (this repository).
+#
+certificate: \
+-----BEGIN CERTIFICATE-----
+MIIFOzCCAyOgAwIBAgIJANKSVz8Ff0f3MA0GCSqGSIb3DQEBCwUAMDcxFzAVBgNV
+BAoMDkNvZGUgU3ludGhlc2lzMRwwGgYDVQQDDBNuYW1lOmRldi5jcHBnZXQub3Jn
+MB4XDTE2MDcwNjE2Mzg1NloXDTE3MDcwNjE2Mzg1NlowNzEXMBUGA1UECgwOQ29k
+ZSBTeW50aGVzaXMxHDAaBgNVBAMME25hbWU6ZGV2LmNwcGdldC5vcmcwggIiMA0G
+CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDK8NqNbQckQpv9B3hBRjnTcpkgKq2e
+1HOFLQJxgS1TS2QfqUTKePpd10LbDgXOhI2iycKCf7Zv/uf3RE+VyQ/BthNUvQ0O
+bWPsEKo+DQOLPjqIaS+u2bmMXzCDjwjufbd9ruPY2PYRTBOsXgTL1+GGIQu0bP5u
+i1mEGn95xuYhEJ4x1UUsVWV0l0D37orV/OaOVffPY3xhlQE++aiXLptof1gzM2D8
+lsQPvWLizrtDAHpiwb4oXQQbifDyeXj+qh7OdIqL10rxZZ/0Q0GqrTOyeSlXuo5i
+C3MdNSlRmWNGqvPwpushFBQec04exXI3AjQZ/DUlMxtDx2xIqQMtaYOQ5iqm9426
+crgrUoXZG/5ePYTCmnSbpZVak9md44inJWqSESTL0+EfWuLdXop0QV7LZrIaV2pV
+BJba0/jiS5mltR/ikiJ7gaP/bbfutJGGfzyk1PrvyehhK/snGUh6Nr0NMHozS+J+
+7QXdSEMjLXbmF5hBsvEfrGub+YSexEEODA34YnBIA453ph4CIo/3nTpDLrm3EkSF
+1jV5vGhg3vzB6v+TIP9MXALm4/NUurn8I643KMoNSS9RCDuiqLnE8V1uCmSP8LR8
+OO7vxlmaM/OfqHehAALgsU/KFT1lgpAfHE2x5YBxT6s407DJJpaPkbHMiCNHScWQ
+5ezqnH0UMNwsawIDAQABo0owSDAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAww
+CgYIKwYBBQUHAwMwHgYDVR0RBBcwFYETaW5mb0BkZXYuY3BwZ2V0Lm9yZzANBgkq
+hkiG9w0BAQsFAAOCAgEAGA83AWQKtVktqPAJwpikLbP+zPAUpQ8C76aFPIYq1u+f
+Sy8koKmklWet/1bQRtYzV7Wa9Gd+OfUjiBSc2zBqKy+9kU0rJsxUjMQayzx5OoOA
+rZHyQGb585XWhdpp/opImYUisCr677YLgJwGUR86ylrSGgCd9YlNyAO13rcmaduu
+smEzKjJtRtZk4FSl9P7DDRZ2oC3lqVNd5oEDGbEaQj5+FL7uiEdQcPYrwxK8kL2z
+uxowough8o9uKLRlirKe/YpiBw+MCsEH+eKX/1cO2upA+vnf0kYrOGLVjv641Feg
+aYLQsSZSv/pPm7AUX25eHYEZOcxRS4YnHmj//OSV/ZquAXvD5jTA/dZrlL/WGBuI
+TUMz9I9RtZHJfxybaEXz3g3EgJMYSBFVoEYTbk7XJrV7cImpJev+uFplGH0zcQqv
+aIgXYmvoAUxo4DixIhZ7E+niBLir9yJCSc2STe9tImtU31UDczohlKm1X2wX8ShW
+K4ugd2FCB9d5THPyeJ0gJg8NiugaucYnuaXbONX2G4Kw/mWpXFJoK6PLiHo6MpRw
+/NPPdNokVDEYPhrqGfwSYhI42KtqKdt+jK1Go4z1blYnqZBYWTnOWPPMimOnx+/S
+XrAdAH187sXX9MAq9TQNmdoz+ua4jqHx44EdfIK2NFEhs1hR8Gt1ZeIjcU3fEO8=
+-----END CERTIFICATE-----
+\ \ No newline at end of file
diff --git a/tests/load/pkg/1/dev.cppget.org/signed/signature b/tests/load/pkg/1/dev.cppget.org/signed/signature
new file mode 100644
index 0000000..7905c14
--- /dev/null
+++ b/tests/load/pkg/1/dev.cppget.org/signed/signature
@@ -0,0 +1,13 @@
+: 1
+sha256sum: 5dc41de74d92011ca533c79e9e88b0aa6d1de29b9a498ef09e7736a87d37307d
+signature: \
+ZSDEdQ3HIQdpd16sS+Y9ZBINQ0ooI+eRISs/RjLWNMxnd7vcDlSItykPTaCpwEvMQme1yFD5cCQG
+ZRmgiMDcht0ptAfGRuyhkYLwvjFsejVKkBmaHLrcn30twLgPTsqZuODmDR79x3o/4fd7xou7mbav
+YbbTUcmvX6pznT7E70x00vRijpGYvgW8LVq6hdnjhsK5TY9dy3wT8HdhivxHoypol+gCljHwZD4T
+11oBafwME+kP8KzDZYa5Ko9h+z1cS/jggqG1H2hKsQn/PC2lbv0pao3vSBS9dO/uwfXasS42PGis
+0midpDLBe0ROPm8kln1mXldhvgBoaNQAy+muLquAcPkPVFXr1pwEABhOGjXxdwPhbYADXTLw5H5X
+YR6Y1LSlb5RJULmHffezwIEu1qTiKIvXvllFJ3Km9h548PijADFN7BFU+Q89WBQZo389NJETFW3m
++mZlBGYG/j89/47R3B9PUZeEjFdObOnkx4eJNsPZXnk8LRC46K4EdzRi9hurtW+209cOHjCwdV4D
+kx85+LMFgxmgEOkZ/+KpdoRfh4rYgHvYig4VGPiG+4Dn4NBYjTU+XfxAB1xANBVttP8MorESqgpv
+VlVp43/w5lr1uPKb5AyKgP63u+mezE2gjWYkE2Yhyg5jku+YTPS9CM4W8ReBxNoCGDCuTt/3Lqg=
+\
diff --git a/tests/load/pkg/1/dev.cppget.org/unsigned/packages b/tests/load/pkg/1/dev.cppget.org/unsigned/packages
new file mode 100644
index 0000000..0de6976
--- /dev/null
+++ b/tests/load/pkg/1/dev.cppget.org/unsigned/packages
@@ -0,0 +1,2 @@
+: 1
+sha256sum: 50071b1450c7b0013075e12f0fb2b17f12acb4d152f8c86e097b5174b343535f
diff --git a/tests/load/pkg/1/dev.cppget.org/unsigned/repositories b/tests/load/pkg/1/dev.cppget.org/unsigned/repositories
new file mode 100644
index 0000000..9a15f2b
--- /dev/null
+++ b/tests/load/pkg/1/dev.cppget.org/unsigned/repositories
@@ -0,0 +1,3 @@
+: 1
+# Local repository manifest (this repository).
+#
diff --git a/tests/load/r.conf b/tests/load/r.conf
index 8da4b77..fe06984 100644
--- a/tests/load/r.conf
+++ b/tests/load/r.conf
@@ -1,2 +1,4 @@
-http://pkg.cppget.org/1/stable stable 1/stable
-http://pkg.cppget.org/1/math math 1/math
+http://dev.cppget.org/1/stable stable cache:1/stable
+http://dev.cppget.org/1/math math cache:1/math
+http://dev.cppget.org/1/signed signed cache:pkg/1/dev.cppget.org/signed fingerprint:AC:9B:64:F3:DA:82:E3:0C:86:25:A5:0A:56:A9:64:31:A5:61:AD:ED:B8:AF:91:0D:3C:88:E4:43:19:30:CF:82
+http://dev.cppget.org/1/unsigned unsigned cache:pkg/1/dev.cppget.org/unsigned fingerprint:
diff --git a/www/package-version-details-body.css b/www/package-version-details-body.css
index df7889e..2fa2972 100644
--- a/www/package-version-details-body.css
+++ b/www/package-version-details-body.css
@@ -106,7 +106,7 @@ h1, h2, h3
#version tr.sha256 td .value
{
/* Increase the chances of 64-char value not to be truncated. */
- font-size: 0.9em;
+ font-size: 0.88em;
}
/*
diff --git a/www/repository-details-body.css b/www/repository-details-body.css
index ae04520..7f211d3 100644
--- a/www/repository-details-body.css
+++ b/www/repository-details-body.css
@@ -26,3 +26,23 @@ h2
margin: .4em 0 .4em 0;
}
+
+/*
+ * Certificate details.
+ */
+p.certfp
+{
+ font-size: 0.74em;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+pre.certpem
+{
+ font-size: 0.97em;
+ white-space: pre;
+ margin: .5em 0 .5em 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}