18d885e4fSRyan Ernst# Licensed to the Apache Software Foundation (ASF) under one or more 28d885e4fSRyan Ernst# contributor license agreements. See the NOTICE file distributed with 38d885e4fSRyan Ernst# this work for additional information regarding copyright ownership. 48d885e4fSRyan Ernst# The ASF licenses this file to You under the Apache License, Version 2.0 58d885e4fSRyan Ernst# (the "License"); you may not use this file except in compliance with 68d885e4fSRyan Ernst# the License. You may obtain a copy of the License at 78d885e4fSRyan Ernst# 88d885e4fSRyan Ernst# http://www.apache.org/licenses/LICENSE-2.0 98d885e4fSRyan Ernst# 108d885e4fSRyan Ernst# Unless required by applicable law or agreed to in writing, software 118d885e4fSRyan Ernst# distributed under the License is distributed on an "AS IS" BASIS, 128d885e4fSRyan Ernst# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138d885e4fSRyan Ernst# See the License for the specific language governing permissions and 148d885e4fSRyan Ernst# limitations under the License. 158d885e4fSRyan Ernst 168d885e4fSRyan Ernstimport argparse 178d885e4fSRyan Ernstimport re 188d885e4fSRyan Ernstimport subprocess 198d885e4fSRyan Ernstimport sys 2044287d42SJan Høydahlimport os 2110c77578SJan Høydahlfrom enum import Enum 2244287d42SJan Høydahlimport time 2344287d42SJan Høydahlimport urllib.request, urllib.error, urllib.parse 2444287d42SJan Høydahlimport urllib.parse 258d885e4fSRyan Ernst 268d885e4fSRyan Ernstclass Version(object): 278d885e4fSRyan Ernst def __init__(self, major, minor, bugfix, prerelease): 288d885e4fSRyan Ernst self.major = major 298d885e4fSRyan Ernst self.minor = minor 308d885e4fSRyan Ernst self.bugfix = bugfix 318d885e4fSRyan Ernst self.prerelease = prerelease 328d885e4fSRyan Ernst self.previous_dot_matcher = self.make_previous_matcher() 338d885e4fSRyan Ernst self.dot = '%d.%d.%d' % (self.major, self.minor, self.bugfix) 348d885e4fSRyan Ernst self.constant = 'LUCENE_%d_%d_%d' % (self.major, self.minor, self.bugfix) 358d885e4fSRyan Ernst 368d885e4fSRyan Ernst @classmethod 378d885e4fSRyan Ernst def parse(cls, value): 388d885e4fSRyan Ernst match = re.search(r'(\d+)\.(\d+).(\d+)(.1|.2)?', value) 398d885e4fSRyan Ernst if match is None: 408d885e4fSRyan Ernst raise argparse.ArgumentTypeError('Version argument must be of format x.y.z(.1|.2)?') 418d885e4fSRyan Ernst parts = [int(v) for v in match.groups()[:-1]] 428d885e4fSRyan Ernst parts.append({ None: 0, '.1': 1, '.2': 2 }[match.groups()[-1]]) 438d885e4fSRyan Ernst return Version(*parts) 448d885e4fSRyan Ernst 458d885e4fSRyan Ernst def __str__(self): 468d885e4fSRyan Ernst return self.dot 478d885e4fSRyan Ernst 488d885e4fSRyan Ernst def make_previous_matcher(self, prefix='', suffix='', sep='\\.'): 498d885e4fSRyan Ernst if self.is_bugfix_release(): 508d885e4fSRyan Ernst pattern = '%s%s%s%s%d' % (self.major, sep, self.minor, sep, self.bugfix - 1) 518d885e4fSRyan Ernst elif self.is_minor_release(): 528d885e4fSRyan Ernst pattern = '%s%s%d%s\\d+' % (self.major, sep, self.minor - 1, sep) 538d885e4fSRyan Ernst else: 548d885e4fSRyan Ernst pattern = '%d%s\\d+%s\\d+' % (self.major - 1, sep, sep) 558d885e4fSRyan Ernst 568d885e4fSRyan Ernst return re.compile(prefix + '(' + pattern + ')' + suffix) 578d885e4fSRyan Ernst 588d885e4fSRyan Ernst def is_bugfix_release(self): 598d885e4fSRyan Ernst return self.bugfix != 0 608d885e4fSRyan Ernst 618d885e4fSRyan Ernst def is_minor_release(self): 628d885e4fSRyan Ernst return self.bugfix == 0 and self.minor != 0 638d885e4fSRyan Ernst 648d885e4fSRyan Ernst def is_major_release(self): 658d885e4fSRyan Ernst return self.bugfix == 0 and self.minor == 0 668d885e4fSRyan Ernst 678d885e4fSRyan Ernst def on_or_after(self, other): 688d885e4fSRyan Ernst return (self.major > other.major or self.major == other.major and 698d885e4fSRyan Ernst (self.minor > other.minor or self.minor == other.minor and 708d885e4fSRyan Ernst (self.bugfix > other.bugfix or self.bugfix == other.bugfix and 718d885e4fSRyan Ernst self.prerelease >= other.prerelease))) 728d885e4fSRyan Ernst 7344287d42SJan Høydahl def gt(self, other): 7444287d42SJan Høydahl return (self.major > other.major or 7544287d42SJan Høydahl (self.major == other.major and self.minor > other.minor) or 7644287d42SJan Høydahl (self.major == other.major and self.minor == other.minor and self.bugfix > other.bugfix)) 7744287d42SJan Høydahl 780018003bSSteve Rowe def is_back_compat_with(self, other): 790018003bSSteve Rowe if not self.on_or_after(other): 800018003bSSteve Rowe raise Exception('Back compat check disallowed for newer version: %s < %s' % (self, other)) 810018003bSSteve Rowe return other.major + 1 >= self.major 820018003bSSteve Rowe 8344287d42SJan Høydahldef run(cmd, cwd=None): 848d885e4fSRyan Ernst try: 8544287d42SJan Høydahl output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, cwd=cwd) 868d885e4fSRyan Ernst except subprocess.CalledProcessError as e: 878d885e4fSRyan Ernst print(e.output.decode('utf-8')) 888d885e4fSRyan Ernst raise e 898d885e4fSRyan Ernst return output.decode('utf-8') 908d885e4fSRyan Ernst 918d885e4fSRyan Ernstdef update_file(filename, line_re, edit): 928d885e4fSRyan Ernst infile = open(filename, 'r') 938d885e4fSRyan Ernst buffer = [] 948d885e4fSRyan Ernst 958d885e4fSRyan Ernst changed = False 968d885e4fSRyan Ernst for line in infile: 978d885e4fSRyan Ernst if not changed: 988d885e4fSRyan Ernst match = line_re.search(line) 998d885e4fSRyan Ernst if match: 1008d885e4fSRyan Ernst changed = edit(buffer, match, line) 1018d885e4fSRyan Ernst if changed is None: 1028d885e4fSRyan Ernst return False 1038d885e4fSRyan Ernst continue 1048d885e4fSRyan Ernst buffer.append(line) 1058d885e4fSRyan Ernst if not changed: 1068d885e4fSRyan Ernst raise Exception('Could not find %s in %s' % (line_re, filename)) 1078d885e4fSRyan Ernst with open(filename, 'w') as f: 1088d885e4fSRyan Ernst f.write(''.join(buffer)) 1098d885e4fSRyan Ernst return True 1108d885e4fSRyan Ernst 11144287d42SJan Høydahl 112a9cc7b63SSteve Rowe# branch types are "release", "stable" and "unstable" 11310c77578SJan Høydahlclass BranchType(Enum): 114a9cc7b63SSteve Rowe unstable = 1 11510c77578SJan Høydahl stable = 2 11610c77578SJan Høydahl release = 3 11710c77578SJan Høydahl 1188d885e4fSRyan Ernstdef find_branch_type(): 11970e61fd9SMike McCandless output = subprocess.check_output('git status', shell=True) 1208d885e4fSRyan Ernst for line in output.split(b'\n'): 12170e61fd9SMike McCandless if line.startswith(b'On branch '): 12270e61fd9SMike McCandless branchName = line.split(b' ')[-1] 1238d885e4fSRyan Ernst break 1248d885e4fSRyan Ernst else: 12570e61fd9SMike McCandless raise Exception('git status missing branch name') 1268d885e4fSRyan Ernst 127*57524c6aSChristine Poerschke if branchName == b'main': 128a9cc7b63SSteve Rowe return BranchType.unstable 1296e446c0bSJan Høydahl if re.match(r'branch_(\d+)x', branchName.decode('UTF-8')): 13010c77578SJan Høydahl return BranchType.stable 1316e446c0bSJan Høydahl if re.match(r'branch_(\d+)_(\d+)', branchName.decode('UTF-8')): 13210c77578SJan Høydahl return BranchType.release 1331ec6a886SSteve Rowe raise Exception('Cannot run %s on feature branch' % sys.argv[0].rsplit('/', 1)[-1]) 1348d885e4fSRyan Ernst 13544287d42SJan Høydahl 13644287d42SJan Høydahldef download(name, urlString, tmpDir, quiet=False, force_clean=True): 13744287d42SJan Høydahl if not quiet: 13844287d42SJan Høydahl print("Downloading %s" % urlString) 13944287d42SJan Høydahl startTime = time.time() 14044287d42SJan Høydahl fileName = '%s/%s' % (tmpDir, name) 14144287d42SJan Høydahl if not force_clean and os.path.exists(fileName): 14244287d42SJan Høydahl if not quiet and fileName.find('.asc') == -1: 14344287d42SJan Høydahl print(' already done: %.1f MB' % (os.path.getsize(fileName)/1024./1024.)) 14444287d42SJan Høydahl return 14544287d42SJan Høydahl try: 14644287d42SJan Høydahl attemptDownload(urlString, fileName) 14744287d42SJan Høydahl except Exception as e: 14844287d42SJan Høydahl print('Retrying download of url %s after exception: %s' % (urlString, e)) 14944287d42SJan Høydahl try: 15044287d42SJan Høydahl attemptDownload(urlString, fileName) 15144287d42SJan Høydahl except Exception as e: 15244287d42SJan Høydahl raise RuntimeError('failed to download url "%s"' % urlString) from e 15344287d42SJan Høydahl if not quiet and fileName.find('.asc') == -1: 15444287d42SJan Høydahl t = time.time()-startTime 15544287d42SJan Høydahl sizeMB = os.path.getsize(fileName)/1024./1024. 15644287d42SJan Høydahl print(' %.1f MB in %.2f sec (%.1f MB/sec)' % (sizeMB, t, sizeMB/t)) 15744287d42SJan Høydahl 15844287d42SJan Høydahl 15944287d42SJan Høydahldef attemptDownload(urlString, fileName): 16044287d42SJan Høydahl fIn = urllib.request.urlopen(urlString) 16144287d42SJan Høydahl fOut = open(fileName, 'wb') 16244287d42SJan Høydahl success = False 16344287d42SJan Høydahl try: 16444287d42SJan Høydahl while True: 16544287d42SJan Høydahl s = fIn.read(65536) 16644287d42SJan Høydahl if s == b'': 16744287d42SJan Høydahl break 16844287d42SJan Høydahl fOut.write(s) 16944287d42SJan Høydahl fOut.close() 17044287d42SJan Høydahl fIn.close() 17144287d42SJan Høydahl success = True 17244287d42SJan Høydahl finally: 17344287d42SJan Høydahl fIn.close() 17444287d42SJan Høydahl fOut.close() 17544287d42SJan Høydahl if not success: 17644287d42SJan Høydahl os.remove(fileName) 17744287d42SJan Høydahl 17808e38d34SMike Drobversion_prop_re = re.compile(r'baseVersion\s*=\s*([\'"])(.*)\1') 1798d885e4fSRyan Ernstdef find_current_version(): 18008e38d34SMike Drob script_path = os.path.dirname(os.path.realpath(__file__)) 18108e38d34SMike Drob top_level_dir = os.path.join(os.path.abspath("%s/" % script_path), os.path.pardir, os.path.pardir) 18208e38d34SMike Drob return version_prop_re.search(open('%s/build.gradle' % top_level_dir).read()).group(2).strip() 1838d885e4fSRyan Ernst 1848d885e4fSRyan Ernstif __name__ == '__main__': 1858d885e4fSRyan Ernst print('This is only a support module, it cannot be run') 1868d885e4fSRyan Ernst sys.exit(1) 187