| ############################################################################# |
| ## |
| ## Copyright (C) 2016 The Qt Company Ltd. |
| ## Contact: https://www.qt.io/licensing/ |
| ## |
| ## This file is part of the QtWebEngine module of the Qt Toolkit. |
| ## |
| ## $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
| ## Commercial License Usage |
| ## Licensees holding valid commercial Qt licenses may use this file in |
| ## accordance with the commercial license agreement provided with the |
| ## Software or, alternatively, in accordance with the terms contained in |
| ## a written agreement between you and The Qt Company. For licensing terms |
| ## and conditions see https://www.qt.io/terms-conditions. For further |
| ## information use the contact form at https://www.qt.io/contact-us. |
| ## |
| ## GNU General Public License Usage |
| ## Alternatively, this file may be used under the terms of the GNU |
| ## General Public License version 3 as published by the Free Software |
| ## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
| ## included in the packaging of this file. Please review the following |
| ## information to ensure the GNU General Public License requirements will |
| ## be met: https://www.gnu.org/licenses/gpl-3.0.html. |
| ## |
| ## $QT_END_LICENSE$ |
| ## |
| ############################################################################# |
| |
| import glob |
| import os |
| import re |
| import subprocess |
| import sys |
| import version_resolver as resolver |
| |
| extra_os = ['mac', 'win'] |
| |
| def subprocessCall(args): |
| print args |
| return subprocess.call(args) |
| |
| def subprocessCheckOutput(args): |
| print args |
| return subprocess.check_output(args) |
| |
| class DEPSParser: |
| def __init__(self): |
| self.global_scope = { |
| 'Var': lambda var_name: '{%s}' % var_name, |
| 'deps_os': {}, |
| } |
| self.local_scope = {} |
| self.topmost_supermodule_path_prefix = '' |
| |
| def get_vars(self): |
| """Returns a dictionary of effective variable values |
| (DEPS file contents with applied custom_vars overrides).""" |
| result = {} |
| # Variables defined in DEPS file override built-in ones. |
| result.update(self.local_scope["vars"]) |
| #result.update(self.custom_vars or {}) |
| return result |
| |
| def get_recursedeps(self): |
| return self.local_scope["recursedeps"] |
| |
| def createSubmodulesFromScope(self, scope, os): |
| submodules = [] |
| for dep in scope: |
| url = '' |
| if (type(scope[dep]) == str): |
| url = scope[dep] |
| elif (type(scope[dep]) == dict and 'url' in scope[dep]): |
| url = scope[dep]['url'] |
| |
| if ('condition' in scope[dep]) and (not 'checkout_linux' in scope[dep]['condition']): |
| url = '' |
| |
| if url: |
| url = url.format(**self.get_vars()) |
| repo_rev = url.split('@') |
| repo = repo_rev[0] |
| rev = repo_rev[1] |
| subdir = dep |
| if subdir.startswith('src/'): |
| subdir = subdir[4:] |
| # Don't skip submodules that have a supermodule path prefix set (at the moment these |
| # are 2nd level deep submodules). |
| elif not self.topmost_supermodule_path_prefix: |
| # Ignore the information about chromium itself since we get that from git, |
| # also ignore anything outside src/ (e.g. depot_tools) |
| continue |
| |
| submodule = Submodule(subdir, repo, sp=self.topmost_supermodule_path_prefix) |
| submodule.os = os |
| |
| if not submodule.matchesOS(): |
| print '-- skipping ' + submodule.pathRelativeToTopMostSupermodule() + ' for this operating system. --' |
| continue |
| |
| if len(rev) == 40: # Length of a git shasum |
| submodule.ref = rev |
| elif len(rev) == 0: |
| submodule.ref = 'master' |
| else: |
| sys.exit("Invalid shasum: " + str(url)) |
| submodules.append(submodule) |
| return submodules |
| |
| def parse(self, deps_content): |
| exec(deps_content, self.global_scope, self.local_scope) |
| |
| submodules = [] |
| submodules.extend(self.createSubmodulesFromScope(self.local_scope['deps'], 'all')) |
| if 'deps_os' in self.local_scope: |
| for os_dep in self.local_scope['deps_os']: |
| submodules.extend(self.createSubmodulesFromScope(self.local_scope['deps_os'][os_dep], os_dep)) |
| return submodules |
| |
| # Strips suffix from end of text. |
| def strip_end(text, suffix): |
| if not text.endswith(suffix): |
| return text |
| return text[:len(text)-len(suffix)] |
| |
| # Given supermodule_path = /chromium |
| # current directory = /chromium/buildtools |
| # submodule_path = third_party/foo/bar |
| # returns = buildtools |
| def computeRelativePathPrefixToTopMostSupermodule(submodule_path, supermodule_path): |
| relpath = os.path.relpath(submodule_path, supermodule_path) |
| topmost_supermodule_path_prefix = strip_end(relpath, submodule_path) |
| return topmost_supermodule_path_prefix |
| |
| class Submodule: |
| def __init__(self, path='', url='', ref='', os=[], sp=''): |
| self.path = path |
| self.url = url |
| self.ref = ref |
| self.os = os |
| self.topmost_supermodule_path_prefix = sp |
| |
| def pathRelativeToTopMostSupermodule(self): |
| return os.path.normpath(os.path.join(self.topmost_supermodule_path_prefix, self.path)) |
| |
| def matchesOS(self): |
| if not self.os: |
| return True |
| if 'all' in self.os: |
| return True |
| if sys.platform.startswith('linux') and 'unix' in self.os: |
| return True |
| if sys.platform.startswith('darwin') and ('unix' in self.os or 'mac' in self.os): |
| return True |
| if sys.platform.startswith('win32') or sys.platform.startswith('cygwin'): |
| if 'win' in self.os: |
| return True |
| else: |
| # Skipping all dependecies of the extra_os on Windows platform, because it caused confict. |
| return False |
| for os in extra_os: |
| if os in self.os: |
| return True |
| return False |
| |
| def findShaAndCheckout(self): |
| oldCwd = os.getcwd() |
| os.chdir(self.path) |
| |
| # Fetch the shasum we parsed from the DEPS file. |
| error = subprocessCall(['git', 'fetch', 'origin', self.ref]) |
| if error != 0: |
| print('ERROR: Could not fetch ' + self.ref + ' from upstream origin.') |
| return error |
| |
| error = subprocessCall(['git', 'checkout', 'FETCH_HEAD']); |
| |
| current_shasum = subprocessCheckOutput(['git', 'rev-parse', 'HEAD']).strip() |
| current_tag = subprocessCheckOutput(['git', 'name-rev', '--tags', '--name-only', current_shasum]).strip() |
| |
| if current_tag == resolver.currentVersion(): |
| # We checked out a tagged version of chromium. |
| self.ref = current_shasum |
| |
| if not self.ref: |
| # No shasum could be deduced, use the submodule shasum. |
| os.chdir(oldCwd) |
| line = subprocessCheckOutput(['git', 'submodule', 'status', self.path]) |
| os.chdir(self.path) |
| line = line.lstrip(' -') |
| self.ref = line.split(' ')[0] |
| |
| if not self.ref.startswith(current_shasum): |
| # In case HEAD differs check out the actual shasum we require. |
| subprocessCall(['git', 'fetch']) |
| error = subprocessCall(['git', 'checkout', self.ref]) |
| os.chdir(oldCwd) |
| return error |
| |
| def findGitDir(self): |
| try: |
| return subprocessCheckOutput(['git', 'rev-parse', '--git-dir']).strip() |
| except subprocess.CalledProcessError, e: |
| sys.exit("git dir could not be determined! - Initialization failed! " + e.output) |
| |
| def reset(self): |
| currentDir = os.getcwd() |
| os.chdir(self.path) |
| gitdir = self.findGitDir() |
| if os.path.isdir(os.path.join(gitdir, 'rebase-merge')): |
| if os.path.isfile(os.path.join(gitdir, 'MERGE_HEAD')): |
| print 'merge in progress... aborting merge.' |
| subprocessCall(['git', 'merge', '--abort']) |
| else: |
| print 'rebase in progress... aborting merge.' |
| subprocessCall(['git', 'rebase', '--abort']) |
| if os.path.isdir(os.path.join(gitdir, 'rebase-apply')): |
| print 'am in progress... aborting am.' |
| subprocessCall(['git', 'am', '--abort']) |
| subprocessCall(['git', 'reset', '--hard']) |
| os.chdir(currentDir) |
| |
| def initialize(self): |
| if self.matchesOS(): |
| print '\n\n-- initializing ' + self.pathRelativeToTopMostSupermodule() + ' --' |
| oldCwd = os.getcwd() |
| |
| # The submodule operations should be done relative to the current submodule's |
| # supermodule. |
| if self.topmost_supermodule_path_prefix: |
| if not os.path.isdir(self.path): |
| print '-- skipping ' + self.path + ' as dir has been stripped. --' |
| return |
| os.chdir(self.topmost_supermodule_path_prefix) |
| |
| if os.path.isdir(self.path): |
| self.reset() |
| |
| if self.url: |
| subprocessCall(['git', 'submodule', 'add', '-f', self.url, self.path]) |
| subprocessCall(['git', 'submodule', 'sync', '--', self.path]) |
| subprocessCall(['git', 'submodule', 'init', self.path]) |
| subprocessCall(['git', 'submodule', 'update', self.path]) |
| |
| if '3rdparty_upstream' in os.path.abspath(self.path): |
| if self.findShaAndCheckout() != 0: |
| sys.exit("!!! initialization failed !!!") |
| |
| # Add baseline commit for upstream repository to be able to reset. |
| os.chdir(self.path) |
| commit = subprocessCheckOutput(['git', 'rev-list', '--max-count=1', 'HEAD']) |
| subprocessCall(['git', 'commit', '-a', '--allow-empty', '-m', '-- QtWebEngine baseline --\n\ncommit ' + commit]) |
| |
| os.chdir(oldCwd) |
| else: |
| print '-- skipping ' + self.path + ' for this operating system. --' |
| |
| def listFiles(self): |
| if self.matchesOS() and os.path.isdir(self.pathRelativeToTopMostSupermodule()): |
| currentDir = os.getcwd() |
| os.chdir(self.pathRelativeToTopMostSupermodule()) |
| files = subprocessCheckOutput(['git', 'ls-files']).splitlines() |
| os.chdir(currentDir) |
| return files |
| else: |
| print '-- skipping ' + self.path + ' for this operating system. --' |
| return [] |
| |
| def parseGitModulesFileContents(self, gitmodules_lines): |
| submodules = [] |
| currentSubmodule = None |
| for line in gitmodules_lines: |
| if line.find('[submodule') == 0: |
| if currentSubmodule: |
| submodules.append(currentSubmodule) |
| currentSubmodule = Submodule() |
| tokens = line.split('=') |
| if len(tokens) >= 2: |
| key = tokens[0].strip() |
| value = tokens[1].strip() |
| if key == 'path': |
| currentSubmodule.path = value |
| elif key == 'url': |
| currentSubmodule.url = value |
| elif key == 'os': |
| currentSubmodule.os = value.split(',') |
| if currentSubmodule: |
| submodules.append(currentSubmodule) |
| return submodules |
| |
| # Return a flattened list of submodules starting from module, and recursively collecting child |
| # submodules. |
| def readSubmodulesFromGitModules(self, module, gitmodules_file_name, top_level_path): |
| flattened_submodules = [] |
| oldCwd = os.getcwd() |
| os.chdir(module.path) |
| |
| if os.path.isfile(gitmodules_file_name): |
| gitmodules_file = open(gitmodules_file_name) |
| gitmodules_lines = gitmodules_file.readlines() |
| gitmodules_file.close() |
| submodules = self.parseGitModulesFileContents(gitmodules_lines) |
| |
| # When inside a 2nd level submodule or deeper, store the path relative to the topmost |
| # module. |
| for submodule in submodules: |
| submodule.topmost_supermodule_path_prefix = computeRelativePathPrefixToTopMostSupermodule(submodule.path, top_level_path) |
| |
| flattened_submodules.extend(submodules) |
| |
| # Recurse into deeper submodules. |
| for submodule in submodules: |
| flattened_submodules.extend(self.readSubmodulesFromGitModules(submodule, gitmodules_file_name, top_level_path)) |
| |
| os.chdir(oldCwd) |
| return flattened_submodules |
| |
| def readSubmodules(self, use_deps=False): |
| submodules = [] |
| if use_deps: |
| submodules = resolver.readSubmodules() |
| print 'DEPS file provides the following submodules:' |
| for submodule in submodules: |
| print '{:<80}'.format(submodule.pathRelativeToTopMostSupermodule()) + '{:<120}'.format(submodule.url) + submodule.ref |
| else: # Try .gitmodules instead |
| gitmodules_file_name = '.gitmodules' |
| submodules = self.readSubmodulesFromGitModules(self, gitmodules_file_name, self.path) |
| return submodules |
| |
| def initSubmodules(self): |
| oldCwd = os.getcwd() |
| os.chdir(self.path) |
| submodules = self.readSubmodules(True) |
| for submodule in submodules: |
| submodule.initialize() |
| subprocessCall(['git', 'commit', '-a', '--amend', '--no-edit']) |
| os.chdir(oldCwd) |