1 /*
2     Copyright (C) 2010 John Arbash Meinel <john@arbash-meinel.com>
3 
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.
8 
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.
13 
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/>.
16 */
17 
18 #include "bzr.h"
19 #include "../gource_settings.h"
20 
21 #include <boost/format.hpp>
22 
23 Regex bzr_commit_regex("^ *([\\d.]+) (.+)\t(\\d{4})-(\\d+)-(\\d+)(?: \\{[^}]+})?(?: \\[merge\\])?$");
24 Regex bzr_file_regex("^ *([AMDR])  (.*[^/])$");
25 
26 // parse Bazaar log entries (using the gource.style template)
27 
logCommand()28 std::string BazaarLog::logCommand() {
29 
30     std::string start = (!gGourceSettings.start_date.empty()) ? "date:"+gGourceSettings.start_date : "1";
31     std::string stop  = (!gGourceSettings.stop_date.empty())  ? "date:"+gGourceSettings.stop_date  : "-1";
32 
33     std::string range = str(boost::format("%s..%s") % start % stop);
34 
35     std::string log_command = str(boost::format("bzr log --verbose -r %s --short -n0 --forward") % range);
36 
37     return log_command;
38 }
39 
BazaarLog(const std::string & logfile)40 BazaarLog::BazaarLog(const std::string& logfile) : RCommitLog(logfile) {
41 
42     log_command = logCommand();
43 
44     //can generate log from directory
45     if(!logf && is_dir) {
46         logf = generateLog(logfile);
47 
48         if(logf) {
49             success  = true;
50             seekable = true;
51         }
52     }
53 }
54 
generateLog(const std::string & dir)55 BaseLog* BazaarLog::generateLog(const std::string& dir) {
56 
57     //does directory have a .bzr ?
58     std::string bzrdir = dir + std::string("/.bzr");
59     struct stat dirinfo;
60     int stat_rc = stat(bzrdir.c_str(), &dirinfo);
61     if(stat_rc!=0 || !(dirinfo.st_mode & S_IFDIR)) {
62         return 0;
63     }
64 
65     std::string command = getLogCommand();
66 
67     // do we have this client installed
68     requireExecutable("bzr");
69 
70     createTempLog();
71 
72     if(temp_file.size()==0) return 0;
73 
74     char cmd_buff[2048];
75     snprintf(cmd_buff, 2048, "%s %s > %s", command.c_str(), dir.c_str(), temp_file.c_str());
76 
77     int command_rc = systemCommand(cmd_buff);
78 
79     if(command_rc != 0) {
80         return 0;
81     }
82 
83     BaseLog* seeklog = new SeekLog(temp_file);
84 
85     return seeklog;
86 }
87 
parseCommit(RCommit & commit)88 bool BazaarLog::parseCommit(RCommit& commit) {
89 
90     std::string line;
91     std::vector<std::string> entries;
92     int year, month, day;
93 
94     if(!logf->getNextLine(line)) return false;
95 
96     if (!bzr_commit_regex.match(line, &entries)) {
97         //debugLog("regex failed\n");
98         return false;
99     }
100 
101     commit.username = entries[1];
102 
103     year  = atoi(entries[2].c_str());
104     month = atoi(entries[3].c_str());
105     day   = atoi(entries[4].c_str());
106 
107     struct tm time_str;
108 
109     time_str.tm_year  = year - 1900;
110     time_str.tm_mon   = month - 1;
111     time_str.tm_mday  = day;
112     time_str.tm_hour  = 0;
113     time_str.tm_min   = 0;
114     time_str.tm_sec   = 0;
115     time_str.tm_isdst = -1;
116 
117     commit.timestamp = mktime(&time_str);
118 
119     while(logf->getNextLine(line) && line.size()) {
120         if (!bzr_file_regex.match(line, &entries)) continue;
121         commit.addFile(entries[1], entries[0]);
122     }
123 
124     return true;
125 }
126