diff options
author | Jonathan Abrahams <jonathan@mongodb.com> | 2018-07-10 14:49:22 -0400 |
---|---|---|
committer | Jonathan Abrahams <jonathan@mongodb.com> | 2018-07-16 09:13:53 -0400 |
commit | 298c3a04c118dcdb22cf27eaa0a9e7381b1e3da8 (patch) | |
tree | 0cf2a9c0df3218e68376058092f13556d5a56e02 /buildscripts/util | |
parent | 9184a03574c398b087b929fda8ed428f0c64d28c (diff) | |
download | mongo-298c3a04c118dcdb22cf27eaa0a9e7381b1e3da8.tar.gz |
SERVER-36019 Create script to collect resource utilization of Android application
Diffstat (limited to 'buildscripts/util')
-rw-r--r-- | buildscripts/util/fileops.py | 27 | ||||
-rw-r--r-- | buildscripts/util/runcommand.py | 98 |
2 files changed, 103 insertions, 22 deletions
diff --git a/buildscripts/util/fileops.py b/buildscripts/util/fileops.py new file mode 100644 index 00000000000..e56348d8548 --- /dev/null +++ b/buildscripts/util/fileops.py @@ -0,0 +1,27 @@ +"""Utility to support file operations.""" + +import os + + +def create_empty(path): + """Create an empty file specified by 'path'.""" + with open(path, "w") as file_handle: + file_handle.write("") + + +def getmtime(path): + """Return the modified time of 'path', or 0 if is does not exist.""" + if not os.path.isfile(path): + return 0 + return os.path.getmtime(path) + + +def is_empty(path): + """Return True if 'path' has a zero size.""" + return os.stat(path).st_size == 0 + + +def get_file_handle(path, append_file=False): + """Open 'path', truncate it if 'append_file' is False, and return file handle.""" + mode = "a+" if append_file else "w" + return open(path, mode) diff --git a/buildscripts/util/runcommand.py b/buildscripts/util/runcommand.py index ff9e726cc3e..edf9e99816c 100644 --- a/buildscripts/util/runcommand.py +++ b/buildscripts/util/runcommand.py @@ -7,6 +7,8 @@ import pipes import shlex import sys +from . import fileops + # The subprocess32 module is untested on Windows and thus isn't recommended for use, even when it's # installed. See https://github.com/google/python-subprocess32/blob/3.2.7/README.md#usage. if os.name == "posix" and sys.version_info[0] == 2: @@ -23,25 +25,23 @@ else: import subprocess -def execute_cmd(cmd): - """Execute specified 'cmd' and return err_code and output. - - If 'cmd' is specified as a string, convert it to a list of strings. - """ - if isinstance(cmd, str): - cmd = shlex.split(cmd) - proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - output, _ = proc.communicate() - error_code = proc.returncode - return error_code, output - - class RunCommand(object): """Class to abstract executing a subprocess.""" - def __init__(self, string=None): + def __init__( # pylint: disable=too-many-arguments + self, string=None, output_file=None, append_file=False, propagate_signals=True): """Initialize the RunCommand object.""" - self._command = string + self._command = string if string else "" + self.output_file = output_file + self.append_file = append_file + self._process = None + if propagate_signals or os.name != "posix": + # The function os.setpgrp is not supported on Windows. + self._preexec_kargs = {} + elif subprocess.__name__ == "subprocess32": + self._preexec_kargs = {"start_new_session": True} + else: + self._preexec_kargs = {"preexec_fn": os.setpgrp} def add(self, string): """Add a string to the command.""" @@ -52,17 +52,71 @@ class RunCommand(object): # For Windows compatability, use pipes.quote around file paths. self._command = "{}{}{}".format(self._command, self._space(), pipes.quote(path)) + def _space(self): + """Return a space if the command has been started to be built.""" + if self._command: + return " " + return "" + + def _cmd_list(self): + """Return 'cmd' as a list of strings.""" + cmd = self._command + if isinstance(cmd, str): + cmd = shlex.split(cmd) + return cmd + def execute(self): - """Execute the command. Return (error_code, output).""" - return execute_cmd(self._command) + """Execute 'cmd' and return err_code and output.""" + self._process = subprocess.Popen(self._cmd_list(), stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, **self._preexec_kargs) + output, _ = self._process.communicate() + error_code = self._process.returncode + return error_code, output + + def execute_with_output(self): + """Execute the command, return result as a string.""" + return subprocess.check_output(self._cmd_list()) + + def execute_save_output(self): + """Execute the command, save result in 'self.output_file' and return returncode.""" + with fileops.get_file_handle(self.output_file, self.append_file) as file_handle: + ret = subprocess.check_call(self._cmd_list(), stdout=file_handle) + return ret + + def start_process(self): + """Start to execute the command.""" + # Do not propagate interrupts to the child process. + with fileops.get_file_handle(self.output_file, self.append_file) as file_handle: + self._process = subprocess.Popen(self._cmd_list(), stdin=subprocess.PIPE, + stdout=file_handle, stderr=subprocess.STDOUT, + **self._preexec_kargs) + + def send_to_process(self, string=None): + """Send 'string' to a running processs and return stdout, stderr.""" + return self._process.communicate(string) + + def wait_for_process(self): + """Wait for a running processs to end and return stdout, stderr.""" + return self.send_to_process() + + def stop_process(self): + """Stop the running process.""" + self._process.terminate() + + def kill_process(self): + """Kill the running process.""" + self._process.kill() + + def is_process_running(self): + """Return True if the process is still running.""" + return self._process.poll() is None @property def command(self): """Get the command.""" return self._command - def _space(self): - """Return a space if the command has been started to be built.""" - if self._command: - return " " - return "" + @property + def process(self): + """Get the process object.""" + return self._process |