Merge tag '1.10.0' into debian/liberty
oslo.concurrency 1.10.0 release
This commit is contained in:
10
README.rst
10
README.rst
@@ -2,7 +2,15 @@
|
||||
oslo.concurrency
|
||||
==================
|
||||
|
||||
Oslo concurrency library has utilities for safely running multi-thread,
|
||||
.. image:: https://pypip.in/version/oslo.concurrency/badge.svg
|
||||
:target: https://pypi.python.org/pypi/oslo.concurrency/
|
||||
:alt: Latest Version
|
||||
|
||||
.. image:: https://pypip.in/download/oslo.concurrency/badge.svg?period=month
|
||||
:target: https://pypi.python.org/pypi/oslo.concurrency/
|
||||
:alt: Downloads
|
||||
|
||||
The oslo.concurrency library has utilities for safely running multi-thread,
|
||||
multi-process applications using locking mechanisms and for running
|
||||
external processes.
|
||||
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
.. oslo.concurrency documentation master file, created by
|
||||
sphinx-quickstart on Tue Jul 9 22:26:36 2013.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
============================================
|
||||
Welcome to oslo.concurrency's documentation!
|
||||
============================================
|
||||
|
||||
==================
|
||||
oslo.concurrency
|
||||
==================
|
||||
The `oslo`_ concurrency library has utilities for safely running multi-thread,
|
||||
multi-process applications using locking mechanisms and for running
|
||||
external processes.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
readme
|
||||
installation
|
||||
usage
|
||||
contributing
|
||||
@@ -30,3 +28,5 @@ Indices and tables
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
||||
.. _oslo: https://wiki.openstack.org/wiki/Oslo
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
.. include:: ../../README.rst
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
# The list of modules to copy from oslo-incubator.git
|
||||
module = fileutils
|
||||
script = tools/run_cross_tests.sh
|
||||
|
||||
# The base module to hold the copy of openstack.common
|
||||
base=oslo.concurrency
|
||||
base=oslo_concurrency
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
# Translations template for oslo.concurrency.
|
||||
# Copyright (C) 2015 ORGANIZATION
|
||||
# This file is distributed under the same license as the oslo.concurrency
|
||||
# project.
|
||||
#
|
||||
# Translators:
|
||||
# Andi Chandler <andi@gowling.com>, 2014-2015
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: oslo.concurrency\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2015-05-28 06:05+0000\n"
|
||||
"PO-Revision-Date: 2015-03-24 01:20+0000\n"
|
||||
"Last-Translator: Andi Chandler <andi@gowling.com>\n"
|
||||
"Language-Team: English (United Kingdom) (http://www.transifex.com/projects/p/"
|
||||
"osloconcurrency/language/en_GB/)\n"
|
||||
"Language: en_GB\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 1.3\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#, python-format
|
||||
msgid "Could not close the acquired file handle `%s`"
|
||||
msgstr "Could not close the acquired file handle `%s`"
|
||||
|
||||
#, python-format
|
||||
msgid "Could not unlock the acquired lock `%s`"
|
||||
msgstr "Could not unlock the acquired lock `%s`"
|
||||
@@ -21,14 +21,10 @@ msgstr ""
|
||||
"Generated-By: Babel 1.3\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: oslo/concurrency/lockutils.py:84
|
||||
#: oslo/concurrency/openstack/common/lockutils.py:82
|
||||
#, python-format
|
||||
msgid "Created lock path: %s"
|
||||
msgstr "Created lock path: %s"
|
||||
|
||||
#: oslo/concurrency/lockutils.py:201
|
||||
#: oslo/concurrency/openstack/common/lockutils.py:251
|
||||
#, python-format
|
||||
msgid "Failed to remove file %(file)s"
|
||||
msgstr "Failed to remove file %(file)s"
|
||||
|
||||
@@ -1,79 +1,25 @@
|
||||
# English (United Kingdom) translations for oslo.concurrency.
|
||||
# Copyright (C) 2014 ORGANIZATION
|
||||
# Copyright (C) 2015 ORGANIZATION
|
||||
# This file is distributed under the same license as the oslo.concurrency
|
||||
# project.
|
||||
#
|
||||
# Translators:
|
||||
# Andi Chandler <andi@gowling.com>, 2014
|
||||
# Andi Chandler <andi@gowling.com>, 2014-2015
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: oslo.concurrency\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2014-10-29 06:10+0000\n"
|
||||
"PO-Revision-Date: 2014-10-28 20:48+0000\n"
|
||||
"Last-Translator: openstackjenkins <jenkins@openstack.org>\n"
|
||||
"Language-Team: English (United Kingdom) "
|
||||
"(http://www.transifex.com/projects/p/osloconcurrency/language/en_GB/)\n"
|
||||
"POT-Creation-Date: 2015-05-28 06:05+0000\n"
|
||||
"PO-Revision-Date: 2015-03-24 01:19+0000\n"
|
||||
"Last-Translator: Andi Chandler <andi@gowling.com>\n"
|
||||
"Language-Team: English (United Kingdom) (http://www.transifex.com/projects/p/"
|
||||
"osloconcurrency/language/en_GB/)\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 1.3\n"
|
||||
|
||||
#: oslo/concurrency/lockutils.py:120
|
||||
#, python-format
|
||||
msgid "Unable to acquire lock on `%(filename)s` due to %(exception)s"
|
||||
msgstr "Unable to acquire lock on `%(filename)s` due to %(exception)s"
|
||||
|
||||
#: oslo/concurrency/lockutils.py:134
|
||||
msgid "Unable to release an unacquired lock"
|
||||
msgstr ""
|
||||
|
||||
#: oslo/concurrency/lockutils.py:385
|
||||
msgid ""
|
||||
"Calling lockutils directly is no longer supported. Please use the "
|
||||
"lockutils-wrapper console script instead."
|
||||
msgstr ""
|
||||
|
||||
#: oslo/concurrency/processutils.py:69
|
||||
msgid "Unexpected error while running command."
|
||||
msgstr "Unexpected error while running command."
|
||||
|
||||
#: oslo/concurrency/processutils.py:72
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%(description)s\n"
|
||||
"Command: %(cmd)s\n"
|
||||
"Exit code: %(exit_code)s\n"
|
||||
"Stdout: %(stdout)r\n"
|
||||
"Stderr: %(stderr)r"
|
||||
msgstr ""
|
||||
"%(description)s\n"
|
||||
"Command: %(cmd)s\n"
|
||||
"Exit code: %(exit_code)s\n"
|
||||
"Stdout: %(stdout)r\n"
|
||||
"Stderr: %(stderr)r"
|
||||
|
||||
#: oslo/concurrency/processutils.py:171
|
||||
#, python-format
|
||||
msgid "Got unknown keyword args: %r"
|
||||
msgstr "Got unknown keyword args: %r"
|
||||
|
||||
#: oslo/concurrency/processutils.py:174
|
||||
#, python-format
|
||||
msgid "Got invalid arg log_errors: %r"
|
||||
msgstr ""
|
||||
|
||||
#: oslo/concurrency/processutils.py:180
|
||||
msgid "Command requested root, but did not specify a root helper."
|
||||
msgstr "Command requested root, but did not specify a root helper."
|
||||
|
||||
#: oslo/concurrency/processutils.py:191
|
||||
#, python-format
|
||||
msgid "Running cmd (subprocess): %s"
|
||||
msgstr "Running cmd (subprocess): %s"
|
||||
|
||||
#: oslo/concurrency/processutils.py:233
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%(desc)r\n"
|
||||
@@ -82,30 +28,78 @@ msgid ""
|
||||
"stdout: %(stdout)r\n"
|
||||
"stderr: %(stderr)r"
|
||||
msgstr ""
|
||||
"%(desc)r\n"
|
||||
"command: %(cmd)r\n"
|
||||
"exit code: %(code)r\n"
|
||||
"stdout: %(stdout)r\n"
|
||||
"stderr: %(stderr)r"
|
||||
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%(description)s\n"
|
||||
"Command: %(cmd)s\n"
|
||||
"Exit code: %(exit_code)s\n"
|
||||
"Stdout: %(stdout)r\n"
|
||||
"Stderr: %(stderr)r"
|
||||
msgstr ""
|
||||
"%(description)s\n"
|
||||
"Command: %(cmd)s\n"
|
||||
"Exit code: %(exit_code)s\n"
|
||||
"Stdout: %(stdout)r\n"
|
||||
"Stderr: %(stderr)r"
|
||||
|
||||
#, python-format
|
||||
msgid "%r failed. Not Retrying."
|
||||
msgstr "%r failed. Not Retrying."
|
||||
|
||||
#, python-format
|
||||
msgid "%r failed. Retrying."
|
||||
msgstr "%r failed. Retrying."
|
||||
|
||||
msgid ""
|
||||
"Calling lockutils directly is no longer supported. Please use the lockutils-"
|
||||
"wrapper console script instead."
|
||||
msgstr ""
|
||||
"Calling lockutils directly is no longer supported. Please use the lockutils-"
|
||||
"wrapper console script instead."
|
||||
|
||||
msgid "Command requested root, but did not specify a root helper."
|
||||
msgstr "Command requested root, but did not specify a root helper."
|
||||
|
||||
msgid "Environment not supported over SSH"
|
||||
msgstr "Environment not supported over SSH"
|
||||
|
||||
#: oslo/concurrency/processutils.py:242
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Got an OSError\n"
|
||||
"command: %(cmd)r\n"
|
||||
"errno: %(errno)r"
|
||||
msgstr ""
|
||||
"Got an OSError\n"
|
||||
"command: %(cmd)r\n"
|
||||
"errno: %(errno)r"
|
||||
|
||||
#: oslo/concurrency/processutils.py:248
|
||||
#, python-format
|
||||
msgid "%r failed. Not Retrying."
|
||||
msgstr ""
|
||||
msgid "Got invalid arg log_errors: %r"
|
||||
msgstr "Got invalid arg log_errors: %r"
|
||||
|
||||
#: oslo/concurrency/processutils.py:252
|
||||
#, python-format
|
||||
msgid "%r failed. Retrying."
|
||||
msgstr "%r failed. Retrying."
|
||||
msgid "Got unknown keyword args: %r"
|
||||
msgstr "Got unknown keyword args: %r"
|
||||
|
||||
#: oslo/concurrency/processutils.py:299
|
||||
msgid "Environment not supported over SSH"
|
||||
msgstr "Environment not supported over SSH"
|
||||
#, python-format
|
||||
msgid "Running cmd (subprocess): %s"
|
||||
msgstr "Running cmd (subprocess): %s"
|
||||
|
||||
#, python-format
|
||||
msgid "Unable to acquire lock on `%(filename)s` due to %(exception)s"
|
||||
msgstr "Unable to acquire lock on `%(filename)s` due to %(exception)s"
|
||||
|
||||
msgid "Unable to release an unacquired lock"
|
||||
msgstr "Unable to release an unacquired lock"
|
||||
|
||||
msgid "Unexpected error while running command."
|
||||
msgstr "Unexpected error while running command."
|
||||
|
||||
#: oslo/concurrency/processutils.py:303
|
||||
msgid "process_input not supported over SSH"
|
||||
msgstr "process_input not supported over SSH"
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: oslo.concurrency\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2015-03-09 06:08+0000\n"
|
||||
"POT-Creation-Date: 2015-05-28 06:05+0000\n"
|
||||
"PO-Revision-Date: 2015-03-08 16:34+0000\n"
|
||||
"Last-Translator: Maxime COQUEREL <max.coquerel@gmail.com>\n"
|
||||
"Language-Team: French (http://www.transifex.com/projects/p/osloconcurrency/"
|
||||
@@ -21,12 +21,10 @@ msgstr ""
|
||||
"Generated-By: Babel 1.3\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#: oslo_concurrency/lockutils.py:217
|
||||
#, python-format
|
||||
msgid "Could not unlock the acquired lock `%s`"
|
||||
msgstr "Impossible de libérer le verrou acquis %s"
|
||||
|
||||
#: oslo_concurrency/lockutils.py:223
|
||||
#, python-format
|
||||
msgid "Could not close the acquired file handle `%s`"
|
||||
msgstr "Impossible de libérer le descripteur de fichier %s"
|
||||
|
||||
#, python-format
|
||||
msgid "Could not unlock the acquired lock `%s`"
|
||||
msgstr "Impossible de libérer le verrou acquis %s"
|
||||
|
||||
@@ -21,12 +21,10 @@ msgstr ""
|
||||
"Generated-By: Babel 1.3\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#: oslo_concurrency/lockutils.py:181
|
||||
#, python-format
|
||||
msgid "Created lock path: %s"
|
||||
msgstr "Chemin de verrou créé %s"
|
||||
|
||||
#: oslo_concurrency/lockutils.py:332
|
||||
#, python-format
|
||||
msgid "Failed to remove file %(file)s"
|
||||
msgstr "Échec lors de la suppression du fichier %(file)s"
|
||||
|
||||
@@ -9,75 +9,17 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: oslo.concurrency\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2015-03-09 06:08+0000\n"
|
||||
"POT-Creation-Date: 2015-05-28 06:05+0000\n"
|
||||
"PO-Revision-Date: 2015-03-08 16:41+0000\n"
|
||||
"Last-Translator: Maxime COQUEREL <max.coquerel@gmail.com>\n"
|
||||
"Language-Team: French "
|
||||
"(http://www.transifex.com/projects/p/osloconcurrency/language/fr/)\n"
|
||||
"Language-Team: French (http://www.transifex.com/projects/p/osloconcurrency/"
|
||||
"language/fr/)\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 1.3\n"
|
||||
|
||||
#: oslo_concurrency/lockutils.py:111
|
||||
#, python-format
|
||||
msgid "Unable to acquire lock on `%(filename)s` due to %(exception)s"
|
||||
msgstr ""
|
||||
"Impossible d'acquérir le verrou sur `%(filename)s` à cause de "
|
||||
"%(exception)s"
|
||||
|
||||
#: oslo_concurrency/lockutils.py:208
|
||||
msgid "Unable to release an unacquired lock"
|
||||
msgstr "Impossible de libérer le verrou acquis %s"
|
||||
|
||||
#: oslo_concurrency/lockutils.py:671
|
||||
msgid ""
|
||||
"Calling lockutils directly is no longer supported. Please use the "
|
||||
"lockutils-wrapper console script instead."
|
||||
msgstr ""
|
||||
"Lockutils appelant directement n'est plus pris en charge. Merci "
|
||||
"d'utiliser le script de la console lockutils -wrapper à la place."
|
||||
|
||||
#: oslo_concurrency/processutils.py:69
|
||||
msgid "Unexpected error while running command."
|
||||
msgstr "Erreur inattendue lors de l’exécution de la commande."
|
||||
|
||||
#: oslo_concurrency/processutils.py:72
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%(description)s\n"
|
||||
"Command: %(cmd)s\n"
|
||||
"Exit code: %(exit_code)s\n"
|
||||
"Stdout: %(stdout)r\n"
|
||||
"Stderr: %(stderr)r"
|
||||
msgstr ""
|
||||
"%(description)s\n"
|
||||
"Commande: %(cmd)s\n"
|
||||
"Code de sortie: %(exit_code)s\n"
|
||||
"Stdout: %(stdout)r\n"
|
||||
"Stderr: %(stderr)r"
|
||||
|
||||
#: oslo_concurrency/processutils.py:174
|
||||
#, python-format
|
||||
msgid "Got unknown keyword args: %r"
|
||||
msgstr "Ags, mot clé inconnu: %r"
|
||||
|
||||
#: oslo_concurrency/processutils.py:177
|
||||
#, python-format
|
||||
msgid "Got invalid arg log_errors: %r"
|
||||
msgstr "Argument reçu non valide log_errors: %r"
|
||||
|
||||
#: oslo_concurrency/processutils.py:183
|
||||
msgid "Command requested root, but did not specify a root helper."
|
||||
msgstr "La commande exigeait root, mais n'indiquait pas comment obtenir root."
|
||||
|
||||
#: oslo_concurrency/processutils.py:199
|
||||
#, python-format
|
||||
msgid "Running cmd (subprocess): %s"
|
||||
msgstr "Exécution de la commande (sous-processus): %s"
|
||||
|
||||
#: oslo_concurrency/processutils.py:242
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%(desc)r\n"
|
||||
@@ -92,7 +34,41 @@ msgstr ""
|
||||
"stdout: %(stdout)r\n"
|
||||
"stderr: %(stderr)r"
|
||||
|
||||
#: oslo_concurrency/processutils.py:251
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%(description)s\n"
|
||||
"Command: %(cmd)s\n"
|
||||
"Exit code: %(exit_code)s\n"
|
||||
"Stdout: %(stdout)r\n"
|
||||
"Stderr: %(stderr)r"
|
||||
msgstr ""
|
||||
"%(description)s\n"
|
||||
"Commande: %(cmd)s\n"
|
||||
"Code de sortie: %(exit_code)s\n"
|
||||
"Stdout: %(stdout)r\n"
|
||||
"Stderr: %(stderr)r"
|
||||
|
||||
#, python-format
|
||||
msgid "%r failed. Not Retrying."
|
||||
msgstr "Echec de %r. Nouvelle tentative."
|
||||
|
||||
#, python-format
|
||||
msgid "%r failed. Retrying."
|
||||
msgstr "Echec de %r. Nouvelle tentative."
|
||||
|
||||
msgid ""
|
||||
"Calling lockutils directly is no longer supported. Please use the lockutils-"
|
||||
"wrapper console script instead."
|
||||
msgstr ""
|
||||
"Lockutils appelant directement n'est plus pris en charge. Merci d'utiliser "
|
||||
"le script de la console lockutils -wrapper à la place."
|
||||
|
||||
msgid "Command requested root, but did not specify a root helper."
|
||||
msgstr "La commande exigeait root, mais n'indiquait pas comment obtenir root."
|
||||
|
||||
msgid "Environment not supported over SSH"
|
||||
msgstr "Environnement non prise en charge sur SSH"
|
||||
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Got an OSError\n"
|
||||
@@ -103,21 +79,28 @@ msgstr ""
|
||||
"commande: %(cmd)r\n"
|
||||
"errno: %(errno)r"
|
||||
|
||||
#: oslo_concurrency/processutils.py:257
|
||||
#, python-format
|
||||
msgid "%r failed. Not Retrying."
|
||||
msgstr "Echec de %r. Nouvelle tentative."
|
||||
msgid "Got invalid arg log_errors: %r"
|
||||
msgstr "Argument reçu non valide log_errors: %r"
|
||||
|
||||
#: oslo_concurrency/processutils.py:261
|
||||
#, python-format
|
||||
msgid "%r failed. Retrying."
|
||||
msgstr "Echec de %r. Nouvelle tentative."
|
||||
msgid "Got unknown keyword args: %r"
|
||||
msgstr "Ags, mot clé inconnu: %r"
|
||||
|
||||
#: oslo_concurrency/processutils.py:308
|
||||
msgid "Environment not supported over SSH"
|
||||
msgstr "Environnement non prise en charge sur SSH"
|
||||
#, python-format
|
||||
msgid "Running cmd (subprocess): %s"
|
||||
msgstr "Exécution de la commande (sous-processus): %s"
|
||||
|
||||
#, python-format
|
||||
msgid "Unable to acquire lock on `%(filename)s` due to %(exception)s"
|
||||
msgstr ""
|
||||
"Impossible d'acquérir le verrou sur `%(filename)s` à cause de %(exception)s"
|
||||
|
||||
msgid "Unable to release an unacquired lock"
|
||||
msgstr "Impossible de libérer le verrou acquis %s"
|
||||
|
||||
msgid "Unexpected error while running command."
|
||||
msgstr "Erreur inattendue lors de l’exécution de la commande."
|
||||
|
||||
#: oslo_concurrency/processutils.py:312
|
||||
msgid "process_input not supported over SSH"
|
||||
msgstr "process_input non pris en charge sur SSH"
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import contextlib
|
||||
import errno
|
||||
import logging
|
||||
import os
|
||||
import stat
|
||||
import tempfile
|
||||
|
||||
from oslo_utils import excutils
|
||||
@@ -24,15 +25,17 @@ from oslo_utils import excutils
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
_FILE_CACHE = {}
|
||||
DEFAULT_MODE = stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO
|
||||
|
||||
|
||||
def ensure_tree(path):
|
||||
def ensure_tree(path, mode=DEFAULT_MODE):
|
||||
"""Create a directory (and any ancestor directories required)
|
||||
|
||||
:param path: Directory to create
|
||||
:param mode: Directory creation permissions
|
||||
"""
|
||||
try:
|
||||
os.makedirs(path)
|
||||
os.makedirs(path, mode)
|
||||
except OSError as exc:
|
||||
if exc.errno == errno.EEXIST:
|
||||
if not os.path.isdir(path):
|
||||
@@ -58,7 +61,7 @@ def read_cached_file(filename, force_reload=False):
|
||||
cache_info = _FILE_CACHE.setdefault(filename, {})
|
||||
|
||||
if not cache_info or mtime > cache_info.get('mtime', 0):
|
||||
LOG.debug("Reloading cached file %s" % filename)
|
||||
LOG.debug("Reloading cached file %s", filename)
|
||||
with open(filename) as fap:
|
||||
cache_info['data'] = fap.read()
|
||||
cache_info['mtime'] = mtime
|
||||
|
||||
@@ -144,6 +144,9 @@ def execute(*cmd, **kwargs):
|
||||
last attempt, and LOG_ALL_ERRORS requires
|
||||
logging on each occurence of an error.
|
||||
:type log_errors: integer.
|
||||
:param binary: On Python 3, return stdout and stderr as bytes if
|
||||
binary is True, as Unicode otherwise.
|
||||
:type binary: boolean
|
||||
:returns: (stdout, stderr) from process execution
|
||||
:raises: :class:`UnknownArgumentError` on
|
||||
receiving unknown arguments
|
||||
@@ -163,6 +166,7 @@ def execute(*cmd, **kwargs):
|
||||
shell = kwargs.pop('shell', False)
|
||||
loglevel = kwargs.pop('loglevel', logging.DEBUG)
|
||||
log_errors = kwargs.pop('log_errors', None)
|
||||
binary = kwargs.pop('binary', False)
|
||||
|
||||
if isinstance(check_exit_code, bool):
|
||||
ignore_exit_code = not check_exit_code
|
||||
@@ -225,13 +229,24 @@ def execute(*cmd, **kwargs):
|
||||
(sanitized_cmd, _returncode, end_time))
|
||||
if not ignore_exit_code and _returncode not in check_exit_code:
|
||||
(stdout, stderr) = result
|
||||
if six.PY3:
|
||||
stdout = os.fsdecode(stdout)
|
||||
stderr = os.fsdecode(stderr)
|
||||
sanitized_stdout = strutils.mask_password(stdout)
|
||||
sanitized_stderr = strutils.mask_password(stderr)
|
||||
raise ProcessExecutionError(exit_code=_returncode,
|
||||
stdout=sanitized_stdout,
|
||||
stderr=sanitized_stderr,
|
||||
cmd=sanitized_cmd)
|
||||
return result
|
||||
if six.PY3 and not binary and result is not None:
|
||||
(stdout, stderr) = result
|
||||
# Decode from the locale using using the surrogateescape error
|
||||
# handler (decoding cannot fail)
|
||||
stdout = os.fsdecode(stdout)
|
||||
stderr = os.fsdecode(stderr)
|
||||
return (stdout, stderr)
|
||||
else:
|
||||
return result
|
||||
|
||||
except (ProcessExecutionError, OSError) as err:
|
||||
# if we want to always log the errors or if this is
|
||||
@@ -301,7 +316,8 @@ def trycmd(*args, **kwargs):
|
||||
|
||||
|
||||
def ssh_execute(ssh, cmd, process_input=None,
|
||||
addl_env=None, check_exit_code=True):
|
||||
addl_env=None, check_exit_code=True,
|
||||
binary=False):
|
||||
sanitized_cmd = strutils.mask_password(cmd)
|
||||
LOG.debug('Running cmd (SSH): %s', sanitized_cmd)
|
||||
if addl_env:
|
||||
@@ -317,24 +333,46 @@ def ssh_execute(ssh, cmd, process_input=None,
|
||||
# NOTE(justinsb): This seems suspicious...
|
||||
# ...other SSH clients have buffering issues with this approach
|
||||
stdout = stdout_stream.read()
|
||||
sanitized_stdout = strutils.mask_password(stdout)
|
||||
stderr = stderr_stream.read()
|
||||
sanitized_stderr = strutils.mask_password(stderr)
|
||||
|
||||
stdin_stream.close()
|
||||
|
||||
exit_status = channel.recv_exit_status()
|
||||
|
||||
if six.PY3:
|
||||
# Decode from the locale using using the surrogateescape error handler
|
||||
# (decoding cannot fail). Decode even if binary is True because
|
||||
# mask_password() requires Unicode on Python 3
|
||||
stdout = os.fsdecode(stdout)
|
||||
stderr = os.fsdecode(stderr)
|
||||
stdout = strutils.mask_password(stdout)
|
||||
stderr = strutils.mask_password(stderr)
|
||||
|
||||
# exit_status == -1 if no exit code was returned
|
||||
if exit_status != -1:
|
||||
LOG.debug('Result was %s' % exit_status)
|
||||
if check_exit_code and exit_status != 0:
|
||||
raise ProcessExecutionError(exit_code=exit_status,
|
||||
stdout=sanitized_stdout,
|
||||
stderr=sanitized_stderr,
|
||||
stdout=stdout,
|
||||
stderr=stderr,
|
||||
cmd=sanitized_cmd)
|
||||
|
||||
return (sanitized_stdout, sanitized_stderr)
|
||||
if binary:
|
||||
if six.PY2:
|
||||
# On Python 2, stdout is a bytes string if mask_password() failed
|
||||
# to decode it, or an Unicode string otherwise. Encode to the
|
||||
# default encoding (ASCII) because mask_password() decodes from
|
||||
# the same encoding.
|
||||
if isinstance(stdout, unicode):
|
||||
stdout = stdout.encode()
|
||||
if isinstance(stderr, unicode):
|
||||
stderr = stderr.encode()
|
||||
else:
|
||||
# fsencode() is the reverse operation of fsdecode()
|
||||
stdout = os.fsencode(stdout)
|
||||
stderr = os.fsencode(stderr)
|
||||
|
||||
return (stdout, stderr)
|
||||
|
||||
|
||||
def get_worker_count():
|
||||
|
||||
@@ -20,6 +20,7 @@ import logging
|
||||
import multiprocessing
|
||||
import os
|
||||
import stat
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
import fixtures
|
||||
@@ -29,6 +30,8 @@ import six
|
||||
|
||||
from oslo_concurrency import processutils
|
||||
from oslotest import mockpatch
|
||||
|
||||
|
||||
PROCESS_EXECUTION_ERROR_LOGGING_TEST = """#!/bin/bash
|
||||
exit 41"""
|
||||
|
||||
@@ -40,6 +43,9 @@ echo onstdout --password='"secret"'
|
||||
echo onstderr --password='"secret"' 1>&2
|
||||
exit 38"""
|
||||
|
||||
# This byte sequence is undecodable from most encoding
|
||||
UNDECODABLE_BYTES = b'[a\x80\xe9\xff]'
|
||||
|
||||
|
||||
class UtilsTest(test_base.BaseTestCase):
|
||||
# NOTE(jkoelker) Moar tests from nova need to be ported. But they
|
||||
@@ -173,7 +179,7 @@ exit 1
|
||||
out, err = processutils.execute('/usr/bin/env',
|
||||
'sh', '-c', 'pwd',
|
||||
cwd=tmpdir)
|
||||
self.assertIn(six.b(tmpdir), out)
|
||||
self.assertIn(tmpdir, out)
|
||||
|
||||
def test_check_exit_code_list(self):
|
||||
processutils.execute('/usr/bin/env', 'sh', '-c', 'exit 101',
|
||||
@@ -301,6 +307,19 @@ grep foo
|
||||
env_vars = {'SUPER_UNIQUE_VAR': 'The answer is 42'}
|
||||
|
||||
out, err = processutils.execute('/usr/bin/env', env_variables=env_vars)
|
||||
self.assertIsInstance(out, str)
|
||||
self.assertIsInstance(err, str)
|
||||
|
||||
self.assertIn('SUPER_UNIQUE_VAR=The answer is 42', out)
|
||||
|
||||
def test_binary(self):
|
||||
env_vars = {'SUPER_UNIQUE_VAR': 'The answer is 42'}
|
||||
|
||||
out, err = processutils.execute('/usr/bin/env',
|
||||
env_variables=env_vars,
|
||||
binary=True)
|
||||
self.assertIsInstance(out, bytes)
|
||||
self.assertIsInstance(err, bytes)
|
||||
|
||||
self.assertIn(b'SUPER_UNIQUE_VAR=The answer is 42', out)
|
||||
|
||||
@@ -321,6 +340,8 @@ grep foo
|
||||
'something')
|
||||
|
||||
self.assertEqual(38, err.exit_code)
|
||||
self.assertIsInstance(err.stdout, six.text_type)
|
||||
self.assertIsInstance(err.stderr, six.text_type)
|
||||
self.assertIn('onstdout --password="***"', err.stdout)
|
||||
self.assertIn('onstderr --password="***"', err.stderr)
|
||||
self.assertEqual(err.cmd, ' '.join([tmpfilename,
|
||||
@@ -328,6 +349,72 @@ grep foo
|
||||
'something']))
|
||||
self.assertNotIn('secret', str(err))
|
||||
|
||||
def execute_undecodable_bytes(self, out_bytes, err_bytes,
|
||||
exitcode=0, binary=False):
|
||||
if six.PY3:
|
||||
code = ';'.join(('import sys',
|
||||
'sys.stdout.buffer.write(%a)' % out_bytes,
|
||||
'sys.stdout.flush()',
|
||||
'sys.stderr.buffer.write(%a)' % err_bytes,
|
||||
'sys.stderr.flush()',
|
||||
'sys.exit(%s)' % exitcode))
|
||||
else:
|
||||
code = ';'.join(('import sys',
|
||||
'sys.stdout.write(%r)' % out_bytes,
|
||||
'sys.stdout.flush()',
|
||||
'sys.stderr.write(%r)' % err_bytes,
|
||||
'sys.stderr.flush()',
|
||||
'sys.exit(%s)' % exitcode))
|
||||
|
||||
return processutils.execute(sys.executable, '-c', code, binary=binary)
|
||||
|
||||
def check_undecodable_bytes(self, binary):
|
||||
out_bytes = b'out: ' + UNDECODABLE_BYTES
|
||||
err_bytes = b'err: ' + UNDECODABLE_BYTES
|
||||
out, err = self.execute_undecodable_bytes(out_bytes, err_bytes,
|
||||
binary=binary)
|
||||
if six.PY3 and not binary:
|
||||
self.assertEqual(out, os.fsdecode(out_bytes))
|
||||
self.assertEqual(err, os.fsdecode(err_bytes))
|
||||
else:
|
||||
self.assertEqual(out, out_bytes)
|
||||
self.assertEqual(err, err_bytes)
|
||||
|
||||
def test_undecodable_bytes(self):
|
||||
self.check_undecodable_bytes(False)
|
||||
|
||||
def test_binary_undecodable_bytes(self):
|
||||
self.check_undecodable_bytes(True)
|
||||
|
||||
def check_undecodable_bytes_error(self, binary):
|
||||
out_bytes = b'out: password="secret1" ' + UNDECODABLE_BYTES
|
||||
err_bytes = b'err: password="secret2" ' + UNDECODABLE_BYTES
|
||||
exc = self.assertRaises(processutils.ProcessExecutionError,
|
||||
self.execute_undecodable_bytes,
|
||||
out_bytes, err_bytes, exitcode=1,
|
||||
binary=binary)
|
||||
|
||||
out = exc.stdout
|
||||
err = exc.stderr
|
||||
out_bytes = b'out: password="***" ' + UNDECODABLE_BYTES
|
||||
err_bytes = b'err: password="***" ' + UNDECODABLE_BYTES
|
||||
if six.PY3:
|
||||
# On Python 3, stdout and stderr attributes of
|
||||
# ProcessExecutionError must always be Unicode
|
||||
self.assertEqual(out, os.fsdecode(out_bytes))
|
||||
self.assertEqual(err, os.fsdecode(err_bytes))
|
||||
else:
|
||||
# On Python 2, stdout and stderr attributes of
|
||||
# ProcessExecutionError must always be bytes
|
||||
self.assertEqual(out, out_bytes)
|
||||
self.assertEqual(err, err_bytes)
|
||||
|
||||
def test_undecodable_bytes_error(self):
|
||||
self.check_undecodable_bytes_error(False)
|
||||
|
||||
def test_binary_undecodable_bytes_error(self):
|
||||
self.check_undecodable_bytes_error(True)
|
||||
|
||||
|
||||
class ProcessExecutionErrorLoggingTest(test_base.BaseTestCase):
|
||||
def setUp(self):
|
||||
@@ -433,21 +520,23 @@ class FakeSshChannel(object):
|
||||
return self.rc
|
||||
|
||||
|
||||
class FakeSshStream(six.StringIO):
|
||||
class FakeSshStream(six.BytesIO):
|
||||
def setup_channel(self, rc):
|
||||
self.channel = FakeSshChannel(rc)
|
||||
|
||||
|
||||
class FakeSshConnection(object):
|
||||
def __init__(self, rc):
|
||||
def __init__(self, rc, out=b'stdout', err=b'stderr'):
|
||||
self.rc = rc
|
||||
self.out = out
|
||||
self.err = err
|
||||
|
||||
def exec_command(self, cmd):
|
||||
stdout = FakeSshStream('stdout')
|
||||
stdout = FakeSshStream(self.out)
|
||||
stdout.setup_channel(self.rc)
|
||||
return (six.StringIO(),
|
||||
return (six.BytesIO(),
|
||||
stdout,
|
||||
six.StringIO('stderr'))
|
||||
six.BytesIO(self.err))
|
||||
|
||||
|
||||
class SshExecuteTestCase(test_base.BaseTestCase):
|
||||
@@ -462,9 +551,70 @@ class SshExecuteTestCase(test_base.BaseTestCase):
|
||||
None, 'ls', process_input='important')
|
||||
|
||||
def test_works(self):
|
||||
o, e = processutils.ssh_execute(FakeSshConnection(0), 'ls')
|
||||
self.assertEqual('stdout', o)
|
||||
self.assertEqual('stderr', e)
|
||||
out, err = processutils.ssh_execute(FakeSshConnection(0), 'ls')
|
||||
self.assertEqual('stdout', out)
|
||||
self.assertEqual('stderr', err)
|
||||
self.assertIsInstance(out, six.text_type)
|
||||
self.assertIsInstance(err, six.text_type)
|
||||
|
||||
def test_binary(self):
|
||||
o, e = processutils.ssh_execute(FakeSshConnection(0), 'ls',
|
||||
binary=True)
|
||||
self.assertEqual(b'stdout', o)
|
||||
self.assertEqual(b'stderr', e)
|
||||
self.assertIsInstance(o, bytes)
|
||||
self.assertIsInstance(e, bytes)
|
||||
|
||||
def check_undecodable_bytes(self, binary):
|
||||
out_bytes = b'out: ' + UNDECODABLE_BYTES
|
||||
err_bytes = b'err: ' + UNDECODABLE_BYTES
|
||||
conn = FakeSshConnection(0, out=out_bytes, err=err_bytes)
|
||||
|
||||
out, err = processutils.ssh_execute(conn, 'ls', binary=binary)
|
||||
if six.PY3 and not binary:
|
||||
self.assertEqual(out, os.fsdecode(out_bytes))
|
||||
self.assertEqual(err, os.fsdecode(err_bytes))
|
||||
else:
|
||||
self.assertEqual(out, out_bytes)
|
||||
self.assertEqual(err, err_bytes)
|
||||
|
||||
def test_undecodable_bytes(self):
|
||||
self.check_undecodable_bytes(False)
|
||||
|
||||
def test_binary_undecodable_bytes(self):
|
||||
self.check_undecodable_bytes(True)
|
||||
|
||||
def check_undecodable_bytes_error(self, binary):
|
||||
out_bytes = b'out: password="secret1" ' + UNDECODABLE_BYTES
|
||||
err_bytes = b'err: password="secret2" ' + UNDECODABLE_BYTES
|
||||
conn = FakeSshConnection(1, out=out_bytes, err=err_bytes)
|
||||
|
||||
out_bytes = b'out: password="***" ' + UNDECODABLE_BYTES
|
||||
err_bytes = b'err: password="***" ' + UNDECODABLE_BYTES
|
||||
|
||||
exc = self.assertRaises(processutils.ProcessExecutionError,
|
||||
processutils.ssh_execute,
|
||||
conn, 'ls',
|
||||
binary=binary, check_exit_code=True)
|
||||
|
||||
out = exc.stdout
|
||||
err = exc.stderr
|
||||
if six.PY3:
|
||||
# On Python 3, stdout and stderr attributes of
|
||||
# ProcessExecutionError must always be Unicode
|
||||
self.assertEqual(out, os.fsdecode(out_bytes))
|
||||
self.assertEqual(err, os.fsdecode(err_bytes))
|
||||
else:
|
||||
# On Python 2, stdout and stderr attributes of
|
||||
# ProcessExecutionError must always be bytes
|
||||
self.assertEqual(out, out_bytes)
|
||||
self.assertEqual(err, err_bytes)
|
||||
|
||||
def test_undecodable_bytes_error(self):
|
||||
self.check_undecodable_bytes_error(False)
|
||||
|
||||
def test_binary_undecodable_bytes_error(self):
|
||||
self.check_undecodable_bytes_error(True)
|
||||
|
||||
def test_fails(self):
|
||||
self.assertRaises(processutils.ProcessExecutionError,
|
||||
@@ -472,13 +622,13 @@ class SshExecuteTestCase(test_base.BaseTestCase):
|
||||
|
||||
def _test_compromising_ssh(self, rc, check):
|
||||
fixture = self.useFixture(fixtures.FakeLogger(level=logging.DEBUG))
|
||||
fake_stdin = six.StringIO()
|
||||
fake_stdin = six.BytesIO()
|
||||
|
||||
fake_stdout = mock.Mock()
|
||||
fake_stdout.channel.recv_exit_status.return_value = rc
|
||||
fake_stdout.read.return_value = 'password="secret"'
|
||||
fake_stdout.read.return_value = b'password="secret"'
|
||||
|
||||
fake_stderr = six.StringIO('password="foobar"')
|
||||
fake_stderr = six.BytesIO(b'password="foobar"')
|
||||
|
||||
command = 'ls --password="bar"'
|
||||
|
||||
|
||||
@@ -2,13 +2,12 @@
|
||||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
|
||||
pbr>=0.6,!=0.7,<1.0
|
||||
pbr>=0.11,<2.0
|
||||
Babel>=1.3
|
||||
iso8601>=0.1.9
|
||||
fixtures>=0.3.14
|
||||
oslo.config>=1.9.0 # Apache-2.0
|
||||
oslo.i18n>=1.3.0 # Apache-2.0
|
||||
oslo.utils>=1.2.0 # Apache-2.0
|
||||
oslo.config>=1.11.0 # Apache-2.0
|
||||
oslo.i18n>=1.5.0 # Apache-2.0
|
||||
oslo.utils>=1.4.0 # Apache-2.0
|
||||
posix_ipc
|
||||
six>=1.9.0
|
||||
retrying>=1.2.3,!=1.3.0 # Apache-2.0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[metadata]
|
||||
name = oslo.concurrency
|
||||
summary = oslo.concurrency library
|
||||
summary = Oslo Concurrency library
|
||||
description-file =
|
||||
README.rst
|
||||
author = OpenStack
|
||||
@@ -17,7 +17,7 @@ classifier =
|
||||
Programming Language :: Python :: 2.7
|
||||
Programming Language :: Python :: 2.6
|
||||
Programming Language :: Python :: 3
|
||||
Programming Language :: Python :: 3.3
|
||||
Programming Language :: Python :: 3.4
|
||||
|
||||
[files]
|
||||
packages =
|
||||
|
||||
@@ -3,12 +3,13 @@
|
||||
# process, which may cause wedges in the gate later.
|
||||
|
||||
hacking>=0.10.0,<0.11
|
||||
oslotest>=1.2.0 # Apache-2.0
|
||||
oslotest>=1.5.1 # Apache-2.0
|
||||
coverage>=3.6
|
||||
futures>=2.1.6
|
||||
futures>=3.0
|
||||
fixtures>=0.3.14
|
||||
|
||||
# These are needed for docs generation
|
||||
oslosphinx>=2.2.0 # Apache-2.0
|
||||
oslosphinx>=2.5.0 # Apache-2.0
|
||||
sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3
|
||||
|
||||
eventlet>=0.16.1
|
||||
eventlet>=0.17.3
|
||||
|
||||
@@ -295,17 +295,22 @@ grep foo
|
||||
env_vars = {'SUPER_UNIQUE_VAR': 'The answer is 42'}
|
||||
|
||||
out, err = processutils.execute('/usr/bin/env', env_variables=env_vars)
|
||||
self.assertEqual(type(out), str)
|
||||
self.assertEqual(type(err), str)
|
||||
|
||||
self.assertIn(b'SUPER_UNIQUE_VAR=The answer is 42', out)
|
||||
self.assertIn('SUPER_UNIQUE_VAR=The answer is 42', out)
|
||||
|
||||
def test_as_root(self):
|
||||
out, err = processutils.execute('a', 'b', 'c', run_as_root=True,
|
||||
root_helper='echo')
|
||||
# For the following two tests: processutils.execute() does not
|
||||
# prepend the root_helper if we are already running with root privs,
|
||||
# so add it as the first argument to be certain.
|
||||
out, err = processutils.execute('echo', 'a', 'b', 'c',
|
||||
run_as_root=True, root_helper='echo')
|
||||
|
||||
self.assertIn('a b c', six.text_type(out))
|
||||
|
||||
def test_as_root_via_shell(self):
|
||||
out, err = processutils.execute('a b c', run_as_root=True,
|
||||
out, err = processutils.execute('echo a b c', run_as_root=True,
|
||||
root_helper='echo', shell=True)
|
||||
|
||||
self.assertIn('a b c', six.text_type(out))
|
||||
@@ -327,6 +332,8 @@ grep foo
|
||||
'something')
|
||||
|
||||
self.assertEqual(38, err.exit_code)
|
||||
self.assertEqual(type(err.stdout), six.text_type)
|
||||
self.assertEqual(type(err.stderr), six.text_type)
|
||||
self.assertIn('onstdout --password="***"', err.stdout)
|
||||
self.assertIn('onstderr --password="***"', err.stderr)
|
||||
self.assertEqual(err.cmd, ' '.join([tmpfilename,
|
||||
@@ -439,7 +446,7 @@ class FakeSshChannel(object):
|
||||
return self.rc
|
||||
|
||||
|
||||
class FakeSshStream(six.StringIO):
|
||||
class FakeSshStream(six.BytesIO):
|
||||
def setup_channel(self, rc):
|
||||
self.channel = FakeSshChannel(rc)
|
||||
|
||||
@@ -449,11 +456,11 @@ class FakeSshConnection(object):
|
||||
self.rc = rc
|
||||
|
||||
def exec_command(self, cmd):
|
||||
stdout = FakeSshStream('stdout')
|
||||
stdout = FakeSshStream(b'stdout')
|
||||
stdout.setup_channel(self.rc)
|
||||
return (six.StringIO(),
|
||||
return (six.BytesIO(),
|
||||
stdout,
|
||||
six.StringIO('stderr'))
|
||||
six.BytesIO(b'stderr'))
|
||||
|
||||
|
||||
class SshExecuteTestCase(test_base.BaseTestCase):
|
||||
@@ -471,6 +478,8 @@ class SshExecuteTestCase(test_base.BaseTestCase):
|
||||
o, e = processutils.ssh_execute(FakeSshConnection(0), 'ls')
|
||||
self.assertEqual('stdout', o)
|
||||
self.assertEqual('stderr', e)
|
||||
self.assertEqual(type(o), six.text_type)
|
||||
self.assertEqual(type(e), six.text_type)
|
||||
|
||||
def test_fails(self):
|
||||
self.assertRaises(processutils.ProcessExecutionError,
|
||||
@@ -478,13 +487,13 @@ class SshExecuteTestCase(test_base.BaseTestCase):
|
||||
|
||||
def _test_compromising_ssh(self, rc, check):
|
||||
fixture = self.useFixture(fixtures.FakeLogger(level=logging.DEBUG))
|
||||
fake_stdin = six.StringIO()
|
||||
fake_stdin = six.BytesIO()
|
||||
|
||||
fake_stdout = mock.Mock()
|
||||
fake_stdout.channel.recv_exit_status.return_value = rc
|
||||
fake_stdout.read.return_value = 'password="secret"'
|
||||
fake_stdout.read.return_value = b'password="secret"'
|
||||
|
||||
fake_stderr = six.StringIO('password="foobar"')
|
||||
fake_stderr = six.BytesIO(b'password="foobar"')
|
||||
|
||||
command = 'ls --password="bar"'
|
||||
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Run cross-project tests
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# run_cross_tests.sh project_dir venv
|
||||
|
||||
# Fail the build if any command fails
|
||||
set -e
|
||||
|
||||
project_dir="$1"
|
||||
venv="$2"
|
||||
|
||||
if [ -z "$project_dir" -o -z "$venv" ]
|
||||
then
|
||||
cat - <<EOF
|
||||
ERROR: Missing argument(s)
|
||||
|
||||
Usage:
|
||||
|
||||
$0 PROJECT_DIR VIRTUAL_ENV
|
||||
|
||||
Example, run the python 2.7 tests for python-neutronclient:
|
||||
|
||||
$0 /opt/stack/python-neutronclient py27
|
||||
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Set up the virtualenv without running the tests
|
||||
(cd $project_dir && tox --notest -e $venv)
|
||||
|
||||
tox_envbin=$project_dir/.tox/$venv/bin
|
||||
|
||||
our_name=$(python setup.py --name)
|
||||
|
||||
# Replace the pip-installed package with the version in our source
|
||||
# tree. Look to see if we are already installed before trying to
|
||||
# uninstall ourselves, to avoid failures from packages that do not use us
|
||||
# yet.
|
||||
if $tox_envbin/pip freeze | grep -q $our_name
|
||||
then
|
||||
$tox_envbin/pip uninstall -y $our_name
|
||||
fi
|
||||
$tox_envbin/pip install -U .
|
||||
|
||||
# Run the tests
|
||||
(cd $project_dir && tox -e $venv)
|
||||
result=$?
|
||||
|
||||
|
||||
# The below checks are modified from
|
||||
# openstack-infra/config/modules/jenkins/files/slave_scripts/run-unittests.sh.
|
||||
|
||||
# They expect to be run in the project being tested.
|
||||
cd $project_dir
|
||||
|
||||
echo "Begin pip freeze output from test virtualenv:"
|
||||
echo "======================================================================"
|
||||
.tox/$venv/bin/pip freeze
|
||||
echo "======================================================================"
|
||||
|
||||
# We only want to run the next check if the tool is installed, so look
|
||||
# for it before continuing.
|
||||
if [ -f /usr/local/jenkins/slave_scripts/subunit2html.py -a -d ".testrepository" ] ; then
|
||||
if [ -f ".testrepository/0.2" ] ; then
|
||||
cp .testrepository/0.2 ./subunit_log.txt
|
||||
elif [ -f ".testrepository/0" ] ; then
|
||||
.tox/$venv/bin/subunit-1to2 < .testrepository/0 > ./subunit_log.txt
|
||||
fi
|
||||
.tox/$venv/bin/python /usr/local/jenkins/slave_scripts/subunit2html.py ./subunit_log.txt testr_results.html
|
||||
gzip -9 ./subunit_log.txt
|
||||
gzip -9 ./testr_results.html
|
||||
|
||||
export PYTHON=.tox/$venv/bin/python
|
||||
set -e
|
||||
rancount=$(.tox/$venv/bin/testr last | sed -ne 's/Ran \([0-9]\+\).*tests in.*/\1/p')
|
||||
if [ "$rancount" -eq "0" ] ; then
|
||||
echo
|
||||
echo "Zero tests were run. At least one test should have been run."
|
||||
echo "Failing this test as a result"
|
||||
echo
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# If we make it this far, report status based on the tests that were
|
||||
# run.
|
||||
exit $result
|
||||
4
tox.ini
4
tox.ini
@@ -19,10 +19,6 @@ commands =
|
||||
lockutils-wrapper python setup.py testr --slowest --testr-args='{posargs}'
|
||||
env TEST_EVENTLET=1 lockutils-wrapper python setup.py testr --slowest --testr-args='{posargs}'
|
||||
|
||||
[testenv:py33]
|
||||
commands =
|
||||
lockutils-wrapper python setup.py testr --slowest --testr-args='{posargs}'
|
||||
|
||||
[testenv:py34]
|
||||
commands =
|
||||
lockutils-wrapper python setup.py testr --slowest --testr-args='{posargs}'
|
||||
|
||||
Reference in New Issue
Block a user