Skip to content

Commit 3b1cfcc

Browse files
committed
cygwin, #533: Allow '/cygdrive/c/' paths on repo init
- Cygwin TCs failing: - PY2: err: 13, fail: 2 - PY3: err: 12, fail: 2
1 parent 57d0537 commit 3b1cfcc

File tree

4 files changed

+75
-29
lines changed

4 files changed

+75
-29
lines changed

Diff for: git/repo/base.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
from git.objects import Submodule, RootModule, Commit
3636
from git.refs import HEAD, Head, Reference, TagReference
3737
from git.remote import Remote, add_progress, to_progress_instance
38-
from git.util import Actor, finalize_process
38+
from git.util import Actor, finalize_process, decygpath
3939

4040
from .fun import rev_parse, is_git_dir, find_git_dir, touch
4141

@@ -99,6 +99,8 @@ def __init__(self, path=None, odbt=DefaultDBType, search_parent_directories=Fals
9999
repo = Repo("~/Development/git-python.git")
100100
repo = Repo("$REPOSITORIES/Development/git-python.git")
101101
102+
In *Cygwin*, path may be a `'cygdrive/...'` prefixed path.
103+
102104
:param odbt:
103105
Object DataBase type - a type which is constructed by providing
104106
the directory containing the database objects, i.e. .git/objects. It will
@@ -111,6 +113,9 @@ def __init__(self, path=None, odbt=DefaultDBType, search_parent_directories=Fals
111113
:raise InvalidGitRepositoryError:
112114
:raise NoSuchPathError:
113115
:return: git.Repo """
116+
if path and Git.is_cygwin():
117+
path = decygpath(path)
118+
114119
epath = _expand_path(path or os.getcwd())
115120
self.git = None # should be set for __del__ not to fail in case we raise
116121
if not os.path.exists(epath):

Diff for: git/test/test_repo.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
assert_true,
5151
raises
5252
)
53-
from git.util import HIDE_WINDOWS_KNOWN_ERRORS
53+
from git.util import HIDE_WINDOWS_KNOWN_ERRORS, cygpath
5454
from git.test.lib import with_rw_directory
5555
from git.util import join_path_native, rmtree, rmfile
5656
from gitdb.util import bin_to_hex
@@ -913,6 +913,8 @@ def test_work_tree_unsupported(self, rw_dir):
913913
rw_master = self.rorepo.clone(join_path_native(rw_dir, 'master_repo'))
914914
rw_master.git.checkout('HEAD~10')
915915
worktree_path = join_path_native(rw_dir, 'worktree_repo')
916+
if Git.is_cygwin():
917+
worktree_path = cygpath(worktree_path)
916918
try:
917919
rw_master.git.worktree('add', worktree_path, 'master')
918920
except Exception as ex:

Diff for: git/test/test_util.py

+53-26
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,34 @@
2929
Actor,
3030
IterableList,
3131
cygpath,
32+
decygpath
33+
)
34+
35+
36+
_norm_cygpath_pairs = (
37+
(r'foo\bar', 'foo/bar'),
38+
(r'foo/bar', 'foo/bar'),
39+
40+
(r'C:\Users', '/cygdrive/c/Users'),
41+
(r'C:\d/e', '/cygdrive/c/d/e'),
42+
43+
('C:\\', '/cygdrive/c/'),
44+
45+
(r'\\server\C$\Users', '//server/C$/Users'),
46+
(r'\\server\C$', '//server/C$'),
47+
('\\\\server\\c$\\', '//server/c$/'),
48+
(r'\\server\BAR/', '//server/BAR/'),
49+
50+
(r'D:/Apps', '/cygdrive/d/Apps'),
51+
(r'D:/Apps\fOO', '/cygdrive/d/Apps/fOO'),
52+
(r'D:\Apps/123', '/cygdrive/d/Apps/123'),
53+
)
54+
55+
_unc_cygpath_pairs = (
56+
(r'\\?\a:\com', '/cygdrive/a/com'),
57+
(r'\\?\a:/com', '/cygdrive/a/com'),
58+
59+
(r'\\?\UNC\server\D$\Apps', '//server/D$/Apps'),
3260
)
3361

3462

@@ -54,46 +82,45 @@ def setup(self):
5482
"array": [42],
5583
}
5684

85+
@skipIf(not is_win, "Paths specifically for Windows.")
86+
@ddt.idata(_norm_cygpath_pairs + _unc_cygpath_pairs)
87+
def test_cygpath_ok(self, case):
88+
wpath, cpath = case
89+
cwpath = cygpath(wpath)
90+
self.assertEqual(cwpath, cpath, wpath)
91+
5792
@skipIf(not is_win, "Paths specifically for Windows.")
5893
@ddt.data(
59-
(r'foo\bar', 'foo/bar'),
60-
(r'foo/bar', 'foo/bar'),
6194
(r'./bar', 'bar'),
6295
(r'.\bar', 'bar'),
6396
(r'../bar', '../bar'),
6497
(r'..\bar', '../bar'),
6598
(r'../bar/.\foo/../chu', '../bar/chu'),
66-
67-
(r'C:\Users', '/cygdrive/c/Users'),
68-
(r'C:\d/e', '/cygdrive/c/d/e'),
69-
70-
(r'\\?\a:\com', '/cygdrive/a/com'),
71-
(r'\\?\a:/com', '/cygdrive/a/com'),
72-
73-
(r'\\server\C$\Users', '//server/C$/Users'),
74-
(r'\\server\C$', '//server/C$'),
75-
(r'\\server\BAR/', '//server/BAR/'),
76-
(r'\\?\UNC\server\D$\Apps', '//server/D$/Apps'),
77-
78-
(r'D:/Apps', '/cygdrive/d/Apps'),
79-
(r'D:/Apps\fOO', '/cygdrive/d/Apps/fOO'),
80-
(r'D:\Apps/123', '/cygdrive/d/Apps/123'),
8199
)
82-
def test_cygpath_ok(self, case):
100+
def test_cygpath_norm_ok(self, case):
83101
wpath, cpath = case
84-
self.assertEqual(cygpath(wpath), cpath or wpath)
102+
cwpath = cygpath(wpath)
103+
self.assertEqual(cwpath, cpath or wpath, wpath)
85104

86105
@skipIf(not is_win, "Paths specifically for Windows.")
87106
@ddt.data(
88-
(r'C:Relative', None),
89-
(r'D:Apps\123', None),
90-
(r'D:Apps/123', None),
91-
(r'\\?\a:rel', None),
92-
(r'\\share\a:rel', None),
107+
r'C:',
108+
r'C:Relative',
109+
r'D:Apps\123',
110+
r'D:Apps/123',
111+
r'\\?\a:rel',
112+
r'\\share\a:rel',
93113
)
94-
def test_cygpath_invalids(self, case):
114+
def test_cygpath_invalids(self, wpath):
115+
cwpath = cygpath(wpath)
116+
self.assertEqual(cwpath, wpath.replace('\\', '/'), wpath)
117+
118+
@skipIf(not is_win, "Paths specifically for Windows.")
119+
@ddt.idata(_norm_cygpath_pairs)
120+
def test_decygpath(self, case):
95121
wpath, cpath = case
96-
self.assertEqual(cygpath(wpath), cpath or wpath.replace('\\', '/'))
122+
wcpath = decygpath(cpath)
123+
self.assertEqual(wcpath, wpath.replace('/', '\\'), cpath)
97124

98125
def test_it_should_dashify(self):
99126
assert_equal('this-is-my-argument', dashify('this_is_my_argument'))

Diff for: git/util.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ def _cygexpath(drive, path):
222222
# It's an error, leave it alone just slashes)
223223
p = path
224224
else:
225-
p = osp.normpath(osp.expandvars(os.path.expanduser(path)))
225+
p = path and osp.normpath(osp.expandvars(os.path.expanduser(path)))
226226
if osp.isabs(p):
227227
if drive:
228228
# Confusing, maybe a remote system should expand vars.
@@ -278,6 +278,18 @@ def cygpath(path):
278278
return path
279279

280280

281+
_decygpath_regex = re.compile(r"/cygdrive/(\w)(/.*)?")
282+
283+
284+
def decygpath(path):
285+
m = _decygpath_regex.match(path)
286+
if m:
287+
drive, rest_path = m.groups()
288+
path = '%s:%s' % (drive.upper(), rest_path or '')
289+
290+
return path.replace('/', '\\')
291+
292+
281293
#: Store boolean flags denoting if a specific Git executable
282294
#: is from a Cygwin installation (since `cache_lru()` unsupported on PY2).
283295
_is_cygwin_cache = {}

0 commit comments

Comments
 (0)