tangled
alpha
login
or
join now
jcs.org
/
openbsd-commitid
0
fork
atom
script to retroactively add commitids to past openbsd commits
0
fork
atom
overview
issues
pulls
pipelines
move classes to separate files
jcs.org
11 years ago
e574a3db
11561c9b
+327
-321
4 changed files
expand all
collapse all
unified
split
openbsd-commitid.rb
rcsfile.rb
rcsrevision.rb
scanner.rb
+9
-321
openbsd-commitid.rb
···
10
10
# add commitids back to rcs files
11
11
# $ ruby openbsd-commitid.rb
12
12
#
13
13
+
# NOTE: rcs/rlog must be modified to end revisions with ###, not just a line of
14
14
+
# dashes since those appear in some commit messages
15
15
+
#
16
16
+
17
17
+
$:.push "."
18
18
+
19
19
+
require "scanner"
20
20
+
require "rcsfile"
21
21
+
require "rcsrevision"
13
22
14
23
CVSROOT = "/var/cvs-commitid/"
15
24
CVSTMP = "/var/cvs-tmp/"
···
35
44
# stored back in CVSROOT/#{tree}
36
45
sc.repo_surgery(CVSTMP, CVSROOT, tree)
37
46
end
38
38
-
39
39
-
BEGIN {
40
40
-
require "sqlite3"
41
41
-
42
42
-
class RCSFile
43
43
-
attr_accessor :revisions
44
44
-
45
45
-
def initialize(file)
46
46
-
@revisions = {}
47
47
-
48
48
-
# rcs modified to end revs in ###
49
49
-
blocks = []
50
50
-
IO.popen([ "rlog", file ]) do |rlog|
51
51
-
blocks = rlog.read.force_encoding("binary").
52
52
-
split(/^(-{28}|={77})###\n?$/).reject{|b| b.match(/^(-{28}|={77})$/) }
53
53
-
end
54
54
-
55
55
-
if !blocks.first.match(/^RCS file/)
56
56
-
raise "file #{file} didn't come out of rlog properly"
57
57
-
end
58
58
-
59
59
-
blocks.shift
60
60
-
blocks.each do |block|
61
61
-
rev = RCSRevision.new(block)
62
62
-
if @revisions[rev.revision]
63
63
-
raise "duplicate revision #{rev.revision} in #{file}"
64
64
-
end
65
65
-
@revisions[rev.revision] = rev
66
66
-
end
67
67
-
end
68
68
-
end
69
69
-
70
70
-
class RCSRevision
71
71
-
attr_accessor :revision, :date, :author, :state, :lines, :commitid, :log
72
72
-
73
73
-
# str: "revision 1.7\ndate: 1996/12/14 12:17:33; author: mickey; state: Exp; lines: +3 -3;\n-Wall'ing."
74
74
-
def initialize(str)
75
75
-
@revision = nil
76
76
-
@date = 0
77
77
-
@author = nil
78
78
-
@state = nil
79
79
-
@lines = nil
80
80
-
@commitid = nil
81
81
-
@log = nil
82
82
-
83
83
-
lines = str.gsub(/^\s*/, "").split("\n")
84
84
-
# -> [
85
85
-
# "revision 1.7",
86
86
-
# "date: 1996/12/14 12:17:33; author: mickey; state: Exp; lines: +3 -3;",
87
87
-
# "-Wall'ing."
88
88
-
# ]
89
89
-
90
90
-
# strip out possible branches line in log
91
91
-
if lines[2].to_s.match(/^branches:\s+([\d\.]+)/)
92
92
-
lines.delete_at(2)
93
93
-
end
94
94
-
95
95
-
@revision = lines.first.scan(/^revision ([\d\.]+)($|\tlocked by)/).first.first
96
96
-
# -> "1.7"
97
97
-
98
98
-
# date/author/state/lines/commitid line
99
99
-
lines[1].split(/;[ \t]*/).each do |piece|
100
100
-
kv = piece.split(": ")
101
101
-
self.send(kv[0] + "=", kv[1])
102
102
-
end
103
103
-
# -> @date = "1996/12/14 12:17:33", @author = "mickey", ...
104
104
-
105
105
-
if m = @date.match(/^\d\d\d\d\/\d\d\/\d\d \d\d:\d\d:\d\d$/)
106
106
-
@date = DateTime.parse(@date).strftime("%s").to_i
107
107
-
else
108
108
-
raise "invalid date #{@date}"
109
109
-
end
110
110
-
# -> @date = 850565853
111
111
-
112
112
-
@log = lines[2, lines.count].join("\n")
113
113
-
end
114
114
-
end
115
115
-
116
116
-
class Scanner
117
117
-
def initialize(dbf, root)
118
118
-
@db = SQLite3::Database.new dbf
119
119
-
120
120
-
@db.execute "CREATE TABLE IF NOT EXISTS changesets
121
121
-
(id integer primary key, date integer, author text, commitid text,
122
122
-
log text)"
123
123
-
@db.execute "CREATE UNIQUE INDEX IF NOT EXISTS u_commitid ON changesets
124
124
-
(commitid)"
125
125
-
126
126
-
@db.execute "CREATE TABLE IF NOT EXISTS files
127
127
-
(id integer primary key, file text)"
128
128
-
@db.execute "CREATE UNIQUE INDEX IF NOT EXISTS u_file ON files
129
129
-
(file)"
130
130
-
131
131
-
@db.execute "CREATE TABLE IF NOT EXISTS revisions
132
132
-
(id integer primary key, file_id integer, changeset_id integer,
133
133
-
date integer, version text, author text, commitid text, log text)"
134
134
-
@db.execute "CREATE UNIQUE INDEX IF NOT EXISTS u_revision ON revisions
135
135
-
(file_id, version)"
136
136
-
@db.execute "CREATE INDEX IF NOT EXISTS empty_changesets ON revisions
137
137
-
(changeset_id)"
138
138
-
@db.execute "CREATE INDEX IF NOT EXISTS cs_by_commitid ON revisions
139
139
-
(commitid, changeset_id)"
140
140
-
@db.execute "CREATE INDEX IF NOT EXISTS all_revs_by_author ON revisions
141
141
-
(author, date)"
142
142
-
143
143
-
@db.results_as_hash = true
144
144
-
145
145
-
@root = (root + "/").gsub(/\/\//, "/")
146
146
-
end
147
147
-
148
148
-
def recursively_scan(dir = nil)
149
149
-
if !dir
150
150
-
dir = @root
151
151
-
end
152
152
-
153
153
-
puts "recursing into #{dir}"
154
154
-
155
155
-
Dir.glob((dir + "/*").gsub(/\/\//, "/")).each do |f|
156
156
-
if Dir.exists?(f)
157
157
-
recursively_scan(f)
158
158
-
elsif f.match(/,v$/)
159
159
-
scan(f)
160
160
-
end
161
161
-
end
162
162
-
end
163
163
-
164
164
-
def scan(f)
165
165
-
canfile = f[@root.length, f.length - @root.length].gsub(/\/Attic\//, "/")
166
166
-
puts " scanning file #{canfile}"
167
167
-
168
168
-
rcs = RCSFile.new(f)
169
169
-
170
170
-
fid = @db.execute("SELECT id FROM files WHERE file = ?", [ canfile ]).first
171
171
-
if !fid
172
172
-
@db.execute("INSERT INTO files (file) VALUES (?)", [ canfile ])
173
173
-
fid = @db.execute("SELECT id FROM files WHERE file = ?",
174
174
-
[ canfile ]).first
175
175
-
end
176
176
-
raise if !fid
177
177
-
178
178
-
rcs.revisions.each do |r,rev|
179
179
-
rid = @db.execute("SELECT id, commitid FROM revisions WHERE " +
180
180
-
"file_id = ? AND version = ?", [ fid["id"], r ]).first
181
181
-
182
182
-
if rid
183
183
-
if rid["commitid"] != rev.commitid
184
184
-
puts " updated #{r} to commitid #{rev.commitid}" +
185
185
-
(rid["commitid"].to_s == "" ? "" : " from #{rid["commitid"]}")
186
186
-
187
187
-
@db.execute("UPDATE revisions SET commitid = ? WHERE file_id = ? " +
188
188
-
"AND version = ?", [ rev.commitid, fid["id"], rev.revision ])
189
189
-
end
190
190
-
else
191
191
-
puts " inserted #{r}, authored #{rev.date} by #{rev.author}" +
192
192
-
(rev.commitid ? ", commitid #{rev.commitid}" : "")
193
193
-
194
194
-
@db.execute("INSERT INTO revisions (file_id, date, version, author, " +
195
195
-
"commitid, log) VALUES (?, ?, ?, ?, ?, ?)", [ fid["id"], rev.date,
196
196
-
rev.revision, rev.author, rev.commitid, rev.log ])
197
197
-
end
198
198
-
end
199
199
-
end
200
200
-
201
201
-
def stray_commitids_to_changesets
202
202
-
stray_commitids = @db.execute("SELECT DISTINCT author, commitid FROM " +
203
203
-
"revisions WHERE commitid IS NOT NULL AND changeset_id IS NULL")
204
204
-
stray_commitids.each do |row|
205
205
-
csid = @db.execute("SELECT id FROM changesets WHERE commitid = ?",
206
206
-
[ row["commitid"] ]).first
207
207
-
if !csid
208
208
-
@db.execute("INSERT INTO changesets (author, commitid) VALUES (?, ?)",
209
209
-
[ row["author"], row["commitid"] ])
210
210
-
csid = @db.execute("SELECT id FROM changesets WHERE commitid = ?",
211
211
-
[ row["commitid"] ]).first
212
212
-
end
213
213
-
raise if !csid
214
214
-
215
215
-
puts "commitid #{row["commitid"]} -> changeset #{csid["id"]}"
216
216
-
217
217
-
@db.execute("UPDATE revisions SET changeset_id = ? WHERE commitid = ?",
218
218
-
[ csid["id"], row["commitid"] ])
219
219
-
end
220
220
-
end
221
221
-
222
222
-
def group_into_changesets
223
223
-
new_sets = []
224
224
-
last_row = {}
225
225
-
cur_set = []
226
226
-
227
227
-
@db.execute("SELECT * FROM revisions WHERE changeset_id IS NULL ORDER " +
228
228
-
"BY author ASC, date ASC") do |row|
229
229
-
# commits by the same author with the same log message (unless they're
230
230
-
# initial imports - 1.1.1.1) within 30 seconds of each other are grouped
231
231
-
# together
232
232
-
if last_row.any? && row["author"] == last_row["author"] &&
233
233
-
(row["log"] == last_row["log"] || row["log"] == "Initial revision" ||
234
234
-
last_row["log"] == "Initial revision") &&
235
235
-
row["date"].to_i - last_row["date"].to_i <= 30
236
236
-
cur_set.push row["id"].to_i
237
237
-
elsif !last_row.any?
238
238
-
cur_set.push row["id"].to_i
239
239
-
else
240
240
-
if cur_set.any?
241
241
-
new_sets.push cur_set
242
242
-
cur_set = []
243
243
-
end
244
244
-
cur_set.push row["id"].to_i
245
245
-
end
246
246
-
247
247
-
last_row = row
248
248
-
end
249
249
-
250
250
-
if cur_set.any?
251
251
-
new_sets.push cur_set
252
252
-
end
253
253
-
254
254
-
new_sets.each do |s|
255
255
-
puts "new set with revision ids #{s.inspect}"
256
256
-
@db.execute("INSERT INTO changesets (id) VALUES (NULL)")
257
257
-
id = @db.execute("SELECT last_insert_rowid() AS id").first["id"]
258
258
-
raise if !id
259
259
-
260
260
-
# avoid an exception caused by passing too many variables
261
261
-
s.each_slice(100) do |chunk|
262
262
-
@db.execute("UPDATE revisions SET changeset_id = ? WHERE id IN (" +
263
263
-
chunk.map{|a| "?" }.join(",") + ")", [ id ] + chunk)
264
264
-
end
265
265
-
end
266
266
-
267
267
-
if @db.execute("SELECT * FROM revisions WHERE changeset_id IS NULL").any?
268
268
-
raise "still have revisions with empty changesets"
269
269
-
end
270
270
-
end
271
271
-
272
272
-
def fill_in_changeset_data
273
273
-
cses = {}
274
274
-
@db.execute("SELECT id, commitid FROM changesets WHERE date IS NULL") do |c|
275
275
-
cses[c["id"]] = c["commitid"]
276
276
-
end
277
277
-
278
278
-
cses.each do |csid,comid|
279
279
-
date = nil
280
280
-
commitid = comid
281
281
-
log = nil
282
282
-
author = nil
283
283
-
284
284
-
@db.execute("SELECT * FROM revisions WHERE changeset_id = ? ORDER BY " +
285
285
-
"date ASC", [ csid ]) do |rev|
286
286
-
if !date
287
287
-
date = rev["date"]
288
288
-
end
289
289
-
290
290
-
if rev["log"] != "Initial revision"
291
291
-
log = rev["log"]
292
292
-
end
293
293
-
294
294
-
if author && rev["author"] != author
295
295
-
raise "authors different between revs of #{csid}"
296
296
-
else
297
297
-
author = rev["author"]
298
298
-
end
299
299
-
end
300
300
-
301
301
-
if commitid.to_s == ""
302
302
-
commitid = ""
303
303
-
while commitid.length < 16
304
304
-
c = rand(75) + 48
305
305
-
if ((c >= 48 && c <= 57) || (c >= 65 && c <= 90) ||
306
306
-
(c >= 97 && c <= 122))
307
307
-
commitid << c.chr
308
308
-
end
309
309
-
end
310
310
-
end
311
311
-
312
312
-
if !date
313
313
-
raise "no date for changeset #{csid}"
314
314
-
end
315
315
-
316
316
-
puts "changeset #{csid} -> commitid #{commitid}"
317
317
-
318
318
-
@db.execute("UPDATE changesets SET date = ?, commitid = ?, log = ?, " +
319
319
-
"author = ? WHERE id = ?", [ date, commitid, log, author, csid ])
320
320
-
end
321
321
-
end
322
322
-
323
323
-
def repo_surgery(tmp_dir, cvs_root, tree)
324
324
-
puts "checking out repo \"#{tree}\" to #{tmp_dir}"
325
325
-
326
326
-
Dir.chdir(tmp_dir)
327
327
-
# don't pass -P because we'll need empty dirs around for Attic changes
328
328
-
system("cvs", "-Q", "-d", cvs_root, "co", tree)
329
329
-
330
330
-
Dir.chdir(tmp_dir + "/#{tree}")
331
331
-
332
332
-
csid = nil
333
333
-
@db.execute("SELECT
334
334
-
files.file, changesets.commitid, changesets.author, changesets.date,
335
335
-
revisions.version
336
336
-
FROM revisions
337
337
-
LEFT OUTER JOIN files ON files.id = file_id
338
338
-
LEFT OUTER JOIN changesets ON revisions.changeset_id = changesets.id
339
339
-
WHERE revisions.commitid IS NULL
340
340
-
ORDER BY changesets.date ASC, files.file ASC") do |rev|
341
341
-
if csid == nil || rev["commitid"] != csid
342
342
-
puts " commit #{rev["commitid"]} at #{Time.at(rev["date"])} by " +
343
343
-
rev["author"]
344
344
-
csid = rev["commitid"]
345
345
-
end
346
346
-
347
347
-
puts " #{rev["file"]} #{rev["version"]}"
348
348
-
349
349
-
system("cvs", "-Q", "admin", "-C",
350
350
-
"#{rev["version"]}:#{rev["commitid"]}", rev["file"].gsub(/,v$/, ""))
351
351
-
end
352
352
-
353
353
-
puts "cleaning up #{tmp_dir}/#{tree}"
354
354
-
355
355
-
system("rm", "-rf", tmp_dir + "/#{tree}")
356
356
-
end
357
357
-
end
358
358
-
}
+27
rcsfile.rb
···
1
1
+
class RCSFile
2
2
+
attr_accessor :revisions
3
3
+
4
4
+
def initialize(file)
5
5
+
@revisions = {}
6
6
+
7
7
+
# rcs modified to end revs in ###
8
8
+
blocks = []
9
9
+
IO.popen([ "rlog", file ]) do |rlog|
10
10
+
blocks = rlog.read.force_encoding("binary").
11
11
+
split(/^(-{28}|={77})###\n?$/).reject{|b| b.match(/^(-{28}|={77})$/) }
12
12
+
end
13
13
+
14
14
+
if !blocks.first.match(/^RCS file/)
15
15
+
raise "file #{file} didn't come out of rlog properly"
16
16
+
end
17
17
+
18
18
+
blocks.shift
19
19
+
blocks.each do |block|
20
20
+
rev = RCSRevision.new(block)
21
21
+
if @revisions[rev.revision]
22
22
+
raise "duplicate revision #{rev.revision} in #{file}"
23
23
+
end
24
24
+
@revisions[rev.revision] = rev
25
25
+
end
26
26
+
end
27
27
+
end
+47
rcsrevision.rb
···
1
1
+
require "date"
2
2
+
3
3
+
class RCSRevision
4
4
+
attr_accessor :revision, :date, :author, :state, :lines, :commitid, :log
5
5
+
6
6
+
# str: "revision 1.7\ndate: 1996/12/14 12:17:33; author: mickey; state: Exp; lines: +3 -3;\n-Wall'ing."
7
7
+
def initialize(str)
8
8
+
@revision = nil
9
9
+
@date = 0
10
10
+
@author = nil
11
11
+
@state = nil
12
12
+
@lines = nil
13
13
+
@commitid = nil
14
14
+
@log = nil
15
15
+
16
16
+
lines = str.gsub(/^\s*/, "").split("\n")
17
17
+
# -> [
18
18
+
# "revision 1.7",
19
19
+
# "date: 1996/12/14 12:17:33; author: mickey; state: Exp; lines: +3 -3;",
20
20
+
# "-Wall'ing."
21
21
+
# ]
22
22
+
23
23
+
# strip out possible branches line in log
24
24
+
if lines[2].to_s.match(/^branches:\s+([\d\.]+)/)
25
25
+
lines.delete_at(2)
26
26
+
end
27
27
+
28
28
+
@revision = lines.first.scan(/^revision ([\d\.]+)($|\tlocked by)/).first.first
29
29
+
# -> "1.7"
30
30
+
31
31
+
# date/author/state/lines/commitid line
32
32
+
lines[1].split(/;[ \t]*/).each do |piece|
33
33
+
kv = piece.split(": ")
34
34
+
self.send(kv[0] + "=", kv[1])
35
35
+
end
36
36
+
# -> @date = "1996/12/14 12:17:33", @author = "mickey", ...
37
37
+
38
38
+
if m = @date.match(/^\d\d\d\d\/\d\d\/\d\d \d\d:\d\d:\d\d$/)
39
39
+
@date = DateTime.parse(@date).strftime("%s").to_i
40
40
+
else
41
41
+
raise "invalid date #{@date}"
42
42
+
end
43
43
+
# -> @date = 850565853
44
44
+
45
45
+
@log = lines[2, lines.count].join("\n")
46
46
+
end
47
47
+
end
+244
scanner.rb
···
1
1
+
require "sqlite3"
2
2
+
3
3
+
class Scanner
4
4
+
def initialize(dbf, root)
5
5
+
@db = SQLite3::Database.new dbf
6
6
+
7
7
+
@db.execute "CREATE TABLE IF NOT EXISTS changesets
8
8
+
(id integer primary key, date integer, author text, commitid text,
9
9
+
log text)"
10
10
+
@db.execute "CREATE UNIQUE INDEX IF NOT EXISTS u_commitid ON changesets
11
11
+
(commitid)"
12
12
+
13
13
+
@db.execute "CREATE TABLE IF NOT EXISTS files
14
14
+
(id integer primary key, file text)"
15
15
+
@db.execute "CREATE UNIQUE INDEX IF NOT EXISTS u_file ON files
16
16
+
(file)"
17
17
+
18
18
+
@db.execute "CREATE TABLE IF NOT EXISTS revisions
19
19
+
(id integer primary key, file_id integer, changeset_id integer,
20
20
+
date integer, version text, author text, commitid text, log text)"
21
21
+
@db.execute "CREATE UNIQUE INDEX IF NOT EXISTS u_revision ON revisions
22
22
+
(file_id, version)"
23
23
+
@db.execute "CREATE INDEX IF NOT EXISTS empty_changesets ON revisions
24
24
+
(changeset_id)"
25
25
+
@db.execute "CREATE INDEX IF NOT EXISTS cs_by_commitid ON revisions
26
26
+
(commitid, changeset_id)"
27
27
+
@db.execute "CREATE INDEX IF NOT EXISTS all_revs_by_author ON revisions
28
28
+
(author, date)"
29
29
+
30
30
+
@db.results_as_hash = true
31
31
+
32
32
+
@root = (root + "/").gsub(/\/\//, "/")
33
33
+
end
34
34
+
35
35
+
def recursively_scan(dir = nil)
36
36
+
if !dir
37
37
+
dir = @root
38
38
+
end
39
39
+
40
40
+
puts "recursing into #{dir}"
41
41
+
42
42
+
Dir.glob((dir + "/*").gsub(/\/\//, "/")).each do |f|
43
43
+
if Dir.exists?(f)
44
44
+
recursively_scan(f)
45
45
+
elsif f.match(/,v$/)
46
46
+
scan(f)
47
47
+
end
48
48
+
end
49
49
+
end
50
50
+
51
51
+
def scan(f)
52
52
+
canfile = f[@root.length, f.length - @root.length].gsub(/\/Attic\//, "/")
53
53
+
puts " scanning file #{canfile}"
54
54
+
55
55
+
rcs = RCSFile.new(f)
56
56
+
57
57
+
fid = @db.execute("SELECT id FROM files WHERE file = ?", [ canfile ]).first
58
58
+
if !fid
59
59
+
@db.execute("INSERT INTO files (file) VALUES (?)", [ canfile ])
60
60
+
fid = @db.execute("SELECT id FROM files WHERE file = ?",
61
61
+
[ canfile ]).first
62
62
+
end
63
63
+
raise if !fid
64
64
+
65
65
+
rcs.revisions.each do |r,rev|
66
66
+
rid = @db.execute("SELECT id, commitid FROM revisions WHERE " +
67
67
+
"file_id = ? AND version = ?", [ fid["id"], r ]).first
68
68
+
69
69
+
if rid
70
70
+
if rid["commitid"] != rev.commitid
71
71
+
puts " updated #{r} to commitid #{rev.commitid}" +
72
72
+
(rid["commitid"].to_s == "" ? "" : " from #{rid["commitid"]}")
73
73
+
74
74
+
@db.execute("UPDATE revisions SET commitid = ? WHERE file_id = ? " +
75
75
+
"AND version = ?", [ rev.commitid, fid["id"], rev.revision ])
76
76
+
end
77
77
+
else
78
78
+
puts " inserted #{r}, authored #{rev.date} by #{rev.author}" +
79
79
+
(rev.commitid ? ", commitid #{rev.commitid}" : "")
80
80
+
81
81
+
@db.execute("INSERT INTO revisions (file_id, date, version, author, " +
82
82
+
"commitid, log) VALUES (?, ?, ?, ?, ?, ?)", [ fid["id"], rev.date,
83
83
+
rev.revision, rev.author, rev.commitid, rev.log ])
84
84
+
end
85
85
+
end
86
86
+
end
87
87
+
88
88
+
def stray_commitids_to_changesets
89
89
+
stray_commitids = @db.execute("SELECT DISTINCT author, commitid FROM " +
90
90
+
"revisions WHERE commitid IS NOT NULL AND changeset_id IS NULL")
91
91
+
stray_commitids.each do |row|
92
92
+
csid = @db.execute("SELECT id FROM changesets WHERE commitid = ?",
93
93
+
[ row["commitid"] ]).first
94
94
+
if !csid
95
95
+
@db.execute("INSERT INTO changesets (author, commitid) VALUES (?, ?)",
96
96
+
[ row["author"], row["commitid"] ])
97
97
+
csid = @db.execute("SELECT id FROM changesets WHERE commitid = ?",
98
98
+
[ row["commitid"] ]).first
99
99
+
end
100
100
+
raise if !csid
101
101
+
102
102
+
puts "commitid #{row["commitid"]} -> changeset #{csid["id"]}"
103
103
+
104
104
+
@db.execute("UPDATE revisions SET changeset_id = ? WHERE commitid = ?",
105
105
+
[ csid["id"], row["commitid"] ])
106
106
+
end
107
107
+
end
108
108
+
109
109
+
def group_into_changesets
110
110
+
new_sets = []
111
111
+
last_row = {}
112
112
+
cur_set = []
113
113
+
114
114
+
@db.execute("SELECT * FROM revisions WHERE changeset_id IS NULL ORDER " +
115
115
+
"BY author ASC, date ASC") do |row|
116
116
+
# commits by the same author with the same log message (unless they're
117
117
+
# initial imports - 1.1.1.1) within 30 seconds of each other are grouped
118
118
+
# together
119
119
+
if last_row.any? && row["author"] == last_row["author"] &&
120
120
+
(row["log"] == last_row["log"] || row["log"] == "Initial revision" ||
121
121
+
last_row["log"] == "Initial revision") &&
122
122
+
row["date"].to_i - last_row["date"].to_i <= 30
123
123
+
cur_set.push row["id"].to_i
124
124
+
elsif !last_row.any?
125
125
+
cur_set.push row["id"].to_i
126
126
+
else
127
127
+
if cur_set.any?
128
128
+
new_sets.push cur_set
129
129
+
cur_set = []
130
130
+
end
131
131
+
cur_set.push row["id"].to_i
132
132
+
end
133
133
+
134
134
+
last_row = row
135
135
+
end
136
136
+
137
137
+
if cur_set.any?
138
138
+
new_sets.push cur_set
139
139
+
end
140
140
+
141
141
+
new_sets.each do |s|
142
142
+
puts "new set with revision ids #{s.inspect}"
143
143
+
@db.execute("INSERT INTO changesets (id) VALUES (NULL)")
144
144
+
id = @db.execute("SELECT last_insert_rowid() AS id").first["id"]
145
145
+
raise if !id
146
146
+
147
147
+
# avoid an exception caused by passing too many variables
148
148
+
s.each_slice(100) do |chunk|
149
149
+
@db.execute("UPDATE revisions SET changeset_id = ? WHERE id IN (" +
150
150
+
chunk.map{|a| "?" }.join(",") + ")", [ id ] + chunk)
151
151
+
end
152
152
+
end
153
153
+
154
154
+
if @db.execute("SELECT * FROM revisions WHERE changeset_id IS NULL").any?
155
155
+
raise "still have revisions with empty changesets"
156
156
+
end
157
157
+
end
158
158
+
159
159
+
def fill_in_changeset_data
160
160
+
cses = {}
161
161
+
@db.execute("SELECT id, commitid FROM changesets WHERE date IS NULL") do |c|
162
162
+
cses[c["id"]] = c["commitid"]
163
163
+
end
164
164
+
165
165
+
cses.each do |csid,comid|
166
166
+
date = nil
167
167
+
commitid = comid
168
168
+
log = nil
169
169
+
author = nil
170
170
+
171
171
+
@db.execute("SELECT * FROM revisions WHERE changeset_id = ? ORDER BY " +
172
172
+
"date ASC", [ csid ]) do |rev|
173
173
+
if !date
174
174
+
date = rev["date"]
175
175
+
end
176
176
+
177
177
+
if rev["log"] != "Initial revision"
178
178
+
log = rev["log"]
179
179
+
end
180
180
+
181
181
+
if author && rev["author"] != author
182
182
+
raise "authors different between revs of #{csid}"
183
183
+
else
184
184
+
author = rev["author"]
185
185
+
end
186
186
+
end
187
187
+
188
188
+
if commitid.to_s == ""
189
189
+
commitid = ""
190
190
+
while commitid.length < 16
191
191
+
c = rand(75) + 48
192
192
+
if ((c >= 48 && c <= 57) || (c >= 65 && c <= 90) ||
193
193
+
(c >= 97 && c <= 122))
194
194
+
commitid << c.chr
195
195
+
end
196
196
+
end
197
197
+
end
198
198
+
199
199
+
if !date
200
200
+
raise "no date for changeset #{csid}"
201
201
+
end
202
202
+
203
203
+
puts "changeset #{csid} -> commitid #{commitid}"
204
204
+
205
205
+
@db.execute("UPDATE changesets SET date = ?, commitid = ?, log = ?, " +
206
206
+
"author = ? WHERE id = ?", [ date, commitid, log, author, csid ])
207
207
+
end
208
208
+
end
209
209
+
210
210
+
def repo_surgery(tmp_dir, cvs_root, tree)
211
211
+
puts "checking out repo \"#{tree}\" to #{tmp_dir}"
212
212
+
213
213
+
Dir.chdir(tmp_dir)
214
214
+
# don't pass -P because we'll need empty dirs around for Attic changes
215
215
+
system("cvs", "-Q", "-d", cvs_root, "co", tree)
216
216
+
217
217
+
Dir.chdir(tmp_dir + "/#{tree}")
218
218
+
219
219
+
csid = nil
220
220
+
@db.execute("SELECT
221
221
+
files.file, changesets.commitid, changesets.author, changesets.date,
222
222
+
revisions.version
223
223
+
FROM revisions
224
224
+
LEFT OUTER JOIN files ON files.id = file_id
225
225
+
LEFT OUTER JOIN changesets ON revisions.changeset_id = changesets.id
226
226
+
WHERE revisions.commitid IS NULL
227
227
+
ORDER BY changesets.date ASC, files.file ASC") do |rev|
228
228
+
if csid == nil || rev["commitid"] != csid
229
229
+
puts " commit #{rev["commitid"]} at #{Time.at(rev["date"])} by " +
230
230
+
rev["author"]
231
231
+
csid = rev["commitid"]
232
232
+
end
233
233
+
234
234
+
puts " #{rev["file"]} #{rev["version"]}"
235
235
+
236
236
+
system("cvs", "-Q", "admin", "-C",
237
237
+
"#{rev["version"]}:#{rev["commitid"]}", rev["file"].gsub(/,v$/, ""))
238
238
+
end
239
239
+
240
240
+
puts "cleaning up #{tmp_dir}/#{tree}"
241
241
+
242
242
+
system("rm", "-rf", tmp_dir + "/#{tree}")
243
243
+
end
244
244
+
end