Hello community,

here is the log from the commit of package python-Fabric for openSUSE:Factory 
checked in at 2012-04-17 07:48:36
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-Fabric (Old)
 and      /work/SRC/openSUSE:Factory/.python-Fabric.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-Fabric", Maintainer is ""

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-Fabric/python-Fabric.changes      
2012-03-05 18:01:31.000000000 +0100
+++ /work/SRC/openSUSE:Factory/.python-Fabric.new/python-Fabric.changes 
2012-04-17 07:48:39.000000000 +0200
@@ -1,0 +2,36 @@
+Thu Apr  5 04:20:21 UTC 2012 - [email protected]
+
+- Update to 1.4.1:
+  * Add ``capture`` kwarg to `~fabric.contrib.project.rsync_project`
+    to aid in debugging rsync problems.
+  * Allow `~fabric.operations.local` to display stdout/stderr when it
+    warns/aborts, if it was capturing them.
+  * Added :ref:`an FAQ entry <init-scripts-pty>` detailing how to
+    handle init scripts which misbehave when a pseudo-tty is allocated.
+  * `~fabric.tasks.execute` allowed too much of its internal state
+    changes (to variables such as ``env.host_string`` and ``env.parallel``) to
+    persist after execution completed; this caused a number of different
+    incorrect behaviors. `~fabric.tasks.execute` has been overhauled to clean 
up
+    its own state changes -- while preserving any state changes made by the 
task
+    being executed.
+  * `~fabric.contrib.project.upload_project` did not take explicit
+    remote directory location into account when untarring, and now uses
+    `~fabric.context_managers.cd` to address this. Thanks to Ben Burry for the
+    patch.
+  * `~fabric.decorators.with_settings` did not perfectly match
+    `~fabric.context_managers.settings`, re: ability to inline additional 
context
+    managers. This has been corrected. Thanks to Rory Geoghegan for the patch.
+  * `contrib.files.first <fabric.contrib.files.first>` used an
+    outdated function signature in its wrapped `~fabric.contrib.files.exists`
+    call. This has been fixed. Thanks to Massimiliano Torromeo for catch & 
patch.
+  * `--list <-l>` output now detects terminal window size
+    and truncates (or doesn't truncate) accordingly. Thanks to Horacio G. de 
Oro
+    for the initial pull request.
+  * Parallel task aborts (as oppposed to unhandled exceptions) now
+    correctly print their abort messages instead of tracebacks, and cause the
+    parent process to exit with the correct (nonzero) return code. Thanks to 
Ian
+    Langworth for the catch.
+  * Remote paths now use posixpath for a separator. Thanks to Jason
+    Coombs for the patch.
+
+-------------------------------------------------------------------

Old:
----
  Fabric-1.4.0.tar.gz

New:
----
  Fabric-1.4.1.tar.bz2

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-Fabric.spec ++++++
--- /var/tmp/diff_new_pack.xZTNs5/_old  2012-04-17 07:48:40.000000000 +0200
+++ /var/tmp/diff_new_pack.xZTNs5/_new  2012-04-17 07:48:40.000000000 +0200
@@ -17,13 +17,13 @@
 
 
 Name:           python-Fabric
-Version:        1.4.0
+Version:        1.4.1
 Release:        0
 Summary:        Fabric is a simple, Pythonic tool for remote execution and 
deployment
 License:        BSD-2-Clause
 Group:          Development/Languages/Python
 Url:            http://fabfile.org
-Source:         Fabric-%{version}.tar.gz
+Source:         Fabric-%{version}.tar.bz2
 BuildRequires:  python-devel
 BuildRequires:  python-distribute
 #BuildRequires:  python-fudge

++++++ Fabric-1.4.0.tar.gz -> Fabric-1.4.1.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Fabric-1.4.0/AUTHORS new/Fabric-1.4.1/AUTHORS
--- old/Fabric-1.4.0/AUTHORS    2012-02-14 06:53:02.000000000 +0100
+++ new/Fabric-1.4.1/AUTHORS    2012-04-05 06:03:05.000000000 +0200
@@ -47,5 +47,7 @@
 Max Arnold
 Szymon Reichmann
 David Wolever
+Jason Coombs
 Ben Davis
 Neilen Marais
+Rory Geoghegan
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Fabric-1.4.0/Fabric.egg-info/PKG-INFO 
new/Fabric-1.4.1/Fabric.egg-info/PKG-INFO
--- old/Fabric-1.4.0/Fabric.egg-info/PKG-INFO   2012-02-14 06:53:03.000000000 
+0100
+++ new/Fabric-1.4.1/Fabric.egg-info/PKG-INFO   2012-04-05 06:03:11.000000000 
+0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.0
 Name: Fabric
-Version: 1.4.0
+Version: 1.4.1
 Summary: Fabric is a simple, Pythonic tool for remote execution and deployment.
 Home-page: http://fabfile.org
 Author: Jeff Forcier
@@ -8,7 +8,7 @@
 License: UNKNOWN
 Description: 
         To find out what's new in this version of Fabric, please see `the 
changelog
-        <http://docs.fabfile.org/en/1.4.0/changelog.html>`_.
+        <http://docs.fabfile.org/en/1.4.1/changelog.html>`_.
         
         You can also install the `in-development version
         <https://github.com/fabric/fabric/tarball/master#egg=fabric-dev>`_ 
using
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Fabric-1.4.0/PKG-INFO new/Fabric-1.4.1/PKG-INFO
--- old/Fabric-1.4.0/PKG-INFO   2012-02-14 06:53:03.000000000 +0100
+++ new/Fabric-1.4.1/PKG-INFO   2012-04-05 06:03:11.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.0
 Name: Fabric
-Version: 1.4.0
+Version: 1.4.1
 Summary: Fabric is a simple, Pythonic tool for remote execution and deployment.
 Home-page: http://fabfile.org
 Author: Jeff Forcier
@@ -8,7 +8,7 @@
 License: UNKNOWN
 Description: 
         To find out what's new in this version of Fabric, please see `the 
changelog
-        <http://docs.fabfile.org/en/1.4.0/changelog.html>`_.
+        <http://docs.fabfile.org/en/1.4.1/changelog.html>`_.
         
         You can also install the `in-development version
         <https://github.com/fabric/fabric/tarball/master#egg=fabric-dev>`_ 
using
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Fabric-1.4.0/docs/changelog.rst 
new/Fabric-1.4.1/docs/changelog.rst
--- old/Fabric-1.4.0/docs/changelog.rst 2012-02-14 06:53:02.000000000 +0100
+++ new/Fabric-1.4.1/docs/changelog.rst 2012-04-05 06:03:05.000000000 +0200
@@ -25,6 +25,39 @@
 Changelog
 =========
 
+* :release:`1.4.1 <2012-04-04>`
+* :release:`1.3.6 <2012-04-04>`
+* :bug:`608` Add ``capture`` kwarg to `~fabric.contrib.project.rsync_project`
+  to aid in debugging rsync problems.
+* :bug:`607` Allow `~fabric.operations.local` to display stdout/stderr when it
+  warns/aborts, if it was capturing them.
+* :bug:`395` Added :ref:`an FAQ entry <init-scripts-pty>` detailing how to
+  handle init scripts which misbehave when a pseudo-tty is allocated.
+* :bug:`568` `~fabric.tasks.execute` allowed too much of its internal state
+  changes (to variables such as ``env.host_string`` and ``env.parallel``) to
+  persist after execution completed; this caused a number of different
+  incorrect behaviors. `~fabric.tasks.execute` has been overhauled to clean up
+  its own state changes -- while preserving any state changes made by the task
+  being executed.
+* :bug:`584` `~fabric.contrib.project.upload_project` did not take explicit
+  remote directory location into account when untarring, and now uses
+  `~fabric.context_managers.cd` to address this. Thanks to Ben Burry for the
+  patch.
+* :bug:`458` `~fabric.decorators.with_settings` did not perfectly match
+  `~fabric.context_managers.settings`, re: ability to inline additional context
+  managers. This has been corrected. Thanks to Rory Geoghegan for the patch.
+* :bug:`499` `contrib.files.first <fabric.contrib.files.first>` used an
+  outdated function signature in its wrapped `~fabric.contrib.files.exists`
+  call. This has been fixed. Thanks to Massimiliano Torromeo for catch & patch.
+* :bug:`551` :option:`--list <-l>` output now detects terminal window size
+  and truncates (or doesn't truncate) accordingly. Thanks to Horacio G. de Oro
+  for the initial pull request.
+* :bug:`572` Parallel task aborts (as oppposed to unhandled exceptions) now
+  correctly print their abort messages instead of tracebacks, and cause the
+  parent process to exit with the correct (nonzero) return code. Thanks to Ian
+  Langworth for the catch.
+* :bug:`306` Remote paths now use posixpath for a separator. Thanks to Jason
+  Coombs for the patch.
 * :release:`1.4.0 <2012-02-13>`
 * :release:`1.3.5 <2012-02-13>`
 * :release:`1.2.6 <2012-02-13>`
@@ -804,7 +837,7 @@
 * :issue:`120`: Tweaked documentation, help strings to make it more obvious
   that fabfiles are simply Python modules.
 * :issue:`127`: Added :ref:`note to install docs <pypm>` re: ActiveState's
-  PyPM. Thanks to Sridhar Ratnakumar for the tip. 
+  PyPM. Thanks to Sridhar Ratnakumar for the tip.
 
 
 Changes in version 0.9 (2009-11-08)
@@ -1082,7 +1115,7 @@
 
 * Various minor tweaks to the (still in-progress) documentation, including one
   thanks to Curt Micol.
-  
+
 * Added a number of TODO items based on user feedback (thanks!)
 
 * Host information now available in granular form (user, host, port) in the
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Fabric-1.4.0/docs/faq.rst 
new/Fabric-1.4.1/docs/faq.rst
--- old/Fabric-1.4.0/docs/faq.rst       2012-02-14 06:52:54.000000000 +0100
+++ new/Fabric-1.4.1/docs/faq.rst       2012-04-02 18:54:53.000000000 +0200
@@ -8,6 +8,22 @@
 <usage-docs>`, so please make sure you check those out if your question is not
 answered here.
 
+.. _init-scripts-pty:
+
+Init scripts don't work!
+========================
+
+Init-style start/stop/restart scripts (e.g. ``/etc/init.d/apache2 start``)
+sometimes don't like Fabric's allocation of a pseudo-tty, which is active by
+default. In almost all cases, explicitly calling the command in question with
+``pty=False`` works correctly::
+
+    sudo("/etc/init.d/apache2 restart", pty=False)
+
+If you have no need for interactive behavior and run into this problem
+frequently, you may want to deactivate pty allocation globally by setting
+:ref:`env.always_use_pty <always-use-pty>` to ``False``.
+
 .. _one-shell-per-command:
 
 My (``cd``/``workon``/``export``/etc) calls don't seem to work!
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Fabric-1.4.0/docs/tutorial.rst 
new/Fabric-1.4.1/docs/tutorial.rst
--- old/Fabric-1.4.0/docs/tutorial.rst  2011-10-24 00:34:53.000000000 +0200
+++ new/Fabric-1.4.1/docs/tutorial.rst  2012-03-21 00:14:37.000000000 +0100
@@ -274,8 +274,9 @@
 
 * Fabric is just Python -- so we can make liberal use of regular Python code
   constructs such as variables and string interpolation;
-* `~fabric.context_managers.cd`, an easy way of prefixing commands with a
-  ``cd /to/some/directory`` call.
+* `~fabric.context_managers.cd`, an easy way of prefixing commands with a ``cd
+  /to/some/directory`` call. This is similar to  `~fabric.context_managers.lcd`
+  which does the same locally.
 * `~fabric.operations.run`, which is similar to `~fabric.operations.local` but
   runs remotely instead of locally.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Fabric-1.4.0/fabric/context_managers.py 
new/Fabric-1.4.1/fabric/context_managers.py
--- old/Fabric-1.4.0/fabric/context_managers.py 2011-10-23 02:59:23.000000000 
+0200
+++ new/Fabric-1.4.1/fabric/context_managers.py 2012-04-05 06:03:05.000000000 
+0200
@@ -10,7 +10,8 @@
 from contextlib import contextmanager, nested
 import sys
 
-from fabric.state import env, output, win32
+from fabric.state import output, win32
+from fabric import state
 
 if not win32:
     import termios
@@ -84,20 +85,29 @@
     This context manager is used internally by `settings` and is not intended
     to be used directly.
     """
+    clean_revert = kwargs.pop('clean_revert', False)
     previous = {}
     new = []
     for key, value in kwargs.iteritems():
-        if key in env:
-            previous[key] = env[key]
+        if key in state.env:
+            previous[key] = state.env[key]
         else:
             new.append(key)
-        env[key] = value
+        state.env[key] = value
     try:
         yield
     finally:
-        env.update(previous)
-        for key in new:
-            del env[key]
+        if clean_revert:
+            for key, value in kwargs.iteritems():
+                # If the current env value for this key still matches the
+                # value we set it to beforehand, we are OK to revert it to the
+                # pre-block value.
+                if value == state.env[key]:
+                    state.env[key] = previous[key]
+        else:
+            state.env.update(previous)
+            for key in new:
+                del state.env[key]
 
 
 def settings(*args, **kwargs):
@@ -109,6 +119,9 @@
     * Most usefully, it allows temporary overriding/updating of ``env`` with
       any provided keyword arguments, e.g. ``with settings(user='foo'):``.
       Original values, if any, will be restored once the ``with`` block closes.
+        * The keyword argument ``clean_revert`` has special meaning for
+          ``settings`` itself (see below) and will be stripped out before
+          execution.
     * In addition, it will use `contextlib.nested`_ to nest any given
       non-keyword arguments, which should be other context managers, e.g.
       ``with settings(hide('stderr'), show('stdout')):``.
@@ -139,6 +152,41 @@
     variables in tandem with hiding (or showing) specific levels of output, or
     in tandem with any other piece of Fabric functionality implemented as a
     context manager.
+
+    If ``clean_revert`` is set to ``True``, ``settings`` will **not** revert
+    keys which are altered within the nested block, instead only reverting keys
+    whose values remain the same as those given. More examples will make this
+    clear; below is how ``settings`` operates normally::
+
+        # Before the block, env.parallel defaults to False, host_string to None
+        with settings(parallel=True, host_string='myhost'):
+            # env.parallel is True
+            # env.host_string is 'myhost'
+            env.host_string = 'otherhost'
+            # env.host_string is now 'otherhost'
+        # Outside the block:
+        # * env.parallel is False again
+        # * env.host_string is None again
+
+    The internal modification of ``env.host_string`` is nullified -- not always
+    desirable. That's where ``clean_revert`` comes in::
+
+        # Before the block, env.parallel defaults to False, host_string to None
+        with settings(parallel=True, host_string='myhost', clean_revert=True):
+            # env.parallel is True
+            # env.host_string is 'myhost'
+            env.host_string = 'otherhost'
+            # env.host_string is now 'otherhost'
+        # Outside the block:
+        # * env.parallel is False again
+        # * env.host_string remains 'otherhost'
+
+    Brand new keys which did not exist in ``env`` prior to using ``settings``
+    are also preserved if ``clean_revert`` is active. When ``False``, such keys
+    are removed when the block exits.
+
+    .. versionadded:: 1.4.1
+        The ``clean_revert`` kwarg.
     """
     managers = list(args)
     if kwargs:
@@ -225,8 +273,8 @@
 
 def _change_cwd(which, path):
     path = path.replace(' ', '\ ')
-    if env.get(which) and not path.startswith('/'):
-        new_cwd = env.get(which) + '/' + path
+    if state.env.get(which) and not path.startswith('/'):
+        new_cwd = state.env.get(which) + '/' + path
     else:
         new_cwd = path
     return _setenv(**{which: new_cwd})
@@ -315,7 +363,7 @@
 
     Contrived, but hopefully illustrative.
     """
-    return _setenv(command_prefixes=env.command_prefixes + [command])
+    return _setenv(command_prefixes=state.env.command_prefixes + [command])
 
 
 @contextmanager
@@ -325,7 +373,7 @@
 
     Only applies on Unix-based systems; on Windows this is a no-op.
     """
-    if win32 or not sys.stdin.isatty():
+    if win32 or not pipe.isatty():
         yield
     else:
         old_settings = termios.tcgetattr(pipe)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Fabric-1.4.0/fabric/contrib/files.py 
new/Fabric-1.4.1/fabric/contrib/files.py
--- old/Fabric-1.4.0/fabric/contrib/files.py    2012-02-14 06:53:02.000000000 
+0100
+++ new/Fabric-1.4.1/fabric/contrib/files.py    2012-04-05 06:03:05.000000000 
+0200
@@ -38,15 +38,11 @@
 def first(*args, **kwargs):
     """
     Given one or more file paths, returns first one found, or None if none
-    exist. May specify ``use_sudo`` which is passed to `exists`.
+    exist. May specify ``use_sudo`` and ``verbose`` which are passed to 
`exists`.
     """
     for directory in args:
-        if not kwargs.get('use_sudo'):
-            if exists(directory, sudo=False):
-                return directory
-        else:
-            if exists(directory):
-                return directory
+        if exists(directory, **kwargs):
+            return directory
 
 
 def upload_template(filename, destination, context=None, use_jinja=False,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Fabric-1.4.0/fabric/contrib/project.py 
new/Fabric-1.4.1/fabric/contrib/project.py
--- old/Fabric-1.4.0/fabric/contrib/project.py  2012-02-14 06:53:02.000000000 
+0100
+++ new/Fabric-1.4.1/fabric/contrib/project.py  2012-04-05 06:03:05.000000000 
+0200
@@ -1,6 +1,7 @@
 """
 Useful non-core functionality, e.g. functions composing multiple operations.
 """
+from __future__ import with_statement
 
 from os import getcwd, sep
 import os.path
@@ -10,12 +11,13 @@
 from fabric.network import needs_host, key_filenames, normalize
 from fabric.operations import local, run, put
 from fabric.state import env, output
+from fabric.context_managers import cd
 
 __all__ = ['rsync_project', 'upload_project']
 
 @needs_host
 def rsync_project(remote_dir, local_dir=None, exclude=(), delete=False,
-    extra_opts='', ssh_opts=''):
+    extra_opts='', ssh_opts='', capture=False):
     """
     Synchronize a remote directory with the current project directory via 
rsync.
 
@@ -65,6 +67,7 @@
       custom arguments or options to ``rsync``.
     * ``ssh_opts``: Like ``extra_opts`` but specifically for the SSH options
       string (rsync's ``--rsh`` flag.)
+    * ``capture``: Sent directly into an inner `~fabric.operations.local` call.
 
     Furthermore, this function transparently honors Fabric's port and SSH key
     settings. Calling this function when the current host string contains a
@@ -77,8 +80,10 @@
         rsync [--delete] [--exclude exclude[0][, --exclude[1][, ...]]] \\
             -pthrvz [extra_opts] <local_dir> <host_string>:<remote_dir>
 
-    .. versionadded:: 1.4
+    .. versionadded:: 1.4.0
         The ``ssh_opts`` keyword argument.
+    .. versionadded:: 1.4.1
+        The ``capture`` keyword argument.
     """
     # Turn single-string exclude into a one-item list for consistency
     if not hasattr(exclude, '__iter__'):
@@ -115,7 +120,7 @@
     cmd = "rsync %s %s %s@%s:%s" % (options, local_dir, user, host, remote_dir)
     if output.running:
         print("[%s] rsync_project: %s" % (env.host_string, cmd))
-    return local(cmd)
+    return local(cmd, capture=capture)
 
 
 def upload_project(local_dir=None, remote_dir=""):
@@ -151,9 +156,10 @@
         tar_path = os.path.join(tmp_folder, tar_file)
         local("tar -czf %s -C %s %s" % (tar_path, local_path, local_name))
         put(tar_path, target_tar)
-        try:
-            run("tar -xzf %s" % tar_file)
-        finally:
-            run("rm -f %s" % tar_file)
+        with cd(remote_dir):
+            try:
+                run("tar -xzf %s" % tar_file)
+            finally:
+                run("rm -f %s" % tar_file)
     finally:
         local("rm -rf %s" % tmp_folder)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Fabric-1.4.0/fabric/decorators.py 
new/Fabric-1.4.1/fabric/decorators.py
--- old/Fabric-1.4.0/fabric/decorators.py       2012-02-14 06:52:54.000000000 
+0100
+++ new/Fabric-1.4.1/fabric/decorators.py       2012-03-21 00:14:37.000000000 
+0100
@@ -188,7 +188,7 @@
     return real_decorator
 
 
-def with_settings(**kw_settings):
+def with_settings(*arg_settings, **kw_settings):
     """
     Decorator equivalent of ``fabric.context_managers.settings``.
 
@@ -209,7 +209,7 @@
     def outer(func):
         @wraps(func)
         def inner(*args, **kwargs):
-            with settings(**kw_settings):
+            with settings(*arg_settings, **kw_settings):
                 return func(*args, **kwargs)
         return _wrap_as_new(func, inner)
     return outer
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Fabric-1.4.0/fabric/job_queue.py 
new/Fabric-1.4.1/fabric/job_queue.py
--- old/Fabric-1.4.0/fabric/job_queue.py        2012-02-14 06:53:02.000000000 
+0100
+++ new/Fabric-1.4.1/fabric/job_queue.py        2012-04-05 06:03:05.000000000 
+0200
@@ -5,6 +5,7 @@
 items, though within Fabric itself only ``Process`` objects are used/supported.
 """
 
+from __future__ import with_statement
 from pprint import pprint
 from Crypto import Random 
 import time
@@ -12,6 +13,7 @@
 
 from fabric.state import env
 from fabric.network import ssh
+from fabric.context_managers import settings
 
 
 class JobQueue(object):
@@ -117,8 +119,8 @@
             job = self._queued.pop()
             if self._debug:
                 print("Popping '%s' off the queue and starting it" % job.name)
-            env.host_string = env.host = job.name
-            job.start()
+            with settings(clean_revert=True, host_string=job.name, 
host=job.name):
+                job.start()
             self._running.append(job)
 
         if not self._closed:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Fabric-1.4.0/fabric/main.py 
new/Fabric-1.4.1/fabric/main.py
--- old/Fabric-1.4.0/fabric/main.py     2012-02-14 06:53:02.000000000 +0100
+++ new/Fabric-1.4.1/fabric/main.py     2012-04-05 06:03:05.000000000 +0200
@@ -25,6 +25,7 @@
 from fabric.tasks import Task, execute
 from fabric.task_utils import _Dict, crawl
 from fabric.utils import abort, indent
+from fabric.operations import _pty_size
 
 # One-time calculation of "all internal callables" to avoid doing this on every
 # check of a given fabfile callable (in is_classic_task()).
@@ -383,6 +384,7 @@
     max_len = reduce(lambda a, b: max(a, len(b)), task_names, 0)
     sep = '  '
     trail = '...'
+    max_width = _pty_size()[1] - 1 - len(trail)
     for name in task_names:
         output = None
         docstring = _print_docstring(docstrings, name)
@@ -390,7 +392,7 @@
             lines = filter(None, docstring.splitlines())
             first_line = lines[0].strip()
             # Truncate it if it's longer than N chars
-            size = 75 - (max_len + len(sep) + len(trail))
+            size = max_width - (max_len + len(sep) + len(trail))
             if len(first_line) > size:
                 first_line = first_line[:size] + trail
             output = name.ljust(max_len) + sep + first_line
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Fabric-1.4.0/fabric/network.py 
new/Fabric-1.4.1/fabric/network.py
--- old/Fabric-1.4.0/fabric/network.py  2012-02-14 06:53:02.000000000 +0100
+++ new/Fabric-1.4.1/fabric/network.py  2012-04-05 06:03:05.000000000 +0200
@@ -302,7 +302,7 @@
         # command line results in the big banner error about man-in-the-middle
         # attacks.
         except ssh.BadHostKeyException, e:
-            raise NetworkError("Host key for %s did not match pre-existing 
key! Server's key was changed recently, or possible man-in-the-middle attack." 
% env.host, e)
+            raise NetworkError("Host key for %s did not match pre-existing 
key! Server's key was changed recently, or possible man-in-the-middle attack." 
% host, e)
         # Prompt for new password to try on auth failure
         except (
             ssh.AuthenticationException,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Fabric-1.4.0/fabric/operations.py 
new/Fabric-1.4.1/fabric/operations.py
--- old/Fabric-1.4.0/fabric/operations.py       2012-02-14 06:53:02.000000000 
+0100
+++ new/Fabric-1.4.1/fabric/operations.py       2012-04-05 06:03:05.000000000 
+0200
@@ -6,6 +6,7 @@
 
 import os
 import os.path
+import posixpath
 import re
 import stat
 import subprocess
@@ -531,7 +532,7 @@
             # Otherwise, be relative to remote home directory (SFTP server's
             # '.')
             else:
-                remote_path = os.path.join(home, remote_path)
+                remote_path = posixpath.join(home, remote_path)
 
         # Track final local destination files so we can return a list
         local_files = []
@@ -1004,7 +1005,7 @@
     if p.returncode != 0:
         out.failed = True
         msg = "local() encountered an error (return code %s) while executing 
'%s'" % (p.returncode, command)
-        error(message=msg)
+        error(message=msg, stdout=out, stderr=err)
     out.succeeded = not out.failed
     # If we were capturing, this will be a string; otherwise it will be None.
     return out
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Fabric-1.4.0/fabric/sftp.py 
new/Fabric-1.4.1/fabric/sftp.py
--- old/Fabric-1.4.0/fabric/sftp.py     2012-02-14 06:52:54.000000000 +0100
+++ new/Fabric-1.4.1/fabric/sftp.py     2012-04-05 06:00:58.000000000 +0200
@@ -2,6 +2,7 @@
 
 import hashlib
 import os
+import posixpath
 import stat
 import tempfile
 from fnmatch import filter as fnfilter
@@ -53,7 +54,7 @@
             s = '/'
             ret = [dirpart.rstrip(s) + s + name.lstrip(s) for name in names]
             if not win32:
-                ret = [os.path.join(dirpart, name) for name in names]
+                ret = [posixpath.join(dirpart, name) for name in names]
         return ret
 
     def walk(self, top, topdown=True, onerror=None, followlinks=False):
@@ -174,8 +175,8 @@
             # Download any files in current directory
             for f in files:
                 # Construct full and relative remote paths to this file
-                rpath = os.path.join(context, f)
-                rremote = os.path.join(rcontext, f)
+                rpath = posixpath.join(context, f)
+                rremote = posixpath.join(rcontext, f)
                 # If local_path isn't using a format string that expands to
                 # include its remote path, we need to add it here.
                 if "%(path)s" not in local_path \
@@ -196,12 +197,12 @@
         pre = pre if pre else ''
         if local_is_path and self.isdir(remote_path):
             basename = os.path.basename(local_path)
-            remote_path = os.path.join(remote_path, basename)
+            remote_path = posixpath.join(remote_path, basename)
         if output.running:
             print("[%s] put: %s -> %s" % (
                 env.host_string,
                 local_path if local_is_path else '<file obj>',
-                os.path.join(pre, remote_path)
+                posixpath.join(pre, remote_path)
             ))
         # When using sudo, "bounce" the file through a guaranteed-unique file
         # path in the default remote CWD (which, typically, the login user will
@@ -258,19 +259,19 @@
         for context, dirs, files in os.walk(local_path):
             rcontext = context.replace(strip, '', 1)
             rcontext = rcontext.lstrip('/')
-            rcontext = os.path.join(remote_path, rcontext)
+            rcontext = posixpath.join(remote_path, rcontext)
 
             if not self.exists(rcontext):
                 self.mkdir(rcontext, use_sudo)
 
             for d in dirs:
-                n = os.path.join(rcontext, d)
+                n = posixpath.join(rcontext, d)
                 if not self.exists(n):
                     self.mkdir(n, use_sudo)
 
             for f in files:
                 local_path = os.path.join(context, f)
-                n = os.path.join(rcontext, f)
+                n = posixpath.join(rcontext, f)
                 p = self.put(local_path, n, use_sudo, mirror_local_mode, mode,
                     True)
                 remote_paths.append(p)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Fabric-1.4.0/fabric/tasks.py 
new/Fabric-1.4.1/fabric/tasks.py
--- old/Fabric-1.4.0/fabric/tasks.py    2012-02-14 06:53:02.000000000 +0100
+++ new/Fabric-1.4.1/fabric/tasks.py    2012-04-05 06:03:05.000000000 +0200
@@ -83,8 +83,7 @@
         pool_size = min((pool_size, len(hosts)))
         # Inform user of final pool size for this task
         if state.output.debug:
-            msg = "Parallel tasks now using pool size of %d"
-            print msg % pool_size
+            print "Parallel tasks now using pool size of %d" % pool_size
         return pool_size
 
 
@@ -149,46 +148,53 @@
     # Create per-run env with connection settings
     local_env = to_dict(host)
     local_env.update(my_env)
-    state.env.update(local_env)
-    # Handle parallel execution
-    if queue is not None: # Since queue is only set for parallel
-        # Set a few more env flags for parallelism
-        state.env.parallel = True # triggers some extra aborts, etc
-        state.env.linewise = True # to mirror -P behavior
-        name = local_env['host_string']
-        # Wrap in another callable that:
-        # * nukes the connection cache to prevent shared-access problems
-        # * knows how to send the tasks' return value back over a Queue
-        # * captures exceptions raised by the task
-        def inner(args, kwargs, queue, name):
-            key = normalize_to_string(state.env.host_string)
-            state.connections.pop(key, "")
-            try:
-                result = task.run(*args, **kwargs)
-            except BaseException, e: # We really do want to capture everything
-                result = e
-                # But still print it out, otherwise users won't know what the
-                # fuck. Especially if the task is run at top level and nobody's
-                # doing anything with the return value.
-                print >> sys.stderr, "!!! Parallel execution exception under 
host %r:" % name
-                sys.excepthook(*sys.exc_info())
-            queue.put({'name': name, 'result': result})
-
-        # Stuff into Process wrapper
-        kwarg_dict = {
-            'args': args,
-            'kwargs': kwargs,
-            'queue': queue,
-            'name': name
-        }
-        p = multiprocessing.Process(target=inner, kwargs=kwarg_dict)
-        # Name/id is host string
-        p.name = name
-        # Add to queue
-        jobs.append(p)
-    # Handle serial execution
-    else:
-        return task.run(*args, **kwargs)
+    # Set a few more env flags for parallelism
+    if queue is not None:
+        local_env.update({'parallel': True, 'linewise': True})
+    with settings(**local_env):
+        # Handle parallel execution
+        if queue is not None: # Since queue is only set for parallel
+            name = local_env['host_string']
+            # Wrap in another callable that:
+            # * nukes the connection cache to prevent shared-access problems
+            # * knows how to send the tasks' return value back over a Queue
+            # * captures exceptions raised by the task
+            def inner(args, kwargs, queue, name):
+                try:
+                    key = normalize_to_string(state.env.host_string)
+                    state.connections.pop(key, "")
+                    result = task.run(*args, **kwargs)
+                except BaseException, e: # We really do want to capture 
everything
+                    result = e
+                    # But still print it out, otherwise users won't know what 
the
+                    # fuck. Especially if the task is run at top level and 
nobody's
+                    # doing anything with the return value.
+                    # BUT don't do this if it's a SystemExit as that implies 
use of
+                    # abort(), which does its own printing.
+                    if e.__class__ is not SystemExit:
+                        print >> sys.stderr, "!!! Parallel execution exception 
under host %r:" % name
+                        sys.excepthook(*sys.exc_info())
+                    # Conversely, if it IS SystemExit, we can raise it to 
ensure a
+                    # correct return value.
+                    else:
+                        raise
+                queue.put({'name': name, 'result': result})
+
+            # Stuff into Process wrapper
+            kwarg_dict = {
+                'args': args,
+                'kwargs': kwargs,
+                'queue': queue,
+                'name': name
+            }
+            p = multiprocessing.Process(target=inner, kwargs=kwarg_dict)
+            # Name/id is host string
+            p.name = name
+            # Add to queue
+            jobs.append(p)
+        # Handle serial execution
+        else:
+            return task.run(*args, **kwargs)
 
 def _is_task(task):
     return isinstance(task, Task)
@@ -235,7 +241,7 @@
         Added the return value mapping; previously this function had no defined
         return value.
     """
-    my_env = {}
+    my_env = {'clean_revert': True}
     results = {}
     # Obtain task
     is_callable = callable(task)
@@ -317,7 +323,8 @@
 
     # Or just run once for local-only
     else:
-        state.env.update(my_env)
-        results['<local-only>'] = task.run(*args, **new_kwargs)
+        with settings(**my_env):
+            results['<local-only>'] = task.run(*args, **new_kwargs)
     # Return what we can from the inner task executions
+
     return results
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Fabric-1.4.0/fabric/version.py 
new/Fabric-1.4.1/fabric/version.py
--- old/Fabric-1.4.0/fabric/version.py  2012-02-14 06:53:02.000000000 +0100
+++ new/Fabric-1.4.1/fabric/version.py  2012-04-05 06:03:05.000000000 +0200
@@ -10,7 +10,7 @@
 from os.path import abspath, dirname
 
 
-VERSION = (1, 4, 0, 'final', 0)
+VERSION = (1, 4, 1, 'final', 0)
 
 
 def git_sha():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Fabric-1.4.0/tests/test_context_managers.py 
new/Fabric-1.4.1/tests/test_context_managers.py
--- old/Fabric-1.4.0/tests/test_context_managers.py     2011-10-24 
00:34:53.000000000 +0200
+++ new/Fabric-1.4.1/tests/test_context_managers.py     2012-04-05 
06:03:05.000000000 +0200
@@ -2,8 +2,8 @@
 
 from nose.tools import eq_, ok_
 
-from fabric.state import env
-from fabric.context_managers import cd, settings
+from fabric.state import env, output
+from fabric.context_managers import cd, settings, lcd
 
 
 #
@@ -75,3 +75,31 @@
         eq_(env.testval2, "inner 2")
     eq_(env.testval1, "outer 1")
     eq_(env.testval2, "outer 2")
+
+def test_settings_with_other_context_managers():
+    """
+    settings() should take other context managers, and use them with other 
overrided
+    key/value pairs.
+    """
+    env.testval1 = "outer 1"
+    prev_lcwd = env.lcwd
+
+    with settings(lcd("here"), testval1="inner 1"):
+        eq_(env.testval1, "inner 1")
+        ok_(env.lcwd.endswith("here")) # Should be the side-effect of adding 
cd to settings
+
+    ok_(env.testval1, "outer 1")
+    eq_(env.lcwd, prev_lcwd)
+
+
+def test_settings_clean_revert():
+    """
+    settings(clean_revert=True) should only revert values matching input values
+    """
+    env.modified = "outer"
+    env.notmodified = "outer"
+    with settings(modified="inner", notmodified="inner", clean_revert=True):
+        eq_(env.modified, "inner")
+        eq_(env.notmodified, "inner")
+        env.modified = "modified internally"
+    eq_(env.modified, "modified internally")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Fabric-1.4.0/tests/test_decorators.py 
new/Fabric-1.4.1/tests/test_decorators.py
--- old/Fabric-1.4.0/tests/test_decorators.py   2012-02-14 06:52:54.000000000 
+0100
+++ new/Fabric-1.4.1/tests/test_decorators.py   2012-03-21 00:14:37.000000000 
+0100
@@ -10,6 +10,7 @@
 from fabric.state import env
 import fabric # for patching fabric.state.xxx
 from fabric.tasks import _parallel_tasks, requires_parallel
+from fabric.context_managers import lcd
 
 
 #
@@ -252,3 +253,24 @@
     decorated_task = decorators.with_settings(value=random_return)(some_task)
     ok_(some_task(), msg="sanity check")
     eq_(random_return, decorated_task())
+
+def test_with_settings_with_other_context_managers():
+    """
+    with_settings() should take other context managers, and use them with other
+    overrided key/value pairs.
+    """
+    env.testval1 = "outer 1"
+    prev_lcwd = env.lcwd
+
+    def some_task():
+        eq_(env.testval1, "inner 1")
+        ok_(env.lcwd.endswith("here")) # Should be the side-effect of adding 
cd to settings
+
+    decorated_task = decorators.with_settings(
+        lcd("here"),
+        testval1="inner 1"
+    )(some_task)
+    decorated_task()
+
+    ok_(env.testval1, "outer 1")
+    eq_(env.lcwd, prev_lcwd)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Fabric-1.4.0/tests/test_network.py 
new/Fabric-1.4.1/tests/test_network.py
--- old/Fabric-1.4.0/tests/test_network.py      2012-02-14 06:53:02.000000000 
+0100
+++ new/Fabric-1.4.1/tests/test_network.py      2012-04-05 06:03:05.000000000 
+0200
@@ -566,6 +566,7 @@
         Test-server connection using ssh_config values
         """
         with settings(
+            hide('everything'),
             ssh_config_path=support("testserver_ssh_config"),
             host_string='testserver',
         ):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Fabric-1.4.0/tests/test_tasks.py 
new/Fabric-1.4.1/tests/test_tasks.py
--- old/Fabric-1.4.0/tests/test_tasks.py        2012-02-14 06:53:02.000000000 
+0100
+++ new/Fabric-1.4.1/tests/test_tasks.py        2012-04-05 06:03:05.000000000 
+0200
@@ -401,3 +401,49 @@
             run = Fake(callable=True, expect_call=True)
         mytask = MyTask()
         execute(mytask)
+
+
+class TestExecuteEnvInteractions(FabricTest):
+    def set_network(self):
+        # Don't update env.host/host_string/etc
+        pass
+
+    @server(port=2200)
+    @server(port=2201)
+    def test_should_not_mutate_its_own_env_vars(self):
+        """
+        internal env changes should not bleed out, but task env changes should
+        """
+        # Task that uses a handful of features which involve env vars
+        @parallel
+        @hosts('[email protected]:2200', '[email protected]:2201')
+        def mytask():
+            run("ls /simple")
+        # Pre-assertions
+        assertions = {
+            'parallel': False,
+            'all_hosts': [],
+            'host': None,
+            'hosts': [],
+            'host_string': None
+        }
+        for key, value in assertions.items():
+            eq_(env[key], value)
+        # Run
+        with hide('everything'):
+            result = execute(mytask)
+        eq_(len(result), 2)
+        # Post-assertions
+        for key, value in assertions.items():
+            eq_(env[key], value)
+
+    @server()
+    def test_should_allow_task_to_modify_env_vars(self):
+        @hosts('[email protected]:2200')
+        def mytask():
+            run("ls /simple")
+            env.foo = "bar"
+        with hide('everything'):
+            execute(mytask)
+        eq_(env.foo, "bar")
+        eq_(env.host_string, None)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Fabric-1.4.0/tests/utils.py 
new/Fabric-1.4.1/tests/utils.py
--- old/Fabric-1.4.0/tests/utils.py     2012-02-14 06:53:02.000000000 +0100
+++ new/Fabric-1.4.1/tests/utils.py     2012-04-05 06:03:05.000000000 +0200
@@ -45,10 +45,13 @@
         # Temporary local file dir
         self.tmpdir = tempfile.mkdtemp()
 
+    def set_network(self):
+        env.update(to_dict('%s@%s:%s' % (USER, HOST, PORT)))
+
     def env_setup(self):
         # Set up default networking for test server
         env.disable_known_hosts = True
-        env.update(to_dict('%s@%s:%s' % (USER, HOST, PORT)))
+        self.set_network()
         env.password = PASSWORDS[USER]
         # Command response mocking is easier without having to account for
         # shell wrapping everywhere.

-- 
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to