aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/version/snapshot-git.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2/version/snapshot-git.cxx')
-rw-r--r--libbuild2/version/snapshot-git.cxx63
1 files changed, 39 insertions, 24 deletions
diff --git a/libbuild2/version/snapshot-git.cxx b/libbuild2/version/snapshot-git.cxx
index 28d96ac..ab0224a 100644
--- a/libbuild2/version/snapshot-git.cxx
+++ b/libbuild2/version/snapshot-git.cxx
@@ -3,7 +3,7 @@
#include <ctime> // time_t
-#include <libbutl/sha1.mxx>
+#include <libbutl/sha1.hxx>
#include <libbuild2/version/snapshot.hxx>
@@ -14,11 +14,20 @@ namespace build2
{
namespace version
{
+ // We have to run git twice to extract the information we need and doing
+ // it repetitively is quite expensive, especially for larger repositories.
+ // So we cache it, which helps multi-package repositories.
+ //
+ static global_cache<snapshot, dir_path> cache;
+
snapshot
- extract_snapshot_git (const dir_path& src_root)
+ extract_snapshot_git (context& ctx, dir_path rep_root)
{
+ if (const snapshot* r = cache.find (rep_root))
+ return *r;
+
snapshot r;
- const char* d (src_root.string ().c_str ());
+ const char* d (rep_root.string ().c_str ());
// On startup git prepends the PATH environment variable value with the
// computed directory path where its sub-programs are supposedly located
@@ -73,7 +82,11 @@ namespace build2
args[args_i + 1] = "--porcelain";
args[args_i + 2] = nullptr;
+ // @@ PERF: redo with custom stream reading code (then could also
+ // get rid of context).
+ //
r.committed = run<string> (
+ ctx,
3 /* verbosity */,
pp,
args,
@@ -99,7 +112,8 @@ namespace build2
// (reluctantly) assume that the only reason git cat-file fails is if
// there is no HEAD (that we equal with the "new repository" condition
// which is, strictly speaking, might not be the case either). So we
- // suppress any diagnostics, and handle non-zero exit code.
+ // suppress any diagnostics, and handle non-zero exit code (and so no
+ // diagnostics buffering is needed, plus we are in the load phase).
//
string data;
@@ -108,12 +122,12 @@ namespace build2
args[args_i + 2] = "HEAD";
args[args_i + 3] = nullptr;
- process pr (run_start (3 /* verbosity */,
+ process pr (run_start (3 /* verbosity */,
pp,
args,
- 0 /* stdin */,
- -1 /* stdout */,
- false /* error */));
+ 0 /* stdin */,
+ -1 /* stdout */,
+ 1 /* stderr (to stdout) */));
string l;
try
@@ -192,30 +206,31 @@ namespace build2
// that.
}
- if (!run_finish_code (args, pr, l))
+ if (run_finish_code (args, pr, l, 2 /* verbosity */))
+ {
+ if (r.sn == 0)
+ fail << "unable to extract git commit id/date for " << rep_root;
+
+ if (r.committed)
+ {
+ sha1 cs;
+ cs.append ("commit " + to_string (data.size ())); // Includes '\0'.
+ cs.append (data.c_str (), data.size ());
+ r.id.assign (cs.string (), 12); // 12-char abbreviated commit id.
+ }
+ else
+ r.sn++; // Add a second.
+ }
+ else
{
// Presumably new repository without HEAD. Return uncommitted snapshot
// with UNIX epoch as timestamp.
//
r.sn = 19700101000000ULL;
r.committed = false;
- return r;
}
- if (r.sn == 0)
- fail << "unable to extract git commit id/date for " << src_root;
-
- if (r.committed)
- {
- sha1 cs;
- cs.append ("commit " + to_string (data.size ())); // Includes '\0'.
- cs.append (data.c_str (), data.size ());
- r.id.assign (cs.string (), 12); // 12-characters abbreviated commit id.
- }
- else
- r.sn++; // Add a second.
-
- return r;
+ return cache.insert (move (rep_root), move (r));
}
}
}