blob: bb173310f3a314c3fb4399ab13dcdac689e3bbc4 [file] [log] [blame]
Matthew Barthccb7f852016-11-23 17:43:02 -06001#!/usr/bin/env python
2
3"""
4This script determines the given package's openbmc dependencies from its
5configure.ac file where it downloads, configures, builds, and installs each of
6these dependencies. Then the given package is configured, built, and installed
7prior to executing its unit tests.
8"""
9
Matthew Barthd1810372016-12-19 16:57:21 -060010from git import Repo
Matthew Barthccb7f852016-11-23 17:43:02 -060011from urlparse import urljoin
Matthew Barth33df8792016-12-19 14:30:17 -060012from subprocess import check_call, call
Matthew Barthccb7f852016-11-23 17:43:02 -060013import os
14import sys
Matthew Barth33df8792016-12-19 14:30:17 -060015import argparse
16
17
18def check_call_cmd(dir, *cmd):
19 """
20 Verbose prints the directory location the given command is called from and
21 the command, then executes the command using check_call.
22
23 Parameter descriptions:
24 dir Directory location command is to be called from
25 cmd List of parameters constructing the complete command
26 """
27 printline(dir, ">", " ".join(cmd))
28 check_call(cmd)
Matthew Barthccb7f852016-11-23 17:43:02 -060029
30
31def clone_pkg(pkg):
Matthew Barth33df8792016-12-19 14:30:17 -060032 """
33 Clone the given openbmc package's git repository from gerrit into
34 the WORKSPACE location
35
36 Parameter descriptions:
37 pkg Name of the package to clone
38 """
Matthew Barthccb7f852016-11-23 17:43:02 -060039 pkg_repo = urljoin('https://gerrit.openbmc-project.xyz/openbmc/', pkg)
Matthew Barthd1810372016-12-19 16:57:21 -060040 os.mkdir(os.path.join(WORKSPACE, pkg))
41 printline(os.path.join(WORKSPACE, pkg), "> git clone", pkg_repo, "./")
42 return Repo.clone_from(pkg_repo, os.path.join(WORKSPACE, pkg))
Matthew Barth33df8792016-12-19 14:30:17 -060043
44
45def get_deps(configure_ac):
46 """
47 Parse the given 'configure.ac' file for package dependencies and return
48 a list of the dependencies found.
49
50 Parameter descriptions:
51 configure_ac Opened 'configure.ac' file object
52 """
53 line = ""
54 dep_pkgs = []
55 for cfg_line in configure_ac:
56 # Remove whitespace & newline
57 cfg_line = cfg_line.rstrip()
58 # Check for line breaks
59 if cfg_line.endswith('\\'):
60 line += str(cfg_line[:-1])
61 continue
62 line = line+cfg_line
63
64 # Find any defined dependency
65 for macro_key in DEPENDENCIES:
66 if not line.startswith(macro_key):
67 continue
68 for dep_key in DEPENDENCIES[macro_key]:
69 if line.find(dep_key) == -1:
70 continue
71 dep_pkgs += [DEPENDENCIES[macro_key][dep_key]]
72 line = ""
73
74 return dep_pkgs
Matthew Barthccb7f852016-11-23 17:43:02 -060075
76
77def build_depends(pkg, pkgdir, dep_installed):
78 """
79 For each package(pkg), starting with the package to be unit tested,
80 parse its 'configure.ac' file from within the package's directory(pkgdir)
81 for each package dependency defined recursively doing the same thing
82 on each package found as a dependency.
83
84 Parameter descriptions:
85 pkg Name of the package
86 pkgdir Directory where package source is located
87 dep_installed Current list of dependencies and installation status
88 """
89 os.chdir(pkgdir)
90 # Open package's configure.ac
Matthew Barth33df8792016-12-19 14:30:17 -060091 with open("configure.ac", "rt") as configure_ac:
92 # Retrieve dependency list from package's configure.ac
93 configure_ac_deps = get_deps(configure_ac)
94 for dep_pkg in configure_ac_deps:
95 # Dependency package not already known
96 if dep_installed.get(dep_pkg) is None:
97 # Dependency package not installed
98 dep_installed[dep_pkg] = False
Matthew Barthd1810372016-12-19 16:57:21 -060099 dep_repo = clone_pkg(dep_pkg)
Matthew Barth33df8792016-12-19 14:30:17 -0600100 # Determine this dependency package's
101 # dependencies and install them before
102 # returning to install this package
103 dep_pkgdir = os.path.join(WORKSPACE, dep_pkg)
Matthew Barthd1810372016-12-19 16:57:21 -0600104 dep_installed = build_depends(dep_pkg,
105 dep_repo.working_dir,
Matthew Barth33df8792016-12-19 14:30:17 -0600106 dep_installed)
107 else:
108 # Dependency package known and installed
109 if dep_installed[dep_pkg]:
Matthew Barthccb7f852016-11-23 17:43:02 -0600110 continue
Matthew Barth33df8792016-12-19 14:30:17 -0600111 else:
112 # Cyclic dependency failure
113 raise Exception("Cyclic dependencies found in "+pkg)
Matthew Barthccb7f852016-11-23 17:43:02 -0600114
115 # Build & install this package
116 if not dep_installed[pkg]:
117 conf_flags = ""
118 os.chdir(pkgdir)
119 # Add any necessary configure flags for package
120 if CONFIGURE_FLAGS.get(pkg) is not None:
121 conf_flags = " ".join(CONFIGURE_FLAGS.get(pkg))
Matthew Barth33df8792016-12-19 14:30:17 -0600122 check_call_cmd(pkgdir, './bootstrap.sh')
123 check_call_cmd(pkgdir, './configure', conf_flags)
124 check_call_cmd(pkgdir, 'make')
125 check_call_cmd(pkgdir, 'make', 'install')
Matthew Barthccb7f852016-11-23 17:43:02 -0600126 dep_installed[pkg] = True
127
128 return dep_installed
129
130
131if __name__ == '__main__':
132 # CONFIGURE_FLAGS = [GIT REPO]:[CONFIGURE FLAGS]
133 CONFIGURE_FLAGS = {
134 'phosphor-objmgr': ['--enable-unpatched-systemd']
135 }
136
137 # DEPENDENCIES = [MACRO]:[library/header]:[GIT REPO]
138 DEPENDENCIES = {
139 'AC_CHECK_LIB': {'mapper': 'phosphor-objmgr'},
Matthew Barth0e90f3c2017-01-16 13:43:05 -0600140 'AC_CHECK_HEADER': {'host-ipmid/ipmid-api.h': 'phosphor-host-ipmid'},
Matthew Barth6cc35d82017-01-18 13:36:31 -0600141 'AC_CHECK_HEADER': {'sdbusplus/server.hpp': 'sdbusplus'},
142 'AC_CHECK_HEADER': {'log.hpp': 'phosphor-logging'}
Matthew Barthccb7f852016-11-23 17:43:02 -0600143 }
144
Matthew Barth33df8792016-12-19 14:30:17 -0600145 # Set command line arguments
146 parser = argparse.ArgumentParser()
147 parser.add_argument("-w", "--workspace", dest="WORKSPACE", required=True,
148 help="Workspace directory location(i.e. /home)")
149 parser.add_argument("-p", "--package", dest="PACKAGE", required=True,
150 help="OpenBMC package to be unit tested")
151 parser.add_argument("-v", "--verbose", action="store_true",
152 help="Print additional package status messages")
153 args = parser.parse_args(sys.argv[1:])
154 WORKSPACE = args.WORKSPACE
155 UNIT_TEST_PKG = args.PACKAGE
156 if args.verbose:
157 def printline(*line):
158 for arg in line:
159 print arg,
160 print
161 else:
162 printline = lambda *l: None
Matthew Barthccb7f852016-11-23 17:43:02 -0600163
164 prev_umask = os.umask(000)
165 # Determine dependencies and install them
166 dep_installed = dict()
167 dep_installed[UNIT_TEST_PKG] = False
168 dep_installed = build_depends(UNIT_TEST_PKG,
169 os.path.join(WORKSPACE, UNIT_TEST_PKG),
170 dep_installed)
171 os.chdir(os.path.join(WORKSPACE, UNIT_TEST_PKG))
172 # Run package unit tests
Matthew Barth33df8792016-12-19 14:30:17 -0600173 check_call_cmd(os.path.join(WORKSPACE, UNIT_TEST_PKG), 'make', 'check')
Matthew Barthccb7f852016-11-23 17:43:02 -0600174 os.umask(prev_umask)