blob: a6716476343bec96ee94914efd75a16b1ef8fd24 [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]:
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 = {
Adriana Kobylak43c31e82017-02-13 09:28:35 -0600134 'phosphor-objmgr': ['--enable-unpatched-systemd'],
135 'sdbusplus': ['--enable-transaction']
Matthew Barthccb7f852016-11-23 17:43:02 -0600136 }
137
138 # DEPENDENCIES = [MACRO]:[library/header]:[GIT REPO]
139 DEPENDENCIES = {
140 'AC_CHECK_LIB': {'mapper': 'phosphor-objmgr'},
Matthew Barth710f3f02017-01-18 15:20:19 -0600141 'AC_CHECK_HEADER': {
142 'host-ipmid': 'phosphor-host-ipmid',
143 'sdbusplus': 'sdbusplus',
Saqib Khan66145052017-02-14 12:02:07 -0600144 'phosphor-logging/log.hpp': 'phosphor-logging',
Patrick Williamseab8a372017-01-30 11:21:32 -0600145 },
Brad Bishopebb49112017-02-13 11:07:26 -0500146 'AC_PATH_PROG': {'sdbus++': 'sdbusplus'},
Patrick Williamseab8a372017-01-30 11:21:32 -0600147 'PKG_CHECK_MODULES': {
Matthew Barth19e261e2017-02-01 12:55:22 -0600148 'phosphor-dbus-interfaces': 'phosphor-dbus-interfaces',
Brad Bishopebb49112017-02-13 11:07:26 -0500149 'sdbusplus': 'sdbusplus',
150 'phosphor-logging': 'phosphor-logging',
151 },
Matthew Barthccb7f852016-11-23 17:43:02 -0600152 }
153
Matthew Barth33df8792016-12-19 14:30:17 -0600154 # Set command line arguments
155 parser = argparse.ArgumentParser()
156 parser.add_argument("-w", "--workspace", dest="WORKSPACE", required=True,
157 help="Workspace directory location(i.e. /home)")
158 parser.add_argument("-p", "--package", dest="PACKAGE", required=True,
159 help="OpenBMC package to be unit tested")
160 parser.add_argument("-v", "--verbose", action="store_true",
161 help="Print additional package status messages")
162 args = parser.parse_args(sys.argv[1:])
163 WORKSPACE = args.WORKSPACE
164 UNIT_TEST_PKG = args.PACKAGE
165 if args.verbose:
166 def printline(*line):
167 for arg in line:
168 print arg,
169 print
170 else:
171 printline = lambda *l: None
Matthew Barthccb7f852016-11-23 17:43:02 -0600172
173 prev_umask = os.umask(000)
174 # Determine dependencies and install them
175 dep_installed = dict()
176 dep_installed[UNIT_TEST_PKG] = False
177 dep_installed = build_depends(UNIT_TEST_PKG,
178 os.path.join(WORKSPACE, UNIT_TEST_PKG),
179 dep_installed)
180 os.chdir(os.path.join(WORKSPACE, UNIT_TEST_PKG))
Matthew Barth948b7cc2017-02-21 09:13:54 -0600181 # Refresh dynamic linker run time bindings for dependencies
182 check_call_cmd(os.path.join(WORKSPACE, UNIT_TEST_PKG), 'ldconfig')
Matthew Barthccb7f852016-11-23 17:43:02 -0600183 # Run package unit tests
Matthew Barth4ecbc9c2017-02-17 10:34:46 -0600184 if args.verbose:
185 check_call_cmd(os.path.join(WORKSPACE, UNIT_TEST_PKG), 'make', 'check',
186 'VERBOSE=1')
187 else:
188 check_call_cmd(os.path.join(WORKSPACE, UNIT_TEST_PKG), 'make', 'check')
Matthew Barthccb7f852016-11-23 17:43:02 -0600189 os.umask(prev_umask)