Complete remaining TODOs in unit test script

Updated docker image unit test script, fixing the following TODOs:
- Replace os.system calls with subprocess.check_call
- Support possible configure.ac line breaks ('\')
- Updated 'make check' call fails Jenkins

Also added helpful command prints for Jenkins console

Change-Id: I6ba3986165b8d313228bcaa611df17bd213447eb
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/scripts/unit-test.py b/scripts/unit-test.py
index 3828369..b1ea3fa 100755
--- a/scripts/unit-test.py
+++ b/scripts/unit-test.py
@@ -8,14 +8,68 @@
 """
 
 from urlparse import urljoin
+from subprocess import check_call, call
 import os
 import sys
+import argparse
+
+
+def check_call_cmd(dir, *cmd):
+    """
+    Verbose prints the directory location the given command is called from and
+    the command, then executes the command using check_call.
+
+    Parameter descriptions:
+    dir                 Directory location command is to be called from
+    cmd                 List of parameters constructing the complete command
+    """
+    printline(dir, ">", " ".join(cmd))
+    check_call(cmd)
 
 
 def clone_pkg(pkg):
+    """
+    Clone the given openbmc package's git repository from gerrit into
+    the WORKSPACE location
+
+    Parameter descriptions:
+    pkg                 Name of the package to clone
+    """
     pkg_repo = urljoin('https://gerrit.openbmc-project.xyz/openbmc/', pkg)
     os.chdir(WORKSPACE)
-    os.system("git clone "+pkg_repo)  # TODO Replace with subprocess call
+    check_call_cmd(WORKSPACE, 'git', 'clone', pkg_repo)
+
+
+def get_deps(configure_ac):
+    """
+    Parse the given 'configure.ac' file for package dependencies and return
+    a list of the dependencies found.
+
+    Parameter descriptions:
+    configure_ac        Opened 'configure.ac' file object
+    """
+    line = ""
+    dep_pkgs = []
+    for cfg_line in configure_ac:
+        # Remove whitespace & newline
+        cfg_line = cfg_line.rstrip()
+        # Check for line breaks
+        if cfg_line.endswith('\\'):
+            line += str(cfg_line[:-1])
+            continue
+        line = line+cfg_line
+
+        # Find any defined dependency
+        for macro_key in DEPENDENCIES:
+            if not line.startswith(macro_key):
+                continue
+            for dep_key in DEPENDENCIES[macro_key]:
+                if line.find(dep_key) == -1:
+                    continue
+                dep_pkgs += [DEPENDENCIES[macro_key][dep_key]]
+        line = ""
+
+    return dep_pkgs
 
 
 def build_depends(pkg, pkgdir, dep_installed):
@@ -32,35 +86,28 @@
     """
     os.chdir(pkgdir)
     # Open package's configure.ac
-    with open("configure.ac", "rt") as infile:
-        for line in infile:  # TODO Handle line breaks
-            # Find any defined dependency
-            for macro_key in DEPENDENCIES:
-                if not line.startswith(macro_key):
+    with open("configure.ac", "rt") as configure_ac:
+        # Retrieve dependency list from package's configure.ac
+        configure_ac_deps = get_deps(configure_ac)
+        for dep_pkg in configure_ac_deps:
+            # Dependency package not already known
+            if dep_installed.get(dep_pkg) is None:
+                # Dependency package not installed
+                dep_installed[dep_pkg] = False
+                clone_pkg(dep_pkg)
+                # Determine this dependency package's
+                # dependencies and install them before
+                # returning to install this package
+                dep_pkgdir = os.path.join(WORKSPACE, dep_pkg)
+                dep_installed = build_depends(dep_pkg, dep_pkgdir,
+                                              dep_installed)
+            else:
+                # Dependency package known and installed
+                if dep_installed[dep_pkg]:
                     continue
-                for dep_key in DEPENDENCIES[macro_key]:
-                    if line.find(dep_key) == -1:
-                        continue
-                    dep_pkg = DEPENDENCIES[macro_key][dep_key]
-                    # Dependency package not already known
-                    if dep_installed.get(dep_pkg) is None:
-                        # Dependency package not installed
-                        dep_installed[dep_pkg] = False
-                        clone_pkg(dep_pkg)
-                        # Determine this dependency package's
-                        # dependencies and install them before
-                        # returning to install this package
-                        dep_pkgdir = os.path.join(WORKSPACE, dep_pkg)
-                        dep_installed = build_depends(dep_pkg, dep_pkgdir,
-                                                      dep_installed)
-                    else:
-                        # Dependency package known and installed
-                        if dep_installed[dep_pkg]:
-                            continue
-                        else:
-                            # Cyclic dependency failure
-                            raise Exception("Cyclic dependencies \
-                                   found in "+pkg)
+                else:
+                    # Cyclic dependency failure
+                    raise Exception("Cyclic dependencies found in "+pkg)
 
     # Build & install this package
     if not dep_installed[pkg]:
@@ -69,8 +116,10 @@
         # Add any necessary configure flags for package
         if CONFIGURE_FLAGS.get(pkg) is not None:
             conf_flags = " ".join(CONFIGURE_FLAGS.get(pkg))
-        os.system("./bootstrap.sh && ./configure " +
-                  conf_flags + "&& make && make install")
+        check_call_cmd(pkgdir, './bootstrap.sh')
+        check_call_cmd(pkgdir, './configure', conf_flags)
+        check_call_cmd(pkgdir, 'make')
+        check_call_cmd(pkgdir, 'make', 'install')
         dep_installed[pkg] = True
 
     return dep_installed
@@ -88,15 +137,24 @@
         'AC_CHECK_HEADER': {'host-ipmid/ipmid-api.h': 'phosphor-host-ipmid'}
     }
 
-    # Get workspace directory (package source to be tested)
-    WORKSPACE = os.environ.get('WORKSPACE')
-    if WORKSPACE is None:
-        raise Exception("Environment variable 'WORKSPACE' not set")
-
-    # Determine package name
-    UNIT_TEST_PKG = os.environ.get('UNIT_TEST_PKG')
-    if UNIT_TEST_PKG is None:
-        raise Exception("Environment variable 'UNIT_TEST_PKG' not set")
+    # Set command line arguments
+    parser = argparse.ArgumentParser()
+    parser.add_argument("-w", "--workspace", dest="WORKSPACE", required=True,
+                        help="Workspace directory location(i.e. /home)")
+    parser.add_argument("-p", "--package", dest="PACKAGE", required=True,
+                        help="OpenBMC package to be unit tested")
+    parser.add_argument("-v", "--verbose", action="store_true",
+                        help="Print additional package status messages")
+    args = parser.parse_args(sys.argv[1:])
+    WORKSPACE = args.WORKSPACE
+    UNIT_TEST_PKG = args.PACKAGE
+    if args.verbose:
+        def printline(*line):
+            for arg in line:
+                print arg,
+            print
+    else:
+        printline = lambda *l: None
 
     prev_umask = os.umask(000)
     # Determine dependencies and install them
@@ -107,5 +165,5 @@
                                   dep_installed)
     os.chdir(os.path.join(WORKSPACE, UNIT_TEST_PKG))
     # Run package unit tests
-    os.system("make check")  # TODO Verify all fails halt Jenkins
+    check_call_cmd(os.path.join(WORKSPACE, UNIT_TEST_PKG), 'make', 'check')
     os.umask(prev_umask)