def test_highLevelFunctions(self): remoteSubModVersionJSONString = """ { "id" : "Onikakushi Ch.1/full", "files":[ {"id": "cg", "version": "1.0.0"}, {"id": "cgalt", "version": "1.0.0"}, {"id": "movie", "version": "1.0.0"}, {"id": "voices", "version": "1.0.0"}, {"id": "script", "version": "6.1.0"}, {"id": "movie-unix", "version": "1.0.0"}, {"id": "ui-windows", "version": "1.0.0"}, {"id": "ui-unix", "version": "1.0.0"} ] } """ remoteVersionObject = fileVersionManagement.SubModVersionInfo( json.loads(remoteSubModVersionJSONString)) test_dir = tempfile.mkdtemp() modList = self.getModListFromDummyJSON() mod = modList[0] submod = mod['submods'][0] subModConfig = installConfiguration.SubModConfig(mod, submod) fullConfig = installConfiguration.FullInstallConfiguration( subModConfig, test_dir, True) originalModFileList = fullConfig.buildFileListSorted('datadir') # If there is no file present, all files should require download fileVersionManager = fileVersionManagement.VersionManager( subMod=subModConfig, modFileList=originalModFileList, localVersionFolder=test_dir, _testRemoteSubModVersion=remoteVersionObject) self.assertEqual(fileVersionManager.getFilesRequiringUpdate(), originalModFileList) self.assertEqual(fileVersionManager.fullUpdateRequired(), True) fileVersionManager.saveVersionInstallFinished() # If there is a file present which is identical, no files should require download fileVersionManagerIdentical = fileVersionManagement.VersionManager( subMod=subModConfig, modFileList=originalModFileList, localVersionFolder=test_dir, _testRemoteSubModVersion=remoteVersionObject) self.assertEqual(fileVersionManagerIdentical.getFilesRequiringUpdate(), []) self.assertEqual(fileVersionManagerIdentical.fullUpdateRequired(), False) shutil.rmtree(test_dir)
def main(*, game_name, game_path, mod_type, mod_options=[], is_steam=True): sys.stdout = logger.Logger(common.Globals.LOG_FILE_PATH) logger.setGlobalLogger(sys.stdout) sys.stderr = logger.StdErrRedirector(sys.stdout) common.Globals.scanForExecutables() gui_main.check07thModServerConnection() modList = gui_main.getModList() subModList = gui_main.getSubModConfigList(modList) print("\n") suitableSubMods = [ x for x in subModList if all(y in x.modName.lower().split() for y in game_name.lower().split("-")) and x.subModName == mod_type ] if len(suitableSubMods) != 1: print(f'Could not find a mod matching "{game_name}"') return neededSubMod = suitableSubMods[0] neededModOptions = [] for i in mod_options: neededModOption = [ x for x in neededSubMod.modOptions if all(y in x.id.lower().split() for y in i.lower().split("-")) ] if len(neededModOption) == 1: neededModOptions += neededModOption if len(neededModOptions) != len(mod_options): print("Couldn't find specified mod options.") return for i in neededSubMod.modOptions: if i.id in [x.id for x in neededModOptions]: i.value = True install_config = installConfiguration.FullInstallConfiguration( neededSubMod, game_path, is_steam ) if neededSubMod.family == "umineko": uminekoInstaller.mainUmineko(install_config) elif neededSubMod.family == "umineko_nscripter": uminekoNScripterInstaller.main(install_config) elif neededSubMod.family == "higurashi": higurashiInstaller.main(install_config) else: print( f"Submod family is not recognised, the script may be out of date." "Please ask us to update it." )
def scanForFullInstallConfigs(subModConfigList, possiblePaths=None, scanExtraPaths=True): # type: (List[installConfiguration.SubModConfig], [str], bool) -> [installConfiguration.FullInstallConfiguration, List[str]] """ This function has two purposes: - When given a specific game path ('possiblePaths' argument), it checks if any of the given SubModConfig can be installed into that path. Each SubModConfig which can be installed into that path will be returned as a FullInstallConfiguration object. - When not given a specific game path, it searches the computer for valid installations where the given SubModConfig could be installed to. Each valid (installation + SubModConfig) combination will be returned as a FullInstallConfiguration object. :param subModConfigList: A **list** of SubModConfig which are to be searched for on disk :param possiblePaths: (Optional) Specify folders to check if the given SubModConfig can be installed into that path. :return: 1. A list of FullInstallConfig, each representing a valid install path that the given SubModConfig(s) couldbe installed into. 2. A list of games which were "partially uninstalled" by Steam - steam deletes game files, but not the mod files. The user should be notified to delete these files manually. """ returnedFullConfigs = [] returnedPartiallyUninstalledPaths = [] pathsToBeScanned = possiblePaths if not pathsToBeScanned: pathsToBeScanned = getMaybeGamePaths() # Build a mapping from subModIdentifier -> List[subMod] # This tells us, for each identifier, which subMods are compatible with that identifier (can be installed) # In all our games, the identifiers are the same for each subMod (but different for each Mod), # but it is easier to work with in the installer if we work with subMods from collections import defaultdict subModConfigDictionary = defaultdict( list) #type: defaultdict[List[installConfiguration.SubModConfig]] for subMod in subModConfigList: # If autodetection is disabled, and autodetection requested, do not scan for this submod if not subMod.autodetect and possiblePaths is None: continue for identifier in subMod.identifiers: subModConfigDictionary[identifier].append(subMod) # If there are no identifiers to be matched, give up immediately as we'll never find a match if not subModConfigDictionary: return [], [] if scanExtraPaths: extraPaths = [] for gamePath in pathsToBeScanned: # MacOS: Any subpath with '.app' is also checked in case the containing path was manually entered extraPaths.extend(glob.glob(os.path.join(gamePath, "*.app"))) # GOG Linux: Higurashi might be inside a 'game' subfolder extraPaths.extend(glob.glob(os.path.join(gamePath, "game"))) pathsToBeScanned += extraPaths logger.printNoTerminal("Scanning:\n\t- " + "\n\t- ".join(pathsToBeScanned)) for gamePath in pathsToBeScanned: possibleIdentifiers = getPossibleIdentifiersFromFolder(gamePath) subModConfigsInThisGamePath = set() possibleSteamPaths = [ os.path.join(gamePath, "steam_api.dll"), os.path.join(gamePath, "Contents/Plugins/CSteamworks.bundle"), os.path.join(gamePath, "libsteam_api.so") ] isSteam = False for possibleSteamPath in possibleSteamPaths: if os.path.exists(possibleSteamPath): isSteam = True if gamePathIsPartiallyUninstalled(gamePath): returnedPartiallyUninstalledPaths.append(gamePath) for possibleIdentifier in possibleIdentifiers: try: # Add each submod which is compatible with the found identifier, unless it has already been detected at this path. for subModConfig in subModConfigDictionary[possibleIdentifier]: if subModConfig not in subModConfigsInThisGamePath: subModConfigsInThisGamePath.add(subModConfig) returnedFullConfigs.append( installConfiguration.FullInstallConfiguration( subModConfig, gamePath, isSteam)) print("Found Game [{}] at [{}] id [{}]".format( subModConfig.modName, gamePath, possibleIdentifier)) except KeyError: pass return returnedFullConfigs, returnedPartiallyUninstalledPaths
def test_filterFileListInner(self): modList = self.getModListFromDummyJSON() mod = modList[0] submod = mod['submods'][0] subModConfig = installConfiguration.SubModConfig(mod, submod) fullConfig = installConfiguration.FullInstallConfiguration(subModConfig, '.', True) fileList = fullConfig.buildFileListSorted('datadir') # Test if versions have not changed unchangedTestSet = (json.loads(""" { "id" : "Onikakushi Ch.1/full", "lastAttemptedInstallID" : "Onikakushi Ch.1/full", "files":[ {"id": "cg", "version": "1.0.0"}, {"id": "cgalt", "version": "1.0.0"}, {"id": "movie", "version": "1.0.0"}, {"id": "voices", "version": "1.0.0"}, {"id": "script", "version": "6.1.0"}, {"id": "ui-windows", "version": "2.1.0"} ] } """), json.loads(""" { "id" : "Onikakushi Ch.1/full", "lastAttemptedInstallID" : "Onikakushi Ch.1/full", "files":[ {"id": "cg", "version": "1.0.0"}, {"id": "cgalt", "version": "1.0.0"}, {"id": "movie", "version": "1.0.0"}, {"id": "voices", "version": "1.0.0"}, {"id": "script", "version": "6.1.0"}, {"id": "ui-windows", "version": "2.1.0"} ] } """)) updateInformation = fileVersionManagement.getFilesNeedingUpdate(fileList, fileVersionManagement.SubModVersionInfo(unchangedTestSet[0]), fileVersionManagement.SubModVersionInfo(unchangedTestSet[1])) result = convertUpdateInformationToModFileList(fileList, updateInformation) self.assertEqual(result, []) print("Unchanged", [x.id for x in result]) # Test if 'cg' version changes, that both 'cg' and 'script' need update dependencyTestSet = (json.loads(""" { "id" : "Onikakushi Ch.1/full", "lastAttemptedInstallID" : "Onikakushi Ch.1/full", "files":[ {"id": "cg", "version": "1.0.0"}, {"id": "cgalt", "version": "1.0.0"}, {"id": "movie", "version": "1.0.0"}, {"id": "voices", "version": "1.0.0"}, {"id": "script", "version": "6.1.0"}, {"id": "ui-windows", "version": "2.1.0"} ] } """), json.loads(""" { "id" : "Onikakushi Ch.1/full", "lastAttemptedInstallID" : "Onikakushi Ch.1/full", "files":[ {"id": "cg", "version": "1.0.1"}, {"id": "cgalt", "version": "1.0.0"}, {"id": "movie", "version": "1.0.0"}, {"id": "voices", "version": "1.0.0"}, {"id": "script", "version": "6.1.0"}, {"id": "ui-windows", "version": "2.1.0"} ] } """)) updateInformation = fileVersionManagement.getFilesNeedingUpdate(fileList, fileVersionManagement.SubModVersionInfo(dependencyTestSet[0]), fileVersionManagement.SubModVersionInfo(dependencyTestSet[1])) result = convertUpdateInformationToModFileList(fileList, updateInformation) idSet = set(x.id for x in result) self.assertIn('cg', idSet) #cg changed version self.assertIn('script', idSet) #script is a dependency of cg (must overwrite cg) idSet.remove('cg') idSet.remove('script') self.assertEqual(idSet, set()) #no other items should remain in the list