Created
September 19, 2012 09:25
-
-
Save SAPikachu/3748673 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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