From f2d79a0db952280bde4910cbcea00dfc1be40e70 Mon Sep 17 00:00:00 2001 From: Craig Tracey Date: Tue, 3 Nov 2015 21:43:34 -0500 Subject: [PATCH] Add ability to extend builders via builder drivers There are times where you may want to extend or modify the way that giftwrap builds packages. Short of submitting a pull request or (worse) forking the repository, there was no easy way to do so. This change introduces builder drivers with stevedore. By merely adding entry points in the 'giftwrap.builder.drivers', additional implementations are now possible. --- CHANGELOG.md | 3 +++ giftwrap/builders/__init__.py | 16 ++++++++++++++-- giftwrap/shell.py | 4 ++-- giftwrap/tests/test_builder.py | 34 ++++++++++++++++++++++++++++++++++ requirements.txt | 1 + setup.cfg | 6 +++++- 6 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 giftwrap/tests/test_builder.py diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..4be6497 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +2.1.0 +----- +- feature: add builder drivers using stevedore diff --git a/giftwrap/builders/__init__.py b/giftwrap/builders/__init__.py index 77c87c4..8498d72 100644 --- a/giftwrap/builders/__init__.py +++ b/giftwrap/builders/__init__.py @@ -19,9 +19,12 @@ import os import threading from giftwrap.gerrit import GerritReview +from stevedore.driver import DriverManager +from stevedore.extension import ExtensionManager from abc import abstractmethod, ABCMeta +BUILDER_DRIVER_NAMESPACE = 'giftwrap.builder.drivers' LOG = logging.getLogger(__name__) @@ -34,6 +37,12 @@ class Builder(object): self._spec = spec self._thread_exit = [] + @staticmethod + def builder_names(ext_mgr=None): + if not ext_mgr: + ext_mgr = ExtensionManager(BUILDER_DRIVER_NAMESPACE) + return ext_mgr.names() + def _get_venv_pip_path(self, venv_path): return os.path.join(venv_path, 'bin/pip') @@ -182,5 +191,8 @@ class BuilderFactory: @staticmethod def create_builder(builder_type, build_spec): - targetclass = "%sBuilder" % builder_type.capitalize() - return globals()[targetclass](build_spec) + driver_mgr = DriverManager(namespace=BUILDER_DRIVER_NAMESPACE, + name=builder_type, + invoke_args=(build_spec,), + invoke_on_load=True) + return driver_mgr.driver diff --git a/giftwrap/shell.py b/giftwrap/shell.py index 18d7019..512cc7a 100644 --- a/giftwrap/shell.py +++ b/giftwrap/shell.py @@ -19,7 +19,7 @@ import logging import signal import sys -from giftwrap.builders import BuilderFactory +from giftwrap.builders import Builder, BuilderFactory from giftwrap.build_spec import BuildSpec from giftwrap.color import ColorStreamHandler @@ -80,7 +80,7 @@ def main(): description='build giftwrap packages') build_subcmd.add_argument('-m', '--manifest', required=True) build_subcmd.add_argument('-v', '--version') - build_subcmd.add_argument('-t', '--type', choices=('docker', 'package'), + build_subcmd.add_argument('-t', '--type', choices=Builder.builder_names(), required=True) build_subcmd.add_argument('-s', '--synchronous', dest='parallel', action='store_false') diff --git a/giftwrap/tests/test_builder.py b/giftwrap/tests/test_builder.py new file mode 100644 index 0000000..06b5cdb --- /dev/null +++ b/giftwrap/tests/test_builder.py @@ -0,0 +1,34 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2015, Craig Tracey +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import unittest2 as unittest + +from giftwrap.builders import Builder, BUILDER_DRIVER_NAMESPACE +from stevedore import extension + + +class TestBuilder(unittest.TestCase): + + def test_default_drivers(self): + drivers = Builder.builder_names() + self.assertEqual(drivers, ['docker', 'package']) + + def test_additional_drivers(self): + em = extension.ExtensionManager(BUILDER_DRIVER_NAMESPACE) + em.extensions.append(extension.Extension('test', None, None, None)) + drivers = Builder.builder_names(em) + self.assertEqual(drivers, ['docker', 'package', 'test']) diff --git a/requirements.txt b/requirements.txt index d1f50b2..f63009f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,3 +9,4 @@ requests pygerrit docker-py virtualenv +stevedore diff --git a/setup.cfg b/setup.cfg index dc6213d..d38e059 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = giftwrap -version = 2.0.0 +version = 2.1.0 summary = giftwrap - A tool to build full-stack native system packages. description-file = README.md @@ -23,6 +23,10 @@ setup-hooks = console_scripts = giftwrap = giftwrap.shell:main +giftwrap.builder.drivers = + package = giftwrap.builders.package_builder:PackageBuilder + docker = giftwrap.builders.docker_builder:DockerBuilder + [files] packages = giftwrap