From 85de6a53e2c055ecffbd396c877d62cfa33f66d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=A1gr?= Date: Fri, 26 Sep 2014 12:22:01 +0200 Subject: [PATCH] Added spec command --- README | 7 +- bade/bade.py | 49 ++++++++ bade/commands/__init__.py | 2 +- bade/commands/spec.py | 108 ++++++++++++++++++ .../openstack-puppet-modules.template | 50 ++++++++ requirements.txt | 1 + setup.py | 3 + 7 files changed, 218 insertions(+), 2 deletions(-) create mode 100644 bade/commands/spec.py create mode 100644 bade/templates/openstack-puppet-modules.template diff --git a/README b/README index f556a4d..012dc73 100644 --- a/README +++ b/README @@ -17,9 +17,14 @@ b) run "bade sync" a) do your updates in Puppetfile, commit changes in Puppetfile b) run "bade sync" or "bade init --commit" if you want to generate a commit too +4. To generate SPEC file from Puppetfile and tag repo with "version-release" tag: +a) do step 3. +b) run "spec --version --release --old /path/to/current/file.spec --output /path/to/new/file.spec" + TO-DO: -- spec command for generating SPEC file from template +- spec command for generating SPEC file from template [DONE] +- spec command should parse patches from old file - add command for adding modules - rm command for removing modules - unit tests diff --git a/bade/bade.py b/bade/bade.py index cb61127..e6ce67b 100644 --- a/bade/bade.py +++ b/bade/bade.py @@ -23,10 +23,18 @@ # import click +import os from . import commands from . import utils + +DEFAULT_OUTPUT = os.path.expanduser( + '~/rpmbuild/SPECS/openstack-puppet-modules.spec' +) +DEFAULT_TEMPLATE = 'openstack-puppet-modules.template' + + # Setup option container class Config(object): def __init__(self): @@ -100,5 +108,46 @@ def sync_wrapper(config, repo, commit): raise +@bade.command('spec') +@click.option('--version', required=True, + help='Version for a tag.') +@click.option('--release', required=True, + help='Release for a tag.') +@click.option('--old', required=True, + help='Path to old SPEC file.') +@click.option('--output', default=DEFAULT_OUTPUT, + help='Path to output SPEC file.') +@click.option('--template', default=DEFAULT_TEMPLATE, + help='Path to template from which SPEC is generated.') +@click.argument('repo', default='.') +@pass_config +def sync_wrapper(config, repo, version, release, old, output, + template): + """Generates SPEC file from Puppetfile and tags repo appropriately. + """ + try: + utils.shout( + 'Generating SPEC file {0} from template {1}'.format( + output, template + ), + verbose=config.verbose, + level='info' + ) + commands.spec.command(config, repo, version, release, old, + output, template) + except utils.ExecutionError as ex: + utils.shout(ex, verbose=True, level='error') + utils.shout( + '====== stdout ======\n{stdout}\n' + '====== stderr ======\n{stderr}'.format(**ex.__dict__), + verbose=config.verbose, + level=None, + ) + except Exception as ex: + utils.shout(ex, verbose=True, level='error') + if config.verbose: + raise + + if __name__ == '__main__': bade() diff --git a/bade/commands/__init__.py b/bade/commands/__init__.py index eeacc70..d37cb97 100644 --- a/bade/commands/__init__.py +++ b/bade/commands/__init__.py @@ -1,2 +1,2 @@ -from . import init, sync +from . import init, sync, spec diff --git a/bade/commands/spec.py b/bade/commands/spec.py new file mode 100644 index 0000000..2ad8e9e --- /dev/null +++ b/bade/commands/spec.py @@ -0,0 +1,108 @@ +# -*- coding: utf-8 -*- + +import codecs +import datetime +import jinja2 +import os + +from .. import utils +from . import init + + +# setup jinja environment +jinja_env = jinja2.Environment( + block_start_string='[@', + block_end_string='@]', + variable_start_string='[[', + variable_end_string=']]', + trim_blocks=True, + loader=jinja2.FileSystemLoader([ + # bades built-in templates + os.path.join( + os.path.dirname(os.path.dirname(__file__)), 'templates' + ), + # user's templates + os.path.join( + os.path.expanduser('~'), '.bade', 'templates' + ) + ]) +) + +def format_datetime(value): + return value.strftime('%a %b %d %Y') +jinja_env.filters['datetime'] = format_datetime + + +def format_global(value): + return value.replace('-', '_') +jinja_env.filters['global'] = format_global + + +def format_rjust(value, value_from, offset): + space = offset - len(value_from) + len(value) + return value.rjust(space) +jinja_env.filters['rjust'] = format_rjust + + +def command(config, repo, version, release, old, output, template): + """Generates SPEC file from template and tags repo accordingly. + """ + puppetfile = utils.PuppetFile(repo) + puppetfile.load() + + # fill required metadata to puppetfile + for module, info in puppetfile.items(): + info['fullname'] = ( + os.path.basename(info['git']).split('.', 1)[0] + ) + for key, value in info.items(): + info[key] = unicode(value) + + # get changelog from old spec + _locals = locals() + rc, stdout, stderr = utils.execute( + 'tail -n +$(' + 'grep -n -e "^%changelog" {old} | cut -d\':\' -f1' + ') {old}'.format(**_locals), + can_fail=False + ) + old_changelog = u'' if rc else stdout[len('%changelog'):] + old_changelog = old_changelog.decode('utf-8') + + # get current date + current_date = datetime.datetime.today() + + # get name and email from git repo + rc, stdout, stderr = utils.execute( + 'cd {repo} && ' + 'git config --get user.name && ' + 'git config --get user.email'.format(**_locals) + ) + user_name, user_email = stdout.strip().split('\n', 1) + user_name = user_name.decode('utf-8') + user_email = user_email.decode('utf-8') + + # generate message for a tag + msg = '{0}-{1}\\n'.format(version, release) + for module, info in puppetfile.items(): + msg += '{0}{1}\\n'.format( + module, format_rjust(info['commit'], module, 10) + ) + + # generate spec file + _locals = locals() + template_obj = jinja_env.get_template(template) + with codecs.open(os.path.abspath(output), 'wb', 'utf-8') as ofile: + ofile.write(template_obj.render(**_locals)) + + # tag repo + rc, stdout, stderr = utils.execute( + 'cd {repo} && ' + 'git tag -a -m $\'{msg}\' {version}-{release}'.format(**_locals) + ) + utils.shout( + 'New tag {version}-{release} has been created in repo. Please run ' + '"git push origin {version}-{release}" to upload tag to upstream'.format(**_locals), + verbose=True, + level='info' + ) diff --git a/bade/templates/openstack-puppet-modules.template b/bade/templates/openstack-puppet-modules.template new file mode 100644 index 0000000..70906f0 --- /dev/null +++ b/bade/templates/openstack-puppet-modules.template @@ -0,0 +1,50 @@ + +[@ for item in puppetfile|dictsort @] +%global [[ item.0|global ]]_commit [[ item.1.commit|rjust(item.0, 16) ]] +[@ endfor @] + +Name: openstack-puppet-modules +Version: [[ version ]] +Release: [[ release ]]%{?dist} +Summary: Set of Puppet modules used to deploy OpenStack +License: ASL 2.0 and GPLv2 and GPLv3 +URL: https://github.com/redhat-openstack/openstack-puppet-modules + +Source: https://github.com/redhat-openstack/openstack-puppet-modules/archive/%{version}-%{release}.tar.gz +BuildArch: noarch +Requires: rubygem-json + +%description +A collection of Puppet modules used to install and configure OpenStack. + + +%prep +%setup 0 + +find %{_builddir}/%{name}-%{version}/ -type f -name ".*" -exec rm {} + +find %{_builddir}/%{name}-%{version}/ -size 0 -exec rm {} + +find %{_builddir}/%{name}-%{version}/ \( -name "*.pl" -o -name "*.sh" \) -exec chmod +x {} + +find %{_builddir}/%{name}-%{version}/ \( -name "*.pp" -o -name "*.py" \) -exec chmod -x {} + +find %{_builddir}/%{name}-%{version}/ \( -name "*.rb" -o -name "*.erb" \) -exec chmod -x {} + -exec sed -i "/^#!/{d;q}" {} + +find %{_builddir}/%{name}-%{version}/ \( -name spec -o -name ext \) | xargs rm -rf + + +%build + + +%install +rm -rf %{buildroot} +install -d -m 0755 %{buildroot}/%{_datadir}/openstack-puppet/modules/ +[@ for item in puppetfile|dictsort @] +cp -r [[ item.1.fullname ]]-%{[[ item.0|global ]]_commit} %{buildroot}/%{_datadir}/openstack-puppet/modules/[[ item.0 ]] +[@ endfor @] + + +%files +%{_datadir}/openstack-puppet/modules/* + + +%changelog +* [[ current_date|datetime ]] [[ user_name ]] <[[ user_email ]]> - [[ version ]]-[[ release ]] +- Updated to release [[ version ]]-[[ release ]] +[[ old_changelog ]] diff --git a/requirements.txt b/requirements.txt index d77b06d..899a968 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ Click +jinja2 diff --git a/setup.py b/setup.py index feedbbc..3c283a6 100644 --- a/setup.py +++ b/setup.py @@ -6,9 +6,12 @@ setup( name='Bade', version='0.1', + author='Martin Magr', + author_email='mmagr@redhat.com', py_modules=['bade'], install_requires=[ 'Click', + 'jinja2', ], entry_points={ 'console_scripts': [