Skip to content

Commit

Permalink
Add Subversion.get_vcs_version method (#6390)
Browse files Browse the repository at this point in the history
Add Subversion.get_vcs_version method to return the version of the currently installed Subversion client.
  • Loading branch information
johnthagen authored and cjerdonek committed Apr 17, 2019
1 parent 14cb4f4 commit c8e9caa
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 1 deletion.
1 change: 1 addition & 0 deletions AUTHORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ Jeremy Stanley <[email protected]>
Jeremy Zafran <[email protected]>
Jim Garrison <[email protected]>
Jivan Amara <[email protected]>
John Hagen <[email protected]>
John-Scott Atlakson <[email protected]>
Jon Banafato <[email protected]>
Jon Dufresne <[email protected]>
Expand Down
34 changes: 34 additions & 0 deletions src/pip/_internal/vcs/subversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from pip._internal.utils.misc import (
display_path, rmtree, split_auth_from_netloc,
)
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
from pip._internal.vcs import VersionControl, vcs

_svn_xml_url_re = re.compile('url="([^"]+)"')
Expand All @@ -16,6 +17,9 @@
_svn_info_xml_url_re = re.compile(r'<url>(.*)</url>')


if MYPY_CHECK_RUNNING:
from typing import Optional, Tuple

logger = logging.getLogger(__name__)


Expand All @@ -33,6 +37,36 @@ def should_add_vcs_url_prefix(cls, remote_url):
def get_base_rev_args(rev):
return ['-r', rev]

def get_vcs_version(self):
# type: () -> Optional[Tuple[int, ...]]
"""Return the version of the currently installed Subversion client.
:return: A tuple containing the parts of the version information or
``None`` if the version returned from ``svn`` could not be parsed.
:raises: BadCommand: If ``svn`` is not installed.
"""
# Example versions:
# svn, version 1.10.3 (r1842928)
# compiled Feb 25 2019, 14:20:39 on x86_64-apple-darwin17.0.0
# svn, version 1.7.14 (r1542130)
# compiled Mar 28 2018, 08:49:13 on x86_64-pc-linux-gnu
version_prefix = 'svn, version '
version = self.run_command(['--version'], show_stdout=False)
if not version.startswith(version_prefix):
return None

version = version[len(version_prefix):].split()[0]
version_list = version.split('.')
try:
parsed_version = tuple(map(int, version_list))
except ValueError:
return None

if not parsed_version:
return None

return parsed_version

def export(self, location):
"""Export the svn repository at the url to the destination location"""
url, rev_options = self.get_url_rev_options(self.url)
Expand Down
8 changes: 8 additions & 0 deletions tests/lib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -897,6 +897,14 @@ def is_bzr_installed():
return True


def is_svn_installed():
try:
subprocess.check_output(('svn', '--version'))
except OSError:
return False
return True


def need_bzr(fn):
return pytest.mark.bzr(need_executable(
'Bazaar', ('bzr', 'version', '--short')
Expand Down
59 changes: 58 additions & 1 deletion tests/unit/test_vcs.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,33 @@
import os

import pytest
from mock import patch
from pip._vendor.packaging.version import parse as parse_version

from pip._internal.exceptions import BadCommand
from pip._internal.vcs import (
RevOptions, VersionControl, make_vcs_requirement_url,
)
from pip._internal.vcs.bazaar import Bazaar
from pip._internal.vcs.git import Git, looks_like_hash
from pip._internal.vcs.mercurial import Mercurial
from pip._internal.vcs.subversion import Subversion
from tests.lib import pyversion
from tests.lib import is_svn_installed, pyversion

if pyversion >= '3':
VERBOSE_FALSE = False
else:
VERBOSE_FALSE = 0


@pytest.mark.skipif(
'TRAVIS' not in os.environ,
reason='Subversion is only required under Travis')
def test_ensure_svn_available():
"""Make sure that svn is available when running in Travis."""
assert is_svn_installed()


@pytest.mark.parametrize('args, expected', [
# Test without subdir.
(('git+https://example.com/pkg', 'dev', 'myproj'),
Expand Down Expand Up @@ -366,3 +377,49 @@ def test_subversion__get_url_rev_options():
def test_get_git_version():
git_version = Git().get_git_version()
assert git_version >= parse_version('1.0.0')


@pytest.mark.svn
def test_subversion__get_vcs_version():
"""
Test Subversion.get_vcs_version() against local ``svn``.
"""
version = Subversion().get_vcs_version()
assert len(version) == 3
for part in version:
assert isinstance(part, int)
assert version[0] >= 1


@pytest.mark.parametrize('svn_output, expected_version', [
('svn, version 1.10.3 (r1842928)\n'
' compiled Feb 25 2019, 14:20:39 on x86_64-apple-darwin17.0.0',
(1, 10, 3)),
('svn, version 1.9.7 (r1800392)', (1, 9, 7)),
('svn, version 1.9.7a1 (r1800392)', None),
('svn, version 1.9 (r1800392)', (1, 9)),
('svn, version .9.7 (r1800392)', None),
('svn version 1.9.7 (r1800392)', None),
('svn 1.9.7', None),
('svn, version . .', None),
('', None),
])
@patch('pip._internal.vcs.subversion.Subversion.run_command')
def test_subversion__get_vcs_version_patched(mock_run_command, svn_output,
expected_version):
"""
Test Subversion.get_vcs_version() against patched output.
"""
mock_run_command.return_value = svn_output
version = Subversion().get_vcs_version()
assert version == expected_version


@patch('pip._internal.vcs.subversion.Subversion.run_command')
def test_subversion__get_vcs_version_svn_not_installed(mock_run_command):
"""
Test Subversion.get_vcs_version() when svn is not installed.
"""
mock_run_command.side_effect = BadCommand
with pytest.raises(BadCommand):
Subversion().get_vcs_version()

0 comments on commit c8e9caa

Please sign in to comment.