1# ##### BEGIN GPL LICENSE BLOCK ##### 2# 3# This program is free software; you can redistribute it and/or 4# modify it under the terms of the GNU General Public License 5# as published by the Free Software Foundation; either version 2 6# of the License, or (at your option) any later version. 7# 8# This program is distributed in the hope that it will be useful, 9# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# GNU General Public License for more details. 12# 13# You should have received a copy of the GNU General Public License 14# along with this program; if not, write to the Free Software Foundation, 15# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16# 17# ##### END GPL LICENSE BLOCK ##### 18 19# <pep8 compliant> 20 21import argparse 22import os 23import re 24import subprocess 25import sys 26 27 28def is_tool(name): 29 """Check whether `name` is on PATH and marked as executable.""" 30 31 # from whichcraft import which 32 from shutil import which 33 34 return which(name) is not None 35 36 37class Builder: 38 def __init__(self, name, branch, codesign): 39 self.name = name 40 self.branch = branch 41 self.is_release_branch = re.match("^blender-v(.*)-release$", branch) is not None 42 self.codesign = codesign 43 44 # Buildbot runs from build/ directory 45 self.blender_dir = os.path.abspath(os.path.join('..', 'blender.git')) 46 self.build_dir = os.path.abspath(os.path.join('..', 'build')) 47 self.install_dir = os.path.abspath(os.path.join('..', 'install')) 48 self.upload_dir = os.path.abspath(os.path.join('..', 'install')) 49 50 # Detect platform 51 if name.startswith('mac'): 52 self.platform = 'mac' 53 self.command_prefix = [] 54 elif name.startswith('linux'): 55 self.platform = 'linux' 56 if is_tool('scl'): 57 self.command_prefix = ['scl', 'enable', 'devtoolset-9', '--'] 58 else: 59 self.command_prefix = [] 60 elif name.startswith('win'): 61 self.platform = 'win' 62 self.command_prefix = [] 63 else: 64 raise ValueError('Unkonw platform for builder ' + self.platform) 65 66 # Always 64 bit now 67 self.bits = 64 68 69 70def create_builder_from_arguments(): 71 parser = argparse.ArgumentParser() 72 parser.add_argument('builder_name') 73 parser.add_argument('branch', default='master', nargs='?') 74 parser.add_argument("--codesign", action="store_true") 75 args = parser.parse_args() 76 return Builder(args.builder_name, args.branch, args.codesign) 77 78 79class VersionInfo: 80 def __init__(self, builder): 81 # Get version information 82 buildinfo_h = os.path.join(builder.build_dir, "source", "creator", "buildinfo.h") 83 blender_h = os.path.join(builder.blender_dir, "source", "blender", "blenkernel", "BKE_blender_version.h") 84 85 version_number = int(self._parse_header_file(blender_h, 'BLENDER_VERSION')) 86 version_number_patch = int(self._parse_header_file(blender_h, 'BLENDER_VERSION_PATCH')) 87 version_numbers = (version_number // 100, version_number % 100, version_number_patch) 88 self.short_version = "%d.%02d" % (version_numbers[0], version_numbers[1]) 89 self.version = "%d.%02d.%d" % version_numbers 90 self.version_cycle = self._parse_header_file(blender_h, 'BLENDER_VERSION_CYCLE') 91 self.version_cycle_number = self._parse_header_file(blender_h, 'BLENDER_VERSION_CYCLE_NUMBER') 92 self.hash = self._parse_header_file(buildinfo_h, 'BUILD_HASH')[1:-1] 93 94 if self.version_cycle == "release": 95 # Final release 96 self.full_version = self.version 97 self.is_development_build = False 98 elif self.version_cycle == "rc": 99 # Release candidate 100 version_cycle = self.version_cycle + self.version_cycle_number 101 self.full_version = self.version + version_cycle 102 self.is_development_build = False 103 else: 104 # Development build 105 self.full_version = self.version + '-' + self.hash 106 self.is_development_build = True 107 108 def _parse_header_file(self, filename, define): 109 import re 110 regex = re.compile(r"^#\s*define\s+%s\s+(.*)" % define) 111 with open(filename, "r") as file: 112 for l in file: 113 match = regex.match(l) 114 if match: 115 return match.group(1) 116 return None 117 118 119def call(cmd, env=None, exit_on_error=True): 120 print(' '.join(cmd)) 121 122 # Flush to ensure correct order output on Windows. 123 sys.stdout.flush() 124 sys.stderr.flush() 125 126 retcode = subprocess.call(cmd, env=env) 127 if exit_on_error and retcode != 0: 128 sys.exit(retcode) 129 return retcode 130