[docs]defformat_npm_command_for_logging(command:list[str])->str:"""Convert npm command list to string for display to user."""ifplatform.system().lower()=="windows"and(command[0]=="npx.cmd"andcommand[1]=="-c"):returnf'npx.cmd -c "{" ".join(command[2:])}"'return" ".join(command)
[docs]defgenerate_node_command(command:str,command_opts:list[str],path:Path,*,logger:logging.Logger|logging.LoggerAdapter[Any]=LOGGER,package:str|None=None,)->list[str]:"""Return node bin command list for subprocess execution. Args: command: Command to execute from a local ``node_modules/.bin``. command_opts: Options to include with the command. path: Current working directory. Used to construct a "fall-back" command when ``npx`` is not available/included as part of npm. logger: A specific logger to use when logging the constructed command. package: Name of the npm package containing the binary to execute. This is recommended when the name of the binary does not match the name of the npm package. """ifwhich(NPX_BIN):# Use npx if available (npm v5.2+)cmd_list=[NPX_BIN]ifpackage:cmd_list.extend(["--package",package,command,*command_opts,])else:cmd_list.append("-c")cmd_list.append(f"{command}{' '.join(command_opts)}".strip())else:logger.debug("npx not found; falling back to invoking shell script directly")cmd_list=[str(path/"node_modules"/".bin"/command),*command_opts]logger.debug("node command: %s",format_npm_command_for_logging(cmd_list))returncmd_list
[docs]defrun_module_command(cmd_list:list[str],env_vars:dict[str,str],exit_on_error:bool=True,logger:logging.Logger|logging.LoggerAdapter[Any]=LOGGER,)->None:"""Shell out to provisioner command. Args: cmd_list: Command to run. env_vars: Environment variables. exit_on_error: If true, ``subprocess.CalledProcessError`` will be caught and the resulting exit code will be passed to ``sys.exit()``. If false, the error will not be caught within this function. logger: Optionally, supply a logger to use. logger: A specific logger to use when logging the constructed command. """logger.debug("running command: %s"," ".join(cmd_list))ifexit_on_error:try:subprocess.check_call(cmd_list,env=env_vars)exceptsubprocess.CalledProcessErrorasshelloutexc:sys.exit(shelloutexc.returncode)else:subprocess.check_call(cmd_list,env=env_vars)
[docs]defuse_npm_ci(path:Path)->bool:"""Return true if npm ci should be used in lieu of npm install."""# https://docs.npmjs.com/cli/ci#descriptionwithopen(os.devnull,"w",encoding="utf-8")asfnull:# noqa: PTH123if((path/"package-lock.json").is_file()or(path/"npm-shrinkwrap.json").is_file())andsubprocess.call([NPM_BIN,"ci","-h"],stdout=fnull,stderr=subprocess.STDOUT)==0:returnTruereturnFalse