blob: 5374327a3c6584193b96a95976f1ea20a92decc6 [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 = ""
Brad Bishopebb49112017-02-13 11:07:26 -050054 dep_pkgs = set()
Matthew Barth33df8792016-12-19 14:30:17 -060055 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
Brad Bishopebb49112017-02-13 11:07:26 -050065 line_has = lambda x: x if x in line else None
66 macros = set(filter(line_has, DEPENDENCIES.iterkeys()))
67 if len(macros) == 1:
68 macro = ''.join(macros)
69 deps = filter(line_has, DEPENDENCIES[macro].iterkeys())
70 dep_pkgs.update(map(lambda x: DEPENDENCIES[macro][x], deps))
71
Matthew Barth33df8792016-12-19 14:30:17 -060072 line = ""
73
Brad Bishopebb49112017-02-13 11:07:26 -050074 return list(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]:
Matthew Barth1d1c6732017-03-24 10:00:28 -0500117 conf_flags = []
Matthew Barthccb7f852016-11-23 17:43:02 -0600118 os.chdir(pkgdir)
119 # Add any necessary configure flags for package
120 if CONFIGURE_FLAGS.get(pkg) is not None:
Matthew Barth1d1c6732017-03-24 10:00:28 -0500121 conf_flags.extend(CONFIGURE_FLAGS.get(pkg))
Matthew Barth33df8792016-12-19 14:30:17 -0600122 check_call_cmd(pkgdir, './bootstrap.sh')
Matthew Barth1d1c6732017-03-24 10:00:28 -0500123 check_call_cmd(pkgdir, './configure', *conf_flags)
Matthew Barth33df8792016-12-19 14:30:17 -0600124 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 = {
Adriana Kobylak43c31e82017-02-13 09:28:35 -0600134 'phosphor-objmgr': ['--enable-unpatched-systemd'],
Matthew Barth1d1c6732017-03-24 10:00:28 -0500135 'sdbusplus': ['--enable-transaction'],
136 'phosphor-logging':
137 ['--enable-metadata-processing',
138 'YAML_DIR=/usr/local/share/phosphor-dbus-interfaces/yaml']
Matthew Barthccb7f852016-11-23 17:43:02 -0600139 }
140
141 # DEPENDENCIES = [MACRO]:[library/header]:[GIT REPO]
142 DEPENDENCIES = {
143 'AC_CHECK_LIB': {'mapper': 'phosphor-objmgr'},
Matthew Barth710f3f02017-01-18 15:20:19 -0600144 'AC_CHECK_HEADER': {
145 'host-ipmid': 'phosphor-host-ipmid',
146 'sdbusplus': 'sdbusplus',
Saqib Khan66145052017-02-14 12:02:07 -0600147 'phosphor-logging/log.hpp': 'phosphor-logging',
Patrick Williamseab8a372017-01-30 11:21:32 -0600148 },
Brad Bishopebb49112017-02-13 11:07:26 -0500149 'AC_PATH_PROG': {'sdbus++': 'sdbusplus'},
Patrick Williamseab8a372017-01-30 11:21:32 -0600150 'PKG_CHECK_MODULES': {
Matthew Barth19e261e2017-02-01 12:55:22 -0600151 'phosphor-dbus-interfaces': 'phosphor-dbus-interfaces',
Patrick Williamsf128b402017-03-29 06:45:59 -0500152 'openpower-dbus-interfaces': 'openpower-dbus-interfaces',
Brad Bishopebb49112017-02-13 11:07:26 -0500153 'sdbusplus': 'sdbusplus',
154 'phosphor-logging': 'phosphor-logging',
155 },
Matthew Barthccb7f852016-11-23 17:43:02 -0600156 }
157
Matthew Barth33df8792016-12-19 14:30:17 -0600158 # Set command line arguments
159 parser = argparse.ArgumentParser()
160 parser.add_argument("-w", "--workspace", dest="WORKSPACE", required=True,
161 help="Workspace directory location(i.e. /home)")
162 parser.add_argument("-p", "--package", dest="PACKAGE", required=True,
163 help="OpenBMC package to be unit tested")
164 parser.add_argument("-v", "--verbose", action="store_true",
165 help="Print additional package status messages")
166 args = parser.parse_args(sys.argv[1:])
167 WORKSPACE = args.WORKSPACE
168 UNIT_TEST_PKG = args.PACKAGE
169 if args.verbose:
170 def printline(*line):
171 for arg in line:
172 print arg,
173 print
174 else:
175 printline = lambda *l: None
Matthew Barthccb7f852016-11-23 17:43:02 -0600176
177 prev_umask = os.umask(000)
178 # Determine dependencies and install them
179 dep_installed = dict()
180 dep_installed[UNIT_TEST_PKG] = False
181 dep_installed = build_depends(UNIT_TEST_PKG,
182 os.path.join(WORKSPACE, UNIT_TEST_PKG),
183 dep_installed)
184 os.chdir(os.path.join(WORKSPACE, UNIT_TEST_PKG))
Matthew Barth948b7cc2017-02-21 09:13:54 -0600185 # Refresh dynamic linker run time bindings for dependencies
186 check_call_cmd(os.path.join(WORKSPACE, UNIT_TEST_PKG), 'ldconfig')
Matthew Barthccb7f852016-11-23 17:43:02 -0600187 # Run package unit tests
Matthew Barth4ecbc9c2017-02-17 10:34:46 -0600188 if args.verbose:
189 check_call_cmd(os.path.join(WORKSPACE, UNIT_TEST_PKG), 'make', 'check',
190 'VERBOSE=1')
191 else:
192 check_call_cmd(os.path.join(WORKSPACE, UNIT_TEST_PKG), 'make', 'check')
Matthew Barthccb7f852016-11-23 17:43:02 -0600193 os.umask(prev_umask)