| # Copyright (C) 2018 and later: Unicode, Inc. and others. | |
| # License & terms of use: http://www.unicode.org/copyright.html | |
| # Python 2/3 Compatibility (ICU-20299) | |
| # TODO(ICU-20301): Remove this. | |
| from __future__ import print_function | |
| from . import * | |
| from .. import * | |
| from .. import utils | |
| from ..request_types import * | |
| import os | |
| import shutil | |
| import subprocess | |
| import sys | |
| def run(build_dirs, requests, common_vars, verbose=True, **kwargs): | |
| for bd in build_dirs: | |
| makedirs(bd.format(**common_vars)) | |
| for request in requests: | |
| status = run_helper(request, common_vars, verbose=verbose, **kwargs) | |
| if status != 0: | |
| print("!!! ERROR executing above command line: exit code %d" % status) | |
| return 1 | |
| if verbose: | |
| print("All data build commands executed") | |
| return 0 | |
| def makedirs(dirs): | |
| """makedirs compatible between Python 2 and 3""" | |
| try: | |
| # Python 3 version | |
| os.makedirs(dirs, exist_ok=True) | |
| except TypeError as e: | |
| # Python 2 version | |
| try: | |
| os.makedirs(dirs) | |
| except OSError as e: | |
| if e.errno != errno.EEXIST: | |
| raise e | |
| def run_helper(request, common_vars, platform, tool_dir, verbose, tool_cfg=None, **kwargs): | |
| if isinstance(request, PrintFileRequest): | |
| output_path = "{DIRNAME}/{FILENAME}".format( | |
| DIRNAME = utils.dir_for(request.output_file).format(**common_vars), | |
| FILENAME = request.output_file.filename, | |
| ) | |
| if verbose: | |
| print("Printing to file: %s" % output_path) | |
| with open(output_path, "w") as f: | |
| f.write(request.content) | |
| return 0 | |
| if isinstance(request, CopyRequest): | |
| input_path = "{DIRNAME}/{FILENAME}".format( | |
| DIRNAME = utils.dir_for(request.input_file).format(**common_vars), | |
| FILENAME = request.input_file.filename, | |
| ) | |
| output_path = "{DIRNAME}/{FILENAME}".format( | |
| DIRNAME = utils.dir_for(request.output_file).format(**common_vars), | |
| FILENAME = request.output_file.filename, | |
| ) | |
| if verbose: | |
| print("Copying file to: %s" % output_path) | |
| shutil.copyfile(input_path, output_path) | |
| return 0 | |
| if isinstance(request, VariableRequest): | |
| # No-op | |
| return 0 | |
| assert isinstance(request.tool, IcuTool) | |
| if platform == "windows": | |
| cmd_template = "{TOOL_DIR}/{TOOL}/{TOOL_CFG}/{TOOL}.exe {{ARGS}}".format( | |
| TOOL_DIR = tool_dir, | |
| TOOL_CFG = tool_cfg, | |
| TOOL = request.tool.name, | |
| **common_vars | |
| ) | |
| elif platform == "unix": | |
| cmd_template = "{TOOL_DIR}/{TOOL} {{ARGS}}".format( | |
| TOOL_DIR = tool_dir, | |
| TOOL = request.tool.name, | |
| **common_vars | |
| ) | |
| elif platform == "bazel": | |
| cmd_template = "{TOOL_DIR}/{TOOL}/{TOOL} {{ARGS}}".format( | |
| TOOL_DIR = tool_dir, | |
| TOOL = request.tool.name, | |
| **common_vars | |
| ) | |
| else: | |
| raise ValueError("Unknown platform: %s" % platform) | |
| if isinstance(request, RepeatedExecutionRequest): | |
| for loop_vars in utils.repeated_execution_request_looper(request): | |
| command_line = utils.format_repeated_request_command( | |
| request, | |
| cmd_template, | |
| loop_vars, | |
| common_vars | |
| ) | |
| if platform == "windows": | |
| # Note: this / to \ substitution may be too aggressive? | |
| command_line = command_line.replace("/", "\\") | |
| returncode = run_shell_command(command_line, platform, verbose) | |
| if returncode != 0: | |
| return returncode | |
| return 0 | |
| if isinstance(request, SingleExecutionRequest): | |
| command_line = utils.format_single_request_command( | |
| request, | |
| cmd_template, | |
| common_vars | |
| ) | |
| if platform == "windows": | |
| # Note: this / to \ substitution may be too aggressive? | |
| command_line = command_line.replace("/", "\\") | |
| returncode = run_shell_command(command_line, platform, verbose) | |
| return returncode | |
| assert False | |
| def run_shell_command(command_line, platform, verbose): | |
| changed_windows_comspec = False | |
| # If the command line length on Windows exceeds the absolute maximum that CMD supports (8191), then | |
| # we temporarily switch over to use PowerShell for the command, and then switch back to CMD. | |
| # We don't want to use PowerShell for everything though, as it tends to be slower. | |
| if (platform == "windows"): | |
| previous_comspec = os.environ["COMSPEC"] | |
| # Add 7 to the length for the argument /c with quotes. | |
| # For example: C:\WINDOWS\system32\cmd.exe /c "<command_line>" | |
| if ((len(previous_comspec) + len(command_line) + 7) > 8190): | |
| if verbose: | |
| print("Command length exceeds the max length for CMD on Windows, using PowerShell instead.") | |
| os.environ["COMSPEC"] = 'powershell' | |
| changed_windows_comspec = True | |
| if verbose: | |
| print("Running: %s" % command_line) | |
| returncode = subprocess.call( | |
| command_line, | |
| shell = True | |
| ) | |
| else: | |
| # Pipe output to /dev/null in quiet mode | |
| with open(os.devnull, "w") as devnull: | |
| returncode = subprocess.call( | |
| command_line, | |
| shell = True, | |
| stdout = devnull, | |
| stderr = devnull | |
| ) | |
| if changed_windows_comspec: | |
| os.environ["COMSPEC"] = previous_comspec | |
| if returncode != 0: | |
| print("Command failed: %s" % command_line, file=sys.stderr) | |
| return returncode |