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& cmd,
Git::Cache& cache) {
59 std::string s = sanitize(cmd);
63 for (Git::Cache::iterator i = cache.begin(); i != cache.end(); ++i)
68 cache.splice(cache.begin(), cache, i);
73 std::cerr << s << std::endl;
74 FILE *stream = popen((s +
" 2>&1").c_str(),
"r");
81 n = fread(buffer, 1, 30000, stream);
83 content_ += std::string(buffer, n);
86 status_ = pclose(stream);
90 cache.push_front(std::make_pair(s, content_));
97 std::string& readLine(std::string& r,
bool stripWhite =
true) {
101 && (idx_ < content_.length()) && isspace(content_[idx_]))
104 while (idx_ < content_.size() && content_[idx_] !=
'\n') {
109 if (idx_ < content_.size())
115 const std::string& contents()
const {
119 bool finished()
const {
120 return idx_ == content_.size();
123 int exitStatus()
const {
128 std::string content_;
133 std::string sanitize(
const std::string& cmd) {
139 std::string unsafe =
"<>&;|[$`";
141 for (
unsigned i = 0; i < cmd.size(); ++i) {
142 if (unsafe.find(cmd[i]) == std::string::npos)
167 : std::runtime_error(msg)
175 if (
id.length() != 40)
178 for (
int i = 0; i < 20; ++i)
179 (*
this)[i] = fromHex(
id[2 * i],
id[2 * i + 1]);
184 std::string result(40,
'-');
186 for (
int i = 0; i < 20; ++i)
187 toHex((*
this)[i], result[2 * i], result[2 * i + 1]);
217 if (!
getCmdResult(
"cat-file -p " +
id.toString(), result, -1))
218 throw Exception(
"Git: could not cat '" +
id.toString() +
"'");
225 std::string sha1Commit;
232 std::string treeLine;
234 throw Exception(
"Git: could not parse tree from commit '" 237 std::vector<std::string> v;
238 boost::split(v, treeLine, boost::is_any_of(
" "));
240 throw Exception(
"Git: could not parse tree from commit '" 241 + commit.
toString() +
"': '" + treeLine +
"'");
247 std::string objectLine;
249 throw Exception(
"Git: could not read object %" 250 + boost::lexical_cast<std::string>(index)
253 std::vector<std::string> v1, v2;
254 boost::split(v1, objectLine, boost::is_any_of(
"\t"));
256 throw Exception(
"Git: could not parse tree object line: '" 258 boost::split(v2, v1[0], boost::is_any_of(
" "));
260 throw Exception(
"Git: could not parse tree object line: '" 263 const std::string& stype = v2[1];
267 else if (stype ==
"blob")
270 throw Exception(
"Git: Unknown type: " + stype);
289 if (p.exitStatus() != 0)
290 throw Exception(
"Git error: " + p.readLine(result));
293 result = p.contents();
298 for (
int i = 0; i < index; ++i) {
308 const std::string& tag)
const 312 if (p.exitStatus() != 0)
313 throw Exception(
"Git error: " + p.readLine(result));
315 while (!p.finished()) {
317 if (boost::starts_with(result, tag))
330 if (p.exitStatus() != 0)
331 throw Exception(
"Git error: " + p.readLine(r));
334 while (!p.finished()) {
347 if (p.exitStatus() != 0)
348 throw Exception(
"Git error: " + p.readLine(r));
ObjectId getCommitTree(const std::string &revision) const
Get the tree for a particular revision.
Object(const ObjectId &id, ObjectType type)
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)
std::string catFile(const ObjectId &id) const
Return the raw contents of a git object.
ObjectType
Git object type.
std::string repository_
The path to the repository.
ObjectId getCommit(const std::string &revision) const
Get the commit for a particular revision.
int getCmdResultLineCount(const std::string &cmd) const
Returns the number of lines in the output of a git command.
void checkRepository() const
Checks the repository.
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.
Cache cache_
A small LRU cache that stores results of git commands.
Exception(const std::string &msg)
Constructor.
ObjectId()
Default constructor.
ObjectId getTreeFromCommit(const ObjectId &commit) const
Get the tree for a particular commit.
Object treeGetObject(const ObjectId &tree, int index) const
Get some info on a tree object.
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.