aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2018-02-19 14:26:02 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2018-02-19 14:27:24 +0300
commit3d4838d3706de2ba0045dc9f99a3dc96398def64 (patch)
treeece29423c4ece1139169a8b952914471593fe577
parentd3ef22615ba7d37be18c31b2fdd1bdb6be164939 (diff)
Parse repositories and packages files for git repositories
-rw-r--r--bpkg/archive.cxx1
-rw-r--r--bpkg/auth.cxx1
-rw-r--r--bpkg/cfg-create.cxx3
-rw-r--r--bpkg/checksum.cxx1
-rw-r--r--bpkg/diagnostics.cxx16
-rw-r--r--bpkg/fetch-bpkg.cxx1
-rw-r--r--bpkg/fetch-git.cxx109
-rw-r--r--bpkg/fetch.cxx2
-rw-r--r--bpkg/fetch.hxx10
-rw-r--r--bpkg/package.hxx3
-rw-r--r--bpkg/pkg-verify.cxx1
-rw-r--r--bpkg/rep-create.cxx1
-rw-r--r--bpkg/rep-fetch.cxx267
-rw-r--r--bpkg/satisfaction.cxx1
-rw-r--r--bpkg/types.hxx9
-rw-r--r--bpkg/utility.cxx26
-rw-r--r--bpkg/utility.hxx8
-rw-r--r--tests/common/git/state0/libbar.tarbin61440 -> 71680 bytes
-rw-r--r--tests/common/git/state0/libfoo.tarbin256000 -> 296960 bytes
-rw-r--r--tests/common/git/state0/style-basic.tarbin61440 -> 71680 bytes
-rw-r--r--tests/common/git/state0/style.tarbin112640 -> 133120 bytes
-rw-r--r--tests/common/git/state1/libbaz.tarbin61440 -> 61440 bytes
-rw-r--r--tests/common/git/state1/libfoo.tarbin337920 -> 378880 bytes
-rw-r--r--tests/common/git/state1/style-basic.tarbin61440 -> 71680 bytes
-rw-r--r--tests/common/git/state1/style.tarbin112640 -> 133120 bytes
-rwxr-xr-xtests/publish30
-rw-r--r--tests/remote-git.test20
-rw-r--r--tests/remote.test2
-rw-r--r--tests/rep-fetch-git-branch.test8
-rw-r--r--tests/rep-fetch-git-commit.test14
-rw-r--r--tests/rep-fetch-git.test2
-rw-r--r--tests/rep-fetch.test28
-rw-r--r--tests/rep-info.test52
l---------tests/rep-info/git/libbar.tar1
l---------tests/rep-info/git/style-basic.tar1
35 files changed, 450 insertions, 168 deletions
diff --git a/bpkg/archive.cxx b/bpkg/archive.cxx
index 03728a4..cc96cd1 100644
--- a/bpkg/archive.cxx
+++ b/bpkg/archive.cxx
@@ -5,7 +5,6 @@
#include <bpkg/archive.hxx>
#include <libbutl/process.mxx>
-#include <libbutl/fdstream.mxx>
#include <bpkg/diagnostics.hxx>
diff --git a/bpkg/auth.cxx b/bpkg/auth.cxx
index df9a259..df31a60 100644
--- a/bpkg/auth.cxx
+++ b/bpkg/auth.cxx
@@ -13,7 +13,6 @@
#include <libbutl/base64.mxx>
#include <libbutl/process.mxx>
#include <libbutl/openssl.mxx>
-#include <libbutl/fdstream.mxx>
#include <libbutl/timestamp.mxx>
#include <libbutl/filesystem.mxx>
diff --git a/bpkg/cfg-create.cxx b/bpkg/cfg-create.cxx
index 1a21cfa..70d8848 100644
--- a/bpkg/cfg-create.cxx
+++ b/bpkg/cfg-create.cxx
@@ -4,15 +4,12 @@
#include <bpkg/cfg-create.hxx>
-#include <libbutl/fdstream.mxx>
-
#include <bpkg/package.hxx>
#include <bpkg/package-odb.hxx>
#include <bpkg/database.hxx>
#include <bpkg/diagnostics.hxx>
using namespace std;
-using namespace butl;
namespace bpkg
{
diff --git a/bpkg/checksum.cxx b/bpkg/checksum.cxx
index 0ada207..14c0bf7 100644
--- a/bpkg/checksum.cxx
+++ b/bpkg/checksum.cxx
@@ -13,7 +13,6 @@
#include <libbutl/sha256.mxx>
#include <libbutl/process.mxx>
-#include <libbutl/fdstream.mxx>
#include <libbutl/filesystem.mxx>
#include <bpkg/diagnostics.hxx>
diff --git a/bpkg/diagnostics.cxx b/bpkg/diagnostics.cxx
index 9672926..bb175d8 100644
--- a/bpkg/diagnostics.cxx
+++ b/bpkg/diagnostics.cxx
@@ -10,6 +10,7 @@
#include <odb/statement.hxx>
#include <libbutl/process.mxx>
+#include <libbutl/process-io.mxx> // operator<<(ostream, process_arg)
using namespace std;
using namespace butl;
@@ -25,19 +26,6 @@ namespace bpkg
print_process (r, args, n);
}
- struct process_args
- {
- const char* const* a;
- size_t n;
- };
-
- inline static ostream&
- operator<< (ostream& o, const process_args& p)
- {
- process::print (o, p.a, p.n);
- return o;
- }
-
void
print_process (diag_record& r, const char* const args[], size_t n)
{
@@ -104,7 +92,7 @@ namespace bpkg
if (verb >= 3)
{
diag_record dr (*this);
- process::print (dr.os, args, n);
+ print_process (dr, args, n);
}
}
diff --git a/bpkg/fetch-bpkg.cxx b/bpkg/fetch-bpkg.cxx
index 4fe0bfc..606843f 100644
--- a/bpkg/fetch-bpkg.cxx
+++ b/bpkg/fetch-bpkg.cxx
@@ -6,7 +6,6 @@
#include <sstream>
-#include <libbutl/fdstream.mxx>
#include <libbutl/filesystem.mxx> // cpfile ()
#include <libbutl/manifest-parser.mxx>
diff --git a/bpkg/fetch-git.cxx b/bpkg/fetch-git.cxx
index fa9723c..7ffaaaf 100644
--- a/bpkg/fetch-git.cxx
+++ b/bpkg/fetch-git.cxx
@@ -10,7 +10,6 @@
#include <libbutl/utility.mxx> // digit(), xdigit()
#include <libbutl/process.mxx>
-#include <libbutl/fdstream.mxx>
#include <libbutl/standard-version.mxx>
#include <bpkg/diagnostics.hxx>
@@ -34,32 +33,6 @@ namespace bpkg
static const diag_noreturn_end<fail_git> endg;
- static fdpipe
- open_pipe ()
- {
- try
- {
- return fdopen_pipe ();
- }
- catch (const io_error& e)
- {
- fail << "unable to open pipe: " << e << endf;
- }
- }
-
- static auto_fd
- open_dev_null ()
- {
- try
- {
- return fdnull ();
- }
- catch (const io_error& e)
- {
- fail << "unable to open null device: " << e << endf;
- }
- }
-
using opt = optional<const char*>; // Program option.
static strings
@@ -167,7 +140,9 @@ namespace bpkg
}
if (v.empty ())
- fail << "unable to obtain git version from '" << s << "'" << endg;
+ fail << "'" << s << "' doesn't appear to contain a git version" <<
+ info << "produced by '" << co.git () << "'; "
+ << "use --git to override" << endg;
if (v.version < 20120000000)
fail << "unsupported git version " << v.string () <<
@@ -191,15 +166,14 @@ namespace bpkg
try
{
- ifdstream is (move (pipe.in), fdstream_mode::skip);
+ ifdstream is (move (pipe.in),
+ fdstream_mode::skip,
+ ifdstream::badbit);
- while (is.peek () != ifdstream::traits_type::eof ())
+ for (string l; !eof (getline (is, l)); )
{
- string v;
- getline (is, v);
-
- if (v != "GIT_CONFIG_PARAMETERS")
- unset_vars->push_back (move (v));
+ if (l != "GIT_CONFIG_PARAMETERS")
+ unset_vars->push_back (move (l));
}
is.close ();
@@ -246,7 +220,9 @@ namespace bpkg
static process_exit
run_git (const common_options& co, A&&... args)
{
- process pr (start_git (co, 1, 2, forward<A> (args)...));
+ process pr (start_git (co,
+ 1 /* stdout */, 2 /* stderr */,
+ forward<A> (args)...));
pr.wait ();
return *pr.exit;
}
@@ -508,16 +484,13 @@ namespace bpkg
try
{
bool r (false);
- ifdstream is (move (pipe.in), fdstream_mode::skip);
+ ifdstream is (move (pipe.in), fdstream_mode::skip, ifdstream::badbit);
- while (is.peek () != ifdstream::traits_type::eof ())
+ for (string l; !eof (getline (is, l)); )
{
- string s;
- getline (is, s);
-
- l4 ([&]{trace << "ref: " << s;});
+ l4 ([&]{trace << "ref: " << l;});
- if (s.compare (0, commit.size (), commit) == 0)
+ if (l.compare (0, commit.size (), commit) == 0)
{
r = true;
break;
@@ -787,9 +760,9 @@ namespace bpkg
try
{
- ifdstream is (move (pipe.in), fdstream_mode::skip);
+ ifdstream is (move (pipe.in), fdstream_mode::skip, ifdstream::badbit);
- while (is.peek () != ifdstream::traits_type::eof ())
+ for (string l; !eof (getline (is, l)); )
{
// The line describing a submodule has the following form:
//
@@ -799,19 +772,16 @@ namespace bpkg
//
// 160000 658436a9522b5a0d016c3da0253708093607f95d 0 doc/style
//
- string s;
- getline (is, s);
-
- l4 ([&]{trace << "submodule: " << s;});
+ l4 ([&]{trace << "submodule: " << l;});
- if (!(s.size () > 50 && s[48] == '0' && s[49] == '\t'))
+ if (!(l.size () > 50 && l[48] == '0' && l[49] == '\t'))
failure ("invalid submodule description");
- string commit (s.substr (7, 40));
+ string commit (l.substr (7, 40));
// Submodule directory path, relative to the containing project.
//
- dir_path sdir (s.substr (50));
+ dir_path sdir (l.substr (50));
// Submodule directory path, relative to the top project.
//
@@ -955,7 +925,22 @@ namespace bpkg
}
}
- void
+ // Produce a repository directory name for the specified git reference.
+ //
+ // Truncate commit id-based directory names to shorten absolute directory
+ // paths, lowering the probability of hitting the limit on Windows.
+ //
+ // Note that we can't truncate them for branches/tags as chances to clash
+ // would be way higher than for commit ids. Though such names are normally
+ // short anyway.
+ //
+ static inline dir_path
+ repository_dir (const git_reference& ref)
+ {
+ return dir_path (ref.commit ? ref.commit->substr (0, 16) : *ref.branch);
+ }
+
+ dir_path
git_clone (const common_options& co,
const repository_location& rl,
const dir_path& destdir)
@@ -975,14 +960,8 @@ namespace bpkg
else
fetch_warn (cap, single_branch ? "branch" : "repository");
- dir_path d (destdir);
-
- // Truncate commit id-based directory names to shorten the absolute
- // directory path to lower probability of hitting the limit on Windows.
- // Note that we can't do the same for branch/tag names as chances to clash
- // would be way higher. Though such names are normally short anyway.
- //
- d /= dir_path (ref.branch ? *ref.branch : ref.commit->substr (0, 16));
+ dir_path r (repository_dir (ref));
+ dir_path d (destdir / r);
strings to (timeout_opts (co, url.scheme));
@@ -1007,9 +986,10 @@ namespace bpkg
update_tree (co, d, dir_path (), ref, cap, shallow, to);
update_submodules (co, d, dir_path ());
+ return r;
}
- void
+ dir_path
git_fetch (const common_options& co,
const repository_location& rl,
const dir_path& destdir)
@@ -1017,6 +997,8 @@ namespace bpkg
repository_url url (rl.url ());
git_reference ref (parse_reference (url, "fetch"));
+ dir_path r (repository_dir (ref));
+
// Fetch is noop if the specific commit is checked out.
//
// What if the user replaces the repository URL with a one with a new
@@ -1026,7 +1008,7 @@ namespace bpkg
// this should work correctly automatically.
//
if (ref.commit)
- return;
+ return r;
assert (ref.branch);
@@ -1045,5 +1027,6 @@ namespace bpkg
timeout_opts (co, url.scheme));
update_submodules (co, d, dir_path ());
+ return r;
}
}
diff --git a/bpkg/fetch.cxx b/bpkg/fetch.cxx
index c5366e3..680ab9e 100644
--- a/bpkg/fetch.cxx
+++ b/bpkg/fetch.cxx
@@ -4,7 +4,7 @@
#include <bpkg/fetch.hxx>
-#include <libbutl/fdstream.mxx>
+#include <libbutl/process.mxx>
#include <bpkg/diagnostics.hxx>
diff --git a/bpkg/fetch.hxx b/bpkg/fetch.hxx
index f243e09..659e019 100644
--- a/bpkg/fetch.hxx
+++ b/bpkg/fetch.hxx
@@ -49,16 +49,18 @@ namespace bpkg
// Repository type git (fetch-git.cxx).
//
- // Clone git repository into destdir/<fragment>/.
+ // Clone git repository into destdir/<name>/. Return the cloned repository
+ // directory name that was deduced from the repository URL fragment.
//
- void
+ dir_path
git_clone (const common_options&,
const repository_location&,
const dir_path& destdir);
- // Fetch git repository in destdir/<fragment>/.
+ // Fetch git repository in destdir/<name>/. Return the fetched repository
+ // directory name that was deduced from the repository URL fragment.
//
- void
+ dir_path
git_fetch (const common_options&,
const repository_location&,
const dir_path& destdir);
diff --git a/bpkg/package.hxx b/bpkg/package.hxx
index 95b1bb3..67b1753 100644
--- a/bpkg/package.hxx
+++ b/bpkg/package.hxx
@@ -354,7 +354,8 @@ namespace bpkg
dependencies_type dependencies;
- // Present for non-transient objects only.
+ // Present for non-transient objects only (and only for certain repository
+ // types).
//
optional<string> sha256sum;
diff --git a/bpkg/pkg-verify.cxx b/bpkg/pkg-verify.cxx
index d46e5b6..2f01f94 100644
--- a/bpkg/pkg-verify.cxx
+++ b/bpkg/pkg-verify.cxx
@@ -5,7 +5,6 @@
#include <bpkg/pkg-verify.hxx>
#include <libbutl/process.mxx>
-#include <libbutl/fdstream.mxx>
#include <libbutl/manifest-parser.mxx>
#include <bpkg/archive.hxx>
diff --git a/bpkg/rep-create.cxx b/bpkg/rep-create.cxx
index 228b7f6..e9619ca 100644
--- a/bpkg/rep-create.cxx
+++ b/bpkg/rep-create.cxx
@@ -6,7 +6,6 @@
#include <map>
-#include <libbutl/fdstream.mxx>
#include <libbutl/filesystem.mxx> // dir_iterator
#include <libbutl/manifest-serializer.mxx>
diff --git a/bpkg/rep-fetch.cxx b/bpkg/rep-fetch.cxx
index d7f0386..029db1d 100644
--- a/bpkg/rep-fetch.cxx
+++ b/bpkg/rep-fetch.cxx
@@ -5,6 +5,9 @@
#include <bpkg/rep-fetch.hxx>
#include <libbutl/sha256.mxx>
+#include <libbutl/process.mxx>
+#include <libbutl/process-io.mxx> // operator<<(ostream, process_path)
+#include <libbutl/manifest-parser.mxx>
#include <bpkg/auth.hxx>
#include <bpkg/fetch.hxx>
@@ -74,30 +77,64 @@ namespace bpkg
return rep_fetch_data {move (rms), move (pms), move (cert)};
}
+ template <typename M>
+ static M
+ parse_manifest (const path& f, bool iu, const repository_location& rl)
+ {
+ try
+ {
+ ifdstream ifs (f);
+ manifest_parser mp (ifs, f.string ());
+ return M (mp, iu);
+ }
+ catch (const manifest_parsing& e)
+ {
+ fail (e.name, e.line, e.column) << e.description <<
+ info << "repository " << rl << endf;
+ }
+ catch (const io_error& e)
+ {
+ fail << "unable to read from " << f << ": " << e <<
+ info << "repository " << rl << endf;
+ }
+ }
+
static rep_fetch_data
rep_fetch_git (const common_options& co,
const dir_path* conf,
const repository_location& rl,
- bool /* ignore_unknown */)
+ bool ignore_unknown)
{
// Plan:
//
// 1. Check repos_dir/<hash>/:
//
- // 1.a If does not exist, git-clone into temp_dir/<hash>/.
+ // 1.a If does not exist, git-clone into temp_dir/<hash>/<fragment>/.
//
// 1.a Otherwise, move as temp_dir/<hash>/ and git-fetch.
//
- // 2. Move from temp_dir/<hash>/ to repos_dir/<hash>/
+ // 2. Move from temp_dir/<hash>/ to repos_dir/<hash>/<fragment>/
//
- // 3. Load manifest from repos_dir/<hash>/<fragment>/
+ // 3. Check if repos_dir/<hash>/<fragment>/repositories exists:
//
- // 4. Run 'b info' in repos_dir/<hash>/<fragment>/ and fix-up
- // package version.
+ // 3.a If exists, load.
//
- // 5. Synthesize repository manifest.
+ // 3.b Otherwise, synthesize repository list with base repository.
//
- // 6. Return repository and package manifest (certificate is NULL).
+ // 4. Check if repos_dir/<hash>/<fragment>/packages exists:
+ //
+ // 4.a If exists, load. (into "skeleton" packages list to be filled?)
+ //
+ // 4.b Otherwise, synthesize as if single 'location: ./'.
+ //
+ // 5. For each package location obtained on step 4:
+ //
+ // 5.a Load repos_dir/<hash>/<fragment>/<location>/manifest.
+ //
+ // 5.b Run 'b info: repos_dir/<hash>/<fragment>/<location>/' and fix-up
+ // package version.
+ //
+ // 6. Return repository and package manifests (certificate is NULL).
//
if (conf != nullptr && conf->empty ())
@@ -105,6 +142,8 @@ namespace bpkg
assert (conf == nullptr || !conf->empty ());
+ // Clone or fetch the repository.
+ //
dir_path h (sha256 (rl.canonical_name ()).abbreviated_string (16));
auto_rmdir rm (temp_dir / h);
@@ -129,10 +168,7 @@ namespace bpkg
}
}
- if (fetch)
- git_fetch (co, rl, td);
- else
- git_clone (co, rl, td);
+ dir_path nm (fetch ? git_fetch (co, rl, td) : git_clone (co, rl, td));
if (!rd.empty ())
mv (td, rd);
@@ -144,9 +180,179 @@ namespace bpkg
rm.cancel ();
- // @@ TODO
+ rd /= nm;
+
+ // Produce repository manifest list.
//
- return rep_fetch_data ();
+ git_repository_manifests rms;
+ {
+ path f (rd / path ("repositories"));
+
+ if (exists (f))
+ rms = parse_manifest<git_repository_manifests> (f, ignore_unknown, rl);
+ else
+ rms.emplace_back (repository_manifest ()); // Add the base repository.
+ }
+
+ // Produce the "skeleton" package manifest list.
+ //
+ git_package_manifests pms;
+ {
+ path f (rd / path ("packages"));
+
+ if (exists (f))
+ pms = parse_manifest<git_package_manifests> (f, ignore_unknown, rl);
+ else
+ {
+ pms.push_back (package_manifest ());
+ pms.back ().location = current_dir;
+ }
+ }
+
+ // Fill "skeleton" package manifests.
+ //
+ for (package_manifest& sm: pms)
+ {
+ assert (sm.location);
+
+ auto package_info = [&sm, &rl] (diag_record& dr)
+ {
+ dr << "package ";
+
+ if (!sm.location->current ())
+ dr << "'" << sm.location->string () << "' "; // Strip trailing '/'.
+
+ dr << "in repository " << rl;
+ };
+
+ auto failure = [&package_info] (const char* desc)
+ {
+ diag_record dr (fail);
+ dr << desc << " for ";
+ package_info (dr);
+ };
+
+ dir_path d (rd / path_cast<dir_path> (*sm.location));
+ path f (d / path ("manifest"));
+
+ if (!exists (f))
+ failure ("no manifest file");
+
+ try
+ {
+ ifdstream ifs (f);
+ manifest_parser mp (ifs, f.string ());
+ package_manifest m (bpkg_package_manifest (mp, ignore_unknown));
+
+ // Save the package manifest, preserving its location.
+ //
+ m.location = move (sm.location);
+ sm = move (m);
+ }
+ catch (const manifest_parsing& e)
+ {
+ diag_record dr (fail (e.name, e.line, e.column));
+ dr << e.description << info;
+ package_info (dr);
+ }
+ catch (const io_error& e)
+ {
+ diag_record dr (fail);
+ dr << "unable to read from " << f << ": " << e << info;
+ package_info (dr);
+ }
+
+ // Fix-up the package version.
+ //
+ const char* b (name_b (co));
+
+ try
+ {
+ process_path pp (process::path_search (b, exec_dir));
+
+ fdpipe pipe (open_pipe ());
+
+ process pr (
+ process_start_callback (
+ [] (const char* const args[], size_t n)
+ {
+ if (verb >= 2)
+ print_process (args, n);
+ },
+ 0 /* stdin */, pipe /* stdout */, 2 /* stderr */,
+ pp,
+
+ verb < 2
+ ? strings ({"-q"})
+ : verb == 2
+ ? strings ({"-v"})
+ : strings ({"--verbose", to_string (verb)}),
+
+ co.build_option (),
+ "info:",
+ d.representation ()));
+
+ // Shouldn't throw, unless something is severely damaged.
+ //
+ pipe.out.close ();
+
+ try
+ {
+ ifdstream is (move (pipe.in),
+ fdstream_mode::skip,
+ ifdstream::badbit);
+
+ for (string l; !eof (getline (is, l)); )
+ {
+ if (l.compare (0, 9, "version: ") == 0)
+ try
+ {
+ string v (l, 9);
+
+ // An empty version indicates that the version module is not
+ // enabled for the project, and so we don't amend the package
+ // version.
+ //
+ if (!v.empty ())
+ sm.version = version (v);
+
+ break;
+ }
+ catch (const invalid_argument&)
+ {
+ fail << "no package version in '" << l << "'" <<
+ info << "produced by '" << pp << "'; use --build to override";
+ }
+ }
+
+ is.close ();
+
+ if (pr.wait ())
+ continue; // Go to the next package.
+
+ // Fall through.
+ }
+ catch (const io_error&)
+ {
+ if (pr.wait ())
+ failure ("unable to read information");
+
+ // Fall through.
+ }
+
+ // We should only get here if the child exited with an error status.
+ //
+ assert (!pr.wait ());
+
+ failure ("unable to obtain information");
+ }
+ catch (const process_error& e)
+ {
+ fail << "unable to execute " << b << ": " << e;
+ }
+ }
+
+ return rep_fetch_data {move (rms), move (pms), nullptr};
}
rep_fetch_data
@@ -319,21 +525,28 @@ namespace bpkg
{
// Make sure this is the same package.
//
- assert (p->sha256sum && !p->locations.empty ()); // Can't be transient.
+ assert (!p->locations.empty ()); // Can't be transient.
- if (*pm.sha256sum != *p->sha256sum)
+ // Note that sha256sum may not present for some repository types.
+ //
+ if (pm.sha256sum)
{
- // All the previous repositories that contain this package have the
- // same checksum (since they passed this test), so we can pick any
- // to show to the user.
- //
- const string& r1 (rl.canonical_name ());
- const string& r2 (p->locations[0].repository.object_id ());
-
- fail << "checksum mismatch for " << pm.name << " " << pm.version <<
- info << r1 << " has " << *pm.sha256sum <<
- info << r2 << " has " << *p->sha256sum <<
- info << "consider reporting this to the repository maintainers";
+ if (!p->sha256sum)
+ p->sha256sum = move (pm.sha256sum);
+ else if (*pm.sha256sum != *p->sha256sum)
+ {
+ // All the previous repositories that have checksum for this
+ // package have it the same (since they passed this test), so we
+ // can pick any to show to the user.
+ //
+ const string& r1 (rl.canonical_name ());
+ const string& r2 (p->locations[0].repository.object_id ());
+
+ fail << "checksum mismatch for " << pm.name << " " << pm.version <<
+ info << r1 << " has " << *pm.sha256sum <<
+ info << r2 << " has " << *p->sha256sum <<
+ info << "consider reporting this to the repository maintainers";
+ }
}
}
diff --git a/bpkg/satisfaction.cxx b/bpkg/satisfaction.cxx
index 9aaca23..9211ac0 100644
--- a/bpkg/satisfaction.cxx
+++ b/bpkg/satisfaction.cxx
@@ -5,7 +5,6 @@
#include <bpkg/satisfaction.hxx>
#include <libbutl/process.mxx>
-#include <libbutl/fdstream.mxx>
#include <bpkg/utility.hxx>
#include <bpkg/package-odb.hxx>
diff --git a/bpkg/types.hxx b/bpkg/types.hxx
index 505d468..3133696 100644
--- a/bpkg/types.hxx
+++ b/bpkg/types.hxx
@@ -24,6 +24,7 @@
#include <libbutl/path.mxx>
#include <libbutl/optional.mxx>
+#include <libbutl/fdstream.mxx>
namespace bpkg
{
@@ -82,6 +83,14 @@ namespace bpkg
using paths = std::vector<path>;
using dir_paths = std::vector<dir_path>;
+
+ // <libbutl/fdstream.mxx>
+ //
+ using butl::auto_fd;
+ using butl::fdpipe;
+ using butl::ifdstream;
+ using butl::ofdstream;
+ using butl::fdstream_mode;
}
// In order to be found (via ADL) these have to be either in std:: or in
diff --git a/bpkg/utility.cxx b/bpkg/utility.cxx
index 26716e8..252bdef 100644
--- a/bpkg/utility.cxx
+++ b/bpkg/utility.cxx
@@ -234,6 +234,32 @@ namespace bpkg
}
}
+ fdpipe
+ open_pipe ()
+ {
+ try
+ {
+ return fdopen_pipe ();
+ }
+ catch (const io_error& e)
+ {
+ fail << "unable to open pipe: " << e << endf;
+ }
+ }
+
+ auto_fd
+ open_dev_null ()
+ {
+ try
+ {
+ return fdnull ();
+ }
+ catch (const io_error& e)
+ {
+ fail << "unable to open null device: " << e << endf;
+ }
+ }
+
dir_path exec_dir;
void
diff --git a/bpkg/utility.hxx b/bpkg/utility.hxx
index 05835b0..b05f668 100644
--- a/bpkg/utility.hxx
+++ b/bpkg/utility.hxx
@@ -116,6 +116,14 @@ namespace bpkg
void
mv (const dir_path& from, const dir_path& to);
+ // File descriptor streams.
+ //
+ fdpipe
+ open_pipe ();
+
+ auto_fd
+ open_dev_null ();
+
// Process.
//
// By default the process command line is printed for verbosity >= 2
diff --git a/tests/common/git/state0/libbar.tar b/tests/common/git/state0/libbar.tar
index 879f042..e78ae06e 100644
--- a/tests/common/git/state0/libbar.tar
+++ b/tests/common/git/state0/libbar.tar
Binary files differ
diff --git a/tests/common/git/state0/libfoo.tar b/tests/common/git/state0/libfoo.tar
index 0533b6d..141a341 100644
--- a/tests/common/git/state0/libfoo.tar
+++ b/tests/common/git/state0/libfoo.tar
Binary files differ
diff --git a/tests/common/git/state0/style-basic.tar b/tests/common/git/state0/style-basic.tar
index 9d0ff47..217ee7c 100644
--- a/tests/common/git/state0/style-basic.tar
+++ b/tests/common/git/state0/style-basic.tar
Binary files differ
diff --git a/tests/common/git/state0/style.tar b/tests/common/git/state0/style.tar
index d83c39f..fc3faa0 100644
--- a/tests/common/git/state0/style.tar
+++ b/tests/common/git/state0/style.tar
Binary files differ
diff --git a/tests/common/git/state1/libbaz.tar b/tests/common/git/state1/libbaz.tar
index c0cdb40..373863e 100644
--- a/tests/common/git/state1/libbaz.tar
+++ b/tests/common/git/state1/libbaz.tar
Binary files differ
diff --git a/tests/common/git/state1/libfoo.tar b/tests/common/git/state1/libfoo.tar
index 5708d07..23275c8 100644
--- a/tests/common/git/state1/libfoo.tar
+++ b/tests/common/git/state1/libfoo.tar
Binary files differ
diff --git a/tests/common/git/state1/style-basic.tar b/tests/common/git/state1/style-basic.tar
index 71b5985..e4e14e9 100644
--- a/tests/common/git/state1/style-basic.tar
+++ b/tests/common/git/state1/style-basic.tar
Binary files differ
diff --git a/tests/common/git/state1/style.tar b/tests/common/git/state1/style.tar
index c939a87..52389c3 100644
--- a/tests/common/git/state1/style.tar
+++ b/tests/common/git/state1/style.tar
Binary files differ
diff --git a/tests/publish b/tests/publish
index 253c703..5d1e928 100755
--- a/tests/publish
+++ b/tests/publish
@@ -56,22 +56,28 @@ for r in $(find test -type d -regex '.*/git/.*/[^/]+\.git'); do
d=$(echo $br | sed -n -e 's%.*/git-bare/\(.*\)%\1%p')
for u in "${urls[@]}"; do
+ url="$u/$d"
- # Point the bare repository origin to the remote repository.
+ # Push local branches and tags to the remote repository, if it exists.
#
- git -C $br config remote.origin.url "$u/$d"
+ if git ls-remote "$url" 2>/dev/null >&2; then
+ # Point the bare repository origin to the remote repository.
+ #
+ git -C $br config remote.origin.url "$url"
- # Delete all remote branches and tags.
- #
- while read commit ref; do
- $echo_git git -C $br push origin ":$ref"
- done < <(git -C $br ls-remote --refs origin)
+ # Delete all remote branches and tags.
+ #
+ while read commit ref; do
+ $echo_git git -C $br push origin ":$ref"
+ done < <(git -C $br ls-remote --refs origin)
- # Push local branches.
- #
- while read branch; do
- $echo_git git -C $br push --tags origin "$branch:$branch"
- done < <(git -C $br for-each-ref --format='%(refname:short)' 'refs/heads/')
+ # Push local branches.
+ #
+ while read branch; do
+ $echo_git git -C $br push --tags origin "$branch:$branch"
+ done < <(git -C $br for-each-ref --format='%(refname:short)' \
+ 'refs/heads/')
+ fi
done
# Prepare the bare repository for serving via the HTTPS dumb protocol.
diff --git a/tests/remote-git.test b/tests/remote-git.test
index 5283b91..466acb9 100644
--- a/tests/remote-git.test
+++ b/tests/remote-git.test
@@ -25,11 +25,14 @@ end
+echo "$git_version" | sed -e 's/(\d+).*/\1/' | set git_version_major
+echo "$git_version" | sed -e 's/\d+\.(\d+).*/\1/' | set git_version_minor
+# This flag must be used by testscripts to decide if they should skip git
+# repository-related tests.
+#
git_supported = ($git_version_major > 2 || \
$git_version_major == 2 && $git_version_minor >= 12)
# Output directory path that testscripts must use to prepare repositories
-# required by tests they contains.
+# required by tests they contain.
#
out_git = $canonicalize([dir_path] $~/git/$cmd)
@@ -42,10 +45,25 @@ remote = $config.bpkg.test.remote
? "file://$out_git" \
: "file:/$regex.replace($out_git, '\\', '/')")
+ rep_git = $rep_git_local # Default local repository URL.
+
mkdir -p $out_git
else
rep_git_https_dumb = "https://build2.org/bpkg/git/$cmd"
rep_git_https_smart = "https://git.build2.org/testing/bpkg/advonly/$cmd"
rep_git_https_smart_unadv = "https://git.build2.org/testing/bpkg/unadv/$cmd"
rep_git_git = "git://git.build2.org/testing/bpkg/unadv/$cmd"
+
+ rep_git = $rep_git_https_dumb # Default remote repository URL.
end
+
+# Command for extracting the git repository from a tarball into the output
+# directory (see above).
+#
+# Note that we can expect that the tar program is present on the platform. We
+# will use the same options as we do for unpacking of bpkg packages (see
+# pkg-unpack.cxx).
+#
+git_extract = ($cxx.target.class != 'windows' \
+ ? tar -C $out_git -xf \
+ : tar -C $regex.replace($out_git, '\\', '/') --force-local -xf)
diff --git a/tests/remote.test b/tests/remote.test
index 581d8be..af0c6f6 100644
--- a/tests/remote.test
+++ b/tests/remote.test
@@ -12,7 +12,7 @@
#
# Output directory path that testscripts must use to prepare repositories
-# required by tests they contains.
+# required by tests they contain.
#
# Note that the local path is carefully crafted so that we end up with the
# same repository names in both (local and remote) cases. This is necessary
diff --git a/tests/rep-fetch-git-branch.test b/tests/rep-fetch-git-branch.test
index ea78986..86f5cb1 100644
--- a/tests/rep-fetch-git-branch.test
+++ b/tests/rep-fetch-git-branch.test
@@ -55,7 +55,7 @@ warning: fetching over dumb HTTP, no progress will be shown'
$warn4
%Cloning into '.+libbar'.+%
%Submodule path 'libbar': checked out .+%
- 0 package\(s\) in 1 repository\(s\)
+ 1 package\(s\) in 1 repository\(s\)
EOE
}
@@ -82,7 +82,7 @@ warning: fetching over dumb HTTP, no progress will be shown'
%fetching git:.+libfoo%
$warn
%Fetching in '.+$branch'.+%
- 0 package\(s\) in 1 repository\(s\)
+ 1 package\(s\) in 1 repository\(s\)
EOE
}
@@ -117,7 +117,7 @@ warning: fetching over dumb HTTP, no progress will be shown'
# Preconditions.
#
test -f $r/tests/TODO;
- test -f $r/libbar/manifest;
+ test -f $r/libbar/libbar/manifest;
test -f $r/doc/style/README != 0;
test -d $r/libbaz != 0;
@@ -143,7 +143,7 @@ warning: fetching over dumb HTTP, no progress will be shown'
$warn3
%Cloning into '.+libbaz'.+%
%Submodule path 'libbaz': checked out .+%
- 0 package\(s\) in 1 repository\(s\)
+ 1 package\(s\) in 1 repository\(s\)
EOE
# Postconditions.
diff --git a/tests/rep-fetch-git-commit.test b/tests/rep-fetch-git-commit.test
index e2752b6..3547010 100644
--- a/tests/rep-fetch-git-commit.test
+++ b/tests/rep-fetch-git-commit.test
@@ -45,7 +45,7 @@ warning: fetching over dumb HTTP, no progress will be shown'
$warn
%Cloning into '.+$abbr_commit'.+%
$fetch
- 0 package\(s\) in 1 repository\(s\)
+ 1 package\(s\) in 1 repository\(s\)
EOE
}
@@ -56,7 +56,7 @@ warning: fetching over dumb HTTP, no progress will be shown'
if ($git_protocol == 'https-smart-unadv')
warn = '%.{0}'
- fetch = "%Fetching in '.+stable'.+%"
+ fetch = "%Fetching in '.+$abbr_commit'.+%"
else
warn = "warning: fetching whole branch history"
@@ -72,9 +72,9 @@ warning: fetching over dumb HTTP, no progress will be shown'
$* 2>>~"%EOE%"
%fetching git:.+style-basic%
$warn
- %Cloning into '.+stable'.+%
+ %Cloning into '.+$abbr_commit'.+%
$fetch
- 0 package\(s\) in 1 repository\(s\)
+ 1 package\(s\) in 1 repository\(s\)
EOE
}
}
@@ -103,7 +103,7 @@ warning: fetching over dumb HTTP, no progress will be shown'
$warn
%Cloning into '.+$abbr_commit'.+%
$fetch
- 0 package\(s\) in 1 repository\(s\)
+ 1 package\(s\) in 1 repository\(s\)
EOE
}
@@ -121,8 +121,8 @@ warning: fetching over dumb HTTP, no progress will be shown'
$* 2>>~"%EOE%"
%fetching git:.+style-basic%
$warn
- %Cloning into '.+stable'.+%
- 0 package\(s\) in 1 repository\(s\)
+ %Cloning into '.+$abbr_commit'.+%
+ 1 package\(s\) in 1 repository\(s\)
EOE
}
}
diff --git a/tests/rep-fetch-git.test b/tests/rep-fetch-git.test
index b3bf875..45badc3 100644
--- a/tests/rep-fetch-git.test
+++ b/tests/rep-fetch-git.test
@@ -6,7 +6,7 @@
# the final states. See tests/common/git/init script for more details.
#
-rep_add += --type git -d cfg 2>!
+rep_add += -d cfg 2>!
test.cleanups += &cfg/.bpkg/repositories/*/***
+if ($git_protocol == 'local')
diff --git a/tests/rep-fetch.test b/tests/rep-fetch.test
index 3630709..499541f 100644
--- a/tests/rep-fetch.test
+++ b/tests/rep-fetch.test
@@ -60,23 +60,15 @@
# Create git repositories.
#
- # Note that we can expect that the tar program is present on the platform. We
- # will use the same options as we do for unpacking of bpkg packages (see
- # pkg-unpack.cxx).
- #
- x = ($cxx.target.class != 'windows' \
- ? tar -C $out_git -xf \
- : tar -C $regex.replace($out_git, '\\', '/') --force-local -xf)
-
- $x $src/git/state0/libfoo.tar
- $x $src/git/state0/libbar.tar
- $x $src/git/state0/style.tar
- $x $src/git/state0/style-basic.tar &$out_git/state0/***
-
- $x $src/git/state1/libfoo.tar
- $x $src/git/state1/libbaz.tar
- $x $src/git/state1/style.tar
- $x $src/git/state1/style-basic.tar &$out_git/state1/***
+ $git_extract $src/git/state0/libfoo.tar
+ $git_extract $src/git/state0/libbar.tar
+ $git_extract $src/git/state0/style.tar
+ $git_extract $src/git/state0/style-basic.tar &$out_git/state0/***
+
+ $git_extract $src/git/state1/libfoo.tar
+ $git_extract $src/git/state1/libbaz.tar
+ $git_extract $src/git/state1/style.tar
+ $git_extract $src/git/state1/style-basic.tar &$out_git/state1/***
end
: no-repos
@@ -165,7 +157,7 @@ $* 2>>/EOE != 0
:
if ($git_supported != true)
{
- # Skip git repository fetch tests.
+ # Skip git repository tests.
#
}
elif ($remote != true)
diff --git a/tests/rep-info.test b/tests/rep-info.test
index 4c90ab6..32b77fb 100644
--- a/tests/rep-info.test
+++ b/tests/rep-info.test
@@ -2,14 +2,18 @@
# copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
# license : MIT; see accompanying LICENSE file
-.include common.test auth.test remote.test
+.include common.test auth.test remote.test remote-git.test
# Source repository:
#
# rep-info
-# `-- testing -> stable (complement), ../foo/testing (prerequisite)
-# |-- foo-1.tar.gz
-# `-- repositories
+# |-- testing -> stable (complement), ../foo/testing (prerequisite)
+# | |-- foo-1.tar.gz
+# | `-- repositories
+# |
+# `-- git
+# |-- libbar.git -> style-basic.git (prerequisite)
+# `-- style-basic.git
# Prepare repositories used by tests if running in the local mode.
#
@@ -26,6 +30,11 @@
cp -r $src/testing $out/signed
cat <<<$cert_manifest >+$out/signed/repositories
$rc --key $key $out/signed &$out/signed/packages &$out/signed/signature
+
+ # Create git repositories.
+ #
+ $git_extract $src/git/libbar.tar
+ $git_extract $src/git/style-basic.tar &$out_git/state0/***
end
test.options += --auth all --trust-yes
@@ -126,3 +135,38 @@ $* --name $rep/testing >"bpkg:build2.org/rep-info/testing ($rep/testing)"
$* --cert-organization >'Code Synthesis' : organization
$* --cert-email >'info@build2.org' : email
}
+
+: git-repos
+:
+if ($git_supported != true)
+{
+ # Skip git repository tests.
+ #
+}
+else
+{
+ rep = "$rep_git/state0"
+ test.redirects += 2>!
+
+ : version-module
+ :
+ : Version module is enabled for the project.
+ :
+ $* "$rep/style-basic.git#master" >>~%EOO%
+ %git:.+style-basic .+style-basic.git#master%
+
+ %style-basic/1\.1\.0-a\.0\..+%
+ EOO
+
+ : manifest-lists
+ :
+ : The packages and repositories files are present in the repository root.
+ :
+ $* "$rep/libbar.git#master" >>~%EOO%
+ %git:.+libbar .+libbar.git#master%
+ %prerequisite git:.+style-basic .+style-basic.git#stable%
+
+ libbar/1.0.0
+ libmbar/1.0.0
+ EOO
+}
diff --git a/tests/rep-info/git/libbar.tar b/tests/rep-info/git/libbar.tar
new file mode 120000
index 0000000..67ccdb1
--- /dev/null
+++ b/tests/rep-info/git/libbar.tar
@@ -0,0 +1 @@
+../../common/git/state0/libbar.tar \ No newline at end of file
diff --git a/tests/rep-info/git/style-basic.tar b/tests/rep-info/git/style-basic.tar
new file mode 120000
index 0000000..2833f83
--- /dev/null
+++ b/tests/rep-info/git/style-basic.tar
@@ -0,0 +1 @@
+../../common/git/state0/style-basic.tar \ No newline at end of file