2 """Build OpenDaylight's RPMs using YAML build configs and Jinja2 templates."""
9 from string import Template
14 sys.stderr.write("We recommend using our included Vagrant env.\n")
15 sys.stderr.write("Else, do `pip install -r requirements.txt` in a venv.\n")
18 import cache.cache as cache
19 import specs.build_specs as build_specs
21 # Common paths used in this script
22 # This file is assumed to be in the root of the RPM build logic's dir structure
23 project_root = os.path.dirname(os.path.abspath(__file__))
24 cache_dir = os.path.join(project_root, "cache")
25 specs_dir = os.path.join(project_root, "specs")
26 rpmbuild_dir = os.path.join(os.path.expanduser("~"), "rpmbuild")
27 src_in_dir = os.path.join(rpmbuild_dir, "SOURCES")
28 spec_in_dir = os.path.join(rpmbuild_dir, "SPECS")
29 srpm_out_dir = os.path.join(rpmbuild_dir, "SRPMS")
30 rpm_out_dir = os.path.join(rpmbuild_dir, "RPMS", "noarch")
32 # Templates that can be specialized into common artifact names per-build
33 odl_template = Template("distribution-karaf-0.$version_major."
34 "$version_minor-$codename.tar.gz")
35 specfile_template = Template("opendaylight-$version_major.$version_minor."
36 "$version_patch-$rpm_release.spec")
37 unitfile_tb_template = Template("opendaylight-$sysd_commit.service.tar.gz")
38 rpm_template = Template("opendaylight-$version_major.$version_minor."
39 "$version_patch-$rpm_release.$rpm_disttag.noarch.rpm")
40 srpm_template = Template("opendaylight-$version_major.$version_minor."
41 "$version_patch-$rpm_release.$rpm_disttag.src.rpm")
45 """Build the RPMs described by the given build description.
47 :param build: Description of an RPM build, typically from build_vars.yaml
51 # Specialize a series of name templates for the given build
52 odl_tarball = odl_template.substitute(build)
53 odl_rpm = rpm_template.substitute(build)
54 odl_srpm = srpm_template.substitute(build)
55 odl_specfile = specfile_template.substitute(build)
56 unitfile_tarball = unitfile_tb_template.substitute(build)
58 # After building strings from the name templates, build their full path
59 odl_tarball_path = os.path.join(cache_dir, odl_tarball)
60 unitfile_tarball_path = os.path.join(cache_dir, unitfile_tarball)
61 specfile_path = os.path.join(specs_dir, odl_specfile)
62 spec_in_path = os.path.join(spec_in_dir, odl_specfile)
63 rpm_out_path = os.path.join(rpm_out_dir, odl_rpm)
64 srpm_out_path = os.path.join(srpm_out_dir, odl_srpm)
66 # Call a helper function to cache the artifacts required for each build
67 cache.cache_build(build)
69 # Call helper script to build the required RPM .spec files
70 build_specs.build_spec(build)
72 # Clean up old rpmbuild dir structure if it exists
73 if os.path.isdir(rpmbuild_dir):
74 shutil.rmtree(rpmbuild_dir)
76 # Create rpmbuild dir structure
77 subprocess.call("rpmdev-setuptree")
79 # Move unitfile, tarball and specfile to correct rpmbuild dirs
80 shutil.copy(odl_tarball_path, src_in_dir)
81 shutil.copy(unitfile_tarball_path, src_in_dir)
82 shutil.copy(specfile_path, spec_in_dir)
84 # Call rpmbuild, build both SRPMs/RPMs
85 subprocess.call(["rpmbuild", "-ba", spec_in_path])
87 # Copy the RPMs/SRPMs from their output dir to the cache dir
88 shutil.copy(rpm_out_path, cache_dir)
89 shutil.copy(srpm_out_path, cache_dir)
92 # When run as a script, accept a set of builds and execute them
93 if __name__ == "__main__":
94 # Load RPM build variables from a YAML config file
95 build_vars_path = os.path.join(project_root, "build_vars.yaml")
96 with open(build_vars_path) as rpm_var_file:
97 build_vars = yaml.load(rpm_var_file)
99 # Accept the version(s) of the build(s) to perform as args
100 # TODO: More docs on ArgParser and argument
101 parser = argparse.ArgumentParser()
102 parser.add_argument("-v", "--version", action="append",
103 metavar="major minor patch rpm", nargs="*",
104 help="RPM version(s) to build")
105 parser.add_argument("-a", "--all", action="store_true",
106 help="Build all RPMs")
108 # Print help if no arguments are given
109 if len(sys.argv) == 1:
113 # Parse the given args
114 args = parser.parse_args()
116 # Build list of RPM builds to perform
119 builds = build_vars["builds"]
121 # Build a list of requested versions as dicts of version components
123 version_keys = ["version_major", "version_minor", "version_patch",
125 # For each version arg, match all version components to build_vars name
126 for version in args.version:
127 versions.append(dict(zip(version_keys, version)))
129 # Find every RPM build that matches any version argument
130 # A passed version "matches" a build when the provided version
131 # components are a subset of the version components of a build. Any
132 # version components that aren't passed are simply not checked, so
133 # they can't fail the match, effectively wild-carding them.
134 for build in build_vars["builds"]:
135 for version in versions:
136 # Converts both dicts' key:value pairs to lists of tuples and
137 # checks that each tuple in the version list is present in the
139 if all(item in build.items() for item in version.items()):