Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

add svn and git support

  • Loading branch information...
commit a21101d125e5c3d812771a666be157bf67cd3e66 1 parent 0645631
@hbussell authored
View
2  MANIFEST.in
@@ -0,0 +1,2 @@
+include examples/*
+include README.rst
View
20 README.rst
@@ -0,0 +1,20 @@
+==========
+django-fab
+==========
+
+Provides common methods to create fabric scripts for django
+
+-------------
+Configuration
+-------------
+
+In your fabfile.py you define a method for each deployment setup.
+Each method sets fabric environment variables unique for that setup.
+
+To make it easier to have a central fabfile.py shared between p
+
+In your fabfile.py you define methods that setup the fabric environment
+
+
+Requries fabric>=0.9
+http://git.fabfile.org/cgit.cgi/fabric/snapshot/fabric-0.9b1.tar.gz
View
0  djangofab/__init__.py
No changes.
View
23 djangofab/decorator.py
@@ -0,0 +1,23 @@
+import os
+import sys
+import ConfigParser
+from fabric.api import *
+from fabric.context_managers import *
+
+def user_settings(file='fab.cfg', group='default'):
+ "Decorator to load user settings from a config file into the env"
+ def wrap(f=None):
+ def wrapped_f(*args):
+ f(*args)
+ config = ConfigParser.ConfigParser()
+ config.readfp(open(file))
+ user_settings = {}
+ os.environ['DJANGO_SETTINGS_MODULE'] = config.get(group,'django.settings')
+ for name,value in config.items(group):
+ user_settings[name] = value
+ for key in env:
+ if env[key] and isinstance(env[key],str):
+ env[key] = env[key] % user_settings
+ return wrapped_f
+ return wrap
+
View
73 djangofab/django.py
@@ -0,0 +1,73 @@
+from __future__ import with_statement
+from fabric.context_managers import cd
+from fabric.api import env, run, get, sudo
+from djangofab.util import local as local
+import os
+
+def get_remote_db():
+ "Download the latest database from the server and load it onto your local database"
+ dbsettings = get_db_settings()
+ with cd(env.path):
+ if dbsettings['engine']=='mysql':
+ run('mysqldump -u%(user)s -p%(pass)s %(name)s > database' % dbsettings )
+ elif dbsettings['engine']=='postgresql' or dbsettings['engine']=='postgresql_psycopg2':
+ run('psql -u%(user)s -p%(pass)s %(name)s > database' % dbsettings)
+
+ get(env.path+'/database', 'database')
+ if dbsettings['engine']=='mysql':
+ local('echo "create database if not exists %(name)s;" | mysql -u%(user)s -p%(pass)s' % dbsettings)
+ local('mysql -u%(user)s -p%(pass)s %(name)s < database' % dbsettings)
+ elif dbsettings['engine']=='postgresql' or dbsettings['engine']=='postgresql_psycopg2':
+ run('echo "create database if not exists %(name)s;" | psql -u%(user)s -p%(pass)s' % dbsettings)
+
+def put_local_db():
+ "Dump your local database and load it onto the servers databse"
+ dbsettings = get_db_settings()
+ if dbsettings['engine']=='mysql':
+ local('mysqldump -u%s -p%s %s > database' %\
+ (settings.DATABASE_USER, settings.DATABASE_PASSWORD, settings.DATABASE_NAME))
+ put('database', 'database')
+ local('mysql -u%s -p%s %s < database' %\
+ (settings.DATABASE_USER, settings.DATABASE_PASSWORD, settings.DATABASE_NAME))
+ elif dbsettings['engine']=='postgresql' or dbsettings['engine']=='postgresql_psycopg2':
+ local('mysqldump -u%s -p%s %s > database' %\
+ (settings.DATABASE_USER, settings.DATABASE_PASSWORD, settings.DATABASE_NAME))
+ put('database', 'database')
+ local('mysql -u%s -p%s %s < database' %\
+ (settings.DATABASE_USER, settings.DATABASE_PASSWORD, settings.DATABASE_NAME))
+
+def get_db_settings():
+ from fabric.operations import _handle_failure
+ try:
+ from fabfile import settings
+ except ImportError:
+ msg = 'Please import django settings in your fabfile.py \nfrom django.conf import settings'
+ _handle_failure(message=msg)
+ if not 'DJANGO_SETTINGS_MODULE' in os.environ:
+ msg = 'DJANGO_SETTINGS_MODULE not set \nYou must call a settings function that sets the os.environ[DJANGO_SETTINGS_MODULE] first'
+ _handle_failure(message=msg)
+ if not hasattr(settings, 'DATABASE_USER'):
+ # global settings is not the django settings
+ msg = 'Please import django settings in your fabfile.py \nfrom django.conf import settings'
+ _handle_failure(message=msg)
+ return {'user': settings.DATABASE_USER, 'pass':settings.DATABASE_PASSWORD, \
+ 'name':settings.DATABASE_NAME,'engine':settings.DATABASE_ENGINE}
+
+
+def change_ownership():
+ "Set user and group ownership on the website path"
+ with cd(env.path):
+ sudo('chown %s.%s -R .' % (env.site_user, env.site_group,))
+ sudo('chmod ug+rw -R .')
+
+def touch_wsgi():
+ "Touch the wsgi file to trigger wsgi to reload the processes."
+ with cd(env.path):
+ run("touch bin/django.wsgi")
+
+def syncdb():
+ "Sync database and run"
+ pass
+
+
+
View
5 djangofab/fab.cfg
@@ -0,0 +1,5 @@
+[default]
+django.settings=website.settings
+giturl=mail:/var/projects/aurealty-platform
+dev_path=/var/www/vhosts/aurealty.com/project/aurealty-platform
+prod_path=/var/www/vhosts/aurealty.com/project/aurealty-platform
View
107 djangofab/fabfile.py
@@ -0,0 +1,107 @@
+from __future__ import with_statement
+from fabric.api import *
+from fabric.context_managers import *
+import os
+import sys
+#import django
+from djangofab.vcs.git import do_checkout, do_push as push, do_pull as pull
+from djangofab.decorator import *
+from djangofab.util import local_out as local
+from django.conf import settings
+#sys.path[len(sys.path):] = ['.']
+#os.environ['DJANGO_SETTINGS_MODULE'] = 'website.settings'
+
+@user_settings()
+def prod():
+ env.hosts = ['mail']
+ env.path = '%(prod_path)s'
+ env.giturl = '%(giturl)s'
+
+@user_settings()
+def dev():
+ env.hosts = ['mail']
+ env.path = '%(dev_path)s' #% {'dev_path': '/dev/path/'}
+ env.giturl = '%(giturl)s'
+
+@user_settings('fab.cfg','local')
+def localhost():
+ env.path = '%(dev_path)s'
+ env.giturl = '%(giturl)s'
+
+def update():
+ "pull changes from the git repository"
+ #local('git pull')
+ pull()
+
+def host_type():
+ "pull changes from the git repository"
+# print sys.path
+# local('echo "testing %s"' % env.giturl)
+ local('echo "database %s"' % settings.DATABASE_NAME)
+
+def test():
+ local('echo "testing path = %s, settings = "' % (env.path,))
+ #local('echo "testing path = %s, settings = %s"' % (env.path, os.environ['DJANGO_SETTINGS_MODULE'],))
+
+def update_all():
+ "update changes from git, update the database and build_media"
+ update()
+ local('bin/django clean_pyc')
+ if os.path.exists('buildout.cfg'):
+ local('bin/buildout')
+ local('bin/django syncdb')
+ if 'south' in settings.INSTALLED_APPS:
+ local('bin/django migrate')
+ local('bin/django build_media --all')
+
+def deploy():
+ "push local changes and update checkout on the remote host"
+ push()
+# local('git push') # might fail if its not a fast forward merge
+ #reset()
+ checkout()
+ touch_wsgi()
+
+def checkout():
+ with cd(env.path):
+ do_checkout()
+
+def touch_wsgi():
+ "Touch the wsgi file to trigger wsgi to reload the processes."
+ with cd(env.path):
+ run("touch bin/django.wsgi")
+
+def get_remote_db():
+ "Download the latest database from the server and load it onto your local database"
+ with cd(env.path):
+ if settings.DATABASE_ENGINE=='mysql':
+ run('mysqldump -u%s -p%s %s > database' %\
+ (settings.DATABASE_USER, settings.DATABASE_PASSWORD, settings.DATABASE_NAME))
+ elif settings.DATABASE_ENGINE=='postgresql' or settings.DATABASE_ENGINE=='postgresql_psycopg2':
+ run('psql -u%s -p%s %s > database' %\
+ (settings.DATABASE_USER, settings.DATABASE_PASSWORD, settings.DATABASE_NAME))
+
+ get(env.path+'/database', 'database')
+ if settings.DATABASE_ENGINE=='mysql':
+ local('echo "create database if not exists %s;" | mysql -u%s -p%s' %\
+ (settings.DATABASE_NAME, settings.DATABASE_USER, settings.DATABASE_PASSWORD))
+ local('mysql -u%s -p%s %s < database' % (settings.DATABSE_USER, settings.DATABSE_PASSWORD, settings.DATABASE_NAME))
+ elif settings.DATABASE_ENGINE=='postgresql' or settings.DATABASE_ENGINE=='postgresql_psycopg2':
+ run('echo "create database %s;" | psql -u%s -p%s' %\
+ (settings.DATABASE_NAME, settings.DATABASE_USER, settings.DATABASE_PASSWORD))
+
+def putlocal_db():
+ "Dump your local database and load it onto the servers databse"
+ if settings.DATABASE_ENGINE=='mysql':
+ local('mysqldump -u%s -p%s %s > database' %\
+ (settings.DATABASE_USER, settings.DATABASE_PASSWORD, settings.DATABASE_NAME))
+ put('database', 'database')
+ local('mysql -u%s -p%s %s < database' %\
+ (settings.DATABASE_USER, settings.DATABASE_PASSWORD, settings.DATABASE_NAME))
+ elif settings.DATABASE_ENGINE=='postgresql' or settings.DATABASE_ENGINE=='postgresql_psycopg2':
+ local('mysqldump -u%s -p%s %s > database' %\
+ (settings.DATABASE_USER, settings.DATABASE_PASSWORD, settings.DATABASE_NAME))
+ put('database', 'database')
+ local('mysql -u%s -p%s %s < database' %\
+ (settings.DATABASE_USER, settings.DATABASE_PASSWORD, settings.DATABASE_NAME))
+
View
70 djangofab/util.py
@@ -0,0 +1,70 @@
+from fabric.api import local as _local
+from fabric.api import env
+
+import os
+import subprocess
+
+from fabric.state import env, connections, output
+#def local_out(cmd):
+# return local(cmd,False)
+
+def local(cmd):
+ if hasattr(env,'capture_default'):
+ _local(cmd, env.capture_default)
+ else:
+ _local(cmd)
+
+
+def safe_local(command, capture=True):
+ """
+ Run a command on the local system.
+
+ `local` is simply a convenience wrapper around the use of the builtin
+ Python ``subprocess`` module with ``shell=True`` activated. If you need to
+ do anything special, consider using the ``subprocess`` module directly.
+
+ `local` will, by default, capture and return the contents of the command's
+ stdout as a string, and will not print anything to the user (the command's
+ stderr is captured but discarded.)
+
+ .. note::
+ This differs from the default behavior of `run` and `sudo` due to the
+ different mechanisms involved: it is difficult to simultaneously
+ capture and print local commands, so we have to choose one or the
+ other. We hope to address this in later releases.
+
+ If you need full interactivity with the command being run (and are willing
+ to accept the loss of captured stdout) you may specify ``capture=False`` so
+ that the subprocess' stdout and stderr pipes are connected to your terminal
+ instead of captured by Fabric.
+
+ When ``capture`` is False, global output controls (``output.stdout`` and
+ ``output.stderr`` will be used to determine what is printed and what is
+ discarded.
+ """
+ if output.running:
+ print("[localhost] run: " + command)
+ # By default, capture both stdout and stderr
+ PIPE = subprocess.PIPE
+ out_stream = PIPE
+ err_stream = PIPE
+ # Tie in to global output controls as best we can; our capture argument
+ # takes precedence over the output settings.
+ if not capture:
+ if output.stdout:
+ out_stream = None
+ if output.stderr:
+ err_stream = None
+ p = subprocess.Popen([command], shell=True, stdout=out_stream,
+ stderr=err_stream)
+ (stdout, stderr) = p.communicate()
+ # Handle error condition (deal with stdout being None, too)
+ out = _AttributeString(stdout or "")
+ out.failed = False
+ if p.returncode != 0:
+ out.failed = True
+ msg = "local() encountered an error (return code %s) while executing '%s'" % (p.returncode, command)
+ out.msg = msg
+ #_handle_failure(message=msg)
+ # If we were capturing, this will be a string; otherwise it will be None.
+ return out
View
0  djangofab/vcs/__init__.py
No changes.
View
26 djangofab/vcs/git.py
@@ -0,0 +1,26 @@
+from __future__ import with_statement
+from fabric.api import run, env
+from fabric.context_managers import cd
+from djangofab.util import local as local, safe_local
+
+def update_remote():
+ "Update remote checkout to the latest version"
+ with cd(env.path):
+ run('git reset --hard')
+ run('git pull')
+
+def push():
+ "Pull changes from version control"
+ local('git push')
+
+def update_local():
+ "Pull changes from version control"
+ local('git pull')
+
+def commit():
+ "Save changes to version control"
+ local('git commit -a')
+
+def add(file):
+ "Add files to the repository"
+ local('git add %s' %file)
View
40 djangofab/vcs/svn.py
@@ -0,0 +1,40 @@
+from __future__ import with_statement
+from fabric.api import run, env
+from fabric.context_managers import cd
+from djangofab.util import local as local
+
+def update_remote():
+ "Update remote checkout to the latest version"
+ with cd(env.path):
+ if not remote_checkout_exists():
+ run('svn co %s %s' % (env.svnurl, env.path))
+ run('svn update')
+
+def remote_export():
+ "Update remote checkout to the latest version"
+ with cd(env.path):
+ run('svn export %s %s' % (env.svnurl, env.svnpath))
+
+def update_local():
+ "Pull changes from version control"
+ local('svn update')
+
+def commit():
+ "Save changes to version control"
+ local('svn commit')
+
+def add(file):
+ "Add files to the repository"
+ local('svn add %s' %file)
+
+def checkout_local():
+ local('svn co %s %s' % (env.svnurl, env.path))
+
+def remote_checkout_exists():
+ #with cd(env.path):
+ out = run('ls -a | grep svn').strip()
+ print out
+ return True
+ if out=='.svn':
+ return True
+ return False
View
6 examples/fab.cfg
@@ -0,0 +1,6 @@
+[default]
+django.settings=website.settings
+giturl=server:/var/git/project
+svnurl=svn+ssh://server/var/svn/project
+dev_path=/var/projects/project/dev/
+prod_path=/var/projects/project/prod
View
43 examples/fabfile-git.py
@@ -0,0 +1,43 @@
+from __future__ import with_statement
+from fabric.api import *
+from fabric.context_managers import *
+from django.conf import settings
+from djangofab.vcs.git import update_remote, update_local, push, commit, add
+from djangofab.decorator import user_settings
+from djangofab.util import local as local
+from djangofab.django import get_remote_db, put_local_db, change_ownership, touch_wsgi
+env.capture_default = False
+
+#use the default section of fab.cfg
+@user_settings()
+def prod():
+ "Production settings"
+ env.hosts = ['mail']
+ env.path = '%(prod_path)s'
+ env.svnurl = '%(svnurl)s'
+ env.site_user = 'owner'
+ env.site_group = 'group'
+
+@user_settings()
+def dev():
+ "Development settings"
+ env.hosts = ['mail']
+ env.path = '%(dev_path)s' #% {'dev_path': '/dev/path/'}
+ env.svnurl = '%(svnurl)s'
+ env.site_user = 'owner'
+ env.site_group = 'group'
+
+#use the local section
+@user_settings('fab.cfg','local')
+def localhost():
+ "Local settings"
+ env.path = '%(dev_path)s'
+ env.svnurl = '%(svnurl)s'
+
+def deploy():
+ "Push local changes and update checkout on the remote host"
+ push()
+ update_remote() # reset and pull on the remote server
+ #remote_export()
+ change_ownership()
+ touch_wsgi()
View
42 examples/fabfile-svn.py
@@ -0,0 +1,42 @@
+from __future__ import with_statement
+from fabric.api import *
+from fabric.context_managers import *
+from django.conf import settings
+from djangofab.vcs.svn import update_remote, update_local, commit, add
+from djangofab.decorator import user_settings
+from djangofab.util import local as local
+from djangofab.django import get_remote_db, put_local_db, change_ownership, touch_wsgi
+env.capture_default = False
+
+#use the default section of fab.cfg
+@user_settings()
+def prod():
+ "Production settings"
+ env.hosts = ['mail']
+ env.path = '%(prod_path)s'
+ env.svnurl = '%(svnurl)s'
+ env.site_user = 'owner'
+ env.site_group = 'group'
+
+@user_settings()
+def dev():
+ "Development settings"
+ env.hosts = ['mail']
+ env.path = '%(dev_path)s' #% {'dev_path': '/dev/path/'}
+ env.svnurl = '%(svnurl)s'
+ env.site_user = 'owner'
+ env.site_group = 'group'
+
+#use the local section
+@user_settings('fab.cfg','local')
+def localhost():
+ "Local settings"
+ env.path = '%(dev_path)s'
+ env.svnurl = '%(svnurl)s'
+
+def deploy():
+ "Push local changes and update checkout on the remote host"
+ update_remote() #this will update a checkout
+ #remote_export()
+ change_ownership()
+ touch_wsgi()
Please sign in to comment.
Something went wrong with that request. Please try again.