From 3f56ff5bfb09f3cf071d023bab97f606d385a637 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Zapke-Gru=CC=88ndemann?= Date: Tue, 24 Jan 2012 03:26:51 +0100 Subject: add fabfile for easy deployment --- fabfile/__init__.py | 32 ++++++++++++++++++ fabfile/helpers.py | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++ fabfile/setups.py | 39 +++++++++++++++++++++ 3 files changed, 168 insertions(+) create mode 100644 fabfile/__init__.py create mode 100644 fabfile/helpers.py create mode 100644 fabfile/setups.py diff --git a/fabfile/__init__.py b/fabfile/__init__.py new file mode 100644 index 0000000..332068c --- /dev/null +++ b/fabfile/__init__.py @@ -0,0 +1,32 @@ +"""subweb deployment package. + +Always prefix a task with the appropriate setup. + +Examples: + + $ fab setups.stage deploy + $ fab setups.production version + $ fab setups.prod load_fixture:fixtures/flatpages.json +""" +from fabric.api import * + +from fabfile import helpers +from fabfile import setups + + +@task +def deploy(): + """Deploys the project. + + Updates the sources, links the appropriate settings, collects the static + files and synchronizes/migrates the database. + + Installing/updating Python packages or loading fixtures needs to be done + manually. + """ + helpers.update_project() + helpers.link_settings() + helpers.collect_static() + helpers.syncdb() + helpers.migrate() + # TODO restart application server diff --git a/fabfile/helpers.py b/fabfile/helpers.py new file mode 100644 index 0000000..c31461b --- /dev/null +++ b/fabfile/helpers.py @@ -0,0 +1,97 @@ +"""Deployment helpers. +""" +from os.path import join as join_path + +from fabric.api import * +from fabric.contrib import files + + +def ve_run(cmd): + """Runs a command inside the activated virtualenv. + """ + require('root', provided_by=['setups.stage', 'setups.production']) + with prefix('source %(root)s/bin/activate' % env): + run(cmd) + + +def manage(cmd): + """Runs a command with manage.py. + """ + require('manage_py', provided_by=['setups.stage', 'setups.production']) + ve_run('%s %s' % (env.manage_py, cmd)) + + +def update_project(): + """Updates the project source. + """ + require('src_root', provided_by=['setups.stage', 'setups.production']) + require('git_branch', provided_by=['setups.stage', 'setups.production']) + with cd(env.src_root): + run('git pull origin %(git_branch)s' % env) + + +def link_settings(): + """Links the appropriate settings. + """ + require('stage', provided_by=['setups.stage', 'setups.production']) + require('config', provided_by=['setups.stage', 'setups.production']) + require('proj_root', provided_by=['setups.stage', 'setups.production']) + if env.stage: + host_settings = join_path(env.config, '%(host)s_stage.py' % env) + else: + host_settings = join_path(env.config, '%(host)s.py' % env) + settings = join_path(env.proj_root, 'local_settings.py') + if files.exists(settings): + run('rm %s' % settings) + if files.exists(host_settings): + run('ln -s %s %s' % (host_settings, settings)) + else: + print 'No host specific settings file found. Create one at %s' % host_settings + + +def collect_static(): + """Collects all static files. + """ + manage('collectstatic') + + +@task +def syncdb(): + """Runs the syncdb management command. + """ + manage('syncdb') + + +@task +def migrate(app_name=None): + """Runs the migrations for one or all apps. + """ + manage('migrate %s' % app_name) + + +@task(alias='id') +def indetify(): + """Identifes the deployed project. + + Displays the deployed project version, all Python packages installed inside + the virtualenv and the state of the migrations. + """ + require('proj_root', provided_by=['setups.stage', 'setups.production']) + with cd(env.proj_root): + run('git log -1') + ve_run('pip freeze') + manage('migrate -list') + + +@task(alias='install') +def install_requirements(): + """Installs the requirements. + """ + require('pip_file', provided_by=['setups.stage', 'setups.production']) + ve_run('pip install -r %(pip_file)s' % env) + + +@task(alias='load') +def load_fixture(fixture_path): + """Loads one or more fixtures.""" + manage('loaddata %s' % fixture_path) diff --git a/fabfile/setups.py b/fabfile/setups.py new file mode 100644 index 0000000..f4d1de8 --- /dev/null +++ b/fabfile/setups.py @@ -0,0 +1,39 @@ +"""Setups to deploy to. +""" +from os.path import join as join_path + +from fabric.api import * + + +@task +def stage(): + """Defines stage setup. + """ + env.stage = True + env.git_branch = 'master' + env.hosts = ['oberon.sublab.org'] + env.home = '/home/subweb' + env.root = join_path(env.home, 'stage') + finalize() + + +@task(alias='prod') +def production(): + """Defines production setup. + """ + env.stage = False + env.git_branch = 'master' + env.hosts = ['oberon.sublab.org'] + env.home = '/home/subweb' + env.root = join_path(env.home, 'production') + finalize() + + +def finalize(): + """Performs the final setup. + """ + env.config = join_path(env.home, 'config') + env.src_root = join_path(env.root, 'subweb') + env.pip_file = join_path(env.src_root, 'requirements.txt') + env.proj_root = join_path(env.src_root, 'sublab_project') + env.manage_py = join_path(env.proj_root, 'manage.py') -- cgit v1.2.1