From 3d4838d3706de2ba0045dc9f99a3dc96398def64 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Mon, 19 Feb 2018 14:26:02 +0300 Subject: Parse repositories and packages files for git repositories --- bpkg/archive.cxx | 1 - bpkg/auth.cxx | 1 - bpkg/cfg-create.cxx | 3 - bpkg/checksum.cxx | 1 - bpkg/diagnostics.cxx | 16 +- bpkg/fetch-bpkg.cxx | 1 - bpkg/fetch-git.cxx | 109 ++++++------- bpkg/fetch.cxx | 2 +- bpkg/fetch.hxx | 10 +- bpkg/package.hxx | 3 +- bpkg/pkg-verify.cxx | 1 - bpkg/rep-create.cxx | 1 - bpkg/rep-fetch.cxx | 267 ++++++++++++++++++++++++++++---- bpkg/satisfaction.cxx | 1 - bpkg/types.hxx | 9 ++ bpkg/utility.cxx | 26 ++++ bpkg/utility.hxx | 8 + tests/common/git/state0/libbar.tar | Bin 61440 -> 71680 bytes tests/common/git/state0/libfoo.tar | Bin 256000 -> 296960 bytes tests/common/git/state0/style-basic.tar | Bin 61440 -> 71680 bytes tests/common/git/state0/style.tar | Bin 112640 -> 133120 bytes tests/common/git/state1/libbaz.tar | Bin 61440 -> 61440 bytes tests/common/git/state1/libfoo.tar | Bin 337920 -> 378880 bytes tests/common/git/state1/style-basic.tar | Bin 61440 -> 71680 bytes tests/common/git/state1/style.tar | Bin 112640 -> 133120 bytes tests/publish | 30 ++-- tests/remote-git.test | 20 ++- tests/remote.test | 2 +- tests/rep-fetch-git-branch.test | 8 +- tests/rep-fetch-git-commit.test | 14 +- tests/rep-fetch-git.test | 2 +- tests/rep-fetch.test | 28 ++-- tests/rep-info.test | 52 ++++++- tests/rep-info/git/libbar.tar | 1 + tests/rep-info/git/style-basic.tar | 1 + 35 files changed, 450 insertions(+), 168 deletions(-) create mode 120000 tests/rep-info/git/libbar.tar create mode 120000 tests/rep-info/git/style-basic.tar 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 #include -#include #include 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 #include #include -#include #include #include 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 -#include - #include #include #include #include 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 #include -#include #include #include 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 #include +#include // 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 -#include #include // cpfile () #include 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 // digit(), xdigit() #include -#include #include #include @@ -34,32 +33,6 @@ namespace bpkg static const diag_noreturn_end 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; // 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 (args)...)); + process pr (start_git (co, + 1 /* stdout */, 2 /* stderr */, + forward (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 -#include +#include #include 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//. + // Clone git repository into destdir//. 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//. + // Fetch git repository in destdir//. 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 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 #include -#include #include #include 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 -#include #include // dir_iterator #include 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 #include +#include +#include // operator<<(ostream, process_path) +#include #include #include @@ -74,30 +77,64 @@ namespace bpkg return rep_fetch_data {move (rms), move (pms), move (cert)}; } + template + 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//: // - // 1.a If does not exist, git-clone into temp_dir//. + // 1.a If does not exist, git-clone into temp_dir///. // // 1.a Otherwise, move as temp_dir// and git-fetch. // - // 2. Move from temp_dir// to repos_dir// + // 2. Move from temp_dir// to repos_dir/// // - // 3. Load manifest from repos_dir/// + // 3. Check if repos_dir///repositories exists: // - // 4. Run 'b info' in repos_dir/// 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///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////manifest. + // + // 5.b Run 'b info: repos_dir////' 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 (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 (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 (*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 #include -#include #include #include 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 #include +#include namespace bpkg { @@ -82,6 +83,14 @@ namespace bpkg using paths = std::vector; using dir_paths = std::vector; + + // + // + 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 Binary files a/tests/common/git/state0/libbar.tar and b/tests/common/git/state0/libbar.tar differ diff --git a/tests/common/git/state0/libfoo.tar b/tests/common/git/state0/libfoo.tar index 0533b6d..141a341 100644 Binary files a/tests/common/git/state0/libfoo.tar and b/tests/common/git/state0/libfoo.tar differ diff --git a/tests/common/git/state0/style-basic.tar b/tests/common/git/state0/style-basic.tar index 9d0ff47..217ee7c 100644 Binary files a/tests/common/git/state0/style-basic.tar and b/tests/common/git/state0/style-basic.tar differ diff --git a/tests/common/git/state0/style.tar b/tests/common/git/state0/style.tar index d83c39f..fc3faa0 100644 Binary files a/tests/common/git/state0/style.tar and b/tests/common/git/state0/style.tar differ diff --git a/tests/common/git/state1/libbaz.tar b/tests/common/git/state1/libbaz.tar index c0cdb40..373863e 100644 Binary files a/tests/common/git/state1/libbaz.tar and b/tests/common/git/state1/libbaz.tar differ diff --git a/tests/common/git/state1/libfoo.tar b/tests/common/git/state1/libfoo.tar index 5708d07..23275c8 100644 Binary files a/tests/common/git/state1/libfoo.tar and b/tests/common/git/state1/libfoo.tar differ diff --git a/tests/common/git/state1/style-basic.tar b/tests/common/git/state1/style-basic.tar index 71b5985..e4e14e9 100644 Binary files a/tests/common/git/state1/style-basic.tar and b/tests/common/git/state1/style-basic.tar differ diff --git a/tests/common/git/state1/style.tar b/tests/common/git/state1/style.tar index c939a87..52389c3 100644 Binary files a/tests/common/git/state1/style.tar and b/tests/common/git/state1/style.tar 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 -- cgit v1.1