1 /*
2 Copyright (C) 2009 Andrew Caudwell (acaudwell@gmail.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 "hg.h"
19 #include "../core/sdlapp.h"
20 #include "../gource_settings.h"
21
22 #include <boost/format.hpp>
23
24 Regex hg_regex("^([0-9]+) -?[0-9]+\\|([^|]+)\\|([ADM]?)\\|(.+)$");
25
logCommand()26 std::string MercurialLog::logCommand() {
27
28 // parse Mercurial log entries (using the gource.style template)
29 std::string gource_style_path = gSDLAppResourceDir + std::string("gource.style");
30
31 std::string range =
32 // date range
33 (!gGourceSettings.start_date.empty() && !gGourceSettings.stop_date.empty()) ?
34 str(boost::format("--date '%s to %s'") % gGourceSettings.start_date % gGourceSettings.stop_date)
35
36 // start date only
37 : (!gGourceSettings.start_date.empty()) ?
38 str(boost::format("--date '>%s'") % gGourceSettings.start_date)
39
40 // stop date only
41 : (!gGourceSettings.stop_date.empty()) ?
42 str(boost::format("--date '<%s'") % gGourceSettings.stop_date)
43
44 // default
45 : "";
46
47 std::string log_command = str(boost::format("hg log %s -r 0:tip --style '%s'") % range % gource_style_path);
48
49 #ifdef _WIN32
50 std::replace(log_command.begin(), log_command.end(), '\'', '"');
51 #endif
52
53 return log_command;
54 }
55
MercurialLog(const std::string & logfile)56 MercurialLog::MercurialLog(const std::string& logfile) : RCommitLog(logfile) {
57
58 log_command = logCommand();
59
60 //can generate log from directory
61 if(!logf && is_dir) {
62 logf = generateLog(logfile);
63
64 if(logf) {
65 success = true;
66 seekable = true;
67 }
68 }
69 }
70
generateLog(const std::string & dir)71 BaseLog* MercurialLog::generateLog(const std::string& dir) {
72
73 //does directory have a .hg ?
74 std::string hgdir = dir + std::string("/.hg");
75 struct stat dirinfo;
76 int stat_rc = stat(hgdir.c_str(), &dirinfo);
77 if(stat_rc!=0 || !(dirinfo.st_mode & S_IFDIR)) {
78 return 0;
79 }
80
81 // do we have this client installed
82 requireExecutable("hg");
83
84 std::string command = getLogCommand();
85
86 createTempLog();
87
88 if(temp_file.size()==0) return 0;
89
90 char cmd_buff[2048];
91 snprintf(cmd_buff, 2048, "%s -R \"%s\" > %s", command.c_str(), dir.c_str(), temp_file.c_str());
92
93 int command_rc = systemCommand(cmd_buff);
94
95 if(command_rc != 0) {
96 return 0;
97 }
98
99 BaseLog* seeklog = new SeekLog(temp_file);
100
101 return seeklog;
102 }
103
104
parseCommit(RCommit & commit)105 bool MercurialLog::parseCommit(RCommit& commit) {
106
107 while(parseCommitEntry(commit));
108
109 return !commit.files.empty();
110 }
111
parseCommitEntry(RCommit & commit)112 bool MercurialLog::parseCommitEntry(RCommit& commit) {
113
114 std::string line;
115 std::vector<std::string> entries;
116
117 if(!getNextLine(line)) return false;
118
119 //custom line
120 if(!hg_regex.match(line, &entries)) return false;
121
122 time_t timestamp = atol(entries[0].c_str());
123 std::string username = entries[1];
124
125 //if this file is for the same person and timestamp
126 //we add to the commit, else we save the lastline
127 //and return false
128 if(commit.files.empty()) {
129 commit.timestamp = timestamp;
130 commit.username = username;
131 } else {
132 if(commit.timestamp != timestamp || commit.username != username) {
133 lastline = line;
134 return false;
135 }
136 }
137
138 std::string action = "A";
139
140 if(!entries[2].empty()) {
141 action = entries[2];
142 }
143
144 commit.addFile(entries[3], action);
145
146 //commit.debug();
147
148 return true;
149 }
150