2012-06-26 00:48:55 -07:00

241 lines
6.7 KiB
Python
Executable File

#!/usr/bin/python
import contextlib
import glob
import os
import shutil
import subprocess
import sys
import tempfile
import re
import tempita
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'
}
@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, capture=True):
# Darn python 2.6 doesn't have check_output (argggg)
info("Running %s" % (cmd))
stdout = subprocess.PIPE
stderr = subprocess.PIPE
if not capture:
stdout = None
stderr = None
sp = subprocess.Popen(cmd, stdout=stdout,
stderr=stderr, stdin=None)
(out, err) = sp.communicate()
if sp.returncode not in [0]:
raise RuntimeError("Failed running %s [rc=%s] (%s, %s)"
% (cmd, sp.returncode, out, err))
return (out, err)
def get_log_header(version):
cmd = ['bzr', 'tags']
(stdout, _stderr) = tiny_p(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)
cmd = ['bzr', 'log', '-r%s' % (a_rev), '--timezone=utc']
(stdout, _stderr) = tiny_p(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 = format_rpm_date(ds)
d += " - %s" % (who)
if comment:
d += " - %s" % (comment)
return "* %s" % (d)
def format_rpm_date(ds):
return ds.strftime("%a %b %d %Y")
def info(msg):
print("INFO: %s" % (msg))
def warn(msg):
print("WARNING: %s" % (msg))
def generate_spec_contents(tmpl_fn, revno, version):
# Tmpl params
subs = {}
subs['version'] = version
subs['revno'] = revno
subs['release'] = 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' % (version, subs['revno'])
subs['requires'] = requires
# Format a nice changelog (as best as we can)
changelog = ''
with open(join(os.pardir, 'ChangeLog')) as fh:
changelog = fh.read()
ch_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)
ch_lines.append(header)
else:
ch_lines.append(line)
subs['changelog'] = "\n".join(ch_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/*',
]
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 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():
# Clean out the root dir and make sure the dirs we want are in place
root_dir = os.path.expanduser("~/rpmbuild")
info("Cleaning %r" % (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)
# Archive the code
(revno, version, archive_fn) = archive_code()
real_archive_fn = os.path.join(arc_dir, os.path.basename(archive_fn))
shutil.move(archive_fn, real_archive_fn)
info("Archived code to %r" % (real_archive_fn))
# Form the spec file to be used
tmpl_fn = os.path.join(os.getcwd(), 'redhat', 'cloud-init.spec')
info("Generated spec file from template %r" % (tmpl_fn))
(base_name, arc_name, contents) = generate_spec_contents(tmpl_fn,
revno, version)
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 %r" % (spec_fn))
# Now build it!
cmd = ['rpmbuild', '-ba', spec_fn]
tiny_p(cmd, capture=False)
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)
shutil.move(fn, tgt_fn)
info("Copied %s to %s" % (n, tgt_fn))
return 0
if __name__ == '__main__':
sys.exit(main())