[edk2-devel] [edk2-staging/EdkRepo] [PATCH v1] EdkRepo: Fixing inconsistent win32 HOME path mapping

Bjorge, Erik C posted 1 patch 3 years, 8 months ago
Failed in applying to current master (apply log)
edkrepo/commands/sync_command.py        | 46 ++++++++++-----------
edkrepo/common/common_repo_functions.py |  6 +--
edkrepo/common/pathfix.py               | 54 ++++++++++++++++++++++++-
edkrepo/common/ui_functions.py          |  6 ++-
edkrepo/config/config_factory.py        |  3 +-
5 files changed, 85 insertions(+), 30 deletions(-)
[edk2-devel] [edk2-staging/EdkRepo] [PATCH v1] EdkRepo: Fixing inconsistent win32 HOME path mapping
Posted by Bjorge, Erik C 3 years, 8 months ago
In Python 3.8.x the method of mapping the users home path was changed
to look at USERPROFILE and then HOMEDRIVE\HOMEPATH.  This change removed
the check of HOME generated by git BASH based on HOMEDRIVE/HOMEPATH.
For users with a USERPROFILE environment variable that does not match
the HOMEDRIVE\HOMEPATH environment variables this can lead to
inconsistent decoding of files such as .gitconfig between BASH and
EdkRepo.

This change attempts to enforce a consistent decode order.
HOME, HOMEDRIVE\HOMEPATH and USERPROFILE.

Cc: Ashley E Desimone <ashley.e.desimone@intel.com>
Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>
Cc: Puja Pandya <puja.pandya@intel.com>
Cc: Bret Barkelew <Bret.Barkelew@microsoft.com>
Cc: Prince Agyeman <prince.agyeman@intel.com>
Cc: Erik Bjorge <erik.c.bjorge@intel.com>
Signed-off-by: Erik Bjorge <erik.c.bjorge@intel.com>
---
 edkrepo/commands/sync_command.py        | 46 ++++++++++-----------
 edkrepo/common/common_repo_functions.py |  6 +--
 edkrepo/common/pathfix.py               | 54 ++++++++++++++++++++++++-
 edkrepo/common/ui_functions.py          |  6 ++-
 edkrepo/config/config_factory.py        |  3 +-
 5 files changed, 85 insertions(+), 30 deletions(-)

diff --git a/edkrepo/commands/sync_command.py b/edkrepo/commands/sync_command.py
index 2cb4630..ea3eed3 100644
--- a/edkrepo/commands/sync_command.py
+++ b/edkrepo/commands/sync_command.py
@@ -31,14 +31,14 @@ from edkrepo.common.humble import NO_SYNC_DETACHED_HEAD, SYNC_COMMITS_ON_MASTER,
 from edkrepo.common.humble import MIRROR_BEHIND_PRIMARY_REPO, SYNC_NEEDS_REBASE, INCLUDED_FILE_NAME
 from edkrepo.common.humble import SYNC_BRANCH_CHANGE_ON_LOCAL, SYNC_INCOMPATIBLE_COMBO
 from edkrepo.common.humble import SYNC_REBASE_CALC_FAIL
-from edkrepo.common.pathfix import get_actual_path
+from edkrepo.common.pathfix import get_actual_path, expanduser
 from edkrepo.common.common_repo_functions import clone_repos, sparse_checkout_enabled
 from edkrepo.common.common_repo_functions import reset_sparse_checkout, sparse_checkout, verify_single_manifest
 from edkrepo.common.common_repo_functions import checkout_repos, check_dirty_repos
 from edkrepo.common.common_repo_functions import update_editor_config
 from edkrepo.common.common_repo_functions import update_repo_commit_template, get_latest_sha
 from edkrepo.common.common_repo_functions import has_primary_repo_remote, fetch_from_primary_repo, in_sync_with_primary
-from edkrepo.common.common_repo_functions import update_hooks, combinations_in_manifest
+from edkrepo.common.common_repo_functions import update_hooks, combinations_in_manifest
 from edkrepo.common.common_repo_functions import write_included_config, remove_included_config
 from edkrepo.common.workspace_maintenance.workspace_maintenance import generate_name_for_obsolete_backup
 from edkrepo.common.workspace_maintenance.manifest_repos_maintenance import pull_workspace_manifest_repo
@@ -48,7 +48,7 @@ from edkrepo.common.ui_functions import init_color_console
 from edkrepo.config.config_factory import get_workspace_path, get_workspace_manifest, get_edkrepo_global_data_directory
 from edkrepo.config.config_factory import get_workspace_manifest_file
 from edkrepo_manifest_parser.edk_manifest import CiIndexXml, ManifestXml
-from project_utils.submodule import deinit_submodules, maintain_submodules
+from project_utils.submodule import deinit_submodules, maintain_submodules
 
 
 class SyncCommand(EdkrepoCommand):
@@ -85,7 +85,7 @@ class SyncCommand(EdkrepoCommand):
         current_combo = initial_manifest.general_config.current_combo
         initial_sources = initial_manifest.get_repo_sources(current_combo)
         initial_hooks = initial_manifest.repo_hooks
-        initial_combo = current_combo
+        initial_combo = current_combo
 
         source_global_manifest_repo = find_source_manifest_repo(initial_manifest, config['cfg_file'], config['user_cfg_file'], args.source_manifest_repo)
         pull_workspace_manifest_repo(initial_manifest, config['cfg_file'], config['user_cfg_file'], args.source_manifest_repo, False)
@@ -102,7 +102,7 @@ class SyncCommand(EdkrepoCommand):
         if not args.update_local_manifest:
             self.__check_for_new_manifest(args, config, initial_manifest, workspace_path, global_manifest_directory)
         check_dirty_repos(initial_manifest, workspace_path)
-
+
         # Determine if sparse checkout needs to be disabled for this operation
         sparse_settings = initial_manifest.sparse_settings
         sparse_enabled = sparse_checkout_enabled(workspace_path, initial_sources)
@@ -116,7 +116,7 @@ class SyncCommand(EdkrepoCommand):
             reset_sparse_checkout(workspace_path, initial_sources)
 
         # Get the latest manifest if requested
-        if args.update_local_manifest:  # NOTE: hyphens in arg name replaced with underscores due to argparse
+        if args.update_local_manifest:  # NOTE: hyphens in arg name replaced with underscores due to argparse
             self.__update_local_manifest(args, config, initial_manifest, workspace_path, global_manifest_directory)
         manifest = get_workspace_manifest()
         if args.update_local_manifest:
@@ -130,12 +130,12 @@ class SyncCommand(EdkrepoCommand):
             repo_sources_to_sync = manifest.get_repo_sources(current_combo)
         manifest.write_current_combo(current_combo)
 
-        # At this point both new and old manifest files are ready so we can deinit any
-        # submodules that are removed due to a manifest update.
-        if not args.skip_submodule:
-            deinit_submodules(workspace_path, initial_manifest, initial_combo,
-                              manifest, current_combo, args.verbose)
-
+        # At this point both new and old manifest files are ready so we can deinit any
+        # submodules that are removed due to a manifest update.
+        if not args.skip_submodule:
+            deinit_submodules(workspace_path, initial_manifest, initial_combo,
+                              manifest, current_combo, args.verbose)
+
         sync_error = False
         # Calculate the hooks which need to be updated, added or removed for the sync
         if args.update_local_manifest:
@@ -205,15 +205,15 @@ class SyncCommand(EdkrepoCommand):
                 print(NO_SYNC_DETACHED_HEAD.format(repo_to_sync.root))
 
             # Update commit message templates
-            update_repo_commit_template(workspace_path, repo, repo_to_sync, config, global_manifest_directory)
+            update_repo_commit_template(workspace_path, repo, repo_to_sync, config, global_manifest_directory)
 
         if sync_error:
             print(SYNC_ERROR)
 
-        # Initialize submodules
-        if not args.skip_submodule:
-            maintain_submodules(workspace_path, manifest, current_combo, args.verbose)
-
+        # Initialize submodules
+        if not args.skip_submodule:
+            maintain_submodules(workspace_path, manifest, current_combo, args.verbose)
+
         # Restore sparse checkout state
         if sparse_enabled:
             print(SPARSE_CHECKOUT)
@@ -244,9 +244,9 @@ class SyncCommand(EdkrepoCommand):
         # the default combo
         initial_combos = combinations_in_manifest(initial_manifest)
         new_combos = combinations_in_manifest(new_manifest_to_check)
-        if current_combo not in new_combos:
-            new_sources_for_current_combo = new_manifest_to_check.get_repo_sources(new_manifest_to_check.general_config.default_combo)
-            new_sources = new_sources_for_current_combo
+        if current_combo not in new_combos:
+            new_sources_for_current_combo = new_manifest_to_check.get_repo_sources(new_manifest_to_check.general_config.default_combo)
+            new_sources = new_sources_for_current_combo
         else:
             new_sources_for_current_combo = new_manifest_to_check.get_repo_sources(current_combo)
             new_sources = new_manifest_to_check.get_repo_sources(current_combo)
@@ -330,7 +330,7 @@ class SyncCommand(EdkrepoCommand):
                 print(path_to_source)
             if len(sources_to_remove) > 0:
                 print(SYNC_REMOVE_LIST_END_FORMATTING)
-            clone_repos(args, workspace_path, sources_to_clone, new_manifest_to_check.repo_hooks, config, new_manifest_to_check)
+            clone_repos(args, workspace_path, sources_to_clone, new_manifest_to_check.repo_hooks, config, new_manifest_to_check)
             # Make a list of and only checkout repos that were newly cloned. Sync keeps repos on their initial active branches
             # cloning the entire combo can prevent existing repos from correctly being returned to their proper branch
             repos_to_checkout = []
@@ -395,7 +395,7 @@ class SyncCommand(EdkrepoCommand):
             print(SYNC_MANIFEST_UPDATE)
 
     def __check_submodule_config(self, workspace_path, manifest, repo_sources):
-        gitconfigpath = os.path.normpath(os.path.expanduser("~/.gitconfig"))
+        gitconfigpath = os.path.normpath(expanduser("~/.gitconfig"))
         gitglobalconfig = git.GitConfigParser(gitconfigpath, read_only=False)
         try:
             local_manifest_dir = os.path.join(workspace_path, "repo")
@@ -448,7 +448,7 @@ class SyncCommand(EdkrepoCommand):
             gitglobalconfig.release()
 
     def __clean_git_globalconfig(self):
-        global_gitconfig_path = os.path.normpath(os.path.expanduser("~/.gitconfig"))
+        global_gitconfig_path = os.path.normpath(expanduser("~/.gitconfig"))
         with git.GitConfigParser(global_gitconfig_path, read_only=False) as git_globalconfig:
             includeif_regex = re.compile('^includeIf "gitdir:(/.+)/"$')
             for section in git_globalconfig.sections():
diff --git a/edkrepo/common/common_repo_functions.py b/edkrepo/common/common_repo_functions.py
index a6a38cf..d14f89a 100644
--- a/edkrepo/common/common_repo_functions.py
+++ b/edkrepo/common/common_repo_functions.py
@@ -51,7 +51,7 @@ from edkrepo.common.humble import ERROR_WRITING_INCLUDE, MULTIPLE_SOURCE_ATTRIBU
 from edkrepo.common.humble import VERIFY_GLOBAL, VERIFY_ARCHIVED, VERIFY_PROJ, VERIFY_PROJ_FAIL
 from edkrepo.common.humble import VERIFY_PROJ_NOT_IN_INDEX, VERIFY_GLOBAL_FAIL
 from edkrepo.common.humble import SUBMODULE_DEINIT_FAILED
-from edkrepo.common.pathfix import get_actual_path
+from edkrepo.common.pathfix import get_actual_path, expanduser
 from project_utils.sparse import BuildInfo, process_sparse_checkout
 from edkrepo.config.config_factory import get_workspace_path
 from edkrepo.config.config_factory import get_workspace_manifest
@@ -164,7 +164,7 @@ def remove_included_config(remotes, submodule_alt_remotes, repo_directory):
             os.remove(include_to_remove)
 
 def write_conditional_include(workspace_path, repo_sources, included_configs):
-    gitconfigpath = os.path.normpath(os.path.expanduser("~/.gitconfig"))
+    gitconfigpath = os.path.normpath(expanduser("~/.gitconfig"))
     for source in repo_sources:
         for included_config in included_configs:
             if included_config[0] == source.remote_name:
@@ -566,7 +566,7 @@ def update_repo_commit_template(workspace_dir, repo, repo_info, config, global_m
 
     #Check for the presence of a gloablly defined commit template
     global_template_in_use = False
-    global_gitconfig_path = os.path.normpath(os.path.expanduser("~/.gitconfig"))
+    global_gitconfig_path = os.path.normpath(expanduser("~/.gitconfig"))
     with git.GitConfigParser(global_gitconfig_path, read_only=False) as gitglobalconfig:
         if gitglobalconfig.has_option(section='commit', option='template'):
             global_template = gitglobalconfig.get_value(section='commit', option='template')
diff --git a/edkrepo/common/pathfix.py b/edkrepo/common/pathfix.py
index 6f3b151..1a9c20f 100644
--- a/edkrepo/common/pathfix.py
+++ b/edkrepo/common/pathfix.py
@@ -3,7 +3,7 @@
 ## @file
 # checkout_command.py
 #
-# Copyright (c) 2018- 2019, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2018- 2020, Intel Corporation. All rights reserved.<BR>
 # SPDX-License-Identifier: BSD-2-Clause-Patent
 #
 import os
@@ -159,3 +159,55 @@ def get_actual_path(path):
         return ''.join(actual_path)
     else:
         return path
+
+
+def _get_bothseps(path):
+    if isinstance(path, bytes):
+        return b'\\/'
+    else:
+        return '\\/'
+
+
+def expanduser(path):
+    """
+    Wrapper to consistently map the users HOME directory location.  Currently
+    three separate environment variable sets exist to do this mapping.  The default
+    python mapping in ntpath.py may not work because of different priority of decode.
+    This function is designed to remove any variation.
+
+    Note: This is a copy of the ntpath.py function with minor modifications.
+    """
+    if sys.platform != 'win32':
+        return os.path.expanduser(path)
+
+    path = os.fspath(path)
+    if isinstance(path, bytes):
+        tilde = b'~'
+    else:
+        tilde = '~'
+    if not path.startswith(tilde):
+        return path
+    i, n = 1, len(path)
+    while i < n and path[i] not in _get_bothseps(path):
+        i += 1
+
+    if 'HOME' in os.environ:
+        userhome = os.environ['HOME']
+    elif 'HOMEPATH' in os.environ:
+        try:
+            drive = os.environ['HOMEDRIVE']
+        except KeyError:
+            drive = ''
+        userhome = os.path.join(drive, os.environ['HOMEPATH'])
+    elif 'USERPROFILE' in os.environ:
+        userhome = os.environ['USERPROFILE']
+    else:
+        return path
+
+    if isinstance(path, bytes):
+        userhome = os.fsencode(userhome)
+
+    if i != 1:  # ~user
+        userhome = os.path.join(os.path.dirname(userhome), path[1:i])
+
+    return userhome + path[i:]
diff --git a/edkrepo/common/ui_functions.py b/edkrepo/common/ui_functions.py
index d42c2de..a23ca91 100644
--- a/edkrepo/common/ui_functions.py
+++ b/edkrepo/common/ui_functions.py
@@ -3,7 +3,7 @@
 ## @file
 # ui_functions.py
 #
-# Copyright (c) 2017- 2019, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2017- 2020, Intel Corporation. All rights reserved.<BR>
 # SPDX-License-Identifier: BSD-2-Clause-Patent
 #
 
@@ -15,8 +15,10 @@ import git
 
 import colorama
 
+from edkrepo.common.pathfix import expanduser
+
 def init_color_console(force_color_output):
-    config = git.GitConfigParser(os.path.normpath(os.path.expanduser("~/.gitconfig")))
+    config = git.GitConfigParser(os.path.normpath(expanduser("~/.gitconfig")))
     config_color = config.get("color", "ui", fallback="auto")
     strip = not sys.stdout.isatty()
     convert = sys.stdout.isatty()
diff --git a/edkrepo/config/config_factory.py b/edkrepo/config/config_factory.py
index 116cb24..a82a438 100644
--- a/edkrepo/config/config_factory.py
+++ b/edkrepo/config/config_factory.py
@@ -19,6 +19,7 @@ from edkrepo.common.edkrepo_exception import EdkrepoWorkspaceInvalidException, E
 from edkrepo.common.edkrepo_exception import EdkrepoConfigFileReadOnlyException
 from edkrepo.common.humble import MIRROR_PRIMARY_REPOS_MISSING, MIRROR_DECODE_WARNING, MAX_PATCH_SET_INVALID
 from edkrepo_manifest_parser import edk_manifest
+from edkrepo.common.pathfix import expanduser
 
 def get_edkrepo_global_data_directory():
     global_data_dir = None
@@ -33,7 +34,7 @@ def get_edkrepo_global_data_directory():
         SHGetFolderPath(None, CSIDL_COMMON_APPDATA, None, SHGFP_TYPE_CURRENT, common_appdata)
         global_data_dir = os.path.join(common_appdata.value, "edkrepo")
     elif sys.platform == "darwin" or sys.platform.startswith("linux") or os.name == "posix":
-        global_data_dir = os.path.expanduser("~/.edkrepo")
+        global_data_dir = expanduser("~/.edkrepo")
     if not os.path.isdir(global_data_dir):
         if not os.path.exists(os.path.dirname(global_data_dir)):
             raise EdkrepoGlobalDataDirectoryNotFoundException(humble.GLOBAL_DATA_DIR_NOT_FOUND.format(os.path.dirname(global_data_dir)))
-- 
2.21.0.windows.1


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#63462): https://edk2.groups.io/g/devel/message/63462
Mute This Topic: https://groups.io/mt/75878234/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-

Re: [edk2-devel] [edk2-staging/EdkRepo] [PATCH v1] EdkRepo: Fixing inconsistent win32 HOME path mapping
Posted by Nate DeSimone 3 years, 8 months ago
Reviewed-by: Nate DeSimone <nathaniel.l.desimone@intel.com>

On 7/29/20, 6:10 PM, "Bjorge, Erik C" <erik.c.bjorge@intel.com> wrote:

    In Python 3.8.x the method of mapping the users home path was changed
    to look at USERPROFILE and then HOMEDRIVE\HOMEPATH.  This change removed
    the check of HOME generated by git BASH based on HOMEDRIVE/HOMEPATH.
    For users with a USERPROFILE environment variable that does not match
    the HOMEDRIVE\HOMEPATH environment variables this can lead to
    inconsistent decoding of files such as .gitconfig between BASH and
    EdkRepo.

    This change attempts to enforce a consistent decode order.
    HOME, HOMEDRIVE\HOMEPATH and USERPROFILE.

    Cc: Ashley E Desimone <ashley.e.desimone@intel.com>
    Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>
    Cc: Puja Pandya <puja.pandya@intel.com>
    Cc: Bret Barkelew <Bret.Barkelew@microsoft.com>
    Cc: Prince Agyeman <prince.agyeman@intel.com>
    Cc: Erik Bjorge <erik.c.bjorge@intel.com>
    Signed-off-by: Erik Bjorge <erik.c.bjorge@intel.com>
    ---
     edkrepo/commands/sync_command.py        | 46 ++++++++++-----------
     edkrepo/common/common_repo_functions.py |  6 +--
     edkrepo/common/pathfix.py               | 54 ++++++++++++++++++++++++-
     edkrepo/common/ui_functions.py          |  6 ++-
     edkrepo/config/config_factory.py        |  3 +-
     5 files changed, 85 insertions(+), 30 deletions(-)

    diff --git a/edkrepo/commands/sync_command.py b/edkrepo/commands/sync_command.py
    index 2cb4630..ea3eed3 100644
    --- a/edkrepo/commands/sync_command.py
    +++ b/edkrepo/commands/sync_command.py
    @@ -31,14 +31,14 @@ from edkrepo.common.humble import NO_SYNC_DETACHED_HEAD, SYNC_COMMITS_ON_MASTER,
     from edkrepo.common.humble import MIRROR_BEHIND_PRIMARY_REPO, SYNC_NEEDS_REBASE, INCLUDED_FILE_NAME
     from edkrepo.common.humble import SYNC_BRANCH_CHANGE_ON_LOCAL, SYNC_INCOMPATIBLE_COMBO
     from edkrepo.common.humble import SYNC_REBASE_CALC_FAIL
    -from edkrepo.common.pathfix import get_actual_path
    +from edkrepo.common.pathfix import get_actual_path, expanduser
     from edkrepo.common.common_repo_functions import clone_repos, sparse_checkout_enabled
     from edkrepo.common.common_repo_functions import reset_sparse_checkout, sparse_checkout, verify_single_manifest
     from edkrepo.common.common_repo_functions import checkout_repos, check_dirty_repos
     from edkrepo.common.common_repo_functions import update_editor_config
     from edkrepo.common.common_repo_functions import update_repo_commit_template, get_latest_sha
     from edkrepo.common.common_repo_functions import has_primary_repo_remote, fetch_from_primary_repo, in_sync_with_primary
    -from edkrepo.common.common_repo_functions import update_hooks, combinations_in_manifest
    +from edkrepo.common.common_repo_functions import update_hooks, combinations_in_manifest
     from edkrepo.common.common_repo_functions import write_included_config, remove_included_config
     from edkrepo.common.workspace_maintenance.workspace_maintenance import generate_name_for_obsolete_backup
     from edkrepo.common.workspace_maintenance.manifest_repos_maintenance import pull_workspace_manifest_repo
    @@ -48,7 +48,7 @@ from edkrepo.common.ui_functions import init_color_console
     from edkrepo.config.config_factory import get_workspace_path, get_workspace_manifest, get_edkrepo_global_data_directory
     from edkrepo.config.config_factory import get_workspace_manifest_file
     from edkrepo_manifest_parser.edk_manifest import CiIndexXml, ManifestXml
    -from project_utils.submodule import deinit_submodules, maintain_submodules
    +from project_utils.submodule import deinit_submodules, maintain_submodules


     class SyncCommand(EdkrepoCommand):
    @@ -85,7 +85,7 @@ class SyncCommand(EdkrepoCommand):
             current_combo = initial_manifest.general_config.current_combo
             initial_sources = initial_manifest.get_repo_sources(current_combo)
             initial_hooks = initial_manifest.repo_hooks
    -        initial_combo = current_combo
    +        initial_combo = current_combo

             source_global_manifest_repo = find_source_manifest_repo(initial_manifest, config['cfg_file'], config['user_cfg_file'], args.source_manifest_repo)
             pull_workspace_manifest_repo(initial_manifest, config['cfg_file'], config['user_cfg_file'], args.source_manifest_repo, False)
    @@ -102,7 +102,7 @@ class SyncCommand(EdkrepoCommand):
             if not args.update_local_manifest:
                 self.__check_for_new_manifest(args, config, initial_manifest, workspace_path, global_manifest_directory)
             check_dirty_repos(initial_manifest, workspace_path)
    -
    +
             # Determine if sparse checkout needs to be disabled for this operation
             sparse_settings = initial_manifest.sparse_settings
             sparse_enabled = sparse_checkout_enabled(workspace_path, initial_sources)
    @@ -116,7 +116,7 @@ class SyncCommand(EdkrepoCommand):
                 reset_sparse_checkout(workspace_path, initial_sources)

             # Get the latest manifest if requested
    -        if args.update_local_manifest:  # NOTE: hyphens in arg name replaced with underscores due to argparse
    +        if args.update_local_manifest:  # NOTE: hyphens in arg name replaced with underscores due to argparse
                 self.__update_local_manifest(args, config, initial_manifest, workspace_path, global_manifest_directory)
             manifest = get_workspace_manifest()
             if args.update_local_manifest:
    @@ -130,12 +130,12 @@ class SyncCommand(EdkrepoCommand):
                 repo_sources_to_sync = manifest.get_repo_sources(current_combo)
             manifest.write_current_combo(current_combo)

    -        # At this point both new and old manifest files are ready so we can deinit any
    -        # submodules that are removed due to a manifest update.
    -        if not args.skip_submodule:
    -            deinit_submodules(workspace_path, initial_manifest, initial_combo,
    -                              manifest, current_combo, args.verbose)
    -
    +        # At this point both new and old manifest files are ready so we can deinit any
    +        # submodules that are removed due to a manifest update.
    +        if not args.skip_submodule:
    +            deinit_submodules(workspace_path, initial_manifest, initial_combo,
    +                              manifest, current_combo, args.verbose)
    +
             sync_error = False
             # Calculate the hooks which need to be updated, added or removed for the sync
             if args.update_local_manifest:
    @@ -205,15 +205,15 @@ class SyncCommand(EdkrepoCommand):
                     print(NO_SYNC_DETACHED_HEAD.format(repo_to_sync.root))

                 # Update commit message templates
    -            update_repo_commit_template(workspace_path, repo, repo_to_sync, config, global_manifest_directory)
    +            update_repo_commit_template(workspace_path, repo, repo_to_sync, config, global_manifest_directory)

             if sync_error:
                 print(SYNC_ERROR)

    -        # Initialize submodules
    -        if not args.skip_submodule:
    -            maintain_submodules(workspace_path, manifest, current_combo, args.verbose)
    -
    +        # Initialize submodules
    +        if not args.skip_submodule:
    +            maintain_submodules(workspace_path, manifest, current_combo, args.verbose)
    +
             # Restore sparse checkout state
             if sparse_enabled:
                 print(SPARSE_CHECKOUT)
    @@ -244,9 +244,9 @@ class SyncCommand(EdkrepoCommand):
             # the default combo
             initial_combos = combinations_in_manifest(initial_manifest)
             new_combos = combinations_in_manifest(new_manifest_to_check)
    -        if current_combo not in new_combos:
    -            new_sources_for_current_combo = new_manifest_to_check.get_repo_sources(new_manifest_to_check.general_config.default_combo)
    -            new_sources = new_sources_for_current_combo
    +        if current_combo not in new_combos:
    +            new_sources_for_current_combo = new_manifest_to_check.get_repo_sources(new_manifest_to_check.general_config.default_combo)
    +            new_sources = new_sources_for_current_combo
             else:
                 new_sources_for_current_combo = new_manifest_to_check.get_repo_sources(current_combo)
                 new_sources = new_manifest_to_check.get_repo_sources(current_combo)
    @@ -330,7 +330,7 @@ class SyncCommand(EdkrepoCommand):
                     print(path_to_source)
                 if len(sources_to_remove) > 0:
                     print(SYNC_REMOVE_LIST_END_FORMATTING)
    -            clone_repos(args, workspace_path, sources_to_clone, new_manifest_to_check.repo_hooks, config, new_manifest_to_check)
    +            clone_repos(args, workspace_path, sources_to_clone, new_manifest_to_check.repo_hooks, config, new_manifest_to_check)
                 # Make a list of and only checkout repos that were newly cloned. Sync keeps repos on their initial active branches
                 # cloning the entire combo can prevent existing repos from correctly being returned to their proper branch
                 repos_to_checkout = []
    @@ -395,7 +395,7 @@ class SyncCommand(EdkrepoCommand):
                 print(SYNC_MANIFEST_UPDATE)

         def __check_submodule_config(self, workspace_path, manifest, repo_sources):
    -        gitconfigpath = os.path.normpath(os.path.expanduser("~/.gitconfig"))
    +        gitconfigpath = os.path.normpath(expanduser("~/.gitconfig"))
             gitglobalconfig = git.GitConfigParser(gitconfigpath, read_only=False)
             try:
                 local_manifest_dir = os.path.join(workspace_path, "repo")
    @@ -448,7 +448,7 @@ class SyncCommand(EdkrepoCommand):
                 gitglobalconfig.release()

         def __clean_git_globalconfig(self):
    -        global_gitconfig_path = os.path.normpath(os.path.expanduser("~/.gitconfig"))
    +        global_gitconfig_path = os.path.normpath(expanduser("~/.gitconfig"))
             with git.GitConfigParser(global_gitconfig_path, read_only=False) as git_globalconfig:
                 includeif_regex = re.compile('^includeIf "gitdir:(/.+)/"$')
                 for section in git_globalconfig.sections():
    diff --git a/edkrepo/common/common_repo_functions.py b/edkrepo/common/common_repo_functions.py
    index a6a38cf..d14f89a 100644
    --- a/edkrepo/common/common_repo_functions.py
    +++ b/edkrepo/common/common_repo_functions.py
    @@ -51,7 +51,7 @@ from edkrepo.common.humble import ERROR_WRITING_INCLUDE, MULTIPLE_SOURCE_ATTRIBU
     from edkrepo.common.humble import VERIFY_GLOBAL, VERIFY_ARCHIVED, VERIFY_PROJ, VERIFY_PROJ_FAIL
     from edkrepo.common.humble import VERIFY_PROJ_NOT_IN_INDEX, VERIFY_GLOBAL_FAIL
     from edkrepo.common.humble import SUBMODULE_DEINIT_FAILED
    -from edkrepo.common.pathfix import get_actual_path
    +from edkrepo.common.pathfix import get_actual_path, expanduser
     from project_utils.sparse import BuildInfo, process_sparse_checkout
     from edkrepo.config.config_factory import get_workspace_path
     from edkrepo.config.config_factory import get_workspace_manifest
    @@ -164,7 +164,7 @@ def remove_included_config(remotes, submodule_alt_remotes, repo_directory):
                 os.remove(include_to_remove)

     def write_conditional_include(workspace_path, repo_sources, included_configs):
    -    gitconfigpath = os.path.normpath(os.path.expanduser("~/.gitconfig"))
    +    gitconfigpath = os.path.normpath(expanduser("~/.gitconfig"))
         for source in repo_sources:
             for included_config in included_configs:
                 if included_config[0] == source.remote_name:
    @@ -566,7 +566,7 @@ def update_repo_commit_template(workspace_dir, repo, repo_info, config, global_m

         #Check for the presence of a gloablly defined commit template
         global_template_in_use = False
    -    global_gitconfig_path = os.path.normpath(os.path.expanduser("~/.gitconfig"))
    +    global_gitconfig_path = os.path.normpath(expanduser("~/.gitconfig"))
         with git.GitConfigParser(global_gitconfig_path, read_only=False) as gitglobalconfig:
             if gitglobalconfig.has_option(section='commit', option='template'):
                 global_template = gitglobalconfig.get_value(section='commit', option='template')
    diff --git a/edkrepo/common/pathfix.py b/edkrepo/common/pathfix.py
    index 6f3b151..1a9c20f 100644
    --- a/edkrepo/common/pathfix.py
    +++ b/edkrepo/common/pathfix.py
    @@ -3,7 +3,7 @@
     ## @file
     # checkout_command.py
     #
    -# Copyright (c) 2018- 2019, Intel Corporation. All rights reserved.<BR>
    +# Copyright (c) 2018- 2020, Intel Corporation. All rights reserved.<BR>
     # SPDX-License-Identifier: BSD-2-Clause-Patent
     #
     import os
    @@ -159,3 +159,55 @@ def get_actual_path(path):
             return ''.join(actual_path)
         else:
             return path
    +
    +
    +def _get_bothseps(path):
    +    if isinstance(path, bytes):
    +        return b'\\/'
    +    else:
    +        return '\\/'
    +
    +
    +def expanduser(path):
    +    """
    +    Wrapper to consistently map the users HOME directory location.  Currently
    +    three separate environment variable sets exist to do this mapping.  The default
    +    python mapping in ntpath.py may not work because of different priority of decode.
    +    This function is designed to remove any variation.
    +
    +    Note: This is a copy of the ntpath.py function with minor modifications.
    +    """
    +    if sys.platform != 'win32':
    +        return os.path.expanduser(path)
    +
    +    path = os.fspath(path)
    +    if isinstance(path, bytes):
    +        tilde = b'~'
    +    else:
    +        tilde = '~'
    +    if not path.startswith(tilde):
    +        return path
    +    i, n = 1, len(path)
    +    while i < n and path[i] not in _get_bothseps(path):
    +        i += 1
    +
    +    if 'HOME' in os.environ:
    +        userhome = os.environ['HOME']
    +    elif 'HOMEPATH' in os.environ:
    +        try:
    +            drive = os.environ['HOMEDRIVE']
    +        except KeyError:
    +            drive = ''
    +        userhome = os.path.join(drive, os.environ['HOMEPATH'])
    +    elif 'USERPROFILE' in os.environ:
    +        userhome = os.environ['USERPROFILE']
    +    else:
    +        return path
    +
    +    if isinstance(path, bytes):
    +        userhome = os.fsencode(userhome)
    +
    +    if i != 1:  # ~user
    +        userhome = os.path.join(os.path.dirname(userhome), path[1:i])
    +
    +    return userhome + path[i:]
    diff --git a/edkrepo/common/ui_functions.py b/edkrepo/common/ui_functions.py
    index d42c2de..a23ca91 100644
    --- a/edkrepo/common/ui_functions.py
    +++ b/edkrepo/common/ui_functions.py
    @@ -3,7 +3,7 @@
     ## @file
     # ui_functions.py
     #
    -# Copyright (c) 2017- 2019, Intel Corporation. All rights reserved.<BR>
    +# Copyright (c) 2017- 2020, Intel Corporation. All rights reserved.<BR>
     # SPDX-License-Identifier: BSD-2-Clause-Patent
     #

    @@ -15,8 +15,10 @@ import git

     import colorama

    +from edkrepo.common.pathfix import expanduser
    +
     def init_color_console(force_color_output):
    -    config = git.GitConfigParser(os.path.normpath(os.path.expanduser("~/.gitconfig")))
    +    config = git.GitConfigParser(os.path.normpath(expanduser("~/.gitconfig")))
         config_color = config.get("color", "ui", fallback="auto")
         strip = not sys.stdout.isatty()
         convert = sys.stdout.isatty()
    diff --git a/edkrepo/config/config_factory.py b/edkrepo/config/config_factory.py
    index 116cb24..a82a438 100644
    --- a/edkrepo/config/config_factory.py
    +++ b/edkrepo/config/config_factory.py
    @@ -19,6 +19,7 @@ from edkrepo.common.edkrepo_exception import EdkrepoWorkspaceInvalidException, E
     from edkrepo.common.edkrepo_exception import EdkrepoConfigFileReadOnlyException
     from edkrepo.common.humble import MIRROR_PRIMARY_REPOS_MISSING, MIRROR_DECODE_WARNING, MAX_PATCH_SET_INVALID
     from edkrepo_manifest_parser import edk_manifest
    +from edkrepo.common.pathfix import expanduser

     def get_edkrepo_global_data_directory():
         global_data_dir = None
    @@ -33,7 +34,7 @@ def get_edkrepo_global_data_directory():
             SHGetFolderPath(None, CSIDL_COMMON_APPDATA, None, SHGFP_TYPE_CURRENT, common_appdata)
             global_data_dir = os.path.join(common_appdata.value, "edkrepo")
         elif sys.platform == "darwin" or sys.platform.startswith("linux") or os.name == "posix":
    -        global_data_dir = os.path.expanduser("~/.edkrepo")
    +        global_data_dir = expanduser("~/.edkrepo")
         if not os.path.isdir(global_data_dir):
             if not os.path.exists(os.path.dirname(global_data_dir)):
                 raise EdkrepoGlobalDataDirectoryNotFoundException(humble.GLOBAL_DATA_DIR_NOT_FOUND.format(os.path.dirname(global_data_dir)))
    -- 
    2.21.0.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#63658): https://edk2.groups.io/g/devel/message/63658
Mute This Topic: https://groups.io/mt/75878234/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-

Re: [edk2-devel] [edk2-staging/EdkRepo] [PATCH v1] EdkRepo: Fixing inconsistent win32 HOME path mapping
Posted by Ashley E Desimone 3 years, 8 months ago
Reviewed-by: Ashley DeSimone <ashley.e.desimone@intel.com>

-----Original Message-----
From: Bjorge, Erik C <erik.c.bjorge@intel.com> 
Sent: Wednesday, July 29, 2020 6:10 PM
To: devel@edk2.groups.io
Cc: Desimone, Ashley E <ashley.e.desimone@intel.com>; Desimone, Nathaniel L <nathaniel.l.desimone@intel.com>; Pandya, Puja <puja.pandya@intel.com>; Bret Barkelew <Bret.Barkelew@microsoft.com>; Agyeman, Prince <prince.agyeman@intel.com>
Subject: [edk2-staging/EdkRepo] [PATCH v1] EdkRepo: Fixing inconsistent win32 HOME path mapping

In Python 3.8.x the method of mapping the users home path was changed to look at USERPROFILE and then HOMEDRIVE\HOMEPATH.  This change removed the check of HOME generated by git BASH based on HOMEDRIVE/HOMEPATH.
For users with a USERPROFILE environment variable that does not match the HOMEDRIVE\HOMEPATH environment variables this can lead to inconsistent decoding of files such as .gitconfig between BASH and EdkRepo.

This change attempts to enforce a consistent decode order.
HOME, HOMEDRIVE\HOMEPATH and USERPROFILE.

Cc: Ashley E Desimone <ashley.e.desimone@intel.com>
Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>
Cc: Puja Pandya <puja.pandya@intel.com>
Cc: Bret Barkelew <Bret.Barkelew@microsoft.com>
Cc: Prince Agyeman <prince.agyeman@intel.com>
Cc: Erik Bjorge <erik.c.bjorge@intel.com>
Signed-off-by: Erik Bjorge <erik.c.bjorge@intel.com>
---
 edkrepo/commands/sync_command.py        | 46 ++++++++++-----------
 edkrepo/common/common_repo_functions.py |  6 +--
 edkrepo/common/pathfix.py               | 54 ++++++++++++++++++++++++-
 edkrepo/common/ui_functions.py          |  6 ++-
 edkrepo/config/config_factory.py        |  3 +-
 5 files changed, 85 insertions(+), 30 deletions(-)

diff --git a/edkrepo/commands/sync_command.py b/edkrepo/commands/sync_command.py
index 2cb4630..ea3eed3 100644
--- a/edkrepo/commands/sync_command.py
+++ b/edkrepo/commands/sync_command.py
@@ -31,14 +31,14 @@ from edkrepo.common.humble import NO_SYNC_DETACHED_HEAD, SYNC_COMMITS_ON_MASTER,  from edkrepo.common.humble import MIRROR_BEHIND_PRIMARY_REPO, SYNC_NEEDS_REBASE, INCLUDED_FILE_NAME  from edkrepo.common.humble import SYNC_BRANCH_CHANGE_ON_LOCAL, SYNC_INCOMPATIBLE_COMBO  from edkrepo.common.humble import SYNC_REBASE_CALC_FAIL -from edkrepo.common.pathfix import get_actual_path
+from edkrepo.common.pathfix import get_actual_path, expanduser
 from edkrepo.common.common_repo_functions import clone_repos, sparse_checkout_enabled  from edkrepo.common.common_repo_functions import reset_sparse_checkout, sparse_checkout, verify_single_manifest  from edkrepo.common.common_repo_functions import checkout_repos, check_dirty_repos  from edkrepo.common.common_repo_functions import update_editor_config  from edkrepo.common.common_repo_functions import update_repo_commit_template, get_latest_sha  from edkrepo.common.common_repo_functions import has_primary_repo_remote, fetch_from_primary_repo, in_sync_with_primary -from edkrepo.common.common_repo_functions import update_hooks, combinations_in_manifest
+from edkrepo.common.common_repo_functions import update_hooks, 
+combinations_in_manifest
 from edkrepo.common.common_repo_functions import write_included_config, remove_included_config  from edkrepo.common.workspace_maintenance.workspace_maintenance import generate_name_for_obsolete_backup  from edkrepo.common.workspace_maintenance.manifest_repos_maintenance import pull_workspace_manifest_repo @@ -48,7 +48,7 @@ from edkrepo.common.ui_functions import init_color_console  from edkrepo.config.config_factory import get_workspace_path, get_workspace_manifest, get_edkrepo_global_data_directory  from edkrepo.config.config_factory import get_workspace_manifest_file  from edkrepo_manifest_parser.edk_manifest import CiIndexXml, ManifestXml -from project_utils.submodule import deinit_submodules, maintain_submodules
+from project_utils.submodule import deinit_submodules, 
+maintain_submodules
 
 
 class SyncCommand(EdkrepoCommand):
@@ -85,7 +85,7 @@ class SyncCommand(EdkrepoCommand):
         current_combo = initial_manifest.general_config.current_combo
         initial_sources = initial_manifest.get_repo_sources(current_combo)
         initial_hooks = initial_manifest.repo_hooks
-        initial_combo = current_combo
+        initial_combo = current_combo
 
         source_global_manifest_repo = find_source_manifest_repo(initial_manifest, config['cfg_file'], config['user_cfg_file'], args.source_manifest_repo)
         pull_workspace_manifest_repo(initial_manifest, config['cfg_file'], config['user_cfg_file'], args.source_manifest_repo, False) @@ -102,7 +102,7 @@ class SyncCommand(EdkrepoCommand):
         if not args.update_local_manifest:
             self.__check_for_new_manifest(args, config, initial_manifest, workspace_path, global_manifest_directory)
         check_dirty_repos(initial_manifest, workspace_path)
-
+
         # Determine if sparse checkout needs to be disabled for this operation
         sparse_settings = initial_manifest.sparse_settings
         sparse_enabled = sparse_checkout_enabled(workspace_path, initial_sources) @@ -116,7 +116,7 @@ class SyncCommand(EdkrepoCommand):
             reset_sparse_checkout(workspace_path, initial_sources)
 
         # Get the latest manifest if requested
-        if args.update_local_manifest:  # NOTE: hyphens in arg name replaced with underscores due to argparse
+        if args.update_local_manifest:  # NOTE: hyphens in arg name 
+ replaced with underscores due to argparse
             self.__update_local_manifest(args, config, initial_manifest, workspace_path, global_manifest_directory)
         manifest = get_workspace_manifest()
         if args.update_local_manifest:
@@ -130,12 +130,12 @@ class SyncCommand(EdkrepoCommand):
             repo_sources_to_sync = manifest.get_repo_sources(current_combo)
         manifest.write_current_combo(current_combo)
 
-        # At this point both new and old manifest files are ready so we can deinit any
-        # submodules that are removed due to a manifest update.
-        if not args.skip_submodule:
-            deinit_submodules(workspace_path, initial_manifest, initial_combo,
-                              manifest, current_combo, args.verbose)
-
+        # At this point both new and old manifest files are ready so we can deinit any
+        # submodules that are removed due to a manifest update.
+        if not args.skip_submodule:
+            deinit_submodules(workspace_path, initial_manifest, initial_combo,
+                              manifest, current_combo, args.verbose)
+
         sync_error = False
         # Calculate the hooks which need to be updated, added or removed for the sync
         if args.update_local_manifest:
@@ -205,15 +205,15 @@ class SyncCommand(EdkrepoCommand):
                 print(NO_SYNC_DETACHED_HEAD.format(repo_to_sync.root))
 
             # Update commit message templates
-            update_repo_commit_template(workspace_path, repo, repo_to_sync, config, global_manifest_directory)
+            update_repo_commit_template(workspace_path, repo, 
+ repo_to_sync, config, global_manifest_directory)
 
         if sync_error:
             print(SYNC_ERROR)
 
-        # Initialize submodules
-        if not args.skip_submodule:
-            maintain_submodules(workspace_path, manifest, current_combo, args.verbose)
-
+        # Initialize submodules
+        if not args.skip_submodule:
+            maintain_submodules(workspace_path, manifest, 
+ current_combo, args.verbose)
+
         # Restore sparse checkout state
         if sparse_enabled:
             print(SPARSE_CHECKOUT)
@@ -244,9 +244,9 @@ class SyncCommand(EdkrepoCommand):
         # the default combo
         initial_combos = combinations_in_manifest(initial_manifest)
         new_combos = combinations_in_manifest(new_manifest_to_check)
-        if current_combo not in new_combos:
-            new_sources_for_current_combo = new_manifest_to_check.get_repo_sources(new_manifest_to_check.general_config.default_combo)
-            new_sources = new_sources_for_current_combo
+        if current_combo not in new_combos:
+            new_sources_for_current_combo = new_manifest_to_check.get_repo_sources(new_manifest_to_check.general_config.default_combo)
+            new_sources = new_sources_for_current_combo
         else:
             new_sources_for_current_combo = new_manifest_to_check.get_repo_sources(current_combo)
             new_sources = new_manifest_to_check.get_repo_sources(current_combo)
@@ -330,7 +330,7 @@ class SyncCommand(EdkrepoCommand):
                 print(path_to_source)
             if len(sources_to_remove) > 0:
                 print(SYNC_REMOVE_LIST_END_FORMATTING)
-            clone_repos(args, workspace_path, sources_to_clone, new_manifest_to_check.repo_hooks, config, new_manifest_to_check)
+            clone_repos(args, workspace_path, sources_to_clone, 
+ new_manifest_to_check.repo_hooks, config, new_manifest_to_check)
             # Make a list of and only checkout repos that were newly cloned. Sync keeps repos on their initial active branches
             # cloning the entire combo can prevent existing repos from correctly being returned to their proper branch
             repos_to_checkout = []
@@ -395,7 +395,7 @@ class SyncCommand(EdkrepoCommand):
             print(SYNC_MANIFEST_UPDATE)
 
     def __check_submodule_config(self, workspace_path, manifest, repo_sources):
-        gitconfigpath = os.path.normpath(os.path.expanduser("~/.gitconfig"))
+        gitconfigpath = os.path.normpath(expanduser("~/.gitconfig"))
         gitglobalconfig = git.GitConfigParser(gitconfigpath, read_only=False)
         try:
             local_manifest_dir = os.path.join(workspace_path, "repo") @@ -448,7 +448,7 @@ class SyncCommand(EdkrepoCommand):
             gitglobalconfig.release()
 
     def __clean_git_globalconfig(self):
-        global_gitconfig_path = os.path.normpath(os.path.expanduser("~/.gitconfig"))
+        global_gitconfig_path = 
+ os.path.normpath(expanduser("~/.gitconfig"))
         with git.GitConfigParser(global_gitconfig_path, read_only=False) as git_globalconfig:
             includeif_regex = re.compile('^includeIf "gitdir:(/.+)/"$')
             for section in git_globalconfig.sections():
diff --git a/edkrepo/common/common_repo_functions.py b/edkrepo/common/common_repo_functions.py
index a6a38cf..d14f89a 100644
--- a/edkrepo/common/common_repo_functions.py
+++ b/edkrepo/common/common_repo_functions.py
@@ -51,7 +51,7 @@ from edkrepo.common.humble import ERROR_WRITING_INCLUDE, MULTIPLE_SOURCE_ATTRIBU  from edkrepo.common.humble import VERIFY_GLOBAL, VERIFY_ARCHIVED, VERIFY_PROJ, VERIFY_PROJ_FAIL  from edkrepo.common.humble import VERIFY_PROJ_NOT_IN_INDEX, VERIFY_GLOBAL_FAIL  from edkrepo.common.humble import SUBMODULE_DEINIT_FAILED -from edkrepo.common.pathfix import get_actual_path
+from edkrepo.common.pathfix import get_actual_path, expanduser
 from project_utils.sparse import BuildInfo, process_sparse_checkout  from edkrepo.config.config_factory import get_workspace_path  from edkrepo.config.config_factory import get_workspace_manifest @@ -164,7 +164,7 @@ def remove_included_config(remotes, submodule_alt_remotes, repo_directory):
             os.remove(include_to_remove)
 
 def write_conditional_include(workspace_path, repo_sources, included_configs):
-    gitconfigpath = os.path.normpath(os.path.expanduser("~/.gitconfig"))
+    gitconfigpath = os.path.normpath(expanduser("~/.gitconfig"))
     for source in repo_sources:
         for included_config in included_configs:
             if included_config[0] == source.remote_name:
@@ -566,7 +566,7 @@ def update_repo_commit_template(workspace_dir, repo, repo_info, config, global_m
 
     #Check for the presence of a gloablly defined commit template
     global_template_in_use = False
-    global_gitconfig_path = os.path.normpath(os.path.expanduser("~/.gitconfig"))
+    global_gitconfig_path = 
+ os.path.normpath(expanduser("~/.gitconfig"))
     with git.GitConfigParser(global_gitconfig_path, read_only=False) as gitglobalconfig:
         if gitglobalconfig.has_option(section='commit', option='template'):
             global_template = gitglobalconfig.get_value(section='commit', option='template') diff --git a/edkrepo/common/pathfix.py b/edkrepo/common/pathfix.py index 6f3b151..1a9c20f 100644
--- a/edkrepo/common/pathfix.py
+++ b/edkrepo/common/pathfix.py
@@ -3,7 +3,7 @@
 ## @file
 # checkout_command.py
 #
-# Copyright (c) 2018- 2019, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2018- 2020, Intel Corporation. All rights reserved.<BR>
 # SPDX-License-Identifier: BSD-2-Clause-Patent  #  import os @@ -159,3 +159,55 @@ def get_actual_path(path):
         return ''.join(actual_path)
     else:
         return path
+
+
+def _get_bothseps(path):
+    if isinstance(path, bytes):
+        return b'\\/'
+    else:
+        return '\\/'
+
+
+def expanduser(path):
+    """
+    Wrapper to consistently map the users HOME directory location.  Currently
+    three separate environment variable sets exist to do this mapping.  The default
+    python mapping in ntpath.py may not work because of different priority of decode.
+    This function is designed to remove any variation.
+
+    Note: This is a copy of the ntpath.py function with minor modifications.
+    """
+    if sys.platform != 'win32':
+        return os.path.expanduser(path)
+
+    path = os.fspath(path)
+    if isinstance(path, bytes):
+        tilde = b'~'
+    else:
+        tilde = '~'
+    if not path.startswith(tilde):
+        return path
+    i, n = 1, len(path)
+    while i < n and path[i] not in _get_bothseps(path):
+        i += 1
+
+    if 'HOME' in os.environ:
+        userhome = os.environ['HOME']
+    elif 'HOMEPATH' in os.environ:
+        try:
+            drive = os.environ['HOMEDRIVE']
+        except KeyError:
+            drive = ''
+        userhome = os.path.join(drive, os.environ['HOMEPATH'])
+    elif 'USERPROFILE' in os.environ:
+        userhome = os.environ['USERPROFILE']
+    else:
+        return path
+
+    if isinstance(path, bytes):
+        userhome = os.fsencode(userhome)
+
+    if i != 1:  # ~user
+        userhome = os.path.join(os.path.dirname(userhome), path[1:i])
+
+    return userhome + path[i:]
diff --git a/edkrepo/common/ui_functions.py b/edkrepo/common/ui_functions.py index d42c2de..a23ca91 100644
--- a/edkrepo/common/ui_functions.py
+++ b/edkrepo/common/ui_functions.py
@@ -3,7 +3,7 @@
 ## @file
 # ui_functions.py
 #
-# Copyright (c) 2017- 2019, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2017- 2020, Intel Corporation. All rights reserved.<BR>
 # SPDX-License-Identifier: BSD-2-Clause-Patent  #
 
@@ -15,8 +15,10 @@ import git
 
 import colorama
 
+from edkrepo.common.pathfix import expanduser
+
 def init_color_console(force_color_output):
-    config = git.GitConfigParser(os.path.normpath(os.path.expanduser("~/.gitconfig")))
+    config = 
+ git.GitConfigParser(os.path.normpath(expanduser("~/.gitconfig")))
     config_color = config.get("color", "ui", fallback="auto")
     strip = not sys.stdout.isatty()
     convert = sys.stdout.isatty()
diff --git a/edkrepo/config/config_factory.py b/edkrepo/config/config_factory.py
index 116cb24..a82a438 100644
--- a/edkrepo/config/config_factory.py
+++ b/edkrepo/config/config_factory.py
@@ -19,6 +19,7 @@ from edkrepo.common.edkrepo_exception import EdkrepoWorkspaceInvalidException, E  from edkrepo.common.edkrepo_exception import EdkrepoConfigFileReadOnlyException
 from edkrepo.common.humble import MIRROR_PRIMARY_REPOS_MISSING, MIRROR_DECODE_WARNING, MAX_PATCH_SET_INVALID  from edkrepo_manifest_parser import edk_manifest
+from edkrepo.common.pathfix import expanduser
 
 def get_edkrepo_global_data_directory():
     global_data_dir = None
@@ -33,7 +34,7 @@ def get_edkrepo_global_data_directory():
         SHGetFolderPath(None, CSIDL_COMMON_APPDATA, None, SHGFP_TYPE_CURRENT, common_appdata)
         global_data_dir = os.path.join(common_appdata.value, "edkrepo")
     elif sys.platform == "darwin" or sys.platform.startswith("linux") or os.name == "posix":
-        global_data_dir = os.path.expanduser("~/.edkrepo")
+        global_data_dir = expanduser("~/.edkrepo")
     if not os.path.isdir(global_data_dir):
         if not os.path.exists(os.path.dirname(global_data_dir)):
             raise EdkrepoGlobalDataDirectoryNotFoundException(humble.GLOBAL_DATA_DIR_NOT_FOUND.format(os.path.dirname(global_data_dir)))
--
2.21.0.windows.1


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#63675): https://edk2.groups.io/g/devel/message/63675
Mute This Topic: https://groups.io/mt/75878234/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-