1 /*
2 Copyright (C) 2010 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 "cvs2cl.h"
19 #include "../gource_settings.h"
20
21 #ifdef HAVE_LIBTINYXML
22 #include <tinyxml.h>
23 #else
24 #include "../tinyxml/tinyxml.h"
25 #endif
26
27 Regex cvs2cl_xml_tag("^<\\??xml");
28 Regex cvs2cl_logentry_start("^<entry");
29 Regex cvs2cl_logentry_end("^</entry>");
30 Regex cvs2cl_logentry_timestamp("(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})Z");
31
logCommand()32 std::string CVS2CLCommitLog::logCommand() {
33 std::string log_command = "cvs2cl --chrono --stdout --xml -g-q";
34 return log_command;
35 }
36
CVS2CLCommitLog(const std::string & logfile)37 CVS2CLCommitLog::CVS2CLCommitLog(const std::string& logfile) : RCommitLog(logfile, '<') {
38 }
39
parseCommit(RCommit & commit)40 bool CVS2CLCommitLog::parseCommit(RCommit& commit) {
41
42 //fprintf(stderr,"parsing cvs2cl log\n");
43
44 std::string line;
45
46 if(!getNextLine(line)) return false;
47
48 //start of log entry
49 if(!cvs2cl_logentry_start.match(line)) {
50
51 //is this the start of the document
52 if(!cvs2cl_xml_tag.match(line)) return false;
53
54 //fprintf(stderr,"found xml tag\n");
55
56 //if so find the first logentry tag
57
58 bool found_logentry = false;
59
60 while(getNextLine(line)) {
61 if(cvs2cl_logentry_start.match(line)) {
62 found_logentry = true;
63 break;
64 }
65 }
66
67 if(!found_logentry) return false;
68 }
69
70 //fprintf(stderr,"found logentry\n");
71
72 logentry.clear();
73
74 logentry.append(line);
75 logentry.append("\n");
76
77 //fprintf(stderr,"found opening tag\n");
78
79 bool endfound = false;
80
81 while(getNextLine(line)) {
82 logentry.append(line);
83 logentry.append("\n");
84 if(cvs2cl_logentry_end.match(line)) {
85 //fprintf(stderr,"found closing tag\n");
86 endfound=true;
87 break;
88 }
89 }
90
91 //incomplete commit
92 if(!endfound) return false;
93
94 //fprintf(stderr,"read logentry\n");
95
96 TiXmlDocument doc;
97
98 if(!doc.Parse(logentry.c_str())) return false;
99
100 //fprintf(stderr,"try to parse logentry: %s\n", logentry.c_str());
101
102 TiXmlElement* leE = doc.FirstChildElement( "entry" );
103
104 std::vector<std::string> entries;
105
106 if(!leE) return false;
107
108 //parse date
109 TiXmlElement* dateE = leE->FirstChildElement( "isoDate" );
110
111 if(!dateE) return false;
112
113 std::string timestamp_str(dateE->GetText());
114
115 if(!cvs2cl_logentry_timestamp.match(timestamp_str, &entries))
116 return false;
117
118 struct tm time_str;
119
120 time_str.tm_year = atoi(entries[0].c_str()) - 1900;
121 time_str.tm_mon = atoi(entries[1].c_str()) - 1;
122 time_str.tm_mday = atoi(entries[2].c_str());
123 time_str.tm_hour = atoi(entries[3].c_str());
124 time_str.tm_min = atoi(entries[4].c_str());
125 time_str.tm_sec = atoi(entries[5].c_str());
126 time_str.tm_isdst = -1;
127
128 commit.timestamp = mktime(&time_str);
129
130 //parse author
131 TiXmlElement* authorE = leE->FirstChildElement("author");
132
133 if(authorE != 0) {
134
135 std::string author(authorE->GetText());
136
137 if(author.empty()) author = "Unknown";
138
139 commit.username = author;
140 }
141
142 //parse changes
143
144 for(TiXmlElement* fileE = leE->FirstChildElement("file"); fileE != 0; fileE = fileE->NextSiblingElement()) {
145
146 TiXmlElement* state = fileE->FirstChildElement("cvsstate");
147 TiXmlElement* name = fileE->FirstChildElement("name");
148
149 //check for state
150 if(name == 0 || state == 0) continue;
151
152 std::string status = strcmp(state->GetText(), "dead") == 0 ? "D" : "M";
153 std::string file(name->GetText());
154
155 if(file.empty()) continue;
156
157 commit.addFile(file, status);
158 }
159
160 //fprintf(stderr,"parsed logentry\n");
161
162 //read files
163
164 return true;
165 }
166