summaryrefslogtreecommitdiff
path: root/packages/brpm
diff options
context:
space:
mode:
Diffstat (limited to 'packages/brpm')
-rwxr-xr-xpackages/brpm287
1 files changed, 287 insertions, 0 deletions
diff --git a/packages/brpm b/packages/brpm
new file mode 100755
index 00000000..bbf30565
--- /dev/null
+++ b/packages/brpm
@@ -0,0 +1,287 @@
+#!/usr/bin/python
+
+import contextlib
+import glob
+import os
+import shutil
+import subprocess
+import sys
+import tempfile
+import re
+
+import argparse
+
+# Use the util functions from cloudinit
+possible_topdir = os.path.normpath(os.path.join(os.path.abspath(
+ sys.argv[0]), os.pardir, os.pardir))
+if os.path.exists(os.path.join(possible_topdir, "cloudinit", "__init__.py")):
+ sys.path.insert(0, possible_topdir)
+
+from cloudinit import templater
+from cloudinit import util
+
+from datetime import datetime
+
+
+# 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'
+}
+
+
+def get_log_header(version):
+ # Try to find the version in the tags output
+ cmd = ['bzr', 'tags']
+ (stdout, _stderr) = util.subp(cmd)
+ a_rev = None
+ for t in stdout.splitlines():
+ ver, rev = t.split(None)
+ if ver == version:
+ a_rev = rev
+ break
+ if not a_rev:
+ return format_change_line(datetime.now(),
+ '??', version)
+
+ # Extract who made that tag as the header
+ cmd = ['bzr', 'log', '-r%s' % (a_rev), '--timezone=utc']
+ (stdout, _stderr) = util.subp(cmd)
+ kvs = {
+ 'comment': version,
+ }
+
+ for line in stdout.splitlines():
+ if line.startswith('committer:'):
+ kvs['who'] = line[len('committer:'):].strip()
+ if line.startswith('timestamp:'):
+ ts = line[len('timestamp:'):]
+ ts = ts.strip()
+ # http://bugs.python.org/issue6641
+ ts = ts.replace("+0000", '').strip()
+ ds = datetime.strptime(ts, '%a %Y-%m-%d %H:%M:%S')
+ kvs['ds'] = ds
+
+ return format_change_line(**kvs)
+
+
+def format_change_line(ds, who, comment=None):
+ d = ds.strftime("%a %b %d %Y")
+ d += " - %s" % (who)
+ if comment:
+ d += " - %s" % (comment)
+ return "* %s" % (d)
+
+
+def generate_spec_contents(args, tmpl_fn):
+
+ # Figure out the version and revno
+ cmd = [sys.executable,
+ util.abs_join(os.pardir, 'tools', 'read-version')]
+ (stdout, _stderr) = util.subp(cmd)
+ version = stdout.strip()
+
+ cmd = ['bzr', 'revno']
+ (stdout, _stderr) = util.subp(cmd)
+ revno = stdout.strip()
+
+ # Tmpl params
+ subs = {}
+ subs['version'] = version
+ subs['revno'] = revno
+ subs['release'] = revno
+ subs['archive_name'] = '%{name}-%{version}-' + revno + '.tar.gz'
+ subs['bd_requires'] = ['python-devel', 'python-setuptools']
+
+ cmd = [sys.executable,
+ util.abs_join(os.pardir, 'tools', 'read-dependencies')]
+ (stdout, _stderr) = util.subp(cmd)
+
+ # Map to known packages
+ pkgs = [p.lower().strip() for p in stdout.splitlines()]
+
+ # Map to known packages
+ requires = []
+ for p in pkgs:
+ tgt_pkg = None
+ for name in PKG_MP.keys():
+ if p.find(name) != -1:
+ tgt_pkg = PKG_MP.get(name)
+ break
+ if not tgt_pkg:
+ raise RuntimeError(("Do not know how to translate %s to "
+ " a known package") % (p))
+ else:
+ requires.append(tgt_pkg)
+ subs['requires'] = requires
+
+ # Format a nice changelog (as best as we can)
+ changelog = util.load_file(util.abs_join(os.pardir, 'ChangeLog'))
+ changelog_lines = []
+ for line in changelog.splitlines():
+ if not line.strip():
+ continue
+ if re.match(r"^\s*[\d][.][\d][.][\d]:\s*", line):
+ line = line.strip(":")
+ header = get_log_header(line)
+ changelog_lines.append(header)
+ else:
+ changelog_lines.append(line)
+ subs['changelog'] = "\n".join(changelog_lines)
+
+ # 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/*',
+ ]
+
+ # Since setup.py installs them all, we need to selectively
+ # remove the wrong ones and ensure the right one/s are kept
+ # for the boot mode that is desired...
+ boot_remove = {
+ 'initd': [
+ '/etc/init.d/cloud-init-local',
+ # Remove the other auto-start folders
+ '/etc/systemd/',
+ '/etc/init/',
+ ],
+ 'initd-local': [
+ '/etc/init.d/cloud-init',
+ # Remove the other auto-start folders
+ '/etc/systemd/',
+ '/etc/init/',
+ ],
+ # It seems like systemd can work with
+ # all of its files being 'active' (and not have naming
+ # or event name conflicts??)
+ 'systemd': [
+ # Remove the other auto-start folders
+ '/etc/init.d/',
+ '/etc/init/',
+ ],
+ 'upstart': [
+ '/etc/init/cloud-init-nonet.conf',
+ '/etc/init/cloud-init-local.conf',
+ # Remove the other auto-start folders
+ '/etc/init.d/',
+ '/etc/systemd/',
+ ],
+ 'upstart-local': [
+ '/etc/init/cloud-init.conf',
+ # Remove the other auto-start folders
+ '/etc/init.d/',
+ '/etc/systemd/',
+ ]
+ }
+ boot_keep = {
+ 'systemd': [
+ '/etc/systemd/*',
+ ],
+ 'upstart': [
+ '/etc/init/*',
+ ],
+ 'upstart-local': [
+ '/etc/init/*',
+ ],
+ 'initd-local': [
+ '/etc/init.d/*',
+ ],
+ 'initd': [
+ '/etc/init.d/*',
+ ],
+ }
+ subs['post_remove'] = boot_remove[args.boot]
+ other_files.extend(boot_keep[args.boot])
+ subs['files'] = other_files
+ return templater.render_from_file(tmpl_fn, params=subs)
+
+
+def archive_code():
+ (stdout, _stderr) = tiny_p([sys.executable,
+ join(os.getcwd(), 'make-tarball')])
+ (revno, version, bname, arc_fn) = stdout.split(None)
+ return (revno, version, arc_fn)
+
+
+def main():
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument("-b", "--boot", dest="boot",
+ help="select boot type (default: %(default)s)",
+ metavar="TYPE", default='initd',
+ choices=('upstart', 'initd', 'systemd',
+ 'upstart-local', 'initd-local'))
+ parser.add_argument("-v", "--verbose", dest="verbose",
+ help=("run verbosely"
+ " (default: %(default)s)"),
+ default=False,
+ action='store_true')
+ args = parser.parse_args()
+ capture = True
+ if args.verbose:
+ capture = False
+
+ # Clean out the root dir and make sure the dirs we want are in place
+ root_dir = os.path.expanduser("~/rpmbuild")
+ if os.path.isdir(root_dir):
+ shutil.rmtree(root_dir)
+ arc_dir = util.abs_join(root_dir, 'SOURCES')
+ util.ensure_dirs([root_dir, arc_dir])
+
+ # Archive the code
+ cmd = [sys.executable,
+ util.abs_join(os.getcwd(), 'make-tarball')]
+ (stdout, _stderr) = util.subp(cmd)
+ archive_fn = stdout.strip()
+ real_archive_fn = os.path.join(arc_dir, os.path.basename(archive_fn))
+ shutil.move(archive_fn, real_archive_fn)
+
+ # Form the spec file to be used
+ tmpl_fn = util.abs_join(os.getcwd(), 'redhat', 'cloud-init.spec')
+ contents = generate_spec_contents(args, tmpl_fn)
+ spec_fn = os.path.join(root_dir, 'cloud-init.spec')
+ util.write_file(spec_fn, contents)
+
+ # Now build it!
+ cmd = ['rpmbuild', '-ba', spec_fn]
+ util.subp(cmd, capture=capture)
+
+ # 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 rpm_fn in globs:
+ tgt_fn = util.abs_join(os.getcwd(), os.path.basename(rpm_fn))
+ shutil.move(rpm_fn, tgt_fn)
+ print(tgt_fn)
+
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main())