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