Get rpm building working with a template.
This commit is contained in:
parent
80eb005650
commit
6a2ffea82b
276
packages/brpm
276
packages/brpm
@ -6,9 +6,19 @@ import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import re
|
||||
import textwrap
|
||||
import shutil
|
||||
import zipfile
|
||||
|
||||
import glob
|
||||
|
||||
import tempita
|
||||
|
||||
from datetime import datetime
|
||||
from datetime import date
|
||||
|
||||
from distutils import version as ver
|
||||
|
||||
# This is more just for running from the bin folder so that
|
||||
# cloud-init binary can find the cloudinit module
|
||||
possible_topdir = os.path.normpath(os.path.join(os.path.abspath(
|
||||
@ -16,28 +26,268 @@ possible_topdir = os.path.normpath(os.path.join(os.path.abspath(
|
||||
if os.path.exists(os.path.join(possible_topdir, "cloudinit", "__init__.py")):
|
||||
sys.path.insert(0, possible_topdir)
|
||||
|
||||
from cloudinit import util
|
||||
from cloudinit import version
|
||||
|
||||
import contextlib
|
||||
|
||||
# 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 chdir(where_to):
|
||||
cur_cwd = os.path.abspath(os.getcwd())
|
||||
where_to = os.path.abspath(where_to)
|
||||
os.chdir(where_to)
|
||||
yield where_to
|
||||
os.chdir(cur_cwd)
|
||||
|
||||
|
||||
PWD = os.getcwd()
|
||||
|
||||
def info(msg):
|
||||
sys.stderr.write("INFO: %s\n" % (msg))
|
||||
print("INFO: %s" % (msg))
|
||||
|
||||
|
||||
def warn(msg):
|
||||
sys.stderr.write("WARNING: %s\n" % (msg))
|
||||
print("WARNING: %s" % (msg))
|
||||
|
||||
|
||||
def cut_up(entry, maxline=80):
|
||||
if len(entry) < maxline:
|
||||
return entry
|
||||
else:
|
||||
c = entry[0:maxline]
|
||||
return "%s..." % (c)
|
||||
|
||||
|
||||
def extract_entry(collecting):
|
||||
a_entry = {}
|
||||
for t in ['tags', 'revno', 'author', 'timestamp', 'committer']:
|
||||
look_for = "%s:" % (t)
|
||||
for v in collecting:
|
||||
if v.startswith(look_for):
|
||||
a_entry[t] = v[len(look_for):].strip()
|
||||
break
|
||||
i = -1
|
||||
for a, v in enumerate(collecting):
|
||||
if v.startswith("message:"):
|
||||
i = a
|
||||
break
|
||||
if i != -1:
|
||||
msg_lines = collecting[i + 1:]
|
||||
n_lines = []
|
||||
for m in msg_lines:
|
||||
m = m.strip()
|
||||
if not m:
|
||||
continue
|
||||
m = m.replace("\n", " ")
|
||||
n_lines.append("" + m.lstrip())
|
||||
message = " ".join(n_lines).lstrip()
|
||||
a_entry['message'] = message
|
||||
return a_entry
|
||||
|
||||
|
||||
def build_changelog(history=-1):
|
||||
cmd = ['bzr', 'log', '--timezone=utc']
|
||||
(stdout, _stderr) = util.subp(cmd)
|
||||
# Clean the format up
|
||||
entries = stdout.splitlines()
|
||||
all_entries = []
|
||||
collecting = []
|
||||
for e in entries:
|
||||
if e.startswith("---"):
|
||||
if collecting:
|
||||
a_entry = extract_entry(collecting)
|
||||
if a_entry:
|
||||
all_entries.append(a_entry)
|
||||
collecting = []
|
||||
else:
|
||||
collecting.append(e)
|
||||
|
||||
a_entry = extract_entry(collecting)
|
||||
if a_entry:
|
||||
all_entries.append(a_entry)
|
||||
|
||||
if history > 0:
|
||||
take_entries = list(all_entries[0:history])
|
||||
else:
|
||||
take_entries = list(all_entries)
|
||||
|
||||
# Merge those with same date
|
||||
date_entries = {}
|
||||
for e in take_entries:
|
||||
author = e.get('author')
|
||||
if not author:
|
||||
author = e.get('committer')
|
||||
if not author:
|
||||
continue
|
||||
timestamp = e.get('timestamp')
|
||||
if not timestamp:
|
||||
continue
|
||||
msg = e.get('message')
|
||||
if not msg:
|
||||
continue
|
||||
revno = e.get('revno')
|
||||
if not revno:
|
||||
continue
|
||||
# http://bugs.python.org/issue6641
|
||||
timestamp = timestamp.replace("+0000", '').strip()
|
||||
ds = datetime.strptime(timestamp, '%a %Y-%m-%d %H:%M:%S')
|
||||
c_ds = ds.date()
|
||||
if c_ds not in date_entries:
|
||||
ap_entry = {}
|
||||
ap_entry['messages'] = []
|
||||
ap_entry['authors'] = []
|
||||
ap_entry['revnos'] = []
|
||||
date_entries[c_ds] = ap_entry
|
||||
ap_entry = date_entries[c_ds]
|
||||
ap_entry['messages'].append(msg)
|
||||
ap_entry['authors'].append(author)
|
||||
ap_entry['revnos'].append(revno)
|
||||
|
||||
dates = sorted(date_entries.keys())
|
||||
chglog = []
|
||||
for ds in reversed(dates):
|
||||
e = date_entries[ds]
|
||||
authors = ", ".join(set(e['authors']))
|
||||
revnos = ", ".join(list(sorted(e['revnos'])))
|
||||
top_line = "%s %s - %s" % (ds.strftime("%a %b %d %Y"),
|
||||
authors, revnos)
|
||||
chglog.append("* %s" % (top_line))
|
||||
for msg in e['messages']:
|
||||
chglog.append("- %s" % (cut_up(msg)))
|
||||
return "\n".join(chglog)
|
||||
|
||||
|
||||
def generate_spec_contents(tmpl_fn):
|
||||
# Version junk
|
||||
cmd = [os.path.join(os.pardir, 'tools', 'read-version')]
|
||||
(stdout, _stderr) = util.subp(cmd)
|
||||
i_version = stdout.strip()
|
||||
|
||||
# Ensure ok match!
|
||||
if ver.StrictVersion(i_version) != version.version():
|
||||
raise RuntimeError("Version found does not match the code version")
|
||||
|
||||
# Tmpl params
|
||||
subs = {}
|
||||
subs['version'] = i_version
|
||||
(stdout, _stderr) = util.subp(['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 = [os.path.join(os.pardir, 'tools', 'read-dependencies')]
|
||||
(stdout, _stderr) = util.subp(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
|
||||
subs['changelog'] = build_changelog()
|
||||
|
||||
# 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():
|
||||
if not os.path.isfile(os.path.join(PWD, 'brpm.tmpl')):
|
||||
warn("Can not find required template file 'brpm.tmpl'")
|
||||
return 1
|
||||
if not os.path.isfile(os.path.join(os.pardir, 'setup.py')):
|
||||
warn("Can not find required root 'setup.py' file")
|
||||
return 1
|
||||
|
||||
cmd = [os.path.join(os.pardir, 'tools', 'read-version')]
|
||||
version = subprocess.check_Call(cmd)
|
||||
|
||||
|
||||
root_dir = os.path.expanduser("~/rpmbuild")
|
||||
info("Cleaning %s" % (root_dir))
|
||||
util.delete_dir_contents(root_dir)
|
||||
arc_dir = os.path.join(root_dir, 'SOURCES')
|
||||
util.ensure_dirs([root_dir, arc_dir])
|
||||
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')
|
||||
util.write_file(spec_fn, contents)
|
||||
info("Wrote spec file to %s" % (spec_fn))
|
||||
with util.tempdir() 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))
|
||||
util.subp(cmd)
|
||||
info("Archived code at %s" % (arc_fn))
|
||||
cmd = ['rpmbuild', '-ba', spec_fn]
|
||||
info("Running rpmbuild %s" % (cmd))
|
||||
util.subp(cmd)
|
||||
info("Rpmbuild completed!")
|
||||
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
|
||||
|
||||
|
||||
|
@ -9,28 +9,21 @@ Group: System Environment/Base
|
||||
License: GPLv3
|
||||
URL: http://launchpad.net/cloud-init
|
||||
|
||||
Source0: %{name}-%{version}-bzr532.tar.gz
|
||||
Source0: {{archive_name}}
|
||||
|
||||
BuildArch: noarch
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||
|
||||
BuildRequires: python-devel
|
||||
BuildRequires: python-setuptools-devel
|
||||
Requires: e2fsprogs
|
||||
Requires: iproute
|
||||
Requires: libselinux-python
|
||||
Requires: net-tools
|
||||
Requires: procps
|
||||
Requires: python-boto
|
||||
Requires: python-cheetah
|
||||
Requires: python-configobj
|
||||
Requires: PyYAML
|
||||
Requires: rsyslog
|
||||
Requires: shadow-utils
|
||||
Requires: /usr/bin/run-parts
|
||||
Requires(post): chkconfig
|
||||
Requires(preun): chkconfig
|
||||
Requires(postun): initscripts
|
||||
BuildRoot: %{_tmppath}
|
||||
|
||||
|
||||
{{for r in bd_requires}}
|
||||
BuildRequires: {{r}}
|
||||
{{endfor}}
|
||||
|
||||
# Install requirements
|
||||
{{for r in requires}}
|
||||
Requires: {{r}}
|
||||
{{endfor}}
|
||||
|
||||
%description
|
||||
Cloud-init is a set of init scripts for cloud instances. Cloud instances
|
||||
@ -39,14 +32,7 @@ ssh keys and to let the user run various scripts.
|
||||
|
||||
|
||||
%prep
|
||||
%setup -q -n %{name}-%{version}-bzr532
|
||||
%patch0 -p0
|
||||
%patch1 -p0
|
||||
%patch2 -p1
|
||||
%patch3 -p1
|
||||
|
||||
cp -p %{SOURCE2} README.fedora
|
||||
|
||||
%setup -q -n %{name}-%{version}-{{revno}}
|
||||
|
||||
%build
|
||||
%{__python} setup.py build
|
||||
@ -56,118 +42,29 @@ cp -p %{SOURCE2} README.fedora
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
%{__python} setup.py install -O1 --skip-build --root $RPM_BUILD_ROOT
|
||||
|
||||
for x in $RPM_BUILD_ROOT/%{_bindir}/*.py; do mv "$x" "${x%.py}"; done
|
||||
chmod +x $RPM_BUILD_ROOT/%{python_sitelib}/cloudinit/SshUtil.py
|
||||
mkdir -p $RPM_BUILD_ROOT/%{_sharedstatedir}/cloud
|
||||
|
||||
# We supply our own config file since our software differs from Ubuntu's.
|
||||
cp -p %{SOURCE1} $RPM_BUILD_ROOT/%{_sysconfdir}/cloud/cloud.cfg
|
||||
|
||||
# Note that /etc/rsyslog.d didn't exist by default until F15.
|
||||
# el6 request: https://bugzilla.redhat.com/show_bug.cgi?id=740420
|
||||
mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/rsyslog.d
|
||||
cp -p tools/21-cloudinit.conf $RPM_BUILD_ROOT/%{_sysconfdir}/rsyslog.d/21-cloudinit.conf
|
||||
|
||||
# Install the init scripts
|
||||
install -p -D -m 755 %{SOURCE3} %{buildroot}%{_initrddir}/cloud-config
|
||||
install -p -D -m 755 %{SOURCE4} %{buildroot}%{_initrddir}/cloud-final
|
||||
install -p -D -m 755 %{SOURCE5} %{buildroot}%{_initrddir}/cloud-init
|
||||
install -p -D -m 755 %{SOURCE6} %{buildroot}%{_initrddir}/cloud-init-local
|
||||
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
|
||||
%post
|
||||
if [ $1 -eq 1 ] ; then
|
||||
# Initial installation
|
||||
# Enabled by default per "runs once then goes away" exception
|
||||
for svc in config final init init-local; do
|
||||
chkconfig --add cloud-$svc
|
||||
chkconfig cloud-$svc on
|
||||
done
|
||||
fi
|
||||
|
||||
%preun
|
||||
if [ $1 -eq 0 ] ; then
|
||||
# Package removal, not upgrade
|
||||
for svc in config final init init-local; do
|
||||
chkconfig --del cloud-$svc
|
||||
chkconfig cloud-$svc on
|
||||
done
|
||||
# One-shot services -> no need to stop
|
||||
fi
|
||||
|
||||
%postun
|
||||
# One-shot services -> no need to restart
|
||||
|
||||
|
||||
%files
|
||||
%doc ChangeLog LICENSE TODO README.fedora
|
||||
%config(noreplace) %{_sysconfdir}/cloud/cloud.cfg
|
||||
%dir %{_sysconfdir}/cloud/cloud.cfg.d
|
||||
%config(noreplace) %{_sysconfdir}/cloud/cloud.cfg.d/*.cfg
|
||||
%doc %{_sysconfdir}/cloud/cloud.cfg.d/README
|
||||
%dir %{_sysconfdir}/cloud/templates
|
||||
%config(noreplace) %{_sysconfdir}/cloud/templates/*
|
||||
%{_initrddir}/cloud-*
|
||||
|
||||
# Docs
|
||||
{{for r in docs}}
|
||||
%doc {{r}}
|
||||
{{endfor}}
|
||||
|
||||
# Configs
|
||||
{{for r in configs}}
|
||||
%config(noreplace) %{_sysconfdir}/{{r}}
|
||||
{{endfor}}
|
||||
|
||||
# Other files
|
||||
{{for r in files}}
|
||||
{{r}}
|
||||
{{endfor}}
|
||||
|
||||
# Python sitelib
|
||||
%{python_sitelib}/*
|
||||
%{_libexecdir}/%{name}
|
||||
%{_bindir}/cloud-init*
|
||||
%doc %{_datadir}/doc/%{name}
|
||||
%dir %{_sharedstatedir}/cloud
|
||||
|
||||
%config(noreplace) %{_sysconfdir}/rsyslog.d/21-cloudinit.conf
|
||||
|
||||
|
||||
%changelog
|
||||
* Mon Jun 18 2012 Pádraig Brady <P@draigBrady.com> - 0.6.3-0.6.bzr532
|
||||
- Further adjustments to support EPEL 6
|
||||
|
||||
* Fri Jun 15 2012 Tomas Karasek <tomas.karasek@cern.ch> - 0.6.3-0.5.bzr532
|
||||
- Fix cloud-init-cfg invocation in init script
|
||||
|
||||
* Tue May 22 2012 Pádraig Brady <P@draigBrady.com> - 0.6.3-0.4.bzr532
|
||||
- Support EPEL 6
|
||||
|
||||
* Sat Mar 31 2012 Andy Grimm <agrimm@gmail.com> - 0.6.3-0.2.bzr532
|
||||
- Fixed incorrect interpretation of relative path for
|
||||
AuthorizedKeysFile (BZ #735521)
|
||||
|
||||
* Mon Mar 5 2012 Garrett Holmstrom <gholms@fedoraproject.org> - 0.6.3-0.1.bzr532
|
||||
- Rebased against upstream rev 532
|
||||
- Fixed runparts() incompatibility with Fedora
|
||||
|
||||
* Thu Jan 12 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.6.2-0.8.bzr457
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild
|
||||
|
||||
* Wed Oct 5 2011 Garrett Holmstrom <gholms@fedoraproject.org> - 0.6.2-0.7.bzr457
|
||||
- Disabled SSH key-deleting on startup
|
||||
|
||||
* Wed Sep 28 2011 Garrett Holmstrom <gholms@fedoraproject.org> - 0.6.2-0.6.bzr457
|
||||
- Consolidated selinux file context patches
|
||||
- Fixed cloud-init.service dependencies
|
||||
- Updated sshkeytypes patch
|
||||
- Dealt with differences from Ubuntu's sshd
|
||||
|
||||
* Sat Sep 24 2011 Garrett Holmstrom <gholms@fedoraproject.org> - 0.6.2-0.5.bzr457
|
||||
- Rebased against upstream rev 457
|
||||
- Added missing dependencies
|
||||
|
||||
* Fri Sep 23 2011 Garrett Holmstrom <gholms@fedoraproject.org> - 0.6.2-0.4.bzr450
|
||||
- Added more macros to the spec file
|
||||
|
||||
* Fri Sep 23 2011 Garrett Holmstrom <gholms@fedoraproject.org> - 0.6.2-0.3.bzr450
|
||||
- Fixed logfile permission checking
|
||||
- Fixed SSH key generation
|
||||
- Fixed a bad method call in FQDN-guessing [LP:857891]
|
||||
- Updated localefile patch
|
||||
- Disabled the grub_dpkg module
|
||||
- Fixed failures due to empty script dirs [LP:857926]
|
||||
|
||||
* Fri Sep 23 2011 Garrett Holmstrom <gholms@fedoraproject.org> - 0.6.2-0.2.bzr450
|
||||
- Updated tzsysconfig patch
|
||||
|
||||
* Wed Sep 21 2011 Garrett Holmstrom <gholms@fedoraproject.org> - 0.6.2-0.1.bzr450
|
||||
- Initial packaging
|
||||
{{changelog}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user