Commits

Mikhail Korobov  committed 7cbb2ab

Support for non-mercurial deployments. Fix #6.

  • Participants
  • Parent commits ff92fad

Comments (0)

Files changed (10)

File docs/CHANGES.rst

 CHANGES
 =======
 
+dev
+---
+
+- mercurial is no longer required
+
 0.3 (2011-02-12)
 ----------------
 

File docs/fabfile.rst

         Make sure this option is set properly. Deployment will fail with
         incorrect value.
 
+.. attribute:: env.conf.VCS
+
+    The name of VCS the project is stored in. Supported values:
+
+    * hg
+    * none
+
+    Default is 'hg'.
+
+    VCS is used for making project clones and for pushing code updates.
+    'none' VCS is able to upload tar.gz file with project sources
+    on server via ssh and then extract it. Please prefer 'hg' over
+    'none' if possible.
+
+    .. note::
+
+        Support for git would be nice but it is not implemented now.
+
+    One can write custom VCS module and set :attr:`env.conf.VCS` to its import
+    path::
+
+        env.conf = dict(
+            # ...
+            VCS = 'my_utils.my_vcs',
+        )
+
+    VCS module should provide 'init', 'up', 'push' and 'configure' functions.
+    Look at :mod:`fab_deploy.vcs.hg` or :mod:`fab_deploy.vcs.none` for examples.
+
 .. attribute:: env.conf.HG_BRANCH
 
     Named hg branch that should be active on server. Default is "default".

File docs/guide.rst

 
 1. Clean Debian Lenny or Debian Squeeze server/VPS with root ssh access;
 2. working ssh key authentication;
-3. django project stored in mercurial VCS.
 
 .. warning::
 
                 PROCESSES = 2,
                 # uncomment this for Debian Squeeze servers
                 # OS = 'squeeze',
+
+                # uncomment this line if the project is not stored in VCS
+                # default value is 'hg'
+                # VCS = 'none',
             )
             update_env()
 
        # ...
 
    ``config.py`` trick is also known as ``local_settings.py``
-   (make sure ``config.py`` is ignored in your ``.hgignore``).
+   (make sure ``config.py`` is ignored in your VCS if one is used).
 
    .. note::
 
            fab update_django_config
 
 
-
 5. Create ``reqs`` folder at project root. This folder should contain
    text files with `pip requirements <http://pip.openplans.org/requirement-format.html>`_.
 

File docs/index.rst

 * requirements are managed using `pip`_;
 * server interactions are automated and repeatable
   (the tool is `fabric`_ here);
-* projects are stored in `mercurial`_ SCM (support for git and rsync
-  would be nice).
 
 Server software:
 

File fab_deploy/deploy.py

 from fab_deploy.apache import apache_setup, apache_install, touch
 from fab_deploy.nginx import nginx_setup, nginx_install
 from fab_deploy.virtualenv import virtualenv_create
+from fab_deploy import vcs
 
 def full_deploy():
     """ Prepares server and deploys the project. """
     """ Deploys project on prepared server. """
     virtualenv_create()
     make_clone()
-    make_hgrc()
 
     pip_update('all', restart=False)
 
         with settings(warn_only=True):
             run('mkdir %s' % env.conf['INSTANCE_NAME'])
             with cd(env.conf['INSTANCE_NAME']):
-                run('hg init')
-    local('hg push ssh://%s/src/%s/' % (env.hosts[0], env.conf['INSTANCE_NAME']))
+                vcs.init()
+    vcs.push()
     with cd('src'):
         with cd(env.conf['INSTANCE_NAME']):
-            run('hg up -C %s' % env.conf['HG_BRANCH'])
+            vcs.up()
     update_django_config(restart=False)
-
-def make_hgrc():
-    """ Updates hgrc file. """
-    upload_config_template('hgrc', env.conf['SRC_DIR'] + '/.hg/hgrc')
+    vcs.configure()
 
 def update_django_config(restart=True):
     """ Updates :file:`config.py` on server (using :file:`config.server.py`) """
         touch()
 
 def up(branch=None):
-    """ Runs ``hg up`` on server and reloads mod_wsgi process. """
+    """ Runs vcs ``up`` or ``checkout`` command on server and reloads
+    mod_wsgi process. """
     delete_pyc()
-    branch = branch or env.conf['HG_BRANCH']
     with cd('src/'+ env.conf['INSTANCE_NAME']):
-        run('hg up -C %s' % branch)
+        vcs.up(branch)
     compress()
     touch()
 
     nginx_setup()
 
 def push(*args):
-    ''' Run it instead of hg push.
+    ''' Run it instead of your VCS push command.
 
     Arguments:
 
             print 'Valid arguments are: %s' % allowed_args
             return
 
-    repo = 'ssh://%s/src/%s/' % (env.hosts[0], env.conf['INSTANCE_NAME'])
-    local('hg push %s' % repo)
+    vcs.push()
     delete_pyc()
     with cd('src/'+env.conf['INSTANCE_NAME']):
-        run('hg up')
+        vcs.up()
 
     if 'pip_update' in args:
         pip_update(restart=False)

File fab_deploy/utils.py

         SERVER_NAME = host,
         SERVER_ADMIN = 'example@example.com',
         OS = 'lenny',
+        VCS = 'hg',
 
         # these options shouldn't be set by user
         HOME_DIR = HOME_DIR,
     defaults.update(env.conf)
     env.conf = defaults
 
+    for vcs in ['hg', 'none']: # expand VCS name to full import path
+        if env.conf.VCS == vcs:
+            env.conf.VCS = 'fab_deploy.vcs.'+vcs
+
     if env.conf.OS not in SUPPORTED_SYSTEMS:
         abort('%s is not supported. Supported operating systems: %s' % (
             env.conf.OS, ', '.join(SUPPORTED_SYSTEMS)

File fab_deploy/vcs/__init__.py

+from fabric.api import env
+def get_vcs():
+    """ Returns a module with current VCS """
+    name = env.conf.VCS
+    return __import__(name, fromlist=name.split('.')[1:])
+
+def push():
+    get_vcs().push()
+
+def up(branch=None):
+    get_vcs().up(branch or default_branch())
+
+def init():
+    get_vcs().init()
+
+def configure():
+    get_vcs().configure()
+
+def default_branch():
+    return env.conf.get(get_vcs().BRANCH_OPTION, None)

File fab_deploy/vcs/hg.py

+from fabric.api import *
+from fab_deploy.utils import upload_config_template
+
+BRANCH_OPTION = 'HG_BRANCH'
+
+def init():
+    run('hg init')
+
+def up(branch):
+    run('hg up -C ' + branch)
+
+def push():
+    local('hg push ssh://%s/src/%s/' % (env.hosts[0], env.conf.INSTANCE_NAME))
+
+def configure():
+    upload_config_template('hgrc', env.conf['SRC_DIR'] + '/.hg/hgrc')

File fab_deploy/vcs/none.py

+import os.path
+from datetime import datetime
+from fabric.api import *
+
+BRANCH_OPTION = None
+
+def _exclude_string():
+    excludes = ['config.py', '*.pyc', '*.pyo']
+    exclude_string = " ".join(['--exclude "%s"' % pattern for pattern in excludes])
+    if os.path.exists('.excludes'):
+        exclude_string =  "-X .excludes " + exclude_string
+    return exclude_string
+
+def push():
+    """
+    Upload the current project to a remote system, tar/gzipping during the move.
+    Files listed at :file:`<project root>/.exclude` file wouldn't be uploaded
+    (glob patterns are supported in .exclude file).
+
+    This function makes use of the ``/tmp/`` directory and the ``tar`` and
+    ``gzip`` programs/libraries; thus it will not work too well on Win32
+    systems unless one is using Cygwin or something similar.
+
+    This should be using ``fabric.contrib.project.upload_project``
+    but upload_project doesn't support excludes.
+    """
+    tar_file = "/tmp/fab.%s.tar" % datetime.utcnow().strftime(
+        '%Y_%m_%d_%H-%M-%S')
+    local("tar %s -czf %s ." % (_exclude_string(), tar_file))
+    tgz_name = env.conf.SRC_DIR + '/' + env.conf.INSTANCE_NAME + ".tar.gz"
+    put(tar_file, tgz_name)
+    local("rm -f " + tar_file)
+    with cd(env.conf.SRC_DIR):
+        run("tar -xzf " + tgz_name)
+        run("rm -f " + tgz_name)
+
+def configure():
+    pass
+
+def init():
+    pass
+
+def up(branch):
+    pass
+
     author='Mikhail Korobov',
     author_email='kmike84@gmail.com',
 
-    packages=['fab_deploy'],
+    packages=['fab_deploy', 'fab_deploy.vcs'],
     package_data={
         'fab_deploy': [
             'config_templates/*.config',