2012-06-28 16:32:47 -07:00

288 lines
8.4 KiB
Python
Executable File

#!/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())