Add dbus interfaces dependency to phosphor logging
Add dbus interfaces dependency to phosphor logging
Fixes openbmc/openbmc#1360
Change-Id: Iea1f9b20d52ca99f5af3199fdae676fa6f00024e
Signed-off-by: Leonel Gonzalez <lgonzalez@us.ibm.com>
diff --git a/scripts/unit-test.py b/scripts/unit-test.py
index 5374327..f509b07 100755
--- a/scripts/unit-test.py
+++ b/scripts/unit-test.py
@@ -13,6 +13,202 @@
import os
import sys
import argparse
+import re
+
+
+class DepTree():
+ """
+ Represents package dependency tree, where each node is a DepTree with a
+ name and DepTree children.
+ """
+
+ def __init__(self, name):
+ """
+ Create new DepTree.
+
+ Parameter descriptions:
+ name Name of new tree node.
+ """
+ self.name = name
+ self.children = list()
+
+ def AddChild(self, name):
+ """
+ Add new child node to current node.
+
+ Parameter descriptions:
+ name Name of new child
+ """
+ new_child = DepTree(name)
+ self.children.append(new_child)
+ return new_child
+
+ def AddChildNode(self, node):
+ """
+ Add existing child node to current node.
+
+ Parameter descriptions:
+ node Tree node to add
+ """
+ self.children.append(node)
+
+ def RemoveChild(self, name):
+ """
+ Remove child node.
+
+ Parameter descriptions:
+ name Name of child to remove
+ """
+ for child in self.children:
+ if child.name == name:
+ self.children.remove(child)
+ return
+
+ def GetNode(self, name):
+ """
+ Return node with matching name. Return None if not found.
+
+ Parameter descriptions:
+ name Name of node to return
+ """
+ if self.name == name:
+ return self
+ for child in self.children:
+ node = child.GetNode(name)
+ if node:
+ return node
+ return None
+
+ def GetParentNode(self, name, parent_node=None):
+ """
+ Return parent of node with matching name. Return none if not found.
+
+ Parameter descriptions:
+ name Name of node to get parent of
+ parent_node Parent of current node
+ """
+ if self.name == name:
+ return parent_node
+ for child in self.children:
+ found_node = child.GetParentNode(name, self)
+ if found_node:
+ return found_node
+ return None
+
+ def GetPath(self, name, path=None):
+ """
+ Return list of node names from head to matching name.
+ Return None if not found.
+
+ Parameter descriptions:
+ name Name of node
+ path List of node names from head to current node
+ """
+ if not path:
+ path = []
+ if self.name == name:
+ path.append(self.name)
+ return path
+ for child in self.children:
+ match = child.GetPath(name, path + [self.name])
+ if match:
+ return match
+ return None
+
+ def GetPathRegex(self, name, regex_str, path=None):
+ """
+ Return list of node paths that end in name, or match regex_str.
+ Return empty list if not found.
+
+ Parameter descriptions:
+ name Name of node to search for
+ regex_str Regex string to match node names
+ path Path of node names from head to current node
+ """
+ new_paths = []
+ if not path:
+ path = []
+ match = re.match(regex_str, self.name)
+ if (self.name == name) or (match):
+ new_paths.append(path + [self.name])
+ for child in self.children:
+ return_paths = None
+ full_path = path + [self.name]
+ return_paths = child.GetPathRegex(name, regex_str, full_path)
+ for i in return_paths:
+ new_paths.append(i)
+ return new_paths
+
+ def MoveNode(self, from_name, to_name):
+ """
+ Mode existing from_name node to become child of to_name node.
+
+ Parameter descriptions:
+ from_name Name of node to make a child of to_name
+ to_name Name of node to make parent of from_name
+ """
+ parent_from_node = self.GetParentNode(from_name)
+ from_node = self.GetNode(from_name)
+ parent_from_node.RemoveChild(from_name)
+ to_node = self.GetNode(to_name)
+ to_node.AddChildNode(from_node)
+
+ def ReorderDeps(self, name, regex_str):
+ """
+ Reorder dependency tree. If tree contains nodes with names that
+ match 'name' and 'regex_str', move 'regex_str' nodes that are
+ to the right of 'name' node, so that they become children of the
+ 'name' node.
+
+ Parameter descriptions:
+ name Name of node to look for
+ regex_str Regex string to match names to
+ """
+ name_path = self.GetPath(name)
+ if not name_path:
+ return
+ paths = self.GetPathRegex(name, regex_str)
+ is_name_in_paths = False
+ name_index = 0
+ for i in range(len(paths)):
+ path = paths[i]
+ if path[-1] == name:
+ is_name_in_paths = True
+ name_index = i
+ break
+ if not is_name_in_paths:
+ return
+ for i in range(name_index + 1, len(paths)):
+ path = paths[i]
+ if name in path:
+ continue
+ from_name = path[-1]
+ self.MoveNode(from_name, name)
+
+ def GetInstallList(self):
+ """
+ Return post-order list of node names.
+
+ Parameter descriptions:
+ """
+ install_list = []
+ for child in self.children:
+ child_install_list = child.GetInstallList()
+ install_list.extend(child_install_list)
+ install_list.append(self.name)
+ return install_list
+
+ def PrintTree(self, level=0):
+ """
+ Print pre-order node names with indentation denoting node depth level.
+
+ Parameter descriptions:
+ level Current depth level
+ """
+ INDENT_PER_LEVEL = 4
+ print ' ' * (level * INDENT_PER_LEVEL) + self.name
+ for child in self.children:
+ child.PrintTree(level + 1)
def check_call_cmd(dir, *cmd):
@@ -70,50 +266,21 @@
dep_pkgs.update(map(lambda x: DEPENDENCIES[macro][x], deps))
line = ""
+ deps = list(dep_pkgs)
- return list(dep_pkgs)
+ return deps
-def build_depends(pkg, pkgdir, dep_installed):
+def install_deps(dep_list):
"""
- For each package(pkg), starting with the package to be unit tested,
- parse its 'configure.ac' file from within the package's directory(pkgdir)
- for each package dependency defined recursively doing the same thing
- on each package found as a dependency.
+ Install each package in the ordered dep_list.
Parameter descriptions:
- pkg Name of the package
- pkgdir Directory where package source is located
- dep_installed Current list of dependencies and installation status
+ dep_list Ordered list of dependencies
"""
- os.chdir(pkgdir)
- # Open package's configure.ac
- 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
- dep_repo = 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_repo.working_dir,
- 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)
-
- # Build & install this package
- if not dep_installed[pkg]:
+ for pkg in dep_list:
+ pkgdir = os.path.join(WORKSPACE, pkg)
+ # Build & install this package
conf_flags = []
os.chdir(pkgdir)
# Add any necessary configure flags for package
@@ -123,9 +290,57 @@
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
+
+def build_dep_tree(pkg, pkgdir, dep_added, head, dep_tree=None):
+ """
+ For each package(pkg), starting with the package to be unit tested,
+ parse its 'configure.ac' file from within the package's directory(pkgdir)
+ for each package dependency defined recursively doing the same thing
+ on each package found as a dependency.
+
+ Parameter descriptions:
+ pkg Name of the package
+ pkgdir Directory where package source is located
+ dep_added Current list of dependencies and added status
+ head Head node of the dependency tree
+ dep_tree Current dependency tree node
+ """
+ if not dep_tree:
+ dep_tree = head
+ os.chdir(pkgdir)
+ # Open package's configure.ac
+ 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_added.get(dep_pkg) is None:
+ # Dependency package not added
+ new_child = dep_tree.AddChild(dep_pkg)
+ dep_added[dep_pkg] = False
+ dep_repo = clone_pkg(dep_pkg)
+ # Determine this dependency package's
+ # dependencies and add them before
+ # returning to add this package
+ dep_pkgdir = os.path.join(WORKSPACE, dep_pkg)
+ dep_added = build_dep_tree(dep_pkg,
+ dep_repo.working_dir,
+ dep_added,
+ head,
+ new_child)
+ else:
+ # Dependency package known and added
+ if dep_added[dep_pkg]:
+ continue
+ else:
+ # Cyclic dependency failure
+ raise Exception("Cyclic dependencies found in "+pkg)
+
+ if not dep_added[pkg]:
+ dep_added[pkg] = True
+
+ return dep_added
if __name__ == '__main__':
@@ -155,6 +370,11 @@
},
}
+ # DEPENDENCIES_REGEX = [GIT REPO]:[REGEX STRING]
+ DEPENDENCIES_REGEX = {
+ 'phosphor-logging': '\S+-dbus-interfaces$'
+ }
+
# Set command line arguments
parser = argparse.ArgumentParser()
parser.add_argument("-w", "--workspace", dest="WORKSPACE", required=True,
@@ -175,12 +395,24 @@
printline = lambda *l: None
prev_umask = os.umask(000)
- # Determine dependencies and install them
- dep_installed = dict()
- dep_installed[UNIT_TEST_PKG] = False
- dep_installed = build_depends(UNIT_TEST_PKG,
- os.path.join(WORKSPACE, UNIT_TEST_PKG),
- dep_installed)
+ # Determine dependencies and add them
+ dep_added = dict()
+ dep_added[UNIT_TEST_PKG] = False
+ # Create dependency tree
+ dep_tree = DepTree(UNIT_TEST_PKG)
+ build_dep_tree(UNIT_TEST_PKG,
+ os.path.join(WORKSPACE, UNIT_TEST_PKG),
+ dep_added,
+ dep_tree)
+
+ # Reorder Dependency Tree
+ for pkg_name, regex_str in DEPENDENCIES_REGEX.iteritems():
+ dep_tree.ReorderDeps(pkg_name, regex_str)
+ if args.verbose:
+ dep_tree.PrintTree()
+ install_list = dep_tree.GetInstallList()
+ # install reordered depdendencies
+ install_deps(install_list)
os.chdir(os.path.join(WORKSPACE, UNIT_TEST_PKG))
# Refresh dynamic linker run time bindings for dependencies
check_call_cmd(os.path.join(WORKSPACE, UNIT_TEST_PKG), 'ldconfig')