Skip to content

Instantly share code, notes, and snippets.

@SAPikachu
Created September 19, 2012 09:25
Show Gist options
  • Save SAPikachu/3748673 to your computer and use it in GitHub Desktop.
Save SAPikachu/3748673 to your computer and use it in GitHub Desktop.
import os
import re
from glob import glob
import random
import string
from fabric.api import *
from fabric.contrib.console import confirm
from fabric.contrib.project import rsync_project
VIRTUALENV_ROOT = "~/virtualenv"
PROJECT_NAME = "propserv"
REMOTE_PYTHON_EXEC = "python2.7"
SITE_PACKAGES_GLOB = "$VIRTUAL_ENV/lib/python*/site-packages"
PROJECT_DIR = "{}/{}".format(VIRTUALENV_ROOT, PROJECT_NAME)
GIT_REPO = "{}/repo.git".format(PROJECT_DIR)
EXTRA_PACKAGES_DIR = "{}/extra-packages".format(PROJECT_DIR)
PRODUCTION_DIR = "{}/production".format(PROJECT_DIR)
EXCLUDED_PIP_PACKAGES = ["Fabric", "pycrypto", "ssh",]
EXTRA_PACKAGES = [
{
"pth_name": "django",
"subdir": "django",
},
{
"pth_name": "pikapika",
"subdir": "pikapika",
},
{
"pth_name": "django-dbbackup",
"subdir": "dbbackup",
},
]
NEW_INSTANCE_ID = "".join(
[random.choice(string.ascii_lowercase) for x in range(8)]
)
EXTRA_INIT_SCRIPT = """
export PRODUCTION_SETTINGS={}/propserv.settings
export INSTANCE_ID="-{}"
""".format(
VIRTUALENV_ROOT,
NEW_INSTANCE_ID,
)
HOSTS = {
"hostgator": {
"reload_app_script": """
cp fcgi.sh ~/public/propserv/index.fcgi
killall -q -s SIGHUP python$INSTANCE_ID || true
""",
},
}
if not env.hosts:
env.hosts = list(HOSTS.keys())
env.use_ssh_config = True
def _validate_local():
if not os.environ.has_key("VIRTUAL_ENV"):
abort("Virtualenv is not initialized!")
def _activate_env(working_dir=PROJECT_DIR):
return prefix(". {}/bin/activate && cd {}".format(PROJECT_DIR, working_dir))
def destroy_env():
if confirm("Do your really want to destroy the project on server?",
default=False):
with cd(VIRTUALENV_ROOT):
run("rm -rf " + PROJECT_NAME)
def init_env():
run("mkdir -p " + VIRTUALENV_ROOT)
with cd(VIRTUALENV_ROOT):
with settings(hide("warnings"), warn_only=True, ):
if run("test -d " + PROJECT_NAME).succeeded:
abort("Project already exists on the server")
run("test -f virtualenv.py || wget --no-check-certificate https://raw.github.com/pypa/virtualenv/master/virtualenv.py")
run("{} virtualenv.py {}".format(REMOTE_PYTHON_EXEC, PROJECT_NAME))
with _activate_env():
run('cat >> bin/activate <<EOF\n{}\nEOF'.format(EXTRA_INIT_SCRIPT))
run("ln -s {0}/bin/python {0}/bin/python$INSTANCE_ID".format(
PROJECT_DIR))
run("mkdir -p " + EXTRA_PACKAGES_DIR)
with _activate_env():
run('echo {} > `echo {}`/extra_packages.pth'.format(
EXTRA_PACKAGES_DIR,
SITE_PACKAGES_GLOB,
))
init_repo()
def init_repo():
run("mkdir -p {}".format(GIT_REPO))
run("mkdir -p {}".format(PRODUCTION_DIR))
with cd(GIT_REPO):
run("git init --bare")
with cd(PRODUCTION_DIR):
run("git clone {} .".format(GIT_REPO))
def push_repo():
local("git push ssh://{}/{}/ production".format(env.host_string, GIT_REPO))
def push():
push_repo()
with _activate_env(PRODUCTION_DIR):
run("git fetch")
run("git checkout production")
run("git merge origin/production")
run("mkdir -p static")
run("python manage.py collectstatic --link --clear --noinput")
def push_force():
with _activate_env(PRODUCTION_DIR):
run("git reset --hard")
run("git checkout -- .")
push()
def stage():
local("git checkout production")
local("git merge --ff-only master")
local("git checkout master")
def migratedb():
with _activate_env(PRODUCTION_DIR):
run("python manage.py migrate --all")
def initdb():
with _activate_env(PRODUCTION_DIR):
run("python manage.py syncdb --noinput")
migratedb()
def backupdb():
with _activate_env(PRODUCTION_DIR):
run("python manage.py backupdb")
def reload_app():
script = HOSTS.get(env.host_string, {}).get("reload_app_script")
if script:
with _activate_env(PRODUCTION_DIR):
for line in [x.strip() for x in script.splitlines()]:
if not line:
continue
run(line)
def load_fixtures():
with _activate_env(PRODUCTION_DIR):
run("python manage.py loaddata fixtures/*.json")
def update_pip_packages():
requirements = local("pip freeze", capture=True)
requirements = "\n".join(
[x for x in requirements.splitlines()
if not re.match(r"({})\b".format("|".join(EXCLUDED_PIP_PACKAGES)), x)]
)
with _activate_env():
run("cat <<EOF > requirements.txt\n{}\nEOF".format(requirements))
run("pip install -r requirements.txt")
def update_extra_packages():
site_dir = glob(
os.path.expandvars(SITE_PACKAGES_GLOB)
)[0]
for package in EXTRA_PACKAGES:
pth_name = package["pth_name"]
with open(os.path.join(site_dir, pth_name + ".pth"), "r") as f:
package_dir = f.read().strip()
rsync_project(
local_dir=os.path.join(package_dir, package["subdir"]).rstrip("/"),
remote_dir=EXTRA_PACKAGES_DIR,
)
def deploy_full():
_validate_local()
init_env()
update_pip_packages()
update_extra_packages()
push()
initdb()
load_fixtures()
reload_app()
def deploy():
stage()
push()
migratedb()
reload_app()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment