def DoExecute(self) -> None: """ Copy a file or directory to the destination """ # Try to do a lookup srcPath = self.TryResolveSrcPathString(self.__SourceCommand.From) if srcPath is None: srcPath = IOUtil.Join(self.Info.SrcRootPath, self.__SourceCommand.From) dstPath = self.TryResolveDstPathString(self.__SourceCommand.To) if dstPath is None: dstPath = IOUtil.Join( self.Info.DstRootPath, self.__SourceCommand.To) if len( self.__SourceCommand.To) > 0 else self.Info.DstRootPath fileExist = IOUtil.Exists(dstPath) if not IOUtil.Exists(dstPath) or self.__Overwrite: if fileExist: self.LogPrint( "Copying from '{0}' to '{1}' overwriting the existing file" .format(srcPath, dstPath)) else: self.LogPrint("Copying from '{0}' to '{1}'".format( srcPath, dstPath)) if IOUtil.IsFile(srcPath): self._CreateDirectory(IOUtil.GetDirectoryName(dstPath)) shutil.copy2(srcPath, dstPath) elif IOUtil.IsDirectory(srcPath): self._CreateDirectory(IOUtil.GetDirectoryName(dstPath)) shutil.copytree(srcPath, dstPath) else: raise Exception("Copy source '{0}' not found".format(srcPath)) else: self.LogPrint( "Copying from '{0}' to '{1}' skipped as target exist".format( srcPath, dstPath))
def __init__(self, filename: str, strPackageName: Optional[str], packageLocation: ToolConfigPackageLocation) -> None: super(PackageFile, self).__init__() if not IOUtil.IsAbsolutePath(filename): raise UsageErrorException() if not isinstance(packageLocation, ToolConfigPackageLocation): raise UsageErrorException() filename = IOUtil.NormalizePath(filename) if not filename.startswith(packageLocation.ResolvedPathEx): raise UsageErrorException( "The filename '{0}' does not belong to the supplied location '{1}'" .format(filename, packageLocation.ResolvedPathEx)) self.Filename = IOUtil.GetFileName(filename) self.RelativeFilePath = filename[ len(packageLocation.ResolvedPathEx ):] # The full relative path to the file self.RelativeDirPath = IOUtil.GetDirectoryName( self.RelativeFilePath) # The relative containing directory self.AbsoluteFilePath = filename # type: str self.AbsoluteDirPath = IOUtil.GetDirectoryName(filename) # type: str self.PackageRootLocation = packageLocation # type: ToolConfigPackageLocation self.PackageName = self.__DeterminePackageNameFromRelativeName( self.RelativeDirPath ) if strPackageName is None else strPackageName # type: str
def __init__(self, log: Log, filename: str) -> None: if not os.path.isfile(filename): raise FileNotFoundException("Could not locate config file %s", filename) tree = ET.parse(filename) elem = tree.getroot() if elem.tag == 'FslBuildGeneratorVSProjectTemplate': pass elif elem.tag == 'FslBuildNewVSProjectTemplate': log.LogPrintWarning("Template file '{0}' using legacy template FslBuildNewVSProjectTemplate update it to FslBuildGeneratorVSProjectTemplate".format(filename)) else: raise XmlInvalidRootElement("The file did not contain the expected root tag 'FslBuildGeneratorVSProjectTemplate'") super().__init__(log, elem) strVersion = self._ReadAttrib(elem, 'Version') if strVersion != "1": raise Exception("Unsupported version") xmlTemplate = self.__LoadTemplateConfiguration(log, elem) if len(xmlTemplate) != 1: raise XmlException("The file did not contain exactly one Template element") directoryName = IOUtil.GetDirectoryName(filename) self.Name = IOUtil.GetFileName(directoryName) self.Id = self.Name.lower() self.Version = 1 self.Template = xmlTemplate[0] self.Path = IOUtil.GetDirectoryName(filename) self.Prefix = ("%s_" % (self.Name)).upper() if self.Name != self.Template.Name: raise Exception("The parent template directory name '{0}' does not match the template name '{1}' {2}".format(self.Name, self.Template.Name, self.Path))
def __ResolvePaths(self, config: Config, filename: str, allowNoInclude: bool) -> None: if not os.path.isabs(filename): raise UsageErrorException() self.AbsolutePath = IOUtil.GetDirectoryName(filename) if not self.IsVirtual: sourcePath = self.BaseSourcePath if self.PackageLanguage == PackageLanguage.CPP: self.__ResolvePathIncludeDir(config, allowNoInclude) elif self.PackageLanguage == PackageLanguage.CSharp: #sourcePath = self.Name pass else: raise UnsupportedException( "Unsupported package language: {0}".format( self.PackageLanguage)) self.AbsoluteSourcePath = IOUtil.Join(self.AbsolutePath, sourcePath) self.AbsoluteContentPath = IOUtil.Join(self.AbsolutePath, "Content") self.AbsoluteContentSourcePath = IOUtil.Join( self.AbsolutePath, "Content.bld") if not os.path.isdir(self.AbsoluteSourcePath ) and not config.DisableSourceDirCheck: raise PackageMissingRequiredSourceDirectoryException( self.AbsoluteSourcePath) elif self.Type == PackageType.HeaderLibrary: if self.PackageLanguage == PackageLanguage.CPP: self.__ResolvePathIncludeDir(config, allowNoInclude) else: raise UsageErrorException( "HeaderLibrary is only supported for C++")
def __AppendAdditional( self, log: Log, rPathDirRecords: List[PathRecord], pathFileRecords: List[PathRecord], additionalFiles: Optional[List[PathRecord]]) -> None: if additionalFiles is None: return uniqueDirs = set() for dirEntry in rPathDirRecords: uniqueDirs.add(dirEntry.RelativeId) uniqueFiles = {} for entry in pathFileRecords: uniqueFiles[entry.RelativeId] = entry for entry in additionalFiles: dirName = IOUtil.GetDirectoryName(entry.RelativePath) if len(dirName) > 0: dirId = dirName.lower() if not dirId in uniqueDirs: uniqueDirs.add(dirId) rPathDirRecords.append( PathRecord(log, entry.SourceRoot, dirName)) if entry.RelativeId in uniqueFiles: raise Exception( "The relative file name '{0}' has already been added by '{1}' and '{2}' tried to add it again" .format(uniqueFiles[entry.RelativeId].RelativePath, uniqueFiles[entry.RelativeId].ResolvedPath, entry.ResolvedPath)) pathFileRecords.append(entry) uniqueFiles[entry.RelativeId] = entry
def __init__(self, log: Log, filename: str) -> None: if not os.path.isfile(filename): raise FileNotFoundException("Could not locate config file %s", filename) tree = ET.parse(filename) elem = tree.getroot() if elem.tag != 'FslBuildGeneratorVSProjectTemplateCustomization': raise XmlInvalidRootElement( "The file did not contain the expected root tag 'FslBuildGeneratorVSProjectTemplateCustomization'" ) super().__init__(log, elem) strVersion = self._ReadAttrib(elem, 'Version') if strVersion != "1": raise Exception("Unsupported version") xmlConfiguration = self.__LoadTemplateConfiguration(log, elem) if len(xmlConfiguration) != 1: raise XmlException( "The file did not contain exactly one BuildOutput element") self.Version = 1 self.BuildOutput = xmlConfiguration[0] self.Path = IOUtil.GetDirectoryName(filename)
def __GetFailedFileCheckExtraHelpString(self, sourcePath: str) -> str: directoryName = IOUtil.GetDirectoryName(sourcePath) if not directoryName or IOUtil.IsDirectory(directoryName): return "" #filename = IOUtil.GetDirectoryName(sourcePath) return " The parent directory '{0}' did not exist either.".format( directoryName)
def __init__(self, log: Log, xmlElement: ET.Element, filename: str) -> None: super().__init__(log, xmlElement) #raise Exception("ExtendedProject not implemented"); self.ProjectName = self._ReadAttrib(xmlElement, 'Name') # type: str self.ShortProjectName = self._TryReadAttrib(xmlElement, 'ShortName') # type: Optional[str] self.ProjectVersion = self._ReadAttrib(xmlElement, 'Version', "1.0.0.0") # type: str self.RootDirectory = IOUtil.GetDirectoryName(filename) self.Parent = self._ReadAttrib(xmlElement, 'Parent') # type: str self.ParentRoot = self._ReadAttrib(xmlElement, 'ParentRoot') # type: str configFilename = IOUtil.GetFileName(filename) # type: str self.ParentConfigFilename = IOUtil.Join(self.ParentRoot, configFilename) # type: str self.SourceFileName = filename # type: str self.ProjectId = ProjectId(self.ProjectName, self.ShortProjectName) variableProcessor = VariableProcessor(log) self.AbsoluteParentConfigFilename = variableProcessor.ResolveAbsolutePathWithLeadingEnvironmentVariablePath(self.ParentConfigFilename) self.XmlPackageConfiguration = _LoadPackageConfigurations(log, xmlElement, filename) # type: List[XmlConfigPackageConfiguration] self.XmlBasePackages = _LoadAddBasePackage(log, xmlElement, filename) # type: List[XmlConfigFileAddBasePackage] self.XmlRootDirectories = _LoadAddRootDirectory(log, xmlElement, filename, self.ProjectId) # type: List[XmlConfigFileAddRootDirectory] self.XmlNewProjectTemplatesRootDirectories = LoadUtil.LoadAddNewProjectTemplatesRootDirectory(log, xmlElement, filename) self.XmlBuildDocConfiguration = _LoadBuildDocConfiguration(log, xmlElement, filename) # type: List[XmlBuildDocConfiguration] self.XmlClangFormatConfiguration = _LoadClangFormatConfiguration(log, xmlElement, filename) # type: List[XmlClangFormatConfiguration] self.XmlClangTidyConfiguration = _LoadClangTidyConfiguration(log, xmlElement, filename) # type: List[XmlClangTidyConfiguration] self.XmlCMakeConfiguration = _LoadCMakeConfiguration(log, xmlElement, filename) # type: List[XmlCMakeConfiguration] self.XmlCompilerConfiguration = _LoadCompilerConfiguration(log, xmlElement, filename) # type: List[XmlConfigCompilerConfiguration] self.XmlExperimental = _TryLoadExperimental(log, xmlElement, filename) # type: Optional[XmlExperimental]
def AddPackage(log: Log, toolConfig: ToolConfig, toolVersionOutputFile: str, writer: Writer, package: Package, outputFolder: str, toolProjectContextsDict: Dict[ProjectId, ToolConfigProjectContext], customPackageFileFilter: Optional[CustomPackageFileFilter], clangFormatConfiguration: ClangFormatConfiguration) -> None: outputFolder = IOUtil.Join(outputFolder, PackagePathUtil.GetPackagePath(package, toolProjectContextsDict)) filteredFiles = GetFilteredFiles(log, customPackageFileFilter, clangFormatConfiguration, package) formatPackageConfig = FormatPackageConfig(log, package, clangFormatConfiguration, filteredFiles) for fileEntry in formatPackageConfig.AllFiles: outputFile = "{0}.dmy".format(IOUtil.Join(outputFolder, fileEntry.SourcePath)) # Locate the closest clang format configuration file so we can add it as a implicit package dependency packageClosestFormatPath = FileFinder.FindClosestFileInRoot(log, toolConfig, fileEntry.ResolvedPath, clangFormatConfiguration.CustomFormatFile) packageClosestFormatFile = IOUtil.Join(packageClosestFormatPath, clangFormatConfiguration.CustomFormatFile) implicitDeps = [packageClosestFormatFile, toolVersionOutputFile] writer.build(outputs=outputFile, rule=PerformClangFormatHelper2.RULE_FORMAT, implicit=implicitDeps, inputs=fileEntry.ResolvedPath) # Write a dummy file so ninja finds a file (this is because clang format overwrites the existing file, so we need a dummy file to track progress) if not IOUtil.Exists(outputFile): parentDir = IOUtil.GetDirectoryName(outputFile) if not IOUtil.Exists(parentDir): IOUtil.SafeMakeDirs(parentDir) IOUtil.WriteFileIfChanged(outputFile, "")
def __init__(self, package: Package, resolvedInstallPath: str, addToolCommand: XmlRecipeValidateCommandAddTool) -> None: super().__init__() self.Package = package self.ToolName = IOUtil.GetFileNameWithoutExtension(addToolCommand.Name) self.RelativeToolPath = IOUtil.GetDirectoryName(addToolCommand.Name) self.AbsoluteToolPath = IOUtil.Join(resolvedInstallPath, self.RelativeToolPath)
def __CopyFiles(self, config: Config, dstPath: str, filesToCopy: List[TemplateFileRecord]) -> None: for file in filesToCopy: if not self.GenFileOnly or file.FileName == config.ToolConfig.GenFileName: dst = IOUtil.Join(dstPath, file.RelativeDestPath) dirName = IOUtil.GetDirectoryName(dst) if not config.DisableWrite: IOUtil.SafeMakeDirs(dirName) IOUtil.CopySmallFile(file.AbsoluteSourcePath, dst)
def __init__(self, packagePath: str, packageRelativeFilePath: str) -> None: packagePath = IOUtil.NormalizePath(packagePath) packageRelativeFilePath = IOUtil.NormalizePath(packageRelativeFilePath) if not IOUtil.IsAbsolutePath(packagePath): raise Exception("packagePath must be absolute") if IOUtil.IsAbsolutePath(packageRelativeFilePath): raise Exception("packageRelativeFilePath can not be absolute") self.Filename = IOUtil.GetFileName(packageRelativeFilePath) absFilePath = IOUtil.Join(packagePath, packageRelativeFilePath) self.AbsoluteFilePath = absFilePath self.AbsoluteDirPath = IOUtil.GetDirectoryName(absFilePath) self.PackageRelativeFilePath = packageRelativeFilePath self.PackageRelativeDirPath = IOUtil.GetDirectoryName( packageRelativeFilePath)
def __ValidateFileExtensions(self, fileExtensions: List[str]) -> None: for fileExt in fileExtensions: normalizedFileExt = IOUtil.NormalizePath(fileExt) directory = IOUtil.GetDirectoryName(normalizedFileExt) if len(directory) > 0: raise Exception("ClangTidyConfiguration: File extension '{0}' can not contain a directory '{1}'".format(fileExt, directory)) if fileExt.startswith(".."): raise Exception("ClangTidyConfiguration: File extension can not start with '..'") if not fileExt.startswith("."): raise Exception("ClangTidyConfiguration: File extension '{0}' does not start with '.'")
def TryFindClosestFileInRoot(log: Log, toolConfig: ToolConfig, startDirectory: str, findFilename: str) -> Optional[str]: foundPath = IOUtil.TryFindFileInCurrentOrParentDir( startDirectory, findFilename) if foundPath is None: return None foundDir = IOUtil.GetDirectoryName(foundPath) rootDir = toolConfig.TryFindRootDirectory(foundDir) return foundDir if rootDir is not None else None
def __GuessDiscoverFilename(self, packageDict: Dict[str, PackageInfo], sourceFilename: str) -> str: sourceDirectory = IOUtil.GetDirectoryName(sourceFilename) sourcePackageName = sourceDirectory.replace('/', '.') allSubPackageNames = sourcePackageName.split('.') while len(allSubPackageNames) > 0: packageNameCandidate = self.__GeneratePackageName(allSubPackageNames) if packageNameCandidate in packageDict: return packageNameCandidate allSubPackageNames.pop(0) raise Exception("Could not determine the package name for the file at '{0}'".format(sourceFilename))
def FindClosestFileInRoot(log: Log, toolConfig: ToolConfig, startDirectory: str, findFilename: str) -> str: foundPath = FileFinder.LocateFileInParentTree(log, startDirectory, findFilename) foundDir = IOUtil.GetDirectoryName(foundPath) rootDir = toolConfig.TryFindRootDirectory(foundDir) if rootDir is None: raise Exception( "Could not find a '{0}' file inside the project root".format( findFilename)) return foundDir
def __init__(self, userRequestedFNMatchPattern: str) -> None: super().__init__() userRequestedFNMatchPattern = IOUtil.NormalizePath( userRequestedFNMatchPattern) #self.FilterDirPath = IOUtil.NormalizePath(filterDirPath) self.UserRequestedFNMatchPattern = userRequestedFNMatchPattern self.IsAbsolutePattern = IOUtil.IsAbsolutePath( userRequestedFNMatchPattern) self.PatternFileName = IOUtil.GetFileName(userRequestedFNMatchPattern) patternDirectory = IOUtil.GetDirectoryName(userRequestedFNMatchPattern) if not self.IsAbsolutePattern and len( patternDirectory) > 0 and not patternDirectory.startswith('/'): patternDirectory = '/' + patternDirectory self.PatternDirectory = patternDirectory
def __MatchPaths(self, filenameList: List[str], filenameToPathsDict: Dict[str, List[str]], directoryPattern: str) -> List[str]: """ Match """ result = [] # type: List[str] for filename in filenameList: if filename in filenameToPathsDict: for filepath in filenameToPathsDict[filename]: filedirectory = IOUtil.GetDirectoryName(filepath) if filedirectory.endswith(directoryPattern): result.append(filepath) return result
def __init__(self, log: Log, filename: str) -> None: if not os.path.isfile(filename): raise FileNotFoundException("Could not locate config file %s", filename) tree = ET.parse(filename) elem = tree.getroot() if elem.tag != 'FslBuildNewTemplate': raise XmlInvalidRootElement("The file did not contain the expected root tag 'FslBuildGenConfig'") super().__init__(log, elem) fileVersion = self._ReadAttrib(elem, 'Version') if fileVersion != '1': raise Exception("The template file version was not correct") xmlTemplate = self.__LoadTemplateConfiguration(log, elem) if len(xmlTemplate) != 1: raise XmlException("The file did not contain exactly one Template element") self.Name = IOUtil.GetFileName(IOUtil.GetDirectoryName(filename)) self.Id = self.Name.lower() self.Version = int(fileVersion) # type: int self.Template = xmlTemplate[0] self.Path = IOUtil.GetDirectoryName(filename) self.Prefix = ("%s_" % (self.Name)).upper()
def __init__(self, filename: str, strPackageName: Optional[str], packageLocation: ToolConfigPackageLocation) -> None: filename = IOUtil.NormalizePath(filename) if not IOUtil.IsAbsolutePath(filename): raise UsageErrorException() rootRelativePath = filename[len(packageLocation.ResolvedPathEx):] super().__init__(IOUtil.GetDirectoryName(rootRelativePath), packageLocation, False) self.Filename = IOUtil.GetFileName(filename) self.RootRelativeFilePath = rootRelativePath # The full root relative path to the file self.AbsoluteFilePath = filename # type: str self.PackageName = self.__DeterminePackageNameFromRelativeName( self.RootRelativeDirPath ) if strPackageName is None else strPackageName # type: str
def __ProcessSyncFiles(self, log: Log, contentBuildPath: str, contentOutputPath: str, srcContent: Content, syncState: BuildState.SyncState, outputSyncState: BuildState.SyncState) -> None: dstRoot = GetContentOutputContentRootRecord(log, contentOutputPath) for contentFile in srcContent.Files: # Generate the output file record outputFileRecord = GetContentSyncOutputFilename( log, dstRoot, contentFile) outputFileName = contentFile.RelativePath ## Query the sync state of the content file syncStateFileName = self.__GetSyncStateFileName( contentFile.SourceRoot.ResolvedPath, contentFile.RelativePath) contentState = syncState.TryGetFileStateByFileName( syncStateFileName) buildResource = contentState is None or contentState.CacheState != BuildState.CacheState.Unmodified if not buildResource: # It was unmodified, so we need to examine the state of the output file to # determine if its safe to skip the building syncStateOutputFileName = self.__GetSyncStateFileName( contentOutputPath, outputFileName) outputContentState = outputSyncState.TryGetFileStateByFileName( syncStateOutputFileName) buildResource = not outputContentState or outputContentState.CacheState != BuildState.CacheState.Unmodified if buildResource: try: log.LogPrintVerbose( 2, "Copying '{0}' to '{1}'".format( contentFile.ResolvedPath, outputFileRecord.ResolvedPath)) dstDirPath = IOUtil.GetDirectoryName( outputFileRecord.ResolvedPath) IOUtil.SafeMakeDirs(dstDirPath) shutil.copy(contentFile.ResolvedPath, outputFileRecord.ResolvedPath) except: # Save if a exception occured to prevent reprocessing the working files outputSyncState.Save() syncState.Save() raise # Add a entry for the output file outputFileState = outputSyncState.BuildContentState( log, outputFileRecord, True, True) outputSyncState.Add(outputFileState)
def __init__(self, log: Log, appInfo: AppInfo, sourceFilename: str) -> None: self.Log = log self.SourceAppInfo = appInfo self.AbsolutePathSourceFile = sourceFilename self.AbsolutePath = IOUtil.GetDirectoryName(sourceFilename) self.__ResolvedPackageDict = self.__BuildPackageDict(appInfo) self.Name = self.__GuessDiscoverFilename(self.__ResolvedPackageDict, sourceFilename) self.ResolvedPackage = self.__ResolvedPackageDict[self.Name] self.ResolvedAllRequirements = self.__ResolvedAllRequirements(self.ResolvedPackage) # type: List[RequirementInfo] self.ResolvedAllUsedFeatures = self.__ResolvedAllUsedFeatures(self.ResolvedPackage) # type: List[RequirementInfo] self.ResolvedPlatformSupported = self.__ResolvedPlatformSupported(self.ResolvedPackage) # type: bool self.Type = self.ResolvedPackage.Type self.GeneratorReport = self.__ResolveGeneratorReport(self.ResolvedPackage) # To be compatible with the Package in some methods self.ResolvedDirectExperimentalRecipe = None
def __CopyAndModifyFiles(self, config: Config, dstPath: str, filesToModify: List[TemplateFileRecord], dstFilenameModifier: Optional[Callable[[str], str]]) -> None: for file in filesToModify: if not self.GenFileOnly or file.FileName == config.ToolConfig.GenFileName: dstFilename = IOUtil.Join(dstPath, file.RelativeDestPath) content = IOUtil.ReadFile(file.AbsoluteSourcePath) # Replace various strings using the 'template environment' for key, value in self.Environment.Dict.items(): strValue = "" if value is None else value content = content.replace(key, strValue) dstFilename = dstFilename.replace(key, strValue) if dstFilenameModifier is not None: dstFilename = dstFilenameModifier(dstFilename) dirName = IOUtil.GetDirectoryName(dstFilename) if not config.DisableWrite: IOUtil.SafeMakeDirs(dirName) IOUtil.WriteFileIfChanged(dstFilename, content)
def __ParseSync(self, log: Log, jsonContent: Any, sourceFilename: str, parentElementName: str, defaultSourcePath: str, pathVariables: PathVariables) -> List[ContentFileRecord]: sourcePath = self.__TryReadKey(jsonContent, "SourcePath", defaultSourcePath) sourceRoot = ContentRootRecord(log, sourcePath, pathVariables) contentKey = "Content" if not contentKey in jsonContent: raise Exception( "The key '{0}' was not found under '{1}' in file '{2}".format( contentKey, parentElementName, sourceFilename)) content = jsonContent[contentKey] uniqueFiles = {} # type: Dict[str, ContentFileRecord] files = [] # type: List[ContentFileRecord] for entry in content: self.__ValidateContentName(entry, sourceFilename) absolutePath = IOUtil.Join(sourceRoot.ResolvedPath, entry) directory = IOUtil.GetDirectoryName(absolutePath) filename = IOUtil.GetFileName(absolutePath) # check if there is a wild card in the filename if '*' in filename: self.__AppendFilesUsingWildcard(log, uniqueFiles, files, sourceRoot, entry, absolutePath, directory, filename) elif IOUtil.IsDirectory(absolutePath): self.__AppendDirectory(log, uniqueFiles, files, sourceRoot, entry, absolutePath) elif IOUtil.IsFile(absolutePath): self.__AppendFile(log, uniqueFiles, files, sourceRoot, entry, absolutePath) else: raise Exception( "No file or directory found for entry '{0}' which expands to '{1}'" .format(entry, absolutePath)) return files
def __TryGenerateRunCommandForExecutable( self, buildContext: LocalBuildContext, package: Package, buildConfig: BuildConfigRecord, runCommands: Optional[List[str]], generatorConfig: GeneratorConfig) -> Optional[List[str]]: if package.Type != PackageType.Executable or runCommands is None or len( runCommands) <= 0: return None if package.ResolvedBuildPath is None or package.AbsolutePath is None: raise Exception("Invalid package") if package not in buildContext.GeneratorReportDict: raise Exception( "ForAllExe not supported by generator for package: {0}".format( package.Name)) generatorReport = buildContext.GeneratorReportDict[package] variableReport = generatorReport.VariableReport executableReport = generatorReport.ExecutableReport if executableReport is None: raise Exception( "ForAllExe not supported by generator for package {0} as it didnt contain a executable record" .format(package.Name)) foundVariantExePath = ReportVariableFormatter.Format( executableReport.ExeFormatString, variableReport, buildConfig.VariantSettingsDict, executableReport.EnvironmentVariableResolveMethod) if buildConfig.Generator is None: raise Exception("Generator is missing") buildExecutableInfo = buildConfig.Generator.TryGetBuildExecutableInfo( self.Log, generatorConfig, package, generatorReport, buildConfig.VariantSettingsDict) if buildExecutableInfo is not None: # Override the "install-type" path with the "development" exe path foundVariantExePath = buildExecutableInfo.BuildExePath packagePath = package.AbsolutePath fullPathExe = IOUtil.Join(packagePath, foundVariantExePath) exeName = IOUtil.GetFileName(foundVariantExePath) exePath = IOUtil.GetDirectoryName(fullPathExe) contentPath = IOUtil.Join(packagePath, ToolSharedValues.CONTENT_FOLDER_NAME) fullBuildDirPath = IOUtil.Join(packagePath, package.ResolvedBuildPath) fullBuildDirPath = buildContext.Config.ToCurrentOSPathDirectConversion( fullBuildDirPath) fullPathExe = buildContext.Config.ToCurrentOSPathDirectConversion( fullPathExe) exeName = buildContext.Config.ToCurrentOSPathDirectConversion(exeName) exePath = buildContext.Config.ToCurrentOSPathDirectConversion(exePath) packagePath = buildContext.Config.ToCurrentOSPathDirectConversion( packagePath) contentPath = buildContext.Config.ToCurrentOSPathDirectConversion( contentPath) commands = [] if executableReport.RunScript is not None: runScript = executableReport.RunScript if not executableReport.UseAsRelative: runScript = IOUtil.Join(packagePath, runScript) commands.append(runScript) for commandToRun in runCommands: command = commandToRun command = command.replace("(EXE)", fullPathExe) command = command.replace("(EXE_NAME)", exeName) command = command.replace("(EXE_PATH)", exePath) command = command.replace("(PACKAGE_NAME)", package.Name) command = command.replace("(PACKAGE_PATH)", packagePath) command = command.replace("(CONTENT_PATH)", contentPath) command = command.replace("(BUILD_PATH)", fullBuildDirPath) commands.append(command) return commands
def Process(self, currentDirPath: str, toolConfig: ToolConfig, localToolConfig: LocalToolConfig) -> None: config = Config(self.Log, toolConfig, localToolConfig.PackageConfigurationType, localToolConfig.BuildVariantsDict, localToolConfig.AllowDevelopmentPlugins) # create a config we control and that can be used to just build the tool recipe's configToolCheck = Config(self.Log, toolConfig, PluginSharedValues.TYPE_DEFAULT, localToolConfig.BuildVariantsDict, localToolConfig.AllowDevelopmentPlugins) if localToolConfig.DryRun: config.ForceDisableAllWrite() configToolCheck.ForceDisableAllWrite() self.__CheckUserArgs(localToolConfig.ClangFormatArgs, "formatArgs") self.__CheckUserArgs(localToolConfig.ClangTidyArgs, "tidyArgs") self.__CheckUserArgs(localToolConfig.ClangTidyPostfixArgs, "tidyPostfixArgs") applyClangFormat = toolConfig.ClangFormatConfiguration is not None and localToolConfig.ClangFormat applyClangTidy = toolConfig.ClangTidyConfiguration is not None and localToolConfig.ClangTidy if localToolConfig.IgnoreNotSupported or ( (localToolConfig.ScanSource or applyClangFormat) and not applyClangTidy): config.IgnoreNotSupported = True configToolCheck.IgnoreNotSupported = True packageFilters = localToolConfig.BuildPackageFilters # Get the platform and see if its supported platform = PluginConfig.GetGeneratorPluginById( localToolConfig.PlatformName, False) PlatformUtil.CheckBuildPlatform(platform.Name) generatorContext = GeneratorContext(config, config.ToolConfig.Experimental, platform) config.LogPrint("Active platform: {0}".format(platform.Name)) packageRecipeResultManager = None # type: Optional[PackageRecipeResultManager] toolPackageNames = [] if applyClangFormat or applyClangTidy: if applyClangFormat: if toolConfig.ClangFormatConfiguration is None: raise Exception("internal error") toolPackageNames.append( toolConfig.ClangFormatConfiguration.RecipePackageName) if applyClangTidy: if toolConfig.ClangTidyConfiguration is None: raise Exception("internal error") toolPackageNames.append( toolConfig.ClangTidyConfiguration.RecipePackageName) packageRecipeResultManager = ForceCheckBuildTools( configToolCheck, generatorContext, toolPackageNames) searchDir = currentDirPath if localToolConfig.File is not None and IOUtil.IsAbsolutePath( localToolConfig.File): searchDir = IOUtil.GetDirectoryName(localToolConfig.File) closestGenFilePath = FileFinder.TryFindClosestFileInRoot( config, toolConfig, searchDir, config.GenFileName) if closestGenFilePath is None: closestGenFilePath = searchDir if (self.Log.Verbosity >= 4): self.Log.LogPrint("Closest '{0}' file path: '{1}'".format( toolConfig.GenFileName, closestGenFilePath)) packageProcess = None # type: Optional[MainFlow.PackageLoadAndResolveProcess] packages = None discoverFeatureList = '*' in packageFilters.FeatureNameList if discoverFeatureList or localToolConfig.Project is None or localToolConfig.ScanSource or applyClangFormat or applyClangTidy: if discoverFeatureList: config.LogPrint( "No features specified, so using package to determine them" ) if localToolConfig.ScanSource or applyClangFormat or applyClangTidy or discoverFeatureList: packageProcess = self.__CreatePackageProcess( config, toolConfig.GetMinimalConfig(), closestGenFilePath, localToolConfig.Recursive, generatorContext.Platform, toolPackageNames) packageProcess.Resolve(generatorContext, packageFilters, applyClangTidy, False) packages = packageProcess.Packages topLevelPackage = PackageListUtil.GetTopLevelPackage(packages) if discoverFeatureList: packageFilters.FeatureNameList = [ entry.Name for entry in topLevelPackage.ResolvedAllUsedFeatures ] customPackageFileFilter = None # type: Optional[CustomPackageFileFilter] if not localToolConfig.ScanSource and not applyClangFormat and not applyClangTidy: Validate.ValidatePlatform(config, localToolConfig.PlatformName, packageFilters.FeatureNameList) if packageProcess is None: packageProcess = self.__CreatePackageProcess( config, toolConfig.GetMinimalConfig(), closestGenFilePath, localToolConfig.Recursive, generatorContext.Platform, toolPackageNames) if not packageProcess.IsFullResolve or packages is None: # For now this requires a full resolve (but basically it only requires basic + files) packages = packageProcess.Resolve(generatorContext, packageFilters, applyClangTidy, True) topLevelPackage = PackageListUtil.GetTopLevelPackage(packages) RecipeBuilder.ValidateInstallationForPackages( config, generatorContext, topLevelPackage.ResolvedBuildOrder) else: if localToolConfig.File is not None: # Delay extension validation customPackageFileFilter = CustomPackageFileFilter( localToolConfig.File) theTopLevelPackage = None # type: Optional[Package] filteredPackageList = [] # type: List[Package] if applyClangTidy or applyClangFormat or localToolConfig.ScanSource: addExternals = applyClangTidy filteredPackageList, theTopLevelPackage = self.__PreparePackages( self.Log, localToolConfig, packageProcess, generatorContext, packageFilters, addExternals, packages, config.IsSDKBuild, applyClangTidy, config) if len(filteredPackageList) <= 0: self.Log.DoPrint("No supported packages left to process") return if applyClangTidy: self.__ApplyClangTidy(self.Log, toolConfig, localToolConfig, packageRecipeResultManager, theTopLevelPackage, filteredPackageList, platform, config, generatorContext, customPackageFileFilter) if applyClangFormat: self.__ApplyClangFormat(self.Log, toolConfig, localToolConfig, packageRecipeResultManager, filteredPackageList, customPackageFileFilter) # Scan source after 'format' to ensure we dont warn about stuff that has been fixed if localToolConfig.ScanSource: self.__ApplyScanSource(self.Log, localToolConfig, config.IsSDKBuild, config.DisableWrite, filteredPackageList, customPackageFileFilter)
def Process(self, currentDirPath: str, toolConfig: ToolConfig, localToolConfig: LocalToolConfig) -> None: #self.Log.LogPrintVerbose(2, "*** Forcing the legacy clang tidy mode ***") #localToolConfig.Legacy = True config = Config(self.Log, toolConfig, localToolConfig.PackageConfigurationType, localToolConfig.BuildVariantsDict, localToolConfig.AllowDevelopmentPlugins) # create a config we control and that can be used to just build the tool recipe's configToolCheck = Config(self.Log, toolConfig, PluginSharedValues.TYPE_DEFAULT, localToolConfig.BuildVariantsDict, localToolConfig.AllowDevelopmentPlugins) if localToolConfig.DryRun: config.ForceDisableAllWrite() configToolCheck.ForceDisableAllWrite() self.__CheckUserArgs(localToolConfig.ClangFormatArgs, "formatArgs") self.__CheckUserArgs(localToolConfig.ClangTidyArgs, "tidyArgs") self.__CheckUserArgs(localToolConfig.ClangTidyPostfixArgs, "tidyPostfixArgs") applyClangFormat = toolConfig.ClangFormatConfiguration is not None and localToolConfig.ClangFormat applyClangTidy = toolConfig.ClangTidyConfiguration is not None and localToolConfig.ClangTidy if localToolConfig.IgnoreNotSupported or ( (localToolConfig.ScanSource or applyClangFormat) and not applyClangTidy): config.IgnoreNotSupported = True configToolCheck.IgnoreNotSupported = True packageFilters = localToolConfig.BuildPackageFilters # Get the platform and see if its supported buildVariantConfig = BuildVariantConfigUtil.GetBuildVariantConfig( localToolConfig.BuildVariantsDict) if localToolConfig.Legacy and applyClangTidy and config.ToolConfig.CMakeConfiguration is not None: # For the LEGACY clangTidy implementation we disable allow find package for the build checks for now as we dont use cmake for those # We basically have to update the tidy pass to utilize ninja+cmake for the tidy pass so that find_package will work self.Log.LogPrintVerbose(2, "Force disabling 'AllowFindPackage'") config.ToolConfig.CMakeConfiguration.SetAllowFindPackage(False) cmakeUserConfig = localToolConfig.GetUserCMakeConfig() if not localToolConfig.Legacy and applyClangTidy: config.LogPrintVerbose( 2, "Forcing the ninja generator for clang tidy") cmakeUserConfig.GeneratorName = "Ninja" generator = self.ToolAppContext.PluginConfigContext.GetGeneratorPluginById( localToolConfig.PlatformName, localToolConfig.Generator, buildVariantConfig, config.ToolConfig.DefaultPackageLanguage, config.ToolConfig.CMakeConfiguration, cmakeUserConfig, True) PlatformUtil.CheckBuildPlatform(generator.PlatformName) generatorContext = GeneratorContext(config, self.ErrorHelpManager, packageFilters.RecipeFilterManager, config.ToolConfig.Experimental, generator) self.Log.LogPrint("Active platform: {0}".format( generator.PlatformName)) packageRecipeResultManager = None # type: Optional[PackageRecipeResultManager] toolPackageNamesSet = set() toolPackageNames = [] if applyClangFormat or applyClangTidy: if applyClangFormat: if toolConfig.ClangFormatConfiguration is None: raise Exception("internal error") toolPackageNamesSet.add( toolConfig.ClangFormatConfiguration.RecipePackageName) toolPackageNamesSet.add( toolConfig.ClangFormatConfiguration.NinjaRecipePackageName) if applyClangTidy: if toolConfig.ClangTidyConfiguration is None: raise Exception("internal error") toolPackageNamesSet.add( toolConfig.ClangTidyConfiguration.ClangRecipePackageName) toolPackageNamesSet.add(toolConfig.ClangTidyConfiguration. ClangTidyRecipePackageName) toolPackageNamesSet.add( toolConfig.ClangTidyConfiguration.NinjaRecipePackageName) toolPackageNames = list(toolPackageNamesSet) packageRecipeResultManager = ForceCheckBuildTools( configToolCheck, generatorContext, toolPackageNames) searchDir = currentDirPath if localToolConfig.File is not None: localToolConfig.File = IOUtil.NormalizePath(localToolConfig.File) if IOUtil.IsAbsolutePath(localToolConfig.File): searchDir = IOUtil.GetDirectoryName(localToolConfig.File) closestGenFilePath = FileFinder.TryFindClosestFileInRoot( config, toolConfig, searchDir, config.GenFileName) if closestGenFilePath is None: closestGenFilePath = searchDir if self.Log.Verbosity >= 4: self.Log.LogPrint("Closest '{0}' file path: '{1}'".format( toolConfig.GenFileName, closestGenFilePath)) packageProcess = None # type: Optional[MainFlow.PackageLoadAndResolveProcess] packages = None discoverFeatureList = '*' in packageFilters.FeatureNameList if discoverFeatureList or localToolConfig.Project is None or localToolConfig.ScanSource or applyClangFormat or applyClangTidy: if discoverFeatureList: config.LogPrint( "No features specified, so using package to determine them" ) if localToolConfig.ScanSource or applyClangFormat or applyClangTidy or discoverFeatureList: packageProcess = self.__CreatePackageProcess( config, toolConfig.GetMinimalConfig(generator.CMakeConfig), closestGenFilePath, localToolConfig.Recursive, generatorContext.Platform, toolPackageNames) packageProcess.Resolve(generatorContext, packageFilters, applyClangTidy, False) packages = packageProcess.Packages topLevelPackage = PackageListUtil.GetTopLevelPackage(packages) if discoverFeatureList: packageFilters.FeatureNameList = [ entry.Name for entry in topLevelPackage.ResolvedAllUsedFeatures ] customPackageFileFilter = None # type: Optional[CustomPackageFileFilter] if not localToolConfig.ScanSource and not applyClangFormat and not applyClangTidy: Validate.ValidatePlatform(config, localToolConfig.PlatformName, packageFilters.FeatureNameList) if packageProcess is None: packageProcess = self.__CreatePackageProcess( config, toolConfig.GetMinimalConfig(generator.CMakeConfig), closestGenFilePath, localToolConfig.Recursive, generatorContext.Platform, toolPackageNames) if not packageProcess.IsFullResolve or packages is None: # For now this requires a full resolve (but basically it only requires basic + files) packages = packageProcess.Resolve(generatorContext, packageFilters, applyClangTidy, True) topLevelPackage = PackageListUtil.GetTopLevelPackage(packages) RecipeBuilder.ValidateInstallationForPackages( config, config.SDKPath, generatorContext, topLevelPackage.ResolvedBuildOrder) else: if localToolConfig.File is not None: # Delay extension validation customPackageFileFilter = CustomPackageFileFilter( localToolConfig.File) theTopLevelPackage = None # type: Optional[Package] filteredPackageList = [] # type: List[Package] if applyClangTidy or applyClangFormat or localToolConfig.ScanSource: addExternals = applyClangTidy filteredPackageList, theTopLevelPackage = self.__PreparePackages( self.Log, localToolConfig, packageProcess, generatorContext, packageFilters, addExternals, packages, config.IsSDKBuild, applyClangTidy, config) if len(filteredPackageList) <= 0: self.Log.DoPrint("No supported packages left to process") return if applyClangTidy: self.__ApplyClangTidy(self.Log, toolConfig, localToolConfig, packageRecipeResultManager, theTopLevelPackage, filteredPackageList, generator, config, generatorContext, customPackageFileFilter) if applyClangFormat: self.__ApplyClangFormat(self.Log, toolConfig, localToolConfig, packageRecipeResultManager, filteredPackageList, customPackageFileFilter, generatorContext.CMakeConfig) # Scan source after 'format' to ensure we dont warn about stuff that has been fixed if localToolConfig.ScanSource: self.__ApplyScanSource(self.Log, localToolConfig, config.IsSDKBuild, config.DisableWrite, filteredPackageList, customPackageFileFilter)
def __TryGenerateRunCommandForExecutable( self, buildContext: LocalBuildContext, package: Package, userVariantSettingDict: Dict[str, str], runCommands: Optional[List[str]]) -> Optional[List[str]]: if package.Type != PackageType.Executable or runCommands is None or len( runCommands) <= 0: return None if package.ResolvedBuildPath is None or package.AbsolutePath is None: raise Exception("Invalid package") if package not in buildContext.GeneratorReportDict: raise Exception( "ForAllExe not supported by generator for package: {0}".format( package.Name)) generatorReport = buildContext.GeneratorReportDict[package] variableReport = generatorReport.VariableReport executableReport = generatorReport.ExecutableReport if executableReport is None: raise Exception( "ForAllExe not supported by generator for package {0} as it didnt contain a executable record" .format(package.Name)) foundVariantExePath = ReportVariableFormatter.Format( executableReport.ExeFormatString, variableReport, userVariantSettingDict, executableReport.EnvironmentVariableResolveMethod) packagePath = package.AbsolutePath fullPathExe = IOUtil.Join(packagePath, foundVariantExePath) exeName = IOUtil.GetFileName(foundVariantExePath) exePath = IOUtil.GetDirectoryName(fullPathExe) contentPath = IOUtil.Join(packagePath, "Content") fullBuildDirPath = IOUtil.Join(packagePath, package.ResolvedBuildPath) fullBuildDirPath = buildContext.Config.ToCurrentOSPathDirectConversion( fullBuildDirPath) fullPathExe = buildContext.Config.ToCurrentOSPathDirectConversion( fullPathExe) exeName = buildContext.Config.ToCurrentOSPathDirectConversion(exeName) exePath = buildContext.Config.ToCurrentOSPathDirectConversion(exePath) packagePath = buildContext.Config.ToCurrentOSPathDirectConversion( packagePath) contentPath = buildContext.Config.ToCurrentOSPathDirectConversion( contentPath) commands = [] if executableReport.RunScript is not None: runScript = executableReport.RunScript if not executableReport.UseAsRelative: runScript = IOUtil.Join(packagePath, runScript) commands.append(runScript) for commandToRun in runCommands: command = commandToRun command = command.replace("(EXE)", fullPathExe) command = command.replace("(EXE_NAME)", exeName) command = command.replace("(EXE_PATH)", exePath) command = command.replace("(PACKAGE_NAME)", package.Name) command = command.replace("(PACKAGE_PATH)", packagePath) command = command.replace("(CONTENT_PATH)", contentPath) command = command.replace("(BUILD_PATH)", fullBuildDirPath) commands.append(command) return commands
def __LoadFromXml(self, log: Log, xmlElement: ET.Element, filename: str, canExtend: bool = True) -> None: self.Version = '1' # type: str self.RootDirectory = LocalInvalidValues.INVALID_FILE_NAME # type: str self.DefaultPackageLanguage = PackageLanguage.CPP # type: int self.DefaultCompany = LocalInvalidValues.INVALID_COMPANY_NAME # type: str self.ToolConfigFile = LocalInvalidValues.INVALID_FILE_NAME # type: str self.RequirePackageCreationYear = False self.XmlExperimental = None # type: Optional[XmlExperimental] self.XmlPackageConfiguration = [ ] # type: List[XmlConfigPackageConfiguration] self.XmlRootDirectories = [ ] # type: List[XmlConfigFileAddRootDirectory] self.XmlNewProjectTemplatesRootDirectories = [ ] # type: List[XmlConfigFileAddNewProjectTemplatesRootDirectory] self.XmlCompilerConfiguration = [ ] # type: List[XmlConfigCompilerConfiguration] self.SourceFileName = LocalInvalidValues.INVALID_FILE_NAME # type: str self.DefaultTemplate = MagicStrings.VSDefaultCPPTemplate # type: str self.ExtendedProject = [] # type: List[XmlExtendedProject] if xmlElement is not None: extendedElement = xmlElement.find( "ExtendedProject") if canExtend else None if extendedElement is None: rootDirectory = IOUtil.GetDirectoryName(filename) variableEnvironment = VariableEnvironment(self.Log) variableEnvironment.Set("PROJECT_ROOT", rootDirectory) variableProcessor = VariableProcessor(self.Log, variableEnvironment) self.Version = self._ReadAttrib(xmlElement, 'Version') self.RootDirectory = rootDirectory projectElem = XmlBase._GetElement( self, xmlElement, "Project") # type: ET.Element toolConfigFilePath = self._ReadAttrib( projectElem, 'ToolConfigFile') # type: str self.DefaultPackageLanguage = self.__GetDefaultPackageLanguage( projectElem) self.DefaultCompany = self._ReadAttrib(projectElem, 'DefaultCompany') # if this is set to true each package is required to contian a 'CreationYear=""' attribute self.RequirePackageCreationYear = self._ReadBoolAttrib( projectElem, 'RequirePackageCreationYear', False) self.ToolConfigFile = variableProcessor.ResolvePathToAbsolute( toolConfigFilePath, self.XMLElement) self.XmlPackageConfiguration = _LoadPackageConfigurations( log, projectElem, filename) self.XmlRootDirectories = _LoadAddRootDirectory( log, projectElem, filename) self.XmlNewProjectTemplatesRootDirectories = LoadUtil.LoadAddNewProjectTemplatesRootDirectory( log, projectElem, filename) self.XmlBuildDocConfiguration = _LoadBuildDocConfiguration( log, projectElem, filename) self.XmlClangFormatConfiguration = _LoadClangFormatConfiguration( log, projectElem, filename) self.XmlClangTidyConfiguration = _LoadClangTidyConfiguration( log, projectElem, filename) self.XmlCompilerConfiguration = _LoadCompilerConfiguration( log, projectElem, filename) self.XmlExperimental = _TryLoadExperimental( log, projectElem, filename) self.SourceFileName = filename self.DefaultTemplate = self._ReadAttrib( projectElem, 'DefaultTemplate', MagicStrings.VSDefaultCPPTemplate) else: # Do something with the extended element extendedProject = XmlExtendedProject(log, extendedElement, filename) parentFileName = extendedProject.AbsoluteParentConfigFilename parentElem = self.__LoadXml(log, parentFileName) self.__LoadFromXml(log, parentElem, parentFileName, True) # True to allow multiple extensions self.ExtendedProject.append(extendedProject) self.__ApplyExtended(self.XmlPackageConfiguration, extendedProject.XmlPackageConfiguration, True) self.__ApplyExtended(self.XmlRootDirectories, extendedProject.XmlRootDirectories, False) self.__ApplyExtended( self.XmlNewProjectTemplatesRootDirectories, extendedProject.XmlNewProjectTemplatesRootDirectories, False) self.__ApplyExtended(self.XmlBuildDocConfiguration, extendedProject.XmlBuildDocConfiguration, False) self.__ApplyExtended( self.XmlClangFormatConfiguration, extendedProject.XmlClangFormatConfiguration, False) self.__ApplyExtended(self.XmlCompilerConfiguration, extendedProject.XmlCompilerConfiguration, False) self.__ApplyExtendedExperimental( self.XmlExperimental, extendedProject.XmlExperimental) if self.RootDirectory == LocalInvalidValues.INVALID_FILE_NAME: raise Exception("RootDirectory not configured") if self.DefaultCompany == LocalInvalidValues.INVALID_COMPANY_NAME: raise Exception("Default company not configured") if self.ToolConfigFile == LocalInvalidValues.INVALID_FILE_NAME: raise Exception("ToolConfigFile not configured") if self.SourceFileName == LocalInvalidValues.INVALID_FILE_NAME: raise Exception("SourceFileName not configured") if len(self.XmlBuildDocConfiguration) > 1: raise Exception( "There can only be one BuildDocConfiguration entry") if len(self.XmlClangFormatConfiguration) > 1: raise Exception( "There can only be one ClangFormatConfiguration entry") if len(self.XmlClangTidyConfiguration) > 1: raise Exception( "There can only be one ClangTidyConfiguration entry")
def DetermineDirAndProjectName(currentDir: str, projectName: str) -> Tuple[str, str]: if projectName == '.': projectName = IOUtil.GetFileName(currentDir) currentDir = IOUtil.GetDirectoryName(currentDir) return currentDir, projectName