script to retroactively add commitids to past openbsd commits
1#
2# Copyright (c) 2014, 2016 joshua stein <jcs@jcs.org>
3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions
6# are met:
7#
8# 1. Redistributions of source code must retain the above copyright
9# notice, this list of conditions and the following disclaimer.
10# 2. Redistributions in binary form must reproduce the above copyright
11# notice, this list of conditions and the following disclaimer in the
12# documentation and/or other materials provided with the distribution.
13# 3. The name of the author may not be used to endorse or promote products
14# derived from this software without specific prior written permission.
15#
16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26#
27
28class RCSFile
29 attr_accessor :file, :revisions, :symbols, :first_undead_version
30
31 RCSEND = "==================OPENBSD_COMMITID_RCS_END=================="
32 REVSEP = "------------------OPENBSD_COMMITID_REV_SEP------------------"
33
34 def initialize(file)
35 @file = file
36 @revisions = {}
37 @symbols = {}
38
39 blocks = []
40 IO.popen([ "rlog", "-E#{RCSEND}", "-S#{REVSEP}", file ]) do |rlog|
41 blocks = rlog.read.force_encoding("iso-8859-1").
42 split(/^(#{REVSEP}|#{RCSEND})\n?$/).
43 reject{|b| b == RCSEND || b == REVSEP }
44 end
45
46 if !blocks.first.match(/^RCS file/)
47 raise "file #{file} didn't come out of rlog properly"
48 end
49
50 insymbols = false
51 blocks.shift.split("\n").each do |l|
52 if l.match(/^symbolic names:/)
53 insymbols = true
54 elsif insymbols && (m = l.match(/^\t(.+): ([\d\.]+)$/))
55 @symbols[m[1].encode("UTF-8")] = m[2].encode("UTF-8")
56 else
57 insymbols = false
58 end
59 end
60
61 blocks.each do |block|
62 rev = RCSRevision.new(self, block)
63 if @revisions[rev.version]
64 raise "duplicate revision #{rev.version} in #{file}"
65 end
66 @revisions[rev.version] = rev
67 end
68
69 @first_undead_version = @revisions.values.
70 # this has nothing to do with Gem, but it has a version comparator
71 sort{|a,b| Gem::Version.new(a.version) <=> Gem::Version.new(b.version) }.
72 select{|r| r.state != "dead" }.first.version
73 end
74
75 def to_s
76 "RCSFile: #{@file}"
77 end
78end