-
Notifications
You must be signed in to change notification settings - Fork 0
/
svn_cvs_msgs.cpp
370 lines (328 loc) · 11 KB
/
svn_cvs_msgs.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
/* S V N _ C V S _ M S G S . C P P
* BRL-CAD
*
* Published in 2020 by the United States Government.
* This work is in the public domain.
*
*/
/** @file repowork.cpp
*
* Utility functions and main processing loop
*
*/
#include <iostream>
#include <sstream>
#include <locale>
#include "repowork.h"
// https://stackoverflow.com/a/5607650
struct schars: std::ctype<char> {
schars(): std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table() {
static const std::ctype<char>::mask *const_table= std::ctype<char>::classic_table();
static std::ctype<char>::mask cmask[std::ctype<char>::table_size];
std::memcpy(cmask, const_table, std::ctype<char>::table_size * sizeof(std::ctype<char>::mask));
cmask[';'] = std::ctype_base::space;
return &cmask[0];
}
};
void
parse_cvs_svn_info(git_commit_data *c, std::string &str)
{
std::stringstream ss(str);
std::string cline;
std::regex svnrevline("^svn:revision:([0-9]+).*");
std::regex svnbranchline("^svn:branch:(.*)");
std::regex svntagline("^svn:tag:(.*)");
std::regex svncommitterline("^svn:account:(.*)");
std::regex cvsbranchline("^cvs:branch:(.*)");
std::regex cvscommitterline("^cvs:account:(.*)");
c->svn_branches.clear();
c->cvs_branches.clear();
while (std::getline(ss, cline, '\n')) {
if (std::regex_match(cline, svnrevline)) {
c->svn_id = cline.substr(13, std::string::npos);
continue;
}
if (std::regex_match(cline, svnbranchline)) {
std::string nbranch = cline.substr(11, std::string::npos);
if (nbranch == std::string("master")) {
nbranch = std::string("trunk");
}
c->svn_branches.insert(nbranch);
continue;
}
if (std::regex_match(cline, svntagline)) {
std::string ntag = cline.substr(8, std::string::npos);
if (ntag == std::string("master")) {
ntag = std::string("trunk");
}
c->svn_tags.insert(ntag);
continue;
}
if (std::regex_match(cline, svncommitterline)) {
c->svn_committer = cline.substr(12, std::string::npos);
continue;
}
if (std::regex_match(cline, cvsbranchline)) {
std::string nbranch = cline.substr(11, std::string::npos);
if (nbranch == std::string("master")) {
nbranch = std::string("trunk");
}
c->cvs_branches.insert(nbranch);
continue;
}
if (std::regex_match(cline, cvscommitterline)) {
c->cvs_committer = cline.substr(12, std::string::npos);
continue;
}
}
}
void
update_commit_msg(git_commit_data *c)
{
// First, get a version of the commit message without any svn or cvs info.
std::set<std::string>::iterator s_it;
std::regex cvsline("^cvs:.*");
std::regex svnline("^svn:.*");
std::string cline;
std::string nmsg;
std::stringstream css(c->commit_msg);
while (std::getline(css, cline, '\n')) {
bool smatch = std::regex_match(cline, svnline);
bool cmatch = std::regex_match(cline, cvsline);
if (smatch || cmatch) {
// If we do already have CVS/SVN info, don't write the last blank
// spacer line - it was inserted to separate it from the actual
// message.
nmsg.pop_back();
break;
}
nmsg.append(cline);
nmsg.append("\n");
}
// If we have any SVN or CVS info, insert a blank line:
if ((c->svn_id.length() && c->svn_id != std::string("-1")) || c->svn_branches.size() || c->svn_tags.size() || c->svn_committer.length() || c->cvs_branches.size() || c->cvs_committer.length() ) {
nmsg.append("\n");
}
// Add all the info we have
if (c->svn_id.length() && c->svn_id != std::string("-1")) {
std::string ninfo = std::string("svn:revision:") + c->svn_id;
nmsg.append(ninfo);
nmsg.append("\n");
}
for (s_it = c->svn_branches.begin(); s_it != c->svn_branches.end(); s_it++) {
std::string ninfo = std::string("svn:branch:") + *s_it;
nmsg.append(ninfo);
nmsg.append("\n");
}
for (s_it = c->svn_tags.begin(); s_it != c->svn_tags.end(); s_it++) {
std::string ninfo = std::string("svn:tag:") + *s_it;
nmsg.append(ninfo);
nmsg.append("\n");
}
if (c->svn_committer.length()) {
std::string ninfo = std::string("svn:account:") + c->svn_committer;
nmsg.append(ninfo);
nmsg.append("\n");
}
for (s_it = c->cvs_branches.begin(); s_it != c->cvs_branches.end(); s_it++) {
std::string ninfo = std::string("cvs:branch:") + *s_it;
nmsg.append(ninfo);
nmsg.append("\n");
}
if (c->cvs_committer.length()) {
std::string ninfo = std::string("cvs:account:") + c->cvs_committer;
nmsg.append(ninfo);
nmsg.append("\n");
}
c->commit_msg = nmsg;
}
// This is the first step of the note correction process - run it first
int
git_update_svn_revs(git_fi_data *s, std::string &svn_rev_map)
{
if (!s->have_sha1s) {
std::cerr << "Fatal - sha1 SVN note updating requested, but don't have original sha1 ids - redo fast-export with the --show-original-ids option.\n";
exit(1);
}
// read maps
std::ifstream infile_revs(svn_rev_map, std::ifstream::binary);
if (svn_rev_map.length() && !infile_revs.good()) {
std::cerr << "Could not open svn_rev_map file: " << svn_rev_map << "\n";
exit(-1);
}
std::map<std::string, int> rmap;
if (infile_revs.good()) {
std::string line;
while (std::getline(infile_revs, line)) {
// Skip empty lines
if (!line.length()) {
continue;
}
size_t spos = line.find_first_of(";");
if (spos == std::string::npos) {
std::cerr << "Invalid sha1;rev map line!: " << line << "\n";
exit(-1);
}
std::string id1 = line.substr(0, spos);
std::string id2 = line.substr(spos+1, std::string::npos);
int rev = (id2.length()) ? std::stoi(id2) : -1;
rmap[id1] = rev;
}
infile_revs.close();
}
for (size_t i = 0; i < s->commits.size(); i++) {
if (!s->commits[i].id.sha1.length()) {
continue;
}
if (rmap.find(s->commits[i].id.sha1) == rmap.end()) {
continue;
}
long nrev = rmap[s->commits[i].id.sha1];
s->commits[i].svn_id = std::to_string(nrev);
if (nrev > 0) {
std::cout << "Assigning new SVN rev " << nrev << " to " << s->commits[i].id.sha1 << "\n";
// Note: this isn't guaranteed to be unique... setting it mostly for
// the cases where it is.
s->rev_to_sha1[s->commits[i].svn_id] = s->commits[i].id.sha1;
update_commit_msg(&s->commits[i]);
}
}
return 0;
}
// This function is intended to handle map files with either sha1 or svn rev keys,
// and multiple branches mapping to one key either on multiple lines or by semicolon
// separated lists.
//
// If update_mode == 0, clear branch lines from the message when we don't have map
// information. If update_mode == 1, leave intact anything not explicitly in the map.
int
git_assign_branch_labels(git_fi_data *s, std::string &svn_branch_map, int update_mode)
{
int key_type = -1;
if (!s->have_sha1s) {
std::cerr << "Fatal - sha1 SVN note updating requested, but don't have original sha1 ids - redo fast-export with the --show-original-ids option.\n";
exit(1);
}
std::ifstream infile_branches(svn_branch_map, std::ifstream::binary);
if (svn_branch_map.length() && !infile_branches.good()) {
std::cerr << "Could not open svn_branch_map file: " << svn_branch_map << "\n";
exit(-1);
}
std::map<std::string, std::set<std::string>> bmap;
if (infile_branches.good()) {
std::string line;
while (std::getline(infile_branches, line)) {
// Skip empty lines
if (!line.length()) {
continue;
}
size_t spos = line.find_first_of(":");
if (spos == std::string::npos) {
std::cerr << "Invalid sha1;branch map line!: " << line << "\n";
exit(-1);
}
std::string id1 = line.substr(0, spos);
std::string id2 = line.substr(spos+1, std::string::npos);
if (key_type < 0) {
key_type = (id1.length() == 40) ? 1 : 2;
}
std::cout << "key: \"" << id1 << "\" -> branch: \"" << id2 << "\n";
// Split into a vector, since there may be more than one branch
std::stringstream ss(id2);
std::ostringstream oss;
ss.imbue(std::locale(std::locale(), new schars()));
std::istream_iterator<std::string> b_begin(ss);
std::istream_iterator<std::string> b_end;
std::vector<std::string> branches_array(b_begin, b_end);
std::copy(branches_array.begin(), branches_array.end(), std::ostream_iterator<std::string>(oss, "\n"));
for (size_t i = 0; i < branches_array.size(); i++) {
bmap[id1].insert(branches_array[i]);
}
}
infile_branches.close();
}
// Iterate over the commits looking for relevant commits, and update msg.
for (size_t i = 0; i < s->commits.size(); i++) {
long int rev = -1;
if (s->commits[i].svn_id.length()) {
rev = std::stol(s->commits[i].svn_id);
}
if (update_mode == 0 && s->commits[i].svn_id.length()) {
// If we're in overwrite mode, don't go beyond the CVS era commits -
// SVN era commits were assigned branches in the original process,
// and any alterations to them should be corrections. The CVS era
// assignments were unreliable, and so should be removed.
if (rev > 29886) {
continue;
}
}
std::set<std::string> sbranches;
if (key_type == 1) {
if (update_mode == 1 && !s->commits[i].id.sha1.length())
continue;
if (update_mode == 1 && bmap.find(s->commits[i].id.sha1) == bmap.end())
continue;
sbranches = bmap[s->commits[i].id.sha1];
}
if (key_type == 2) {
if (update_mode == 1 && !s->commits[i].svn_id.length())
continue;
if (update_mode == 1 && bmap.find(s->commits[i].svn_id) == bmap.end())
continue;
sbranches = bmap[s->commits[i].svn_id];
}
if (rev > 29886) {
s->commits[i].svn_branches.clear();
s->commits[i].svn_branches = sbranches;
} else {
s->commits[i].cvs_branches.clear();
s->commits[i].cvs_branches = sbranches;
}
// Update the message
update_commit_msg(&s->commits[i]);
}
return 0;
}
int
git_set_tag_labels(git_fi_data *s, std::string &tag_list)
{
if (!s->have_sha1s) {
std::cerr << "Fatal - sha1 SVN note updating requested, but don't have original sha1 ids - redo fast-export with the --show-original-ids option.\n";
exit(1);
}
std::ifstream infile_tag_list(tag_list, std::ifstream::binary);
if (tag_list.length() && !infile_tag_list.good()) {
std::cerr << "Could not open tag_list file: " << tag_list << "\n";
exit(-1);
}
std::set<std::string> tag_sha1s;
if (infile_tag_list.good()) {
std::string line;
while (std::getline(infile_tag_list, line)) {
// Skip anything the wrong length
if (line.length() != 40)
continue;
tag_sha1s.insert(line);
std::cout << "tag sha1: " << line << "\n";
bool valid = (s->sha1_to_mark.find(line) != s->sha1_to_mark.end());
if (!valid) {
std::cout << "INVALID sha1 supplied for tag!\n";
}
git_commit_data &c = s->commits[s->mark_to_index[s->sha1_to_mark[line]]];
c.svn_tags = c.svn_branches;
c.svn_branches.clear();
update_commit_msg(&c);
}
infile_tag_list.close();
}
return 0;
}
// Local Variables:
// tab-width: 8
// mode: C++
// c-basic-offset: 4
// indent-tabs-mode: t
// c-file-style: "stroustrup"
// End:
// ex: shiftwidth=4 tabstop=8