diff --git a/DEPS b/DEPS index 719a844e5631..47270f56aa59 100644 --- a/DEPS +++ b/DEPS @@ -5,8 +5,6 @@ vars = { } deps = { - "vendor/requests": "https://github.com/kennethreitz/requests@e4d59bedfd3c7f4f254f4f5d036587bcd8152458", - "vendor/boto": "https://github.com/boto/boto@f7574aa6cc2c819430c1f05e9a1a1a666ef8169b", "vendor/python-patch": "https://github.com/brave/python-patch@d8880110be6554686bc08261766538c2926d4e82", "vendor/omaha": { "url": "https://github.com/brave/omaha.git@138c95d58f9c41113f7e0dd5acdbcaab8be20df9", diff --git a/patches/mojo-public-tools-bindings-generators-mojom_ts_generator.py.patch b/patches/mojo-public-tools-bindings-generators-mojom_ts_generator.py.patch new file mode 100644 index 000000000000..fb2681c84093 --- /dev/null +++ b/patches/mojo-public-tools-bindings-generators-mojom_ts_generator.py.patch @@ -0,0 +1,17 @@ +diff --git a/mojo/public/tools/bindings/generators/mojom_ts_generator.py b/mojo/public/tools/bindings/generators/mojom_ts_generator.py +index d8e0cf30486690b5aa33906985642dc8f7f762f5..1c43796152811d020370aa0a42bc4fddf8b05c06 100644 +--- a/mojo/public/tools/bindings/generators/mojom_ts_generator.py ++++ b/mojo/public/tools/bindings/generators/mojom_ts_generator.py +@@ -175,8 +175,10 @@ def _GetWebUiModulePath(module): + path. Otherwise, returned paths always end in a '/' and begin with either + `chrome://resources/` or a '/'.""" + path = module.metadata.get('webui_module_path') +- if path is None or path == '/': +- return path ++ if path is None: ++ return None ++ if path == '' or path == '/': ++ return '/' + if _IsAbsoluteChromeResourcesPath(path): + return path.rstrip('/') + '/' + return '/{}/'.format(path.strip('/')) diff --git a/script/audit_deps.py b/script/audit_deps.py index cf8ce007772c..cc892ed0701e 100755 --- a/script/audit_deps.py +++ b/script/audit_deps.py @@ -1,6 +1,5 @@ -#!/usr/bin/env python3 +#!/usr/bin/env vpython3 # pylint: disable=line-too-long - """This script runs `npm audit' and `cargo audit' on relevant paths in the repo.""" @@ -14,26 +13,25 @@ import os import subprocess import sys +import urllib.request -import requests def get_remote_audit_config( - url = "https://raw.githubusercontent.com/brave/audit-config/main/config.json", - retry = 3): - """Fetch additional audit configuration""" - s = requests.Session() - s.mount(url, requests.adapters.HTTPAdapter(max_retries=retry)) - return s.get(url).json() + url="https://raw.githubusercontent.com/brave/audit-config/main/config.json" +): + return json.loads(urllib.request.urlopen(url).read().decode("utf-8")) + REMOTE_AUDIT_CONFIG = get_remote_audit_config() -IGNORED_CARGO_ADVISORIES = [e["advisory"] for e in REMOTE_AUDIT_CONFIG["ignore"]["cargo"]] -IGNORED_NPM_ADVISORIES = [e["advisory"] for e in REMOTE_AUDIT_CONFIG["ignore"]["npm"]] +IGNORED_CARGO_ADVISORIES = [ + e["advisory"] for e in REMOTE_AUDIT_CONFIG["ignore"]["cargo"] +] +IGNORED_NPM_ADVISORIES = [ + e["advisory"] for e in REMOTE_AUDIT_CONFIG["ignore"]["npm"] +] # Use all (sub)paths except these for npm audit. -NPM_EXCLUDE_PATHS = [ - 'build', - os.path.join('node_modules') -] +NPM_EXCLUDE_PATHS = ['build', os.path.join('node_modules')] # Only check Cargo.lock for this path. CARGO_INCLUDE_PATH = os.path.join('third_party', 'rust') @@ -43,15 +41,11 @@ def main(): """Audit a specified path, or the whole project.""" if len(IGNORED_NPM_ADVISORIES) > 0: - print( - f"Ignoring NPM advisories " - f"{', '.join(map(str, IGNORED_NPM_ADVISORIES))}" - ) + print(f"Ignoring NPM advisories " + f"{', '.join(map(str, IGNORED_NPM_ADVISORIES))}") if len(IGNORED_CARGO_ADVISORIES) > 0: - print( - f"Ignoring Cargo advisories " - f"{', '.join(map(str, IGNORED_CARGO_ADVISORIES))}" - ) + print(f"Ignoring Cargo advisories " + f"{', '.join(map(str, IGNORED_CARGO_ADVISORIES))}") args = parse_args() errors = 0 @@ -59,8 +53,9 @@ def main(): if args.input_dir: return audit_path(os.path.abspath(args.input_dir), args) - for path in [os.path.dirname(os.path.dirname(args.source_root)), - args.source_root]: + for path in [ + os.path.dirname(os.path.dirname(args.source_root)), args.source_root + ]: errors += audit_path(path, args) for dir_path, dirs, _ in os.walk(args.source_root): @@ -101,8 +96,7 @@ def npm_audit_deps(path, args): # Don't support npm audit --production until dev dependencies are # correctly identified in package.json print('npm audit --production not supported; auditing dev dependencies') - audit_process = subprocess.Popen( - npm_args, stdout=subprocess.PIPE, cwd=path) + audit_process = subprocess.Popen(npm_args, stdout=subprocess.PIPE, cwd=path) output, _ = audit_process.communicate() try: @@ -172,7 +166,8 @@ def parse_args(): parser = argparse.ArgumentParser(description='Audit brave-core npm deps') parser.add_argument('input_dir', nargs='?', help='Directory to check') - parser.add_argument('--source_root', required=True, + parser.add_argument('--source_root', + required=True, help='Full path of the src/brave directory') parser.add_argument('--cargo_audit_exe', required=True) parser.add_argument('--audit_dev_deps', diff --git a/script/bootstrap.py b/script/bootstrap.py index a32f7908a38a..880042bd6058 100755 --- a/script/bootstrap.py +++ b/script/bootstrap.py @@ -9,31 +9,20 @@ import os import sys -from lib.config import PLATFORM, SOURCE_ROOT, \ - enable_verbose_mode, is_verbose_mode +from lib.config import PLATFORM, enable_verbose_mode, is_verbose_mode from lib.util import execute_stdout, scoped_cwd - -VENDOR_DIR = os.path.join(SOURCE_ROOT, 'vendor') -PYTHON_26_URL = 'https://chromium.googlesource.com/chromium/deps/python_26' - NPM = 'npm' if sys.platform in ['win32', 'cygwin']: NPM += '.cmd' - def main(): - os.chdir(SOURCE_ROOT) - args = parse_args() if not args.yes and PLATFORM != 'win32': check_root() if args.verbose: enable_verbose_mode() - if sys.platform == 'cygwin': - update_win32_python() - setup_python_libs() update_node_modules('.') @@ -45,10 +34,8 @@ def parse_args(): action='store_true', help='Run non-interactively by assuming "yes" to all ' 'prompts.') - return parser.parse_args() - def check_root(): if os.geteuid() == 0: # pylint: disable=no-member print("We suggest not running this as root, unless you're really sure.") @@ -56,13 +43,6 @@ def check_root(): if choice not in ('y', 'Y'): sys.exit(0) - -def setup_python_libs(): - for lib in ('requests', 'boto'): - with scoped_cwd(os.path.join(VENDOR_DIR, lib)): - execute_stdout([sys.executable, 'setup.py', 'build']) - - def update_node_modules(dirname, env=None): if env is None: env = os.environ.copy() @@ -73,11 +53,5 @@ def update_node_modules(dirname, env=None): execute_stdout(args, env) -def update_win32_python(): - with scoped_cwd(VENDOR_DIR): - if not os.path.exists('python_26'): - execute_stdout(['git', 'clone', PYTHON_26_URL]) - - if __name__ == '__main__': sys.exit(main()) diff --git a/script/brave_license_helper.py b/script/brave_license_helper.py index 9d1fd0ad77f0..46e5d4d476ad 100644 --- a/script/brave_license_helper.py +++ b/script/brave_license_helper.py @@ -56,11 +56,6 @@ def AddBraveCredits(root, prune_paths, special_cases, prune_dirs, "URL": "https://github.com/brave-intl/bat-native-bip39wally-core", "License": "MIT", }, - os.path.join('brave', 'vendor', 'boto'): { - "Name": "boto", - "URL": "https://github.com/boto/boto", - "License": "MIT", - }, os.path.join('brave', 'vendor', 'brave-extension'): { "Name": "Brave Only Extension", "URL": "https://github.com/brave/brave-extension", @@ -135,11 +130,6 @@ def AddBraveCredits(root, prune_paths, special_cases, prune_dirs, "License": "MIT", "License File": ["/brave/vendor/python-patch/doc/LICENSE"], }, - os.path.join('brave', 'vendor', 'requests'): { - "Name": "Requests", - "URL": "https://github.com/psf/requests", - "License": "Apache-2.0", - }, os.path.join('brave', 'vendor', 'sparkle'): { "Name": "Sparkle", "URL": "https://github.com/brave/Sparkle", diff --git a/script/bump-version.py b/script/bump-version.py deleted file mode 100755 index 4ecd6ac9257f..000000000000 --- a/script/bump-version.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env python - -import os -import re -import sys -from lib.config import SOURCE_ROOT, get_brave_version, get_chrome_version -from lib.util import execute, parse_version, scoped_cwd - - -def main(): - if len(sys.argv) != 2 or sys.argv[1] == '-h': - print 'Usage: bump-version.py [ | major | minor | patch]' - return 1 - - option = sys.argv[1] - increments = ['major', 'minor', 'patch'] - if option in increments: - version = get_brave_version() - versions = parse_version(version.split('-')[0]) - versions = increase_version(versions, increments.index(option)) - chrome = get_chrome_version() - else: - versions = parse_version(option) - chrome = versions[3] - - version = '.'.join(versions[:3]) - version = version + '+' + chrome - - with scoped_cwd(SOURCE_ROOT): - update_package_json(version) - tag_version(version) - - -def increase_version(versions, index): - for i in range(index + 1, 3): - versions[i] = '0' - versions[index] = str(int(versions[index]) + 1) - return versions - - -def update_package_json(version): - package_json = 'package.json' - with open(package_json, 'r') as f: - lines = f.readlines() - - for i in range(0, len(lines)): - line = lines[i] - if 'version' in line: - lines[i] = ' "version": "{0}",\n'.format(version) - break - - with open(package_json, 'w') as f: - f.write(''.join(lines)) - - -def tag_version(version): - execute(['git', 'commit', '-a', '-m', 'Bump v{0}'.format(version)]) - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/script/lib/connect.py b/script/lib/connect.py deleted file mode 100644 index 70294bfecf5d..000000000000 --- a/script/lib/connect.py +++ /dev/null @@ -1,22 +0,0 @@ -import base64 -import mimetypes -import requests - - -def get_content_type(filename): - return mimetypes.guess_type(filename)[0] or 'application/octet-stream' - - -def get(url, headers): - response = requests.get(url, headers=headers) - return response - - -def post(url, params, headers): - response = requests.post(url, json=params, headers=headers) - return response - - -def post_with_file(url, files, params, headers): - response = requests.post(url, files=files, data=params, headers=headers) - return response diff --git a/script/lib/github.py b/script/lib/github.py index a452ed9e9226..899035bd08cd 100644 --- a/script/lib/github.py +++ b/script/lib/github.py @@ -1,30 +1,26 @@ -#!/usr/bin/env python +# Copyright (c) 2018 The Brave Authors. All rights reserved. +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at https://mozilla.org/MPL/2.0/. from __future__ import print_function from __future__ import absolute_import from builtins import str -from builtins import object import json -import os -import re -import requests -import sys import base64 +import re +import urllib.request try: from .util import execute, scoped_cwd except ImportError: pass -REQUESTS_DIR = os.path.abspath(os.path.join(__file__, '..', '..', '..', - 'vendor', 'requests')) -sys.path.append(os.path.join(REQUESTS_DIR, 'build', 'lib')) -sys.path.append(os.path.join(REQUESTS_DIR, 'build', 'lib.linux-x86_64-2.7')) - GITHUB_URL = 'https://api.github.com' GITHUB_UPLOAD_ASSET_URL = 'https://uploads.github.com' -class GitHub(object): +class GitHub(): + def __init__(self, access_token): self._authorization = 'token %s' % access_token @@ -52,7 +48,8 @@ def send(self, method, path, **kw): kw['data'] = json.dumps(kw['data']) try: - r = getattr(requests, method)(url, **kw).json() + kw['method'] = method + r = json.loads(urllib.request.urlopen(url, **kw).read()) except ValueError: # Returned response may be empty in some cases r = {} @@ -61,7 +58,8 @@ def send(self, method, path, **kw): return r -class _Executable(object): +class _Executable(): + def __init__(self, gh, method, path): self._gh = gh self._method = method @@ -71,7 +69,8 @@ def __call__(self, **kw): return self._gh.send(self._method, self._path, **kw) -class _Callable(object): +class _Callable(): + def __init__(self, gh, name): self._gh = gh self._name = name @@ -91,9 +90,12 @@ def __getattr__(self, attr): return _Callable(self._gh, name) +# pylint: disable=inconsistent-return-statements def get_authenticated_user_login(token): - """given a valid GitHub access token, return the associated GitHub user login""" - # for more info see: https://developer.github.com/v3/users/#get-the-authenticated-user + """given a valid GitHub access token, return the associated GitHub user + login""" + # for more info see: + # https://developer.github.com/v3/users/#get-the-authenticated-user user = GitHub(token).user() try: response = user.get() @@ -103,7 +105,8 @@ def get_authenticated_user_login(token): def parse_user_logins(token, login_csv, verbose=False): - """given a list of logins in csv format, parse into a list and validate logins""" + """given a list of logins in csv format, parse into a list and validate + logins""" if login_csv is None: return [] login_csv = login_csv.replace(" ", "") @@ -114,7 +117,8 @@ def parse_user_logins(token, login_csv, verbose=False): invalid_logins = [] # check login/username against GitHub - # for more info see: https://developer.github.com/v3/users/#get-a-single-user + # for more info see: + # https://developer.github.com/v3/users/#get-a-single-user for login in parsed_logins: try: response = users(login).get() @@ -127,14 +131,13 @@ def parse_user_logins(token, login_csv, verbose=False): invalid_logins.append(login) if len(invalid_logins) > 0: - raise Exception( - 'Invalid logins found. Are they misspelled? ' + ','.join(invalid_logins)) + raise Exception('Invalid logins found. Are they misspelled? ' + + ','.join(invalid_logins)) return parsed_logins def parse_labels(token, repo_name, label_csv, verbose=False): - global config if label_csv is None: return [] label_csv = label_csv.replace(" ", "") @@ -143,7 +146,8 @@ def parse_labels(token, repo_name, label_csv, verbose=False): invalid_labels = [] # validate labels passed in are correct - # for more info see: https://developer.github.com/v3/issues/labels/#get-a-single-label + # for more info see: + # https://developer.github.com/v3/issues/labels/#get-a-single-label repo = GitHub(token).repos(repo_name) for label in parsed_labels: try: @@ -157,8 +161,8 @@ def parse_labels(token, repo_name, label_csv, verbose=False): invalid_labels.append(label) if len(invalid_labels) > 0: - raise Exception( - 'Invalid labels found. Are they misspelled? ' + ','.join(invalid_labels)) + raise Exception('Invalid labels found. Are they misspelled? ' + + ','.join(invalid_labels)) return parsed_labels @@ -176,8 +180,15 @@ def get_file_contents(token, repo_name, filename, branch=None): return file['content'] -def add_reviewers_to_pull_request(token, repo_name, pr_number, reviewers=[], team_reviewers=[], - verbose=False, dryrun=False): +# pylint: disable=dangerous-default-value +# pylint: disable=inconsistent-return-statements +def add_reviewers_to_pull_request(token, + repo_name, + pr_number, + reviewers=[], + team_reviewers=[], + verbose=False, + dryrun=False): # add reviewers to pull request # for more info see: https://developer.github.com/v3/pulls/review_requests/ repo = GitHub(token).repos(repo_name) @@ -207,8 +218,15 @@ def get_milestones(token, repo_name, verbose=False): return response -def create_pull_request(token, repo_name, title, body, branch_src, branch_dst, - open_in_browser=False, verbose=False, dryrun=False): +def create_pull_request(token, + repo_name, + title, + body, + branch_src, + branch_dst, + open_in_browser=False, + verbose=False, + dryrun=False): post_data = { 'title': title, 'head': branch_src, @@ -228,13 +246,21 @@ def create_pull_request(token, repo_name, title, body, branch_src, branch_dst, if verbose: print('repo.pulls.post(data) response:\n' + str(response)) if open_in_browser: + # pylint: disable=import-outside-toplevel import webbrowser webbrowser.open(response['html_url']) return int(response['number']) -def set_issue_details(token, repo_name, issue_number, milestone_number=None, - assignees=[], labels=[], verbose=False, dryrun=False): +# pylint: disable=dangerous-default-value +def set_issue_details(token, + repo_name, + issue_number, + milestone_number=None, + assignees=[], + labels=[], + verbose=False, + dryrun=False): patch_data = {} if milestone_number: patch_data['milestone'] = milestone_number @@ -247,18 +273,19 @@ def set_issue_details(token, repo_name, issue_number, milestone_number=None, # add milestone and assignee to issue / pull request # for more info see: https://developer.github.com/v3/issues/#edit-an-issue if dryrun: - print('[INFO] would call `repo.issues(' + - str(issue_number) + ').patch(' + str(patch_data) + ')`') + print('[INFO] would call `repo.issues(' + str(issue_number) + + ').patch(' + str(patch_data) + ')`') return repo = GitHub(token).repos(repo_name) response = repo.issues(issue_number).patch(data=patch_data) if verbose: - print('repo.issues(' + str(issue_number) + - ').patch(data) response:\n' + str(response)) + print('repo.issues(' + str(issue_number) + ').patch(data) response:\n' + + str(response)) def fetch_origin_check_staged(path): - """given a path on disk (to a git repo), fetch origin and ensure there aren't unstaged files""" + """given a path on disk (to a git repo), fetch origin and ensure there + aren't unstaged files""" with scoped_cwd(path): execute(['git', 'fetch', 'origin']) status = execute(['git', 'status', '-s']).strip() @@ -277,14 +304,14 @@ def get_local_branch_name(path): def get_title_from_first_commit(path, branch_to_compare): """get the first commit subject (useful for the title of a pull request)""" with scoped_cwd(path): - local_branch = execute( - ['git', 'rev-parse', '--abbrev-ref', 'HEAD']).strip() - title_list = execute(['git', 'log', 'origin/' + branch_to_compare + - '..HEAD', '--pretty=format:%s', '--reverse']) + title_list = execute([ + 'git', 'log', 'origin/' + branch_to_compare + '..HEAD', + '--pretty=format:%s', '--reverse' + ]) title_list = title_list.split('\n') if len(title_list) == 0: - raise Exception( - 'No commits found! Local branch matches "' + branch_to_compare + '"') + raise Exception('No commits found! Local branch matches "' + + branch_to_compare + '"') return title_list[0] @@ -301,8 +328,7 @@ def push_branches_to_remote(path, branches_to_push, dryrun=False, token=None): ['git', 'remote', 'get-url', '--push', 'origin']).strip() if response.startswith('https://'): if len(str(token)) == 0: - raise Exception( - 'GitHub token cannot be null or empty!') + raise Exception('GitHub token cannot be null or empty!') remote = response.replace( 'https://', 'https://' + token + ':x-oauth-basic@') execute(['git', 'push', '-u', remote, branch_to_push]) diff --git a/script/lib/helpers.py b/script/lib/helpers.py index dc43aac6ee4c..f2a1af914773 100644 --- a/script/lib/helpers.py +++ b/script/lib/helpers.py @@ -1,12 +1,13 @@ -#!/usr/bin/env python +# Copyright (c) 2018 The Brave Authors. All rights reserved. # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this file, -# You can obtain one at http://mozilla.org/MPL/2.0/. +# You can obtain one at https://mozilla.org/MPL/2.0/. from __future__ import print_function from builtins import range import os -import requests +import sys +import urllib.request from .config import get_raw_version, get_env_var BRAVE_REPO = "brave/brave-browser" @@ -24,19 +25,19 @@ def get_channel_display_name(): return d[release_channel()] +# pylint: disable=inconsistent-return-statements def call_github_api(url, headers): try: - r = requests.get(url, headers=headers) - except requests.exceptions.ConnectionError: + r = urllib.request(url, headers=headers) + except urllib.error.URLError: print("Error: Received requests.exceptions.ConnectionError, Exiting...") - exit(1) - except Exception as e: - raise Exception(e) + sys.exit(1) if r.status_code == 200: return r +# pylint: disable=unused-argument def get_releases_by_tag(repo, tag_name, include_drafts=False): GITHUB_URL = 'https://api.github.com' diff --git a/script/lib/util.py b/script/lib/util.py index 95ad82819094..944463771029 100644 --- a/script/lib/util.py +++ b/script/lib/util.py @@ -5,12 +5,9 @@ from __future__ import print_function -import argparse import atexit import contextlib import errno -import platform -import re import shutil import ssl import subprocess @@ -27,52 +24,6 @@ from .config import is_verbose_mode from .env_util import get_vs_env -_PLATFORM_MAPPING = { - 'cygwin': 'win', - 'darwin': 'mac', - 'linux2': 'linux', - 'linux': 'linux', - 'win32': 'win', -} - -BOTO_DIR = os.path.abspath(os.path.join(__file__, '..', '..', '..', 'vendor', - 'boto')) - - -def get_host_os(): - """Returns the host OS with a predictable string.""" - if sys.platform in _PLATFORM_MAPPING: - return _PLATFORM_MAPPING[sys.platform] - - try: - return os.uname().sysname.lower() - except AttributeError: - return sys.platform - - -def get_host_arch(): - """Returns the host architecture with a predictable string.""" - host_arch = platform.machine() - - # Convert machine type to format recognized by gyp. - if re.match(r'i.86', host_arch) or host_arch == 'i86pc': - host_arch = 'ia32' - elif host_arch in ['x86_64', 'amd64']: - host_arch = 'x64' - elif host_arch.startswith('arm64') or host_arch.startswith('aarch64'): - host_arch = 'arm64' - elif host_arch.startswith('arm'): - host_arch = 'arm' - - # platform.machine is based on running kernel. It's possible to use 64-bit - # kernel with 32-bit userland, e.g. to give linker slightly more memory. - # Distinguish between different userland bitness by querying - # the python binary. - if host_arch == 'x64' and platform.architecture()[0] == '32bit': - host_arch = 'ia32' - - return host_arch - def tempdir(prefix=''): directory = tempfile.mkdtemp(prefix=prefix) @@ -263,68 +214,3 @@ def execute_stdout(argv, env=os.environ): raise e else: execute(argv, env) - - -def parse_version(version): - if version[0] == 'v': - version = version[1:] - - vs = version.split('+')[0] - vs = vs.split('.') - - if len(version.split('+')) == 2: - vs = vs + [version.split('+')[1]] - - return vs - - -def boto_path_dirs(): - return [ - os.path.join(BOTO_DIR, 'build', 'lib'), - os.path.join(BOTO_DIR, 'build', 'lib.linux-x86_64-2.7') - ] - - -def run_boto_script(access_key, secret_key, script_name, *args): - env = os.environ.copy() - env['AWS_ACCESS_KEY_ID'] = access_key - env['AWS_SECRET_ACCESS_KEY'] = secret_key - env['PYTHONPATH'] = os.path.pathsep.join( - [env.get('PYTHONPATH', '')] + boto_path_dirs()) - - boto = os.path.join(BOTO_DIR, 'bin', script_name) - execute([sys.executable, boto] + list(args), env) - - -def s3put(bucket, access_key, secret_key, prefix, key_prefix, files): - args = [ - '--bucket', bucket, - '--prefix', prefix, - '--key_prefix', key_prefix, - '--grant', 'public-read' - ] + files - - run_boto_script(access_key, secret_key, 's3put', *args) - - -def import_vs_env(target_arch): - if sys.platform != 'win32': - return - - if target_arch == 'ia32': - vs_arch = 'amd64_x86' - else: - vs_arch = 'x86_amd64' - env = get_vs_env('14.0', vs_arch) - os.environ.update(env) - - -def str2bool(v): - if isinstance(v, bool): - return v - v = v.lower() - if v in ('yes', 'true', 't', 'y', '1'): - return True - if v in ('no', 'false', 'f', 'n', '0'): - return False - raise argparse.ArgumentTypeError('Boolean value expected.')