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
28require "date"
29
30class RCSRevision
31 attr_accessor :rcsfile, :version, :date, :author, :state, :lines, :commitid,
32 :log, :branch, :vendor_branches
33
34 def self.previous_of(ver)
35 nums = ver.split(".").map{|z| z.to_i }
36
37 if nums.last == 1
38 # 1.3.2.1 -> 1.3
39 2.times { nums.pop }
40 else
41 # 1.3.2.2 -> 1.3.2.1
42 nums[nums.count - 1] -= 1
43 end
44
45 outnum = nums.join(".")
46 if outnum == ""
47 return "0"
48 else
49 return outnum
50 end
51 end
52
53 # 1.1.0.2 -> 1.1.2.1
54 def self.first_branch_version_of(ver)
55 nums = ver.split(".").map{|z| z.to_i }
56
57 if nums[nums.length - 2] != 0
58 return ver
59 end
60
61 last = nums.pop
62 nums.pop
63 nums.push last
64 nums.push 1
65
66 return nums.join(".")
67 end
68
69 def self.is_vendor_branch?(ver)
70 !!ver.match(/^1\.1\.1\..*/)
71 end
72
73 def self.is_trunk?(ver)
74 ver.split(".").count == 2
75 end
76
77 # str: "revision 1.7\ndate: 1996/12/14 12:17:33; author: mickey; state: Exp; lines: +3 -3;\n-Wall'ing."
78 def initialize(rcsfile, str)
79 @rcsfile = rcsfile
80 @version = nil
81 @date = 0
82 @author = nil
83 @state = nil
84 @lines = nil
85 @commitid = nil
86 @log = nil
87 @branch = nil
88 @vendor_branches = []
89
90 lines = str.gsub(/^\s*/, "").split("\n")
91 # -> [
92 # "revision 1.7",
93 # "date: 1996/12/14 12:17:33; author: mickey; state: Exp; lines: +3 -3;",
94 # "-Wall'ing."
95 # ]
96
97 # strip out possible branches line in log
98 if lines[2].to_s.match(/^branches:\s+([\d\.]+)/)
99 lines.delete_at(2)
100 end
101
102 @version = lines.first.scan(/^revision ([\d\.]+)($|\tlocked by)/).first.
103 first.encode("UTF-8")
104 # -> "1.7"
105
106 # date/author/state/lines/commitid line
107 lines[1].split(/;[ \t]*/).each do |piece|
108 kv = piece.split(": ")
109 self.send(kv[0] + "=", kv[1].encode("UTF-8"))
110 end
111 # -> @date = "1996/12/14 12:17:33", @author = "mickey", ...
112
113 if m = @date.match(/^\d\d\d\d\/\d\d\/\d\d \d\d:\d\d:\d\d$/)
114 @date = DateTime.parse(@date).strftime("%s").to_i
115 else
116 raise "invalid date #{@date}"
117 end
118 # -> @date = 850565853
119
120 @log = lines[2, lines.count].join("\n").encode("UTF-8",
121 :invalid => :replace, :undef => :replace, :replace => "?")
122
123 if @version.match(/^\d+\.\d+$/)
124 # no branch
125 elsif @version.match(/^1\.1\.1\./) ||
126 (@version == "1.1.2.1" && @branch == nil)
127 # vendor
128 @rcsfile.symbols.each do |k,v|
129 if v == "1.1.1"
130 @vendor_branches.push k
131 end
132 end
133 elsif m = @version.match(/^(\d+)\.(\d+)\.(\d+)\.\d+$/)
134 # 1.2.2.3 -> 1.2.0.2
135 sym = [ m[1], m[2], "0", m[3] ].join(".")
136 @rcsfile.symbols.each do |s,v|
137 if v == sym
138 if @branch
139 raise "version #{@version} matched two symbols (#{@branch}, #{s})"
140 end
141
142 @branch = s
143 end
144 end
145
146 if !@branch && @rcsfile.symbols.values.include?(@version)
147 # if there's an exact match, this was probably just an import done with
148 # a vendor branch id (import -b)
149 elsif !@branch
150 # branch was deleted, but we don't want this appearing on HEAD, so call
151 # it something
152 @branch = "_branchless_#{@version.gsub(".", "_")}"
153 end
154
155 if @branch && @rcsfile.symbols[@branch] &&
156 @rcsfile.symbols[@branch].match(/^1\.1\.0\.\d+$/)
157 # this is also a vendor branch
158 if !@vendor_branches.include?(@branch)
159 @vendor_branches.push @branch
160 end
161 end
162 else
163 raise "TODO: handle version #{@version}"
164 end
165 end
166end