#!/usr/bin/python import contextlib import glob import os import shutil import subprocess import sys import tempfile import tempita # Mapping of expected packages to there full name... PKG_MP = { 'boto': 'python-boto', 'tempita': 'python-tempita', 'prettytable': 'python-prettytable', 'oauth': 'python-oauth', 'configobj': 'python-configobj', 'yaml': 'PyYAML', 'argparse': 'python-argparse' } @contextlib.contextmanager def tmpdir(): t = tempfile.mkdtemp() try: yield t finally: shutil.rmtree(t) def join(*paths): p = os.path.join(*paths) return os.path.abspath(p) def tiny_p(cmd): # Darn python 2.6 doesn't have check_output (argggg) info("Running %s" % (cmd)) sp = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=None) (out, err) = sp.communicate() if sp.returncode not in [0]: raise RuntimeError("Failed running %s [rc=%s]" % (cmd, sp.returncode)) return (out, err) def info(msg): print("INFO: %s" % (msg)) def warn(msg): print("WARNING: %s" % (msg)) def generate_spec_contents(tmpl_fn): # Version junk cmd = [sys.executable, join(os.pardir, 'tools', 'read-version')] (stdout, _stderr) = tiny_p(cmd) i_version = stdout.strip() # Tmpl params subs = {} subs['version'] = i_version (stdout, _stderr) = tiny_p(['bzr', 'revno']) subs['revno'] = "%s" % (stdout.strip()) subs['release'] = "%s" % (subs['revno']) subs['archive_name'] = '%{name}-%{version}-' + subs['revno'] + '.tar.gz' subs['bd_requires'] = ['python-devel', 'python-setuptools'] requires = [] cmd = [sys.executable, join(os.pardir, 'tools', 'read-dependencies')] (stdout, _stderr) = tiny_p(cmd) pkgs = stdout.splitlines() # Map to known packages for e in pkgs: e = e.lower().strip() tgt_pkg = None for n in PKG_MP.keys(): if e.find(n) != -1: tgt_pkg = PKG_MP.get(n) if not tgt_pkg: raise RuntimeError(("Do not know how to translate %s to " " a known package") % (e)) else: requires.append(tgt_pkg) base_name = 'cloud-init-%s-%s' % (i_version, subs['revno']) subs['requires'] = requires (stdout, _stderr) = tiny_p([sys.executable, join(os.getcwd(), 'rpm-changelog')]) subs['changelog'] = stdout # See: http://www.zarb.org/~jasonc/macros.php # Pickup any special files docs = [ 'TODO', 'LICENSE', 'ChangeLog', 'Requires', '%{_defaultdocdir}/cloud-init/*', ] subs['docs'] = docs configs = [ 'cloud/cloud.cfg', 'cloud/cloud.cfg.d/*.cfg', 'cloud/cloud.cfg.d/README', 'cloud/templates/*', ] subs['configs'] = configs other_files = [ '%{_bindir}/*', '/usr/lib/cloud-init/*', ] subs['files'] = other_files with open(tmpl_fn, 'r') as fh: tmpl = tempita.Template(fh.read()) contents = tmpl.substitute(**subs) return (base_name, '%s.tar.gz' % (base_name), contents) def main(): # Clean out the root dir and make sure the dirs we want are in place root_dir = os.path.expanduser("~/rpmbuild") info("Cleaning %s" % (root_dir)) if os.path.isdir(root_dir): shutil.rmtree(root_dir) arc_dir = os.path.join(root_dir, 'SOURCES') for d in [root_dir, arc_dir]: os.makedirs(d) # Form the spec file to be used tmpl_fn = os.path.join(os.getcwd(), 'brpm.tmpl') info("Generated spec file from template %s" % (tmpl_fn)) (base_name, arc_name, contents) = generate_spec_contents(tmpl_fn) spec_fn = os.path.join(root_dir, 'cloud-init.spec') with open(spec_fn, 'w') as fh: fh.write(contents) info("Wrote spec file to %s" % (spec_fn)) # Archive the code and files that we want to with tmpdir() as td: src_dir = os.path.join(td, base_name) os.makedirs(src_dir) for fn in os.listdir(os.pardir): if fn.startswith("."): continue full_fn = os.path.abspath(os.path.join(os.pardir, fn)) if os.path.isfile(full_fn): shutil.copy(full_fn, os.path.join(src_dir, fn)) else: shutil.copytree(full_fn, os.path.join(src_dir, fn), ignore=shutil.ignore_patterns('*.pyc', '.bzr', 'tmp*', '*bzr*')) arc_fn = os.path.join(arc_dir, arc_name) cmd = ['tar', '-zcvf', arc_fn, '-C', td] cmd.extend(os.listdir(td)) tiny_p(cmd) info("Archived code at %s" % (arc_fn)) # Now build it! cmd = ['rpmbuild', '-ba', spec_fn] info("Running rpmbuild %s" % (cmd)) tiny_p(cmd) info("Rpmbuild completed!") # Copy the items built to our local dir globs = [] globs.extend(glob.glob("%s/*.rpm" % (os.path.join(root_dir, 'RPMS', 'noarch')))) globs.extend(glob.glob("%s/*.rpm" % (os.path.join(root_dir, 'RPMS')))) globs.extend(glob.glob("%s/*.rpm" % (os.path.join(root_dir, 'SRPMS')))) for fn in globs: n = os.path.basename(fn) tgt_fn = os.path.join(os.getcwd(), n) util.copy(fn, tgt_fn) info("Copied %s to %s" % (n, tgt_fn)) return 0 if __name__ == '__main__': sys.exit(main())