Skip to content

Commit

Permalink
cygwin, gitpython-developers#525: Try to make it work with Cygwin's Git.
Browse files Browse the repository at this point in the history
+ Make `Git.polish_url()` convert paths into Cygwin-friendly paths.
+ Add utility and soe TCs for funcs for detecting cygwin and converting
abs-paths to `/cygdrive/c/...`.
  • Loading branch information
ankostis committed Oct 13, 2016
1 parent 57a6e9a commit 90d6903
Show file tree
Hide file tree
Showing 5 changed files with 250 additions and 67 deletions.
18 changes: 17 additions & 1 deletion git/cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
)
from git.exc import CommandError
from git.odict import OrderedDict
from git.util import is_cygwin_git, cygpath

from .exc import (
GitCommandError,
Expand Down Expand Up @@ -190,9 +191,24 @@ def __setstate__(self, d):
# Override this value using `Git.USE_SHELL = True`
USE_SHELL = False

@classmethod
def is_cygwin(cls):
return is_cygwin_git(cls.GIT_PYTHON_GIT_EXECUTABLE)

@classmethod
def polish_url(cls, url):
return url.replace("\\\\", "\\").replace("\\", "/")
if cls.is_cygwin():
"""Remove any backslahes from urls to be written in config files.
Windows might create config-files containing paths with backslashed,
but git stops liking them as it will escape the backslashes.
Hence we undo the escaping just to be sure.
"""
url = cygpath(url)
else:
url = url.replace("\\\\", "\\").replace("\\", "/")

return url

class AutoInterrupt(object):
"""Kill/Interrupt the stored process instance once this instance goes out of scope. It is
Expand Down
75 changes: 30 additions & 45 deletions git/repo/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,51 +4,21 @@
# This module is part of GitPython and is released under
# the BSD License: http://www.opensource.org/licenses/bsd-license.php

from git.exc import (
InvalidGitRepositoryError,
NoSuchPathError,
GitCommandError
)
from git.cmd import (
Git,
handle_process_output
)
from git.refs import (
HEAD,
Head,
Reference,
TagReference,
)
from git.objects import (
Submodule,
RootModule,
Commit
)
from git.util import (
Actor,
finalize_process
)
from git.index import IndexFile
from git.config import GitConfigParser
from git.remote import (
Remote,
add_progress,
to_progress_instance
)

from git.db import GitCmdObjectDB
from collections import namedtuple
import logging
import os
import re
import sys

from gitdb.util import (
join,
isfile,
hex_to_bin
)

from .fun import (
rev_parse,
is_git_dir,
find_git_dir,
touch,
from git.cmd import (
Git,
handle_process_output
)
from git.compat import (
text_type,
Expand All @@ -58,12 +28,17 @@
range,
is_win,
)
from git.config import GitConfigParser
from git.db import GitCmdObjectDB
from git.exc import InvalidGitRepositoryError, NoSuchPathError, GitCommandError
from git.index import IndexFile
from git.objects import Submodule, RootModule, Commit
from git.refs import HEAD, Head, Reference, TagReference
from git.remote import Remote, add_progress, to_progress_instance
from git.util import Actor, finalize_process

from .fun import rev_parse, is_git_dir, find_git_dir, touch

import os
import sys
import re
import logging
from collections import namedtuple

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -875,12 +850,22 @@ def _clone(cls, git, url, path, odb_default_type, progress, **kwargs):
progress = to_progress_instance(progress)

odbt = kwargs.pop('odbt', odb_default_type)
proc = git.clone(url, path, with_extended_output=True, as_process=True,

## A bug win cygwin's Git, when `--bare`
# it prepends the basename of the `url` into the `path::
# git clone --bare /cygwin/a/foo.git C:\\Work
# becomes::
# git clone --bare /cygwin/a/foo.git /cygwin/a/C:\\Work
#
clone_path = (Git.polish_url(path)
if Git.is_cygwin() and 'bare' in kwargs
else path)
proc = git.clone(Git.polish_url(url), clone_path, with_extended_output=True, as_process=True,
v=True, **add_progress(kwargs, git, progress))
if progress:
handle_process_output(proc, None, progress.new_message_handler(), finalize_process)
else:
(stdout, stderr) = proc.communicate() # FIXME: Will block of outputs are big!
(stdout, stderr) = proc.communicate() # FIXME: Will block if outputs are big!
log.debug("Cmd(%s)'s unused stdout: %s", getattr(proc, 'args', ''), stdout)
finalize_process(proc, stderr=stderr)

Expand Down
2 changes: 1 addition & 1 deletion git/test/lib/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
'GIT_REPO', 'GIT_DAEMON_PORT'
)

log = logging.getLogger('git.util')
log = logging.getLogger(__name__)

#{ Routines

Expand Down
67 changes: 55 additions & 12 deletions git/test/test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,19 @@
# the BSD License: http://www.opensource.org/licenses/bsd-license.php

import tempfile
import time
from unittest.case import skipIf

import ddt

from git.cmd import dashify
from git.compat import string_types, is_win
from git.objects.util import (
altz_to_utctz_str,
utctz_to_altz,
verify_utctz,
parse_date,
)
from git.test.lib import (
TestBase,
assert_equal
Expand All @@ -15,19 +27,9 @@
BlockingLockFile,
get_user_id,
Actor,
IterableList
IterableList,
cygpath,
)
from git.objects.util import (
altz_to_utctz_str,
utctz_to_altz,
verify_utctz,
parse_date,
)
from git.cmd import dashify
from git.compat import string_types, is_win

import time
import ddt


class TestIterableMember(object):
Expand All @@ -52,6 +54,47 @@ def setup(self):
"array": [42],
}

@skipIf(not is_win, "Paths specifically for Windows.")
@ddt.data(
(r'foo\bar', 'foo/bar'),
(r'foo/bar', 'foo/bar'),
(r'./bar', 'bar'),
(r'.\bar', 'bar'),
(r'../bar', '../bar'),
(r'..\bar', '../bar'),
(r'../bar/.\foo/../chu', '../bar/chu'),
(r'C:\Users', '/cygdrive/c/Users'),
(r'C:\d/e', '/cygdrive/c/d/e'),
(r'\\?\a:\com', '/cygdrive/a/com'),
(r'\\?\a:/com', '/cygdrive/a/com'),
(r'\\server\C$\Users', '//server/C$/Users'),
(r'\\server\C$', '//server/C$'),
(r'\\server\BAR/', '//server/BAR/'),
(r'\\?\UNC\server\D$\Apps', '//server/D$/Apps'),
(r'D:/Apps', '/cygdrive/d/Apps'),
(r'D:/Apps\fOO', '/cygdrive/d/Apps/fOO'),
(r'D:\Apps/123', '/cygdrive/d/Apps/123'),
)
def test_cygpath_ok(self, case):
wpath, cpath = case
self.assertEqual(cygpath(wpath), cpath or wpath)

@skipIf(not is_win, "Paths specifically for Windows.")
@ddt.data(
(r'C:Relative', None),
(r'D:Apps\123', None),
(r'D:Apps/123', None),
(r'\\?\a:rel', None),
(r'\\share\a:rel', None),
)
def test_cygpath_invalids(self, case):
wpath, cpath = case
self.assertEqual(cygpath(wpath), cpath or wpath.replace('\\', '/'))

def test_it_should_dashify(self):
assert_equal('this-is-my-argument', dashify('this_is_my_argument'))
assert_equal('foo', dashify('foo'))
Expand Down
Loading

0 comments on commit 90d6903

Please sign in to comment.