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 "cvs-exp.h"
19
20 Regex cvsexp_commitno_regex("^([0-9]{6}):");
21 Regex cvsexp_branch_regex("^BRANCH \\[(.+)\\]$");
22 Regex cvsexp_date_regex("^\\(date: ([0-9]{4})[-/]([0-9]{2})[-/]([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2})(?: [+-][0-9]{4})?;(.+)$");
23 Regex cvsexp_detail_regex("author: ([^;]+); state: ([^;]+);(.+)$");
24 //Regex cvsexp_lines_regex("lines: \\+([0-9]+) -([0-9]+)");
25 Regex cvsexp_entry_regex("\\| (.+),v:([0-9.]+),?");
26 Regex cvsexp_end_regex("^(=+)$");
27
logCommand()28 std::string CVSEXPCommitLog::logCommand() {
29 std::string log_command = "cvs-exp.pl -notree";
30 return log_command;
31 }
32
CVSEXPCommitLog(const std::string & logfile)33 CVSEXPCommitLog::CVSEXPCommitLog(const std::string& logfile) : RCommitLog(logfile) {
34 }
35
36 // parse modified cvs format log entries
37
parseCommit(RCommit & commit)38 bool CVSEXPCommitLog::parseCommit(RCommit& commit) {
39
40 std::string line;
41 std::vector<std::string> entries;
42
43 if(!logf->getNextLine(line)) return false;
44
45 //skip empty line if there is one
46 if(line.size() == 0) {
47 if(!logf->getNextLine(line)) return false;
48 }
49
50 //read commit no
51 if(!cvsexp_commitno_regex.match(line, &entries)) return false;
52
53 //int commitno = atoi(entries[0].c_str());
54 //debugLog("commitno matched\n");
55
56 if(!logf->getNextLine(line)) return false;
57
58 //should be a branch
59 if(cvsexp_branch_regex.match(line, &entries)) {
60
61 //read next blank line
62 if(!logf->getNextLine(line)) return false;
63 if(line.size()) return false;
64 if(!logf->getNextLine(line)) return false;
65 }
66
67 //parse date
68 if(!cvsexp_date_regex.match(line, &entries)) return false;
69
70 //debugLog("date matched\n");
71
72 struct tm time_str;
73
74 time_str.tm_year = atoi(entries[0].c_str()) - 1900;
75 time_str.tm_mon = atoi(entries[1].c_str()) - 1;
76 time_str.tm_mday = atoi(entries[2].c_str());
77 time_str.tm_hour = atoi(entries[3].c_str());
78 time_str.tm_min = atoi(entries[4].c_str());
79 time_str.tm_sec = atoi(entries[5].c_str());
80 time_str.tm_isdst = -1;
81
82 commit.timestamp = mktime(&time_str);
83
84 //parse author,state
85 std::string rest = entries[6];
86 if(!cvsexp_detail_regex.match(rest, &entries)) return false;
87
88 //debugLog("author/state matched\n");
89
90 commit.username = entries[0];
91
92 std::string commit_state = entries[1];
93
94 /* not used
95 //if rest is not ')' parse lines
96 rest = entries[2];
97
98 // need to parse lines
99 if(rest.size() > 2) {
100 if(!cvsexp_lines_regex.match(rest, &entries)) return false;
101 }
102 */
103
104 if(!logf->getNextLine(line)) return false;
105
106 std::string commit_action = (commit_state == "dead") ? "D" : "M";
107
108 while(cvsexp_entry_regex.match(line, &entries)) {
109
110 //ignore files in Attic - previously deleted file
111 if(entries[0].find("/Attic/") == std::string::npos) {
112 commit.addFile(entries[0], commit_action);
113 }
114
115 if(!logf->getNextLine(line)) return false;
116 }
117
118 //read blank line
119 if(!logf->getNextLine(line)) return false;
120
121 //std::string message;
122
123 //read commit message
124 while(logf->getNextLine(line) && line.size()) {
125 //if(message.size()) message += std::string("\n");
126 //message += line;
127 }
128
129 //read until end of commit or eof
130 while(logf->getNextLine(line)) {
131 if(cvsexp_end_regex.match(line,&entries)) {
132 //debugLog("read end of commit %s\n", entries[0].c_str());
133 break;
134 }
135 }
136
137 return true;
138 }
139