mirror of
https://github.com/clinton-hall/nzbToMedia.git
synced 2025-08-21 13:53:15 -07:00
Move common libs to libs/common
This commit is contained in:
parent
8dbb1a2451
commit
1f4bd41bcc
1612 changed files with 962 additions and 10 deletions
26
libs/common/pbr/tests/__init__.py
Normal file
26
libs/common/pbr/tests/__init__.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
|
||||
import testscenarios
|
||||
|
||||
|
||||
def load_tests(loader, standard_tests, pattern):
|
||||
# top level directory cached on loader instance
|
||||
this_dir = os.path.dirname(__file__)
|
||||
package_tests = loader.discover(start_dir=this_dir, pattern=pattern)
|
||||
result = loader.suiteClass()
|
||||
result.addTests(testscenarios.generate_scenarios(standard_tests))
|
||||
result.addTests(testscenarios.generate_scenarios(package_tests))
|
||||
return result
|
221
libs/common/pbr/tests/base.py
Normal file
221
libs/common/pbr/tests/base.py
Normal file
|
@ -0,0 +1,221 @@
|
|||
# Copyright 2010-2011 OpenStack Foundation
|
||||
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
# Copyright (C) 2013 Association of Universities for Research in Astronomy
|
||||
# (AURA)
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
#
|
||||
# 3. The name of AURA and its representatives may not be used to
|
||||
# endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY AURA ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL AURA BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
|
||||
"""Common utilities used in testing"""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import fixtures
|
||||
import testresources
|
||||
import testtools
|
||||
from testtools import content
|
||||
|
||||
from pbr import options
|
||||
|
||||
|
||||
class DiveDir(fixtures.Fixture):
|
||||
"""Dive into given directory and return back on cleanup.
|
||||
|
||||
:ivar path: The target directory.
|
||||
"""
|
||||
|
||||
def __init__(self, path):
|
||||
self.path = path
|
||||
|
||||
def setUp(self):
|
||||
super(DiveDir, self).setUp()
|
||||
self.addCleanup(os.chdir, os.getcwd())
|
||||
os.chdir(self.path)
|
||||
|
||||
|
||||
class BaseTestCase(testtools.TestCase, testresources.ResourcedTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(BaseTestCase, self).setUp()
|
||||
test_timeout = os.environ.get('OS_TEST_TIMEOUT', 30)
|
||||
try:
|
||||
test_timeout = int(test_timeout)
|
||||
except ValueError:
|
||||
# If timeout value is invalid, fail hard.
|
||||
print("OS_TEST_TIMEOUT set to invalid value"
|
||||
" defaulting to no timeout")
|
||||
test_timeout = 0
|
||||
if test_timeout > 0:
|
||||
self.useFixture(fixtures.Timeout(test_timeout, gentle=True))
|
||||
|
||||
if os.environ.get('OS_STDOUT_CAPTURE') in options.TRUE_VALUES:
|
||||
stdout = self.useFixture(fixtures.StringStream('stdout')).stream
|
||||
self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
|
||||
if os.environ.get('OS_STDERR_CAPTURE') in options.TRUE_VALUES:
|
||||
stderr = self.useFixture(fixtures.StringStream('stderr')).stream
|
||||
self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
|
||||
self.log_fixture = self.useFixture(
|
||||
fixtures.FakeLogger('pbr'))
|
||||
|
||||
# Older git does not have config --local, so create a temporary home
|
||||
# directory to permit using git config --global without stepping on
|
||||
# developer configuration.
|
||||
self.useFixture(fixtures.TempHomeDir())
|
||||
self.useFixture(fixtures.NestedTempfile())
|
||||
self.useFixture(fixtures.FakeLogger())
|
||||
# TODO(lifeless) we should remove PBR_VERSION from the environment.
|
||||
# rather than setting it, because thats not representative - we need to
|
||||
# test non-preversioned codepaths too!
|
||||
self.useFixture(fixtures.EnvironmentVariable('PBR_VERSION', '0.0'))
|
||||
|
||||
self.temp_dir = self.useFixture(fixtures.TempDir()).path
|
||||
self.package_dir = os.path.join(self.temp_dir, 'testpackage')
|
||||
shutil.copytree(os.path.join(os.path.dirname(__file__), 'testpackage'),
|
||||
self.package_dir)
|
||||
self.addCleanup(os.chdir, os.getcwd())
|
||||
os.chdir(self.package_dir)
|
||||
self.addCleanup(self._discard_testpackage)
|
||||
# Tests can opt into non-PBR_VERSION by setting preversioned=False as
|
||||
# an attribute.
|
||||
if not getattr(self, 'preversioned', True):
|
||||
self.useFixture(fixtures.EnvironmentVariable('PBR_VERSION'))
|
||||
setup_cfg_path = os.path.join(self.package_dir, 'setup.cfg')
|
||||
with open(setup_cfg_path, 'rt') as cfg:
|
||||
content = cfg.read()
|
||||
content = content.replace(u'version = 0.1.dev', u'')
|
||||
with open(setup_cfg_path, 'wt') as cfg:
|
||||
cfg.write(content)
|
||||
|
||||
def _discard_testpackage(self):
|
||||
# Remove pbr.testpackage from sys.modules so that it can be freshly
|
||||
# re-imported by the next test
|
||||
for k in list(sys.modules):
|
||||
if (k == 'pbr_testpackage' or
|
||||
k.startswith('pbr_testpackage.')):
|
||||
del sys.modules[k]
|
||||
|
||||
def run_pbr(self, *args, **kwargs):
|
||||
return self._run_cmd('pbr', args, **kwargs)
|
||||
|
||||
def run_setup(self, *args, **kwargs):
|
||||
return self._run_cmd(sys.executable, ('setup.py',) + args, **kwargs)
|
||||
|
||||
def _run_cmd(self, cmd, args=[], allow_fail=True, cwd=None):
|
||||
"""Run a command in the root of the test working copy.
|
||||
|
||||
Runs a command, with the given argument list, in the root of the test
|
||||
working copy--returns the stdout and stderr streams and the exit code
|
||||
from the subprocess.
|
||||
|
||||
:param cwd: If falsy run within the test package dir, otherwise run
|
||||
within the named path.
|
||||
"""
|
||||
cwd = cwd or self.package_dir
|
||||
result = _run_cmd([cmd] + list(args), cwd=cwd)
|
||||
if result[2] and not allow_fail:
|
||||
raise Exception("Command failed retcode=%s" % result[2])
|
||||
return result
|
||||
|
||||
|
||||
class CapturedSubprocess(fixtures.Fixture):
|
||||
"""Run a process and capture its output.
|
||||
|
||||
:attr stdout: The output (a string).
|
||||
:attr stderr: The standard error (a string).
|
||||
:attr returncode: The return code of the process.
|
||||
|
||||
Note that stdout and stderr are decoded from the bytestrings subprocess
|
||||
returns using error=replace.
|
||||
"""
|
||||
|
||||
def __init__(self, label, *args, **kwargs):
|
||||
"""Create a CapturedSubprocess.
|
||||
|
||||
:param label: A label for the subprocess in the test log. E.g. 'foo'.
|
||||
:param *args: The *args to pass to Popen.
|
||||
:param **kwargs: The **kwargs to pass to Popen.
|
||||
"""
|
||||
super(CapturedSubprocess, self).__init__()
|
||||
self.label = label
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
self.kwargs['stderr'] = subprocess.PIPE
|
||||
self.kwargs['stdin'] = subprocess.PIPE
|
||||
self.kwargs['stdout'] = subprocess.PIPE
|
||||
|
||||
def setUp(self):
|
||||
super(CapturedSubprocess, self).setUp()
|
||||
proc = subprocess.Popen(*self.args, **self.kwargs)
|
||||
out, err = proc.communicate()
|
||||
self.out = out.decode('utf-8', 'replace')
|
||||
self.err = err.decode('utf-8', 'replace')
|
||||
self.addDetail(self.label + '-stdout', content.text_content(self.out))
|
||||
self.addDetail(self.label + '-stderr', content.text_content(self.err))
|
||||
self.returncode = proc.returncode
|
||||
if proc.returncode:
|
||||
raise AssertionError('Failed process %s' % proc.returncode)
|
||||
self.addCleanup(delattr, self, 'out')
|
||||
self.addCleanup(delattr, self, 'err')
|
||||
self.addCleanup(delattr, self, 'returncode')
|
||||
|
||||
|
||||
def _run_cmd(args, cwd):
|
||||
"""Run the command args in cwd.
|
||||
|
||||
:param args: The command to run e.g. ['git', 'status']
|
||||
:param cwd: The directory to run the comamnd in.
|
||||
:return: ((stdout, stderr), returncode)
|
||||
"""
|
||||
p = subprocess.Popen(
|
||||
args, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE, cwd=cwd)
|
||||
streams = tuple(s.decode('latin1').strip() for s in p.communicate())
|
||||
for stream_content in streams:
|
||||
print(stream_content)
|
||||
return (streams) + (p.returncode,)
|
||||
|
||||
|
||||
def _config_git():
|
||||
_run_cmd(
|
||||
['git', 'config', '--global', 'user.email', 'example@example.com'],
|
||||
None)
|
||||
_run_cmd(
|
||||
['git', 'config', '--global', 'user.name', 'OpenStack Developer'],
|
||||
None)
|
||||
_run_cmd(
|
||||
['git', 'config', '--global', 'user.signingkey',
|
||||
'example@example.com'], None)
|
84
libs/common/pbr/tests/test_commands.py
Normal file
84
libs/common/pbr/tests/test_commands.py
Normal file
|
@ -0,0 +1,84 @@
|
|||
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Copyright (C) 2013 Association of Universities for Research in Astronomy
|
||||
# (AURA)
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
#
|
||||
# 3. The name of AURA and its representatives may not be used to
|
||||
# endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY AURA ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL AURA BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
|
||||
from testtools import content
|
||||
|
||||
from pbr.tests import base
|
||||
|
||||
|
||||
class TestCommands(base.BaseTestCase):
|
||||
def test_custom_build_py_command(self):
|
||||
"""Test custom build_py command.
|
||||
|
||||
Test that a custom subclass of the build_py command runs when listed in
|
||||
the commands [global] option, rather than the normal build command.
|
||||
"""
|
||||
|
||||
stdout, stderr, return_code = self.run_setup('build_py')
|
||||
self.addDetail('stdout', content.text_content(stdout))
|
||||
self.addDetail('stderr', content.text_content(stderr))
|
||||
self.assertIn('Running custom build_py command.', stdout)
|
||||
self.assertEqual(0, return_code)
|
||||
|
||||
def test_custom_deb_version_py_command(self):
|
||||
"""Test custom deb_version command."""
|
||||
stdout, stderr, return_code = self.run_setup('deb_version')
|
||||
self.addDetail('stdout', content.text_content(stdout))
|
||||
self.addDetail('stderr', content.text_content(stderr))
|
||||
self.assertIn('Extracting deb version', stdout)
|
||||
self.assertEqual(0, return_code)
|
||||
|
||||
def test_custom_rpm_version_py_command(self):
|
||||
"""Test custom rpm_version command."""
|
||||
stdout, stderr, return_code = self.run_setup('rpm_version')
|
||||
self.addDetail('stdout', content.text_content(stdout))
|
||||
self.addDetail('stderr', content.text_content(stderr))
|
||||
self.assertIn('Extracting rpm version', stdout)
|
||||
self.assertEqual(0, return_code)
|
||||
|
||||
def test_freeze_command(self):
|
||||
"""Test that freeze output is sorted in a case-insensitive manner."""
|
||||
stdout, stderr, return_code = self.run_pbr('freeze')
|
||||
self.assertEqual(0, return_code)
|
||||
pkgs = []
|
||||
for l in stdout.split('\n'):
|
||||
pkgs.append(l.split('==')[0].lower())
|
||||
pkgs_sort = sorted(pkgs[:])
|
||||
self.assertEqual(pkgs_sort, pkgs)
|
151
libs/common/pbr/tests/test_core.py
Normal file
151
libs/common/pbr/tests/test_core.py
Normal file
|
@ -0,0 +1,151 @@
|
|||
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Copyright (C) 2013 Association of Universities for Research in Astronomy
|
||||
# (AURA)
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
#
|
||||
# 3. The name of AURA and its representatives may not be used to
|
||||
# endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY AURA ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL AURA BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
|
||||
import glob
|
||||
import os
|
||||
import tarfile
|
||||
|
||||
import fixtures
|
||||
|
||||
from pbr.tests import base
|
||||
|
||||
|
||||
class TestCore(base.BaseTestCase):
|
||||
|
||||
cmd_names = ('pbr_test_cmd', 'pbr_test_cmd_with_class')
|
||||
|
||||
def check_script_install(self, install_stdout):
|
||||
for cmd_name in self.cmd_names:
|
||||
install_txt = 'Installing %s script to %s' % (cmd_name,
|
||||
self.temp_dir)
|
||||
self.assertIn(install_txt, install_stdout)
|
||||
|
||||
cmd_filename = os.path.join(self.temp_dir, cmd_name)
|
||||
|
||||
script_txt = open(cmd_filename, 'r').read()
|
||||
self.assertNotIn('pkg_resources', script_txt)
|
||||
|
||||
stdout, _, return_code = self._run_cmd(cmd_filename)
|
||||
self.assertIn("PBR", stdout)
|
||||
|
||||
def test_setup_py_keywords(self):
|
||||
"""setup.py --keywords.
|
||||
|
||||
Test that the `./setup.py --keywords` command returns the correct
|
||||
value without balking.
|
||||
"""
|
||||
|
||||
self.run_setup('egg_info')
|
||||
stdout, _, _ = self.run_setup('--keywords')
|
||||
assert stdout == 'packaging,distutils,setuptools'
|
||||
|
||||
def test_setup_py_build_sphinx(self):
|
||||
stdout, _, return_code = self.run_setup('build_sphinx')
|
||||
self.assertEqual(0, return_code)
|
||||
|
||||
def test_sdist_extra_files(self):
|
||||
"""Test that the extra files are correctly added."""
|
||||
|
||||
stdout, _, return_code = self.run_setup('sdist', '--formats=gztar')
|
||||
|
||||
# There can be only one
|
||||
try:
|
||||
tf_path = glob.glob(os.path.join('dist', '*.tar.gz'))[0]
|
||||
except IndexError:
|
||||
assert False, 'source dist not found'
|
||||
|
||||
tf = tarfile.open(tf_path)
|
||||
names = ['/'.join(p.split('/')[1:]) for p in tf.getnames()]
|
||||
|
||||
self.assertIn('extra-file.txt', names)
|
||||
|
||||
def test_console_script_install(self):
|
||||
"""Test that we install a non-pkg-resources console script."""
|
||||
|
||||
if os.name == 'nt':
|
||||
self.skipTest('Windows support is passthrough')
|
||||
|
||||
stdout, _, return_code = self.run_setup(
|
||||
'install_scripts', '--install-dir=%s' % self.temp_dir)
|
||||
|
||||
self.useFixture(
|
||||
fixtures.EnvironmentVariable('PYTHONPATH', '.'))
|
||||
|
||||
self.check_script_install(stdout)
|
||||
|
||||
def test_console_script_develop(self):
|
||||
"""Test that we develop a non-pkg-resources console script."""
|
||||
|
||||
if os.name == 'nt':
|
||||
self.skipTest('Windows support is passthrough')
|
||||
|
||||
self.useFixture(
|
||||
fixtures.EnvironmentVariable(
|
||||
'PYTHONPATH', ".:%s" % self.temp_dir))
|
||||
|
||||
stdout, _, return_code = self.run_setup(
|
||||
'develop', '--install-dir=%s' % self.temp_dir)
|
||||
|
||||
self.check_script_install(stdout)
|
||||
|
||||
|
||||
class TestGitSDist(base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestGitSDist, self).setUp()
|
||||
|
||||
stdout, _, return_code = self._run_cmd('git', ('init',))
|
||||
if return_code:
|
||||
self.skipTest("git not installed")
|
||||
|
||||
stdout, _, return_code = self._run_cmd('git', ('add', '.'))
|
||||
stdout, _, return_code = self._run_cmd(
|
||||
'git', ('commit', '-m', 'Turn this into a git repo'))
|
||||
|
||||
stdout, _, return_code = self.run_setup('sdist', '--formats=gztar')
|
||||
|
||||
def test_sdist_git_extra_files(self):
|
||||
"""Test that extra files found in git are correctly added."""
|
||||
# There can be only one
|
||||
tf_path = glob.glob(os.path.join('dist', '*.tar.gz'))[0]
|
||||
tf = tarfile.open(tf_path)
|
||||
names = ['/'.join(p.split('/')[1:]) for p in tf.getnames()]
|
||||
|
||||
self.assertIn('git-extra-file.txt', names)
|
78
libs/common/pbr/tests/test_files.py
Normal file
78
libs/common/pbr/tests/test_files.py
Normal file
|
@ -0,0 +1,78 @@
|
|||
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
|
||||
import fixtures
|
||||
|
||||
from pbr.hooks import files
|
||||
from pbr.tests import base
|
||||
|
||||
|
||||
class FilesConfigTest(base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(FilesConfigTest, self).setUp()
|
||||
|
||||
pkg_fixture = fixtures.PythonPackage(
|
||||
"fake_package", [
|
||||
("fake_module.py", b""),
|
||||
("other_fake_module.py", b""),
|
||||
])
|
||||
self.useFixture(pkg_fixture)
|
||||
pkg_etc = os.path.join(pkg_fixture.base, 'etc')
|
||||
pkg_sub = os.path.join(pkg_etc, 'sub')
|
||||
subpackage = os.path.join(
|
||||
pkg_fixture.base, 'fake_package', 'subpackage')
|
||||
os.makedirs(pkg_sub)
|
||||
os.makedirs(subpackage)
|
||||
with open(os.path.join(pkg_etc, "foo"), 'w') as foo_file:
|
||||
foo_file.write("Foo Data")
|
||||
with open(os.path.join(pkg_sub, "bar"), 'w') as foo_file:
|
||||
foo_file.write("Bar Data")
|
||||
with open(os.path.join(subpackage, "__init__.py"), 'w') as foo_file:
|
||||
foo_file.write("# empty")
|
||||
|
||||
self.useFixture(base.DiveDir(pkg_fixture.base))
|
||||
|
||||
def test_implicit_auto_package(self):
|
||||
config = dict(
|
||||
files=dict(
|
||||
)
|
||||
)
|
||||
files.FilesConfig(config, 'fake_package').run()
|
||||
self.assertIn('subpackage', config['files']['packages'])
|
||||
|
||||
def test_auto_package(self):
|
||||
config = dict(
|
||||
files=dict(
|
||||
packages='fake_package',
|
||||
)
|
||||
)
|
||||
files.FilesConfig(config, 'fake_package').run()
|
||||
self.assertIn('subpackage', config['files']['packages'])
|
||||
|
||||
def test_data_files_globbing(self):
|
||||
config = dict(
|
||||
files=dict(
|
||||
data_files="\n etc/pbr = etc/*"
|
||||
)
|
||||
)
|
||||
files.FilesConfig(config, 'fake_package').run()
|
||||
self.assertIn(
|
||||
'\netc/pbr/ = \n etc/foo\netc/pbr/sub = \n etc/sub/bar',
|
||||
config['files']['data_files'])
|
75
libs/common/pbr/tests/test_hooks.py
Normal file
75
libs/common/pbr/tests/test_hooks.py
Normal file
|
@ -0,0 +1,75 @@
|
|||
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Copyright (C) 2013 Association of Universities for Research in Astronomy
|
||||
# (AURA)
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
#
|
||||
# 3. The name of AURA and its representatives may not be used to
|
||||
# endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY AURA ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL AURA BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
|
||||
import os
|
||||
|
||||
from testtools import matchers
|
||||
from testtools import skipUnless
|
||||
|
||||
from pbr import testr_command
|
||||
from pbr.tests import base
|
||||
from pbr.tests import util
|
||||
|
||||
|
||||
class TestHooks(base.BaseTestCase):
|
||||
def setUp(self):
|
||||
super(TestHooks, self).setUp()
|
||||
with util.open_config(
|
||||
os.path.join(self.package_dir, 'setup.cfg')) as cfg:
|
||||
cfg.set('global', 'setup-hooks',
|
||||
'pbr_testpackage._setup_hooks.test_hook_1\n'
|
||||
'pbr_testpackage._setup_hooks.test_hook_2')
|
||||
|
||||
def test_global_setup_hooks(self):
|
||||
"""Test setup_hooks.
|
||||
|
||||
Test that setup_hooks listed in the [global] section of setup.cfg are
|
||||
executed in order.
|
||||
"""
|
||||
|
||||
stdout, _, return_code = self.run_setup('egg_info')
|
||||
assert 'test_hook_1\ntest_hook_2' in stdout
|
||||
assert return_code == 0
|
||||
|
||||
@skipUnless(testr_command.have_testr, "testrepository not available")
|
||||
def test_custom_commands_known(self):
|
||||
stdout, _, return_code = self.run_setup('--help-commands')
|
||||
self.assertFalse(return_code)
|
||||
self.assertThat(stdout, matchers.Contains(" testr "))
|
269
libs/common/pbr/tests/test_integration.py
Normal file
269
libs/common/pbr/tests/test_integration.py
Normal file
|
@ -0,0 +1,269 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import os.path
|
||||
import shlex
|
||||
import sys
|
||||
|
||||
import fixtures
|
||||
import testtools
|
||||
import textwrap
|
||||
|
||||
from pbr.tests import base
|
||||
from pbr.tests import test_packaging
|
||||
|
||||
PIPFLAGS = shlex.split(os.environ.get('PIPFLAGS', ''))
|
||||
PIPVERSION = os.environ.get('PIPVERSION', 'pip')
|
||||
PBRVERSION = os.environ.get('PBRVERSION', 'pbr')
|
||||
REPODIR = os.environ.get('REPODIR', '')
|
||||
WHEELHOUSE = os.environ.get('WHEELHOUSE', '')
|
||||
PIP_CMD = ['-m', 'pip'] + PIPFLAGS + ['install', '-f', WHEELHOUSE]
|
||||
PROJECTS = shlex.split(os.environ.get('PROJECTS', ''))
|
||||
PBR_ROOT = os.path.abspath(os.path.join(__file__, '..', '..', '..'))
|
||||
|
||||
|
||||
def all_projects():
|
||||
if not REPODIR:
|
||||
return
|
||||
# Future: make this path parameterisable.
|
||||
excludes = set(['tempest', 'requirements'])
|
||||
for name in PROJECTS:
|
||||
name = name.strip()
|
||||
short_name = name.split('/')[-1]
|
||||
try:
|
||||
with open(os.path.join(
|
||||
REPODIR, short_name, 'setup.py'), 'rt') as f:
|
||||
if 'pbr' not in f.read():
|
||||
continue
|
||||
except IOError:
|
||||
continue
|
||||
if short_name in excludes:
|
||||
continue
|
||||
yield (short_name, dict(name=name, short_name=short_name))
|
||||
|
||||
|
||||
class TestIntegration(base.BaseTestCase):
|
||||
|
||||
scenarios = list(all_projects())
|
||||
|
||||
def setUp(self):
|
||||
# Integration tests need a higher default - big repos can be slow to
|
||||
# clone, particularly under guest load.
|
||||
env = fixtures.EnvironmentVariable(
|
||||
'OS_TEST_TIMEOUT', os.environ.get('OS_TEST_TIMEOUT', '600'))
|
||||
with env:
|
||||
super(TestIntegration, self).setUp()
|
||||
base._config_git()
|
||||
|
||||
@testtools.skipUnless(
|
||||
os.environ.get('PBR_INTEGRATION', None) == '1',
|
||||
'integration tests not enabled')
|
||||
def test_integration(self):
|
||||
# Test that we can:
|
||||
# - run sdist from the repo in a venv
|
||||
# - install the resulting tarball in a new venv
|
||||
# - pip install the repo
|
||||
# - pip install -e the repo
|
||||
# We don't break these into separate tests because we'd need separate
|
||||
# source dirs to isolate from side effects of running pip, and the
|
||||
# overheads of setup would start to beat the benefits of parallelism.
|
||||
self.useFixture(base.CapturedSubprocess(
|
||||
'sync-req',
|
||||
['python', 'update.py', os.path.join(REPODIR, self.short_name)],
|
||||
cwd=os.path.join(REPODIR, 'requirements')))
|
||||
self.useFixture(base.CapturedSubprocess(
|
||||
'commit-requirements',
|
||||
'git diff --quiet || git commit -amrequirements',
|
||||
cwd=os.path.join(REPODIR, self.short_name), shell=True))
|
||||
path = os.path.join(
|
||||
self.useFixture(fixtures.TempDir()).path, 'project')
|
||||
self.useFixture(base.CapturedSubprocess(
|
||||
'clone',
|
||||
['git', 'clone', os.path.join(REPODIR, self.short_name), path]))
|
||||
venv = self.useFixture(
|
||||
test_packaging.Venv('sdist',
|
||||
modules=['pip', 'wheel', PBRVERSION],
|
||||
pip_cmd=PIP_CMD))
|
||||
python = venv.python
|
||||
self.useFixture(base.CapturedSubprocess(
|
||||
'sdist', [python, 'setup.py', 'sdist'], cwd=path))
|
||||
venv = self.useFixture(
|
||||
test_packaging.Venv('tarball',
|
||||
modules=['pip', 'wheel', PBRVERSION],
|
||||
pip_cmd=PIP_CMD))
|
||||
python = venv.python
|
||||
filename = os.path.join(
|
||||
path, 'dist', os.listdir(os.path.join(path, 'dist'))[0])
|
||||
self.useFixture(base.CapturedSubprocess(
|
||||
'tarball', [python] + PIP_CMD + [filename]))
|
||||
venv = self.useFixture(
|
||||
test_packaging.Venv('install-git',
|
||||
modules=['pip', 'wheel', PBRVERSION],
|
||||
pip_cmd=PIP_CMD))
|
||||
root = venv.path
|
||||
python = venv.python
|
||||
self.useFixture(base.CapturedSubprocess(
|
||||
'install-git', [python] + PIP_CMD + ['git+file://' + path]))
|
||||
if self.short_name == 'nova':
|
||||
found = False
|
||||
for _, _, filenames in os.walk(root):
|
||||
if 'migrate.cfg' in filenames:
|
||||
found = True
|
||||
self.assertTrue(found)
|
||||
venv = self.useFixture(
|
||||
test_packaging.Venv('install-e',
|
||||
modules=['pip', 'wheel', PBRVERSION],
|
||||
pip_cmd=PIP_CMD))
|
||||
root = venv.path
|
||||
python = venv.python
|
||||
self.useFixture(base.CapturedSubprocess(
|
||||
'install-e', [python] + PIP_CMD + ['-e', path]))
|
||||
|
||||
|
||||
class TestInstallWithoutPbr(base.BaseTestCase):
|
||||
|
||||
@testtools.skipUnless(
|
||||
os.environ.get('PBR_INTEGRATION', None) == '1',
|
||||
'integration tests not enabled')
|
||||
def test_install_without_pbr(self):
|
||||
# Test easy-install of a thing that depends on a thing using pbr
|
||||
tempdir = self.useFixture(fixtures.TempDir()).path
|
||||
# A directory containing sdists of the things we're going to depend on
|
||||
# in using-package.
|
||||
dist_dir = os.path.join(tempdir, 'distdir')
|
||||
os.mkdir(dist_dir)
|
||||
self._run_cmd(sys.executable, ('setup.py', 'sdist', '-d', dist_dir),
|
||||
allow_fail=False, cwd=PBR_ROOT)
|
||||
# testpkg - this requires a pbr-using package
|
||||
test_pkg_dir = os.path.join(tempdir, 'testpkg')
|
||||
os.mkdir(test_pkg_dir)
|
||||
pkgs = {
|
||||
'pkgTest': {
|
||||
'setup.py': textwrap.dedent("""\
|
||||
#!/usr/bin/env python
|
||||
import setuptools
|
||||
setuptools.setup(
|
||||
name = 'pkgTest',
|
||||
tests_require = ['pkgReq'],
|
||||
test_suite='pkgReq'
|
||||
)
|
||||
"""),
|
||||
'setup.cfg': textwrap.dedent("""\
|
||||
[easy_install]
|
||||
find_links = %s
|
||||
""" % dist_dir)},
|
||||
'pkgReq': {
|
||||
'requirements.txt': textwrap.dedent("""\
|
||||
pbr
|
||||
"""),
|
||||
'pkgReq/__init__.py': textwrap.dedent("""\
|
||||
print("FakeTest loaded and ran")
|
||||
""")},
|
||||
}
|
||||
pkg_dirs = self.useFixture(
|
||||
test_packaging.CreatePackages(pkgs)).package_dirs
|
||||
test_pkg_dir = pkg_dirs['pkgTest']
|
||||
req_pkg_dir = pkg_dirs['pkgReq']
|
||||
|
||||
self._run_cmd(sys.executable, ('setup.py', 'sdist', '-d', dist_dir),
|
||||
allow_fail=False, cwd=req_pkg_dir)
|
||||
# A venv to test within
|
||||
venv = self.useFixture(test_packaging.Venv('nopbr', ['pip', 'wheel']))
|
||||
python = venv.python
|
||||
# Run the depending script
|
||||
self.useFixture(base.CapturedSubprocess(
|
||||
'nopbr', [python] + ['setup.py', 'test'], cwd=test_pkg_dir))
|
||||
|
||||
|
||||
class TestMarkersPip(base.BaseTestCase):
|
||||
|
||||
scenarios = [
|
||||
('pip-1.5', {'modules': ['pip>=1.5,<1.6']}),
|
||||
('pip-6.0', {'modules': ['pip>=6.0,<6.1']}),
|
||||
('pip-latest', {'modules': ['pip']}),
|
||||
('setuptools-EL7', {'modules': ['pip==1.4.1', 'setuptools==0.9.8']}),
|
||||
('setuptools-Trusty', {'modules': ['pip==1.5', 'setuptools==2.2']}),
|
||||
('setuptools-minimum', {'modules': ['pip==1.5', 'setuptools==0.7.2']}),
|
||||
]
|
||||
|
||||
@testtools.skipUnless(
|
||||
os.environ.get('PBR_INTEGRATION', None) == '1',
|
||||
'integration tests not enabled')
|
||||
def test_pip_versions(self):
|
||||
pkgs = {
|
||||
'test_markers':
|
||||
{'requirements.txt': textwrap.dedent("""\
|
||||
pkg_a; python_version=='1.2'
|
||||
pkg_b; python_version!='1.2'
|
||||
""")},
|
||||
'pkg_a': {},
|
||||
'pkg_b': {},
|
||||
}
|
||||
pkg_dirs = self.useFixture(
|
||||
test_packaging.CreatePackages(pkgs)).package_dirs
|
||||
temp_dir = self.useFixture(fixtures.TempDir()).path
|
||||
repo_dir = os.path.join(temp_dir, 'repo')
|
||||
venv = self.useFixture(test_packaging.Venv('markers'))
|
||||
bin_python = venv.python
|
||||
os.mkdir(repo_dir)
|
||||
for module in self.modules:
|
||||
self._run_cmd(
|
||||
bin_python,
|
||||
['-m', 'pip', 'install', '--upgrade', module],
|
||||
cwd=venv.path, allow_fail=False)
|
||||
for pkg in pkg_dirs:
|
||||
self._run_cmd(
|
||||
bin_python, ['setup.py', 'sdist', '-d', repo_dir],
|
||||
cwd=pkg_dirs[pkg], allow_fail=False)
|
||||
self._run_cmd(
|
||||
bin_python,
|
||||
['-m', 'pip', 'install', '--no-index', '-f', repo_dir,
|
||||
'test_markers'],
|
||||
cwd=venv.path, allow_fail=False)
|
||||
self.assertIn('pkg-b', self._run_cmd(
|
||||
bin_python, ['-m', 'pip', 'freeze'], cwd=venv.path,
|
||||
allow_fail=False)[0])
|
||||
|
||||
|
||||
class TestLTSSupport(base.BaseTestCase):
|
||||
|
||||
# These versions come from the versions installed from the 'virtualenv'
|
||||
# command from the 'python-virtualenv' package.
|
||||
scenarios = [
|
||||
('EL7', {'modules': ['pip==1.4.1', 'setuptools==0.9.8'],
|
||||
'py3support': True}), # And EPEL6
|
||||
('Trusty', {'modules': ['pip==1.5', 'setuptools==2.2'],
|
||||
'py3support': True}),
|
||||
('Jessie', {'modules': ['pip==1.5.6', 'setuptools==5.5.1'],
|
||||
'py3support': True}),
|
||||
# Wheezy has pip1.1, which cannot be called with '-m pip'
|
||||
# So we'll use a different version of pip here.
|
||||
('WheezyPrecise', {'modules': ['pip==1.4.1', 'setuptools==0.6c11'],
|
||||
'py3support': False})
|
||||
]
|
||||
|
||||
@testtools.skipUnless(
|
||||
os.environ.get('PBR_INTEGRATION', None) == '1',
|
||||
'integration tests not enabled')
|
||||
def test_lts_venv_default_versions(self):
|
||||
if (sys.version_info[0] == 3 and not self.py3support):
|
||||
self.skipTest('This combination will not install with py3, '
|
||||
'skipping test')
|
||||
venv = self.useFixture(
|
||||
test_packaging.Venv('setuptools', modules=self.modules))
|
||||
bin_python = venv.python
|
||||
pbr = 'file://%s#egg=pbr' % PBR_ROOT
|
||||
# Installing PBR is a reasonable indication that we are not broken on
|
||||
# this particular combination of setuptools and pip.
|
||||
self._run_cmd(bin_python, ['-m', 'pip', 'install', pbr],
|
||||
cwd=venv.path, allow_fail=False)
|
923
libs/common/pbr/tests/test_packaging.py
Normal file
923
libs/common/pbr/tests/test_packaging.py
Normal file
|
@ -0,0 +1,923 @@
|
|||
# Copyright (c) 2013 New Dream Network, LLC (DreamHost)
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Copyright (C) 2013 Association of Universities for Research in Astronomy
|
||||
# (AURA)
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
#
|
||||
# 3. The name of AURA and its representatives may not be used to
|
||||
# endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY AURA ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL AURA BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
|
||||
import email
|
||||
import email.errors
|
||||
import imp
|
||||
import os
|
||||
import re
|
||||
import sysconfig
|
||||
import tempfile
|
||||
import textwrap
|
||||
|
||||
import fixtures
|
||||
import mock
|
||||
import pkg_resources
|
||||
import six
|
||||
import testscenarios
|
||||
import testtools
|
||||
from testtools import matchers
|
||||
import virtualenv
|
||||
from wheel import wheelfile
|
||||
|
||||
from pbr import git
|
||||
from pbr import packaging
|
||||
from pbr.tests import base
|
||||
|
||||
|
||||
PBR_ROOT = os.path.abspath(os.path.join(__file__, '..', '..', '..'))
|
||||
|
||||
|
||||
class TestRepo(fixtures.Fixture):
|
||||
"""A git repo for testing with.
|
||||
|
||||
Use of TempHomeDir with this fixture is strongly recommended as due to the
|
||||
lack of config --local in older gits, it will write to the users global
|
||||
configuration without TempHomeDir.
|
||||
"""
|
||||
|
||||
def __init__(self, basedir):
|
||||
super(TestRepo, self).__init__()
|
||||
self._basedir = basedir
|
||||
|
||||
def setUp(self):
|
||||
super(TestRepo, self).setUp()
|
||||
base._run_cmd(['git', 'init', '.'], self._basedir)
|
||||
base._config_git()
|
||||
base._run_cmd(['git', 'add', '.'], self._basedir)
|
||||
|
||||
def commit(self, message_content='test commit'):
|
||||
files = len(os.listdir(self._basedir))
|
||||
path = self._basedir + '/%d' % files
|
||||
open(path, 'wt').close()
|
||||
base._run_cmd(['git', 'add', path], self._basedir)
|
||||
base._run_cmd(['git', 'commit', '-m', message_content], self._basedir)
|
||||
|
||||
def uncommit(self):
|
||||
base._run_cmd(['git', 'reset', '--hard', 'HEAD^'], self._basedir)
|
||||
|
||||
def tag(self, version):
|
||||
base._run_cmd(
|
||||
['git', 'tag', '-sm', 'test tag', version], self._basedir)
|
||||
|
||||
|
||||
class GPGKeyFixture(fixtures.Fixture):
|
||||
"""Creates a GPG key for testing.
|
||||
|
||||
It's recommended that this be used in concert with a unique home
|
||||
directory.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(GPGKeyFixture, self).setUp()
|
||||
tempdir = self.useFixture(fixtures.TempDir())
|
||||
gnupg_version_re = re.compile('^gpg\s.*\s([\d+])\.([\d+])\.([\d+])')
|
||||
gnupg_version = base._run_cmd(['gpg', '--version'], tempdir.path)
|
||||
for line in gnupg_version[0].split('\n'):
|
||||
gnupg_version = gnupg_version_re.match(line)
|
||||
if gnupg_version:
|
||||
gnupg_version = (int(gnupg_version.group(1)),
|
||||
int(gnupg_version.group(2)),
|
||||
int(gnupg_version.group(3)))
|
||||
break
|
||||
else:
|
||||
if gnupg_version is None:
|
||||
gnupg_version = (0, 0, 0)
|
||||
config_file = tempdir.path + '/key-config'
|
||||
f = open(config_file, 'wt')
|
||||
try:
|
||||
if gnupg_version[0] == 2 and gnupg_version[1] >= 1:
|
||||
f.write("""
|
||||
%no-protection
|
||||
%transient-key
|
||||
""")
|
||||
f.write("""
|
||||
%no-ask-passphrase
|
||||
Key-Type: RSA
|
||||
Name-Real: Example Key
|
||||
Name-Comment: N/A
|
||||
Name-Email: example@example.com
|
||||
Expire-Date: 2d
|
||||
Preferences: (setpref)
|
||||
%commit
|
||||
""")
|
||||
finally:
|
||||
f.close()
|
||||
# Note that --quick-random (--debug-quick-random in GnuPG 2.x)
|
||||
# does not have a corresponding preferences file setting and
|
||||
# must be passed explicitly on the command line instead
|
||||
if gnupg_version[0] == 1:
|
||||
gnupg_random = '--quick-random'
|
||||
elif gnupg_version[0] >= 2:
|
||||
gnupg_random = '--debug-quick-random'
|
||||
else:
|
||||
gnupg_random = ''
|
||||
base._run_cmd(
|
||||
['gpg', '--gen-key', '--batch', gnupg_random, config_file],
|
||||
tempdir.path)
|
||||
|
||||
|
||||
class Venv(fixtures.Fixture):
|
||||
"""Create a virtual environment for testing with.
|
||||
|
||||
:attr path: The path to the environment root.
|
||||
:attr python: The path to the python binary in the environment.
|
||||
"""
|
||||
|
||||
def __init__(self, reason, modules=(), pip_cmd=None):
|
||||
"""Create a Venv fixture.
|
||||
|
||||
:param reason: A human readable string to bake into the venv
|
||||
file path to aid diagnostics in the case of failures.
|
||||
:param modules: A list of modules to install, defaults to latest
|
||||
pip, wheel, and the working copy of PBR.
|
||||
:attr pip_cmd: A list to override the default pip_cmd passed to
|
||||
python for installing base packages.
|
||||
"""
|
||||
self._reason = reason
|
||||
if modules == ():
|
||||
pbr = 'file://%s#egg=pbr' % PBR_ROOT
|
||||
modules = ['pip', 'wheel', pbr]
|
||||
self.modules = modules
|
||||
if pip_cmd is None:
|
||||
self.pip_cmd = ['-m', 'pip', 'install']
|
||||
else:
|
||||
self.pip_cmd = pip_cmd
|
||||
|
||||
def _setUp(self):
|
||||
path = self.useFixture(fixtures.TempDir()).path
|
||||
virtualenv.create_environment(path, clear=True)
|
||||
python = os.path.join(path, 'bin', 'python')
|
||||
command = [python] + self.pip_cmd + ['-U']
|
||||
if self.modules and len(self.modules) > 0:
|
||||
command.extend(self.modules)
|
||||
self.useFixture(base.CapturedSubprocess(
|
||||
'mkvenv-' + self._reason, command))
|
||||
self.addCleanup(delattr, self, 'path')
|
||||
self.addCleanup(delattr, self, 'python')
|
||||
self.path = path
|
||||
self.python = python
|
||||
return path, python
|
||||
|
||||
|
||||
class CreatePackages(fixtures.Fixture):
|
||||
"""Creates packages from dict with defaults
|
||||
|
||||
:param package_dirs: A dict of package name to directory strings
|
||||
{'pkg_a': '/tmp/path/to/tmp/pkg_a', 'pkg_b': '/tmp/path/to/tmp/pkg_b'}
|
||||
"""
|
||||
|
||||
defaults = {
|
||||
'setup.py': textwrap.dedent(six.u("""\
|
||||
#!/usr/bin/env python
|
||||
import setuptools
|
||||
setuptools.setup(
|
||||
setup_requires=['pbr'],
|
||||
pbr=True,
|
||||
)
|
||||
""")),
|
||||
'setup.cfg': textwrap.dedent(six.u("""\
|
||||
[metadata]
|
||||
name = {pkg_name}
|
||||
"""))
|
||||
}
|
||||
|
||||
def __init__(self, packages):
|
||||
"""Creates packages from dict with defaults
|
||||
|
||||
:param packages: a dict where the keys are the package name and a
|
||||
value that is a second dict that may be empty, containing keys of
|
||||
filenames and a string value of the contents.
|
||||
{'package-a': {'requirements.txt': 'string', 'setup.cfg': 'string'}
|
||||
"""
|
||||
self.packages = packages
|
||||
|
||||
def _writeFile(self, directory, file_name, contents):
|
||||
path = os.path.abspath(os.path.join(directory, file_name))
|
||||
path_dir = os.path.dirname(path)
|
||||
if not os.path.exists(path_dir):
|
||||
if path_dir.startswith(directory):
|
||||
os.makedirs(path_dir)
|
||||
else:
|
||||
raise ValueError
|
||||
with open(path, 'wt') as f:
|
||||
f.write(contents)
|
||||
|
||||
def _setUp(self):
|
||||
tmpdir = self.useFixture(fixtures.TempDir()).path
|
||||
package_dirs = {}
|
||||
for pkg_name in self.packages:
|
||||
pkg_path = os.path.join(tmpdir, pkg_name)
|
||||
package_dirs[pkg_name] = pkg_path
|
||||
os.mkdir(pkg_path)
|
||||
for cf in ['setup.py', 'setup.cfg']:
|
||||
if cf in self.packages[pkg_name]:
|
||||
contents = self.packages[pkg_name].pop(cf)
|
||||
else:
|
||||
contents = self.defaults[cf].format(pkg_name=pkg_name)
|
||||
self._writeFile(pkg_path, cf, contents)
|
||||
|
||||
for cf in self.packages[pkg_name]:
|
||||
self._writeFile(pkg_path, cf, self.packages[pkg_name][cf])
|
||||
self.useFixture(TestRepo(pkg_path)).commit()
|
||||
self.addCleanup(delattr, self, 'package_dirs')
|
||||
self.package_dirs = package_dirs
|
||||
return package_dirs
|
||||
|
||||
|
||||
class TestPackagingInGitRepoWithCommit(base.BaseTestCase):
|
||||
|
||||
scenarios = [
|
||||
('preversioned', dict(preversioned=True)),
|
||||
('postversioned', dict(preversioned=False)),
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
super(TestPackagingInGitRepoWithCommit, self).setUp()
|
||||
self.repo = self.useFixture(TestRepo(self.package_dir))
|
||||
self.repo.commit()
|
||||
|
||||
def test_authors(self):
|
||||
self.run_setup('sdist', allow_fail=False)
|
||||
# One commit, something should be in the authors list
|
||||
with open(os.path.join(self.package_dir, 'AUTHORS'), 'r') as f:
|
||||
body = f.read()
|
||||
self.assertNotEqual(body, '')
|
||||
|
||||
def test_changelog(self):
|
||||
self.run_setup('sdist', allow_fail=False)
|
||||
with open(os.path.join(self.package_dir, 'ChangeLog'), 'r') as f:
|
||||
body = f.read()
|
||||
# One commit, something should be in the ChangeLog list
|
||||
self.assertNotEqual(body, '')
|
||||
|
||||
def test_changelog_handles_astrisk(self):
|
||||
self.repo.commit(message_content="Allow *.openstack.org to work")
|
||||
self.run_setup('sdist', allow_fail=False)
|
||||
with open(os.path.join(self.package_dir, 'ChangeLog'), 'r') as f:
|
||||
body = f.read()
|
||||
self.assertIn('\*', body)
|
||||
|
||||
def test_changelog_handles_dead_links_in_commit(self):
|
||||
self.repo.commit(message_content="See os_ for to_do about qemu_.")
|
||||
self.run_setup('sdist', allow_fail=False)
|
||||
with open(os.path.join(self.package_dir, 'ChangeLog'), 'r') as f:
|
||||
body = f.read()
|
||||
self.assertIn('os\_', body)
|
||||
self.assertIn('to\_do', body)
|
||||
self.assertIn('qemu\_', body)
|
||||
|
||||
def test_changelog_handles_backticks(self):
|
||||
self.repo.commit(message_content="Allow `openstack.org` to `work")
|
||||
self.run_setup('sdist', allow_fail=False)
|
||||
with open(os.path.join(self.package_dir, 'ChangeLog'), 'r') as f:
|
||||
body = f.read()
|
||||
self.assertIn('\`', body)
|
||||
|
||||
def test_manifest_exclude_honoured(self):
|
||||
self.run_setup('sdist', allow_fail=False)
|
||||
with open(os.path.join(
|
||||
self.package_dir,
|
||||
'pbr_testpackage.egg-info/SOURCES.txt'), 'r') as f:
|
||||
body = f.read()
|
||||
self.assertThat(
|
||||
body, matchers.Not(matchers.Contains('pbr_testpackage/extra.py')))
|
||||
self.assertThat(body, matchers.Contains('pbr_testpackage/__init__.py'))
|
||||
|
||||
def test_install_writes_changelog(self):
|
||||
stdout, _, _ = self.run_setup(
|
||||
'install', '--root', self.temp_dir + 'installed',
|
||||
allow_fail=False)
|
||||
self.expectThat(stdout, matchers.Contains('Generating ChangeLog'))
|
||||
|
||||
|
||||
class TestExtrafileInstallation(base.BaseTestCase):
|
||||
def test_install_glob(self):
|
||||
stdout, _, _ = self.run_setup(
|
||||
'install', '--root', self.temp_dir + 'installed',
|
||||
allow_fail=False)
|
||||
self.expectThat(
|
||||
stdout, matchers.Contains('copying data_files/a.txt'))
|
||||
self.expectThat(
|
||||
stdout, matchers.Contains('copying data_files/b.txt'))
|
||||
|
||||
|
||||
class TestPackagingInGitRepoWithoutCommit(base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestPackagingInGitRepoWithoutCommit, self).setUp()
|
||||
self.useFixture(TestRepo(self.package_dir))
|
||||
self.run_setup('sdist', allow_fail=False)
|
||||
|
||||
def test_authors(self):
|
||||
# No commits, no authors in list
|
||||
with open(os.path.join(self.package_dir, 'AUTHORS'), 'r') as f:
|
||||
body = f.read()
|
||||
self.assertEqual('\n', body)
|
||||
|
||||
def test_changelog(self):
|
||||
# No commits, nothing should be in the ChangeLog list
|
||||
with open(os.path.join(self.package_dir, 'ChangeLog'), 'r') as f:
|
||||
body = f.read()
|
||||
self.assertEqual('CHANGES\n=======\n\n', body)
|
||||
|
||||
|
||||
class TestPackagingWheels(base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestPackagingWheels, self).setUp()
|
||||
self.useFixture(TestRepo(self.package_dir))
|
||||
# Build the wheel
|
||||
self.run_setup('bdist_wheel', allow_fail=False)
|
||||
# Slowly construct the path to the generated whl
|
||||
dist_dir = os.path.join(self.package_dir, 'dist')
|
||||
relative_wheel_filename = os.listdir(dist_dir)[0]
|
||||
absolute_wheel_filename = os.path.join(
|
||||
dist_dir, relative_wheel_filename)
|
||||
wheel_file = wheelfile.WheelFile(absolute_wheel_filename)
|
||||
wheel_name = wheel_file.parsed_filename.group('namever')
|
||||
# Create a directory path to unpack the wheel to
|
||||
self.extracted_wheel_dir = os.path.join(dist_dir, wheel_name)
|
||||
# Extract the wheel contents to the directory we just created
|
||||
wheel_file.extractall(self.extracted_wheel_dir)
|
||||
wheel_file.close()
|
||||
|
||||
def test_data_directory_has_wsgi_scripts(self):
|
||||
# Build the path to the scripts directory
|
||||
scripts_dir = os.path.join(
|
||||
self.extracted_wheel_dir, 'pbr_testpackage-0.0.data/scripts')
|
||||
self.assertTrue(os.path.exists(scripts_dir))
|
||||
scripts = os.listdir(scripts_dir)
|
||||
|
||||
self.assertIn('pbr_test_wsgi', scripts)
|
||||
self.assertIn('pbr_test_wsgi_with_class', scripts)
|
||||
self.assertNotIn('pbr_test_cmd', scripts)
|
||||
self.assertNotIn('pbr_test_cmd_with_class', scripts)
|
||||
|
||||
def test_generates_c_extensions(self):
|
||||
built_package_dir = os.path.join(
|
||||
self.extracted_wheel_dir, 'pbr_testpackage')
|
||||
static_object_filename = 'testext.so'
|
||||
soabi = get_soabi()
|
||||
if soabi:
|
||||
static_object_filename = 'testext.{0}.so'.format(soabi)
|
||||
static_object_path = os.path.join(
|
||||
built_package_dir, static_object_filename)
|
||||
|
||||
self.assertTrue(os.path.exists(built_package_dir))
|
||||
self.assertTrue(os.path.exists(static_object_path))
|
||||
|
||||
|
||||
class TestPackagingHelpers(testtools.TestCase):
|
||||
|
||||
def test_generate_script(self):
|
||||
group = 'console_scripts'
|
||||
entry_point = pkg_resources.EntryPoint(
|
||||
name='test-ep',
|
||||
module_name='pbr.packaging',
|
||||
attrs=('LocalInstallScripts',))
|
||||
header = '#!/usr/bin/env fake-header\n'
|
||||
template = ('%(group)s %(module_name)s %(import_target)s '
|
||||
'%(invoke_target)s')
|
||||
|
||||
generated_script = packaging.generate_script(
|
||||
group, entry_point, header, template)
|
||||
|
||||
expected_script = (
|
||||
'#!/usr/bin/env fake-header\nconsole_scripts pbr.packaging '
|
||||
'LocalInstallScripts LocalInstallScripts'
|
||||
)
|
||||
self.assertEqual(expected_script, generated_script)
|
||||
|
||||
def test_generate_script_validates_expectations(self):
|
||||
group = 'console_scripts'
|
||||
entry_point = pkg_resources.EntryPoint(
|
||||
name='test-ep',
|
||||
module_name='pbr.packaging')
|
||||
header = '#!/usr/bin/env fake-header\n'
|
||||
template = ('%(group)s %(module_name)s %(import_target)s '
|
||||
'%(invoke_target)s')
|
||||
self.assertRaises(
|
||||
ValueError, packaging.generate_script, group, entry_point, header,
|
||||
template)
|
||||
|
||||
entry_point = pkg_resources.EntryPoint(
|
||||
name='test-ep',
|
||||
module_name='pbr.packaging',
|
||||
attrs=('attr1', 'attr2', 'attr3'))
|
||||
self.assertRaises(
|
||||
ValueError, packaging.generate_script, group, entry_point, header,
|
||||
template)
|
||||
|
||||
|
||||
class TestPackagingInPlainDirectory(base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestPackagingInPlainDirectory, self).setUp()
|
||||
|
||||
def test_authors(self):
|
||||
self.run_setup('sdist', allow_fail=False)
|
||||
# Not a git repo, no AUTHORS file created
|
||||
filename = os.path.join(self.package_dir, 'AUTHORS')
|
||||
self.assertFalse(os.path.exists(filename))
|
||||
|
||||
def test_changelog(self):
|
||||
self.run_setup('sdist', allow_fail=False)
|
||||
# Not a git repo, no ChangeLog created
|
||||
filename = os.path.join(self.package_dir, 'ChangeLog')
|
||||
self.assertFalse(os.path.exists(filename))
|
||||
|
||||
def test_install_no_ChangeLog(self):
|
||||
stdout, _, _ = self.run_setup(
|
||||
'install', '--root', self.temp_dir + 'installed',
|
||||
allow_fail=False)
|
||||
self.expectThat(
|
||||
stdout, matchers.Not(matchers.Contains('Generating ChangeLog')))
|
||||
|
||||
|
||||
class TestPresenceOfGit(base.BaseTestCase):
|
||||
|
||||
def testGitIsInstalled(self):
|
||||
with mock.patch.object(git,
|
||||
'_run_shell_command') as _command:
|
||||
_command.return_value = 'git version 1.8.4.1'
|
||||
self.assertEqual(True, git._git_is_installed())
|
||||
|
||||
def testGitIsNotInstalled(self):
|
||||
with mock.patch.object(git,
|
||||
'_run_shell_command') as _command:
|
||||
_command.side_effect = OSError
|
||||
self.assertEqual(False, git._git_is_installed())
|
||||
|
||||
|
||||
class ParseRequirementsTest(base.BaseTestCase):
|
||||
|
||||
def test_empty_requirements(self):
|
||||
actual = packaging.parse_requirements([])
|
||||
self.assertEqual([], actual)
|
||||
|
||||
def test_default_requirements(self):
|
||||
"""Ensure default files used if no files provided."""
|
||||
tempdir = tempfile.mkdtemp()
|
||||
requirements = os.path.join(tempdir, 'requirements.txt')
|
||||
with open(requirements, 'w') as f:
|
||||
f.write('pbr')
|
||||
# the defaults are relative to where pbr is called from so we need to
|
||||
# override them. This is OK, however, as we want to validate that
|
||||
# defaults are used - not what those defaults are
|
||||
with mock.patch.object(packaging, 'REQUIREMENTS_FILES', (
|
||||
requirements,)):
|
||||
result = packaging.parse_requirements()
|
||||
self.assertEqual(['pbr'], result)
|
||||
|
||||
def test_override_with_env(self):
|
||||
"""Ensure environment variable used if no files provided."""
|
||||
_, tmp_file = tempfile.mkstemp(prefix='openstack', suffix='.setup')
|
||||
with open(tmp_file, 'w') as fh:
|
||||
fh.write("foo\nbar")
|
||||
self.useFixture(
|
||||
fixtures.EnvironmentVariable('PBR_REQUIREMENTS_FILES', tmp_file))
|
||||
self.assertEqual(['foo', 'bar'],
|
||||
packaging.parse_requirements())
|
||||
|
||||
def test_override_with_env_multiple_files(self):
|
||||
_, tmp_file = tempfile.mkstemp(prefix='openstack', suffix='.setup')
|
||||
with open(tmp_file, 'w') as fh:
|
||||
fh.write("foo\nbar")
|
||||
self.useFixture(
|
||||
fixtures.EnvironmentVariable('PBR_REQUIREMENTS_FILES',
|
||||
"no-such-file," + tmp_file))
|
||||
self.assertEqual(['foo', 'bar'],
|
||||
packaging.parse_requirements())
|
||||
|
||||
def test_index_present(self):
|
||||
tempdir = tempfile.mkdtemp()
|
||||
requirements = os.path.join(tempdir, 'requirements.txt')
|
||||
with open(requirements, 'w') as f:
|
||||
f.write('-i https://myindex.local')
|
||||
f.write(' --index-url https://myindex.local')
|
||||
f.write(' --extra-index-url https://myindex.local')
|
||||
result = packaging.parse_requirements([requirements])
|
||||
self.assertEqual([], result)
|
||||
|
||||
def test_nested_requirements(self):
|
||||
tempdir = tempfile.mkdtemp()
|
||||
requirements = os.path.join(tempdir, 'requirements.txt')
|
||||
nested = os.path.join(tempdir, 'nested.txt')
|
||||
with open(requirements, 'w') as f:
|
||||
f.write('-r ' + nested)
|
||||
with open(nested, 'w') as f:
|
||||
f.write('pbr')
|
||||
result = packaging.parse_requirements([requirements])
|
||||
self.assertEqual(['pbr'], result)
|
||||
|
||||
|
||||
class ParseRequirementsTestScenarios(base.BaseTestCase):
|
||||
|
||||
versioned_scenarios = [
|
||||
('non-versioned', {'versioned': False, 'expected': ['bar']}),
|
||||
('versioned', {'versioned': True, 'expected': ['bar>=1.2.3']})
|
||||
]
|
||||
|
||||
subdirectory_scenarios = [
|
||||
('non-subdirectory', {'has_subdirectory': False}),
|
||||
('has-subdirectory', {'has_subdirectory': True})
|
||||
]
|
||||
|
||||
scenarios = [
|
||||
('normal', {'url': "foo\nbar", 'expected': ['foo', 'bar']}),
|
||||
('normal_with_comments', {
|
||||
'url': "# this is a comment\nfoo\n# and another one\nbar",
|
||||
'expected': ['foo', 'bar']}),
|
||||
('removes_index_lines', {'url': '-f foobar', 'expected': []}),
|
||||
]
|
||||
|
||||
scenarios = scenarios + testscenarios.multiply_scenarios([
|
||||
('ssh_egg_url', {'url': 'git+ssh://foo.com/zipball#egg=bar'}),
|
||||
('git_https_egg_url', {'url': 'git+https://foo.com/zipball#egg=bar'}),
|
||||
('http_egg_url', {'url': 'https://foo.com/zipball#egg=bar'}),
|
||||
], versioned_scenarios, subdirectory_scenarios)
|
||||
|
||||
scenarios = scenarios + testscenarios.multiply_scenarios(
|
||||
[
|
||||
('git_egg_url',
|
||||
{'url': 'git://foo.com/zipball#egg=bar', 'name': 'bar'})
|
||||
], [
|
||||
('non-editable', {'editable': False}),
|
||||
('editable', {'editable': True}),
|
||||
],
|
||||
versioned_scenarios, subdirectory_scenarios)
|
||||
|
||||
def test_parse_requirements(self):
|
||||
tmp_file = tempfile.NamedTemporaryFile()
|
||||
req_string = self.url
|
||||
if hasattr(self, 'editable') and self.editable:
|
||||
req_string = ("-e %s" % req_string)
|
||||
if hasattr(self, 'versioned') and self.versioned:
|
||||
req_string = ("%s-1.2.3" % req_string)
|
||||
if hasattr(self, 'has_subdirectory') and self.has_subdirectory:
|
||||
req_string = ("%s&subdirectory=baz" % req_string)
|
||||
with open(tmp_file.name, 'w') as fh:
|
||||
fh.write(req_string)
|
||||
self.assertEqual(self.expected,
|
||||
packaging.parse_requirements([tmp_file.name]))
|
||||
|
||||
|
||||
class ParseDependencyLinksTest(base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(ParseDependencyLinksTest, self).setUp()
|
||||
_, self.tmp_file = tempfile.mkstemp(prefix="openstack",
|
||||
suffix=".setup")
|
||||
|
||||
def test_parse_dependency_normal(self):
|
||||
with open(self.tmp_file, "w") as fh:
|
||||
fh.write("http://test.com\n")
|
||||
self.assertEqual(
|
||||
["http://test.com"],
|
||||
packaging.parse_dependency_links([self.tmp_file]))
|
||||
|
||||
def test_parse_dependency_with_git_egg_url(self):
|
||||
with open(self.tmp_file, "w") as fh:
|
||||
fh.write("-e git://foo.com/zipball#egg=bar")
|
||||
self.assertEqual(
|
||||
["git://foo.com/zipball#egg=bar"],
|
||||
packaging.parse_dependency_links([self.tmp_file]))
|
||||
|
||||
|
||||
class TestVersions(base.BaseTestCase):
|
||||
|
||||
scenarios = [
|
||||
('preversioned', dict(preversioned=True)),
|
||||
('postversioned', dict(preversioned=False)),
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
super(TestVersions, self).setUp()
|
||||
self.repo = self.useFixture(TestRepo(self.package_dir))
|
||||
self.useFixture(GPGKeyFixture())
|
||||
self.useFixture(base.DiveDir(self.package_dir))
|
||||
|
||||
def test_email_parsing_errors_are_handled(self):
|
||||
mocked_open = mock.mock_open()
|
||||
with mock.patch('pbr.packaging.open', mocked_open):
|
||||
with mock.patch('email.message_from_file') as message_from_file:
|
||||
message_from_file.side_effect = [
|
||||
email.errors.MessageError('Test'),
|
||||
{'Name': 'pbr_testpackage'}]
|
||||
version = packaging._get_version_from_pkg_metadata(
|
||||
'pbr_testpackage')
|
||||
|
||||
self.assertTrue(message_from_file.called)
|
||||
self.assertIsNone(version)
|
||||
|
||||
def test_capitalized_headers(self):
|
||||
self.repo.commit()
|
||||
self.repo.tag('1.2.3')
|
||||
self.repo.commit('Sem-Ver: api-break')
|
||||
version = packaging._get_version_from_git()
|
||||
self.assertThat(version, matchers.StartsWith('2.0.0.dev1'))
|
||||
|
||||
def test_capitalized_headers_partial(self):
|
||||
self.repo.commit()
|
||||
self.repo.tag('1.2.3')
|
||||
self.repo.commit('Sem-ver: api-break')
|
||||
version = packaging._get_version_from_git()
|
||||
self.assertThat(version, matchers.StartsWith('2.0.0.dev1'))
|
||||
|
||||
def test_tagged_version_has_tag_version(self):
|
||||
self.repo.commit()
|
||||
self.repo.tag('1.2.3')
|
||||
version = packaging._get_version_from_git('1.2.3')
|
||||
self.assertEqual('1.2.3', version)
|
||||
|
||||
def test_non_canonical_tagged_version_bump(self):
|
||||
self.repo.commit()
|
||||
self.repo.tag('1.4')
|
||||
self.repo.commit('Sem-Ver: api-break')
|
||||
version = packaging._get_version_from_git()
|
||||
self.assertThat(version, matchers.StartsWith('2.0.0.dev1'))
|
||||
|
||||
def test_untagged_version_has_dev_version_postversion(self):
|
||||
self.repo.commit()
|
||||
self.repo.tag('1.2.3')
|
||||
self.repo.commit()
|
||||
version = packaging._get_version_from_git()
|
||||
self.assertThat(version, matchers.StartsWith('1.2.4.dev1'))
|
||||
|
||||
def test_untagged_pre_release_has_pre_dev_version_postversion(self):
|
||||
self.repo.commit()
|
||||
self.repo.tag('1.2.3.0a1')
|
||||
self.repo.commit()
|
||||
version = packaging._get_version_from_git()
|
||||
self.assertThat(version, matchers.StartsWith('1.2.3.0a2.dev1'))
|
||||
|
||||
def test_untagged_version_minor_bump(self):
|
||||
self.repo.commit()
|
||||
self.repo.tag('1.2.3')
|
||||
self.repo.commit('sem-ver: deprecation')
|
||||
version = packaging._get_version_from_git()
|
||||
self.assertThat(version, matchers.StartsWith('1.3.0.dev1'))
|
||||
|
||||
def test_untagged_version_major_bump(self):
|
||||
self.repo.commit()
|
||||
self.repo.tag('1.2.3')
|
||||
self.repo.commit('sem-ver: api-break')
|
||||
version = packaging._get_version_from_git()
|
||||
self.assertThat(version, matchers.StartsWith('2.0.0.dev1'))
|
||||
|
||||
def test_untagged_version_has_dev_version_preversion(self):
|
||||
self.repo.commit()
|
||||
self.repo.tag('1.2.3')
|
||||
self.repo.commit()
|
||||
version = packaging._get_version_from_git('1.2.5')
|
||||
self.assertThat(version, matchers.StartsWith('1.2.5.dev1'))
|
||||
|
||||
def test_untagged_version_after_pre_has_dev_version_preversion(self):
|
||||
self.repo.commit()
|
||||
self.repo.tag('1.2.3.0a1')
|
||||
self.repo.commit()
|
||||
version = packaging._get_version_from_git('1.2.5')
|
||||
self.assertThat(version, matchers.StartsWith('1.2.5.dev1'))
|
||||
|
||||
def test_untagged_version_after_rc_has_dev_version_preversion(self):
|
||||
self.repo.commit()
|
||||
self.repo.tag('1.2.3.0a1')
|
||||
self.repo.commit()
|
||||
version = packaging._get_version_from_git('1.2.3')
|
||||
self.assertThat(version, matchers.StartsWith('1.2.3.0a2.dev1'))
|
||||
|
||||
def test_preversion_too_low_simple(self):
|
||||
# That is, the target version is either already released or not high
|
||||
# enough for the semver requirements given api breaks etc.
|
||||
self.repo.commit()
|
||||
self.repo.tag('1.2.3')
|
||||
self.repo.commit()
|
||||
# Note that we can't target 1.2.3 anymore - with 1.2.3 released we
|
||||
# need to be working on 1.2.4.
|
||||
err = self.assertRaises(
|
||||
ValueError, packaging._get_version_from_git, '1.2.3')
|
||||
self.assertThat(err.args[0], matchers.StartsWith('git history'))
|
||||
|
||||
def test_preversion_too_low_semver_headers(self):
|
||||
# That is, the target version is either already released or not high
|
||||
# enough for the semver requirements given api breaks etc.
|
||||
self.repo.commit()
|
||||
self.repo.tag('1.2.3')
|
||||
self.repo.commit('sem-ver: feature')
|
||||
# Note that we can't target 1.2.4, the feature header means we need
|
||||
# to be working on 1.3.0 or above.
|
||||
err = self.assertRaises(
|
||||
ValueError, packaging._get_version_from_git, '1.2.4')
|
||||
self.assertThat(err.args[0], matchers.StartsWith('git history'))
|
||||
|
||||
def test_get_kwargs_corner_cases(self):
|
||||
# No tags:
|
||||
git_dir = self.repo._basedir + '/.git'
|
||||
get_kwargs = lambda tag: packaging._get_increment_kwargs(git_dir, tag)
|
||||
|
||||
def _check_combinations(tag):
|
||||
self.repo.commit()
|
||||
self.assertEqual(dict(), get_kwargs(tag))
|
||||
self.repo.commit('sem-ver: bugfix')
|
||||
self.assertEqual(dict(), get_kwargs(tag))
|
||||
self.repo.commit('sem-ver: feature')
|
||||
self.assertEqual(dict(minor=True), get_kwargs(tag))
|
||||
self.repo.uncommit()
|
||||
self.repo.commit('sem-ver: deprecation')
|
||||
self.assertEqual(dict(minor=True), get_kwargs(tag))
|
||||
self.repo.uncommit()
|
||||
self.repo.commit('sem-ver: api-break')
|
||||
self.assertEqual(dict(major=True), get_kwargs(tag))
|
||||
self.repo.commit('sem-ver: deprecation')
|
||||
self.assertEqual(dict(major=True, minor=True), get_kwargs(tag))
|
||||
_check_combinations('')
|
||||
self.repo.tag('1.2.3')
|
||||
_check_combinations('1.2.3')
|
||||
|
||||
def test_invalid_tag_ignored(self):
|
||||
# Fix for bug 1356784 - we treated any tag as a version, not just those
|
||||
# that are valid versions.
|
||||
self.repo.commit()
|
||||
self.repo.tag('1')
|
||||
self.repo.commit()
|
||||
# when the tree is tagged and its wrong:
|
||||
self.repo.tag('badver')
|
||||
version = packaging._get_version_from_git()
|
||||
self.assertThat(version, matchers.StartsWith('1.0.1.dev1'))
|
||||
# When the tree isn't tagged, we also fall through.
|
||||
self.repo.commit()
|
||||
version = packaging._get_version_from_git()
|
||||
self.assertThat(version, matchers.StartsWith('1.0.1.dev2'))
|
||||
# We don't fall through x.y versions
|
||||
self.repo.commit()
|
||||
self.repo.tag('1.2')
|
||||
self.repo.commit()
|
||||
self.repo.tag('badver2')
|
||||
version = packaging._get_version_from_git()
|
||||
self.assertThat(version, matchers.StartsWith('1.2.1.dev1'))
|
||||
# Or x.y.z versions
|
||||
self.repo.commit()
|
||||
self.repo.tag('1.2.3')
|
||||
self.repo.commit()
|
||||
self.repo.tag('badver3')
|
||||
version = packaging._get_version_from_git()
|
||||
self.assertThat(version, matchers.StartsWith('1.2.4.dev1'))
|
||||
# Or alpha/beta/pre versions
|
||||
self.repo.commit()
|
||||
self.repo.tag('1.2.4.0a1')
|
||||
self.repo.commit()
|
||||
self.repo.tag('badver4')
|
||||
version = packaging._get_version_from_git()
|
||||
self.assertThat(version, matchers.StartsWith('1.2.4.0a2.dev1'))
|
||||
# Non-release related tags are ignored.
|
||||
self.repo.commit()
|
||||
self.repo.tag('2')
|
||||
self.repo.commit()
|
||||
self.repo.tag('non-release-tag/2014.12.16-1')
|
||||
version = packaging._get_version_from_git()
|
||||
self.assertThat(version, matchers.StartsWith('2.0.1.dev1'))
|
||||
|
||||
def test_valid_tag_honoured(self):
|
||||
# Fix for bug 1370608 - we converted any target into a 'dev version'
|
||||
# even if there was a distance of 0 - indicating that we were on the
|
||||
# tag itself.
|
||||
self.repo.commit()
|
||||
self.repo.tag('1.3.0.0a1')
|
||||
version = packaging._get_version_from_git()
|
||||
self.assertEqual('1.3.0.0a1', version)
|
||||
|
||||
def test_skip_write_git_changelog(self):
|
||||
# Fix for bug 1467440
|
||||
self.repo.commit()
|
||||
self.repo.tag('1.2.3')
|
||||
os.environ['SKIP_WRITE_GIT_CHANGELOG'] = '1'
|
||||
version = packaging._get_version_from_git('1.2.3')
|
||||
self.assertEqual('1.2.3', version)
|
||||
|
||||
def tearDown(self):
|
||||
super(TestVersions, self).tearDown()
|
||||
os.environ.pop('SKIP_WRITE_GIT_CHANGELOG', None)
|
||||
|
||||
|
||||
class TestRequirementParsing(base.BaseTestCase):
|
||||
|
||||
def test_requirement_parsing(self):
|
||||
pkgs = {
|
||||
'test_reqparse':
|
||||
{
|
||||
'requirements.txt': textwrap.dedent("""\
|
||||
bar
|
||||
quux<1.0; python_version=='2.6'
|
||||
requests-aws>=0.1.4 # BSD License (3 clause)
|
||||
Routes>=1.12.3,!=2.0,!=2.1;python_version=='2.7'
|
||||
requests-kerberos>=0.6;python_version=='2.7' # MIT
|
||||
"""),
|
||||
'setup.cfg': textwrap.dedent("""\
|
||||
[metadata]
|
||||
name = test_reqparse
|
||||
|
||||
[extras]
|
||||
test =
|
||||
foo
|
||||
baz>3.2 :python_version=='2.7' # MIT
|
||||
bar>3.3 :python_version=='2.7' # MIT # Apache
|
||||
""")},
|
||||
}
|
||||
pkg_dirs = self.useFixture(CreatePackages(pkgs)).package_dirs
|
||||
pkg_dir = pkg_dirs['test_reqparse']
|
||||
# pkg_resources.split_sections uses None as the title of an
|
||||
# anonymous section instead of the empty string. Weird.
|
||||
expected_requirements = {
|
||||
None: ['bar', 'requests-aws>=0.1.4'],
|
||||
":(python_version=='2.6')": ['quux<1.0'],
|
||||
":(python_version=='2.7')": ['Routes!=2.0,!=2.1,>=1.12.3',
|
||||
'requests-kerberos>=0.6'],
|
||||
'test': ['foo'],
|
||||
"test:(python_version=='2.7')": ['baz>3.2', 'bar>3.3']
|
||||
}
|
||||
venv = self.useFixture(Venv('reqParse'))
|
||||
bin_python = venv.python
|
||||
# Two things are tested by this
|
||||
# 1) pbr properly parses markers from requiremnts.txt and setup.cfg
|
||||
# 2) bdist_wheel causes pbr to not evaluate markers
|
||||
self._run_cmd(bin_python, ('setup.py', 'bdist_wheel'),
|
||||
allow_fail=False, cwd=pkg_dir)
|
||||
egg_info = os.path.join(pkg_dir, 'test_reqparse.egg-info')
|
||||
|
||||
requires_txt = os.path.join(egg_info, 'requires.txt')
|
||||
with open(requires_txt, 'rt') as requires:
|
||||
generated_requirements = dict(
|
||||
pkg_resources.split_sections(requires))
|
||||
|
||||
# NOTE(dhellmann): We have to spell out the comparison because
|
||||
# the rendering for version specifiers in a range is not
|
||||
# consistent across versions of setuptools.
|
||||
|
||||
for section, expected in expected_requirements.items():
|
||||
exp_parsed = [
|
||||
pkg_resources.Requirement.parse(s)
|
||||
for s in expected
|
||||
]
|
||||
gen_parsed = [
|
||||
pkg_resources.Requirement.parse(s)
|
||||
for s in generated_requirements[section]
|
||||
]
|
||||
self.assertEqual(exp_parsed, gen_parsed)
|
||||
|
||||
|
||||
def get_soabi():
|
||||
soabi = None
|
||||
try:
|
||||
soabi = sysconfig.get_config_var('SOABI')
|
||||
arch = sysconfig.get_config_var('MULTIARCH')
|
||||
except IOError:
|
||||
pass
|
||||
if soabi and arch and 'pypy' in sysconfig.get_scheme_names():
|
||||
soabi = '%s-%s' % (soabi, arch)
|
||||
if soabi is None and 'pypy' in sysconfig.get_scheme_names():
|
||||
# NOTE(sigmavirus24): PyPy only added support for the SOABI config var
|
||||
# to sysconfig in 2015. That was well after 2.2.1 was published in the
|
||||
# Ubuntu 14.04 archive.
|
||||
for suffix, _, _ in imp.get_suffixes():
|
||||
if suffix.startswith('.pypy') and suffix.endswith('.so'):
|
||||
soabi = suffix.split('.')[1]
|
||||
break
|
||||
return soabi
|
30
libs/common/pbr/tests/test_pbr_json.py
Normal file
30
libs/common/pbr/tests/test_pbr_json.py
Normal file
|
@ -0,0 +1,30 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import mock
|
||||
|
||||
from pbr import pbr_json
|
||||
from pbr.tests import base
|
||||
|
||||
|
||||
class TestJsonContent(base.BaseTestCase):
|
||||
@mock.patch('pbr.git._run_git_functions', return_value=True)
|
||||
@mock.patch('pbr.git.get_git_short_sha', return_value="123456")
|
||||
@mock.patch('pbr.git.get_is_release', return_value=True)
|
||||
def test_content(self, mock_get_is, mock_get_git, mock_run):
|
||||
cmd = mock.Mock()
|
||||
pbr_json.write_pbr_json(cmd, "basename", "pbr.json")
|
||||
cmd.write_file.assert_called_once_with(
|
||||
'pbr',
|
||||
'pbr.json',
|
||||
'{"git_version": "123456", "is_release": true}'
|
||||
)
|
445
libs/common/pbr/tests/test_setup.py
Normal file
445
libs/common/pbr/tests/test_setup.py
Normal file
|
@ -0,0 +1,445 @@
|
|||
# Copyright (c) 2011 OpenStack Foundation
|
||||
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
|
||||
try:
|
||||
import cStringIO as io
|
||||
BytesIO = io.StringIO
|
||||
except ImportError:
|
||||
import io
|
||||
BytesIO = io.BytesIO
|
||||
|
||||
import fixtures
|
||||
|
||||
from pbr import git
|
||||
from pbr import options
|
||||
from pbr import packaging
|
||||
from pbr.tests import base
|
||||
|
||||
|
||||
class SkipFileWrites(base.BaseTestCase):
|
||||
|
||||
scenarios = [
|
||||
('changelog_option_true',
|
||||
dict(option_key='skip_changelog', option_value='True',
|
||||
env_key='SKIP_WRITE_GIT_CHANGELOG', env_value=None,
|
||||
pkg_func=git.write_git_changelog, filename='ChangeLog')),
|
||||
('changelog_option_false',
|
||||
dict(option_key='skip_changelog', option_value='False',
|
||||
env_key='SKIP_WRITE_GIT_CHANGELOG', env_value=None,
|
||||
pkg_func=git.write_git_changelog, filename='ChangeLog')),
|
||||
('changelog_env_true',
|
||||
dict(option_key='skip_changelog', option_value='False',
|
||||
env_key='SKIP_WRITE_GIT_CHANGELOG', env_value='True',
|
||||
pkg_func=git.write_git_changelog, filename='ChangeLog')),
|
||||
('changelog_both_true',
|
||||
dict(option_key='skip_changelog', option_value='True',
|
||||
env_key='SKIP_WRITE_GIT_CHANGELOG', env_value='True',
|
||||
pkg_func=git.write_git_changelog, filename='ChangeLog')),
|
||||
('authors_option_true',
|
||||
dict(option_key='skip_authors', option_value='True',
|
||||
env_key='SKIP_GENERATE_AUTHORS', env_value=None,
|
||||
pkg_func=git.generate_authors, filename='AUTHORS')),
|
||||
('authors_option_false',
|
||||
dict(option_key='skip_authors', option_value='False',
|
||||
env_key='SKIP_GENERATE_AUTHORS', env_value=None,
|
||||
pkg_func=git.generate_authors, filename='AUTHORS')),
|
||||
('authors_env_true',
|
||||
dict(option_key='skip_authors', option_value='False',
|
||||
env_key='SKIP_GENERATE_AUTHORS', env_value='True',
|
||||
pkg_func=git.generate_authors, filename='AUTHORS')),
|
||||
('authors_both_true',
|
||||
dict(option_key='skip_authors', option_value='True',
|
||||
env_key='SKIP_GENERATE_AUTHORS', env_value='True',
|
||||
pkg_func=git.generate_authors, filename='AUTHORS')),
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
super(SkipFileWrites, self).setUp()
|
||||
self.temp_path = self.useFixture(fixtures.TempDir()).path
|
||||
self.root_dir = os.path.abspath(os.path.curdir)
|
||||
self.git_dir = os.path.join(self.root_dir, ".git")
|
||||
if not os.path.exists(self.git_dir):
|
||||
self.skipTest("%s is missing; skipping git-related checks"
|
||||
% self.git_dir)
|
||||
return
|
||||
self.filename = os.path.join(self.temp_path, self.filename)
|
||||
self.option_dict = dict()
|
||||
if self.option_key is not None:
|
||||
self.option_dict[self.option_key] = ('setup.cfg',
|
||||
self.option_value)
|
||||
self.useFixture(
|
||||
fixtures.EnvironmentVariable(self.env_key, self.env_value))
|
||||
|
||||
def test_skip(self):
|
||||
self.pkg_func(git_dir=self.git_dir,
|
||||
dest_dir=self.temp_path,
|
||||
option_dict=self.option_dict)
|
||||
self.assertEqual(
|
||||
not os.path.exists(self.filename),
|
||||
(self.option_value.lower() in options.TRUE_VALUES
|
||||
or self.env_value is not None))
|
||||
|
||||
_changelog_content = """7780758\x00Break parser\x00 (tag: refs/tags/1_foo.1)
|
||||
04316fe\x00Make python\x00 (refs/heads/review/monty_taylor/27519)
|
||||
378261a\x00Add an integration test script.\x00
|
||||
3c373ac\x00Merge "Lib\x00 (HEAD, tag: refs/tags/2013.2.rc2, tag: refs/tags/2013.2, refs/heads/mile-proposed)
|
||||
182feb3\x00Fix pip invocation for old versions of pip.\x00 (tag: refs/tags/0.5.17)
|
||||
fa4f46e\x00Remove explicit depend on distribute.\x00 (tag: refs/tags/0.5.16)
|
||||
d1c53dd\x00Use pip instead of easy_install for installation.\x00
|
||||
a793ea1\x00Merge "Skip git-checkout related tests when .git is missing"\x00
|
||||
6c27ce7\x00Skip git-checkout related tests when .git is missing\x00
|
||||
451e513\x00Bug fix: create_stack() fails when waiting\x00
|
||||
4c8cfe4\x00Improve test coverage: network delete API\x00 (tag: refs/tags/(evil))
|
||||
d7e6167\x00Bug fix: Fix pass thru filtering in list_networks\x00 (tag: refs/tags/ev()il)
|
||||
c47ec15\x00Consider 'in-use' a non-pending volume for caching\x00 (tag: refs/tags/ev)il)
|
||||
8696fbd\x00Improve test coverage: private extension API\x00 (tag: refs/tags/ev(il)
|
||||
f0440f8\x00Improve test coverage: hypervisor list\x00 (tag: refs/tags/e(vi)l)
|
||||
04984a5\x00Refactor hooks file.\x00 (HEAD, tag: 0.6.7,b, tag: refs/tags/(12), refs/heads/master)
|
||||
a65e8ee\x00Remove jinja pin.\x00 (tag: refs/tags/0.5.14, tag: refs/tags/0.5.13)
|
||||
""" # noqa
|
||||
|
||||
|
||||
def _make_old_git_changelog_format(line):
|
||||
"""Convert post-1.8.1 git log format to pre-1.8.1 git log format"""
|
||||
|
||||
if not line.strip():
|
||||
return line
|
||||
sha, msg, refname = line.split('\x00')
|
||||
refname = refname.replace('tag: ', '')
|
||||
return '\x00'.join((sha, msg, refname))
|
||||
|
||||
_old_git_changelog_content = '\n'.join(
|
||||
_make_old_git_changelog_format(line)
|
||||
for line in _changelog_content.split('\n'))
|
||||
|
||||
|
||||
class GitLogsTest(base.BaseTestCase):
|
||||
|
||||
scenarios = [
|
||||
('pre1.8.3', {'changelog': _old_git_changelog_content}),
|
||||
('post1.8.3', {'changelog': _changelog_content}),
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
super(GitLogsTest, self).setUp()
|
||||
self.temp_path = self.useFixture(fixtures.TempDir()).path
|
||||
self.root_dir = os.path.abspath(os.path.curdir)
|
||||
self.git_dir = os.path.join(self.root_dir, ".git")
|
||||
self.useFixture(
|
||||
fixtures.EnvironmentVariable('SKIP_GENERATE_AUTHORS'))
|
||||
self.useFixture(
|
||||
fixtures.EnvironmentVariable('SKIP_WRITE_GIT_CHANGELOG'))
|
||||
|
||||
def test_write_git_changelog(self):
|
||||
self.useFixture(fixtures.FakePopen(lambda _: {
|
||||
"stdout": BytesIO(self.changelog.encode('utf-8'))
|
||||
}))
|
||||
|
||||
git.write_git_changelog(git_dir=self.git_dir,
|
||||
dest_dir=self.temp_path)
|
||||
|
||||
with open(os.path.join(self.temp_path, "ChangeLog"), "r") as ch_fh:
|
||||
changelog_contents = ch_fh.read()
|
||||
self.assertIn("2013.2", changelog_contents)
|
||||
self.assertIn("0.5.17", changelog_contents)
|
||||
self.assertIn("------", changelog_contents)
|
||||
self.assertIn("Refactor hooks file", changelog_contents)
|
||||
self.assertIn(
|
||||
"Bug fix: create\_stack() fails when waiting",
|
||||
changelog_contents)
|
||||
self.assertNotIn("Refactor hooks file.", changelog_contents)
|
||||
self.assertNotIn("182feb3", changelog_contents)
|
||||
self.assertNotIn("review/monty_taylor/27519", changelog_contents)
|
||||
self.assertNotIn("0.5.13", changelog_contents)
|
||||
self.assertNotIn("0.6.7", changelog_contents)
|
||||
self.assertNotIn("12", changelog_contents)
|
||||
self.assertNotIn("(evil)", changelog_contents)
|
||||
self.assertNotIn("ev()il", changelog_contents)
|
||||
self.assertNotIn("ev(il", changelog_contents)
|
||||
self.assertNotIn("ev)il", changelog_contents)
|
||||
self.assertNotIn("e(vi)l", changelog_contents)
|
||||
self.assertNotIn('Merge "', changelog_contents)
|
||||
self.assertNotIn('1\_foo.1', changelog_contents)
|
||||
|
||||
def test_generate_authors(self):
|
||||
author_old = u"Foo Foo <email@foo.com>"
|
||||
author_new = u"Bar Bar <email@bar.com>"
|
||||
co_author = u"Foo Bar <foo@bar.com>"
|
||||
co_author_by = u"Co-authored-by: " + co_author
|
||||
|
||||
git_log_cmd = (
|
||||
"git --git-dir=%s log --format=%%aN <%%aE>"
|
||||
% self.git_dir)
|
||||
git_co_log_cmd = ("git --git-dir=%s log" % self.git_dir)
|
||||
git_top_level = "git rev-parse --show-toplevel"
|
||||
cmd_map = {
|
||||
git_log_cmd: author_new,
|
||||
git_co_log_cmd: co_author_by,
|
||||
git_top_level: self.root_dir,
|
||||
}
|
||||
|
||||
exist_files = [self.git_dir,
|
||||
os.path.join(self.temp_path, "AUTHORS.in")]
|
||||
self.useFixture(fixtures.MonkeyPatch(
|
||||
"os.path.exists",
|
||||
lambda path: os.path.abspath(path) in exist_files))
|
||||
|
||||
def _fake_run_shell_command(cmd, **kwargs):
|
||||
return cmd_map[" ".join(cmd)]
|
||||
|
||||
self.useFixture(fixtures.MonkeyPatch(
|
||||
"pbr.git._run_shell_command",
|
||||
_fake_run_shell_command))
|
||||
|
||||
with open(os.path.join(self.temp_path, "AUTHORS.in"), "w") as auth_fh:
|
||||
auth_fh.write("%s\n" % author_old)
|
||||
|
||||
git.generate_authors(git_dir=self.git_dir,
|
||||
dest_dir=self.temp_path)
|
||||
|
||||
with open(os.path.join(self.temp_path, "AUTHORS"), "r") as auth_fh:
|
||||
authors = auth_fh.read()
|
||||
self.assertTrue(author_old in authors)
|
||||
self.assertTrue(author_new in authors)
|
||||
self.assertTrue(co_author in authors)
|
||||
|
||||
|
||||
class _SphinxConfig(object):
|
||||
man_pages = ['foo']
|
||||
|
||||
|
||||
class BaseSphinxTest(base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(BaseSphinxTest, self).setUp()
|
||||
|
||||
# setup_command requires the Sphinx instance to have some
|
||||
# attributes that aren't set normally with the way we use the
|
||||
# class (because we replace the constructor). Add default
|
||||
# values directly to the class definition.
|
||||
import sphinx.application
|
||||
sphinx.application.Sphinx.messagelog = []
|
||||
sphinx.application.Sphinx.statuscode = 0
|
||||
|
||||
self.useFixture(fixtures.MonkeyPatch(
|
||||
"sphinx.application.Sphinx.__init__", lambda *a, **kw: None))
|
||||
self.useFixture(fixtures.MonkeyPatch(
|
||||
"sphinx.application.Sphinx.build", lambda *a, **kw: None))
|
||||
self.useFixture(fixtures.MonkeyPatch(
|
||||
"sphinx.application.Sphinx.config", _SphinxConfig))
|
||||
self.useFixture(fixtures.MonkeyPatch(
|
||||
"sphinx.config.Config.init_values", lambda *a: None))
|
||||
self.useFixture(fixtures.MonkeyPatch(
|
||||
"sphinx.config.Config.__init__", lambda *a: None))
|
||||
from distutils import dist
|
||||
self.distr = dist.Distribution()
|
||||
self.distr.packages = ("fake_package",)
|
||||
self.distr.command_options["build_sphinx"] = {
|
||||
"source_dir": ["a", "."]}
|
||||
pkg_fixture = fixtures.PythonPackage(
|
||||
"fake_package", [("fake_module.py", b""),
|
||||
("another_fake_module_for_testing.py", b""),
|
||||
("fake_private_module.py", b"")])
|
||||
self.useFixture(pkg_fixture)
|
||||
self.useFixture(base.DiveDir(pkg_fixture.base))
|
||||
self.distr.command_options["pbr"] = {}
|
||||
if hasattr(self, "excludes"):
|
||||
self.distr.command_options["pbr"]["autodoc_exclude_modules"] = (
|
||||
'setup.cfg',
|
||||
"fake_package.fake_private_module\n"
|
||||
"fake_package.another_fake_*\n"
|
||||
"fake_package.unknown_module")
|
||||
if hasattr(self, 'has_opt') and self.has_opt:
|
||||
options = self.distr.command_options["pbr"]
|
||||
options["autodoc_index_modules"] = ('setup.cfg', self.autodoc)
|
||||
|
||||
|
||||
class BuildSphinxTest(BaseSphinxTest):
|
||||
|
||||
scenarios = [
|
||||
('true_autodoc_caps',
|
||||
dict(has_opt=True, autodoc='True', has_autodoc=True)),
|
||||
('true_autodoc_caps_with_excludes',
|
||||
dict(has_opt=True, autodoc='True', has_autodoc=True,
|
||||
excludes="fake_package.fake_private_module\n"
|
||||
"fake_package.another_fake_*\n"
|
||||
"fake_package.unknown_module")),
|
||||
('true_autodoc_lower',
|
||||
dict(has_opt=True, autodoc='true', has_autodoc=True)),
|
||||
('false_autodoc',
|
||||
dict(has_opt=True, autodoc='False', has_autodoc=False)),
|
||||
('no_autodoc',
|
||||
dict(has_opt=False, autodoc='False', has_autodoc=False)),
|
||||
]
|
||||
|
||||
def test_build_doc(self):
|
||||
build_doc = packaging.LocalBuildDoc(self.distr)
|
||||
build_doc.run()
|
||||
|
||||
self.assertTrue(
|
||||
os.path.exists("api/autoindex.rst") == self.has_autodoc)
|
||||
self.assertTrue(
|
||||
os.path.exists(
|
||||
"api/fake_package.fake_module.rst") == self.has_autodoc)
|
||||
if not self.has_autodoc or hasattr(self, "excludes"):
|
||||
assertion = self.assertFalse
|
||||
else:
|
||||
assertion = self.assertTrue
|
||||
assertion(
|
||||
os.path.exists(
|
||||
"api/fake_package.fake_private_module.rst"))
|
||||
assertion(
|
||||
os.path.exists(
|
||||
"api/fake_package.another_fake_module_for_testing.rst"))
|
||||
|
||||
def test_builders_config(self):
|
||||
build_doc = packaging.LocalBuildDoc(self.distr)
|
||||
build_doc.finalize_options()
|
||||
|
||||
self.assertEqual(1, len(build_doc.builders))
|
||||
self.assertIn('html', build_doc.builders)
|
||||
|
||||
build_doc = packaging.LocalBuildDoc(self.distr)
|
||||
build_doc.builders = ''
|
||||
build_doc.finalize_options()
|
||||
|
||||
self.assertEqual('', build_doc.builders)
|
||||
|
||||
build_doc = packaging.LocalBuildDoc(self.distr)
|
||||
build_doc.builders = 'man'
|
||||
build_doc.finalize_options()
|
||||
|
||||
self.assertEqual(1, len(build_doc.builders))
|
||||
self.assertIn('man', build_doc.builders)
|
||||
|
||||
build_doc = packaging.LocalBuildDoc(self.distr)
|
||||
build_doc.builders = 'html,man,doctest'
|
||||
build_doc.finalize_options()
|
||||
|
||||
self.assertIn('html', build_doc.builders)
|
||||
self.assertIn('man', build_doc.builders)
|
||||
self.assertIn('doctest', build_doc.builders)
|
||||
|
||||
def test_cmd_builder_override(self):
|
||||
|
||||
if self.has_opt:
|
||||
self.distr.command_options["pbr"] = {
|
||||
"autodoc_index_modules": ('setup.cfg', self.autodoc)
|
||||
}
|
||||
|
||||
self.distr.command_options["build_sphinx"]["builder"] = (
|
||||
"command line", "non-existing-builder")
|
||||
|
||||
build_doc = packaging.LocalBuildDoc(self.distr)
|
||||
self.assertNotIn('non-existing-builder', build_doc.builders)
|
||||
self.assertIn('html', build_doc.builders)
|
||||
|
||||
# process command line options which should override config
|
||||
build_doc.finalize_options()
|
||||
|
||||
self.assertIn('non-existing-builder', build_doc.builders)
|
||||
self.assertNotIn('html', build_doc.builders)
|
||||
|
||||
def test_cmd_builder_override_multiple_builders(self):
|
||||
|
||||
if self.has_opt:
|
||||
self.distr.command_options["pbr"] = {
|
||||
"autodoc_index_modules": ('setup.cfg', self.autodoc)
|
||||
}
|
||||
|
||||
self.distr.command_options["build_sphinx"]["builder"] = (
|
||||
"command line", "builder1,builder2")
|
||||
|
||||
build_doc = packaging.LocalBuildDoc(self.distr)
|
||||
build_doc.finalize_options()
|
||||
|
||||
self.assertEqual(["builder1", "builder2"], build_doc.builders)
|
||||
|
||||
|
||||
class APIAutoDocTest(base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(APIAutoDocTest, self).setUp()
|
||||
|
||||
# setup_command requires the Sphinx instance to have some
|
||||
# attributes that aren't set normally with the way we use the
|
||||
# class (because we replace the constructor). Add default
|
||||
# values directly to the class definition.
|
||||
import sphinx.application
|
||||
sphinx.application.Sphinx.messagelog = []
|
||||
sphinx.application.Sphinx.statuscode = 0
|
||||
|
||||
self.useFixture(fixtures.MonkeyPatch(
|
||||
"sphinx.application.Sphinx.__init__", lambda *a, **kw: None))
|
||||
self.useFixture(fixtures.MonkeyPatch(
|
||||
"sphinx.application.Sphinx.build", lambda *a, **kw: None))
|
||||
self.useFixture(fixtures.MonkeyPatch(
|
||||
"sphinx.application.Sphinx.config", _SphinxConfig))
|
||||
self.useFixture(fixtures.MonkeyPatch(
|
||||
"sphinx.config.Config.init_values", lambda *a: None))
|
||||
self.useFixture(fixtures.MonkeyPatch(
|
||||
"sphinx.config.Config.__init__", lambda *a: None))
|
||||
from distutils import dist
|
||||
self.distr = dist.Distribution()
|
||||
self.distr.packages = ("fake_package",)
|
||||
self.distr.command_options["build_sphinx"] = {
|
||||
"source_dir": ["a", "."]}
|
||||
self.sphinx_options = self.distr.command_options["build_sphinx"]
|
||||
pkg_fixture = fixtures.PythonPackage(
|
||||
"fake_package", [("fake_module.py", b""),
|
||||
("another_fake_module_for_testing.py", b""),
|
||||
("fake_private_module.py", b"")])
|
||||
self.useFixture(pkg_fixture)
|
||||
self.useFixture(base.DiveDir(pkg_fixture.base))
|
||||
self.pbr_options = self.distr.command_options.setdefault('pbr', {})
|
||||
self.pbr_options["autodoc_index_modules"] = ('setup.cfg', 'True')
|
||||
|
||||
def test_default_api_build_dir(self):
|
||||
build_doc = packaging.LocalBuildDoc(self.distr)
|
||||
build_doc.run()
|
||||
|
||||
print('PBR OPTIONS:', self.pbr_options)
|
||||
print('DISTR OPTIONS:', self.distr.command_options)
|
||||
|
||||
self.assertTrue(os.path.exists("api/autoindex.rst"))
|
||||
self.assertTrue(os.path.exists("api/fake_package.fake_module.rst"))
|
||||
self.assertTrue(
|
||||
os.path.exists(
|
||||
"api/fake_package.fake_private_module.rst"))
|
||||
self.assertTrue(
|
||||
os.path.exists(
|
||||
"api/fake_package.another_fake_module_for_testing.rst"))
|
||||
|
||||
def test_different_api_build_dir(self):
|
||||
# Options have to come out of the settings dict as a tuple
|
||||
# showing the source and the value.
|
||||
self.pbr_options['api_doc_dir'] = (None, 'contributor/api')
|
||||
build_doc = packaging.LocalBuildDoc(self.distr)
|
||||
build_doc.run()
|
||||
|
||||
print('PBR OPTIONS:', self.pbr_options)
|
||||
print('DISTR OPTIONS:', self.distr.command_options)
|
||||
|
||||
self.assertTrue(os.path.exists("contributor/api/autoindex.rst"))
|
||||
self.assertTrue(
|
||||
os.path.exists("contributor/api/fake_package.fake_module.rst"))
|
||||
self.assertTrue(
|
||||
os.path.exists(
|
||||
"contributor/api/fake_package.fake_private_module.rst"))
|
91
libs/common/pbr/tests/test_util.py
Normal file
91
libs/common/pbr/tests/test_util.py
Normal file
|
@ -0,0 +1,91 @@
|
|||
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. (HP)
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import io
|
||||
import textwrap
|
||||
|
||||
import six
|
||||
from six.moves import configparser
|
||||
import sys
|
||||
|
||||
from pbr.tests import base
|
||||
from pbr import util
|
||||
|
||||
|
||||
class TestExtrasRequireParsingScenarios(base.BaseTestCase):
|
||||
|
||||
scenarios = [
|
||||
('simple_extras', {
|
||||
'config_text': """
|
||||
[extras]
|
||||
first =
|
||||
foo
|
||||
bar==1.0
|
||||
second =
|
||||
baz>=3.2
|
||||
foo
|
||||
""",
|
||||
'expected_extra_requires': {
|
||||
'first': ['foo', 'bar==1.0'],
|
||||
'second': ['baz>=3.2', 'foo'],
|
||||
'test': ['requests-mock'],
|
||||
"test:(python_version=='2.6')": ['ordereddict'],
|
||||
}
|
||||
}),
|
||||
('with_markers', {
|
||||
'config_text': """
|
||||
[extras]
|
||||
test =
|
||||
foo:python_version=='2.6'
|
||||
bar
|
||||
baz<1.6 :python_version=='2.6'
|
||||
zaz :python_version>'1.0'
|
||||
""",
|
||||
'expected_extra_requires': {
|
||||
"test:(python_version=='2.6')": ['foo', 'baz<1.6'],
|
||||
"test": ['bar', 'zaz']}}),
|
||||
('no_extras', {
|
||||
'config_text': """
|
||||
[metadata]
|
||||
long_description = foo
|
||||
""",
|
||||
'expected_extra_requires':
|
||||
{}
|
||||
})]
|
||||
|
||||
def config_from_ini(self, ini):
|
||||
config = {}
|
||||
if sys.version_info >= (3, 2):
|
||||
parser = configparser.ConfigParser()
|
||||
else:
|
||||
parser = configparser.SafeConfigParser()
|
||||
ini = textwrap.dedent(six.u(ini))
|
||||
parser.readfp(io.StringIO(ini))
|
||||
for section in parser.sections():
|
||||
config[section] = dict(parser.items(section))
|
||||
return config
|
||||
|
||||
def test_extras_parsing(self):
|
||||
config = self.config_from_ini(self.config_text)
|
||||
kwargs = util.setup_cfg_to_setup_kwargs(config)
|
||||
|
||||
self.assertEqual(self.expected_extra_requires,
|
||||
kwargs['extras_require'])
|
||||
|
||||
|
||||
class TestInvalidMarkers(base.BaseTestCase):
|
||||
|
||||
def test_invalid_marker_raises_error(self):
|
||||
config = {'extras': {'test': "foo :bad_marker>'1.0'"}}
|
||||
self.assertRaises(SyntaxError, util.setup_cfg_to_setup_kwargs, config)
|
311
libs/common/pbr/tests/test_version.py
Normal file
311
libs/common/pbr/tests/test_version.py
Normal file
|
@ -0,0 +1,311 @@
|
|||
# Copyright 2012 Red Hat, Inc.
|
||||
# Copyright 2012-2013 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import itertools
|
||||
|
||||
from testtools import matchers
|
||||
|
||||
from pbr.tests import base
|
||||
from pbr import version
|
||||
|
||||
|
||||
from_pip_string = version.SemanticVersion.from_pip_string
|
||||
|
||||
|
||||
class TestSemanticVersion(base.BaseTestCase):
|
||||
|
||||
def test_ordering(self):
|
||||
ordered_versions = [
|
||||
"1.2.3.dev6",
|
||||
"1.2.3.dev7",
|
||||
"1.2.3.a4.dev12",
|
||||
"1.2.3.a4.dev13",
|
||||
"1.2.3.a4",
|
||||
"1.2.3.a5.dev1",
|
||||
"1.2.3.a5",
|
||||
"1.2.3.b3.dev1",
|
||||
"1.2.3.b3",
|
||||
"1.2.3.rc2.dev1",
|
||||
"1.2.3.rc2",
|
||||
"1.2.3.rc3.dev1",
|
||||
"1.2.3",
|
||||
"1.2.4",
|
||||
"1.3.3",
|
||||
"2.2.3",
|
||||
]
|
||||
for v in ordered_versions:
|
||||
sv = version.SemanticVersion.from_pip_string(v)
|
||||
self.expectThat(sv, matchers.Equals(sv))
|
||||
for left, right in itertools.combinations(ordered_versions, 2):
|
||||
l_pos = ordered_versions.index(left)
|
||||
r_pos = ordered_versions.index(right)
|
||||
if l_pos < r_pos:
|
||||
m1 = matchers.LessThan
|
||||
m2 = matchers.GreaterThan
|
||||
else:
|
||||
m1 = matchers.GreaterThan
|
||||
m2 = matchers.LessThan
|
||||
left_sv = version.SemanticVersion.from_pip_string(left)
|
||||
right_sv = version.SemanticVersion.from_pip_string(right)
|
||||
self.expectThat(left_sv, m1(right_sv))
|
||||
self.expectThat(right_sv, m2(left_sv))
|
||||
|
||||
def test_from_pip_string_legacy_alpha(self):
|
||||
expected = version.SemanticVersion(
|
||||
1, 2, 0, prerelease_type='rc', prerelease=1)
|
||||
parsed = from_pip_string('1.2.0rc1')
|
||||
self.assertEqual(expected, parsed)
|
||||
|
||||
def test_from_pip_string_legacy_postN(self):
|
||||
# When pbr trunk was incompatible with PEP-440, a stable release was
|
||||
# made that used postN versions to represent developer builds. As
|
||||
# we expect only to be parsing versions of our own, we map those
|
||||
# into dev builds of the next version.
|
||||
expected = version.SemanticVersion(1, 2, 4, dev_count=5)
|
||||
parsed = from_pip_string('1.2.3.post5')
|
||||
self.expectThat(expected, matchers.Equals(parsed))
|
||||
expected = version.SemanticVersion(1, 2, 3, 'a', 5, dev_count=6)
|
||||
parsed = from_pip_string('1.2.3.0a4.post6')
|
||||
self.expectThat(expected, matchers.Equals(parsed))
|
||||
# We can't define a mapping for .postN.devM, so it should raise.
|
||||
self.expectThat(
|
||||
lambda: from_pip_string('1.2.3.post5.dev6'),
|
||||
matchers.raises(ValueError))
|
||||
|
||||
def test_from_pip_string_v_version(self):
|
||||
parsed = from_pip_string('v1.2.3')
|
||||
expected = version.SemanticVersion(1, 2, 3)
|
||||
self.expectThat(expected, matchers.Equals(parsed))
|
||||
|
||||
expected = version.SemanticVersion(1, 2, 3, 'a', 5, dev_count=6)
|
||||
parsed = from_pip_string('V1.2.3.0a4.post6')
|
||||
self.expectThat(expected, matchers.Equals(parsed))
|
||||
|
||||
self.expectThat(
|
||||
lambda: from_pip_string('x1.2.3'),
|
||||
matchers.raises(ValueError))
|
||||
|
||||
def test_from_pip_string_legacy_nonzero_lead_in(self):
|
||||
# reported in bug 1361251
|
||||
expected = version.SemanticVersion(
|
||||
0, 0, 1, prerelease_type='a', prerelease=2)
|
||||
parsed = from_pip_string('0.0.1a2')
|
||||
self.assertEqual(expected, parsed)
|
||||
|
||||
def test_from_pip_string_legacy_short_nonzero_lead_in(self):
|
||||
expected = version.SemanticVersion(
|
||||
0, 1, 0, prerelease_type='a', prerelease=2)
|
||||
parsed = from_pip_string('0.1a2')
|
||||
self.assertEqual(expected, parsed)
|
||||
|
||||
def test_from_pip_string_legacy_no_0_prerelease(self):
|
||||
expected = version.SemanticVersion(
|
||||
2, 1, 0, prerelease_type='rc', prerelease=1)
|
||||
parsed = from_pip_string('2.1.0.rc1')
|
||||
self.assertEqual(expected, parsed)
|
||||
|
||||
def test_from_pip_string_legacy_no_0_prerelease_2(self):
|
||||
expected = version.SemanticVersion(
|
||||
2, 0, 0, prerelease_type='rc', prerelease=1)
|
||||
parsed = from_pip_string('2.0.0.rc1')
|
||||
self.assertEqual(expected, parsed)
|
||||
|
||||
def test_from_pip_string_legacy_non_440_beta(self):
|
||||
expected = version.SemanticVersion(
|
||||
2014, 2, prerelease_type='b', prerelease=2)
|
||||
parsed = from_pip_string('2014.2.b2')
|
||||
self.assertEqual(expected, parsed)
|
||||
|
||||
def test_from_pip_string_pure_git_hash(self):
|
||||
self.assertRaises(ValueError, from_pip_string, '6eed5ae')
|
||||
|
||||
def test_from_pip_string_non_digit_start(self):
|
||||
self.assertRaises(ValueError, from_pip_string,
|
||||
'non-release-tag/2014.12.16-1')
|
||||
|
||||
def test_final_version(self):
|
||||
semver = version.SemanticVersion(1, 2, 3)
|
||||
self.assertEqual((1, 2, 3, 'final', 0), semver.version_tuple())
|
||||
self.assertEqual("1.2.3", semver.brief_string())
|
||||
self.assertEqual("1.2.3", semver.debian_string())
|
||||
self.assertEqual("1.2.3", semver.release_string())
|
||||
self.assertEqual("1.2.3", semver.rpm_string())
|
||||
self.assertEqual(semver, from_pip_string("1.2.3"))
|
||||
|
||||
def test_parsing_short_forms(self):
|
||||
semver = version.SemanticVersion(1, 0, 0)
|
||||
self.assertEqual(semver, from_pip_string("1"))
|
||||
self.assertEqual(semver, from_pip_string("1.0"))
|
||||
self.assertEqual(semver, from_pip_string("1.0.0"))
|
||||
|
||||
def test_dev_version(self):
|
||||
semver = version.SemanticVersion(1, 2, 4, dev_count=5)
|
||||
self.assertEqual((1, 2, 4, 'dev', 4), semver.version_tuple())
|
||||
self.assertEqual("1.2.4", semver.brief_string())
|
||||
self.assertEqual("1.2.4~dev5", semver.debian_string())
|
||||
self.assertEqual("1.2.4.dev5", semver.release_string())
|
||||
self.assertEqual("1.2.3.dev5", semver.rpm_string())
|
||||
self.assertEqual(semver, from_pip_string("1.2.4.dev5"))
|
||||
|
||||
def test_dev_no_git_version(self):
|
||||
semver = version.SemanticVersion(1, 2, 4, dev_count=5)
|
||||
self.assertEqual((1, 2, 4, 'dev', 4), semver.version_tuple())
|
||||
self.assertEqual("1.2.4", semver.brief_string())
|
||||
self.assertEqual("1.2.4~dev5", semver.debian_string())
|
||||
self.assertEqual("1.2.4.dev5", semver.release_string())
|
||||
self.assertEqual("1.2.3.dev5", semver.rpm_string())
|
||||
self.assertEqual(semver, from_pip_string("1.2.4.dev5"))
|
||||
|
||||
def test_dev_zero_version(self):
|
||||
semver = version.SemanticVersion(1, 2, 0, dev_count=5)
|
||||
self.assertEqual((1, 2, 0, 'dev', 4), semver.version_tuple())
|
||||
self.assertEqual("1.2.0", semver.brief_string())
|
||||
self.assertEqual("1.2.0~dev5", semver.debian_string())
|
||||
self.assertEqual("1.2.0.dev5", semver.release_string())
|
||||
self.assertEqual("1.1.9999.dev5", semver.rpm_string())
|
||||
self.assertEqual(semver, from_pip_string("1.2.0.dev5"))
|
||||
|
||||
def test_alpha_dev_version(self):
|
||||
semver = version.SemanticVersion(1, 2, 4, 'a', 1, 12)
|
||||
self.assertEqual((1, 2, 4, 'alphadev', 12), semver.version_tuple())
|
||||
self.assertEqual("1.2.4", semver.brief_string())
|
||||
self.assertEqual("1.2.4~a1.dev12", semver.debian_string())
|
||||
self.assertEqual("1.2.4.0a1.dev12", semver.release_string())
|
||||
self.assertEqual("1.2.3.a1.dev12", semver.rpm_string())
|
||||
self.assertEqual(semver, from_pip_string("1.2.4.0a1.dev12"))
|
||||
|
||||
def test_alpha_version(self):
|
||||
semver = version.SemanticVersion(1, 2, 4, 'a', 1)
|
||||
self.assertEqual((1, 2, 4, 'alpha', 1), semver.version_tuple())
|
||||
self.assertEqual("1.2.4", semver.brief_string())
|
||||
self.assertEqual("1.2.4~a1", semver.debian_string())
|
||||
self.assertEqual("1.2.4.0a1", semver.release_string())
|
||||
self.assertEqual("1.2.3.a1", semver.rpm_string())
|
||||
self.assertEqual(semver, from_pip_string("1.2.4.0a1"))
|
||||
|
||||
def test_alpha_zero_version(self):
|
||||
semver = version.SemanticVersion(1, 2, 0, 'a', 1)
|
||||
self.assertEqual((1, 2, 0, 'alpha', 1), semver.version_tuple())
|
||||
self.assertEqual("1.2.0", semver.brief_string())
|
||||
self.assertEqual("1.2.0~a1", semver.debian_string())
|
||||
self.assertEqual("1.2.0.0a1", semver.release_string())
|
||||
self.assertEqual("1.1.9999.a1", semver.rpm_string())
|
||||
self.assertEqual(semver, from_pip_string("1.2.0.0a1"))
|
||||
|
||||
def test_alpha_major_zero_version(self):
|
||||
semver = version.SemanticVersion(1, 0, 0, 'a', 1)
|
||||
self.assertEqual((1, 0, 0, 'alpha', 1), semver.version_tuple())
|
||||
self.assertEqual("1.0.0", semver.brief_string())
|
||||
self.assertEqual("1.0.0~a1", semver.debian_string())
|
||||
self.assertEqual("1.0.0.0a1", semver.release_string())
|
||||
self.assertEqual("0.9999.9999.a1", semver.rpm_string())
|
||||
self.assertEqual(semver, from_pip_string("1.0.0.0a1"))
|
||||
|
||||
def test_alpha_default_version(self):
|
||||
semver = version.SemanticVersion(1, 2, 4, 'a')
|
||||
self.assertEqual((1, 2, 4, 'alpha', 0), semver.version_tuple())
|
||||
self.assertEqual("1.2.4", semver.brief_string())
|
||||
self.assertEqual("1.2.4~a0", semver.debian_string())
|
||||
self.assertEqual("1.2.4.0a0", semver.release_string())
|
||||
self.assertEqual("1.2.3.a0", semver.rpm_string())
|
||||
self.assertEqual(semver, from_pip_string("1.2.4.0a0"))
|
||||
|
||||
def test_beta_dev_version(self):
|
||||
semver = version.SemanticVersion(1, 2, 4, 'b', 1, 12)
|
||||
self.assertEqual((1, 2, 4, 'betadev', 12), semver.version_tuple())
|
||||
self.assertEqual("1.2.4", semver.brief_string())
|
||||
self.assertEqual("1.2.4~b1.dev12", semver.debian_string())
|
||||
self.assertEqual("1.2.4.0b1.dev12", semver.release_string())
|
||||
self.assertEqual("1.2.3.b1.dev12", semver.rpm_string())
|
||||
self.assertEqual(semver, from_pip_string("1.2.4.0b1.dev12"))
|
||||
|
||||
def test_beta_version(self):
|
||||
semver = version.SemanticVersion(1, 2, 4, 'b', 1)
|
||||
self.assertEqual((1, 2, 4, 'beta', 1), semver.version_tuple())
|
||||
self.assertEqual("1.2.4", semver.brief_string())
|
||||
self.assertEqual("1.2.4~b1", semver.debian_string())
|
||||
self.assertEqual("1.2.4.0b1", semver.release_string())
|
||||
self.assertEqual("1.2.3.b1", semver.rpm_string())
|
||||
self.assertEqual(semver, from_pip_string("1.2.4.0b1"))
|
||||
|
||||
def test_decrement_nonrelease(self):
|
||||
# The prior version of any non-release is a release
|
||||
semver = version.SemanticVersion(1, 2, 4, 'b', 1)
|
||||
self.assertEqual(
|
||||
version.SemanticVersion(1, 2, 3), semver.decrement())
|
||||
|
||||
def test_decrement_nonrelease_zero(self):
|
||||
# We set an arbitrary max version of 9999 when decrementing versions
|
||||
# - this is part of handling rpm support.
|
||||
semver = version.SemanticVersion(1, 0, 0)
|
||||
self.assertEqual(
|
||||
version.SemanticVersion(0, 9999, 9999), semver.decrement())
|
||||
|
||||
def test_decrement_release(self):
|
||||
# The next patch version of a release version requires a change to the
|
||||
# patch level.
|
||||
semver = version.SemanticVersion(2, 2, 5)
|
||||
self.assertEqual(
|
||||
version.SemanticVersion(2, 2, 4), semver.decrement())
|
||||
|
||||
def test_increment_nonrelease(self):
|
||||
# The next patch version of a non-release version is another
|
||||
# non-release version as the next release doesn't need to be
|
||||
# incremented.
|
||||
semver = version.SemanticVersion(1, 2, 4, 'b', 1)
|
||||
self.assertEqual(
|
||||
version.SemanticVersion(1, 2, 4, 'b', 2), semver.increment())
|
||||
# Major and minor increments however need to bump things.
|
||||
self.assertEqual(
|
||||
version.SemanticVersion(1, 3, 0), semver.increment(minor=True))
|
||||
self.assertEqual(
|
||||
version.SemanticVersion(2, 0, 0), semver.increment(major=True))
|
||||
|
||||
def test_increment_release(self):
|
||||
# The next patch version of a release version requires a change to the
|
||||
# patch level.
|
||||
semver = version.SemanticVersion(1, 2, 5)
|
||||
self.assertEqual(
|
||||
version.SemanticVersion(1, 2, 6), semver.increment())
|
||||
self.assertEqual(
|
||||
version.SemanticVersion(1, 3, 0), semver.increment(minor=True))
|
||||
self.assertEqual(
|
||||
version.SemanticVersion(2, 0, 0), semver.increment(major=True))
|
||||
|
||||
def test_rc_dev_version(self):
|
||||
semver = version.SemanticVersion(1, 2, 4, 'rc', 1, 12)
|
||||
self.assertEqual((1, 2, 4, 'candidatedev', 12), semver.version_tuple())
|
||||
self.assertEqual("1.2.4", semver.brief_string())
|
||||
self.assertEqual("1.2.4~rc1.dev12", semver.debian_string())
|
||||
self.assertEqual("1.2.4.0rc1.dev12", semver.release_string())
|
||||
self.assertEqual("1.2.3.rc1.dev12", semver.rpm_string())
|
||||
self.assertEqual(semver, from_pip_string("1.2.4.0rc1.dev12"))
|
||||
|
||||
def test_rc_version(self):
|
||||
semver = version.SemanticVersion(1, 2, 4, 'rc', 1)
|
||||
self.assertEqual((1, 2, 4, 'candidate', 1), semver.version_tuple())
|
||||
self.assertEqual("1.2.4", semver.brief_string())
|
||||
self.assertEqual("1.2.4~rc1", semver.debian_string())
|
||||
self.assertEqual("1.2.4.0rc1", semver.release_string())
|
||||
self.assertEqual("1.2.3.rc1", semver.rpm_string())
|
||||
self.assertEqual(semver, from_pip_string("1.2.4.0rc1"))
|
||||
|
||||
def test_to_dev(self):
|
||||
self.assertEqual(
|
||||
version.SemanticVersion(1, 2, 3, dev_count=1),
|
||||
version.SemanticVersion(1, 2, 3).to_dev(1))
|
||||
self.assertEqual(
|
||||
version.SemanticVersion(1, 2, 3, 'rc', 1, dev_count=1),
|
||||
version.SemanticVersion(1, 2, 3, 'rc', 1).to_dev(1))
|
163
libs/common/pbr/tests/test_wsgi.py
Normal file
163
libs/common/pbr/tests/test_wsgi.py
Normal file
|
@ -0,0 +1,163 @@
|
|||
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. (HP)
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
try:
|
||||
# python 2
|
||||
from urllib2 import urlopen
|
||||
except ImportError:
|
||||
# python 3
|
||||
from urllib.request import urlopen
|
||||
|
||||
from pbr.tests import base
|
||||
|
||||
|
||||
class TestWsgiScripts(base.BaseTestCase):
|
||||
|
||||
cmd_names = ('pbr_test_wsgi', 'pbr_test_wsgi_with_class')
|
||||
|
||||
def _get_path(self):
|
||||
if os.path.isdir("%s/lib64" % self.temp_dir):
|
||||
path = "%s/lib64" % self.temp_dir
|
||||
elif os.path.isdir("%s/lib" % self.temp_dir):
|
||||
path = "%s/lib" % self.temp_dir
|
||||
elif os.path.isdir("%s/site-packages" % self.temp_dir):
|
||||
return ".:%s/site-packages" % self.temp_dir
|
||||
else:
|
||||
raise Exception("Could not determine path for test")
|
||||
return ".:%s/python%s.%s/site-packages" % (
|
||||
path,
|
||||
sys.version_info[0],
|
||||
sys.version_info[1])
|
||||
|
||||
def test_wsgi_script_install(self):
|
||||
"""Test that we install a non-pkg-resources wsgi script."""
|
||||
if os.name == 'nt':
|
||||
self.skipTest('Windows support is passthrough')
|
||||
|
||||
stdout, _, return_code = self.run_setup(
|
||||
'install', '--prefix=%s' % self.temp_dir)
|
||||
|
||||
self._check_wsgi_install_content(stdout)
|
||||
|
||||
def test_wsgi_script_run(self):
|
||||
"""Test that we install a runnable wsgi script.
|
||||
|
||||
This test actually attempts to start and interact with the
|
||||
wsgi script in question to demonstrate that it's a working
|
||||
wsgi script using simple server.
|
||||
|
||||
"""
|
||||
if os.name == 'nt':
|
||||
self.skipTest('Windows support is passthrough')
|
||||
|
||||
stdout, _, return_code = self.run_setup(
|
||||
'install', '--prefix=%s' % self.temp_dir)
|
||||
|
||||
self._check_wsgi_install_content(stdout)
|
||||
|
||||
# Live test run the scripts and see that they respond to wsgi
|
||||
# requests.
|
||||
for cmd_name in self.cmd_names:
|
||||
self._test_wsgi(cmd_name, b'Hello World')
|
||||
|
||||
def _test_wsgi(self, cmd_name, output, extra_args=None):
|
||||
cmd = os.path.join(self.temp_dir, 'bin', cmd_name)
|
||||
print("Running %s -p 0" % cmd)
|
||||
popen_cmd = [cmd, '-p', '0']
|
||||
if extra_args:
|
||||
popen_cmd.extend(extra_args)
|
||||
|
||||
env = {'PYTHONPATH': self._get_path()}
|
||||
|
||||
p = subprocess.Popen(popen_cmd, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE, cwd=self.temp_dir,
|
||||
env=env)
|
||||
self.addCleanup(p.kill)
|
||||
|
||||
stdoutdata = p.stdout.readline() # ****...
|
||||
|
||||
stdoutdata = p.stdout.readline() # STARTING test server...
|
||||
self.assertIn(
|
||||
b"STARTING test server pbr_testpackage.wsgi",
|
||||
stdoutdata)
|
||||
|
||||
stdoutdata = p.stdout.readline() # Available at ...
|
||||
print(stdoutdata)
|
||||
m = re.search(b'(http://[^:]+:\d+)/', stdoutdata)
|
||||
self.assertIsNotNone(m, "Regex failed to match on %s" % stdoutdata)
|
||||
|
||||
stdoutdata = p.stdout.readline() # DANGER! ...
|
||||
self.assertIn(
|
||||
b"DANGER! For testing only, do not use in production",
|
||||
stdoutdata)
|
||||
|
||||
stdoutdata = p.stdout.readline() # ***...
|
||||
|
||||
f = urlopen(m.group(1).decode('utf-8'))
|
||||
self.assertEqual(output, f.read())
|
||||
|
||||
# Request again so that the application can force stderr.flush(),
|
||||
# otherwise the log is buffered and the next readline() will hang.
|
||||
urlopen(m.group(1).decode('utf-8'))
|
||||
|
||||
stdoutdata = p.stderr.readline()
|
||||
# we should have logged an HTTP request, return code 200, that
|
||||
# returned the right amount of bytes
|
||||
status = '"GET / HTTP/1.1" 200 %d' % len(output)
|
||||
self.assertIn(status.encode('utf-8'), stdoutdata)
|
||||
|
||||
def _check_wsgi_install_content(self, install_stdout):
|
||||
for cmd_name in self.cmd_names:
|
||||
install_txt = 'Installing %s script to %s' % (cmd_name,
|
||||
self.temp_dir)
|
||||
self.assertIn(install_txt, install_stdout)
|
||||
|
||||
cmd_filename = os.path.join(self.temp_dir, 'bin', cmd_name)
|
||||
|
||||
script_txt = open(cmd_filename, 'r').read()
|
||||
self.assertNotIn('pkg_resources', script_txt)
|
||||
|
||||
main_block = """if __name__ == "__main__":
|
||||
import argparse
|
||||
import socket
|
||||
import sys
|
||||
import wsgiref.simple_server as wss"""
|
||||
|
||||
if cmd_name == 'pbr_test_wsgi':
|
||||
app_name = "main"
|
||||
else:
|
||||
app_name = "WSGI.app"
|
||||
|
||||
starting_block = ("STARTING test server pbr_testpackage.wsgi."
|
||||
"%s" % app_name)
|
||||
|
||||
else_block = """else:
|
||||
application = None"""
|
||||
|
||||
self.assertIn(main_block, script_txt)
|
||||
self.assertIn(starting_block, script_txt)
|
||||
self.assertIn(else_block, script_txt)
|
||||
|
||||
def test_with_argument(self):
|
||||
if os.name == 'nt':
|
||||
self.skipTest('Windows support is passthrough')
|
||||
|
||||
stdout, _, return_code = self.run_setup(
|
||||
'install', '--prefix=%s' % self.temp_dir)
|
||||
|
||||
self._test_wsgi('pbr_test_wsgi', b'Foo Bar', ["--", "-c", "Foo Bar"])
|
86
libs/common/pbr/tests/testpackage/CHANGES.txt
Normal file
86
libs/common/pbr/tests/testpackage/CHANGES.txt
Normal file
|
@ -0,0 +1,86 @@
|
|||
Changelog
|
||||
===========
|
||||
|
||||
0.3 (unreleased)
|
||||
------------------
|
||||
|
||||
- The ``glob_data_files`` hook became a pre-command hook for the install_data
|
||||
command instead of being a setup-hook. This is to support the additional
|
||||
functionality of requiring data_files with relative destination paths to be
|
||||
install relative to the package's install path (i.e. site-packages).
|
||||
|
||||
- Dropped support for and deprecated the easier_install custom command.
|
||||
Although it should still work, it probably won't be used anymore for
|
||||
stsci_python packages.
|
||||
|
||||
- Added support for the ``build_optional_ext`` command, which replaces/extends
|
||||
the default ``build_ext`` command. See the README for more details.
|
||||
|
||||
- Added the ``tag_svn_revision`` setup_hook as a replacement for the
|
||||
setuptools-specific tag_svn_revision option to the egg_info command. This
|
||||
new hook is easier to use than the old tag_svn_revision option: It's
|
||||
automatically enabled by the presence of ``.dev`` in the version string, and
|
||||
disabled otherwise.
|
||||
|
||||
- The ``svn_info_pre_hook`` and ``svn_info_post_hook`` have been replaced with
|
||||
``version_pre_command_hook`` and ``version_post_command_hook`` respectively.
|
||||
However, a new ``version_setup_hook``, which has the same purpose, has been
|
||||
added. It is generally easier to use and will give more consistent results
|
||||
in that it will run every time setup.py is run, regardless of which command
|
||||
is used. ``stsci.distutils`` itself uses this hook--see the `setup.cfg` file
|
||||
and `stsci/distutils/__init__.py` for example usage.
|
||||
|
||||
- Instead of creating an `svninfo.py` module, the new ``version_`` hooks create
|
||||
a file called `version.py`. In addition to the SVN info that was included
|
||||
in `svninfo.py`, it includes a ``__version__`` variable to be used by the
|
||||
package's `__init__.py`. This allows there to be a hard-coded
|
||||
``__version__`` variable included in the source code, rather than using
|
||||
pkg_resources to get the version.
|
||||
|
||||
- In `version.py`, the variables previously named ``__svn_version__`` and
|
||||
``__full_svn_info__`` are now named ``__svn_revision__`` and
|
||||
``__svn_full_info__``.
|
||||
|
||||
- Fixed a bug when using stsci.distutils in the installation of other packages
|
||||
in the ``stsci.*`` namespace package. If stsci.distutils was not already
|
||||
installed, and was downloaded automatically by distribute through the
|
||||
setup_requires option, then ``stsci.distutils`` would fail to import. This
|
||||
is because the way the namespace package (nspkg) mechanism currently works,
|
||||
all packages belonging to the nspkg *must* be on the import path at initial
|
||||
import time.
|
||||
|
||||
So when installing stsci.tools, for example, if ``stsci.tools`` is imported
|
||||
from within the source code at install time, but before ``stsci.distutils``
|
||||
is downloaded and added to the path, the ``stsci`` package is already
|
||||
imported and can't be extended to include the path of ``stsci.distutils``
|
||||
after the fact. The easiest way of dealing with this, it seems, is to
|
||||
delete ``stsci`` from ``sys.modules``, which forces it to be reimported, now
|
||||
the its ``__path__`` extended to include ``stsci.distutil``'s path.
|
||||
|
||||
|
||||
0.2.2 (2011-11-09)
|
||||
------------------
|
||||
|
||||
- Fixed check for the issue205 bug on actual setuptools installs; before it
|
||||
only worked on distribute. setuptools has the issue205 bug prior to version
|
||||
0.6c10.
|
||||
|
||||
- Improved the fix for the issue205 bug, especially on setuptools.
|
||||
setuptools, prior to 0.6c10, did not back of sys.modules either before
|
||||
sandboxing, which causes serious problems. In fact, it's so bad that it's
|
||||
not enough to add a sys.modules backup to the current sandbox: It's in fact
|
||||
necessary to monkeypatch setuptools.sandbox.run_setup so that any subsequent
|
||||
calls to it also back up sys.modules.
|
||||
|
||||
|
||||
0.2.1 (2011-09-02)
|
||||
------------------
|
||||
|
||||
- Fixed the dependencies so that setuptools is requirement but 'distribute'
|
||||
specifically. Previously installation could fail if users had plain
|
||||
setuptools installed and not distribute
|
||||
|
||||
0.2 (2011-08-23)
|
||||
------------------
|
||||
|
||||
- Initial public release
|
29
libs/common/pbr/tests/testpackage/LICENSE.txt
Normal file
29
libs/common/pbr/tests/testpackage/LICENSE.txt
Normal file
|
@ -0,0 +1,29 @@
|
|||
Copyright (C) 2005 Association of Universities for Research in Astronomy (AURA)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
3. The name of AURA and its representatives may not be used to
|
||||
endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY AURA ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL AURA BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
|
2
libs/common/pbr/tests/testpackage/MANIFEST.in
Normal file
2
libs/common/pbr/tests/testpackage/MANIFEST.in
Normal file
|
@ -0,0 +1,2 @@
|
|||
include data_files/*
|
||||
exclude pbr_testpackage/extra.py
|
148
libs/common/pbr/tests/testpackage/README.txt
Normal file
148
libs/common/pbr/tests/testpackage/README.txt
Normal file
|
@ -0,0 +1,148 @@
|
|||
Introduction
|
||||
============
|
||||
This package contains utilities used to package some of STScI's Python
|
||||
projects; specifically those projects that comprise stsci_python_ and
|
||||
Astrolib_.
|
||||
|
||||
It currently consists mostly of some setup_hook scripts meant for use with
|
||||
`distutils2/packaging`_ and/or pbr_, and a customized easy_install command
|
||||
meant for use with distribute_.
|
||||
|
||||
This package is not meant for general consumption, though it might be worth
|
||||
looking at for examples of how to do certain things with your own packages, but
|
||||
YMMV.
|
||||
|
||||
Features
|
||||
========
|
||||
|
||||
Hook Scripts
|
||||
------------
|
||||
Currently the main features of this package are a couple of setup_hook scripts.
|
||||
In distutils2, a setup_hook is a script that runs at the beginning of any
|
||||
pysetup command, and can modify the package configuration read from setup.cfg.
|
||||
There are also pre- and post-command hooks that only run before/after a
|
||||
specific setup command (eg. build_ext, install) is run.
|
||||
|
||||
stsci.distutils.hooks.use_packages_root
|
||||
'''''''''''''''''''''''''''''''''''''''
|
||||
If using the ``packages_root`` option under the ``[files]`` section of
|
||||
setup.cfg, this hook will add that path to ``sys.path`` so that modules in your
|
||||
package can be imported and used in setup. This can be used even if
|
||||
``packages_root`` is not specified--in this case it adds ``''`` to
|
||||
``sys.path``.
|
||||
|
||||
stsci.distutils.hooks.version_setup_hook
|
||||
''''''''''''''''''''''''''''''''''''''''
|
||||
Creates a Python module called version.py which currently contains four
|
||||
variables:
|
||||
|
||||
* ``__version__`` (the release version)
|
||||
* ``__svn_revision__`` (the SVN revision info as returned by the ``svnversion``
|
||||
command)
|
||||
* ``__svn_full_info__`` (as returned by the ``svn info`` command)
|
||||
* ``__setup_datetime__`` (the date and time that setup.py was last run).
|
||||
|
||||
These variables can be imported in the package's `__init__.py` for degugging
|
||||
purposes. The version.py module will *only* be created in a package that
|
||||
imports from the version module in its `__init__.py`. It should be noted that
|
||||
this is generally preferable to writing these variables directly into
|
||||
`__init__.py`, since this provides more control and is less likely to
|
||||
unexpectedly break things in `__init__.py`.
|
||||
|
||||
stsci.distutils.hooks.version_pre_command_hook
|
||||
''''''''''''''''''''''''''''''''''''''''''''''
|
||||
Identical to version_setup_hook, but designed to be used as a pre-command
|
||||
hook.
|
||||
|
||||
stsci.distutils.hooks.version_post_command_hook
|
||||
'''''''''''''''''''''''''''''''''''''''''''''''
|
||||
The complement to version_pre_command_hook. This will delete any version.py
|
||||
files created during a build in order to prevent them from cluttering an SVN
|
||||
working copy (note, however, that version.py is *not* deleted from the build/
|
||||
directory, so a copy of it is still preserved). It will also not be deleted
|
||||
if the current directory is not an SVN working copy. For example, if source
|
||||
code extracted from a source tarball it will be preserved.
|
||||
|
||||
stsci.distutils.hooks.tag_svn_revision
|
||||
''''''''''''''''''''''''''''''''''''''
|
||||
A setup_hook to add the SVN revision of the current working copy path to the
|
||||
package version string, but only if the version ends in .dev.
|
||||
|
||||
For example, ``mypackage-1.0.dev`` becomes ``mypackage-1.0.dev1234``. This is
|
||||
in accordance with the version string format standardized by PEP 386.
|
||||
|
||||
This should be used as a replacement for the ``tag_svn_revision`` option to
|
||||
the egg_info command. This hook is more compatible with packaging/distutils2,
|
||||
which does not include any VCS support. This hook is also more flexible in
|
||||
that it turns the revision number on/off depending on the presence of ``.dev``
|
||||
in the version string, so that it's not automatically added to the version in
|
||||
final releases.
|
||||
|
||||
This hook does require the ``svnversion`` command to be available in order to
|
||||
work. It does not examine the working copy metadata directly.
|
||||
|
||||
stsci.distutils.hooks.numpy_extension_hook
|
||||
''''''''''''''''''''''''''''''''''''''''''
|
||||
This is a pre-command hook for the build_ext command. To use it, add a
|
||||
``[build_ext]`` section to your setup.cfg, and add to it::
|
||||
|
||||
pre-hook.numpy-extension-hook = stsci.distutils.hooks.numpy_extension_hook
|
||||
|
||||
This hook must be used to build extension modules that use Numpy. The primary
|
||||
side-effect of this hook is to add the correct numpy include directories to
|
||||
`include_dirs`. To use it, add 'numpy' to the 'include-dirs' option of each
|
||||
extension module that requires numpy to build. The value 'numpy' will be
|
||||
replaced with the actual path to the numpy includes.
|
||||
|
||||
stsci.distutils.hooks.is_display_option
|
||||
'''''''''''''''''''''''''''''''''''''''
|
||||
This is not actually a hook, but is a useful utility function that can be used
|
||||
in writing other hooks. Basically, it returns ``True`` if setup.py was run
|
||||
with a "display option" such as --version or --help. This can be used to
|
||||
prevent your hook from running in such cases.
|
||||
|
||||
stsci.distutils.hooks.glob_data_files
|
||||
'''''''''''''''''''''''''''''''''''''
|
||||
A pre-command hook for the install_data command. Allows filename wildcards as
|
||||
understood by ``glob.glob()`` to be used in the data_files option. This hook
|
||||
must be used in order to have this functionality since it does not normally
|
||||
exist in distutils.
|
||||
|
||||
This hook also ensures that data files are installed relative to the package
|
||||
path. data_files shouldn't normally be installed this way, but the
|
||||
functionality is required for a few special cases.
|
||||
|
||||
|
||||
Commands
|
||||
--------
|
||||
build_optional_ext
|
||||
''''''''''''''''''
|
||||
This serves as an optional replacement for the default built_ext command,
|
||||
which compiles C extension modules. Its purpose is to allow extension modules
|
||||
to be *optional*, so that if their build fails the rest of the package is
|
||||
still allowed to be built and installed. This can be used when an extension
|
||||
module is not definitely required to use the package.
|
||||
|
||||
To use this custom command, add::
|
||||
|
||||
commands = stsci.distutils.command.build_optional_ext.build_optional_ext
|
||||
|
||||
under the ``[global]`` section of your package's setup.cfg. Then, to mark
|
||||
an individual extension module as optional, under the setup.cfg section for
|
||||
that extension add::
|
||||
|
||||
optional = True
|
||||
|
||||
Optionally, you may also add a custom failure message by adding::
|
||||
|
||||
fail_message = The foobar extension module failed to compile.
|
||||
This could be because you lack such and such headers.
|
||||
This package will still work, but such and such features
|
||||
will be disabled.
|
||||
|
||||
|
||||
.. _stsci_python: http://www.stsci.edu/resources/software_hardware/pyraf/stsci_python
|
||||
.. _Astrolib: http://www.scipy.org/AstroLib/
|
||||
.. _distutils2/packaging: http://distutils2.notmyidea.org/
|
||||
.. _d2to1: http://pypi.python.org/pypi/d2to1
|
||||
.. _distribute: http://pypi.python.org/pypi/distribute
|
0
libs/common/pbr/tests/testpackage/data_files/a.txt
Normal file
0
libs/common/pbr/tests/testpackage/data_files/a.txt
Normal file
0
libs/common/pbr/tests/testpackage/data_files/b.txt
Normal file
0
libs/common/pbr/tests/testpackage/data_files/b.txt
Normal file
0
libs/common/pbr/tests/testpackage/data_files/c.rst
Normal file
0
libs/common/pbr/tests/testpackage/data_files/c.rst
Normal file
74
libs/common/pbr/tests/testpackage/doc/source/conf.py
Normal file
74
libs/common/pbr/tests/testpackage/doc/source/conf.py
Normal file
|
@ -0,0 +1,74 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.abspath('../..'))
|
||||
# -- General configuration ----------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
#'sphinx.ext.intersphinx',
|
||||
]
|
||||
|
||||
# autodoc generation is a bit aggressive and a nuisance when doing heavy
|
||||
# text edit cycles.
|
||||
# execute "export SPHINX_DEBUG=1" in your terminal to disable
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'testpackage'
|
||||
copyright = u'2013, OpenStack Foundation'
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
add_module_names = True
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# -- Options for HTML output --------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. Major themes that come with
|
||||
# Sphinx are currently 'default' and 'sphinxdoc'.
|
||||
# html_theme_path = ["."]
|
||||
# html_theme = '_theme'
|
||||
# html_static_path = ['static']
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = '%sdoc' % project
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass
|
||||
# [howto/manual]).
|
||||
latex_documents = [
|
||||
('index',
|
||||
'%s.tex' % project,
|
||||
u'%s Documentation' % project,
|
||||
u'OpenStack Foundation', 'manual'),
|
||||
]
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
#intersphinx_mapping = {'http://docs.python.org/': None}
|
23
libs/common/pbr/tests/testpackage/doc/source/index.rst
Normal file
23
libs/common/pbr/tests/testpackage/doc/source/index.rst
Normal file
|
@ -0,0 +1,23 @@
|
|||
.. testpackage 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 testpackage's documentation!
|
||||
========================================================
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
installation
|
||||
usage
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
============
|
||||
Installation
|
||||
============
|
||||
|
||||
At the command line::
|
||||
|
||||
$ pip install testpackage
|
||||
|
||||
Or, if you have virtualenvwrapper installed::
|
||||
|
||||
$ mkvirtualenv testpackage
|
||||
$ pip install testpackage
|
7
libs/common/pbr/tests/testpackage/doc/source/usage.rst
Normal file
7
libs/common/pbr/tests/testpackage/doc/source/usage.rst
Normal file
|
@ -0,0 +1,7 @@
|
|||
========
|
||||
Usage
|
||||
========
|
||||
|
||||
To use testpackage in a project::
|
||||
|
||||
import testpackage
|
0
libs/common/pbr/tests/testpackage/extra-file.txt
Normal file
0
libs/common/pbr/tests/testpackage/extra-file.txt
Normal file
0
libs/common/pbr/tests/testpackage/git-extra-file.txt
Normal file
0
libs/common/pbr/tests/testpackage/git-extra-file.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
import pbr.version
|
||||
|
||||
__version__ = pbr.version.VersionInfo('pbr_testpackage').version_string()
|
|
@ -0,0 +1,65 @@
|
|||
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Copyright (C) 2013 Association of Universities for Research in Astronomy
|
||||
# (AURA)
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
#
|
||||
# 3. The name of AURA and its representatives may not be used to
|
||||
# endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY AURA ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL AURA BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
|
||||
from distutils.command import build_py
|
||||
|
||||
|
||||
def test_hook_1(config):
|
||||
print('test_hook_1')
|
||||
|
||||
|
||||
def test_hook_2(config):
|
||||
print('test_hook_2')
|
||||
|
||||
|
||||
class test_command(build_py.build_py):
|
||||
command_name = 'build_py'
|
||||
|
||||
def run(self):
|
||||
print('Running custom build_py command.')
|
||||
return build_py.build_py.run(self)
|
||||
|
||||
|
||||
def test_pre_hook(cmdobj):
|
||||
print('build_ext pre-hook')
|
||||
|
||||
|
||||
def test_post_hook(cmdobj):
|
||||
print('build_ext post-hook')
|
26
libs/common/pbr/tests/testpackage/pbr_testpackage/cmd.py
Normal file
26
libs/common/pbr/tests/testpackage/pbr_testpackage/cmd.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from __future__ import print_function
|
||||
|
||||
|
||||
def main():
|
||||
print("PBR Test Command")
|
||||
|
||||
|
||||
class Foo(object):
|
||||
|
||||
@classmethod
|
||||
def bar(self):
|
||||
print("PBR Test Command - with class!")
|
40
libs/common/pbr/tests/testpackage/pbr_testpackage/wsgi.py
Normal file
40
libs/common/pbr/tests/testpackage/pbr_testpackage/wsgi.py
Normal file
|
@ -0,0 +1,40 @@
|
|||
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import functools
|
||||
import sys
|
||||
|
||||
|
||||
def application(env, start_response, data):
|
||||
sys.stderr.flush() # Force the previous request log to be written.
|
||||
start_response('200 OK', [('Content-Type', 'text/html')])
|
||||
return [data.encode('utf-8')]
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Return a string.')
|
||||
parser.add_argument('--content', '-c', help='String returned',
|
||||
default='Hello World')
|
||||
args = parser.parse_args()
|
||||
return functools.partial(application, data=args.content)
|
||||
|
||||
|
||||
class WSGI(object):
|
||||
|
||||
@classmethod
|
||||
def app(self):
|
||||
return functools.partial(application, data='Hello World')
|
21
libs/common/pbr/tests/testpackage/setup.py
Normal file
21
libs/common/pbr/tests/testpackage/setup.py
Normal file
|
@ -0,0 +1,21 @@
|
|||
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import setuptools
|
||||
|
||||
setuptools.setup(
|
||||
setup_requires=['pbr'],
|
||||
pbr=True,
|
||||
)
|
29
libs/common/pbr/tests/testpackage/src/testext.c
Normal file
29
libs/common/pbr/tests/testpackage/src/testext.c
Normal file
|
@ -0,0 +1,29 @@
|
|||
#include <Python.h>
|
||||
|
||||
|
||||
static PyMethodDef TestextMethods[] = {
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
|
||||
#if PY_MAJOR_VERSION >=3
|
||||
static struct PyModuleDef testextmodule = {
|
||||
PyModuleDef_HEAD_INIT, /* This should correspond to a PyModuleDef_Base type */
|
||||
"testext", /* This is the module name */
|
||||
"Test extension module", /* This is the module docstring */
|
||||
-1, /* This defines the size of the module and says everything is global */
|
||||
TestextMethods /* This is the method definition */
|
||||
};
|
||||
|
||||
PyObject*
|
||||
PyInit_testext(void)
|
||||
{
|
||||
return PyModule_Create(&testextmodule);
|
||||
}
|
||||
#else
|
||||
PyMODINIT_FUNC
|
||||
inittestext(void)
|
||||
{
|
||||
Py_InitModule("testext", TestextMethods);
|
||||
}
|
||||
#endif
|
2
libs/common/pbr/tests/testpackage/test-requirements.txt
Normal file
2
libs/common/pbr/tests/testpackage/test-requirements.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
ordereddict;python_version=='2.6'
|
||||
requests-mock
|
78
libs/common/pbr/tests/util.py
Normal file
78
libs/common/pbr/tests/util.py
Normal file
|
@ -0,0 +1,78 @@
|
|||
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Copyright (C) 2013 Association of Universities for Research in Astronomy
|
||||
# (AURA)
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
#
|
||||
# 3. The name of AURA and its representatives may not be used to
|
||||
# endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY AURA ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL AURA BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
|
||||
import contextlib
|
||||
import os
|
||||
import shutil
|
||||
import stat
|
||||
import sys
|
||||
|
||||
try:
|
||||
import ConfigParser as configparser
|
||||
except ImportError:
|
||||
import configparser
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def open_config(filename):
|
||||
if sys.version_info >= (3, 2):
|
||||
cfg = configparser.ConfigParser()
|
||||
else:
|
||||
cfg = configparser.SafeConfigParser()
|
||||
cfg.read(filename)
|
||||
yield cfg
|
||||
with open(filename, 'w') as fp:
|
||||
cfg.write(fp)
|
||||
|
||||
|
||||
def rmtree(path):
|
||||
"""shutil.rmtree() with error handler.
|
||||
|
||||
Handle 'access denied' from trying to delete read-only files.
|
||||
"""
|
||||
|
||||
def onerror(func, path, exc_info):
|
||||
if not os.access(path, os.W_OK):
|
||||
os.chmod(path, stat.S_IWUSR)
|
||||
func(path)
|
||||
else:
|
||||
raise
|
||||
|
||||
return shutil.rmtree(path, onerror=onerror)
|
Loading…
Add table
Add a link
Reference in a new issue