2
Copyright (C) 2009 Andrew Caudwell (acaudwell@gmail.com)
4
This program is free software; you can redistribute it and/or
5
modify it under the terms of the GNU General Public License
6
as published by the Free Software Foundation; either version
7
3 of the License, or (at your option) any later version.
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU General Public License for more details.
14
You should have received a copy of the GNU General Public License
15
along with this program. If not, see <http://www.gnu.org/licenses/>.
20
// parse git log entries
22
//git-log command notes:
23
// - no single quotes on WIN32 as system call treats them differently
24
// - 'user:' prefix allows us to quickly tell if the log is the wrong format
25
// and try a different format (eg cvs-exp)
27
std::string gGourceGitLogCommand = "git log "
28
"--pretty=format:user:%aN%n%ct "
29
"--reverse --raw --encoding=UTF-8 "
32
GitCommitLog::GitCommitLog(const std::string& logfile) : RCommitLog(logfile, 'u') {
34
log_command = gGourceGitLogCommand;
36
if(gGourceSettings.git_branch.size()>0) {
38
log_command += gGourceSettings.git_branch;
41
//can generate log from directory
43
logf = generateLog(logfile);
52
BaseLog* GitCommitLog::generateLog(const std::string& dir) {
53
//get working directory
56
if(getcwd(cwd_buff, 1024) != cwd_buff) {
60
//does directory have a .git ?
61
std::string gitdir = dir + std::string("/.git");
63
int stat_rc = stat(gitdir.c_str(), &dirinfo);
64
if(stat_rc!=0 || !(dirinfo.st_mode & S_IFDIR)) {
68
std::string command = getLogCommand();
73
if(temp_file.size()==0) return 0;
75
if(chdir(dir.c_str()) != 0) {
80
sprintf(cmd_buff, "%s > %s", command.c_str(), temp_file.c_str());
82
int command_rc = system(cmd_buff);
89
// check for new-enough Git version
90
// if %aN does not appear to be supported try %an
91
std::ifstream in(temp_file.c_str());
93
in.read(firstBytes, 8);
96
if(!strcmp(firstBytes, "user:%aN")) {
97
char *pos = strstr(cmd_buff, "%aN");
99
command_rc = system(cmd_buff);
102
//change back to original directoy
105
if(command_rc != 0) {
109
BaseLog* seeklog = new SeekLog(temp_file);
114
// parse modified git format log entries
116
bool GitCommitLog::parseCommit(RCommit& commit) {
120
commit.username = "";
122
while(logf->getNextLine(line) && line.size()) {
124
if(line.find("user:") == 0) {
126
//username follows user prefix
127
commit.username = line.substr(5);
129
if(!logf->getNextLine(line)) return false;
131
commit.timestamp = atol(line.c_str());
133
//this isnt a commit we are parsing, abort
134
if(commit.timestamp == 0) return false;
139
//should see username before files
140
if(commit.username.size() == 0) return false;
142
size_t tab = line.find('\t');
144
//incorrect log format
145
if(tab == std::string::npos || tab == 0 || tab == line.size()-1) continue;
147
std::string status = line.substr(tab - 1, 1);
148
std::string file = line.substr(tab + 1);
150
if(file.empty()) continue;
152
//check for and remove double quotes
153
if(file.find('"') == 0 && file.rfind('"') == file.size()-1) {
154
if(file.size()<=2) continue;
156
file = file.substr(1,file.size()-2);
159
commit.addFile(file, status);
162
//check we at least got a username
163
if(commit.username.size()==0) return false;