Merge branch 'master' of stigma:platforma
authorŁukasz Rekucki <lrekucki@gmail.com>
Thu, 15 Oct 2009 16:28:32 +0000 (18:28 +0200)
committerŁukasz Rekucki <lrekucki@gmail.com>
Thu, 15 Oct 2009 16:28:32 +0000 (18:28 +0200)
.gitignore
crop.py [deleted file]
dump_toolbar.sh [deleted file]
fabfile.py
imgconv.py [deleted file]
pip-options.txt [new file with mode: 0644]
requirements.txt
scripts/crop.py [new file with mode: 0755]
scripts/dump_toolbar.sh [new file with mode: 0755]
scripts/imgconv.py [new file with mode: 0755]

index c91e29e..9fa4e40 100644 (file)
@@ -1,10 +1,17 @@
 localsettings.py
 dev.sqlite
+requirements.pybundle
+
+# Python garbage
 *.pyc
-.*.swp
+.coverage
+
+# Mac OS X garbage
 .DS_Store
-media
-files
+
+# Windows garbage
+thumbs.db
+
+# Netbeans garbage
 nbproject
-nbproject/*
-.coverage
+nbproject/*
\ No newline at end of file
diff --git a/crop.py b/crop.py
deleted file mode 100755 (executable)
index a7d8384..0000000
--- a/crop.py
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/usr/bin/env python
-import sys
-import os
-from os.path import splitext, dirname, basename, realpath
-from PIL import Image
-
-
-def crop(image, top=0, right=0, bottom=0, left=0):
-    width, height = image.size
-    if top < 1:
-        top = int(height * top)
-    if right < 1:
-        right = int(width * right)
-    if bottom < 1:
-        bottom = int(height * bottom)
-    if left < 1:
-        left = int(width * left)
-    
-    bounds = (int(left), int(top), int(width - right), int(height - bottom))
-    image = image.crop(bounds)
-    image.load()
-    return image
-
-
-output_dir = realpath(os.getcwd()) + '/output'
-bounds = [float(i) for i in sys.argv[1].split(':')]
-
-for file_name in sys.argv[2:]:
-    base_name, ext = splitext(file_name)
-    try:
-        image = Image.open(file_name)
-    except IOError, e:
-        sys.stderr.write('\nerror:%s:%s\n' % (file_name, e.message))
-        continue
-    
-    image = crop(image, *bounds)
-    image.save(output_dir + '/' + basename(file_name))
\ No newline at end of file
diff --git a/dump_toolbar.sh b/dump_toolbar.sh
deleted file mode 100755 (executable)
index aede174..0000000
+++ /dev/null
@@ -1 +0,0 @@
-./project/manage.py dumpdata --format=xml toolbar | xmllint --format - > apps/toolbar/fixtures/przyciski.xml
index 5f9cd3f..8b55e58 100644 (file)
-from __future__ import with_statement
+from __future__ import with_statement # needed for python 2.5
+from fabric.api import *
 
-from fabric.api import run, env, cd
+import os
 
+
+# ==========
+# = Config =
+# ==========
+# Globals
+env.project_name = 'platforma'
+env.use_south = False
+
+# Servers
 def staging():
-    '''Add staging server to hosts'''
-    env.hosts = ['platforma@stigma.nowoczesnapolska.org.pl:2222']
-    env.project_dir = '/home/platforma/platforma'
+    """Use staging server"""
+    env.hosts = ['stigma.nowoczesnapolska.org.pl:2222']
+    env.user = 'zuber'
+    env.path = '/var/services/platforma'
+    env.python = '/usr/bin/python'
+    env.virtualenv = '/usr/bin/virtualenv'
+    env.pip = '/usr/bin/pip'
+    
+def production():
+    """Use production server"""
+    env.hosts = ['wolnelektury.pl:22123']
+    env.user = 'fundacja'
+    env.path = '/opt/lektury/platforma'
+    env.python = '/opt/lektury/basevirtualenv/bin/python'
+    env.virtualenv = '/opt/lektury/basevirtualenv/bin/virtualenv'
+    env.pip = '/opt/lektury/basevirtualenv/bin/pip'
+
+
+# =========
+# = Tasks =
+# =========
+def test():
+    "Run the test suite and bail out if it fails"
+    require('hosts', 'path', provided_by=[staging, production])
+    result = run('cd %(path)s/%(project_name)s; %(python)s manage.py test' % env)
+
+def setup():
+    """
+    Setup a fresh virtualenv as well as a few useful directories, then run
+    a full deployment. virtualenv and pip should be already installed.
+    """
+    require('hosts', 'path', provided_by=[staging, production])
+
+    run('mkdir -p %(path)s; cd %(path)s; %(virtualenv)s --no-site-packages .;' % env, pty=True)
+    run('cd %(path)s; mkdir releases; mkdir shared; mkdir packages;' % env, pty=True)
+    run('cd %(path)s/releases; ln -s . current; ln -s . previous' % env, pty=True)
+    deploy()
 
 def deploy():
-    '''Deploy server'''
-    with cd(env.project_dir):
-        run('git pull')
-        run('./project/manage.py syncdb')
-    restart_server()
+    """
+    Deploy the latest version of the site to the servers, 
+    install any required third party modules, 
+    install the virtual host and then restart the webserver
+    """
+    require('hosts', 'path', provided_by=[staging, production])
+
+    import time
+    env.release = time.strftime('%Y-%m-%dT%H%M')
+
+    upload_tar_from_git()
+    upload_pybundle()
+    install_requirements()
+    symlink_current_release()
+    migrate()
+    restart_webserver()
+
+def deploy_version(version):
+    "Specify a specific version to be made live"
+    require('hosts', 'path', provided_by=[localhost,webserver])
+    env.version = version
+    with cd(env.path):
+        run('rm releases/previous; mv releases/current releases/previous;', pty=True)
+        run('ln -s %(version)s releases/current' % env, pty=True)
+    restart_webserver()
+
+def rollback():
+    """
+    Limited rollback capability. Simple loads the previously current
+    version of the code. Rolling back again will swap between the two.
+    """
+    require('hosts', provided_by=[staging, production])
+    require('path')
+    with cd(env.path):
+        run('mv releases/current releases/_previous;', pty=True)
+        run('mv releases/previous releases/current;', pty=True)
+        run('mv releases/_previous releases/previous;', pty=True)
+    restart_webserver()
+
+
+# =====================================================================
+# = Helpers. These are called by other functions rather than directly =
+# =====================================================================
+def upload_tar_from_git():
+    "Create an archive from the current Git master branch and upload it"
+    print '>>> upload tar from git'
+    require('release', provided_by=[deploy])
+    local('git archive --format=tar master | gzip > %(release)s.tar.gz' % env)
+    run('mkdir -p %(path)s/releases/%(release)s' % env, pty=True)
+    run('mkdir -p %(path)s/packages' % env, pty=True)
+    put('%(release)s.tar.gz' % env, '%(path)s/packages/' % env)
+    run('cd %(path)s/releases/%(release)s && tar zxf ../../packages/%(release)s.tar.gz' % env, pty=True)
+    local('rm %(release)s.tar.gz' % env)
+
+def install_requirements():
+    "Install the required packages from the requirements file using pip"
+    print '>>> install requirements'
+    require('release', provided_by=[deploy])
+    run('cd %(path)s; %(pip)s install -E . requirements.pybundle' % env)
+
+def upload_pybundle():
+    "Create pybundle with required libraries and upload it"
+    print ">>> upload pybundle"
+    require('release', provided_by=[deploy])
+    with settings(warn_only=True):
+        pip_options = run('cat %(path)s/releases/%(release)s/pip-options.txt' % env)
+        if pip_options.failed:
+            env.pip_options = ''
+        else:
+            env.pip_options = pip_options
+            
+    requirements_mtime = os.path.getmtime('requirements.txt')
+    bundle_mtime = 0
+    try:
+        bundle_mtime = os.path.getmtime('requirements.pybundle')
+    except os.error:
+        pass
+
+    if requirements_mtime > bundle_mtime:
+        local('pip bundle requirements.pybundle %(pip_options)s -r requirements.txt' % env)
+        put('requirements.pybundle', '%(path)s' % env)
+
+def symlink_current_release():
+    "Symlink our current release"
+    print '>>> symlink current release'
+    require('release', provided_by=[deploy])
+    require('path', provided_by=[staging, production])
+    with cd(env.path):
+        run('rm releases/previous; mv releases/current releases/previous')
+        run('ln -s %(release)s releases/current' % env)
 
-def restart_server():
-    with cd(env.project_dir):
-        run('touch project/dispatch.wsgi')
+def migrate():
+    "Update the database"
+    print '>>> migrate'
+    require('project_name', provided_by=[staging, production])
+    with cd('%(path)s/releases/current/%(project_name)s' % env):
+        run('../../../bin/python manage.py syncdb --noinput' % env, pty=True)
+        if env.use_south:
+            run('../../../bin/python manage.py migrate' % env, pty=True)
 
+def restart_webserver():
+    "Restart the web server"
+    print '>>> restart webserver'
+    run('touch %(path)s/releases/current/%(project_name)s/%(project_name)s.wsgi' % env)
diff --git a/imgconv.py b/imgconv.py
deleted file mode 100755 (executable)
index ce514b3..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-#!/usr/bin/env python
-import sys
-import os
-import shutil
-from os.path import splitext, dirname, basename, realpath
-from PIL import Image, ImageFilter, ImageEnhance, ImageOps
-
-
-def resize(image, max_width, max_height):
-    """Resize image so it's not wider than max_width and not higher than max_height."""
-    width, height = image.size
-    ratio = max(1.0, float(width) / max_width, float(height) / max_height)
-    new_width, new_height = int(width / ratio), int(height / ratio)
-    return image.resize((new_width, new_height), Image.ANTIALIAS)
-
-
-def crop(image, ratio, from_right=False):
-    """Crop image to ratio of current width."""
-    width, height = image.size
-    new_width = width * ratio
-    if from_right:
-        bounds = (int(width - new_width), 0, int(width), int(height))
-    else:
-        bounds = (0, 0, int(new_width), int(height))
-    image = image.crop(bounds)
-    image.load()
-    return image
-
-
-def ratio(image):
-    """Return width to height ratio of image."""
-    width, height = image.size
-    return float(width) / height
-    
-
-def try_creating(directory):
-    try:
-        os.mkdir(directory)
-    except:
-        pass
-
-
-output_dir = realpath(os.getcwd()) + '/output'
-# big_output_dir = output_dir + '/big'
-tmp_output_dir = output_dir + '/tmp'
-
-try_creating(output_dir)
-# try_creating(big_output_dir)
-try_creating(tmp_output_dir)
-
-
-for file_name in sys.argv[1:]:
-    base_name, ext = splitext(file_name)
-    try:
-        image = Image.open(file_name)
-    except IOError, e:
-        sys.stderr.write('\nerror:%s:%s\n' % (file_name, e.message))
-        continue
-    
-    # Check ratio
-    if ratio(image) > 1:
-        images = [crop(image, 0.6), crop(image, 0.6, from_right=True)]
-    else:
-        images = [image]
-    
-    for i, image in enumerate(images):
-        image_name = '%s.%d.png' % (basename(base_name), i)
-        
-        # Save files
-        small_image = resize(image, 640, 960)
-        small_image = small_image.convert('L')
-        small_image = ImageOps.autocontrast(small_image, cutoff=85)
-        # small_image = small_image.filter(ImageFilter.SHARPEN)
-        small_image.save(tmp_output_dir + '/' + image_name)
-
-        os.system('pngnq -n 128 -s 1 -e .png -d "%s" -f "%s"' % (
-            output_dir,
-            tmp_output_dir + '/' + image_name,
-        ))
-        os.remove(tmp_output_dir + '/' + image_name)
-        
-        # big_image = resize(image, 960, 1440)
-        # big_image = big_image.convert('L')
-        # big_image = big_image.filter(ImageFilter.SHARPEN)
-        # big_image.save(tmp_output_dir + '/' + image_name, optimize=True)
-        # os.system('pngnq -n 16 -s 1 -e .png -d "%s" -f "%s"' % (
-        #     big_output_dir,
-        #     tmp_output_dir + '/' + image_name,
-        # ))
-        # os.remove(tmp_output_dir + '/' + image_name)
-        
-    sys.stderr.write('.')
-
-shutil.rmtree(tmp_output_dir)
diff --git a/pip-options.txt b/pip-options.txt
new file mode 100644 (file)
index 0000000..a0993ce
--- /dev/null
@@ -0,0 +1 @@
+-f http://redmine.nowoczesnapolska.org.pl/projects/librarian/files
\ No newline at end of file
index bff92e5..972644b 100644 (file)
@@ -1,6 +1,6 @@
-Django==1.1
-django-piston==0.2.3rc1
-librarian==1.2.2
+Django==1.1.1
+-e hg+ssh://hg@bitbucket.org/jespern/django-piston/#egg=django-piston
+librarian==1.2.6
 lxml==2.2.2
 mercurial==1.3.1
 -e git://github.com/zuber/django-cas-consumer.git#egg=django-cas-consumer
\ No newline at end of file
diff --git a/scripts/crop.py b/scripts/crop.py
new file mode 100755 (executable)
index 0000000..a7d8384
--- /dev/null
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+import sys
+import os
+from os.path import splitext, dirname, basename, realpath
+from PIL import Image
+
+
+def crop(image, top=0, right=0, bottom=0, left=0):
+    width, height = image.size
+    if top < 1:
+        top = int(height * top)
+    if right < 1:
+        right = int(width * right)
+    if bottom < 1:
+        bottom = int(height * bottom)
+    if left < 1:
+        left = int(width * left)
+    
+    bounds = (int(left), int(top), int(width - right), int(height - bottom))
+    image = image.crop(bounds)
+    image.load()
+    return image
+
+
+output_dir = realpath(os.getcwd()) + '/output'
+bounds = [float(i) for i in sys.argv[1].split(':')]
+
+for file_name in sys.argv[2:]:
+    base_name, ext = splitext(file_name)
+    try:
+        image = Image.open(file_name)
+    except IOError, e:
+        sys.stderr.write('\nerror:%s:%s\n' % (file_name, e.message))
+        continue
+    
+    image = crop(image, *bounds)
+    image.save(output_dir + '/' + basename(file_name))
\ No newline at end of file
diff --git a/scripts/dump_toolbar.sh b/scripts/dump_toolbar.sh
new file mode 100755 (executable)
index 0000000..aede174
--- /dev/null
@@ -0,0 +1 @@
+./project/manage.py dumpdata --format=xml toolbar | xmllint --format - > apps/toolbar/fixtures/przyciski.xml
diff --git a/scripts/imgconv.py b/scripts/imgconv.py
new file mode 100755 (executable)
index 0000000..ce514b3
--- /dev/null
@@ -0,0 +1,94 @@
+#!/usr/bin/env python
+import sys
+import os
+import shutil
+from os.path import splitext, dirname, basename, realpath
+from PIL import Image, ImageFilter, ImageEnhance, ImageOps
+
+
+def resize(image, max_width, max_height):
+    """Resize image so it's not wider than max_width and not higher than max_height."""
+    width, height = image.size
+    ratio = max(1.0, float(width) / max_width, float(height) / max_height)
+    new_width, new_height = int(width / ratio), int(height / ratio)
+    return image.resize((new_width, new_height), Image.ANTIALIAS)
+
+
+def crop(image, ratio, from_right=False):
+    """Crop image to ratio of current width."""
+    width, height = image.size
+    new_width = width * ratio
+    if from_right:
+        bounds = (int(width - new_width), 0, int(width), int(height))
+    else:
+        bounds = (0, 0, int(new_width), int(height))
+    image = image.crop(bounds)
+    image.load()
+    return image
+
+
+def ratio(image):
+    """Return width to height ratio of image."""
+    width, height = image.size
+    return float(width) / height
+    
+
+def try_creating(directory):
+    try:
+        os.mkdir(directory)
+    except:
+        pass
+
+
+output_dir = realpath(os.getcwd()) + '/output'
+# big_output_dir = output_dir + '/big'
+tmp_output_dir = output_dir + '/tmp'
+
+try_creating(output_dir)
+# try_creating(big_output_dir)
+try_creating(tmp_output_dir)
+
+
+for file_name in sys.argv[1:]:
+    base_name, ext = splitext(file_name)
+    try:
+        image = Image.open(file_name)
+    except IOError, e:
+        sys.stderr.write('\nerror:%s:%s\n' % (file_name, e.message))
+        continue
+    
+    # Check ratio
+    if ratio(image) > 1:
+        images = [crop(image, 0.6), crop(image, 0.6, from_right=True)]
+    else:
+        images = [image]
+    
+    for i, image in enumerate(images):
+        image_name = '%s.%d.png' % (basename(base_name), i)
+        
+        # Save files
+        small_image = resize(image, 640, 960)
+        small_image = small_image.convert('L')
+        small_image = ImageOps.autocontrast(small_image, cutoff=85)
+        # small_image = small_image.filter(ImageFilter.SHARPEN)
+        small_image.save(tmp_output_dir + '/' + image_name)
+
+        os.system('pngnq -n 128 -s 1 -e .png -d "%s" -f "%s"' % (
+            output_dir,
+            tmp_output_dir + '/' + image_name,
+        ))
+        os.remove(tmp_output_dir + '/' + image_name)
+        
+        # big_image = resize(image, 960, 1440)
+        # big_image = big_image.convert('L')
+        # big_image = big_image.filter(ImageFilter.SHARPEN)
+        # big_image.save(tmp_output_dir + '/' + image_name, optimize=True)
+        # os.system('pngnq -n 16 -s 1 -e .png -d "%s" -f "%s"' % (
+        #     big_output_dir,
+        #     tmp_output_dir + '/' + image_name,
+        # ))
+        # os.remove(tmp_output_dir + '/' + image_name)
+        
+    sys.stderr.write('.')
+
+shutil.rmtree(tmp_output_dir)