blob: dc105d7e18a8d7d3b5046cdbb981bdc9cd52023f [file]
## @file
# manage multiple workspace file.
#
# This file is required to make Python interpreter treat the directory
# as containing package.
#
# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
import re
import Common.LongFilePathOs as Os
from Common.DataType import TAB_WORKSPACE
## MultipleWorkspace
#
# This class manage multiple workspace behavior
#
# @param class:
#
# @var WORKSPACE: defined the current WORKSPACE
# @var PACKAGES_PATH: defined the other WORKSPACE, if current WORKSPACE is invalid, search valid WORKSPACE from PACKAGES_PATH
#
class MultipleWorkspace(object):
WORKSPACE = ''
PACKAGES_PATH = None
## convertPackagePath()
#
# Convert path to match workspace.
#
# @param cls The class pointer
# @param Ws The current WORKSPACE
# @param Path Path to be converted to match workspace.
#
@classmethod
def convertPackagePath(cls, Ws, Path):
if str(Os.path.normcase (Os.path.normpath(Path))).startswith(Os.path.normcase(Os.path.normpath(Ws))):
return Os.path.join(Ws, Os.path.relpath(Path, Ws))
return Path
## setWs()
#
# set WORKSPACE and PACKAGES_PATH environment
#
# @param cls The class pointer
# @param Ws initialize WORKSPACE variable
# @param PackagesPath initialize PackagesPath variable
#
@classmethod
def setWs(cls, Ws, PackagesPath=None):
cls.WORKSPACE = Ws
if PackagesPath:
cls.PACKAGES_PATH = [cls.convertPackagePath (Ws, Os.path.normpath(Path.strip())) for Path in PackagesPath.split(Os.pathsep)]
else:
cls.PACKAGES_PATH = []
## join()
#
# rewrite os.path.join function
#
# @param cls The class pointer
# @param Ws the current WORKSPACE
# @param *p path of the inf/dec/dsc/fdf/conf file
# @retval Path the absolute path of specified file
#
@classmethod
def join(cls, Ws, *p):
Path = Os.path.join(Ws, *p)
if not Os.path.exists(Path):
for Pkg in cls.PACKAGES_PATH:
Path = Os.path.join(Pkg, *p)
if Os.path.exists(Path):
return Path
Path = Os.path.join(Ws, *p)
return Path
## relpath()
#
# rewrite os.path.relpath function
#
# @param cls The class pointer
# @param Path path of the inf/dec/dsc/fdf/conf file
# @param Ws the current WORKSPACE
# @retval Path the relative path of specified file
#
@classmethod
def relpath(cls, Path, Ws):
for Pkg in cls.PACKAGES_PATH:
if Path.lower().startswith(Pkg.lower()):
Path = Os.path.relpath(Path, Pkg)
return Path
if Path.lower().startswith(Ws.lower()):
Path = Os.path.relpath(Path, Ws)
return Path
## getWs()
#
# get valid workspace for the path
#
# @param cls The class pointer
# @param Ws the current WORKSPACE
# @param Path path of the inf/dec/dsc/fdf/conf file
# @retval Ws the valid workspace relative to the specified file path
#
@classmethod
def getWs(cls, Ws, Path):
absPath = Os.path.join(Ws, Path)
if not Os.path.exists(absPath):
for Pkg in cls.PACKAGES_PATH:
absPath = Os.path.join(Pkg, Path)
if Os.path.exists(absPath):
return Pkg
return Ws
## handleWsMacro()
#
# Resolve $(WORKSPACE) paths against the workspace, then PACKAGES_PATH.
# Preserve quoting and whitespace; keep missing paths rooted in WORKSPACE.
#
# @param cls The class pointer
# @retval PathStr Path string include the $(WORKSPACE)
#
@classmethod
def handleWsMacro(cls, PathStr):
if TAB_WORKSPACE not in PathStr:
return PathStr
def ReplaceMacro(Match):
Token = Match.group(0)
if TAB_WORKSPACE not in Token:
return Token
# Group 1 captures the opening quote; \1 requires the same closing quote.
# Replace with group 2 (the contents) only for filesystem checks.
# The original token is unchanged, and Windows backslashes are not interpreted.
Unquoted = re.sub(r"""(["'])(.*?)\1""", r"\2", Token, flags=re.DOTALL)
Substr = Unquoted[Unquoted.find(TAB_WORKSPACE):]
Path = Substr.replace(TAB_WORKSPACE, cls.WORKSPACE)
if not Os.path.exists(Path):
for Pkg in cls.PACKAGES_PATH:
Path = Substr.replace(TAB_WORKSPACE, Pkg)
if Os.path.exists(Path):
return Token.replace(TAB_WORKSPACE, Pkg)
return Token.replace(TAB_WORKSPACE, cls.WORKSPACE)
# A token combines unquoted non-whitespace characters with complete quoted
# segments, keeping options such as --config=".../file name" together.
# Replace tokens in place so whitespace between them remains unchanged.
return re.sub(r"""(?:[^\s"']|"[^"]*"|'[^']*')+""", ReplaceMacro, PathStr)
## getPkgPath()
#
# get all package paths.
#
# @param cls The class pointer
#
@classmethod
def getPkgPath(cls):
return cls.PACKAGES_PATH