From 52b3c33f5a3d7833986a57133c657ec9110cfb82 Mon Sep 17 00:00:00 2001 From: Tyler Smith Date: Tue, 22 Feb 2011 20:42:24 -0500 Subject: [PATCH] blueprint quantum-packaging Change-Id: Ica19170540b06ecddb0fbb6d340ee7a6819c1708 --- setup.py | 176 +++++++++++++++++++++----- tools/__init__.py | 0 tools/build_debs.sh | 27 ++++ tools/build_rpms.sh | 2 + tools/clean.sh | 5 + tools/install_venv.py | 33 +++-- tools/source_environment.py | 28 ++++ tools/source_nonplugin_environment.py | 26 ++++ tools/with_venv.sh | 2 +- 9 files changed, 251 insertions(+), 48 deletions(-) create mode 100644 tools/__init__.py create mode 100755 tools/build_debs.sh create mode 100755 tools/build_rpms.sh create mode 100755 tools/clean.sh create mode 100644 tools/source_environment.py create mode 100644 tools/source_nonplugin_environment.py diff --git a/setup.py b/setup.py index 8ddc6fccf..cdb14e4ab 100644 --- a/setup.py +++ b/setup.py @@ -1,35 +1,153 @@ -import os +from copy import deepcopy +from optparse import OptionParser +from os import path +import re import sys -from setuptools import setup, find_packages + +from tools import install_venv + +ROOT = path.abspath(path.dirname(__file__)) +CONFIG_PATH = path.abspath('/etc/quantum') +BASE_PACKAGES = ['common', 'server', 'client'] +PLUGINS = ['plugins/sample-plugin', 'plugins/cisco-plugin', + 'plugins/openvswitch-plugin'] + +RELATIVE = False -def read(fname): - return open(os.path.join(os.path.dirname(__file__), fname)).read() +def clean_path(dirty): + """Makes sure path delimiters are OS compliant""" + return path.join(*dirty.split('/')) -requirements = ['httplib2', 'eventlet', 'routes', 'webob'] -setup( - name='Quantum', - version='0.1', - description='Layer 2 network as a service for Openstack', - long_description=read('README'), - url='http://launchpad.net/quantum', - license='Apache', - author='Netstack', - author_email='netstack@launchpad.net', - packages=find_packages(exclude=['tests']), - classifiers=[ - 'Development Status :: 4 - Beta', - 'Environment :: Console', - 'Intended Audience :: Developers', - 'Intended Audience :: Information Technology', - 'License :: OSI Approved :: BSD License', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - ], - namespace_packages=["quantum"], - install_requires=requirements, +def script_dir(): + script_dir = '/usr/sbin/' + if RELATIVE: + script_dir = 'usr/sbin/' + return script_dir - tests_require=["nose"], - test_suite="nose.collector", -) + +def create_parser(): + """Setup the option parser""" + usagestr = "Usage: %prog [OPTIONS] [args]" + parser = OptionParser(usage=usagestr) + parser.add_option("-V", "--virtualenv", "--venv", dest="venv", + action="store_true", default=False, help="Install to a virtual-env") + parser.add_option("-U", "--user", dest="user", action="store_true", + default=False, help="Install to users's home") + options, args = parser.parse_args() + + if args.__len__() is 0: + print usagestr + print "Commands:\ninstall\nuninstall\nbuild\nclean" + exit(0) + + cmd = args[0] + args = args[1:] + return (options, cmd, args) + + +def install_packages(options, args=None): + """Builds and installs packages""" + # Start building a command list + cmd = ['pip', 'install'] + + # If no options, just a regular install. If venv, create, prepare and + # install in venv. If --user install in user's local dir. Usually + # ~/.local/ + if options.venv: + if install_venv.VENV_EXISTS: + print "Virtual-env exists" + else: + install_venv.create_virtualenv(install_pip=False) + install_venv.install_dependencies() + cmd.extend(['-E', install_venv.VENV]) + elif options.user: + cmd.append('--user') + + # Install packages + # TODO(Tyler) allow users to pass in packages in cli + for package in BASE_PACKAGES + PLUGINS: + print "Installing %s" % package + # Each package needs its own command list, and it needs the path + # in the correct place (after "pip install") + pcmd = deepcopy(cmd) + pcmd.insert(2, path.join(ROOT, clean_path(package))) + + if package is 'server': + pcmd.append("--install-option=--install-scripts=%s" %\ + script_dir()) + print pcmd + install_venv.run_command(pcmd) + print "done." + + +def uninstall_packages(options, args=None): + """Removes packages""" + cmd = ['pip', 'uninstall', '-y'] + + for package in ['quantum-' + x.split('/')[-1] \ + for x in BASE_PACKAGES + PLUGINS]: + print "Uninstalling %s" % package + # Each package needs its own command list, and it needs the path + # in the correct place (after "pip uninstall" + pcmd = deepcopy(cmd) + pcmd.insert(2, package) + print pcmd + install_venv.run_command(pcmd) + print "done." + + +def build_packages(options, args=None): + """Build RPM and/or deb packages""" + if not args: + print "To build packages you must specifiy either 'rpm', " \ + "'deb', or 'all'" + exit(0) + if args[0] not in ['rpm', 'deb', 'all']: + raise Exception("Packge type must be rpm, deb, or all") + + if 'rpm' in args or 'all' in args: + # Since we need to cd to build rpms, we call this sh script + cmd = ['tools/build_rpms.sh'] + for package in BASE_PACKAGES + PLUGINS: + print "Building %s rpm" % package + pcmd = deepcopy(cmd) + pcmd.append(package) + install_venv.run_command(pcmd) + print "done." + + if 'deb' in args or 'all' in args: + cmd = ['tools/build_debs.sh'] + for p in BASE_PACKAGES + PLUGINS: + print "Building %s deb" % p + pcmd = deepcopy(cmd) + pcmd.append(p) + install_venv.run_command(pcmd) + print "done." + + +def clean_packages(options, args): + """Cleans build packages""" + cmd = ["tools/clean.sh"] + install_venv.run_command(cmd) + + +def main(): + """Main Build script for Quantum""" + options, cmd, args = create_parser() + + if options.user: + RELATIVE = True + + print "Checking for virtual-env and easy_install" + install_venv.check_dependencies() + + # Execute command + try: + globals()["%s_packages" % cmd](options, args) + except KeyError as exc: + print "Command %s' not found" % exc.__str__().split('_')[0] + +if __name__ == "__main__": + main() diff --git a/tools/__init__.py b/tools/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tools/build_debs.sh b/tools/build_debs.sh new file mode 100755 index 000000000..557876349 --- /dev/null +++ b/tools/build_debs.sh @@ -0,0 +1,27 @@ +#!/bin/bash +ALIEN=`which alien` +if [ $? -ne 0 ]; then + echo "You must have alien installed to build debian packages" + exit 1 +fi +FAKEROOT="" +if [ `id -u` != 0 ]; then + FAKEROOT=`which fakeroot` + if [ $? -ne 0 ]; then + echo "You must be root or have fakeroot installed to build debian packages" + exit 1 + fi +fi + +ls $@/dist/*.rpm >/dev/null 2>&1 +if [ $? -ne 0 ]; then + echo "You must build rpms before building debian packages" + exit 1 +fi + +cd $@ +if [ $? -ne 0 ]; then + echo "Directory $@ doesn't exist -- what do you want me to build?" + exit 1 +fi +$FAKEROOT $ALIEN -c -v -d dist/*.noarch.rpm diff --git a/tools/build_rpms.sh b/tools/build_rpms.sh new file mode 100755 index 000000000..7ae6ef7a2 --- /dev/null +++ b/tools/build_rpms.sh @@ -0,0 +1,2 @@ +#!/bin/bash +cd $@ && python setup.py bdist_rpm diff --git a/tools/clean.sh b/tools/clean.sh new file mode 100755 index 000000000..c1deb844c --- /dev/null +++ b/tools/clean.sh @@ -0,0 +1,5 @@ +#!/bin/bash +rm -rf ./*.deb ./*.tar.gz ./*.dsc ./*.changes +rm -rf */*.deb +rm -rf ./plugins/**/build/ ./plugins/**/dist +rm -rf ./plugins/**/lib/quantum_*_plugin.egg-info ./plugins/quantum-* diff --git a/tools/install_venv.py b/tools/install_venv.py index 5c3ef374b..f6fb708f0 100644 --- a/tools/install_venv.py +++ b/tools/install_venv.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python # vim: tabstop=4 shiftwidth=4 softtabstop=4 # Copyright 2010 United States Government as represented by the @@ -28,7 +29,8 @@ import sys ROOT = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) -VENV = os.path.join(ROOT, '.quantum-venv') +VENV = os.path.expanduser('~/.quantum-venv') +VENV_EXISTS = bool(os.path.exists(VENV)) PIP_REQUIRES = os.path.join(ROOT, 'tools', 'pip-requires') @@ -46,11 +48,10 @@ def run_command(cmd, redirect_output=True, check_exit_code=True): stdout = subprocess.PIPE else: stdout = None - proc = subprocess.Popen(cmd, cwd=ROOT, stdout=stdout) output = proc.communicate()[0] if check_exit_code and proc.returncode != 0: - die('Command "%s" failed.\n%s', ' '.join(cmd), output) + raise Exception('Command "%s" failed.\n%s' % (' '.join(cmd), output)) return output @@ -64,27 +65,24 @@ def check_dependencies(): """Make sure virtualenv is in the path.""" if not HAS_VIRTUALENV: - print 'not found.' - # Try installing it via easy_install... - if HAS_EASY_INSTALL: - print 'Installing virtualenv via easy_install...', - if not run_command(['which', 'easy_install']): - die('ERROR: virtualenv not found.\n\n' - 'Quantum requires virtualenv, please install' - ' it using your favorite package management tool') - print 'done.' + raise Exception('Virtualenv not found. ' + \ + 'Try installing python-virtualenv') print 'done.' -def create_virtualenv(venv=VENV): +def create_virtualenv(venv=VENV, install_pip=False): """Creates the virtual environment and installs PIP only into the virtual environment """ print 'Creating venv...', - run_command(['virtualenv', '-q', '--no-site-packages', VENV]) + + install = ['virtualenv', '-q', venv] + run_command(install) + print 'done.' print 'Installing pip in virtualenv...', - if not run_command(['tools/with_venv.sh', 'easy_install', 'pip']).strip(): + if install_pip and \ + not run_command(['tools/with_venv.sh', 'easy_install', 'pip']): die("Failed to install pip.") print 'done.' @@ -94,9 +92,8 @@ def install_dependencies(venv=VENV): # Install greenlet by hand - just listing it in the requires file does not # get it in stalled in the right order - venv_tool = 'tools/with_venv.sh' - run_command([venv_tool, 'pip', 'install', '-E', venv, '-r', PIP_REQUIRES], - redirect_output=False) + run_command(['tools/with_venv.sh', 'pip', 'install', '-E', venv, + '-r', PIP_REQUIRES], redirect_output=False) # Tell the virtual env how to "import quantum" pthfile = os.path.join(venv, "lib", "python2.6", "site-packages", diff --git a/tools/source_environment.py b/tools/source_environment.py new file mode 100644 index 000000000..960225cb8 --- /dev/null +++ b/tools/source_environment.py @@ -0,0 +1,28 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 Cisco Systems +# 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. +# @author: Tyler Smith, Cisco Systems +import os +import sys + +# To run from the source code, we need to add the various packages +# to our path so we can find all of the modules correctly +packages = ['common', 'server', 'client'] +plugins = ["plugins/%s" % p for p in + os.listdir(os.path.join(os.getcwd(), 'plugins'))] + +for project in packages + plugins: + sys.path.insert(0, os.path.join(os.getcwd(), project, 'lib')) diff --git a/tools/source_nonplugin_environment.py b/tools/source_nonplugin_environment.py new file mode 100644 index 000000000..0891c2f70 --- /dev/null +++ b/tools/source_nonplugin_environment.py @@ -0,0 +1,26 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 Cisco Systems +# 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. +# @author: Tyler Smith, Cisco Systems +import os +import sys + +# To run from the source code, we need to add the various packages +# to our path so we can find all of the modules correctly +packages = ['common', 'server', 'client'] + +for project in packages + ["plugins/sample-plugin"]: + sys.path.insert(0, os.path.join(os.getcwd(), project, 'lib')) diff --git a/tools/with_venv.sh b/tools/with_venv.sh index 83149462c..88444a240 100755 --- a/tools/with_venv.sh +++ b/tools/with_venv.sh @@ -17,5 +17,5 @@ # under the License. TOOLS=`dirname $0` -VENV=$TOOLS/../.quantum-venv +VENV=~/.quantum-venv source $VENV/bin/activate && $@