Commits

lakin.wecker  committed 0e9dd9a

Integrating Darren Pearce's changes to allow baste to manage development environments that are not local. This commit improves the patch to allow you to set a single settings in your ~/.fabricrc file to indicate where you want baste to manage it locally or on a VM.

  • Participants
  • Parent commits 3fe7964

Comments (0)

Files changed (1)

File baste/__init__.py

 
 from fabric.api import (
         env,
+        execute,
         hide,
         lcd,
-        local,
-        run,
+        local as local_run,
+        run as remote_run,
         settings,
-        sudo,
+        sudo as remote_sudo,
     )
 from fabric import colors
 from fabric.contrib.project import rsync_project
     'Subversion',
 ]
 
-LOCAL_SCOPE_ENV = True
 #-------------------------------------------------------------------------------
-def run_scoped(cmd, *args , **kwargs):
+class ExecuteOnHosts(object):
     """
-    Runs the specified command on the local machine unless LOCAL_SCOPE_ENV 
-    is False then it will run against the current fab ENV
+    Represents a command to be run on a set of hosts.
+
+    Using this allows us to temporarily override the fabric env.hosts for a
+    specific command.
     """
-    if LOCAL_SCOPE_ENV:
-        local(cmd,*args, **kwargs)
-    else:
-        run(cmd, *args, **kwargs)
+    #---------------------------------------------------------------------------
+    def __init__(self, command, hosts):
+        self.command = command
+        self.hosts = list(hosts)
 
-def sudo_scoped(cmd, *args, **kwargs):
+    #---------------------------------------------------------------------------
+    def __call__(self, *args, **kwargs):
+        kwargs['hosts'] = self.hosts
+        return execute(self.command, *args, **kwargs)
+
+#-------------------------------------------------------------------------------
+def local_sudo(command, shell=True, pty=True, combine_stderr=None, user=None):
     """
-    Runs the specified command as `sudo` on the local machine unless LOCAL_SCOPE_ENV
-    is False then it runs against the current fab ENV.
+    Run a shell command on a local host, with superuser privileges.
+
+    `sudo` is identical in every way to fabric's `fabric.operations.sudo`, except
+    that it will run the command locally, instead of remotely.
     """
-    print LOCAL_SCOPE_ENV
+    cmd = """sudo -u %s sh -c "%s" """ % (user, cmd)
+    local_run(cmd, shell=shell, pty=pty, combine_stderr=combine_stderr)
 
-    if LOCAL_SCOPE_ENV:
-        cmd = """sudo -u %s sh -c "%s" """ % (kwargs['user'], cmd)
-        local(cmd, *args)
-    else:
-        sudo(cmd, *args, **kwargs)
+#-------------------------------------------------------------------------------
+class BasteEnvironment(object):
+    """
+    A simple class used to store baste environment settings.
+    """
+    #---------------------------------------------------------------------------
+    def get_baste_dev_hosts(self):
+        """
+        A helper which retrieves the environments `baste_dev_hosts` setting.
+
+        Defaults to "localhost".
+        """
+        return getattr(env, 'baste_dev_hosts', 'localhost')
+    baste_dev_hosts = property(get_baste_dev_hosts)
+
+    #---------------------------------------------------------------------------
+    def get_baste_env_hosts(self):
+        """
+        Parses the `baste_dev_hosts` as a set of semi-colon separated host values.
+        """
+        return self.baste_dev_hosts.split(";")
+    baste_env_hosts = property(get_baste_env_hosts)
+
+    #---------------------------------------------------------------------------
+    def get_run_command(self):
+        """
+        Returns a run command that will run against either a local or remote env.
+
+        Uses the fabric env setting `baste_dev_hosts` to determine which it is.
+        `baste_dev_hosts` may be set to "localhost" or "host1;host2". The default
+        is "localhost".  When set to "localhost", the fabric "local" command
+        will be used and commands are run directly, rather than over ssh. If
+        `baste_dev_hosts` is anything else, it is interpreted as the env.hosts
+        necessary to run the commands over an ssh connection.  Multiple hosts
+        can be specified by separating them with semi-colons.
+
+        """
+        if self.baste_dev_hosts == "localhost":
+            return local_run
+        else:
+            env.hosts = hosts = self.baste_env_hosts
+            return ExecuteOnHosts(remote_run, hosts)
+    run = property(get_run_command)
+
+    #---------------------------------------------------------------------------
+    def get_sudo_command(self):
+        """
+        Returns a sudo command that will run against either a local or remote env.
+
+        Uses the fabric env setting `baste_dev_hosts` to determine which it is.
+        `baste_dev_hosts` may be set to "localhost" or "host1;host2". The default
+        is "localhost".  When set to "localhost", the fabric "local" command
+        will be used and commands are run directly, rather than over ssh. If
+        `baste_dev_hosts` is anything else, it is interpreted as the env.hosts
+        necessary to run the commands over an ssh connection.  Multiple hosts
+        can be specified by separating them with semi-colons.
+        """
+        if self.baste_dev_hosts == "localhost":
+            return local_sudo
+        else:
+            env.hosts = hosts = self.baste_env_hosts
+            return ExecuteOnHosts(remote_sudo, hosts)
+    sudo = property(get_sudo_command)
+baste_env = BasteEnvironment()
 
 #-------------------------------------------------------------------------------
 def project_relative(path):
     return os.path.join(os.path.dirname(env.real_fabfile), path)
 
-
 #-------------------------------------------------------------------------------
 class Repository(object):
     """
 
     #---------------------------------------------------------------------------
     def status(self):
-        run_scoped(self.status_command())
+        baste_env.run(self.status_command())
 
     #---------------------------------------------------------------------------
     def update(self):
             cmd = "test -d %s && %s || %s" % (
                         self.directory, self.update_command(), self.create_command()
                         )
-            run_scoped(cmd)
+            baste_env.run(cmd)
 
 #-------------------------------------------------------------------------------
 class Subversion(Repository):
     create_symbolic_link = "ln -s %s %s" % (python_path, symlink)
     print(colors.green("[install] ") + package)
     with hide('running'):
-        run_scoped("test -L %s || %s" % (symlink, create_symbolic_link))
+        baste_env.run("test -L %s || %s" % (symlink, create_symbolic_link))
 
 #-------------------------------------------------------------------------------
 class StatusCommand(object):
         commands = []
         for repo in self.repos.values():
             commands.append(repo.diff_command())
-        run_scoped("{ %s; } | less" % (" && ".join(commands)))
+        baste_env.run("{ %s; } | less" % (" && ".join(commands)))
 
 #-------------------------------------------------------------------------------
 class PgRestore(object):
         """
         Uses the pg_restore command to restore the database from the given file.
         """
-        run_scoped(
+        baste_env.run(
             "pg_restore --clean --no-owner --no-privileges --format=%s --host=localhost --username=%s --dbname=%s %s" % (
                 self.format, self.user, self.db, self.file
             )
     #---------------------------------------------------------------------------
     def __call__(self):
         """Uses psql to load a plain dump format"""
-        run_scoped(
+        baste_env.run(
             "bzcat %s | psql --host=localhost --username=%s --dbname=%s" % (
                 self.file, self.user, self.db
             )
         """
         Uses the psql command to give someone a shell within the db.
         """
-        run_scoped("psql --host=localhost --username=%s %s" % (self.user, self.db))
+        baste_env.run("psql --host=localhost --username=%s %s" % (self.user, self.db))
 
 #-------------------------------------------------------------------------------
 class MysqlLoadPlain(object):
     #---------------------------------------------------------------------------
     def __call__(self):
         """Uses mysql command line client to load a plain dump format."""
-        run_scoped(
+        baste_env.run(
             "mysql -h localhost -u %s -p %s < %s" % (self.user, self.db, self.file)
         )
 
         """
         Uses the psql command to give someone a shell within the db.
         """
-        local("rsync --progress -avz --exclude=\".svn/*\" --exclude=\".svn\" -e ssh %s:%s %s" % (self.host, self.remote_directory, self.local_directory))
+        local_run("rsync --progress -avz --exclude=\".svn/*\" --exclude=\".svn\" -e ssh %s:%s %s" % (self.host, self.remote_directory, self.local_directory))
 
 REPO_EXCLUDES = ['.svn', '.git', '.hg', '.hgignore', 'fabfile.py', '*.pyc', 'env']
 #-------------------------------------------------------------------------------
                 exclude=REPO_EXCLUDES,
                 delete=True,
             )
-        run("cp -r %s %s" % (source_directory, date_directory))
-        run("ln -sf %s %s; mv -Tf %s %s" % (date_directory, tmp_symlink, tmp_symlink, current_symlink))
+        remote_run("cp -r %s %s" % (source_directory, date_directory))
+        remote_run("ln -sf %s %s; mv -Tf %s %s" % (date_directory, tmp_symlink, tmp_symlink, current_symlink))
 
 
 #-------------------------------------------------------------------------------
     #---------------------------------------------------------------------------
     def __call__(self):
         with settings(warn_only=True, hide=('warnings',)):
-            sudo_scoped("dropdb %s" % self.db_name, user="postgres")
-            sudo_scoped("dropuser %s" % self.db_user, user="postgres")
-            sudo_scoped("createuser --createdb --pwprompt --no-superuser --no-createrole %s" %
+            baste_env.sudo("dropdb %s" % self.db_name, user="postgres")
+            baste_env.sudo("dropuser %s" % self.db_user, user="postgres")
+            baste_env.sudo("createuser --createdb --pwprompt --no-superuser --no-createrole %s" %
                     self.db_user, user="postgres")
-            sudo_scoped("createdb -O %s %s" % (self.db_user, self.db_name), user="postgres")
+            baste_env.sudo("createdb -O %s %s" % (self.db_user, self.db_name), user="postgres")