• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2# Usage: ./update_version.py <MAJOR>.<MINOR>.<MICRO> [<RC version>]
3#
4# Example:
5# ./update_version.py 3.7.1 2
6#   => Version will become 3.7.1-rc-2 (beta)
7# ./update_version.py 3.7.1
8#   => Version will become 3.7.1 (stable)
9
10import datetime
11import re
12import sys
13from xml.dom import minidom
14
15if len(sys.argv) < 2 or len(sys.argv) > 3:
16  print """
17[ERROR] Please specify a version.
18
19./update_version.py <MAJOR>.<MINOR>.<MICRO> [<RC version>]
20
21Example:
22./update_version.py 3.7.1 2
23"""
24  exit(1)
25
26NEW_VERSION = sys.argv[1]
27NEW_VERSION_INFO = [int(x) for x in NEW_VERSION.split('.')]
28if len(NEW_VERSION_INFO) != 3:
29  print """
30[ERROR] Version must be in the format <MAJOR>.<MINOR>.<MICRO>
31
32Example:
33./update_version.py 3.7.3
34"""
35  exit(1)
36
37RC_VERSION = -1
38if len(sys.argv) > 2:
39  RC_VERSION = int(sys.argv[2])
40
41
42def Find(elem, tagname):
43  for child in elem.childNodes:
44    if child.nodeName == tagname:
45      return child
46  return None
47
48
49def FindAndClone(elem, tagname):
50  return Find(elem, tagname).cloneNode(True)
51
52
53def ReplaceText(elem, text):
54  elem.firstChild.replaceWholeText(text)
55
56
57def GetFullVersion(rc_suffix = '-rc-'):
58  if RC_VERSION < 0:
59    return NEW_VERSION
60  else:
61    return '%s%s%s' % (NEW_VERSION, rc_suffix, RC_VERSION)
62
63
64def RewriteXml(filename, rewriter, add_xml_prefix=True):
65  document = minidom.parse(filename)
66  rewriter(document)
67  # document.toxml() always prepend the XML version without inserting new line.
68  # We wants to preserve as much of the original formatting as possible, so we
69  # will remove the default XML version and replace it with our custom one when
70  # whever necessary.
71  content = document.toxml().replace('<?xml version="1.0" ?>', '')
72  file_handle = open(filename, 'wb')
73  if add_xml_prefix:
74    file_handle.write('<?xml version="1.0" encoding="UTF-8"?>\n')
75  file_handle.write(content)
76  file_handle.write('\n')
77  file_handle.close()
78
79
80def RewriteTextFile(filename, line_rewriter):
81  lines = open(filename, 'r').readlines()
82  updated_lines = []
83  for line in lines:
84    updated_lines.append(line_rewriter(line))
85  if lines == updated_lines:
86    print '%s was not updated. Please double check.' % filename
87  f = open(filename, 'w')
88  f.write(''.join(updated_lines))
89  f.close()
90
91
92def UpdateConfigure():
93  RewriteTextFile('configure.ac',
94    lambda line : re.sub(
95      r'^AC_INIT\(\[Protocol Buffers\],\[.*\],\[protobuf@googlegroups.com\],\[protobuf\]\)$',
96      ('AC_INIT([Protocol Buffers],[%s],[protobuf@googlegroups.com],[protobuf])'
97        % GetFullVersion()),
98      line))
99
100
101def UpdateCpp():
102  cpp_version = '%d%03d%03d' % (
103    NEW_VERSION_INFO[0], NEW_VERSION_INFO[1], NEW_VERSION_INFO[2])
104  def RewriteCommon(line):
105    line = re.sub(
106      r'^#define GOOGLE_PROTOBUF_VERSION .*$',
107      '#define GOOGLE_PROTOBUF_VERSION %s' % cpp_version,
108      line)
109    line = re.sub(
110      r'^#define PROTOBUF_VERSION .*$',
111      '#define PROTOBUF_VERSION %s' % cpp_version,
112      line)
113    if NEW_VERSION_INFO[2] == 0:
114      line = re.sub(
115        r'^#define PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC .*$',
116        '#define PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC %s' % cpp_version,
117        line)
118      line = re.sub(
119        r'^#define GOOGLE_PROTOBUF_MIN_PROTOC_VERSION .*$',
120        '#define GOOGLE_PROTOBUF_MIN_PROTOC_VERSION %s' % cpp_version,
121        line)
122      line = re.sub(
123        r'^static const int kMinHeaderVersionForLibrary = .*$',
124        'static const int kMinHeaderVersionForLibrary = %s;' % cpp_version,
125        line)
126      line = re.sub(
127        r'^static const int kMinHeaderVersionForProtoc = .*$',
128        'static const int kMinHeaderVersionForProtoc = %s;' % cpp_version,
129        line)
130    return line
131
132  def RewritePortDef(line):
133    line = re.sub(
134      r'^#define PROTOBUF_VERSION .*$',
135      '#define PROTOBUF_VERSION %s' % cpp_version,
136      line)
137    if NEW_VERSION_INFO[2] == 0:
138      line = re.sub(
139        r'^#define PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC .*$',
140        '#define PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC %s' % cpp_version,
141        line)
142      line = re.sub(
143        r'^#define PROTOBUF_MIN_PROTOC_VERSION .*$',
144        '#define PROTOBUF_MIN_PROTOC_VERSION %s' % cpp_version,
145        line)
146      line = re.sub(
147        r'^#define GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION .*$',
148        '#define GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION %s' % cpp_version,
149        line)
150    return line
151
152  def RewritePbH(line):
153    line = re.sub(
154        r'^#if PROTOBUF_VERSION < .*$',
155        '#if PROTOBUF_VERSION < %s' % cpp_version,
156        line)
157    line = re.sub(
158        r'^#if .* < PROTOBUF_MIN_PROTOC_VERSION$',
159        '#if %s < PROTOBUF_MIN_PROTOC_VERSION' % cpp_version,
160        line)
161    return line
162
163  RewriteTextFile('src/google/protobuf/stubs/common.h', RewriteCommon)
164  RewriteTextFile('src/google/protobuf/port_def.inc', RewritePortDef)
165  RewriteTextFile('src/google/protobuf/any.pb.h', RewritePbH)
166  RewriteTextFile('src/google/protobuf/api.pb.h', RewritePbH)
167  RewriteTextFile('src/google/protobuf/descriptor.pb.h', RewritePbH)
168  RewriteTextFile('src/google/protobuf/duration.pb.h', RewritePbH)
169  RewriteTextFile('src/google/protobuf/empty.pb.h', RewritePbH)
170  RewriteTextFile('src/google/protobuf/field_mask.pb.h', RewritePbH)
171  RewriteTextFile('src/google/protobuf/source_context.pb.h', RewritePbH)
172  RewriteTextFile('src/google/protobuf/struct.pb.h', RewritePbH)
173  RewriteTextFile('src/google/protobuf/timestamp.pb.h', RewritePbH)
174  RewriteTextFile('src/google/protobuf/type.pb.h', RewritePbH)
175  RewriteTextFile('src/google/protobuf/wrappers.pb.h', RewritePbH)
176  RewriteTextFile('src/google/protobuf/compiler/plugin.pb.h', RewritePbH)
177
178
179def UpdateCsharp():
180  RewriteXml('csharp/src/Google.Protobuf/Google.Protobuf.csproj',
181    lambda document : ReplaceText(
182      Find(Find(document.documentElement, 'PropertyGroup'), 'VersionPrefix'),
183      GetFullVersion(rc_suffix = '-rc')),
184    add_xml_prefix=False)
185
186  RewriteXml('csharp/Google.Protobuf.Tools.nuspec',
187    lambda document : ReplaceText(
188      Find(Find(document.documentElement, 'metadata'), 'version'),
189      GetFullVersion(rc_suffix = '-rc')))
190
191
192def UpdateJava():
193  RewriteXml('java/pom.xml',
194    lambda document : ReplaceText(
195      Find(document.documentElement, 'version'), GetFullVersion()))
196
197  RewriteXml('java/bom/pom.xml',
198    lambda document : ReplaceText(
199      Find(document.documentElement, 'version'), GetFullVersion()))
200
201  RewriteXml('java/core/pom.xml',
202    lambda document : ReplaceText(
203      Find(Find(document.documentElement, 'parent'), 'version'),
204      GetFullVersion()))
205
206  RewriteXml('java/lite/pom.xml',
207    lambda document : ReplaceText(
208      Find(Find(document.documentElement, 'parent'), 'version'),
209      GetFullVersion()))
210
211  RewriteXml('java/util/pom.xml',
212    lambda document : ReplaceText(
213      Find(Find(document.documentElement, 'parent'), 'version'),
214      GetFullVersion()))
215
216  RewriteXml('protoc-artifacts/pom.xml',
217    lambda document : ReplaceText(
218      Find(document.documentElement, 'version'), GetFullVersion()))
219
220
221def UpdateJavaScript():
222  RewriteTextFile('js/package.json',
223    lambda line : re.sub(
224      r'^  "version": ".*",$',
225      '  "version": "%s",' % GetFullVersion(rc_suffix = '-rc.'),
226      line))
227
228
229def UpdateMakefile():
230  protobuf_version_offset = 11
231  expected_major_version = 3
232  if NEW_VERSION_INFO[0] != expected_major_version:
233    print """[ERROR] Major protobuf version has changed. Please update
234update_version.py to readjust the protobuf_version_offset and
235expected_major_version such that the PROTOBUF_VERSION in src/Makefile.am is
236always increasing.
237    """
238    exit(1)
239
240  protobuf_version_info = '%d:%d:0' % (
241    NEW_VERSION_INFO[1] + protobuf_version_offset, NEW_VERSION_INFO[2])
242  RewriteTextFile('src/Makefile.am',
243    lambda line : re.sub(
244      r'^PROTOBUF_VERSION = .*$',
245      'PROTOBUF_VERSION = %s' % protobuf_version_info,
246      line))
247
248
249def UpdateObjectiveC():
250  RewriteTextFile('Protobuf.podspec',
251    lambda line : re.sub(
252      r"^  s.version  = '.*'$",
253      "  s.version  = '%s'" % GetFullVersion(rc_suffix = '-rc'),
254      line))
255  RewriteTextFile('Protobuf-C++.podspec',
256    lambda line : re.sub(
257      r"^  s.version  = '.*'$",
258      "  s.version  = '%s'" % GetFullVersion(rc_suffix = '-rc'),
259      line))
260
261
262def UpdatePhp():
263  def Callback(document):
264    def CreateNode(tagname, indent, children):
265      elem = document.createElement(tagname)
266      indent += 1
267      for child in children:
268        elem.appendChild(document.createTextNode('\n' + (' ' * indent)))
269        elem.appendChild(child)
270      indent -= 1
271      elem.appendChild(document.createTextNode('\n' + (' ' * indent)))
272      return elem
273
274    root = document.documentElement
275    now = datetime.datetime.now()
276    ReplaceText(Find(root, 'date'), now.strftime('%Y-%m-%d'))
277    ReplaceText(Find(root, 'time'), now.strftime('%H:%M:%S'))
278    version = Find(root, 'version')
279    ReplaceText(Find(version, 'release'), GetFullVersion(rc_suffix = 'RC'))
280    ReplaceText(Find(version, 'api'), NEW_VERSION)
281    stability = Find(root, 'stability')
282    ReplaceText(Find(stability, 'release'),
283        'stable' if RC_VERSION < 0 else 'beta')
284    ReplaceText(Find(stability, 'api'), 'stable' if RC_VERSION < 0 else 'beta')
285    changelog = Find(root, 'changelog')
286    for old_version in changelog.getElementsByTagName('version'):
287      if Find(old_version, 'release').firstChild.nodeValue == NEW_VERSION:
288        print ('[WARNING] Version %s already exists in the change log.'
289          % NEW_VERSION)
290        return
291    if RC_VERSION != 0:
292      changelog.appendChild(document.createTextNode(' '))
293      release = CreateNode('release', 2, [
294          CreateNode('version', 3, [
295            FindAndClone(version, 'release'),
296            FindAndClone(version, 'api')
297          ]),
298          CreateNode('stability', 3, [
299            FindAndClone(stability, 'release'),
300            FindAndClone(stability, 'api')
301          ]),
302          FindAndClone(root, 'date'),
303          FindAndClone(root, 'time'),
304          FindAndClone(root, 'license'),
305          FindAndClone(root, 'notes')
306        ])
307      changelog.appendChild(release)
308      changelog.appendChild(document.createTextNode('\n '))
309  RewriteXml('php/ext/google/protobuf/package.xml', Callback)
310  RewriteTextFile('php/ext/google/protobuf/protobuf.h',
311    lambda line : re.sub(
312      r'PHP_PROTOBUF_VERSION ".*"$',
313      'PHP_PROTOBUF_VERSION "%s"' % NEW_VERSION,
314      line))
315
316  RewriteTextFile('php/ext/google/protobuf/protobuf.h',
317    lambda line : re.sub(
318      r"^#define PHP_PROTOBUF_VERSION .*$",
319      "#define PHP_PROTOBUF_VERSION \"%s\"" % GetFullVersion(rc_suffix = 'RC'),
320      line))
321
322  RewriteTextFile('php/ext/google/protobuf/protobuf.h',
323    lambda line : re.sub(
324      r"^#define PHP_PROTOBUF_VERSION .*$",
325      "#define PHP_PROTOBUF_VERSION \"%s\"" % GetFullVersion(rc_suffix = 'RC'),
326      line))
327
328def UpdatePython():
329  RewriteTextFile('python/google/protobuf/__init__.py',
330    lambda line : re.sub(
331      r"^__version__ = '.*'$",
332      "__version__ = '%s'" % GetFullVersion(rc_suffix = 'rc'),
333      line))
334
335def UpdateRuby():
336  RewriteTextFile('ruby/google-protobuf.gemspec',
337    lambda line : re.sub(
338      r'^  s.version     = ".*"$',
339      '  s.version     = "%s"' % GetFullVersion(rc_suffix = '.rc.'),
340      line))
341
342
343UpdateConfigure()
344UpdateCsharp()
345UpdateCpp()
346UpdateJava()
347UpdateJavaScript()
348UpdateMakefile()
349UpdateObjectiveC()
350UpdatePhp()
351UpdatePython()
352UpdateRuby()
353