| Karl Schultz | 5ff6f74 | 2018-06-21 17:38:56 -0600 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | |
| 3 | # Copyright 2017 The Glslang Authors. All rights reserved. |
| 4 | # Copyright (c) 2018 Valve Corporation |
| 5 | # Copyright (c) 2018 LunarG, Inc. |
| 6 | # |
| 7 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 8 | # you may not use this file except in compliance with the License. |
| 9 | # You may obtain a copy of the License at |
| 10 | # |
| 11 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 12 | # |
| 13 | # Unless required by applicable law or agreed to in writing, software |
| 14 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 16 | # See the License for the specific language governing permissions and |
| 17 | # limitations under the License. |
| 18 | |
| 19 | # This script was heavily leveraged from KhronosGroup/glslang |
| 20 | # update_glslang_sources.py. |
| 21 | """update_deps.py |
| 22 | |
| 23 | Get and build dependent repositories using known-good commits. |
| 24 | |
| 25 | Purpose |
| 26 | ------- |
| 27 | |
| 28 | This program is intended to assist a developer of this repository |
| 29 | (the "home" repository) by gathering and building the repositories that |
| 30 | this home repository depend on. It also checks out each dependent |
| 31 | repository at a "known-good" commit in order to provide stability in |
| 32 | the dependent repositories. |
| 33 | |
| 34 | Python Compatibility |
| 35 | -------------------- |
| 36 | |
| 37 | This program can be used with Python 2.7 and Python 3. |
| 38 | |
| 39 | Known-Good JSON Database |
| 40 | ------------------------ |
| 41 | |
| 42 | This program expects to find a file named "known-good.json" in the |
| 43 | same directory as the program file. This JSON file is tailored for |
| 44 | the needs of the home repository by including its dependent repositories. |
| 45 | |
| 46 | Program Options |
| 47 | --------------- |
| 48 | |
| 49 | See the help text (update_deps.py --help) for a complete list of options. |
| 50 | |
| 51 | Program Operation |
| 52 | ----------------- |
| 53 | |
| 54 | The program uses the user's current directory at the time of program |
| 55 | invocation as the location for fetching and building the dependent |
| 56 | repositories. The user can override this by using the "--dir" option. |
| 57 | |
| 58 | For example, a directory named "build" in the repository's root directory |
| 59 | is a good place to put the dependent repositories because that directory |
| 60 | is not tracked by Git. (See the .gitignore file.) The "external" directory |
| 61 | may also be a suitable location. |
| 62 | A user can issue: |
| 63 | |
| 64 | $ cd My-Repo |
| 65 | $ mkdir build |
| 66 | $ cd build |
| 67 | $ ../scripts/update_deps.py |
| 68 | |
| 69 | or, to do the same thing, but using the --dir option: |
| 70 | |
| 71 | $ cd My-Repo |
| 72 | $ mkdir build |
| 73 | $ scripts/update_deps.py --dir=build |
| 74 | |
| 75 | With these commands, the "build" directory is considered the "top" |
| 76 | directory where the program clones the dependent repositories. The |
| 77 | JSON file configures the build and install working directories to be |
| 78 | within this "top" directory. |
| 79 | |
| 80 | Note that the "dir" option can also specify an absolute path: |
| 81 | |
| 82 | $ cd My-Repo |
| 83 | $ scripts/update_deps.py --dir=/tmp/deps |
| 84 | |
| 85 | The "top" dir is then /tmp/deps (Linux filesystem example) and is |
| 86 | where this program will clone and build the dependent repositories. |
| 87 | |
| 88 | Helper CMake Config File |
| 89 | ------------------------ |
| 90 | |
| 91 | When the program finishes building the dependencies, it writes a file |
| 92 | named "helper.cmake" to the "top" directory that contains CMake commands |
| 93 | for setting CMake variables for locating the dependent repositories. |
| 94 | This helper file can be used to set up the CMake build files for this |
| 95 | "home" repository. |
| 96 | |
| 97 | A complete sequence might look like: |
| 98 | |
| 99 | $ git clone git@github.com:My-Group/My-Repo.git |
| 100 | $ cd My-Repo |
| 101 | $ mkdir build |
| 102 | $ cd build |
| 103 | $ ../scripts/update_deps.py |
| 104 | $ cmake -C helper.cmake .. |
| 105 | $ cmake --build . |
| 106 | |
| 107 | JSON File Schema |
| 108 | ---------------- |
| 109 | |
| 110 | There's no formal schema for the "known-good" JSON file, but here is |
| 111 | a description of its elements. All elements are required except those |
| 112 | marked as optional. Please see the "known_good.json" file for |
| 113 | examples of all of these elements. |
| 114 | |
| 115 | - name |
| 116 | |
| 117 | The name of the dependent repository. This field can be referenced |
| 118 | by the "deps.repo_name" structure to record a dependency. |
| 119 | |
| 120 | - url |
| 121 | |
| 122 | Specifies the URL of the repository. |
| 123 | Example: https://github.com/KhronosGroup/Vulkan-Loader.git |
| 124 | |
| 125 | - sub_dir |
| 126 | |
| 127 | The directory where the program clones the repository, relative to |
| 128 | the "top" directory. |
| 129 | |
| 130 | - build_dir |
| 131 | |
| 132 | The directory used to build the repository, relative to the "top" |
| 133 | directory. |
| 134 | |
| 135 | - install_dir |
| 136 | |
| 137 | The directory used to store the installed build artifacts, relative |
| 138 | to the "top" directory. |
| 139 | |
| 140 | - commit |
| 141 | |
| 142 | The commit used to checkout the repository. This can be a SHA-1 |
| 143 | object name or a refname used with the remote name "origin". |
| 144 | For example, this field can be set to "origin/sdk-1.1.77" to |
| 145 | select the end of the sdk-1.1.77 branch. |
| 146 | |
| 147 | - deps (optional) |
| 148 | |
| 149 | An array of pairs consisting of a CMake variable name and a |
| 150 | repository name to specify a dependent repo and a "link" to |
| 151 | that repo's install artifacts. For example: |
| 152 | |
| 153 | "deps" : [ |
| 154 | { |
| 155 | "var_name" : "VULKAN_HEADERS_INSTALL_DIR", |
| 156 | "repo_name" : "Vulkan-Headers" |
| 157 | } |
| 158 | ] |
| 159 | |
| 160 | which represents that this repository depends on the Vulkan-Headers |
| 161 | repository and uses the VULKAN_HEADERS_INSTALL_DIR CMake variable to |
| 162 | specify the location where it expects to find the Vulkan-Headers install |
| 163 | directory. |
| 164 | Note that the "repo_name" element must match the "name" element of some |
| 165 | other repository in the JSON file. |
| 166 | |
| 167 | - prebuild (optional) |
| 168 | - prebuild_linux (optional) (For Linux and MacOS) |
| 169 | - prebuild_windows (optional) |
| 170 | |
| 171 | A list of commands to execute before building a dependent repository. |
| 172 | This is useful for repositories that require the execution of some |
| 173 | sort of "update" script or need to clone an auxillary repository like |
| 174 | googletest. |
| 175 | |
| 176 | The commands listed in "prebuild" are executed first, and then the |
| 177 | commands for the specific platform are executed. |
| 178 | |
| 179 | - cmake_options (optional) |
| 180 | |
| 181 | A list of options to pass to CMake during the generation phase. |
| 182 | |
| 183 | - ci_only (optional) |
| 184 | |
| 185 | A list of environment variables where one must be set to "true" |
| 186 | (case-insensitive) in order for this repo to be fetched and built. |
| 187 | This list can be used to specify repos that should be built only in CI. |
| 188 | Typically, this list might contain "TRAVIS" and/or "APPVEYOR" because |
| 189 | each of these CI systems sets an environment variable with its own |
| 190 | name to "true". Note that this could also be (ab)used to control |
| 191 | the processing of the repo with any environment variable. The default |
| 192 | is an empty list, which means that the repo is always processed. |
| 193 | |
| 194 | Note |
| 195 | ---- |
| 196 | |
| 197 | The "sub_dir", "build_dir", and "install_dir" elements are all relative |
| 198 | to the effective "top" directory. Specifying absolute paths is not |
| 199 | supported. However, the "top" directory specified with the "--dir" |
| 200 | option can be a relative or absolute path. |
| 201 | |
| 202 | """ |
| 203 | |
| 204 | from __future__ import print_function |
| 205 | |
| 206 | import argparse |
| 207 | import json |
| 208 | import distutils.dir_util |
| 209 | import os.path |
| 210 | import subprocess |
| 211 | import sys |
| 212 | import platform |
| 213 | import multiprocessing |
| 214 | import shutil |
| 215 | |
| Mark Lobodzinski | ac1043c | 2018-07-19 13:20:46 -0600 | [diff] [blame^] | 216 | KNOWN_GOOD_FILE_NAME = 'known_good.json' |
| Karl Schultz | 5ff6f74 | 2018-06-21 17:38:56 -0600 | [diff] [blame] | 217 | |
| 218 | CONFIG_MAP = { |
| 219 | 'debug': 'Debug', |
| 220 | 'release': 'Release', |
| 221 | 'relwithdebinfo': 'RelWithDebInfo', |
| 222 | 'minsizerel': 'MinSizeRel' |
| 223 | } |
| 224 | |
| 225 | VERBOSE = False |
| 226 | |
| 227 | DEVNULL = open(os.devnull, 'wb') |
| 228 | |
| 229 | |
| 230 | def command_output(cmd, directory, fail_ok=False): |
| 231 | """Runs a command in a directory and returns its standard output stream. |
| 232 | |
| 233 | Captures the standard error stream and prints it if error. |
| 234 | |
| 235 | Raises a RuntimeError if the command fails to launch or otherwise fails. |
| 236 | """ |
| 237 | if VERBOSE: |
| 238 | print('In {d}: {cmd}'.format(d=directory, cmd=cmd)) |
| 239 | p = subprocess.Popen( |
| 240 | cmd, cwd=directory, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
| 241 | (stdout, stderr) = p.communicate() |
| 242 | if p.returncode != 0: |
| 243 | print('*** Error ***\nstderr contents:\n{}'.format(stderr)) |
| 244 | if not fail_ok: |
| 245 | raise RuntimeError('Failed to run {} in {}'.format(cmd, directory)) |
| 246 | if VERBOSE: |
| 247 | print(stdout) |
| 248 | return stdout |
| 249 | |
| 250 | |
| 251 | class GoodRepo(object): |
| 252 | """Represents a repository at a known-good commit.""" |
| 253 | |
| 254 | def __init__(self, json, args): |
| 255 | """Initializes this good repo object. |
| 256 | |
| 257 | Args: |
| 258 | 'json': A fully populated JSON object describing the repo. |
| 259 | 'args': Results from ArgumentParser |
| 260 | """ |
| 261 | self._json = json |
| 262 | self._args = args |
| 263 | # Required JSON elements |
| 264 | self.name = json['name'] |
| 265 | self.url = json['url'] |
| 266 | self.sub_dir = json['sub_dir'] |
| 267 | self.build_dir = json['build_dir'] |
| 268 | self.install_dir = json['install_dir'] |
| 269 | self.commit = json['commit'] |
| 270 | # Optional JSON elements |
| 271 | self.deps = json['deps'] if ('deps' in json) else [] |
| 272 | self.prebuild = json['prebuild'] if ('prebuild' in json) else [] |
| 273 | self.prebuild_linux = json['prebuild_linux'] if ( |
| 274 | 'prebuild_linux' in json) else [] |
| 275 | self.prebuild_windows = json['prebuild_windows'] if ( |
| 276 | 'prebuild_windows' in json) else [] |
| 277 | self.cmake_options = json['cmake_options'] if ( |
| 278 | 'cmake_options' in json) else [] |
| 279 | self.ci_only = json['ci_only'] if ('ci_only' in json) else [] |
| 280 | # Absolute paths for a repo's directories |
| 281 | dir_top = os.path.abspath(args.dir) |
| 282 | self.repo_dir = os.path.join(dir_top, self.sub_dir) |
| 283 | self.build_dir = os.path.join(dir_top, self.build_dir) |
| 284 | self.install_dir = os.path.join(dir_top, self.install_dir) |
| 285 | |
| 286 | def Clone(self): |
| 287 | distutils.dir_util.mkpath(self.repo_dir) |
| 288 | command_output(['git', 'clone', self.url, '.'], self.repo_dir) |
| 289 | |
| 290 | def Fetch(self): |
| 291 | command_output(['git', 'fetch', 'origin'], self.repo_dir) |
| 292 | |
| 293 | def Checkout(self): |
| 294 | print('Checking out {n} in {d}'.format(n=self.name, d=self.repo_dir)) |
| 295 | if self._args.do_clean_repo: |
| 296 | shutil.rmtree(self.repo_dir) |
| 297 | if not os.path.exists(os.path.join(self.repo_dir, '.git')): |
| 298 | self.Clone() |
| 299 | self.Fetch() |
| 300 | if len(self._args.ref): |
| 301 | command_output(['git', 'checkout', self._args.ref], self.repo_dir) |
| 302 | else: |
| 303 | command_output(['git', 'checkout', self.commit], self.repo_dir) |
| 304 | print(command_output(['git', 'status'], self.repo_dir)) |
| 305 | |
| 306 | def PreBuild(self): |
| 307 | """Execute any prebuild steps from the repo root""" |
| 308 | for p in self.prebuild: |
| 309 | command_output(p.split(), self.repo_dir) |
| 310 | if platform.system() == 'Linux' or platform.system() == 'Darwin': |
| 311 | for p in self.prebuild_linux: |
| 312 | command_output(p.split(), self.repo_dir) |
| 313 | if platform.system() == 'Windows': |
| 314 | for p in self.prebuild_windows: |
| 315 | command_output(p.split(), self.repo_dir) |
| 316 | |
| 317 | def CMakeConfig(self, repos): |
| 318 | """Build CMake command for the configuration phase and execute it""" |
| 319 | if self._args.do_clean_build: |
| 320 | shutil.rmtree(self.build_dir) |
| 321 | if self._args.do_clean_install: |
| 322 | shutil.rmtree(self.install_dir) |
| 323 | |
| 324 | # Create and change to build directory |
| 325 | distutils.dir_util.mkpath(self.build_dir) |
| 326 | os.chdir(self.build_dir) |
| 327 | |
| 328 | cmake_cmd = [ |
| 329 | 'cmake', self.repo_dir, |
| 330 | '-DCMAKE_INSTALL_PREFIX=' + self.install_dir |
| 331 | ] |
| 332 | |
| 333 | # For each repo this repo depends on, generate a CMake variable |
| 334 | # definitions for "...INSTALL_DIR" that points to that dependent |
| 335 | # repo's install dir. |
| 336 | for d in self.deps: |
| 337 | dep_commit = [r for r in repos if r.name == d['repo_name']] |
| 338 | if len(dep_commit): |
| 339 | cmake_cmd.append('-D{var_name}={install_dir}'.format( |
| 340 | var_name=d['var_name'], |
| 341 | install_dir=dep_commit[0].install_dir)) |
| 342 | |
| 343 | # Add any CMake options |
| 344 | for option in self.cmake_options: |
| 345 | cmake_cmd.append(option) |
| 346 | |
| 347 | # Set build config for single-configuration generators |
| 348 | if platform.system() == 'Linux' or platform.system() == 'Darwin': |
| 349 | cmake_cmd.append('-DCMAKE_BUILD_TYPE={config}'.format( |
| 350 | config=CONFIG_MAP[self._args.config])) |
| 351 | |
| 352 | # Use the CMake -A option to select the platform architecture |
| 353 | # without needing a Visual Studio generator. |
| 354 | if platform.system() == 'Windows': |
| 355 | if self._args.arch == '64' or self._args.arch == 'x64' or self._args.arch == 'win64': |
| 356 | cmake_cmd.append('-A') |
| 357 | cmake_cmd.append('x64') |
| 358 | |
| 359 | if VERBOSE: |
| 360 | print("CMake command: " + " ".join(cmake_cmd)) |
| 361 | |
| 362 | ret_code = subprocess.call(cmake_cmd) |
| 363 | if ret_code != 0: |
| 364 | sys.exit(ret_code) |
| 365 | |
| 366 | def CMakeBuild(self): |
| 367 | """Build CMake command for the build phase and execute it""" |
| 368 | cmake_cmd = ['cmake', '--build', self.build_dir, '--target', 'install'] |
| 369 | if self._args.do_clean: |
| 370 | cmake_cmd.append('--clean-first') |
| 371 | |
| 372 | if platform.system() == 'Windows': |
| 373 | cmake_cmd.append('--config') |
| 374 | cmake_cmd.append(CONFIG_MAP[self._args.config]) |
| 375 | |
| 376 | # Speed up the build. |
| 377 | if platform.system() == 'Linux' or platform.system() == 'Darwin': |
| 378 | cmake_cmd.append('--') |
| 379 | cmake_cmd.append('-j{ncpu}' |
| 380 | .format(ncpu=multiprocessing.cpu_count())) |
| 381 | if platform.system() == 'Windows': |
| 382 | cmake_cmd.append('--') |
| 383 | cmake_cmd.append('/maxcpucount') |
| 384 | |
| 385 | if VERBOSE: |
| 386 | print("CMake command: " + " ".join(cmake_cmd)) |
| 387 | |
| 388 | ret_code = subprocess.call(cmake_cmd) |
| 389 | if ret_code != 0: |
| 390 | sys.exit(ret_code) |
| 391 | |
| 392 | def Build(self, repos): |
| 393 | """Build the dependent repo""" |
| 394 | print('Building {n} in {d}'.format(n=self.name, d=self.repo_dir)) |
| 395 | print('Build dir = {b}'.format(b=self.build_dir)) |
| 396 | print('Install dir = {i}\n'.format(i=self.install_dir)) |
| 397 | |
| 398 | # Run any prebuild commands |
| 399 | self.PreBuild() |
| 400 | |
| 401 | # Build and execute CMake command for creating build files |
| 402 | self.CMakeConfig(repos) |
| 403 | |
| 404 | # Build and execute CMake command for the build |
| 405 | self.CMakeBuild() |
| 406 | |
| 407 | |
| 408 | def GetGoodRepos(args): |
| 409 | """Returns the latest list of GoodRepo objects. |
| 410 | |
| 411 | The known-good file is expected to be in the same |
| Mark Lobodzinski | ac1043c | 2018-07-19 13:20:46 -0600 | [diff] [blame^] | 412 | directory as this script unless overridden by the 'known_good_dir' |
| 413 | parameter. |
| Karl Schultz | 5ff6f74 | 2018-06-21 17:38:56 -0600 | [diff] [blame] | 414 | """ |
| Mark Lobodzinski | ac1043c | 2018-07-19 13:20:46 -0600 | [diff] [blame^] | 415 | if args.known_good_dir: |
| 416 | known_good_file = os.path.join( os.path.abspath(args.known_good_dir), |
| 417 | KNOWN_GOOD_FILE_NAME) |
| 418 | else: |
| 419 | known_good_file = os.path.join( |
| 420 | os.path.dirname(os.path.abspath(__file__)), KNOWN_GOOD_FILE_NAME) |
| Karl Schultz | 5ff6f74 | 2018-06-21 17:38:56 -0600 | [diff] [blame] | 421 | with open(known_good_file) as known_good: |
| 422 | return [ |
| 423 | GoodRepo(repo, args) |
| 424 | for repo in json.loads(known_good.read())['repos'] |
| 425 | ] |
| 426 | |
| 427 | |
| Mark Lobodzinski | ac1043c | 2018-07-19 13:20:46 -0600 | [diff] [blame^] | 428 | def GetInstallNames(args): |
| Karl Schultz | 5ff6f74 | 2018-06-21 17:38:56 -0600 | [diff] [blame] | 429 | """Returns the install names list. |
| Mark Lobodzinski | ac1043c | 2018-07-19 13:20:46 -0600 | [diff] [blame^] | 430 | |
| Karl Schultz | 5ff6f74 | 2018-06-21 17:38:56 -0600 | [diff] [blame] | 431 | The known-good file is expected to be in the same |
| Mark Lobodzinski | ac1043c | 2018-07-19 13:20:46 -0600 | [diff] [blame^] | 432 | directory as this script unless overridden by the 'known_good_dir' |
| 433 | parameter. |
| Karl Schultz | 5ff6f74 | 2018-06-21 17:38:56 -0600 | [diff] [blame] | 434 | """ |
| Mark Lobodzinski | ac1043c | 2018-07-19 13:20:46 -0600 | [diff] [blame^] | 435 | if args.known_good_dir: |
| 436 | known_good_file = os.path.join(os.path.abspath(args.known_good_dir), |
| 437 | KNOWN_GOOD_FILE_NAME) |
| 438 | else: |
| 439 | known_good_file = os.path.join( |
| 440 | os.path.dirname(os.path.abspath(__file__)), KNOWN_GOOD_FILE_NAME) |
| Karl Schultz | 5ff6f74 | 2018-06-21 17:38:56 -0600 | [diff] [blame] | 441 | with open(known_good_file) as known_good: |
| 442 | return json.loads(known_good.read())['install_names'] |
| 443 | |
| 444 | |
| Mark Lobodzinski | ac1043c | 2018-07-19 13:20:46 -0600 | [diff] [blame^] | 445 | def CreateHelper(args, repos, filename): |
| Karl Schultz | 5ff6f74 | 2018-06-21 17:38:56 -0600 | [diff] [blame] | 446 | """Create a CMake config helper file. |
| Mark Lobodzinski | ac1043c | 2018-07-19 13:20:46 -0600 | [diff] [blame^] | 447 | |
| Karl Schultz | 5ff6f74 | 2018-06-21 17:38:56 -0600 | [diff] [blame] | 448 | The helper file is intended to be used with 'cmake -C <file>' |
| 449 | to build this home repo using the dependencies built by this script. |
| 450 | |
| 451 | The install_names dictionary represents the CMake variables used by the |
| 452 | home repo to locate the install dirs of the dependent repos. |
| 453 | This information is baked into the CMake files of the home repo and so |
| 454 | this dictionary is kept with the repo via the json file. |
| 455 | """ |
| Mark Lobodzinski | ac1043c | 2018-07-19 13:20:46 -0600 | [diff] [blame^] | 456 | install_names = GetInstallNames(args) |
| Karl Schultz | 5ff6f74 | 2018-06-21 17:38:56 -0600 | [diff] [blame] | 457 | with open(filename, 'w') as helper_file: |
| 458 | for repo in repos: |
| 459 | if repo.name in install_names: |
| 460 | helper_file.write('set({var} "{dir}" CACHE STRING "" FORCE)\n' |
| 461 | .format( |
| 462 | var=install_names[repo.name], |
| 463 | dir=repo.install_dir)) |
| 464 | |
| 465 | |
| 466 | def main(): |
| 467 | parser = argparse.ArgumentParser( |
| 468 | description='Get and build dependent repos at known-good commits') |
| 469 | parser.add_argument( |
| Mark Lobodzinski | ac1043c | 2018-07-19 13:20:46 -0600 | [diff] [blame^] | 470 | '--known_good_dir', |
| 471 | dest='known_good_dir', |
| 472 | help="Specify directory for known_good.json file.") |
| 473 | parser.add_argument( |
| Karl Schultz | 5ff6f74 | 2018-06-21 17:38:56 -0600 | [diff] [blame] | 474 | '--dir', |
| 475 | dest='dir', |
| 476 | default='.', |
| 477 | help="Set target directory for repository roots. Default is \'.\'.") |
| 478 | parser.add_argument( |
| 479 | '--ref', |
| 480 | dest='ref', |
| 481 | default='', |
| 482 | help="Override 'commit' with git reference. E.g., 'origin/master'") |
| 483 | parser.add_argument( |
| 484 | '--no-build', |
| 485 | dest='do_build', |
| 486 | action='store_false', |
| 487 | help= |
| 488 | "Clone/update repositories and generate build files without performing compilation", |
| 489 | default=True) |
| 490 | parser.add_argument( |
| 491 | '--clean', |
| 492 | dest='do_clean', |
| 493 | action='store_true', |
| 494 | help="Clean files generated by compiler and linker before building", |
| 495 | default=False) |
| 496 | parser.add_argument( |
| 497 | '--clean-repo', |
| 498 | dest='do_clean_repo', |
| 499 | action='store_true', |
| 500 | help="Delete repository directory before building", |
| 501 | default=False) |
| 502 | parser.add_argument( |
| 503 | '--clean-build', |
| 504 | dest='do_clean_build', |
| 505 | action='store_true', |
| 506 | help="Delete build directory before building", |
| 507 | default=False) |
| 508 | parser.add_argument( |
| 509 | '--clean-install', |
| 510 | dest='do_clean_install', |
| 511 | action='store_true', |
| 512 | help="Delete install directory before building", |
| 513 | default=False) |
| 514 | parser.add_argument( |
| 515 | '--arch', |
| 516 | dest='arch', |
| 517 | choices=['32', '64', 'x86', 'x64', 'Win32', 'Win64'], |
| 518 | type=str.lower, |
| 519 | help="Set build files architecture (Windows)", |
| 520 | default='64') |
| 521 | parser.add_argument( |
| 522 | '--config', |
| 523 | dest='config', |
| 524 | choices=['debug', 'release', 'relwithdebinfo', 'minsizerel'], |
| 525 | type=str.lower, |
| 526 | help="Set build files configuration", |
| 527 | default='debug') |
| 528 | |
| 529 | args = parser.parse_args() |
| 530 | save_cwd = os.getcwd() |
| 531 | |
| 532 | # Create working "top" directory if needed |
| 533 | distutils.dir_util.mkpath(args.dir) |
| 534 | abs_top_dir = os.path.abspath(args.dir) |
| 535 | |
| 536 | repos = GetGoodRepos(args) |
| 537 | |
| 538 | print('Starting builds in {d}'.format(d=abs_top_dir)) |
| 539 | for repo in repos: |
| 540 | # If the repo has a CI whitelist, skip the repo unless |
| 541 | # one of the CI's environment variable is set to true. |
| 542 | if len(repo.ci_only): |
| 543 | do_build = False |
| 544 | for env in repo.ci_only: |
| 545 | if not env in os.environ: |
| 546 | continue |
| 547 | if os.environ[env].lower() == 'true': |
| 548 | do_build = True |
| 549 | break |
| 550 | if not do_build: |
| 551 | continue |
| 552 | |
| 553 | # Clone/update the repository |
| 554 | repo.Checkout() |
| 555 | |
| 556 | # Build the repository |
| 557 | if args.do_build: |
| 558 | repo.Build(repos) |
| 559 | |
| 560 | # Need to restore original cwd in order for CreateHelper to find json file |
| 561 | os.chdir(save_cwd) |
| Mark Lobodzinski | ac1043c | 2018-07-19 13:20:46 -0600 | [diff] [blame^] | 562 | CreateHelper(args, repos, os.path.join(abs_top_dir, 'helper.cmake')) |
| Karl Schultz | 5ff6f74 | 2018-06-21 17:38:56 -0600 | [diff] [blame] | 563 | |
| 564 | sys.exit(0) |
| 565 | |
| 566 | |
| 567 | if __name__ == '__main__': |
| 568 | main() |