Esempio n. 1
0
def _install_etc():
    """Install files from the current build's etc/ into /etc/

    Also remove stale links made by old builds. Used by deploy and rollback tasks."""
    current = paths.site_dir('current')
    etclinks = paths.site_dir('.etclinks-created')

    # Install the newly deployed etc/ files. Record the links created so we can check
    # them later.
    with cd(current):
        # Workaround: fabric 1.4.3 will execute this block even if the cd fails!
        run("[ `pwd` == '%s' ] && pwd" % current)

        sudo("""find etc -type d -print0 | xargs -0 -I '{}' mkdir -p '/{}'
        find etc -type f -print0 | xargs -0 -I '{}' ln -sf '%s/{}' '/{}'
        """ % current)
        with hide('stdout'):
            run('find etc -type f >> %s' % etclinks)

    # Check that all the links we have created still resolve (inluding links
    # from previous builds)
    if remotefile.exists(etclinks):
        # readlink -e returns true even if the thing is not a link!
        sudo("""for item in `sort %s | uniq`; do
        readlink -e /$item || rm -f /$item
        done
        """ % etclinks)
Esempio n. 2
0
def rollback():
    """Undo deployment, roll back to the previous deploy."""
    site_dir = paths.site_dir()
    if not remotefile.exists(site_dir + '/previous'):
        abort("No previous deployment to roll back to!")
    with cd(site_dir):
        run("""
            ln -sfn `readlink current` rolledback
            ln -sfn `readlink previous` current
        """)
    _install_etc()
    enable_site()
Esempio n. 3
0
def list():
    """List deployments available at the server"""
    site_dir = paths.site_dir()
    with cd(site_dir):
        with hide('running', 'stdout'):
            current = run('[ -e current ] && readlink current || echo None')
            previous = run('[ -e previous ] && readlink previous || echo None')
            staged = run('[ -e staged ] && readlink staged || echo None')
            available = run('ls -d [0123456789]* | sort')

        print colors.green("Current: %s" % current)
        print colors.yellow("Staged: %s" % staged)
        print colors.red("Previous: %s" % previous)
        print "Available:\n%s" % available
Esempio n. 4
0
def deploy():
    """Make your staged site content "live"."""
    site_dir = paths.site_dir()
    if not remotefile.exists(site_dir + '/staged'):
        abort("No staged build to deploy! Use the stage task first.")

    # Update the "previous" and "current" links
    with cd(site_dir):
        run("""
        if [ -L current ] && [ `readlink current` != `readlink staged` ] ; then
            ln -sfn `readlink current` previous
        fi
        ln -sfn `readlink staged` current
        """)
    _install_etc()
    enable_site()
Esempio n. 5
0
def cleanup():
    """Remove old unused deployments from server.

    Any build that has a symbolic link in this directory pointing to it will be preserved.
    Also trims the database of /etc/ links created down to ones that currently exist."""
    site_dir = paths.site_dir()
    etclinks = '%s/.etclinks-created' % site_dir

    with cd(site_dir):
        run("""find . -maxdepth 1 -type l -print0 | xargs -0 -n 1 readlink > ../keeplist
        for dir in `ls | grep -f ../keeplist -v`; do
            [ ! -L $dir ] && rm -rf $dir
        done
        rm ../keeplist
        for file in `sort %s | uniq`; do
            [ -e /$file ] && echo $file >> %s
        done
        echo "Cleaned old deployments."
        """ % (etclinks, etclinks))
Esempio n. 6
0
def stage(target=None):
    """Upload site content to web server.

    When you run the stage task, Otto pushes your code to the server and then
    runs the `clean` and `build` tasks at the server to produce your web site
    files. The clean task is run to ensure files removed from the repository
    are also removed from the build. You are responsible for ensuring `clean`
    does the right thing!

    Otto then uses rsync to copy the content to a staging directory from which
    it can be deployed. If necessary, Otto will setup Otto on your server, and
    add the otto remote to your local repo.

    If no tag name is supplied as an argument, Otto will attempt to tag the
    HEAD of the current branch, or if you are operating with a detached HEAD
    (ouch!), the branch named in `env['otto.git.staging_branch']`. However,
    Otto will refuse to do so if you have modifications in your local
    workspace, as this could result in the remote build being different from
    the local build.
    """
    # Perform the server setup just in time 
    if not remotefile.exists(paths.repos()):
        setup()

    deploy_ts = make_timestamp()

    if target == None:
        target = local("git branch | grep '^\*' | awk '{print $2}'", capture=True)
        if not target:
            target = env['otto.git.staging_branch']
        mods = git.local_modifications()
        if mods != None:
            print colors.red('Local modifications! You may get unexpected results from your build.')
            abort(" Specify a tag to stage or check in your workspace.")

    tagname = "otto-" + deploy_ts
    local('git tag -f %s %s' % (tagname, target))
    git.push()

    # Check out the tag into the workspace
    basename = env['otto.site']
    remote_repo = paths.repos(basename)
    workspace = paths.workspace(basename)
    git.clone_or_update(workspace, remote_repo)

    with cd(workspace):
        run('git reset --hard ' + tagname)

        # Ensure the virtualenv has been built
        checksum = run("md5sum requirements.txt | awk '{print $1}'")
        virtualenv_path = paths.virtualenvs(checksum)
        venv_activate = paths.virtualenvs(checksum, 'bin', 'activate')
        if not remotefile.exists(venv_activate):
            run('virtualenv --system-site-packages ' + virtualenv_path)
            run('pip install -r requirements.txt -E ' + virtualenv_path)

        # Activate the virtualenv and run the build task
        build_dir = paths.workspace(env['otto.site'], env['otto.build_dir'])
        if not build_dir.endswith('/'):
            build_dir += '/'
        stage_dir = paths.site_dir(deploy_ts)
        with prefix('source ' + venv_activate):
            has_clean = run("fab --shortlist | grep '^clean$'")
            if has_clean.succeeded:
                run('fab clean')
            run('fab build')
        run('mkdir -p ' + stage_dir)
        run('rsync -a %s %s' % (build_dir, stage_dir))
        with cd(paths.site_dir()):
            run('ln -sfn %s staged' % deploy_ts)