xref: /aosp_15_r20/external/vulkan-validation-layers/scripts/update_deps.py (revision b7893ccf7851cd6a48cc5a1e965257d8a5cdcc70)
1*b7893ccfSSadaf Ebrahimi#!/usr/bin/env python
2*b7893ccfSSadaf Ebrahimi
3*b7893ccfSSadaf Ebrahimi# Copyright 2017 The Glslang Authors. All rights reserved.
4*b7893ccfSSadaf Ebrahimi# Copyright (c) 2018 Valve Corporation
5*b7893ccfSSadaf Ebrahimi# Copyright (c) 2018 LunarG, Inc.
6*b7893ccfSSadaf Ebrahimi#
7*b7893ccfSSadaf Ebrahimi# Licensed under the Apache License, Version 2.0 (the "License");
8*b7893ccfSSadaf Ebrahimi# you may not use this file except in compliance with the License.
9*b7893ccfSSadaf Ebrahimi# You may obtain a copy of the License at
10*b7893ccfSSadaf Ebrahimi#
11*b7893ccfSSadaf Ebrahimi#     http://www.apache.org/licenses/LICENSE-2.0
12*b7893ccfSSadaf Ebrahimi#
13*b7893ccfSSadaf Ebrahimi# Unless required by applicable law or agreed to in writing, software
14*b7893ccfSSadaf Ebrahimi# distributed under the License is distributed on an "AS IS" BASIS,
15*b7893ccfSSadaf Ebrahimi# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16*b7893ccfSSadaf Ebrahimi# See the License for the specific language governing permissions and
17*b7893ccfSSadaf Ebrahimi# limitations under the License.
18*b7893ccfSSadaf Ebrahimi
19*b7893ccfSSadaf Ebrahimi# This script was heavily leveraged from KhronosGroup/glslang
20*b7893ccfSSadaf Ebrahimi# update_glslang_sources.py.
21*b7893ccfSSadaf Ebrahimi"""update_deps.py
22*b7893ccfSSadaf Ebrahimi
23*b7893ccfSSadaf EbrahimiGet and build dependent repositories using known-good commits.
24*b7893ccfSSadaf Ebrahimi
25*b7893ccfSSadaf EbrahimiPurpose
26*b7893ccfSSadaf Ebrahimi-------
27*b7893ccfSSadaf Ebrahimi
28*b7893ccfSSadaf EbrahimiThis program is intended to assist a developer of this repository
29*b7893ccfSSadaf Ebrahimi(the "home" repository) by gathering and building the repositories that
30*b7893ccfSSadaf Ebrahimithis home repository depend on.  It also checks out each dependent
31*b7893ccfSSadaf Ebrahimirepository at a "known-good" commit in order to provide stability in
32*b7893ccfSSadaf Ebrahimithe dependent repositories.
33*b7893ccfSSadaf Ebrahimi
34*b7893ccfSSadaf EbrahimiPython Compatibility
35*b7893ccfSSadaf Ebrahimi--------------------
36*b7893ccfSSadaf Ebrahimi
37*b7893ccfSSadaf EbrahimiThis program can be used with Python 2.7 and Python 3.
38*b7893ccfSSadaf Ebrahimi
39*b7893ccfSSadaf EbrahimiKnown-Good JSON Database
40*b7893ccfSSadaf Ebrahimi------------------------
41*b7893ccfSSadaf Ebrahimi
42*b7893ccfSSadaf EbrahimiThis program expects to find a file named "known-good.json" in the
43*b7893ccfSSadaf Ebrahimisame directory as the program file.  This JSON file is tailored for
44*b7893ccfSSadaf Ebrahimithe needs of the home repository by including its dependent repositories.
45*b7893ccfSSadaf Ebrahimi
46*b7893ccfSSadaf EbrahimiProgram Options
47*b7893ccfSSadaf Ebrahimi---------------
48*b7893ccfSSadaf Ebrahimi
49*b7893ccfSSadaf EbrahimiSee the help text (update_deps.py --help) for a complete list of options.
50*b7893ccfSSadaf Ebrahimi
51*b7893ccfSSadaf EbrahimiProgram Operation
52*b7893ccfSSadaf Ebrahimi-----------------
53*b7893ccfSSadaf Ebrahimi
54*b7893ccfSSadaf EbrahimiThe program uses the user's current directory at the time of program
55*b7893ccfSSadaf Ebrahimiinvocation as the location for fetching and building the dependent
56*b7893ccfSSadaf Ebrahimirepositories.  The user can override this by using the "--dir" option.
57*b7893ccfSSadaf Ebrahimi
58*b7893ccfSSadaf EbrahimiFor example, a directory named "build" in the repository's root directory
59*b7893ccfSSadaf Ebrahimiis a good place to put the dependent repositories because that directory
60*b7893ccfSSadaf Ebrahimiis not tracked by Git. (See the .gitignore file.)  The "external" directory
61*b7893ccfSSadaf Ebrahimimay also be a suitable location.
62*b7893ccfSSadaf EbrahimiA user can issue:
63*b7893ccfSSadaf Ebrahimi
64*b7893ccfSSadaf Ebrahimi$ cd My-Repo
65*b7893ccfSSadaf Ebrahimi$ mkdir build
66*b7893ccfSSadaf Ebrahimi$ cd build
67*b7893ccfSSadaf Ebrahimi$ ../scripts/update_deps.py
68*b7893ccfSSadaf Ebrahimi
69*b7893ccfSSadaf Ebrahimior, to do the same thing, but using the --dir option:
70*b7893ccfSSadaf Ebrahimi
71*b7893ccfSSadaf Ebrahimi$ cd My-Repo
72*b7893ccfSSadaf Ebrahimi$ mkdir build
73*b7893ccfSSadaf Ebrahimi$ scripts/update_deps.py --dir=build
74*b7893ccfSSadaf Ebrahimi
75*b7893ccfSSadaf EbrahimiWith these commands, the "build" directory is considered the "top"
76*b7893ccfSSadaf Ebrahimidirectory where the program clones the dependent repositories.  The
77*b7893ccfSSadaf EbrahimiJSON file configures the build and install working directories to be
78*b7893ccfSSadaf Ebrahimiwithin this "top" directory.
79*b7893ccfSSadaf Ebrahimi
80*b7893ccfSSadaf EbrahimiNote that the "dir" option can also specify an absolute path:
81*b7893ccfSSadaf Ebrahimi
82*b7893ccfSSadaf Ebrahimi$ cd My-Repo
83*b7893ccfSSadaf Ebrahimi$ scripts/update_deps.py --dir=/tmp/deps
84*b7893ccfSSadaf Ebrahimi
85*b7893ccfSSadaf EbrahimiThe "top" dir is then /tmp/deps (Linux filesystem example) and is
86*b7893ccfSSadaf Ebrahimiwhere this program will clone and build the dependent repositories.
87*b7893ccfSSadaf Ebrahimi
88*b7893ccfSSadaf EbrahimiHelper CMake Config File
89*b7893ccfSSadaf Ebrahimi------------------------
90*b7893ccfSSadaf Ebrahimi
91*b7893ccfSSadaf EbrahimiWhen the program finishes building the dependencies, it writes a file
92*b7893ccfSSadaf Ebrahiminamed "helper.cmake" to the "top" directory that contains CMake commands
93*b7893ccfSSadaf Ebrahimifor setting CMake variables for locating the dependent repositories.
94*b7893ccfSSadaf EbrahimiThis helper file can be used to set up the CMake build files for this
95*b7893ccfSSadaf Ebrahimi"home" repository.
96*b7893ccfSSadaf Ebrahimi
97*b7893ccfSSadaf EbrahimiA complete sequence might look like:
98*b7893ccfSSadaf Ebrahimi
99*b7893ccfSSadaf Ebrahimi$ git clone [email protected]:My-Group/My-Repo.git
100*b7893ccfSSadaf Ebrahimi$ cd My-Repo
101*b7893ccfSSadaf Ebrahimi$ mkdir build
102*b7893ccfSSadaf Ebrahimi$ cd build
103*b7893ccfSSadaf Ebrahimi$ ../scripts/update_deps.py
104*b7893ccfSSadaf Ebrahimi$ cmake -C helper.cmake ..
105*b7893ccfSSadaf Ebrahimi$ cmake --build .
106*b7893ccfSSadaf Ebrahimi
107*b7893ccfSSadaf EbrahimiJSON File Schema
108*b7893ccfSSadaf Ebrahimi----------------
109*b7893ccfSSadaf Ebrahimi
110*b7893ccfSSadaf EbrahimiThere's no formal schema for the "known-good" JSON file, but here is
111*b7893ccfSSadaf Ebrahimia description of its elements.  All elements are required except those
112*b7893ccfSSadaf Ebrahimimarked as optional.  Please see the "known_good.json" file for
113*b7893ccfSSadaf Ebrahimiexamples of all of these elements.
114*b7893ccfSSadaf Ebrahimi
115*b7893ccfSSadaf Ebrahimi- name
116*b7893ccfSSadaf Ebrahimi
117*b7893ccfSSadaf EbrahimiThe name of the dependent repository.  This field can be referenced
118*b7893ccfSSadaf Ebrahimiby the "deps.repo_name" structure to record a dependency.
119*b7893ccfSSadaf Ebrahimi
120*b7893ccfSSadaf Ebrahimi- url
121*b7893ccfSSadaf Ebrahimi
122*b7893ccfSSadaf EbrahimiSpecifies the URL of the repository.
123*b7893ccfSSadaf EbrahimiExample: https://github.com/KhronosGroup/Vulkan-Loader.git
124*b7893ccfSSadaf Ebrahimi
125*b7893ccfSSadaf Ebrahimi- sub_dir
126*b7893ccfSSadaf Ebrahimi
127*b7893ccfSSadaf EbrahimiThe directory where the program clones the repository, relative to
128*b7893ccfSSadaf Ebrahimithe "top" directory.
129*b7893ccfSSadaf Ebrahimi
130*b7893ccfSSadaf Ebrahimi- build_dir
131*b7893ccfSSadaf Ebrahimi
132*b7893ccfSSadaf EbrahimiThe directory used to build the repository, relative to the "top"
133*b7893ccfSSadaf Ebrahimidirectory.
134*b7893ccfSSadaf Ebrahimi
135*b7893ccfSSadaf Ebrahimi- install_dir
136*b7893ccfSSadaf Ebrahimi
137*b7893ccfSSadaf EbrahimiThe directory used to store the installed build artifacts, relative
138*b7893ccfSSadaf Ebrahimito the "top" directory.
139*b7893ccfSSadaf Ebrahimi
140*b7893ccfSSadaf Ebrahimi- commit
141*b7893ccfSSadaf Ebrahimi
142*b7893ccfSSadaf EbrahimiThe commit used to checkout the repository.  This can be a SHA-1
143*b7893ccfSSadaf Ebrahimiobject name or a refname used with the remote name "origin".
144*b7893ccfSSadaf EbrahimiFor example, this field can be set to "origin/sdk-1.1.77" to
145*b7893ccfSSadaf Ebrahimiselect the end of the sdk-1.1.77 branch.
146*b7893ccfSSadaf Ebrahimi
147*b7893ccfSSadaf Ebrahimi- deps (optional)
148*b7893ccfSSadaf Ebrahimi
149*b7893ccfSSadaf EbrahimiAn array of pairs consisting of a CMake variable name and a
150*b7893ccfSSadaf Ebrahimirepository name to specify a dependent repo and a "link" to
151*b7893ccfSSadaf Ebrahimithat repo's install artifacts.  For example:
152*b7893ccfSSadaf Ebrahimi
153*b7893ccfSSadaf Ebrahimi"deps" : [
154*b7893ccfSSadaf Ebrahimi    {
155*b7893ccfSSadaf Ebrahimi        "var_name" : "VULKAN_HEADERS_INSTALL_DIR",
156*b7893ccfSSadaf Ebrahimi        "repo_name" : "Vulkan-Headers"
157*b7893ccfSSadaf Ebrahimi    }
158*b7893ccfSSadaf Ebrahimi]
159*b7893ccfSSadaf Ebrahimi
160*b7893ccfSSadaf Ebrahimiwhich represents that this repository depends on the Vulkan-Headers
161*b7893ccfSSadaf Ebrahimirepository and uses the VULKAN_HEADERS_INSTALL_DIR CMake variable to
162*b7893ccfSSadaf Ebrahimispecify the location where it expects to find the Vulkan-Headers install
163*b7893ccfSSadaf Ebrahimidirectory.
164*b7893ccfSSadaf EbrahimiNote that the "repo_name" element must match the "name" element of some
165*b7893ccfSSadaf Ebrahimiother repository in the JSON file.
166*b7893ccfSSadaf Ebrahimi
167*b7893ccfSSadaf Ebrahimi- prebuild (optional)
168*b7893ccfSSadaf Ebrahimi- prebuild_linux (optional)  (For Linux and MacOS)
169*b7893ccfSSadaf Ebrahimi- prebuild_windows (optional)
170*b7893ccfSSadaf Ebrahimi
171*b7893ccfSSadaf EbrahimiA list of commands to execute before building a dependent repository.
172*b7893ccfSSadaf EbrahimiThis is useful for repositories that require the execution of some
173*b7893ccfSSadaf Ebrahimisort of "update" script or need to clone an auxillary repository like
174*b7893ccfSSadaf Ebrahimigoogletest.
175*b7893ccfSSadaf Ebrahimi
176*b7893ccfSSadaf EbrahimiThe commands listed in "prebuild" are executed first, and then the
177*b7893ccfSSadaf Ebrahimicommands for the specific platform are executed.
178*b7893ccfSSadaf Ebrahimi
179*b7893ccfSSadaf Ebrahimi- custom_build (optional)
180*b7893ccfSSadaf Ebrahimi
181*b7893ccfSSadaf EbrahimiA list of commands to execute as a custom build instead of using
182*b7893ccfSSadaf Ebrahimithe built in CMake way of building. Requires "build_step" to be
183*b7893ccfSSadaf Ebrahimiset to "custom"
184*b7893ccfSSadaf Ebrahimi
185*b7893ccfSSadaf EbrahimiYou can insert the following keywords into the commands listed in
186*b7893ccfSSadaf Ebrahimi"custom_build" if they require runtime information (like whether the
187*b7893ccfSSadaf Ebrahimibuild config is "Debug" or "Release").
188*b7893ccfSSadaf Ebrahimi
189*b7893ccfSSadaf EbrahimiKeywords:
190*b7893ccfSSadaf Ebrahimi{0} reference to a dictionary of repos and their attributes
191*b7893ccfSSadaf Ebrahimi{1} reference to the command line arguments set before start
192*b7893ccfSSadaf Ebrahimi{2} reference to the CONFIG_MAP value of config.
193*b7893ccfSSadaf Ebrahimi
194*b7893ccfSSadaf EbrahimiExample:
195*b7893ccfSSadaf Ebrahimi{2} returns the CONFIG_MAP value of config e.g. debug -> Debug
196*b7893ccfSSadaf Ebrahimi{1}.config returns the config variable set when you ran update_dep.py
197*b7893ccfSSadaf Ebrahimi{0}[Vulkan-Headers][repo_root] returns the repo_root variable from
198*b7893ccfSSadaf Ebrahimi                                   the Vulkan-Headers GoodRepo object.
199*b7893ccfSSadaf Ebrahimi
200*b7893ccfSSadaf Ebrahimi- cmake_options (optional)
201*b7893ccfSSadaf Ebrahimi
202*b7893ccfSSadaf EbrahimiA list of options to pass to CMake during the generation phase.
203*b7893ccfSSadaf Ebrahimi
204*b7893ccfSSadaf Ebrahimi- ci_only (optional)
205*b7893ccfSSadaf Ebrahimi
206*b7893ccfSSadaf EbrahimiA list of environment variables where one must be set to "true"
207*b7893ccfSSadaf Ebrahimi(case-insensitive) in order for this repo to be fetched and built.
208*b7893ccfSSadaf EbrahimiThis list can be used to specify repos that should be built only in CI.
209*b7893ccfSSadaf EbrahimiTypically, this list might contain "TRAVIS" and/or "APPVEYOR" because
210*b7893ccfSSadaf Ebrahimieach of these CI systems sets an environment variable with its own
211*b7893ccfSSadaf Ebrahiminame to "true".  Note that this could also be (ab)used to control
212*b7893ccfSSadaf Ebrahimithe processing of the repo with any environment variable.  The default
213*b7893ccfSSadaf Ebrahimiis an empty list, which means that the repo is always processed.
214*b7893ccfSSadaf Ebrahimi
215*b7893ccfSSadaf Ebrahimi- build_step (optional)
216*b7893ccfSSadaf Ebrahimi
217*b7893ccfSSadaf EbrahimiSpecifies if the dependent repository should be built or not. This can
218*b7893ccfSSadaf Ebrahimihave a value of 'build', 'custom',  or 'skip'. The dependent repositories are
219*b7893ccfSSadaf Ebrahimibuilt by default.
220*b7893ccfSSadaf Ebrahimi
221*b7893ccfSSadaf Ebrahimi- build_platforms (optional)
222*b7893ccfSSadaf Ebrahimi
223*b7893ccfSSadaf EbrahimiA list of platforms the repository will be built on.
224*b7893ccfSSadaf EbrahimiLegal options include:
225*b7893ccfSSadaf Ebrahimi"windows"
226*b7893ccfSSadaf Ebrahimi"linux"
227*b7893ccfSSadaf Ebrahimi"darwin"
228*b7893ccfSSadaf Ebrahimi
229*b7893ccfSSadaf EbrahimiBuilds on all platforms by default.
230*b7893ccfSSadaf Ebrahimi
231*b7893ccfSSadaf EbrahimiNote
232*b7893ccfSSadaf Ebrahimi----
233*b7893ccfSSadaf Ebrahimi
234*b7893ccfSSadaf EbrahimiThe "sub_dir", "build_dir", and "install_dir" elements are all relative
235*b7893ccfSSadaf Ebrahimito the effective "top" directory.  Specifying absolute paths is not
236*b7893ccfSSadaf Ebrahimisupported.  However, the "top" directory specified with the "--dir"
237*b7893ccfSSadaf Ebrahimioption can be a relative or absolute path.
238*b7893ccfSSadaf Ebrahimi
239*b7893ccfSSadaf Ebrahimi"""
240*b7893ccfSSadaf Ebrahimi
241*b7893ccfSSadaf Ebrahimifrom __future__ import print_function
242*b7893ccfSSadaf Ebrahimi
243*b7893ccfSSadaf Ebrahimiimport argparse
244*b7893ccfSSadaf Ebrahimiimport json
245*b7893ccfSSadaf Ebrahimiimport distutils.dir_util
246*b7893ccfSSadaf Ebrahimiimport os.path
247*b7893ccfSSadaf Ebrahimiimport subprocess
248*b7893ccfSSadaf Ebrahimiimport sys
249*b7893ccfSSadaf Ebrahimiimport platform
250*b7893ccfSSadaf Ebrahimiimport multiprocessing
251*b7893ccfSSadaf Ebrahimiimport shlex
252*b7893ccfSSadaf Ebrahimiimport shutil
253*b7893ccfSSadaf Ebrahimi
254*b7893ccfSSadaf EbrahimiKNOWN_GOOD_FILE_NAME = 'known_good.json'
255*b7893ccfSSadaf Ebrahimi
256*b7893ccfSSadaf EbrahimiCONFIG_MAP = {
257*b7893ccfSSadaf Ebrahimi    'debug': 'Debug',
258*b7893ccfSSadaf Ebrahimi    'release': 'Release',
259*b7893ccfSSadaf Ebrahimi    'relwithdebinfo': 'RelWithDebInfo',
260*b7893ccfSSadaf Ebrahimi    'minsizerel': 'MinSizeRel'
261*b7893ccfSSadaf Ebrahimi}
262*b7893ccfSSadaf Ebrahimi
263*b7893ccfSSadaf EbrahimiVERBOSE = False
264*b7893ccfSSadaf Ebrahimi
265*b7893ccfSSadaf EbrahimiDEVNULL = open(os.devnull, 'wb')
266*b7893ccfSSadaf Ebrahimi
267*b7893ccfSSadaf Ebrahimi
268*b7893ccfSSadaf Ebrahimidef command_output(cmd, directory, fail_ok=False):
269*b7893ccfSSadaf Ebrahimi    """Runs a command in a directory and returns its standard output stream.
270*b7893ccfSSadaf Ebrahimi
271*b7893ccfSSadaf Ebrahimi    Captures the standard error stream and prints it if error.
272*b7893ccfSSadaf Ebrahimi
273*b7893ccfSSadaf Ebrahimi    Raises a RuntimeError if the command fails to launch or otherwise fails.
274*b7893ccfSSadaf Ebrahimi    """
275*b7893ccfSSadaf Ebrahimi    if VERBOSE:
276*b7893ccfSSadaf Ebrahimi        print('In {d}: {cmd}'.format(d=directory, cmd=cmd))
277*b7893ccfSSadaf Ebrahimi    p = subprocess.Popen(
278*b7893ccfSSadaf Ebrahimi        cmd, cwd=directory, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
279*b7893ccfSSadaf Ebrahimi    (stdout, stderr) = p.communicate()
280*b7893ccfSSadaf Ebrahimi    if p.returncode != 0:
281*b7893ccfSSadaf Ebrahimi        print('*** Error ***\nstderr contents:\n{}'.format(stderr))
282*b7893ccfSSadaf Ebrahimi        if not fail_ok:
283*b7893ccfSSadaf Ebrahimi            raise RuntimeError('Failed to run {} in {}'.format(cmd, directory))
284*b7893ccfSSadaf Ebrahimi    if VERBOSE:
285*b7893ccfSSadaf Ebrahimi        print(stdout)
286*b7893ccfSSadaf Ebrahimi    return stdout
287*b7893ccfSSadaf Ebrahimi
288*b7893ccfSSadaf Ebrahimiclass GoodRepo(object):
289*b7893ccfSSadaf Ebrahimi    """Represents a repository at a known-good commit."""
290*b7893ccfSSadaf Ebrahimi
291*b7893ccfSSadaf Ebrahimi    def __init__(self, json, args):
292*b7893ccfSSadaf Ebrahimi        """Initializes this good repo object.
293*b7893ccfSSadaf Ebrahimi
294*b7893ccfSSadaf Ebrahimi        Args:
295*b7893ccfSSadaf Ebrahimi        'json':  A fully populated JSON object describing the repo.
296*b7893ccfSSadaf Ebrahimi        'args':  Results from ArgumentParser
297*b7893ccfSSadaf Ebrahimi        """
298*b7893ccfSSadaf Ebrahimi        self._json = json
299*b7893ccfSSadaf Ebrahimi        self._args = args
300*b7893ccfSSadaf Ebrahimi        # Required JSON elements
301*b7893ccfSSadaf Ebrahimi        self.name = json['name']
302*b7893ccfSSadaf Ebrahimi        self.url = json['url']
303*b7893ccfSSadaf Ebrahimi        self.sub_dir = json['sub_dir']
304*b7893ccfSSadaf Ebrahimi        self.commit = json['commit']
305*b7893ccfSSadaf Ebrahimi        # Optional JSON elements
306*b7893ccfSSadaf Ebrahimi        self.build_dir = None
307*b7893ccfSSadaf Ebrahimi        self.install_dir = None
308*b7893ccfSSadaf Ebrahimi        if json.get('build_dir'):
309*b7893ccfSSadaf Ebrahimi            self.build_dir = os.path.normpath(json['build_dir'])
310*b7893ccfSSadaf Ebrahimi        if json.get('install_dir'):
311*b7893ccfSSadaf Ebrahimi            self.install_dir = os.path.normpath(json['install_dir'])
312*b7893ccfSSadaf Ebrahimi        self.deps = json['deps'] if ('deps' in json) else []
313*b7893ccfSSadaf Ebrahimi        self.prebuild = json['prebuild'] if ('prebuild' in json) else []
314*b7893ccfSSadaf Ebrahimi        self.prebuild_linux = json['prebuild_linux'] if (
315*b7893ccfSSadaf Ebrahimi            'prebuild_linux' in json) else []
316*b7893ccfSSadaf Ebrahimi        self.prebuild_windows = json['prebuild_windows'] if (
317*b7893ccfSSadaf Ebrahimi            'prebuild_windows' in json) else []
318*b7893ccfSSadaf Ebrahimi        self.custom_build = json['custom_build'] if ('custom_build' in json) else []
319*b7893ccfSSadaf Ebrahimi        self.cmake_options = json['cmake_options'] if (
320*b7893ccfSSadaf Ebrahimi            'cmake_options' in json) else []
321*b7893ccfSSadaf Ebrahimi        self.ci_only = json['ci_only'] if ('ci_only' in json) else []
322*b7893ccfSSadaf Ebrahimi        self.build_step = json['build_step'] if ('build_step' in json) else 'build'
323*b7893ccfSSadaf Ebrahimi        self.build_platforms = json['build_platforms'] if ('build_platforms' in json) else []
324*b7893ccfSSadaf Ebrahimi        # Absolute paths for a repo's directories
325*b7893ccfSSadaf Ebrahimi        dir_top = os.path.abspath(args.dir)
326*b7893ccfSSadaf Ebrahimi        self.repo_dir = os.path.join(dir_top, self.sub_dir)
327*b7893ccfSSadaf Ebrahimi        if self.build_dir:
328*b7893ccfSSadaf Ebrahimi            self.build_dir = os.path.join(dir_top, self.build_dir)
329*b7893ccfSSadaf Ebrahimi        if self.install_dir:
330*b7893ccfSSadaf Ebrahimi            self.install_dir = os.path.join(dir_top, self.install_dir)
331*b7893ccfSSadaf Ebrahimi	    # Check if platform is one to build on
332*b7893ccfSSadaf Ebrahimi        self.on_build_platform = False
333*b7893ccfSSadaf Ebrahimi        if self.build_platforms == [] or platform.system().lower() in self.build_platforms:
334*b7893ccfSSadaf Ebrahimi            self.on_build_platform = True
335*b7893ccfSSadaf Ebrahimi
336*b7893ccfSSadaf Ebrahimi    def Clone(self):
337*b7893ccfSSadaf Ebrahimi        distutils.dir_util.mkpath(self.repo_dir)
338*b7893ccfSSadaf Ebrahimi        command_output(['git', 'clone', self.url, '.'], self.repo_dir)
339*b7893ccfSSadaf Ebrahimi
340*b7893ccfSSadaf Ebrahimi    def Fetch(self):
341*b7893ccfSSadaf Ebrahimi        command_output(['git', 'fetch', 'origin'], self.repo_dir)
342*b7893ccfSSadaf Ebrahimi
343*b7893ccfSSadaf Ebrahimi    def Checkout(self):
344*b7893ccfSSadaf Ebrahimi        print('Checking out {n} in {d}'.format(n=self.name, d=self.repo_dir))
345*b7893ccfSSadaf Ebrahimi        if self._args.do_clean_repo:
346*b7893ccfSSadaf Ebrahimi            shutil.rmtree(self.repo_dir, ignore_errors=True)
347*b7893ccfSSadaf Ebrahimi        if not os.path.exists(os.path.join(self.repo_dir, '.git')):
348*b7893ccfSSadaf Ebrahimi            self.Clone()
349*b7893ccfSSadaf Ebrahimi        self.Fetch()
350*b7893ccfSSadaf Ebrahimi        if len(self._args.ref):
351*b7893ccfSSadaf Ebrahimi            command_output(['git', 'checkout', self._args.ref], self.repo_dir)
352*b7893ccfSSadaf Ebrahimi        else:
353*b7893ccfSSadaf Ebrahimi            command_output(['git', 'checkout', self.commit], self.repo_dir)
354*b7893ccfSSadaf Ebrahimi        print(command_output(['git', 'status'], self.repo_dir))
355*b7893ccfSSadaf Ebrahimi
356*b7893ccfSSadaf Ebrahimi    def CustomPreProcess(self, cmd_str, repo_dict):
357*b7893ccfSSadaf Ebrahimi        return cmd_str.format(repo_dict, self._args, CONFIG_MAP[self._args.config])
358*b7893ccfSSadaf Ebrahimi
359*b7893ccfSSadaf Ebrahimi    def PreBuild(self):
360*b7893ccfSSadaf Ebrahimi        """Execute any prebuild steps from the repo root"""
361*b7893ccfSSadaf Ebrahimi        for p in self.prebuild:
362*b7893ccfSSadaf Ebrahimi            command_output(shlex.split(p), self.repo_dir)
363*b7893ccfSSadaf Ebrahimi        if platform.system() == 'Linux' or platform.system() == 'Darwin':
364*b7893ccfSSadaf Ebrahimi            for p in self.prebuild_linux:
365*b7893ccfSSadaf Ebrahimi                command_output(shlex.split(p), self.repo_dir)
366*b7893ccfSSadaf Ebrahimi        if platform.system() == 'Windows':
367*b7893ccfSSadaf Ebrahimi            for p in self.prebuild_windows:
368*b7893ccfSSadaf Ebrahimi                command_output(shlex.split(p), self.repo_dir)
369*b7893ccfSSadaf Ebrahimi
370*b7893ccfSSadaf Ebrahimi    def CustomBuild(self, repo_dict):
371*b7893ccfSSadaf Ebrahimi        """Execute any custom_build steps from the repo root"""
372*b7893ccfSSadaf Ebrahimi        for p in self.custom_build:
373*b7893ccfSSadaf Ebrahimi            cmd = self.CustomPreProcess(p, repo_dict)
374*b7893ccfSSadaf Ebrahimi            command_output(shlex.split(cmd), self.repo_dir)
375*b7893ccfSSadaf Ebrahimi
376*b7893ccfSSadaf Ebrahimi    def CMakeConfig(self, repos):
377*b7893ccfSSadaf Ebrahimi        """Build CMake command for the configuration phase and execute it"""
378*b7893ccfSSadaf Ebrahimi        if self._args.do_clean_build:
379*b7893ccfSSadaf Ebrahimi            shutil.rmtree(self.build_dir)
380*b7893ccfSSadaf Ebrahimi        if self._args.do_clean_install:
381*b7893ccfSSadaf Ebrahimi            shutil.rmtree(self.install_dir)
382*b7893ccfSSadaf Ebrahimi
383*b7893ccfSSadaf Ebrahimi        # Create and change to build directory
384*b7893ccfSSadaf Ebrahimi        distutils.dir_util.mkpath(self.build_dir)
385*b7893ccfSSadaf Ebrahimi        os.chdir(self.build_dir)
386*b7893ccfSSadaf Ebrahimi
387*b7893ccfSSadaf Ebrahimi        cmake_cmd = [
388*b7893ccfSSadaf Ebrahimi            'cmake', self.repo_dir,
389*b7893ccfSSadaf Ebrahimi            '-DCMAKE_INSTALL_PREFIX=' + self.install_dir
390*b7893ccfSSadaf Ebrahimi        ]
391*b7893ccfSSadaf Ebrahimi
392*b7893ccfSSadaf Ebrahimi        # For each repo this repo depends on, generate a CMake variable
393*b7893ccfSSadaf Ebrahimi        # definitions for "...INSTALL_DIR" that points to that dependent
394*b7893ccfSSadaf Ebrahimi        # repo's install dir.
395*b7893ccfSSadaf Ebrahimi        for d in self.deps:
396*b7893ccfSSadaf Ebrahimi            dep_commit = [r for r in repos if r.name == d['repo_name']]
397*b7893ccfSSadaf Ebrahimi            if len(dep_commit):
398*b7893ccfSSadaf Ebrahimi                cmake_cmd.append('-D{var_name}={install_dir}'.format(
399*b7893ccfSSadaf Ebrahimi                    var_name=d['var_name'],
400*b7893ccfSSadaf Ebrahimi                    install_dir=dep_commit[0].install_dir))
401*b7893ccfSSadaf Ebrahimi
402*b7893ccfSSadaf Ebrahimi        # Add any CMake options
403*b7893ccfSSadaf Ebrahimi        for option in self.cmake_options:
404*b7893ccfSSadaf Ebrahimi            cmake_cmd.append(option)
405*b7893ccfSSadaf Ebrahimi
406*b7893ccfSSadaf Ebrahimi        # Set build config for single-configuration generators
407*b7893ccfSSadaf Ebrahimi        if platform.system() == 'Linux' or platform.system() == 'Darwin':
408*b7893ccfSSadaf Ebrahimi            cmake_cmd.append('-DCMAKE_BUILD_TYPE={config}'.format(
409*b7893ccfSSadaf Ebrahimi                config=CONFIG_MAP[self._args.config]))
410*b7893ccfSSadaf Ebrahimi
411*b7893ccfSSadaf Ebrahimi        # Use the CMake -A option to select the platform architecture
412*b7893ccfSSadaf Ebrahimi        # without needing a Visual Studio generator.
413*b7893ccfSSadaf Ebrahimi        if platform.system() == 'Windows':
414*b7893ccfSSadaf Ebrahimi            if self._args.arch == '64' or self._args.arch == 'x64' or self._args.arch == 'win64':
415*b7893ccfSSadaf Ebrahimi                cmake_cmd.append('-A')
416*b7893ccfSSadaf Ebrahimi                cmake_cmd.append('x64')
417*b7893ccfSSadaf Ebrahimi
418*b7893ccfSSadaf Ebrahimi        # Apply a generator, if one is specified.  This can be used to supply
419*b7893ccfSSadaf Ebrahimi        # a specific generator for the dependent repositories to match
420*b7893ccfSSadaf Ebrahimi        # that of the main repository.
421*b7893ccfSSadaf Ebrahimi        if self._args.generator is not None:
422*b7893ccfSSadaf Ebrahimi            cmake_cmd.extend(['-G', self._args.generator])
423*b7893ccfSSadaf Ebrahimi
424*b7893ccfSSadaf Ebrahimi        if VERBOSE:
425*b7893ccfSSadaf Ebrahimi            print("CMake command: " + " ".join(cmake_cmd))
426*b7893ccfSSadaf Ebrahimi
427*b7893ccfSSadaf Ebrahimi        ret_code = subprocess.call(cmake_cmd)
428*b7893ccfSSadaf Ebrahimi        if ret_code != 0:
429*b7893ccfSSadaf Ebrahimi            sys.exit(ret_code)
430*b7893ccfSSadaf Ebrahimi
431*b7893ccfSSadaf Ebrahimi    def CMakeBuild(self):
432*b7893ccfSSadaf Ebrahimi        """Build CMake command for the build phase and execute it"""
433*b7893ccfSSadaf Ebrahimi        cmake_cmd = ['cmake', '--build', self.build_dir, '--target', 'install']
434*b7893ccfSSadaf Ebrahimi        if self._args.do_clean:
435*b7893ccfSSadaf Ebrahimi            cmake_cmd.append('--clean-first')
436*b7893ccfSSadaf Ebrahimi
437*b7893ccfSSadaf Ebrahimi        if platform.system() == 'Windows':
438*b7893ccfSSadaf Ebrahimi            cmake_cmd.append('--config')
439*b7893ccfSSadaf Ebrahimi            cmake_cmd.append(CONFIG_MAP[self._args.config])
440*b7893ccfSSadaf Ebrahimi
441*b7893ccfSSadaf Ebrahimi        # Speed up the build.
442*b7893ccfSSadaf Ebrahimi        if platform.system() == 'Linux' or platform.system() == 'Darwin':
443*b7893ccfSSadaf Ebrahimi            cmake_cmd.append('--')
444*b7893ccfSSadaf Ebrahimi            num_make_jobs = multiprocessing.cpu_count()
445*b7893ccfSSadaf Ebrahimi            env_make_jobs = os.environ.get('MAKE_JOBS', None)
446*b7893ccfSSadaf Ebrahimi            if env_make_jobs is not None:
447*b7893ccfSSadaf Ebrahimi                try:
448*b7893ccfSSadaf Ebrahimi                    num_make_jobs = min(num_make_jobs, int(env_make_jobs))
449*b7893ccfSSadaf Ebrahimi                except ValueError:
450*b7893ccfSSadaf Ebrahimi                    print('warning: environment variable MAKE_JOBS has non-numeric value "{}".  '
451*b7893ccfSSadaf Ebrahimi                          'Using {} (CPU count) instead.'.format(env_make_jobs, num_make_jobs))
452*b7893ccfSSadaf Ebrahimi            cmake_cmd.append('-j{}'.format(num_make_jobs))
453*b7893ccfSSadaf Ebrahimi        if platform.system() == 'Windows':
454*b7893ccfSSadaf Ebrahimi            cmake_cmd.append('--')
455*b7893ccfSSadaf Ebrahimi            cmake_cmd.append('/maxcpucount')
456*b7893ccfSSadaf Ebrahimi
457*b7893ccfSSadaf Ebrahimi        if VERBOSE:
458*b7893ccfSSadaf Ebrahimi            print("CMake command: " + " ".join(cmake_cmd))
459*b7893ccfSSadaf Ebrahimi
460*b7893ccfSSadaf Ebrahimi        ret_code = subprocess.call(cmake_cmd)
461*b7893ccfSSadaf Ebrahimi        if ret_code != 0:
462*b7893ccfSSadaf Ebrahimi            sys.exit(ret_code)
463*b7893ccfSSadaf Ebrahimi
464*b7893ccfSSadaf Ebrahimi    def Build(self, repos, repo_dict):
465*b7893ccfSSadaf Ebrahimi        """Build the dependent repo"""
466*b7893ccfSSadaf Ebrahimi        print('Building {n} in {d}'.format(n=self.name, d=self.repo_dir))
467*b7893ccfSSadaf Ebrahimi        print('Build dir = {b}'.format(b=self.build_dir))
468*b7893ccfSSadaf Ebrahimi        print('Install dir = {i}\n'.format(i=self.install_dir))
469*b7893ccfSSadaf Ebrahimi
470*b7893ccfSSadaf Ebrahimi        # Run any prebuild commands
471*b7893ccfSSadaf Ebrahimi        self.PreBuild()
472*b7893ccfSSadaf Ebrahimi
473*b7893ccfSSadaf Ebrahimi        if self.build_step == 'custom':
474*b7893ccfSSadaf Ebrahimi            self.CustomBuild(repo_dict)
475*b7893ccfSSadaf Ebrahimi            return
476*b7893ccfSSadaf Ebrahimi
477*b7893ccfSSadaf Ebrahimi        # Build and execute CMake command for creating build files
478*b7893ccfSSadaf Ebrahimi        self.CMakeConfig(repos)
479*b7893ccfSSadaf Ebrahimi
480*b7893ccfSSadaf Ebrahimi        # Build and execute CMake command for the build
481*b7893ccfSSadaf Ebrahimi        self.CMakeBuild()
482*b7893ccfSSadaf Ebrahimi
483*b7893ccfSSadaf Ebrahimi
484*b7893ccfSSadaf Ebrahimidef GetGoodRepos(args):
485*b7893ccfSSadaf Ebrahimi    """Returns the latest list of GoodRepo objects.
486*b7893ccfSSadaf Ebrahimi
487*b7893ccfSSadaf Ebrahimi    The known-good file is expected to be in the same
488*b7893ccfSSadaf Ebrahimi    directory as this script unless overridden by the 'known_good_dir'
489*b7893ccfSSadaf Ebrahimi    parameter.
490*b7893ccfSSadaf Ebrahimi    """
491*b7893ccfSSadaf Ebrahimi    if args.known_good_dir:
492*b7893ccfSSadaf Ebrahimi        known_good_file = os.path.join( os.path.abspath(args.known_good_dir),
493*b7893ccfSSadaf Ebrahimi            KNOWN_GOOD_FILE_NAME)
494*b7893ccfSSadaf Ebrahimi    else:
495*b7893ccfSSadaf Ebrahimi        known_good_file = os.path.join(
496*b7893ccfSSadaf Ebrahimi            os.path.dirname(os.path.abspath(__file__)), KNOWN_GOOD_FILE_NAME)
497*b7893ccfSSadaf Ebrahimi    with open(known_good_file) as known_good:
498*b7893ccfSSadaf Ebrahimi        return [
499*b7893ccfSSadaf Ebrahimi            GoodRepo(repo, args)
500*b7893ccfSSadaf Ebrahimi            for repo in json.loads(known_good.read())['repos']
501*b7893ccfSSadaf Ebrahimi        ]
502*b7893ccfSSadaf Ebrahimi
503*b7893ccfSSadaf Ebrahimi
504*b7893ccfSSadaf Ebrahimidef GetInstallNames(args):
505*b7893ccfSSadaf Ebrahimi    """Returns the install names list.
506*b7893ccfSSadaf Ebrahimi
507*b7893ccfSSadaf Ebrahimi    The known-good file is expected to be in the same
508*b7893ccfSSadaf Ebrahimi    directory as this script unless overridden by the 'known_good_dir'
509*b7893ccfSSadaf Ebrahimi    parameter.
510*b7893ccfSSadaf Ebrahimi    """
511*b7893ccfSSadaf Ebrahimi    if args.known_good_dir:
512*b7893ccfSSadaf Ebrahimi        known_good_file = os.path.join(os.path.abspath(args.known_good_dir),
513*b7893ccfSSadaf Ebrahimi            KNOWN_GOOD_FILE_NAME)
514*b7893ccfSSadaf Ebrahimi    else:
515*b7893ccfSSadaf Ebrahimi        known_good_file = os.path.join(
516*b7893ccfSSadaf Ebrahimi            os.path.dirname(os.path.abspath(__file__)), KNOWN_GOOD_FILE_NAME)
517*b7893ccfSSadaf Ebrahimi    with open(known_good_file) as known_good:
518*b7893ccfSSadaf Ebrahimi        install_info = json.loads(known_good.read())
519*b7893ccfSSadaf Ebrahimi        if install_info.get('install_names'):
520*b7893ccfSSadaf Ebrahimi            return install_info['install_names']
521*b7893ccfSSadaf Ebrahimi        else:
522*b7893ccfSSadaf Ebrahimi            return None
523*b7893ccfSSadaf Ebrahimi
524*b7893ccfSSadaf Ebrahimi
525*b7893ccfSSadaf Ebrahimidef CreateHelper(args, repos, filename):
526*b7893ccfSSadaf Ebrahimi    """Create a CMake config helper file.
527*b7893ccfSSadaf Ebrahimi
528*b7893ccfSSadaf Ebrahimi    The helper file is intended to be used with 'cmake -C <file>'
529*b7893ccfSSadaf Ebrahimi    to build this home repo using the dependencies built by this script.
530*b7893ccfSSadaf Ebrahimi
531*b7893ccfSSadaf Ebrahimi    The install_names dictionary represents the CMake variables used by the
532*b7893ccfSSadaf Ebrahimi    home repo to locate the install dirs of the dependent repos.
533*b7893ccfSSadaf Ebrahimi    This information is baked into the CMake files of the home repo and so
534*b7893ccfSSadaf Ebrahimi    this dictionary is kept with the repo via the json file.
535*b7893ccfSSadaf Ebrahimi    """
536*b7893ccfSSadaf Ebrahimi    def escape(path):
537*b7893ccfSSadaf Ebrahimi        return path.replace('\\', '\\\\')
538*b7893ccfSSadaf Ebrahimi    install_names = GetInstallNames(args)
539*b7893ccfSSadaf Ebrahimi    with open(filename, 'w') as helper_file:
540*b7893ccfSSadaf Ebrahimi        for repo in repos:
541*b7893ccfSSadaf Ebrahimi            if install_names and repo.name in install_names and repo.on_build_platform:
542*b7893ccfSSadaf Ebrahimi                helper_file.write('set({var} "{dir}" CACHE STRING "" FORCE)\n'
543*b7893ccfSSadaf Ebrahimi                                  .format(
544*b7893ccfSSadaf Ebrahimi                                      var=install_names[repo.name],
545*b7893ccfSSadaf Ebrahimi                                      dir=escape(repo.install_dir)))
546*b7893ccfSSadaf Ebrahimi
547*b7893ccfSSadaf Ebrahimi
548*b7893ccfSSadaf Ebrahimidef main():
549*b7893ccfSSadaf Ebrahimi    parser = argparse.ArgumentParser(
550*b7893ccfSSadaf Ebrahimi        description='Get and build dependent repos at known-good commits')
551*b7893ccfSSadaf Ebrahimi    parser.add_argument(
552*b7893ccfSSadaf Ebrahimi        '--known_good_dir',
553*b7893ccfSSadaf Ebrahimi        dest='known_good_dir',
554*b7893ccfSSadaf Ebrahimi        help="Specify directory for known_good.json file.")
555*b7893ccfSSadaf Ebrahimi    parser.add_argument(
556*b7893ccfSSadaf Ebrahimi        '--dir',
557*b7893ccfSSadaf Ebrahimi        dest='dir',
558*b7893ccfSSadaf Ebrahimi        default='.',
559*b7893ccfSSadaf Ebrahimi        help="Set target directory for repository roots. Default is \'.\'.")
560*b7893ccfSSadaf Ebrahimi    parser.add_argument(
561*b7893ccfSSadaf Ebrahimi        '--ref',
562*b7893ccfSSadaf Ebrahimi        dest='ref',
563*b7893ccfSSadaf Ebrahimi        default='',
564*b7893ccfSSadaf Ebrahimi        help="Override 'commit' with git reference. E.g., 'origin/master'")
565*b7893ccfSSadaf Ebrahimi    parser.add_argument(
566*b7893ccfSSadaf Ebrahimi        '--no-build',
567*b7893ccfSSadaf Ebrahimi        dest='do_build',
568*b7893ccfSSadaf Ebrahimi        action='store_false',
569*b7893ccfSSadaf Ebrahimi        help=
570*b7893ccfSSadaf Ebrahimi        "Clone/update repositories and generate build files without performing compilation",
571*b7893ccfSSadaf Ebrahimi        default=True)
572*b7893ccfSSadaf Ebrahimi    parser.add_argument(
573*b7893ccfSSadaf Ebrahimi        '--clean',
574*b7893ccfSSadaf Ebrahimi        dest='do_clean',
575*b7893ccfSSadaf Ebrahimi        action='store_true',
576*b7893ccfSSadaf Ebrahimi        help="Clean files generated by compiler and linker before building",
577*b7893ccfSSadaf Ebrahimi        default=False)
578*b7893ccfSSadaf Ebrahimi    parser.add_argument(
579*b7893ccfSSadaf Ebrahimi        '--clean-repo',
580*b7893ccfSSadaf Ebrahimi        dest='do_clean_repo',
581*b7893ccfSSadaf Ebrahimi        action='store_true',
582*b7893ccfSSadaf Ebrahimi        help="Delete repository directory before building",
583*b7893ccfSSadaf Ebrahimi        default=False)
584*b7893ccfSSadaf Ebrahimi    parser.add_argument(
585*b7893ccfSSadaf Ebrahimi        '--clean-build',
586*b7893ccfSSadaf Ebrahimi        dest='do_clean_build',
587*b7893ccfSSadaf Ebrahimi        action='store_true',
588*b7893ccfSSadaf Ebrahimi        help="Delete build directory before building",
589*b7893ccfSSadaf Ebrahimi        default=False)
590*b7893ccfSSadaf Ebrahimi    parser.add_argument(
591*b7893ccfSSadaf Ebrahimi        '--clean-install',
592*b7893ccfSSadaf Ebrahimi        dest='do_clean_install',
593*b7893ccfSSadaf Ebrahimi        action='store_true',
594*b7893ccfSSadaf Ebrahimi        help="Delete install directory before building",
595*b7893ccfSSadaf Ebrahimi        default=False)
596*b7893ccfSSadaf Ebrahimi    parser.add_argument(
597*b7893ccfSSadaf Ebrahimi        '--arch',
598*b7893ccfSSadaf Ebrahimi        dest='arch',
599*b7893ccfSSadaf Ebrahimi        choices=['32', '64', 'x86', 'x64', 'win32', 'win64'],
600*b7893ccfSSadaf Ebrahimi        type=str.lower,
601*b7893ccfSSadaf Ebrahimi        help="Set build files architecture (Windows)",
602*b7893ccfSSadaf Ebrahimi        default='64')
603*b7893ccfSSadaf Ebrahimi    parser.add_argument(
604*b7893ccfSSadaf Ebrahimi        '--config',
605*b7893ccfSSadaf Ebrahimi        dest='config',
606*b7893ccfSSadaf Ebrahimi        choices=['debug', 'release', 'relwithdebinfo', 'minsizerel'],
607*b7893ccfSSadaf Ebrahimi        type=str.lower,
608*b7893ccfSSadaf Ebrahimi        help="Set build files configuration",
609*b7893ccfSSadaf Ebrahimi        default='debug')
610*b7893ccfSSadaf Ebrahimi    parser.add_argument(
611*b7893ccfSSadaf Ebrahimi        '--generator',
612*b7893ccfSSadaf Ebrahimi        dest='generator',
613*b7893ccfSSadaf Ebrahimi        help="Set the CMake generator",
614*b7893ccfSSadaf Ebrahimi        default=None)
615*b7893ccfSSadaf Ebrahimi
616*b7893ccfSSadaf Ebrahimi    args = parser.parse_args()
617*b7893ccfSSadaf Ebrahimi    save_cwd = os.getcwd()
618*b7893ccfSSadaf Ebrahimi
619*b7893ccfSSadaf Ebrahimi    # Create working "top" directory if needed
620*b7893ccfSSadaf Ebrahimi    distutils.dir_util.mkpath(args.dir)
621*b7893ccfSSadaf Ebrahimi    abs_top_dir = os.path.abspath(args.dir)
622*b7893ccfSSadaf Ebrahimi
623*b7893ccfSSadaf Ebrahimi    repos = GetGoodRepos(args)
624*b7893ccfSSadaf Ebrahimi    repo_dict = {}
625*b7893ccfSSadaf Ebrahimi
626*b7893ccfSSadaf Ebrahimi    print('Starting builds in {d}'.format(d=abs_top_dir))
627*b7893ccfSSadaf Ebrahimi    for repo in repos:
628*b7893ccfSSadaf Ebrahimi        # If the repo has a platform whitelist, skip the repo
629*b7893ccfSSadaf Ebrahimi        # unless we are building on a whitelisted platform.
630*b7893ccfSSadaf Ebrahimi        if not repo.on_build_platform:
631*b7893ccfSSadaf Ebrahimi            continue
632*b7893ccfSSadaf Ebrahimi
633*b7893ccfSSadaf Ebrahimi        field_list = ('url',
634*b7893ccfSSadaf Ebrahimi                      'sub_dir',
635*b7893ccfSSadaf Ebrahimi                      'commit',
636*b7893ccfSSadaf Ebrahimi                      'build_dir',
637*b7893ccfSSadaf Ebrahimi                      'install_dir',
638*b7893ccfSSadaf Ebrahimi                      'deps',
639*b7893ccfSSadaf Ebrahimi                      'prebuild',
640*b7893ccfSSadaf Ebrahimi                      'prebuild_linux',
641*b7893ccfSSadaf Ebrahimi                      'prebuild_windows',
642*b7893ccfSSadaf Ebrahimi                      'custom_build',
643*b7893ccfSSadaf Ebrahimi                      'cmake_options',
644*b7893ccfSSadaf Ebrahimi                      'ci_only',
645*b7893ccfSSadaf Ebrahimi                      'build_step',
646*b7893ccfSSadaf Ebrahimi                      'build_platforms',
647*b7893ccfSSadaf Ebrahimi                      'repo_dir',
648*b7893ccfSSadaf Ebrahimi                      'on_build_platform')
649*b7893ccfSSadaf Ebrahimi        repo_dict[repo.name] = {field: getattr(repo, field) for field in field_list}
650*b7893ccfSSadaf Ebrahimi
651*b7893ccfSSadaf Ebrahimi        # If the repo has a CI whitelist, skip the repo unless
652*b7893ccfSSadaf Ebrahimi        # one of the CI's environment variable is set to true.
653*b7893ccfSSadaf Ebrahimi        if len(repo.ci_only):
654*b7893ccfSSadaf Ebrahimi            do_build = False
655*b7893ccfSSadaf Ebrahimi            for env in repo.ci_only:
656*b7893ccfSSadaf Ebrahimi                if not env in os.environ:
657*b7893ccfSSadaf Ebrahimi                    continue
658*b7893ccfSSadaf Ebrahimi                if os.environ[env].lower() == 'true':
659*b7893ccfSSadaf Ebrahimi                    do_build = True
660*b7893ccfSSadaf Ebrahimi                    break
661*b7893ccfSSadaf Ebrahimi            if not do_build:
662*b7893ccfSSadaf Ebrahimi                continue
663*b7893ccfSSadaf Ebrahimi
664*b7893ccfSSadaf Ebrahimi        # Clone/update the repository
665*b7893ccfSSadaf Ebrahimi        repo.Checkout()
666*b7893ccfSSadaf Ebrahimi
667*b7893ccfSSadaf Ebrahimi        # Build the repository
668*b7893ccfSSadaf Ebrahimi        if args.do_build and repo.build_step != 'skip':
669*b7893ccfSSadaf Ebrahimi            repo.Build(repos, repo_dict)
670*b7893ccfSSadaf Ebrahimi
671*b7893ccfSSadaf Ebrahimi    # Need to restore original cwd in order for CreateHelper to find json file
672*b7893ccfSSadaf Ebrahimi    os.chdir(save_cwd)
673*b7893ccfSSadaf Ebrahimi    CreateHelper(args, repos, os.path.join(abs_top_dir, 'helper.cmake'))
674*b7893ccfSSadaf Ebrahimi
675*b7893ccfSSadaf Ebrahimi    sys.exit(0)
676*b7893ccfSSadaf Ebrahimi
677*b7893ccfSSadaf Ebrahimi
678*b7893ccfSSadaf Ebrahimiif __name__ == '__main__':
679*b7893ccfSSadaf Ebrahimi    main()
680