blob: 2626bc08a3680a7899be2130858479248778331f [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 = {
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 Barth710f3f02017-01-18 15:20:19 -0600140 'AC_CHECK_HEADER': {
141 'host-ipmid': 'phosphor-host-ipmid',
142 'sdbusplus': 'sdbusplus',
Brad Bishopebb49112017-02-13 11:07:26 -0500143 'log.hpp': 'phosphor-logging',
Patrick Williamseab8a372017-01-30 11:21:32 -0600144 },
Brad Bishopebb49112017-02-13 11:07:26 -0500145 'AC_PATH_PROG': {'sdbus++': 'sdbusplus'},
Patrick Williamseab8a372017-01-30 11:21:32 -0600146 'PKG_CHECK_MODULES': {
Matthew Barth19e261e2017-02-01 12:55:22 -0600147 'phosphor-dbus-interfaces': 'phosphor-dbus-interfaces',
Brad Bishopebb49112017-02-13 11:07:26 -0500148 'sdbusplus': 'sdbusplus',
149 'phosphor-logging': 'phosphor-logging',
150 },
Matthew Barthccb7f852016-11-23 17:43:02 -0600151 }
152
Matthew Barth33df8792016-12-19 14:30:17 -0600153 # Set command line arguments
154 parser = argparse.ArgumentParser()
155 parser.add_argument("-w", "--workspace", dest="WORKSPACE", required=True,
156 help="Workspace directory location(i.e. /home)")
157 parser.add_argument("-p", "--package", dest="PACKAGE", required=True,
158 help="OpenBMC package to be unit tested")
159 parser.add_argument("-v", "--verbose", action="store_true",
160 help="Print additional package status messages")
161 args = parser.parse_args(sys.argv[1:])
162 WORKSPACE = args.WORKSPACE
163 UNIT_TEST_PKG = args.PACKAGE
164 if args.verbose:
165 def printline(*line):
166 for arg in line:
167 print arg,
168 print
169 else:
170 printline = lambda *l: None
Matthew Barthccb7f852016-11-23 17:43:02 -0600171
172 prev_umask = os.umask(000)
173 # Determine dependencies and install them
174 dep_installed = dict()
175 dep_installed[UNIT_TEST_PKG] = False
176 dep_installed = build_depends(UNIT_TEST_PKG,
177 os.path.join(WORKSPACE, UNIT_TEST_PKG),
178 dep_installed)
179 os.chdir(os.path.join(WORKSPACE, UNIT_TEST_PKG))
180 # Run package unit tests
Matthew Barth33df8792016-12-19 14:30:17 -0600181 check_call_cmd(os.path.join(WORKSPACE, UNIT_TEST_PKG), 'make', 'check')
Matthew Barthccb7f852016-11-23 17:43:02 -0600182 os.umask(prev_umask)