crytic_compile.utils.subprocess
Process execution helpers.
1""" 2Process execution helpers. 3""" 4import logging 5import os 6from pathlib import Path 7import shutil 8import subprocess 9from typing import Any, Dict, List, Optional, Union 10 11LOGGER = logging.getLogger("CryticCompile") 12 13 14def run( 15 cmd: List[str], 16 cwd: Optional[Union[str, os.PathLike]] = None, 17 extra_env: Optional[Dict[str, str]] = None, 18 **kwargs: Any, 19) -> Optional[subprocess.CompletedProcess]: 20 """ 21 Execute a command in a cross-platform compatible way. 22 23 Args: 24 cmd (List[str]): Command to run 25 cwd (PathLike): Working directory to run the command in 26 extra_env (Dict[str, str]): extra environment variables to define for the execution 27 **kwargs: optional arguments passed to `subprocess.run` 28 29 Returns: 30 CompletedProcess: If the execution succeeded 31 None: if there was a problem executing 32 """ 33 subprocess_cwd = Path(os.getcwd() if cwd is None else cwd).resolve() 34 subprocess_env = None if extra_env is None else dict(os.environ, **extra_env) 35 subprocess_exe = shutil.which(cmd[0]) 36 37 if subprocess_exe is None: 38 LOGGER.error("Cannot execute `%s`, is it installed and in PATH?", cmd[0]) 39 return None 40 41 LOGGER.info( 42 "'%s' running (wd: %s)", 43 " ".join(cmd), 44 subprocess_cwd, 45 ) 46 47 try: 48 return subprocess.run( 49 cmd, 50 executable=subprocess_exe, 51 cwd=subprocess_cwd, 52 env=subprocess_env, 53 check=True, 54 capture_output=True, 55 **kwargs, 56 ) 57 except FileNotFoundError: 58 LOGGER.error("Could not execute `%s`, is it installed and in PATH?", cmd[0]) 59 except subprocess.CalledProcessError as e: 60 LOGGER.error("'%s' returned non-zero exit code %d", cmd[0], e.returncode) 61 stdout, stderr = ( 62 e.stdout.decode(errors="backslashreplace").strip(), 63 e.stderr.decode(errors="backslashreplace").strip(), 64 ) 65 if stdout: 66 LOGGER.error("\nstdout: ".join(stdout.split("\n"))) 67 if stderr: 68 LOGGER.error("\nstderr: ".join(stderr.split("\n"))) 69 except OSError: 70 LOGGER.error("OS error executing:", exc_info=True) 71 72 return None
LOGGER =
<Logger CryticCompile (WARNING)>
def
run( cmd: List[str], cwd: Union[str, os.PathLike, NoneType] = None, extra_env: Union[Dict[str, str], NoneType] = None, **kwargs: Any) -> Union[subprocess.CompletedProcess, NoneType]:
15def run( 16 cmd: List[str], 17 cwd: Optional[Union[str, os.PathLike]] = None, 18 extra_env: Optional[Dict[str, str]] = None, 19 **kwargs: Any, 20) -> Optional[subprocess.CompletedProcess]: 21 """ 22 Execute a command in a cross-platform compatible way. 23 24 Args: 25 cmd (List[str]): Command to run 26 cwd (PathLike): Working directory to run the command in 27 extra_env (Dict[str, str]): extra environment variables to define for the execution 28 **kwargs: optional arguments passed to `subprocess.run` 29 30 Returns: 31 CompletedProcess: If the execution succeeded 32 None: if there was a problem executing 33 """ 34 subprocess_cwd = Path(os.getcwd() if cwd is None else cwd).resolve() 35 subprocess_env = None if extra_env is None else dict(os.environ, **extra_env) 36 subprocess_exe = shutil.which(cmd[0]) 37 38 if subprocess_exe is None: 39 LOGGER.error("Cannot execute `%s`, is it installed and in PATH?", cmd[0]) 40 return None 41 42 LOGGER.info( 43 "'%s' running (wd: %s)", 44 " ".join(cmd), 45 subprocess_cwd, 46 ) 47 48 try: 49 return subprocess.run( 50 cmd, 51 executable=subprocess_exe, 52 cwd=subprocess_cwd, 53 env=subprocess_env, 54 check=True, 55 capture_output=True, 56 **kwargs, 57 ) 58 except FileNotFoundError: 59 LOGGER.error("Could not execute `%s`, is it installed and in PATH?", cmd[0]) 60 except subprocess.CalledProcessError as e: 61 LOGGER.error("'%s' returned non-zero exit code %d", cmd[0], e.returncode) 62 stdout, stderr = ( 63 e.stdout.decode(errors="backslashreplace").strip(), 64 e.stderr.decode(errors="backslashreplace").strip(), 65 ) 66 if stdout: 67 LOGGER.error("\nstdout: ".join(stdout.split("\n"))) 68 if stderr: 69 LOGGER.error("\nstderr: ".join(stderr.split("\n"))) 70 except OSError: 71 LOGGER.error("OS error executing:", exc_info=True) 72 73 return None
Execute a command in a cross-platform compatible way.
Args:
cmd (List[str]): Command to run
cwd (PathLike): Working directory to run the command in
extra_env (Dict[str, str]): extra environment variables to define for the execution
**kwargs: optional arguments passed to subprocess.run
Returns: CompletedProcess: If the execution succeeded None: if there was a problem executing