def __TryAddAsCMakeLib(self, recipe: Optional[PackageExperimentalRecipe], package: Package) -> Optional[AndroidCMakeLib]: if recipe is None or recipe.ResolvedInstallPath is None or recipe.Pipeline is None: return None if not PackageRecipeUtil.CommandListContainsBuildCMake( recipe.Pipeline.CommandList): return None path = "{0}".format(recipe.ResolvedInstallPath) staticLibs = [] # type: List[AndroidCMakeLibRecord] if recipe.ValidateInstallation is not None and recipe.ValidateInstallation.CommandList is not None: for command in recipe.ValidateInstallation.CommandList: if command.CommandType == BuildRecipeValidateCommand.AddLib: commandEx = cast(XmlRecipeValidateCommandAddLib, command) libName = LibUtil.ToUnixLibName( IOUtil.GetFileName(commandEx.Name)) libPath = IOUtil.Join(path, "${ANDROID_ABI}") libPath = IOUtil.Join(libPath, commandEx.Name) staticLibs.append(AndroidCMakeLibRecord(libName, libPath)) # elif command.CommandType == BuildRecipeValidateCommand.AddDLL: # dynamicLibs.append(LibUtil.ToUnixLibName(IOUtil.GetFileName(command.Name))) return AndroidCMakeLib(path, staticLibs)
def SaveBuildInformation(log: Log, recipeRecord: Optional[RecipeRecord], recipePackageStateCache: RecipePackageStateCache, path: str) -> None: if recipeRecord is None or not PackageRecipeUtil.HasBuildPipeline( recipeRecord.SourcePackage): return if recipeRecord.SourceRecipe is None or recipeRecord.SourceRecipe.ResolvedInstallLocation is None: return installPath = recipeRecord.SourceRecipe.ResolvedInstallLocation.ResolvedPath jsonRootDict = BuildInfoFile.TryCreateJsonBuildInfoRootDict( log, path, recipeRecord.SourcePackage, recipeRecord.SourceRecipe, recipePackageStateCache) if jsonRootDict is None: return jsonText = json.dumps(jsonRootDict, ensure_ascii=False, sort_keys=True, indent=2, cls=BuildInfoComplexJsonEncoder) dstFilePath = IOUtil.Join(installPath, path) IOUtil.WriteFileIfChanged(dstFilePath, jsonText)
def __TryValidateInstallation(basicConfig: BasicConfig, validationEngine: ValidationEngine, package: Package, packagesToBuild: List[Package], recipePackageStateCache: RecipePackageStateCache, cmakeConfig: GeneratorCMakeConfig) -> bool: if package.ResolvedDirectExperimentalRecipe is None: raise Exception("Invalid package") sourceRecipe = package.ResolvedDirectExperimentalRecipe installPath = sourceRecipe.ResolvedInstallLocation if installPath is not None: if not IOUtil.IsDirectory(installPath.ResolvedPath): basicConfig.LogPrintVerbose( 2, "Installation directory not located: {0}".format( installPath.ResolvedPath)) return False elif basicConfig.Verbosity >= 2: basicConfig.LogPrint( "Installation directory located at '{0}'".format( installPath.ResolvedPath)) # Check if the user decided to do a build override by creating the required file. # This allows the user to tell the system that it has been build and it should mind its own buisness packageHasUserBuildOverride = False if not installPath is None: overrideFilename = IOUtil.Join( installPath.ResolvedPath, __g_BuildPackageInformationOverrideFilename) packageHasUserBuildOverride = IOUtil.IsFile(overrideFilename) if packageHasUserBuildOverride: basicConfig.LogPrint( "Package {0} contained a build override file '{1}'".format( package.Name, __g_BuildPackageInformationOverrideFilename)) if not __RunValidationEngineCheck(validationEngine, package): if packageHasUserBuildOverride: raise Exception( "Package {0} contained a build override file '{1}', but it failed validation. Fix the issues or delete the override file '{2}'" .format(package.Name, __g_BuildPackageInformationOverrideFilename, overrideFilename)) basicConfig.LogPrintVerbose(2, "Install validation failed") return False # If there is a user build override we dont check the build dependency json file if packageHasUserBuildOverride: return True # If there is no build pipeline we consider the validation to be completed, else we need to check the saved build info if not PackageRecipeUtil.HasBuildPipeline(package): return True if not BuildInfoFileUtil.TryValidateBuildInformation( basicConfig, package, packagesToBuild, recipePackageStateCache, cmakeConfig, __g_BuildPackageInformationFilename): basicConfig.LogPrintVerbose( 2, "Install validator failed to load build information") return False return True
def TryLoadBuildInformation(log: Log, sourcePackage: Package, path: str) -> Optional[JsonDictType]: try: if not PackageRecipeUtil.HasBuildPipeline(sourcePackage): return None sourceRecipe = sourcePackage.ResolvedDirectExperimentalRecipe if sourceRecipe is None or sourceRecipe.ResolvedInstallLocation is None: raise Exception("Invalid recipe") # Generally this should not be called if there is no pipeline srcFilePath = IOUtil.Join( sourceRecipe.ResolvedInstallLocation.ResolvedPath, path) fileContent = IOUtil.TryReadFile(srcFilePath) if fileContent is None: log.LogPrint( "Package build information for package {0} not found in the expected file '{1}'" .format(sourcePackage.Name, srcFilePath)) return None jsonBuildInfoDict = json.loads(fileContent) if not BuildInfoFile.IsDictValid(jsonBuildInfoDict): log.LogPrint( "Package build information for package {0} found in file '{1}' is invalid" .format(sourcePackage.Name, srcFilePath)) return None # Decode the complex element to a object of the right type jsonBuildInfoDict[ BuildInfoFileElements. ContentState] = BuildInfoComplexJsonDecoder.DecodeJson( jsonBuildInfoDict[BuildInfoFileElements.ContentState]) if BuildInfoFileElements.SourceState in jsonBuildInfoDict: jsonBuildInfoDict[ BuildInfoFileElements. SourceState] = BuildInfoComplexJsonDecoder.DecodeJson( jsonBuildInfoDict[BuildInfoFileElements.SourceState]) return cast(JsonDictType, jsonBuildInfoDict) except Exception as ex: log.LogPrintWarning( "TryLoadBuildInformation failed for package '{0}' with {1}". format(sourcePackage.Name, ex)) return None
def TryValidateBuildInformation( log: Log, sourcePackage: Package, packagesToBuild: List[Package], recipePackageStateCache: RecipePackageStateCache, path: str) -> bool: if not PackageRecipeUtil.HasBuildPipeline(sourcePackage): return False loadedBuildInfoDict = BuildInfoFileHelper.TryLoadBuildInformation( log, sourcePackage, path) if loadedBuildInfoDict is None: return False if sourcePackage.ResolvedDirectExperimentalRecipe is None: raise Exception("Invalid package") # Loaded information loadedInfo = BuildInfoFile(loadedBuildInfoDict) cachedContentState = loadedInfo.ContentState # Load current information currentInfoDict = BuildInfoFile.TryCreateJsonBuildInfoRootDict( log, path, sourcePackage, sourcePackage.ResolvedDirectExperimentalRecipe, recipePackageStateCache, cachedContentState, loadedInfo.SourceState) if currentInfoDict is None: log.LogPrint( "Failed to create Package build information for package {0}". format(sourcePackage.Name)) return False currentInfo = BuildInfoFile(currentInfoDict) if loadedInfo.PackageName != currentInfo.PackageName: log.LogPrint( "The current package name {0} did not match the stored package {1}" .format(currentInfo.PackageName, loadedInfo.PackageName)) return False if loadedInfo.RecipeHash != currentInfo.RecipeHash: log.LogPrint( "The current package recipe hash {0} did not match the stored package hash {1}" .format(currentInfo.RecipeHash, loadedInfo.RecipeHash)) return False if len(currentInfo.PackageDependencies) != len( loadedInfo.PackageDependencies): log.LogPrint( "The current package dependencies {0} did not match the stored package dependencies {1}" .format(currentInfo.PackageDependencies, loadedInfo.PackageDependencies)) return False if currentInfo.ContentStateHash != loadedInfo.ContentStateHash: log.LogPrint( "The current package contentStateHash {0} did not match the stored package contentStateHash {1}" .format(currentInfo.ContentStateHash, loadedInfo.ContentStateHash)) return False # As long as we trust the hash is unique this check wont be necessary #if not BuildInfoFile.Compare(loadedInfo.ContentState, currentInfo.ContentState): # log.LogPrint("The current package build content {0} did not match the stored package content {1}".format(currentInfo.ContentState, loadedInfo.ContentState)) # return False if currentInfo.SourceStateHash != loadedInfo.SourceStateHash: log.LogPrint( "The current package sourceStateHash {0} did not match the stored package sourceStateHash {1}" .format(currentInfo.SourceStateHash, loadedInfo.SourceStateHash)) return False loadedDependencyDict = { dep.Name: dep for dep in loadedInfo.DecodedPackageDependencies } rebuildPackages = set(package.Name for package in packagesToBuild) for dependency in currentInfo.DecodedPackageDependencies: # Future improvement: # If the user just deleted a package the 'newly build package' might not actually have changed # that can be checked using the ContentStateHash, # however the problem is that we would not have that available before we have build the package # meaning the validation check would have to occur while building instead of as a prebuild step if dependency.Name in rebuildPackages: log.LogPrint( "The dependency {0} is being rebuild so we also rebuild {1}" .format(dependency.Name, loadedInfo.PackageName)) return False if not dependency.Name in loadedDependencyDict: log.LogPrint( "The dependency {0} did not exist in the stored package {1}" .format(dependency.Name, loadedInfo.PackageName)) return False loadedDep = loadedDependencyDict[dependency.Name] currentState = recipePackageStateCache.TryGet(dependency.Name) if currentState is not None and loadedDep.Revision != currentState.ContentStateHash: log.LogPrint( "The dependency {0} content revision has changed from {1} to {2}, rebuilding" .format(dependency.Name, currentState.ContentStateHash, loadedDep.Revision)) return False return True