Hao Nguyen | 9349e23 | 2018-12-14 15:05:48 -0800 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | |
| 3 | import datetime |
| 4 | import re |
| 5 | import sys |
| 6 | from xml.dom import minidom |
| 7 | |
| 8 | if len(sys.argv) < 2: |
| 9 | print """ |
| 10 | [ERROR] Please specify a version. |
| 11 | |
| 12 | Example: |
| 13 | ./update_version.py 2.1.3 |
| 14 | """ |
| 15 | exit(1) |
| 16 | |
| 17 | NEW_VERSION = sys.argv[1] |
| 18 | NEW_VERSION_INFO = NEW_VERSION.split('.') |
| 19 | if len(NEW_VERSION_INFO) != 3: |
| 20 | print """ |
| 21 | [ERROR] Version must be in the format <MAJOR>.<MINOR>.<MICRO> |
| 22 | |
| 23 | Example: |
| 24 | ./update_version.py 2.1.3 |
| 25 | """ |
| 26 | exit(1) |
| 27 | |
| 28 | |
| 29 | def Find(elem, tagname): |
| 30 | for child in elem.childNodes: |
| 31 | if child.nodeName == tagname: |
| 32 | return child |
| 33 | return None |
| 34 | |
| 35 | |
| 36 | def FindAndClone(elem, tagname): |
| 37 | return Find(elem, tagname).cloneNode(True) |
| 38 | |
| 39 | |
| 40 | def ReplaceText(elem, text): |
| 41 | elem.firstChild.replaceWholeText(text) |
| 42 | |
| 43 | |
| 44 | def RewriteXml(filename, rewriter, add_xml_prefix=True): |
| 45 | document = minidom.parse(filename) |
| 46 | rewriter(document) |
| 47 | # document.toxml() always prepend the XML version without inserting new line. |
| 48 | # We wants to preserve as much of the original formatting as possible, so we |
| 49 | # will remove the default XML version and replace it with our custom one when |
| 50 | # whever necessary. |
| 51 | content = document.toxml().replace('<?xml version="1.0" ?>', '') |
| 52 | file_handle = open(filename, 'wb') |
| 53 | if add_xml_prefix: |
| 54 | file_handle.write('<?xml version="1.0" encoding="UTF-8"?>\n') |
| 55 | file_handle.write(content) |
Hao Nguyen | 4b02f65 | 2018-12-14 15:10:11 -0800 | [diff] [blame] | 56 | file_handle.write('\n') |
Hao Nguyen | 9349e23 | 2018-12-14 15:05:48 -0800 | [diff] [blame] | 57 | file_handle.close() |
| 58 | |
| 59 | |
| 60 | def RewriteTextFile(filename, line_rewriter): |
| 61 | lines = open(filename, 'r').readlines() |
| 62 | updated_lines = [] |
| 63 | for line in lines: |
| 64 | updated_lines.append(line_rewriter(line)) |
| 65 | if lines == updated_lines: |
| 66 | print '%s was not updated. Please double check.' % filename |
| 67 | f = open(filename, 'w') |
| 68 | f.write(''.join(updated_lines)) |
| 69 | f.close() |
| 70 | |
| 71 | |
| 72 | def UpdateConfigure(): |
| 73 | RewriteTextFile('configure.ac', |
| 74 | lambda line : re.sub( |
| 75 | r'^AC_INIT\(\[Protocol Buffers\],\[.*\],\[protobuf@googlegroups.com\],\[protobuf\]\)$', |
| 76 | ('AC_INIT([Protocol Buffers],[%s],[protobuf@googlegroups.com],[protobuf])' |
| 77 | % NEW_VERSION), |
| 78 | line)) |
| 79 | |
| 80 | |
| 81 | def UpdateCpp(): |
| 82 | cpp_version = '%s00%s00%s' % ( |
| 83 | NEW_VERSION_INFO[0], NEW_VERSION_INFO[1], NEW_VERSION_INFO[2]) |
| 84 | def RewriteCpp(line): |
| 85 | line = re.sub( |
| 86 | r'^#define GOOGLE_PROTOBUF_VERSION .*$', |
| 87 | '#define GOOGLE_PROTOBUF_VERSION %s' % cpp_version, |
| 88 | line) |
| 89 | if NEW_VERSION_INFO[2] == '0': |
| 90 | line = re.sub( |
| 91 | r'^#define GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION .*$', |
| 92 | '#define GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION %s' % cpp_version, |
| 93 | line) |
| 94 | line = re.sub( |
| 95 | r'^#define GOOGLE_PROTOBUF_MIN_PROTOC_VERSION .*$', |
| 96 | '#define GOOGLE_PROTOBUF_MIN_PROTOC_VERSION %s' % cpp_version, |
| 97 | line) |
| 98 | line = re.sub( |
| 99 | r'^static const int kMinHeaderVersionForLibrary = .*$', |
| 100 | 'static const int kMinHeaderVersionForLibrary = %s;' % cpp_version, |
| 101 | line) |
| 102 | line = re.sub( |
| 103 | r'^static const int kMinHeaderVersionForProtoc = .*$', |
| 104 | 'static const int kMinHeaderVersionForProtoc = %s;' % cpp_version, |
| 105 | line) |
| 106 | return line |
| 107 | RewriteTextFile('src/google/protobuf/stubs/common.h', RewriteCpp) |
| 108 | |
| 109 | |
| 110 | def UpdateCsharp(): |
| 111 | RewriteXml('csharp/src/Google.Protobuf/Google.Protobuf.csproj', |
| 112 | lambda document : ReplaceText( |
| 113 | Find(Find(document.documentElement, 'PropertyGroup'), 'VersionPrefix'), |
| 114 | NEW_VERSION), |
| 115 | add_xml_prefix=False) |
| 116 | |
| 117 | RewriteXml('csharp/Google.Protobuf.Tools.nuspec', |
| 118 | lambda document : ReplaceText( |
| 119 | Find(Find(document.documentElement, 'metadata'), 'version'), |
| 120 | NEW_VERSION)) |
| 121 | |
| 122 | |
| 123 | def UpdateJava(): |
| 124 | RewriteXml('java/pom.xml', |
| 125 | lambda document : ReplaceText( |
| 126 | Find(document.documentElement, 'version'), NEW_VERSION)) |
| 127 | |
Paul Yang | c7b3392 | 2019-02-19 15:54:45 -0800 | [diff] [blame^] | 128 | RewriteXml('java/bom/pom.xml', |
| 129 | lambda document : ReplaceText( |
| 130 | Find(document.documentElement, 'version'), NEW_VERSION)) |
| 131 | |
Hao Nguyen | 9349e23 | 2018-12-14 15:05:48 -0800 | [diff] [blame] | 132 | RewriteXml('java/core/pom.xml', |
| 133 | lambda document : ReplaceText( |
| 134 | Find(Find(document.documentElement, 'parent'), 'version'), |
| 135 | NEW_VERSION)) |
| 136 | |
| 137 | RewriteXml('java/util/pom.xml', |
| 138 | lambda document : ReplaceText( |
| 139 | Find(Find(document.documentElement, 'parent'), 'version'), |
| 140 | NEW_VERSION)) |
| 141 | |
| 142 | RewriteXml('protoc-artifacts/pom.xml', |
| 143 | lambda document : ReplaceText( |
| 144 | Find(document.documentElement, 'version'), NEW_VERSION)) |
| 145 | |
| 146 | |
| 147 | def UpdateJavaScript(): |
| 148 | RewriteTextFile('js/package.json', |
| 149 | lambda line : re.sub( |
| 150 | r'^ "version": ".*",$', |
| 151 | ' "version": "%s",' % NEW_VERSION, |
| 152 | line)) |
| 153 | |
| 154 | |
| 155 | def UpdateMakefile(): |
| 156 | protobuf_version_offset = 11 |
| 157 | expected_major_version = '3' |
| 158 | if NEW_VERSION_INFO[0] != expected_major_version: |
| 159 | print """[ERROR] Major protobuf version has changed. Please update |
| 160 | update_version.py to readjust the protobuf_version_offset and |
| 161 | expected_major_version such that the PROTOBUF_VERSION in src/Makefile.am is |
| 162 | always increasing. |
| 163 | """ |
| 164 | exit(1) |
| 165 | |
| 166 | protobuf_version_info = '%s:%s:0' % ( |
| 167 | int(NEW_VERSION_INFO[1]) + protobuf_version_offset, NEW_VERSION_INFO[2]) |
| 168 | RewriteTextFile('src/Makefile.am', |
| 169 | lambda line : re.sub( |
| 170 | r'^PROTOBUF_VERSION = .*$', |
| 171 | 'PROTOBUF_VERSION = %s' % protobuf_version_info, |
| 172 | line)) |
| 173 | |
| 174 | |
| 175 | def UpdateObjectiveC(): |
| 176 | RewriteTextFile('Protobuf.podspec', |
| 177 | lambda line : re.sub( |
| 178 | r"^ s.version = '.*'$", |
| 179 | " s.version = '%s'" % NEW_VERSION, |
| 180 | line)) |
| 181 | |
| 182 | |
| 183 | def UpdatePhp(): |
| 184 | def Callback(document): |
| 185 | def CreateNode(tagname, indent, children): |
| 186 | elem = document.createElement(tagname) |
| 187 | indent += 1 |
| 188 | for child in children: |
| 189 | elem.appendChild(document.createTextNode('\n' + (' ' * indent))) |
| 190 | elem.appendChild(child) |
| 191 | indent -= 1 |
| 192 | elem.appendChild(document.createTextNode('\n' + (' ' * indent))) |
| 193 | return elem |
| 194 | |
| 195 | root = document.documentElement |
| 196 | version = Find(root, 'version') |
| 197 | ReplaceText(Find(version, 'release'), NEW_VERSION) |
| 198 | ReplaceText(Find(version, 'api'), NEW_VERSION) |
| 199 | now = datetime.datetime.now() |
| 200 | ReplaceText(Find(root, 'date'), now.strftime('%Y-%m-%d')) |
| 201 | ReplaceText(Find(root, 'time'), now.strftime('%H:%M:%S')) |
| 202 | changelog = Find(root, 'changelog') |
| 203 | for old_version in changelog.getElementsByTagName('version'): |
| 204 | if Find(old_version, 'release').firstChild.nodeValue == NEW_VERSION: |
| 205 | print ('[WARNING] Version %s already exists in the change log.' |
| 206 | % NEW_VERSION) |
| 207 | return |
| 208 | changelog.appendChild(document.createTextNode(' ')) |
| 209 | stability = Find(root, 'stability') |
| 210 | release = CreateNode('release', 2, [ |
| 211 | CreateNode('version', 3, [ |
| 212 | FindAndClone(version, 'release'), |
| 213 | FindAndClone(version, 'api') |
| 214 | ]), |
| 215 | CreateNode('stability', 3, [ |
| 216 | FindAndClone(stability, 'release'), |
| 217 | FindAndClone(stability, 'api') |
| 218 | ]), |
| 219 | FindAndClone(root, 'date'), |
| 220 | FindAndClone(root, 'time'), |
| 221 | FindAndClone(root, 'license'), |
| 222 | FindAndClone(root, 'notes') |
| 223 | ]) |
| 224 | changelog.appendChild(release) |
| 225 | changelog.appendChild(document.createTextNode('\n ')) |
| 226 | RewriteXml('php/ext/google/protobuf/package.xml', Callback) |
Paul Yang | c7b3392 | 2019-02-19 15:54:45 -0800 | [diff] [blame^] | 227 | RewriteTextFile('php/ext/google/protobuf/protobuf.h', |
| 228 | lambda line : re.sub( |
| 229 | r'PHP_PROTOBUF_VERSION ".*"$', |
| 230 | 'PHP_PROTOBUF_VERSION "%s"' % NEW_VERSION, |
| 231 | line)) |
Hao Nguyen | 9349e23 | 2018-12-14 15:05:48 -0800 | [diff] [blame] | 232 | |
| 233 | def UpdatePython(): |
| 234 | RewriteTextFile('python/google/protobuf/__init__.py', |
| 235 | lambda line : re.sub( |
| 236 | r"^__version__ = '.*'$", |
| 237 | "__version__ = '%s'" % NEW_VERSION, |
| 238 | line)) |
| 239 | |
| 240 | def UpdateRuby(): |
| 241 | RewriteTextFile('ruby/google-protobuf.gemspec', |
| 242 | lambda line : re.sub( |
| 243 | r'^ s.version = ".*"$', |
| 244 | ' s.version = "%s"' % NEW_VERSION, |
| 245 | line)) |
| 246 | |
| 247 | |
| 248 | UpdateConfigure() |
| 249 | UpdateCsharp() |
| 250 | UpdateCpp() |
| 251 | UpdateJava() |
| 252 | UpdateJavaScript() |
| 253 | UpdateMakefile() |
| 254 | UpdateObjectiveC() |
| 255 | UpdatePhp() |
| 256 | UpdatePython() |
| 257 | UpdateRuby() |