public string getCachedOrDownloadFile(IUser user, string url, string expectedFilename) { string cachePath = getPathToCachedOrDownloadedFile(user, url, expectedFilename); string firstCharacters = head(cachePath, 100).TrimStart(); if (firstCharacters.StartsWith("<!DOCTYPE")) { throw new HtmlInsteadOfModDownloadedKraken("Downloaded some kind of html."); } // the json string with error usually is from github if (firstCharacters.StartsWith("{\"error\":")) { throw new HtmlInsteadOfModDownloadedKraken("Downloaded some kind of json error."); } string temporaryFile = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); File.Copy(cachePath, temporaryFile); modNormalizer.normalizeModFile(temporaryFile, Path.GetFileNameWithoutExtension(expectedFilename)); // move to target place ModInfoJson modInfo = FactorioModParser.parseMod(temporaryFile); expectedFilename = CfanModule.createStandardFileName(modInfo.name, modInfo.version.ToString()); // normalize again, this time with real filename (in order to fix directory name in zip file) modNormalizer.normalizeModFile(temporaryFile, expectedFilename); string fmmModFile = Path.Combine(RepoModsDirectoryPath, expectedFilename) + ".zip"; if (File.Exists(fmmModFile)) { File.Delete(fmmModFile); } File.Move(temporaryFile, fmmModFile); return(fmmModFile); }
public static CfanJson createCfanJsonFromFile(string directoryOrZipFile) { ModInfoJson modInfo = FactorioModParser.parseMod(directoryOrZipFile); if (modInfo == null) { throw new Exception($"Couldn't parse info.json from '{directoryOrZipFile}'!"); } return(createCfanJsonFromModInfoJson(modInfo, new System.IO.FileInfo(directoryOrZipFile).Length)); }
public static CfanJson createCfanJsonFromModInfoJson(ModInfoJson modInfo, long downloadSize) { return(new CfanJson { modInfo = modInfo, aggregatorData = new Dictionary <string, string>(), authors = modInfo.author.ToArray(), categories = new string[0], downloadSize = downloadSize, downloadUrls = new string[0], releasedAt = null, suggests = new ModDependency[0], recommends = new ModDependency[0], conflicts = new ModDependency[0], tags = new string[0], type = CfanJson.CfanModType.MOD }); }
protected void fixBaseGameVersionRequirement(ModInfoJson modInfoJson) { // cfan does not allow empty base game version requirement for versions above 0.13 var baseGameRequirement = modInfoJson.dependencies.FirstOrDefault(p => p.modName == "base"); if (String.IsNullOrEmpty(modInfoJson.factorio_version)) { throw new Exception("Mod " + modInfoJson.name + " has empty factorio_version field."); } ModVersion minVersion = ModVersion.minWithTheSameMinor(new ModVersion(modInfoJson.factorio_version)); ModVersion maxVersion = ModVersion.maxWithTheSameMinor(new ModVersion(modInfoJson.factorio_version)); var newBaseDependency = new ModDependency(minVersion, maxVersion, "base", false); // add new or substitute existing base dependency var newDependencies = modInfoJson.dependencies.Where(p => p != baseGameRequirement).ToList(); newDependencies.Add(newBaseDependency); modInfoJson.dependencies = newDependencies.ToArray(); }
/// <summary> /// Registers the given DLL as having been installed. This provides some support /// for pre-CKAN modules. /// /// Does nothing if the DLL is already part of an installed module. /// </summary> public void RegisterPreexistingModule(KSP ksp, string absolute_path, ModInfoJson modInfo) { SealionTransaction(); string relative_path = ksp.ToRelativeGameDataDir(absolute_path); InstalledModule owner; if (installed_modules.TryGetValue(modInfo.name, out owner)) { log.InfoFormat( "Not registering {0}, it is already installed", relative_path ); return; } log.InfoFormat("Registering {0} from {1}", modInfo.name, relative_path); // We're fine if we overwrite an existing key. installed_preexisting_modules[modInfo.name] = new AutodetectedModule(relative_path, modInfo); }
protected CfanJson getCfanJson(IUser user, ModJson modJson, LatestModReleaseJson latestModReleaseJson) { if (string.IsNullOrEmpty(latestModReleaseJson.download_url)) { user.RaiseError($"Mod {modJson.name} does not have download url, omitting"); return(null); } ModInfoJson infoJson = new ModInfoJson { factorio_version = latestModReleaseJson.info_json.factorio_version, author = new List <string> { modJson.owner }, name = modJson.name, title = modJson.title, homepage = modJson.homepage, contact = modJson.github_path, version = new ModVersion(latestModReleaseJson.version), description = modJson.summary, dependencies = new ModDependency[] { } }; fixBaseGameVersionRequirement(infoJson); var cfanJson = CfanGenerator.createCfanJsonFromModInfoJson(infoJson, 0); cfanJson.downloadUrls = new[] { FactorioComAggregator.BASE_URI + latestModReleaseJson.download_url }; cfanJson.aggregatorData = new Dictionary <string, string> { ["x-source"] = typeof(FactorioComAggregator).Name, ["factorio-com-id"] = modJson.id.ToString(), ["factorio-com-source"] = FactorioComAggregator.BASE_URI + "/mods/" + modJson.owner + "/" + modJson.name, ["requires-factorio-token"] = "1" }; cfanJson.tags = new string[] { }; cfanJson.categories = new string[] { }; return(cfanJson); }
/// <summary> /// Clears the registry of DLL data, and refreshes it by scanning GameData. /// This operates as a transaction. /// This *saves* the registry upon completion. /// </summary> // TODO: This would likely be better in the Registry class itself. public void ScanGameData() { using (TransactionScope tx = CkanTransaction.CreateTransactionScope()) { Registry.ClearPreexistingModules(); var detectedModules = FactorioModDetector.findAllModsInDirectory(Path.Combine(gamedatadir, "mods")); foreach (var detectedModule in detectedModules) { string detectedModulePath = detectedModule.Key; ModInfoJson detectedModInfo = detectedModule.Value; if (Registry.InstalledModules.Any(p => p.identifier == detectedModInfo.name)) { continue; } AvailableModule availableModule; if (Registry.available_modules.TryGetValue(detectedModInfo.name, out availableModule)) { CfanModule availableCfan = availableModule.ByVersion(detectedModInfo.version); if (availableCfan != null) { string expectedFilename = availableCfan.standardFileName + ".zip"; if (Path.GetFileName(detectedModulePath) == expectedFilename) { // yay, we can use this mod as installed (we will be able to update/remove it through cfan) Registry.RegisterModule(availableCfan, new [] { detectedModulePath }, this); continue; } } } // we only register that this module exists, but we won't be able to do anything with it Registry.RegisterPreexistingModule(this, detectedModulePath, detectedModInfo); } try { Registry.CheckSanity(); } catch (InconsistentKraken e) { User.RaiseError("Autodetected mods has unmet dependencies, they won't be managed by CFAN until you fix inconsitencies.\n{0}", e.InconsistenciesPretty); var unmet = SanityChecker.FindUnmetDependencies(Registry.InstalledModules.Select(p => p.Module), Registry.InstalledPreexistingModules); do { unmet .Select(unmetDependencyKeyValue => unmetDependencyKeyValue.Value) .SelectMany(p => p.Select(modWithUnmetDependencies => detectedModules.FirstOrDefault(detectedModule => detectedModule.Value.name == modWithUnmetDependencies.identifier))) .Where(p => !p.Equals(default(KeyValuePair <string, ModInfoJson>))) .ToList() .ForEach(modWithUnmetDependencies => { Registry.DeregisterModule(this, modWithUnmetDependencies.Value.name, true); Registry.RegisterPreexistingModule(this, modWithUnmetDependencies.Key, modWithUnmetDependencies.Value); }); unmet = SanityChecker.FindUnmetDependencies(Registry.InstalledModules.Select(p => p.Module), Registry.InstalledPreexistingModules); } while (unmet.Any()); } tx.Complete(); } RegistryManager.Save(); }
public AutodetectedModule(string path, ModInfoJson modInfo) { this.path = path; this.modInfo = modInfo; }