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("opendaylight-$version_major.$version_minor."
34 "$version_patch-$rpm_release.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.el7.noarch.rpm")
40 srpm_template = Template("opendaylight-$version_major.$version_minor."
41 "$version_patch-$rpm_release.el7.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 existing_build_group = parser.add_argument_group("Existing build")
103 existing_build_group.add_argument(
104 "-v", "--version", action="append", metavar="major minor patch rpm",
105 nargs="*", help="RPM version(s) to build"
107 new_build_group = parser.add_argument_group("New build")
108 new_build_group.add_argument("--major", help="Major (element) version to build")
109 new_build_group.add_argument("--minor", help="Minor (SR) version to build")
110 new_build_group.add_argument("--patch", help="Patch version to build")
111 new_build_group.add_argument("--rpm", help="RPM version to build")
112 new_build_group.add_argument("--sysd_commit", help="Version of ODL unitfile to package")
113 new_build_group.add_argument("--codename", help="Codename for ODL version")
114 new_build_group.add_argument("--download_url", help="Tarball to repackage into RPM")
115 new_build_group.add_argument("--changelog_date", help="Date this RPM was defined")
116 new_build_group.add_argument("--changelog_name", help="Name of person who defined RPM")
117 new_build_group.add_argument("--changelog_email", help="Email of person who defined RPM")
119 # Print help if no arguments are given
120 if len(sys.argv) == 1:
124 # Parse the given args
125 args = parser.parse_args()
127 # Build list of RPM builds to perform
130 # Build a list of requested versions as dicts of version components
132 version_keys = ["version_major", "version_minor", "version_patch",
134 # For each version arg, match all version components to build_vars name
135 for version in args.version:
136 versions.append(dict(zip(version_keys, version)))
138 # Find every RPM build that matches any version argument
139 # A passed version "matches" a build when the provided version
140 # components are a subset of the version components of a build. Any
141 # version components that aren't passed are simply not checked, so
142 # they can't fail the match, effectively wild-carding them.
143 for build in build_vars["builds"]:
144 for version in versions:
145 # Converts both dicts' key:value pairs to lists of tuples and
146 # checks that each tuple in the version list is present in the
148 if all(item in build.items() for item in version.items()):
151 builds.append({"version_major": args.major,
152 "version_minor": args.minor,
153 "version_patch": args.patch,
154 "rpm_release": args.rpm,
155 "sysd_commit": args.sysd_commit,
156 "codename": args.codename,
157 "download_url": args.download_url,
158 "changelog_date": args.changelog_date,
159 "changelog_name": args.changelog_name,
160 "changelog_email": args.changelog_email})