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]
