Skip to content

Commit c8e9caa

Browse files
johnthagencjerdonek
authored andcommitted
Add Subversion.get_vcs_version method (#6390)
Add Subversion.get_vcs_version method to return the version of the currently installed Subversion client.
1 parent 14cb4f4 commit c8e9caa

File tree

4 files changed

+101
-1
lines changed

4 files changed

+101
-1
lines changed

AUTHORS.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ Jeremy Stanley <[email protected]>
214214
Jeremy Zafran <[email protected]>
215215
Jim Garrison <[email protected]>
216216
Jivan Amara <[email protected]>
217+
John Hagen <[email protected]>
217218
John-Scott Atlakson <[email protected]>
218219
Jon Banafato <[email protected]>
219220
Jon Dufresne <[email protected]>

src/pip/_internal/vcs/subversion.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from pip._internal.utils.misc import (
99
display_path, rmtree, split_auth_from_netloc,
1010
)
11+
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
1112
from pip._internal.vcs import VersionControl, vcs
1213

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

1819

20+
if MYPY_CHECK_RUNNING:
21+
from typing import Optional, Tuple
22+
1923
logger = logging.getLogger(__name__)
2024

2125

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

40+
def get_vcs_version(self):
41+
# type: () -> Optional[Tuple[int, ...]]
42+
"""Return the version of the currently installed Subversion client.
43+
44+
:return: A tuple containing the parts of the version information or
45+
``None`` if the version returned from ``svn`` could not be parsed.
46+
:raises: BadCommand: If ``svn`` is not installed.
47+
"""
48+
# Example versions:
49+
# svn, version 1.10.3 (r1842928)
50+
# compiled Feb 25 2019, 14:20:39 on x86_64-apple-darwin17.0.0
51+
# svn, version 1.7.14 (r1542130)
52+
# compiled Mar 28 2018, 08:49:13 on x86_64-pc-linux-gnu
53+
version_prefix = 'svn, version '
54+
version = self.run_command(['--version'], show_stdout=False)
55+
if not version.startswith(version_prefix):
56+
return None
57+
58+
version = version[len(version_prefix):].split()[0]
59+
version_list = version.split('.')
60+
try:
61+
parsed_version = tuple(map(int, version_list))
62+
except ValueError:
63+
return None
64+
65+
if not parsed_version:
66+
return None
67+
68+
return parsed_version
69+
3670
def export(self, location):
3771
"""Export the svn repository at the url to the destination location"""
3872
url, rev_options = self.get_url_rev_options(self.url)

tests/lib/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -897,6 +897,14 @@ def is_bzr_installed():
897897
return True
898898

899899

900+
def is_svn_installed():
901+
try:
902+
subprocess.check_output(('svn', '--version'))
903+
except OSError:
904+
return False
905+
return True
906+
907+
900908
def need_bzr(fn):
901909
return pytest.mark.bzr(need_executable(
902910
'Bazaar', ('bzr', 'version', '--short')

tests/unit/test_vcs.py

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,33 @@
1+
import os
2+
13
import pytest
24
from mock import patch
35
from pip._vendor.packaging.version import parse as parse_version
46

7+
from pip._internal.exceptions import BadCommand
58
from pip._internal.vcs import (
69
RevOptions, VersionControl, make_vcs_requirement_url,
710
)
811
from pip._internal.vcs.bazaar import Bazaar
912
from pip._internal.vcs.git import Git, looks_like_hash
1013
from pip._internal.vcs.mercurial import Mercurial
1114
from pip._internal.vcs.subversion import Subversion
12-
from tests.lib import pyversion
15+
from tests.lib import is_svn_installed, pyversion
1316

1417
if pyversion >= '3':
1518
VERBOSE_FALSE = False
1619
else:
1720
VERBOSE_FALSE = 0
1821

1922

23+
@pytest.mark.skipif(
24+
'TRAVIS' not in os.environ,
25+
reason='Subversion is only required under Travis')
26+
def test_ensure_svn_available():
27+
"""Make sure that svn is available when running in Travis."""
28+
assert is_svn_installed()
29+
30+
2031
@pytest.mark.parametrize('args, expected', [
2132
# Test without subdir.
2233
(('git+https://example.com/pkg', 'dev', 'myproj'),
@@ -366,3 +377,49 @@ def test_subversion__get_url_rev_options():
366377
def test_get_git_version():
367378
git_version = Git().get_git_version()
368379
assert git_version >= parse_version('1.0.0')
380+
381+
382+
@pytest.mark.svn
383+
def test_subversion__get_vcs_version():
384+
"""
385+
Test Subversion.get_vcs_version() against local ``svn``.
386+
"""
387+
version = Subversion().get_vcs_version()
388+
assert len(version) == 3
389+
for part in version:
390+
assert isinstance(part, int)
391+
assert version[0] >= 1
392+
393+
394+
@pytest.mark.parametrize('svn_output, expected_version', [
395+
('svn, version 1.10.3 (r1842928)\n'
396+
' compiled Feb 25 2019, 14:20:39 on x86_64-apple-darwin17.0.0',
397+
(1, 10, 3)),
398+
('svn, version 1.9.7 (r1800392)', (1, 9, 7)),
399+
('svn, version 1.9.7a1 (r1800392)', None),
400+
('svn, version 1.9 (r1800392)', (1, 9)),
401+
('svn, version .9.7 (r1800392)', None),
402+
('svn version 1.9.7 (r1800392)', None),
403+
('svn 1.9.7', None),
404+
('svn, version . .', None),
405+
('', None),
406+
])
407+
@patch('pip._internal.vcs.subversion.Subversion.run_command')
408+
def test_subversion__get_vcs_version_patched(mock_run_command, svn_output,
409+
expected_version):
410+
"""
411+
Test Subversion.get_vcs_version() against patched output.
412+
"""
413+
mock_run_command.return_value = svn_output
414+
version = Subversion().get_vcs_version()
415+
assert version == expected_version
416+
417+
418+
@patch('pip._internal.vcs.subversion.Subversion.run_command')
419+
def test_subversion__get_vcs_version_svn_not_installed(mock_run_command):
420+
"""
421+
Test Subversion.get_vcs_version() when svn is not installed.
422+
"""
423+
mock_run_command.side_effect = BadCommand
424+
with pytest.raises(BadCommand):
425+
Subversion().get_vcs_version()

0 commit comments

Comments
 (0)