Ejemplo n.º 1
0
        private static async Task <bool> DownloadVersionAsync(ModVersion modVersion)
        {
            Console.WriteLine($"Downloading update: {modVersion.Version}...");

            List <string> filesToDeleteInScript = new List <string>();
            var           currentVersion        = LocalData.Version;

            if (currentVersion != null)
            {
                var filesToDelete = currentVersion.Checksums.Where(checksum => !modVersion.Checksums.Select(c => c.FilePath)
                                                                   .Contains(checksum.FilePath))
                                    .Select(checksum => checksum.FilePath)
                                    .Where(File.Exists).ToList();

                if (filesToDelete.Count > 0)
                {
                    Console.WriteLine($"Deleting {filesToDelete.Count} old file(s)...");
                }

                var allDirectories = new List <string>();

                foreach (string filePath in filesToDelete)
                {
                    if (Utility.FileInUse(filePath))
                    {
                        filesToDeleteInScript.Add(filePath);
                        continue;
                    }

                    try
                    {
                        File.Delete(filePath);

                        string directory = Path.GetDirectoryName(filePath);

                        if (directory != string.Empty && !allDirectories.Contains(directory))
                        {
                            List <string> directories = GetDirectories(directory).ToList();
                            allDirectories.AddRange(directories.Where(d => !allDirectories.Contains(d)));
                        }
                    }
                    catch (IOException ex)
                    {
                        Console.Error.WriteLine($"Failed to delete file: {filePath} ({ex.Message}");
                    }
                }

                foreach (string directory in allDirectories)
                {
                    try
                    {
                        if (Directory.Exists(directory) && Directory.GetFiles(directory, "*", SearchOption.AllDirectories).Length == 0)
                        {
                            Console.WriteLine($"Deleting empty directory: {directory}");
                            Directory.Delete(directory, true);
                        }
                    }
                    catch (IOException ex)
                    {
                        Console.Error.WriteLine($"Failed to delete directory: {directory} ({ex.Message})");
                    }
                }
            }

            List <string> filesToDownload = modVersion.Checksums.Where(checksum => !checksum.MatchesExistingFile()).Select(checksum => checksum.FilePath).ToList();
            bool          failed          = false;

            if (filesToDownload.Count > 0)
            {
                List <string> filesToReplace = new List <string>();

                using (var progressBar = new ProgressBar(filesToDownload.Count, $"Downloading files", progressBarOptions))
                {
                    var runningTasks = new Task[filesToDownload.Count];

                    for (int i = 0; i < filesToDownload.Count; ++i)
                    {
                        string filePath = filesToDownload[i];
                        runningTasks[i] = DownloadFile(filePath, modVersion.Type, modVersion.Version, progressBar, filesToReplace, (success) =>
                        {
                            if (success)
                            {
                                progressBar.Tick();
                            }
                            else
                            {
                                failed = true;
                            }
                        });
                    }

                    await Task.WhenAll(runningTasks);
                }

                if (filesToReplace.Count > 0 || filesToDeleteInScript.Count > 0)
                {
                    var scriptGenerator = new ScriptGenerator();
                    scriptGenerator.WriteLine("Waiting for updater to exit...").SleepSeconds(1);
                    filesToReplace.ForEach(filePath => scriptGenerator.MoveFile(filePath + ".new", filePath));
                    filesToDeleteInScript.ForEach(filePath => scriptGenerator.DeleteFile(filePath));

                    string scriptFileName = scriptGenerator.GetFileName("update-finish");

                    File.WriteAllText("version.json.new", JsonConvert.SerializeObject(modVersion, Formatting.None, SerializerSettings));
                    scriptGenerator.MoveFile("version.json.new", "version.json");

                    scriptGenerator.DeleteFile(scriptFileName);
                    scriptGenerator.LaunchFile(Assembly.GetEntryAssembly().Location, string.Join(" ", Environment.GetCommandLineArgs().Skip(1)));
                    var script = scriptGenerator.Generate();
                    File.WriteAllText(scriptFileName, script);

                    Console.WriteLine("Exiting updater to replace files in use...");

                    await Task.Delay(1000);

                    Process.Start(scriptFileName);
                    Environment.Exit(3);
                }
            }

            if (failed)
            {
                return(false);
            }

            File.WriteAllText("version.json", JsonConvert.SerializeObject(modVersion, Formatting.None, SerializerSettings));

            return(true);
        }
Ejemplo n.º 2
0
        public static CfanJson createCfanJsonFromModListJson(string file, string name, string title, ModVersion version, string author, string description = "")
        {
            ModListJson modList  = JsonConvert.DeserializeObject <ModListJson>(File.ReadAllText(file, Encoding.UTF8));
            CfanJson    cfanJson = createEmptyMetaCfanJson(name, title, version, author, description);

            cfanJson.modInfo.dependencies = modList.mods.Where(p => p.enabled == ModListJson.ModListJsonTruthy.YES)
                                            .Select(p => new ModDependency(p.name))
                                            .ToArray();
            cfanJson.suggests = modList.mods.Where(p => p.enabled == ModListJson.ModListJsonTruthy.NO).Select(p => new ModDependency(p.name)).ToArray();
            return(cfanJson);
        }
        private static ReleaseFileNameTestDataPoint CreateTestDataPointFromProperties(String ModName, ModVersion ModVersion)
        {
            String creationString = $"{ModName}_{ModVersion}.zip";

            return(new ReleaseFileNameTestDataPoint
            {
                CreationString = creationString,
                ModName = ModName,
                ModVersion = ModVersion,
                ObjectFromFor = ReleaseFileName.For(creationString)
            });
        }
Ejemplo n.º 4
0
 public bool ChangeModStatus(ModMetadata meta, ModVersion version, ModStatus status)
 {
     throw new NotImplementedException();
 }
Ejemplo n.º 5
0
        private async Task <object> UploadVersionAsync(dynamic args, CancellationToken cancellationToken)
        {
            this.RequiresAuthentication();

            if (!ParseModType(args, out ModType modType, out Response errorResponse))
            {
                return(await errorResponse);
            }

            var file = Request.Files.FirstOrDefault();
            UploadVersionDTO data = JsonConvert.DeserializeObject <UploadVersionDTO>(Request.Form.data);

            if (file == null)
            {
                return(await Response.JsonError("No file found", HttpStatusCode.BadRequest));
            }

            if (file.ContentType != "application/zip" &&
                file.ContentType != "application/x-zip-compressed" &&
                file.ContentType != "application/zip-compressed")
            {
                return(await Response.JsonError("File is not a zip file", HttpStatusCode.BadRequest));
            }

            // Verify that the version not older or equal to the current latest version
            if (Data.GetLatestVersion(modType, true, out ModVersion latestVersion))
            {
                if (modType == ModType.Server)
                {
                    if (!Version.TryParse(data.Version, out Version serverVersion))
                    {
                        return(await Response.JsonError("The specified version is not valid.", HttpStatusCode.BadRequest));
                    }

                    var currentServerVersion = Version.Parse(latestVersion.Version);

                    /*if (serverVersion <= currentServerVersion)
                     * {
                     *  return await Response.JsonError("The specified version is older or equal to the current version.", HttpStatusCode.BadRequest);
                     * }*/
                }
                else if (modType == ModType.Client)
                {
                    if (!data.Version.Contains("_"))
                    {
                        return(await Response.JsonError("The specified version is not valid.", HttpStatusCode.BadRequest));
                    }

                    string[] currentVersions      = latestVersion.Version.Split('_');
                    Version  currentClientVersion = Version.Parse(currentVersions[0]);
                    Version  currentGameVersion   = Version.Parse(currentVersions[1]);
                    string[] versions             = data.Version.Split('_');

                    if (!Version.TryParse(versions[0], out Version clientVersion) || !Version.TryParse(versions[1], out Version gameVersion))
                    {
                        return(await Response.JsonError("The specified version is not valid.", HttpStatusCode.BadRequest));
                    }

                    /*if (clientVersion <= currentClientVersion && gameVersion <= currentGameVersion)
                     *  return await Response.JsonError("The specified version is older or equal to the current version.", HttpStatusCode.BadRequest);*/
                }
            }

            var modVersion = new ModVersion
            {
                Version       = data.Version,
                ReleaseDate   = data.ReleaseDate,
                DirectoryPath = $"versions/{modType}/{data.Version}",
                Type          = modType
            };

            byte[] archiveBytes = new byte[file.Value.Length];
            await file.Value.ReadAsync(archiveBytes, 0, archiveBytes.Length, cancellationToken);

            var zipStream = new MemoryStream();
            await zipStream.WriteAsync(archiveBytes, 0, archiveBytes.Length, cancellationToken);

            zipStream.Position = 0;

            try
            {
                using (var zipArchive = new ZipArchive(zipStream, ZipArchiveMode.Update, true))
                {
                    using (var md5 = MD5.Create())
                    {
                        foreach (ZipArchiveEntry entry in zipArchive.Entries)
                        {
                            // Ignore directories
                            if (entry.Name == string.Empty)
                            {
                                continue;
                            }

                            using (var entryStream = entry.Open())
                            {
                                var    md5Bytes  = md5.ComputeHash(entryStream);
                                string md5String = BitConverter.ToString(md5Bytes).Replace("-", "").ToLowerInvariant();
                                modVersion.Checksums.Add(new ModVersion.FileChecksum {
                                    FilePath = entry.FullName, Md5 = md5String
                                });
                            }
                        }
                    }

                    // Add version.json to archive.
                    var versionEntry = zipArchive.CreateEntry("version.json", CompressionLevel.Optimal);
                    using (var stream = versionEntry.Open())
                    {
                        string versionJson = await Task.Factory.StartNew(() => JsonConvert.SerializeObject(modVersion), cancellationToken);

                        byte[] bytes = Encoding.UTF8.GetBytes(versionJson);
                        await stream.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
                    }
                }
            }
            catch (InvalidDataException)
            {
                return(await Response.JsonError("File is not a valid zip file.", HttpStatusCode.BadRequest));
            }

            Directory.CreateDirectory(modVersion.DirectoryPath);

            // Save archive
            using (var fileStream = File.Create(Path.Combine(modVersion.DirectoryPath, "archive.zip")))
            {
                zipStream.Position = 0;
                byte[] bytes = new byte[zipStream.Length];
                await zipStream.ReadAsync(bytes, 0, bytes.Length, cancellationToken);

                await fileStream.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
            }

            zipStream.Dispose();

            // Save json file
            string json = await Task.Factory.StartNew(() => JsonConvert.SerializeObject(modVersion), cancellationToken);

            File.WriteAllText(Path.Combine(modVersion.DirectoryPath, "version.json"), json, Encoding.UTF8);

            // Add version to version index if it's not already there.
            var indexTuple = new Tuple <ModType, string>(modType, modVersion.Version);

            if (!Data.VersionIndex.Contains(indexTuple))
            {
                Data.VersionIndex.Add(indexTuple);
            }

            Data.Versions.Add(modVersion);
            Data.InvalidateLatestVersion();
            await Data.SaveAsync(default);
Ejemplo n.º 6
0
 public ModVersion calculateMaxVersion()
 {
     if (modName == "base" && maxVersion == null)
     {
         // we assume that mods without no game version specified are only valid for versions below 0.13
         return(minVersion == null?ModVersion.maxWithTheSameMinor(new ModVersion("0.12")) : ModVersion.maxWithTheSameMinor(minVersion));
     }
     return(maxVersion);
 }
Ejemplo n.º 7
0
 public bool IsEqualOrAbove(ModVersion version)
 {
     return(Major >= version.Major && Minor >= version.Minor && Patch >= version.Patch);
 }
        public Release(DateTime ReleasedAt, String Sha1String, ReleaseDownloadUrl ReleaseDownloadUrl, ReleaseFileName ReleaseFileName, ModVersion ModVersion, FactorioVersion FactorioVersion, List <Dependency> Dependencies)
        {
            DateTimeValidator.ValidateRequiredDateTimeBeforePresent(ReleasedAt, nameof(ReleasedAt));
            ObjectValidator.ValidateRequiredObject(Sha1String, nameof(Sha1String));
            ObjectValidator.ValidateRequiredObject(ReleaseDownloadUrl, nameof(ReleaseDownloadUrl));
            ObjectValidator.ValidateRequiredObject(ReleaseFileName, nameof(ReleaseFileName));
            ObjectValidator.ValidateRequiredObject(ModVersion, nameof(ModVersion));
            ObjectValidator.ValidateRequiredObject(FactorioVersion, nameof(FactorioVersion));
            ListValidator.ValidateRequiredListNotEmpty(Dependencies, nameof(Dependencies));

            Regex sha1CaptureRegex = new Regex(Release.Sha1CapturePattern);
            Match match            = sha1CaptureRegex.Match(Sha1String);

            if (!match.Success)
            {
                throw new ArgumentException($"Unable to parse \"{Sha1String}\" to a valid SHA-1 hash due to formatting.", "Sha1String");
            }

            String sha1 = match.Groups[1].Value;

            if (sha1.Length != Sha1Length)
            {
                throw new ArgumentException($"Unable to parse \"{Sha1String}\" to a valid SHA-1 hash due to length. The SHA-1 hash must have a length of exactly {Release.Sha1Length} characters.", "Sha1String");
            }
            if (ModVersion != ReleaseFileName.ModVersion)
            {
                throw new ArgumentException("The specified release file name version does not match the specified release version.", "ReleaseFileName");
            }

            this.ReleasedAt         = ReleasedAt;
            this.ReleaseDownloadUrl = new ReleaseDownloadUrl(ReleaseDownloadUrl);
            this.ReleaseFileName    = new ReleaseFileName(ReleaseFileName);
            this.Sha1            = sha1;
            this.ModVersion      = new ModVersion(ModVersion);
            this.FactorioVersion = new FactorioVersion(FactorioVersion);
            // TODO: We may want to write an .AddDependency() method that validates that the dependency we're adding isn't for the release/mod itself. That would generate a circular dependency.
            this.Dependencies = Dependencies.ConvertAll(dependency => new Dependency(dependency));
        }
 private static ReleaseTestDataPoint CreateTestDataPointFromProperties(DateTime ReleasedAt, String Sha1String, ReleaseDownloadUrl ReleaseDownloadUrl, ReleaseFileName ReleaseFileName, ModVersion ModVersion, FactorioVersion FactorioVersion, List <Dependency> Dependencies)
 {
     return(new ReleaseTestDataPoint
     {
         ReleasedAt = ReleasedAt,
         Sha1 = Sha1String,
         ReleaseDownloadUrl = ReleaseDownloadUrl,
         ReleaseFileName = ReleaseFileName,
         ModVersion = ModVersion,
         FactorioVersion = FactorioVersion,
         Dependencies = Dependencies,
         ObjectFromConstructor = new Release(ReleasedAt, Sha1String, ReleaseDownloadUrl, ReleaseFileName, ModVersion, FactorioVersion, Dependencies)
     });
 }
Ejemplo n.º 10
0
        /// <summary>
        /// Updates the supplied registry from the URL given.
        /// This does not *save* the registry. For that, you probably want Repo.Update
        /// </summary>
        internal static void UpdateRegistry(Uri repo, Registry registry, KSP ksp, IUser user, Boolean clear = true)
        {
            log.InfoFormat("Downloading {0}", repo);

            string repo_file = String.Empty;

            try
            {
                repo_file = Net.Download(repo);
            }
            catch (System.Net.WebException e)
            {
                user.RaiseError($"Couldn't download {repo}.", e);
                return;
            }

            // Clear our list of known modules.
            var old_available = registry.available_modules;

            if (clear)
            {
                registry.ClearAvailable();
            }

            // Check the filetype.
            FileType type = FileIdentifier.IdentifyFile(repo_file);

            switch (type)
            {
            case FileType.TarGz:
                UpdateRegistryFromTarGz(repo_file, registry);
                break;

            case FileType.Zip:
                UpdateRegistryFromZip(repo_file, registry);
                break;

            default:
                break;
            }

            List <CfanModule> metadataChanges = new List <CfanModule>();

            foreach (var identifierModulePair in old_available)
            {
                var identifier = identifierModulePair.Key;

                if (registry.IsInstalled(identifier))
                {
                    AbstractVersion abstractVersion  = registry.InstalledVersion(identifier);
                    var             installedVersion = new ModVersion(abstractVersion.ToString());

                    if (!(registry.available_modules.ContainsKey(identifier)))
                    {
                        log.InfoFormat("UpdateRegistry, module {0}, version {1} not in repository ({2})", identifier, installedVersion, repo);
                        continue;
                    }

                    if (!registry.available_modules[identifier].module_version.ContainsKey(installedVersion))
                    {
                        continue;
                    }

                    // if the mod is installed and the metadata is different we have to reinstall it
                    CfanModule metadata = new CfanModule(registry.available_modules[identifier].module_version[installedVersion]);

                    if (!old_available.ContainsKey(identifier) ||
                        !old_available[identifier].module_version.ContainsKey(installedVersion))
                    {
                        continue;
                    }

                    CfanModule oldMetadata = new CfanModule(old_available[identifier].module_version[installedVersion]);

                    bool same = metadata.kind == oldMetadata.kind;

                    if (!same)
                    {
                        metadataChanges.Add(new CfanModule(registry.available_modules[identifier].module_version[installedVersion]));
                    }
                }
            }

            if (metadataChanges.Any())
            {
                string mods = "";
                for (int i = 0; i < metadataChanges.Count; i++)
                {
                    mods += metadataChanges[i].identifier + " "
                            + metadataChanges[i].modVersion.ToString() + ((i < metadataChanges.Count - 1) ? ", " : "");
                }

                if (user.RaiseYesNoDialog(String.Format(
                                              @"The following mods have had their metadata changed since last update - {0}.
It is advisable that you reinstall them in order to preserve consistency with the repository. Do you wish to reinstall now?", mods)))
                {
                    ModuleInstaller installer = ModuleInstaller.GetInstance(ksp, new NullUser());
                    installer.Upgrade(metadataChanges, new NetAsyncModulesDownloader(new NullUser(), ksp.tryGetFactorioAuthData()));
                }
            }

            // Remove our downloaded meta-data now we've processed it.
            // Seems weird to do this as part of a transaction, but Net.Download uses them, so let's be consistent.
            file_transaction.Delete(repo_file);
        }
Ejemplo n.º 11
0
        public GUIMod(CfanModule mod, IRegistryQuerier registry, FactorioVersion current_ksp_version)
        {
            IsCKAN = mod is CfanModule;
            //Currently anything which could alter these causes a full reload of the modlist
            // If this is ever changed these could be moved into the properties
            Mod              = mod;
            IsInstalled      = registry.IsInstalled(mod.identifier, false);
            IsInstallChecked = IsInstalled;
            HasUpdate        = registry.HasUpdate(mod.identifier, current_ksp_version);
            IsIncompatible   = !mod.IsCompatibleKSP(current_ksp_version);
            IsAutodetected   = registry.IsAutodetected(mod.identifier);
            Authors          = mod.authors == null ? "N/A" : String.Join(",", mod.authors);

            var             installed_version = registry.InstalledVersion(mod.identifier);
            AbstractVersion latest_version    = null;
            var             ksp_version       = mod.getMinFactorioVersion();

            CfanModule latest_available = null;

            try
            {
                latest_available = registry.LatestAvailable(mod.identifier, current_ksp_version);
                if (latest_available != null)
                {
                    latest_version = latest_available.modVersion;
                }
            }
            catch (ModuleNotFoundKraken)
            {
                latest_version = installed_version;
            }

            InstalledVersion = installed_version != null?installed_version.ToString() : "-";

            // Let's try to find the compatibility for this mod. If it's not in the registry at
            // all (because it's a DarkKAN mod) then this might fail.

            CfanModule latest_available_for_any_ksp = null;

            try
            {
                latest_available_for_any_ksp = registry.LatestAvailable(mod.identifier, null);
            }
            catch
            {
                // If we can't find the mod in the CKAN, but we've a CkanModule installed, then
                // use that.
                if (IsCKAN)
                {
                    latest_available_for_any_ksp = (CfanModule)mod;
                }
            }

            var showInfoFrom = latest_available ?? latest_available_for_any_ksp;

            // If there's known information for this mod in any form, calculate the highest compatible
            // KSP.
            if (showInfoFrom != null)
            {
                string minVersion = showInfoFrom.getMinFactorioVersion()?.ToString();
                string maxVersion = showInfoFrom.HighestCompatibleKSP()?.ToString();
                if (maxVersion != null && ModVersion.isMaxWithTheSameMinor(new ModVersion(maxVersion)))
                {
                    maxVersion = maxVersion.Replace(int.MaxValue.ToString(), "x");
                }

                if (minVersion != null && maxVersion != null)
                {
                    KSPCompatibility = minVersion.ToString() + " - " + maxVersion.ToString();
                }
                else if (minVersion != null)
                {
                    KSPCompatibility = " >= " + minVersion.ToString();
                }
                else if (maxVersion != null)
                {
                    KSPCompatibility = " <= " + maxVersion.ToString();
                }
                else
                {
                    KSPCompatibility = "any";
                }
                KSPCompatibilityLong = KSPCompatibility;

                // If the mod we have installed is *not* the mod we have installed, or we don't know
                // what we have installed, indicate that an upgrade would be needed.
                if (installed_version == null || !showInfoFrom.modVersion.Equals(installed_version))
                {
                    KSPCompatibilityLong = string.Format("{0} (using mod version {1})",
                                                         KSPCompatibility, showInfoFrom.modVersion);
                }
            }
            else
            {
                // No idea what this mod is, sorry!
                KSPCompatibility = KSPCompatibilityLong = "unknown";
            }

            if (latest_version != null)
            {
                LatestVersion = latest_version.ToString();
            }
            else if (latest_available_for_any_ksp != null)
            {
                LatestVersion = latest_available_for_any_ksp.modVersion.ToString();
            }
            else
            {
                LatestVersion = "-";
            }

            KSPversion = ksp_version != null?ksp_version.ToString() : "-";

            Abstract = mod.@abstract;

            // If we have homepage provided use that, otherwise use the spacedock page or the github repo so that users have somewhere to get more info than just the abstract.

            Homepage = "N/A";
            if (!string.IsNullOrEmpty(mod.homepage))
            {
                Homepage = mod.homepage;
            }

            Identifier = mod.identifier;

            if (mod.download_size == 0)
            {
                DownloadSize = "N/A";
            }
            else if (mod.download_size / 1024.0 < 1)
            {
                DownloadSize = "1<KB";
            }
            else
            {
                DownloadSize = mod.download_size / 1024 + "";
            }

            Abbrevation = new string(mod.title.Split(' ').
                                     Where(s => s.Length > 0).Select(s => s[0]).ToArray());

            if (Main.Instance != null)
            {
                IsCached = Main.Instance.CurrentInstance.Cache.IsMaybeCachedZip(mod.download);
            }
        }
        public void ReleaseConstructor_WhenValidParameters_ReturnsCorrectReleasedAt(DateTime releasedAt, String sha1String, ReleaseDownloadUrl releaseDownloadUrl, ReleaseFileName releaseFileName, ModVersion modVersion, FactorioVersion factorioVersion, List <Dependency> dependencies)
        {
            var testRelease = new Release(releasedAt, sha1String, releaseDownloadUrl, releaseFileName, modVersion, factorioVersion, dependencies);

            Assert.Equal(releasedAt, testRelease.ReleasedAt);
        }
        public void CopyConstructor_WhenValidParameters_ReturnsCorrectModVersion(Release release, ModVersion expectedModVersion)
        {
            var testRelease = new Release(release);

            Assert.Equal(expectedModVersion, testRelease.ModVersion);
        }