Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/SCons/scons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Brill <48932340+jcbrill@users.noreply.github.com>2023-10-15 00:19:59 +0300
committerJoseph Brill <48932340+jcbrill@users.noreply.github.com>2023-10-15 00:19:59 +0300
commitbcb02dc61812f159aee7b0327e92fabc5d79214d (patch)
treeee1d55ceca7ef93e31781ef54a210c1ca90f9f63
parent120b2cd0b71363f63e8eb4898a44f1ba8a48af64 (diff)
Replace process_path with normalize_path in MSCommon/MSVC/Util.py
Changes: * Replace process_path function with resolve_path and normalize_path functions in MSCommon/MSVC/Util.py. * Replace process_path invocations with normalize_path invocations. * Protect against inadvertent resolve/realpath for windows drive specifications in resolve_path and normalize_path. * Additional options for normalize_path with defaults consistent with process_path.
-rw-r--r--SCons/Tool/MSCommon/MSVC/Registry.py4
-rw-r--r--SCons/Tool/MSCommon/MSVC/Util.py87
-rw-r--r--SCons/Tool/MSCommon/MSVC/UtilTests.py103
-rw-r--r--SCons/Tool/MSCommon/MSVC/WinSDK.py4
4 files changed, 180 insertions, 18 deletions
diff --git a/SCons/Tool/MSCommon/MSVC/Registry.py b/SCons/Tool/MSCommon/MSVC/Registry.py
index eee20ccbc..f9e544c6f 100644
--- a/SCons/Tool/MSCommon/MSVC/Registry.py
+++ b/SCons/Tool/MSCommon/MSVC/Registry.py
@@ -62,7 +62,7 @@ def registry_query_path(key, val, suffix, expand: bool=True):
extval = val + '\\' + suffix if suffix else val
qpath = read_value(key, extval, expand=expand)
if qpath and os.path.exists(qpath):
- qpath = Util.process_path(qpath)
+ qpath = Util.normalize_path(qpath)
else:
qpath = None
return (qpath, key, val, extval)
@@ -81,7 +81,7 @@ def microsoft_query_paths(suffix, usrval=None, expand: bool=True):
extval = val + '\\' + suffix if suffix else val
qpath = read_value(key, extval, expand=expand)
if qpath and os.path.exists(qpath):
- qpath = Util.process_path(qpath)
+ qpath = Util.normalize_path(qpath)
if qpath not in paths:
paths.append(qpath)
records.append((qpath, key, val, extval, usrval))
diff --git a/SCons/Tool/MSCommon/MSVC/Util.py b/SCons/Tool/MSCommon/MSVC/Util.py
index 64b8d673e..8afe784ac 100644
--- a/SCons/Tool/MSCommon/MSVC/Util.py
+++ b/SCons/Tool/MSCommon/MSVC/Util.py
@@ -26,16 +26,25 @@ Helper functions for Microsoft Visual C/C++.
"""
import os
+import pathlib
import re
from collections import (
namedtuple,
)
+from ..common import debug
+
from . import Config
# path utilities
+# windows drive specification (e.g., 'C:')
+_RE_DRIVESPEC = re.compile(r'^[A-Za-z][:]$', re.IGNORECASE)
+
+# windows path separators
+_OS_PATH_SEPS = ('\\', '/')
+
def listdir_dirs(p):
"""
Return a list of tuples for each subdirectory of the given directory path.
@@ -57,22 +66,92 @@ def listdir_dirs(p):
dirs.append((dir_name, dir_path))
return dirs
-def process_path(p):
+def resolve_path(p, ignore_drivespec=True):
"""
- Normalize a system path
+ Make path absolute resolving any symlinks
Args:
p: str
system path
+ ignore_drivespec: bool
+ ignore drive specifications when True
Returns:
- str: normalized system path
+ str: absolute path with symlinks resolved
"""
+
if p:
+
+ if ignore_drivespec and _RE_DRIVESPEC.match(p):
+ # don't attempt to resolve drive specification (e.g., C:)
+ pass
+ else:
+ # both abspath and resolve necessary to produce identical path
+ # when (unqualified) file name is on a mapped network drive for
+ # python 3.6 and 3.11
+ p = os.path.abspath(p)
+ try:
+ p = str(pathlib.Path(p).resolve())
+ except OSError as e:
+ debug(
+ 'caught exception: path=%s, exception=%s(%s)',
+ repr(p), type(e).__name__, repr(str(e))
+ )
+
+ return p
+
+def normalize_path(
+ p,
+ strip=True,
+ preserve_trailing=False,
+ expand=False,
+ realpath=True,
+ ignore_drivespec=True,
+):
+ """
+ Normalize path
+
+ Args:
+ p: str
+ system path
+ strip: bool
+ remove leading and trailing whitespace when True
+ preserve_trailing: bool
+ preserve trailing path separator when True
+ expand: bool
+ apply expanduser and expandvars when True
+ realpath: bool
+ make the path absolute resolving any symlinks when True
+ ignore_drivespec: bool
+ ignore drive specifications for realpath when True
+
+ Returns:
+ str: normalized path
+
+ """
+
+ if p and strip:
+ p = p.strip()
+
+ if p:
+
+ trailing = bool(preserve_trailing and p.endswith(_OS_PATH_SEPS))
+
+ if expand:
+ p = os.path.expanduser(p)
+ p = os.path.expandvars(p)
+
p = os.path.normpath(p)
- p = os.path.realpath(p)
+
+ if realpath:
+ p = resolve_path(p, ignore_drivespec=ignore_drivespec)
+
p = os.path.normcase(p)
+
+ if trailing:
+ p += os.path.sep
+
return p
# msvc version and msvc toolset version regexes
diff --git a/SCons/Tool/MSCommon/MSVC/UtilTests.py b/SCons/Tool/MSCommon/MSVC/UtilTests.py
index 36e08f5eb..d92d2ca5c 100644
--- a/SCons/Tool/MSCommon/MSVC/UtilTests.py
+++ b/SCons/Tool/MSCommon/MSVC/UtilTests.py
@@ -28,14 +28,46 @@ Test helper functions for Microsoft Visual C/C++.
import unittest
import os
import re
+import sys
+import pathlib
from SCons.Tool.MSCommon.MSVC import Config
from SCons.Tool.MSCommon.MSVC import Util
from SCons.Tool.MSCommon.MSVC import WinSDK
+def resolve(p):
+ p = os.path.abspath(p)
+ p = str(pathlib.Path(p).resolve())
+ return p
+
+def normalize(*comps):
+ p = os.path.join(*comps)
+ p = os.path.normpath(p)
+ p = os.path.normcase(p)
+ return os.path.normcase(p)
+
class Data:
- UTIL_PARENT_DIR = os.path.join(os.path.dirname(Util.__file__), os.pardir)
+ IS_WINDOWS = sys.platform == 'win32'
+
+ CWD = os.getcwd()
+
+ UTIL_MODULE = os.path.dirname(Util.__file__)
+ UTIL_MODULE_PARENT = os.path.join(UTIL_MODULE, os.pardir)
+
+ HOME = pathlib.Path.home()
+ HOMEDRIVE = HOME.drive
+ HOMEPATH = str(HOME)
+
+ REALPATH_CWD = resolve(CWD)
+
+ REALPATH_UTIL_MODULE = resolve(UTIL_MODULE)
+ REALPATH_UTIL_MODULE_PARENT = resolve(UTIL_MODULE_PARENT)
+
+ REALPATH_HOMEPATH = resolve(HOMEPATH)
+ REALPATH_HOMEPATH_PARENT = resolve(os.path.join(HOMEPATH, os.pardir))
+ REALPATH_HOMEDRIVE = resolve(HOMEDRIVE)
+ REALPATH_HOMEDRIVE_CWD = resolve(HOMEDRIVE)
class UtilTests(unittest.TestCase):
@@ -43,21 +75,72 @@ class UtilTests(unittest.TestCase):
func = Util.listdir_dirs
for dirname, expect in [
(None, False), ('', False), ('doesnotexist.xyz.abc', False),
- (Data.UTIL_PARENT_DIR, True),
+ (Data.UTIL_MODULE_PARENT, True),
]:
dirs = func(dirname)
self.assertTrue((len(dirs) > 0) == expect, "{}({}): {}".format(
func.__name__, repr(dirname), 'list is empty' if expect else 'list is not empty'
))
- def test_process_path(self) -> None:
- func = Util.process_path
- for p, expect in [
- (None, True), ('', True),
- ('doesnotexist.xyz.abc', False), (Data.UTIL_PARENT_DIR, False),
- ]:
- rval = func(p)
- self.assertTrue((p == rval) == expect, "{}({}): {}".format(
+ def test_resolve_path(self) -> None:
+ func = Util.resolve_path
+ # default kwargs:
+ # ignore_drivespec=True
+ test_list = [
+ (Data.UTIL_MODULE, Data.REALPATH_UTIL_MODULE, {}),
+ (os.path.join(Data.UTIL_MODULE, os.pardir), Data.REALPATH_UTIL_MODULE_PARENT, {}),
+ (Data.HOMEPATH, Data.REALPATH_HOMEPATH, {}),
+ (os.path.join(Data.HOMEPATH, os.pardir), Data.REALPATH_HOMEPATH_PARENT, {}),
+ ]
+ if Data.IS_WINDOWS:
+ test_list.extend([
+ (Data.HOMEDRIVE, Data.HOMEDRIVE, {}),
+ (Data.HOMEDRIVE, Data.HOMEDRIVE, {'ignore_drivespec': True}),
+ (Data.HOMEDRIVE, Data.REALPATH_HOMEDRIVE_CWD, {'ignore_drivespec': False}),
+ ])
+ for p, expect, kwargs in test_list:
+ rval = func(p, **kwargs)
+ # print(repr(p), repr(expect), repr(rval))
+ self.assertTrue(rval == expect, "{}({}): {}".format(
+ func.__name__, repr(p), repr(rval)
+ ))
+
+ def test_normalize_path(self) -> None:
+ func = Util.normalize_path
+ # default kwargs:
+ # strip=True
+ # preserve_trailing=False
+ # expand=False
+ # realpath=True
+ # ignore_drivespec=True
+ test_list = [
+ (Data.UTIL_MODULE, normalize(Data.REALPATH_UTIL_MODULE), {}),
+ (os.path.join(Data.UTIL_MODULE, os.pardir), normalize(Data.REALPATH_UTIL_MODULE_PARENT), {}),
+ (None, None, {}),
+ ('', '', {'realpath': False}),
+ ('', '', {'realpath': True}),
+ ('DoesNotExist.xyz.abc', normalize('DoesNotExist.xyz.abc'), {'realpath': False}),
+ ('DoesNotExist.xyz.abc', normalize(Data.REALPATH_CWD, 'DoesNotExist.xyz.abc'), {'realpath': True}),
+ (' DoesNotExist.xyz.abc ', normalize(Data.REALPATH_CWD, 'DoesNotExist.xyz.abc'), {'realpath': True}),
+ (' ~ ', '~', {'realpath': False, 'expand': False}),
+ (' ~ ', normalize(Data.REALPATH_HOMEPATH), {'realpath': True, 'expand': True}),
+ ]
+ if Data.IS_WINDOWS:
+ test_list.extend([
+ ('DoesNotExist.xyz.abc/', normalize('DoesNotExist.xyz.abc') + os.path.sep, {'realpath': False, 'preserve_trailing': True}),
+ (' DoesNotExist.xyz.abc\\ ', normalize('DoesNotExist.xyz.abc') + os.path.sep, {'realpath': False, 'preserve_trailing': True}),
+ (' ~/ ', normalize(Data.REALPATH_HOMEPATH) + os.path.sep, {'realpath': True, 'expand': True, 'preserve_trailing': True}),
+ (' ~\\ ', normalize(Data.REALPATH_HOMEPATH) + os.path.sep, {'realpath': True, 'expand': True, 'preserve_trailing': True}),
+ (' ~/ ', normalize(Data.REALPATH_CWD, '~') + os.path.sep, {'realpath': True, 'expand': False, 'preserve_trailing': True}),
+ (' ~\\ ', normalize(Data.REALPATH_CWD, '~') + os.path.sep, {'realpath': True, 'expand': False, 'preserve_trailing': True}),
+ (Data.HOMEDRIVE, normalize(Data.HOMEDRIVE), {}),
+ (Data.HOMEDRIVE, normalize(Data.HOMEDRIVE), {'ignore_drivespec': True}),
+ (Data.HOMEDRIVE, normalize(Data.REALPATH_HOMEDRIVE_CWD), {'ignore_drivespec': False}),
+ ])
+ for p, expect, kwargs in test_list:
+ rval = func(p, **kwargs)
+ # print(repr(p), repr(expect), repr(rval))
+ self.assertTrue(rval == expect, "{}({}): {}".format(
func.__name__, repr(p), repr(rval)
))
diff --git a/SCons/Tool/MSCommon/MSVC/WinSDK.py b/SCons/Tool/MSCommon/MSVC/WinSDK.py
index 39617b16c..7115d505e 100644
--- a/SCons/Tool/MSCommon/MSVC/WinSDK.py
+++ b/SCons/Tool/MSCommon/MSVC/WinSDK.py
@@ -83,7 +83,7 @@ def _sdk_10_layout(version):
if not version_nbr.startswith(folder_prefix):
continue
- sdk_inc_path = Util.process_path(os.path.join(version_nbr_path, 'um'))
+ sdk_inc_path = Util.normalize_path(os.path.join(version_nbr_path, 'um'))
if not os.path.exists(sdk_inc_path):
continue
@@ -127,7 +127,7 @@ def _sdk_81_layout(version):
# msvc does not check for existence of root or other files
- sdk_inc_path = Util.process_path(os.path.join(sdk_root, r'include\um'))
+ sdk_inc_path = Util.normalize_path(os.path.join(sdk_root, r'include\um'))
if not os.path.exists(sdk_inc_path):
continue