windows: introduce a `util.abspath` to replace os.path.abspath
This will let us mitigate the drive letter capitalization hell.
See inline comment for details.
Differential Revision: https://phab.mercurial-scm.org/D11059
--- a/mercurial/posix.py Sat Jul 10 13:10:18 2021 +0200
+++ b/mercurial/posix.py Sat Jul 10 13:46:24 2021 +0200
@@ -36,6 +36,8 @@
normpath = os.path.normpath
samestat = os.path.samestat
+abspath = os.path.abspath # re-exports
+
try:
oslink = os.link
except AttributeError:
--- a/mercurial/util.py Sat Jul 10 13:10:18 2021 +0200
+++ b/mercurial/util.py Sat Jul 10 13:46:24 2021 +0200
@@ -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)
--- a/mercurial/windows.py Sat Jul 10 13:10:18 2021 +0200
+++ b/mercurial/windows.py Sat Jul 10 13:46:24 2021 +0200
@@ -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