def UpdateGameFiles() -> bool: """ Send currently built mod files to the Sims 4 mod folder. :return: """ try: if os.path.exists(Mod.GetCurrentMod().UninstallFilesFilePath): with open(Mod.GetCurrentMod().UninstallFilesFilePath ) as uninstallFilesFile: uninstallFiles = uninstallFilesFile.read().splitlines( ) # type: typing.List[str] for uninstallFile in uninstallFiles: # type: str uninstallFilePath = os.path.join(Paths.S4ModsPath, uninstallFile) # type: str if os.path.exists(uninstallFilePath): os.remove(uninstallFilePath) except Exception as e: print("Failed to uninstall the previous mod version.\n" + \ "Mod: '" + Mod.GetCurrentMod().Namespace + "'\n" + \ Exceptions.FormatException(e), file = sys.stderr) try: dir_util.copy_tree(Paths.BuildPath, Paths.S4ModsPath) except Exception as e: print("Failed to send mod to the Sims 4 mod folder.\n" + \ "Mod: '" + Mod.GetCurrentMod().Namespace + "'\n" + \ Exceptions.FormatException(e), file = sys.stderr) return False return True
def UpdateGamePython() -> bool: """ Send currently built python files to the Sims 4 mod folder. :return: """ try: currentPythonFilePath = os.path.join( Paths.S4ModsPath, Mod.GetCurrentMod().PythonMergeRelativeRoot, Mod.GetCurrentMod().PythonBuildArchiveFileName) # type: str if os.path.exists(currentPythonFilePath): os.remove(currentPythonFilePath) shutil.copy( Mod.GetCurrentMod().PythonBuildArchiveFilePath, os.path.join(Paths.S4ModsPath, Mod.GetCurrentMod().PythonMergeRelativeRoot)) except Exception as e: print("Failed to send python to the Sims 4 mod folder.\n" + \ "Mod: '" + Mod.GetCurrentMod().Namespace + "'\n" + \ Exceptions.FormatException(e), file = sys.stderr) return False return True
def BuildInformation() -> bool: if not Information.CanBuildInformation(): return True Information.BuildInformation(Mod.GetCurrentMod().InformationSourceFilePath, Mod.GetCurrentMod().InformationBuildFilePath) return True
def BuildPublishing() -> bool: print("Building mod publishing '" + Mod.GetCurrentMod().Namespace + "'.") for phase in _publishingPhases: # type: typing.Callable try: if not phase(): print("Forced to skip all or part of phase 'Publishing'.\n" + \ "Phase: 'Publishing' Mod: '" + Mod.GetCurrentMod().Namespace + "'", file = sys.stderr) except Exception as e: print("Failed to complete mod build phase.\n" + \ "Phase: 'Publishing' Mod: '" + Mod.GetCurrentMod().Namespace + "'" + \ Exceptions.FormatException(e), file = sys.stderr) return False return True
def BuildPackageEverything() -> bool: if not Package.CanBuildPackage(): return False for package in Mod.GetCurrentMod().Packages: # type: Mod.Package _BuildPackageEverythingInternal(package) return True
def BuildDistribution() -> bool: if not Distribution.CanSendToInstaller( ) or not Distribution.CanBuildInstaller(): return False IO.ClearDirectory( os.path.dirname(Mod.GetCurrentMod().DistributionFilesFilePath)) IO.ClearDirectory( os.path.dirname(Mod.GetCurrentMod().DistributionInstallerFilePath)) IO.ZipDirectory(Paths.BuildPath, Mod.GetCurrentMod().DistributionFilesFilePath, compress=True) IO.ClearDirectory( os.path.dirname(Mod.GetCurrentMod().DistributionInstallerFilePath)) Distribution.SendToNOModInstaller( Mod.GetCurrentMod().DistributionFilesFilePath, Paths.PublishingAdditionalInstallerPath) Distribution.BuildInstaller( os.path.dirname(Mod.GetCurrentMod().DistributionInstallerFilePath), os.path.splitext( os.path.split( Mod.GetCurrentMod().DistributionInstallerFilePath)[1])[0]) return True
def BuildSTBLEverything() -> bool: canBuildSTBL = STBL.CanBuildSTBL() # type: bool if not canBuildSTBL: return False for package in Mod.GetCurrentMod().Packages: # type: Mod.Package if not os.path.exists(package.STBLPath): continue for stblXMLFileName in os.listdir(package.STBLPath): # type: str stblXMLFilePath = os.path.join(package.STBLPath, stblXMLFileName) # type: str if os.path.isfile(stblXMLFilePath) and os.path.splitext( stblXMLFileName)[1].casefold() == ".xml": modifiedTime = os.path.getmtime(stblXMLFilePath) # type: float manifestFilePath = os.path.splitext( stblXMLFilePath)[0] + "_Manifest.json" # type: str buildTempDirectory = stblXMLFilePath + "_Temp_Build" # type: str if not os.path.exists(buildTempDirectory): os.makedirs(buildTempDirectory) try: STBL.BuildSTBL(buildTempDirectory, stblXMLFilePath) manifest = dict() # type: typing.Dict[str, typing.Any] manifest[ManifestBuiltModifiedTimeKey] = modifiedTime builtFileNames = list() for builtFileName in os.listdir(buildTempDirectory): builtFilePath = os.path.join(buildTempDirectory, builtFileName) if os.path.isfile(builtFilePath): builtFileNames.append(builtFileName) manifest[ManifestBuiltFileNamesKey] = builtFileNames with open(manifestFilePath, "w+") as manifestFile: manifestFile.write( json.JSONEncoder(indent="\t").encode(manifest)) dir_util.copy_tree( buildTempDirectory, os.path.join(package.SourceLoosePath, "STBL")) finally: shutil.rmtree(buildTempDirectory) return True
def BuildMod(modeName: str) -> bool: if not modeName in _modBuildModes: modeName = _modBuildDefaultMode modePhases = _modBuildModes.get( modeName) # type: typing.List[typing.Callable] print("Building mod '" + Mod.GetCurrentMod().Namespace + "' in mode '" + modeName + "'.") for phase in modePhases: # type: typing.Callable try: if not phase(): print("Forced to skip all or part of phase '" + phase.__name__ + "'.\n" + \ "Phase: '" + phase.__name__ + "' Mod: '" + Mod.GetCurrentMod().Namespace + "' Build mode: '" + modeName + "'", file = sys.stderr) except Exception as e: print("Failed to complete mod build phase.\n" + \ "Phase: '" + phase.__name__ + "' Mod: '" + Mod.GetCurrentMod().Namespace + "' Build mode: '" + modeName + "' \n" + \ Exceptions.FormatException(e), file = sys.stderr) return False return True
def BuildMisc () -> bool: if not Misc.CanBuildMarkdown(): return False IO.ClearDirectory(Paths.MiscPath) changesFilePath = Mod.GetCurrentMod().ChangesFilePath # type: str if os.path.exists(changesFilePath): changesBuildFileName = os.path.splitext(os.path.split(changesFilePath)[1])[0] + ".html" # type: str changesBuildFilePath = os.path.join(Paths.MiscPath, Mod.GetCurrentMod().Namespace, changesBuildFileName) # type: str Misc.BuildMarkdown(changesBuildFilePath, changesFilePath) plansFilePath = Mod.GetCurrentMod().PlansFilePath # type: str if os.path.exists(plansFilePath): plansBuildFileName = os.path.splitext(os.path.split(plansFilePath)[1])[0] + ".html" # type: str plansBuildFilePath = os.path.join(Paths.MiscPath, Mod.GetCurrentMod().Namespace, plansBuildFileName) # type: str Misc.BuildMarkdown(plansBuildFilePath, plansFilePath) return True
def GetEntries() -> typing.List[typing.Tuple[str, int]]: entries = list() # type: typing.List[typing.Tuple[str, int]] for package in Mod.GetCurrentMod().Packages: # type: Mod.Package if not os.path.exists(package.STBLPath): continue if os.path.exists(package.STBLPath): for stblXMLFileName in os.listdir(package.STBLPath): # type: str stblXMLFilePath = os.path.join(package.STBLPath, stblXMLFileName) # type: str if os.path.isfile(stblXMLFilePath) and os.path.splitext( stblXMLFileName)[1].casefold() == ".xml": try: stblXMLFile = ElementTree.parse( stblXMLFilePath) # type: ElementTree.ElementTree entriesElements = stblXMLFile.findall( "Entries/STBLXMLEntry" ) # type: typing.Optional[typing.List[ElementTree.Element]] if entriesElements is None: continue for entryElement in entriesElements: # type: ElementTree.Element entryIdentifierElement = entryElement.find( "Identifier") # type: ElementTree.Element entryKeyElement = entryElement.find( "Key") # type: ElementTree.Element if entryIdentifierElement is None or entryKeyElement is None: continue entryIdentifier = entryIdentifierElement.text # type: str entryKeyText = entryKeyElement.text # type: str entryKey = int(entryKeyText) # type: int entries.append((entryIdentifier, entryKey)) except Exception as e: print("Failed to read potential stbl xml file at '" + stblXMLFilePath + "'\n" + str(e), file=sys.stderr) continue return entries
def BuildPython() -> bool: if not Python.CanBuildPython(): return False IO.ClearDirectory(Paths.PythonBuildArchivePath) IO.ClearDirectory(Paths.PythonBuildLoosePath) Python.BuildPython(Paths.PythonBuildLoosePath, Mod.GetCurrentMod().PythonBuildArchiveFilePath, Mod.GetCurrentMod().PythonSourceRootPath, Mod.GetCurrentMod().PythonSourceTargetPath, Mod.GetCurrentMod().PythonSourceExcludedFiles) if not os.path.exists(Mod.GetCurrentMod().PythonMergeRoot): os.makedirs(Mod.GetCurrentMod().PythonMergeRoot) shutil.copy(Mod.GetCurrentMod().PythonBuildArchiveFilePath, Mod.GetCurrentMod().PythonMergeRoot) return True
def _BuildManifest () -> None: Merging.BuildManifest(os.path.join(Mod.GetCurrentMod().Namespace, Mod.GetCurrentMod().Namespace + "-Uninstall-Files.txt"), Paths.BuildPath)
def _MergePackage () -> None: for package in Mod.GetCurrentMod().Packages: # type: Mod.Package if os.path.exists(package.BuildFilePath): shutil.copy(package.BuildFilePath, package.MergeRoot)
def _MergePython () -> None: if os.path.exists(Mod.GetCurrentMod().PythonBuildArchiveFilePath): shutil.copy(Mod.GetCurrentMod().PythonBuildArchiveFilePath, Mod.GetCurrentMod().PythonMergeRoot)
def BuildPackageChanges() -> bool: if not Package.CanBuildPackage(): return False for package in Mod.GetCurrentMod().Packages: # type: Mod.Package baseFileExists = os.path.exists( package.SourceBaseFilePath) # type: bool loosePathExists = os.path.exists(package.SourceLoosePath) # type: bool packageManifest = None # type: typing.Optional[typing.Dict[str, typing.Union[float, typing.Dict[str, float]]]] if not os.path.exists(package.BuildFilePath): _BuildPackageEverythingInternal(package) return True if os.path.exists(package.BuildManifestFilePath): with open(package.BuildManifestFilePath) as packageManifestFile: packageManifest = decoder.JSONDecoder().decode( packageManifestFile.read()) if packageManifest is not None and not isinstance( packageManifest, dict): packageManifest = None if packageManifest is not None and (not "Loose" in packageManifest or not "Base" in packageManifest): packageManifest = None if packageManifest is None: _BuildPackageEverythingInternal(package) return True else: filesChanged = False # type: bool if baseFileExists: baseCurrentChangeTime = os.path.getmtime( package.SourceBaseFilePath) # type: float if packageManifest["Base"] != os.path.getmtime( package.SourceBaseFilePath): packageManifest["Base"] = baseCurrentChangeTime filesChanged = True if loosePathExists: packageManifestLooseDictionary = packageManifest[ "Loose"] # type: dict for entryFileName in list( packageManifestLooseDictionary.keys()): # type: str entryChangeTime = packageManifestLooseDictionary[ entryFileName] # type: float entryFilePath = os.path.join(package.SourceLoosePath, entryFileName) # type: str if not os.path.exists(entryFilePath): packageManifestLooseDictionary.pop(entryFileName) filesChanged = True continue entryCurrentChangeTime = os.path.getmtime( entryFilePath) # type: float if entryCurrentChangeTime != entryChangeTime: packageManifest["Loose"][ entryFileName] = entryCurrentChangeTime filesChanged = True for sourceDirectoryRoot, sourceDirectoryNames, sourceFileNames in os.walk( package.SourceLoosePath ): # type: str, typing.List[str], typing.List[str] for sourceFileName in sourceFileNames: # type: str sourceFilePath = os.path.join( sourceDirectoryRoot, sourceFileName) # type: str relativeSourceFilePath = os.path.relpath( sourceFilePath, package.SourceLoosePath) # type: str sourceFileDuplicate = False # type: bool for entryFileName in packageManifest["Loose"].keys( ): # type: str if entryFileName.lower( ) == relativeSourceFilePath.lower(): sourceFileDuplicate = True break if not sourceFileDuplicate: packageManifest["Loose"][ relativeSourceFilePath] = os.path.getmtime( sourceFilePath) filesChanged = True if filesChanged: addingFilePaths = list() # type: typing.List[str] if loosePathExists: for sourceDirectoryRoot, sourceDirectoryNames, sourceFileNames in os.walk( package.SourceLoosePath ): # type: str, typing.List[str], typing.List[str] for sourceFileName in sourceFileNames: # type: str # noinspection SpellCheckingInspection if os.path.splitext(sourceFileName)[1].lower( ) == ".sourceinfo": continue sourceFilePath = os.path.join( sourceDirectoryRoot, sourceFileName) # type: str if os.path.isfile(sourceFilePath): addingFilePaths.append(sourceFilePath) if baseFileExists: Package.BuildPackage( package.BuildFilePath, baseFilePath=package.SourceBaseFilePath, addingFilePaths=addingFilePaths) else: Package.BuildPackage(package.BuildFilePath, addingFilePaths=addingFilePaths) with open(package.BuildManifestFilePath, "w+") as packageManifestFile: packageManifestFile.write( encoder.JSONEncoder( indent="\t").encode(packageManifest)) return True
def BuildSTBLChanges() -> bool: canBuildSTBL = STBL.CanBuildSTBL() # type: bool if not canBuildSTBL: return False for package in Mod.GetCurrentMod().Packages: # type: Mod.Package if not os.path.exists(package.STBLPath): continue for stblXMLFileName in os.listdir(package.STBLPath): # type: str stblXMLFilePath = os.path.join(package.STBLPath, stblXMLFileName) # type: str if os.path.isfile(stblXMLFilePath) and os.path.splitext( stblXMLFileName)[1].casefold() == ".xml": manifestFilePath = os.path.splitext( stblXMLFilePath)[0] + "_Manifest.json" # type: str modifiedTime = os.path.getmtime(stblXMLFilePath) # type: float builtModifiedTime = None # type: typing.Optional[int] builtFileNames = list() # type: typing.List[str] try: if os.path.exists(manifestFilePath): with open(manifestFilePath) as manifestFile: manifest = json.JSONDecoder().decode( manifestFile.read() ) # type: typing.Dict[str, typing.Any] if not isinstance(manifest, dict): raise Exceptions.IncorrectTypeException( manifest, "Root", (dict, )) if ManifestBuiltModifiedTimeKey in manifest: builtModifiedTime = manifest[ ManifestBuiltModifiedTimeKey] if not isinstance(builtModifiedTime, float) and not isinstance( builtModifiedTime, int): incorrectValue = builtModifiedTime # type: typing.Any builtModifiedTime = None raise Exceptions.IncorrectTypeException( incorrectValue, "Root[%s]" % ManifestBuiltModifiedTimeKey, (dict, )) if ManifestBuiltFileNamesKey in manifest: builtFileNames = manifest[ ManifestBuiltFileNamesKey] if not isinstance(builtFileNames, list): incorrectValue = builtFileNames # type: typing.Any builtFileNames = list() raise Exceptions.IncorrectTypeException( incorrectValue, "Root[%s]" % ManifestBuiltFileNamesKey, (dict, )) for builtFileNameIndex in range( len(builtFileNames)): # type: int builtFileName = builtFileNames[ builtFileNameIndex] # type: str if not isinstance(builtFileName, str): builtFileNames = list() raise Exceptions.IncorrectTypeException( builtFileName, "Root[%s][%s]" % (ManifestBuiltFileNamesKey, builtFileNameIndex), (dict, )) except Exception as e: print("Failed to read STBL manifest file at '" + manifestFilePath + "'\n" + str(e), file=sys.stderr) missingBuiltFile = False # type: bool for builtFileName in builtFileNames: builtFilePath = os.path.join( os.path.join(package.SourceLoosePath, "STBL"), builtFileName) # type: str if not os.path.exists(builtFilePath): missingBuiltFile = True break if missingBuiltFile or modifiedTime != builtModifiedTime: buildTempDirectory = stblXMLFilePath + "_Temp_Build" # type: str if not os.path.exists(buildTempDirectory): os.makedirs(buildTempDirectory) try: STBL.BuildSTBL(buildTempDirectory, stblXMLFilePath) manifest = dict() # type: typing.Dict[str, typing.Any] manifest[ManifestBuiltModifiedTimeKey] = modifiedTime builtFileNames = list() for builtFileName in os.listdir(buildTempDirectory): builtFilePath = os.path.join( buildTempDirectory, builtFileName) if os.path.isfile(builtFilePath): builtFileNames.append(builtFileName) manifest[ManifestBuiltFileNamesKey] = builtFileNames with open(manifestFilePath, "w+") as manifestFile: manifestFile.write( json.JSONEncoder(indent="\t").encode(manifest)) dir_util.copy_tree( buildTempDirectory, os.path.join(package.SourceLoosePath, "STBL")) finally: shutil.rmtree(buildTempDirectory) return True