13 #include <boost/algorithm/string/classification.hpp>
14 #include <boost/algorithm/string/predicate.hpp>
15 #include <boost/algorithm/string/split.hpp>
16 #include <boost/lexical_cast.hpp>
22 unsigned char fromHex(
char b)
27 return (b -
'A') + 0x0A;
29 return (b -
'a') + 0x0A;
32 unsigned char fromHex(
char msb,
char lsb)
34 return (fromHex(msb) << 4) + fromHex(lsb);
37 char toHex(
unsigned char b)
42 return 'a' + (b - 0xA);
45 void toHex(
unsigned char b,
char& msb,
char& lsb)
47 lsb = toHex(b & 0x0F);
58 POpenWrapper(
const std::string& s,
Git::Cache& cache) {
61 for (Git::Cache::iterator i = cache.begin(); i != cache.end(); ++i)
66 cache.splice(cache.begin(), cache, i);
71 std::cerr << s << std::endl;
72 FILE *stream = popen((s +
" 2>&1").c_str(),
"r");
79 n = fread(buffer, 1, 30000, stream);
81 content_ += std::string(buffer, n);
84 status_ = pclose(stream);
88 cache.push_front(std::make_pair(s, content_));
95 std::string& readLine(std::string& r,
bool stripWhite =
true) {
99 && (idx_ < content_.length()) && isspace(content_[idx_]))
102 while (idx_ < content_.size() && content_[idx_] !=
'\n') {
107 if (idx_ < content_.size())
113 const std::string& contents()
const {
117 bool finished()
const {
118 return idx_ == content_.size();
121 int exitStatus()
const {
126 std::string content_;
148 : std::runtime_error(msg)
156 if (
id.length() != 40)
159 for (
int i = 0; i < 20; ++i)
160 (*
this)[i] = fromHex(
id[2 * i],
id[2 * i + 1]);
165 std::string result(40,
'-');
167 for (
int i = 0; i < 20; ++i)
168 toHex((*
this)[i], result[2 * i], result[2 * i + 1]);
198 if (!
getCmdResult(
"cat-file -p " +
id.toString(), result, -1))
199 throw Exception(
"Git: could not cat '" +
id.toString() +
"'");
206 std::string sha1Commit;
213 std::string treeLine;
215 throw Exception(
"Git: could not parse tree from commit '"
218 std::vector<std::string> v;
219 boost::split(v, treeLine, boost::is_any_of(
" "));
221 throw Exception(
"Git: could not parse tree from commit '"
222 + commit.
toString() +
"': '" + treeLine +
"'");
228 std::string objectLine;
230 throw Exception(
"Git: could not read object %"
231 + boost::lexical_cast<std::string>(index)
234 std::vector<std::string> v1, v2;
235 boost::split(v1, objectLine, boost::is_any_of(
"\t"));
237 throw Exception(
"Git: could not parse tree object line: '"
239 boost::split(v2, v1[0], boost::is_any_of(
" "));
241 throw Exception(
"Git: could not parse tree object line: '"
244 const std::string& stype = v2[1];
248 else if (stype ==
"blob")
251 throw Exception(
"Git: Unknown type: " + stype);
270 if (p.exitStatus() != 0)
271 throw Exception(
"Git error: " + p.readLine(result));
274 result = p.contents();
279 for (
int i = 0; i < index; ++i) {
289 const std::string& tag)
const
293 if (p.exitStatus() != 0)
294 throw Exception(
"Git error: " + p.readLine(result));
296 while (!p.finished()) {
298 if (boost::starts_with(result, tag))
311 if (p.exitStatus() != 0)
312 throw Exception(
"Git error: " + p.readLine(r));
315 while (!p.finished()) {
328 if (p.exitStatus() != 0)
329 throw Exception(
"Git error: " + p.readLine(r));
void checkRepository() const
Checks the repository.
int getCmdResultLineCount(const std::string &cmd) const
Returns the number of lines in the output of a git command.
Object(const ObjectId &id, ObjectType type)
int treeSize(const ObjectId &tree) const
Return the number of objects inside a tree object.
Object treeGetObject(const ObjectId &tree, int index) const
Get some info on a tree object.
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 toString() const
Print as a 40-digit hexadecimal number.
std::list< std::pair< std::string, std::string > > Cache
void id(Action &action, V &value, const std::string &name="id", int size=-1)
ObjectId getCommit(const std::string &revision) const
Get the commit for a particular revision.
ObjectType
Git object type.
std::string repository_
The path to the repository.
Cache cache_
A small LRU cache that stores results of git commands.
ObjectId getTreeFromCommit(const ObjectId &commit) const
Get the tree for a particular commit.
Exception(const std::string &msg)
Constructor.
ObjectId()
Default constructor.
ObjectId getCommitTree(const std::string &revision) const
Get the tree for a particular revision.
std::string catFile(const ObjectId &id) const
Return the raw contents of a git object.
void setRepositoryPath(const std::string &repository)
Set the git repository path.