summaryrefslogtreecommitdiff
path: root/buildscripts/util
diff options
context:
space:
mode:
authorJonathan Abrahams <jonathan@mongodb.com>2018-07-10 14:49:22 -0400
committerJonathan Abrahams <jonathan@mongodb.com>2018-07-16 09:13:53 -0400
commit298c3a04c118dcdb22cf27eaa0a9e7381b1e3da8 (patch)
tree0cf2a9c0df3218e68376058092f13556d5a56e02 /buildscripts/util
parent9184a03574c398b087b929fda8ed428f0c64d28c (diff)
downloadmongo-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.py27
-rw-r--r--buildscripts/util/runcommand.py98
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