14 #include <boost/algorithm/string/classification.hpp>
15 #include <boost/algorithm/string/predicate.hpp>
16 #include <boost/algorithm/string/split.hpp>
17 #include <boost/filesystem.hpp>
25 unsigned char fromHex(
char b)
30 return (b -
'A') + 0x0A;
32 return (b -
'a') + 0x0A;
35 unsigned char fromHex(
char msb,
char lsb)
37 return (fromHex(msb) << 4) + fromHex(lsb);
40 char toHex(
unsigned char b)
45 return 'a' + (b - 0xA);
48 void toHex(
unsigned char b,
char& msb,
char& lsb)
50 lsb = toHex(b & 0x0F);
61 POpenWrapper(
const std::string& cmd,
Git::Cache& cache) {
62 std::string s = sanitize(cmd);
66 for (Git::Cache::iterator i = cache.begin(); i != cache.end(); ++i)
71 cache.splice(cache.begin(), cache, i);
76 std::cerr << s << std::endl;
77 FILE *stream = popen((s +
" 2>&1").c_str(),
"r");
84 n = fread(buffer, 1, 30000, stream);
86 content_ += std::string(buffer, n);
89 status_ = pclose(stream);
93 cache.push_front(std::make_pair(s, content_));
100 std::string& readLine(std::string& r,
bool stripWhite =
true) {
104 && (idx_ < content_.length()) && isspace(content_[idx_]))
107 while (idx_ < content_.size() && content_[idx_] !=
'\n') {
112 if (idx_ < content_.size())
118 const std::string& contents()
const {
122 bool finished()
const {
123 return idx_ == content_.size();
126 int exitStatus()
const {
131 std::string content_;
136 std::string sanitize(
const std::string& cmd) {
142 std::string unsafe =
"<>&;|[$`";
144 for (
auto item : cmd) {
145 if (unsafe.find(item) == std::string::npos)
170 : std::runtime_error(msg)
178 if (
id.length() != 40)
181 for (
int i = 0; i < 20; ++i)
182 (*
this)[i] = fromHex(
id[2 * i],
id[2 * i + 1]);
187 std::string result(40,
'-');
189 for (
int i = 0; i < 20; ++i)
190 toHex((*
this)[i], result[2 * i], result[2 * i + 1]);
207 namespace fs = boost::filesystem;
208 boost::system::error_code ignored;
209 is_bare_ = !fs::is_directory(fs::path(repositoryPath) /
".git", ignored);
224 if (!
getCmdResult(
"cat-file -p " +
id.toString(), result, -1))
225 throw Exception(
"Git: could not cat '" +
id.toString() +
"'");
232 std::string sha1Commit;
239 std::string treeLine;
241 throw Exception(
"Git: could not parse tree from commit '"
244 std::vector<std::string> v;
245 boost::split(v, treeLine, boost::is_any_of(
" "));
247 throw Exception(
"Git: could not parse tree from commit '"
248 + commit.
toString() +
"': '" + treeLine +
"'");
254 std::string objectLine;
256 throw Exception(
"Git: could not read object %"
260 std::vector<std::string> v1,
v2;
261 boost::split(v1, objectLine, boost::is_any_of(
"\t"));
263 throw Exception(
"Git: could not parse tree object line: '"
265 boost::split(
v2, v1[0], boost::is_any_of(
" "));
267 throw Exception(
"Git: could not parse tree object line: '"
270 const std::string& stype =
v2[1];
274 else if (stype ==
"blob")
277 throw Exception(
"Git: Unknown type: " + stype);
305 if (p.exitStatus() != 0)
306 throw Exception(
"Git error: " + p.readLine(result));
309 result = p.contents();
314 for (
int i = 0; i < index; ++i) {
324 const std::string& tag)
const
328 if (p.exitStatus() != 0)
329 throw Exception(
"Git error: " + p.readLine(result));
331 while (!p.finished()) {
333 if (boost::starts_with(result, tag))
346 if (p.exitStatus() != 0)
347 throw Exception(
"Git error: " + p.readLine(r));
350 while (!p.finished()) {
363 if (p.exitStatus() != 0)
364 throw Exception(
"Git error: " + p.readLine(r));
Exception(const std::string &msg)
Constructor.
std::string toString() const
Print as a 40-digit hexadecimal number.
ObjectId()
Default constructor.
Cache cache_
A small LRU cache that stores results of git commands.
std::list< std::pair< std::string, std::string > > Cache
ObjectId getCommit(const std::string &revision) const
Get the commit for a particular revision.
std::string repository_
The path to the repository.
ObjectId getTreeFromCommit(const ObjectId &commit) const
Get the tree for a particular commit.
std::string catFile(const ObjectId &id) const
Return the raw contents of a git object.
int getCmdResultLineCount(const std::string &cmd) const
Returns the number of lines in the output of a git command.
bool is_bare_
Whether the repositoy is a bare repository.
Object treeGetObject(const ObjectId &tree, int index) const
Get some info on a tree object.
void checkRepository() const
Checks the repository.
int treeSize(const ObjectId &tree) const
Return the number of objects inside a tree object.
void setRepositoryPath(const std::string &repository)
Set the git repository path.
ObjectType
Git object type.
bool getCmdResult(const std::string &cmd, std::string &result, const std::string &tag) const
Returns a line identified by a tag from the output of a git command.
std::string baseCmd() const
The git base command after which extra arguments are added.
ObjectId getCommitTree(const std::string &revision) const
Get the tree for a particular revision.
void id(Action &action, V &value, const std::string &name="id", int size=-1)
WString asString(const cpp17::any &v, const WString &formatString=WString())
Object(const ObjectId &id, ObjectType type)