From 05cc51ad5894c8904d0fe5cdcf3f4d0a07dab85d Mon Sep 17 00:00:00 2001 From: Li YangX Date: Thu, 8 Oct 2015 09:27:14 +0000 Subject: BaseTools: Update Build tool to support multiple workspaces WORKSPACE is still kept. New PACKAGES_PATH is introduced to specify the additional WORKSPACEs. In PACKAGES_PATH, ';' is separator in Windows, ':' is separator in Linux. Build directory is in WORKSPACE. Package, BaseTools and Conf directory will be found from WORKSPACE and PACKAGES_PATH. In implementation, BaseTools adds MultipleWorkspace class for the file path conversion from WORKSPACE and PACKAGES_PATH. Verify two tree layouts. Root\edk2\MdePkg Root\edk2\MdeMdeModulePkg Root\edk2\... 1. set WORKSPACE=Root\edk2 2. set WORKSPACE=Root, and set PACKAGES_PATH=Root\edk2 Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Li YangX Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@18579 6f19259b-4bc3-4df7-8a09-765794883524 --- BaseTools/Source/Python/Common/EdkIIWorkspace.py | 3 +- BaseTools/Source/Python/Common/FdfParserLite.py | 6 +- .../Source/Python/Common/LongFilePathOsPath.py | 2 + BaseTools/Source/Python/Common/Misc.py | 7 +- .../Source/Python/Common/MultipleWorkspace.py | 148 +++++++++++++++++++++ BaseTools/Source/Python/Common/String.py | 8 +- 6 files changed, 169 insertions(+), 5 deletions(-) create mode 100644 BaseTools/Source/Python/Common/MultipleWorkspace.py (limited to 'BaseTools/Source/Python/Common') diff --git a/BaseTools/Source/Python/Common/EdkIIWorkspace.py b/BaseTools/Source/Python/Common/EdkIIWorkspace.py index 84d89b6c2e..401efeef3c 100644 --- a/BaseTools/Source/Python/Common/EdkIIWorkspace.py +++ b/BaseTools/Source/Python/Common/EdkIIWorkspace.py @@ -17,6 +17,7 @@ import Common.LongFilePathOs as os, sys, time from DataType import * from Common.LongFilePathSupport import OpenLongFilePath as open +from Common.MultipleWorkspace import MultipleWorkspace as mws ## EdkIIWorkspace # @@ -112,7 +113,7 @@ class EdkIIWorkspace: # @retval string The full path filename # def WorkspaceFile(self, FileName): - return os.path.realpath(os.path.join(self.WorkspaceDir,FileName)) + return os.path.realpath(mws.join(self.WorkspaceDir,FileName)) ## Convert to a real path filename # diff --git a/BaseTools/Source/Python/Common/FdfParserLite.py b/BaseTools/Source/Python/Common/FdfParserLite.py index 54a60a7e8f..a0ee249748 100644 --- a/BaseTools/Source/Python/Common/FdfParserLite.py +++ b/BaseTools/Source/Python/Common/FdfParserLite.py @@ -20,6 +20,7 @@ import Common.LongFilePathOs as os import CommonDataClass.FdfClass from Common.LongFilePathSupport import OpenLongFilePath as open +from Common.MultipleWorkspace import MultipleWorkspace as mws ##define T_CHAR_SPACE ' ' ##define T_CHAR_NULL '\0' @@ -485,7 +486,8 @@ class FdfParser(object): IncFileName = self.__Token if not os.path.isabs(IncFileName): if IncFileName.startswith('$(WORKSPACE)'): - Str = IncFileName.replace('$(WORKSPACE)', os.environ.get('WORKSPACE')) + Str = mws.handleWsMacro(IncFileName) + Str = Str.replace('$(WORKSPACE)', os.environ.get('WORKSPACE')) if os.path.exists(Str): if not os.path.isabs(Str): Str = os.path.abspath(Str) @@ -494,7 +496,7 @@ class FdfParser(object): # file is in the same dir with FDF file FullFdf = self.FileName if not os.path.isabs(self.FileName): - FullFdf = os.path.join(os.environ.get('WORKSPACE'), self.FileName) + FullFdf = mws.join(os.environ.get('WORKSPACE'), self.FileName) IncFileName = os.path.join(os.path.dirname(FullFdf), IncFileName) diff --git a/BaseTools/Source/Python/Common/LongFilePathOsPath.py b/BaseTools/Source/Python/Common/LongFilePathOsPath.py index cb89b1b813..0bba446419 100644 --- a/BaseTools/Source/Python/Common/LongFilePathOsPath.py +++ b/BaseTools/Source/Python/Common/LongFilePathOsPath.py @@ -49,3 +49,5 @@ dirname = os.path.dirname islink = os.path.islink isabs = os.path.isabs realpath = os.path.realpath +relpath = os.path.relpath +pardir = os.path.pardir diff --git a/BaseTools/Source/Python/Common/Misc.py b/BaseTools/Source/Python/Common/Misc.py index 8ba5819cc1..0eedddc861 100644 --- a/BaseTools/Source/Python/Common/Misc.py +++ b/BaseTools/Source/Python/Common/Misc.py @@ -35,6 +35,7 @@ from BuildToolError import * from CommonDataClass.DataClass import * from Parsing import GetSplitValueList from Common.LongFilePathSupport import OpenLongFilePath as open +from Common.MultipleWorkspace import MultipleWorkspace as mws ## Regular expression used to find out place holders in string template gPlaceholderPattern = re.compile("\$\{([^$()\s]+)\}", re.MULTILINE|re.UNICODE) @@ -1728,6 +1729,7 @@ class PathClass(object): # Remove any '.' and '..' in path if self.Root: + self.Root = mws.getWs(self.Root, self.File) self.Path = os.path.normpath(os.path.join(self.Root, self.File)) self.Root = os.path.normpath(CommonPath([self.Root, self.Path])) # eliminate the side-effect of 'C:' @@ -1838,7 +1840,10 @@ class PathClass(object): RealFile = os.path.join(self.AlterRoot, self.File) elif self.Root: RealFile = os.path.join(self.Root, self.File) - return FILE_NOT_FOUND, os.path.join(self.AlterRoot, RealFile) + if len (mws.getPkgPath()) == 0: + return FILE_NOT_FOUND, os.path.join(self.AlterRoot, RealFile) + else: + return FILE_NOT_FOUND, "%s is not found in packages path:\n\t%s" % (self.File, '\n\t'.join(mws.getPkgPath())) ErrorCode = 0 ErrorInfo = '' diff --git a/BaseTools/Source/Python/Common/MultipleWorkspace.py b/BaseTools/Source/Python/Common/MultipleWorkspace.py new file mode 100644 index 0000000000..8088404f30 --- /dev/null +++ b/BaseTools/Source/Python/Common/MultipleWorkspace.py @@ -0,0 +1,148 @@ +## @file +# manage multiple workspace file. +# +# This file is required to make Python interpreter treat the directory +# as containing package. +# +# Copyright (c) 2015, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# + +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 WORKSAPCE, 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 (Path)).startswith(Ws): + return os.path.join(Ws, Path[len(Ws) + 1:]) + 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() + # + # handle the $(WORKSPACE) tag, if current workspace is invalid path relative the tool, replace it. + # + # @param cls The class pointer + # @retval PathStr Path string include the $(WORKSPACE) + # + @classmethod + def handleWsMacro(cls, PathStr): + if TAB_WORKSPACE in PathStr: + Path = PathStr.replace(TAB_WORKSPACE, cls.WORKSPACE).strip() + if not os.path.exists(Path): + for Pkg in cls.PACKAGES_PATH: + Path = PathStr.replace(TAB_WORKSPACE, Pkg).strip() + if os.path.exists(Path): + return Path + return PathStr + + ## getPkgPath() + # + # get all package pathes. + # + # @param cls The class pointer + # + @classmethod + def getPkgPath(cls): + return cls.PACKAGES_PATH + \ No newline at end of file diff --git a/BaseTools/Source/Python/Common/String.py b/BaseTools/Source/Python/Common/String.py index 6c9671d514..5c8d1e0ded 100644 --- a/BaseTools/Source/Python/Common/String.py +++ b/BaseTools/Source/Python/Common/String.py @@ -24,6 +24,7 @@ import GlobalData from BuildToolError import * from CommonDataClass.Exceptions import * from Common.LongFilePathSupport import OpenLongFilePath as open +from Common.MultipleWorkspace import MultipleWorkspace as mws gHexVerPatt = re.compile('0x[a-f0-9]{4}[a-f0-9]{4}$', re.IGNORECASE) gHumanReadableVerPatt = re.compile(r'([1-9][0-9]*|0)\.[0-9]{1,2}$') @@ -305,6 +306,11 @@ def NormPath(Path, Defines={}): # To local path format # Path = os.path.normpath(Path) + if Path.startswith(GlobalData.gWorkspace) and not os.path.exists(Path): + Path = Path[len (GlobalData.gWorkspace):] + if Path[0] == os.path.sep: + Path = Path[1:] + Path = mws.join(GlobalData.gWorkspace, Path) if IsRelativePath and Path[0] != '.': Path = os.path.join('.', Path) @@ -702,7 +708,7 @@ def RaiseParserError(Line, Section, File, Format='', LineNo= -1): # @retval string A full path # def WorkspaceFile(WorkspaceDir, Filename): - return os.path.join(NormPath(WorkspaceDir), NormPath(Filename)) + return mws.join(NormPath(WorkspaceDir), NormPath(Filename)) ## Split string # -- cgit v1.2.3