diff --git a/mercurial/posix.py b/mercurial/posix.py --- a/mercurial/posix.py +++ b/mercurial/posix.py @@ -36,6 +36,8 @@ normpath = os.path.normpath samestat = os.path.samestat +abspath = os.path.abspath # re-exports + try: oslink = os.link except AttributeError: diff --git a/mercurial/util.py b/mercurial/util.py --- a/mercurial/util.py +++ b/mercurial/util.py @@ -99,6 +99,7 @@ _ = i18n._ +abspath = platform.abspath bindunixsocket = platform.bindunixsocket cachestat = platform.cachestat checkexec = platform.checkexec @@ -2632,7 +2633,7 @@ return if err.errno != errno.ENOENT or not name: raise - parent = os.path.dirname(os.path.abspath(name)) + parent = os.path.dirname(abspath(name)) if parent == name: raise makedirs(parent, mode, notindexed) diff --git a/mercurial/windows.py b/mercurial/windows.py --- a/mercurial/windows.py +++ b/mercurial/windows.py @@ -333,6 +333,25 @@ return encoding.upper(path) # NTFS compares via upper() +DRIVE_RE_B = re.compile(b'^[a-z]:') +DRIVE_RE_S = re.compile('^[a-z]:') + + +def abspath(path): + abs_path = os.path.abspath(path) # re-exports + # Python on Windows is inconsistent regarding the capitalization of drive + # letter and this cause issue with various path comparison along the way. + # So we normalize the drive later to upper case here. + # + # See https://bugs.python.org/issue40368 for and example of this hell. + if isinstance(abs_path, bytes): + if DRIVE_RE_B.match(abs_path): + abs_path = abs_path[0:1].upper() + abs_path[1:] + elif DRIVE_RE_S.match(abs_path): + abs_path = abs_path[0:1].upper() + abs_path[1:] + return abs_path + + # see posix.py for definitions normcasespec = encoding.normcasespecs.upper normcasefallback = encoding.upperfallback