Beispiel #1
0
 public AvcVersion GetInternalAvc(CkanModule module, string filePath, string internalFilePath = null)
 {
     using (var zipfile = new ZipFile(filePath))
     {
         return GetInternalAvc(module, zipfile, internalFilePath);
     }
 }
        public bool Compatible(KSPVersion gameVersion, CkanModule module)
        {
            KSPVersion ksp_version = module.ksp_version;
            KSPVersion ksp_version_min = module.ksp_version_min;
            KSPVersion ksp_version_max = module.ksp_version_max;

            // Check the min and max versions.

            if (ksp_version_min.IsNotAny() && gameVersion < ksp_version_min)
            {
                return false;
            }

            if (ksp_version_max.IsNotAny() && gameVersion > ksp_version_max)
            {
                return false;
            }

            // We didn't hit the min/max guards. They may not have existed.

            // Note that since ksp_version is "any" if not specified, this
            // will work fine if there's no target, or if there were min/max
            // fields and we passed them successfully.

            return ksp_version.Targets(gameVersion);
        }
Beispiel #3
0
 public CkanModule GeneratorRandomModule(
     KSPVersion ksp_version = null,
     List<RelationshipDescriptor> conflicts = null,
     List<RelationshipDescriptor> depends = null,
     List<RelationshipDescriptor> sugests = null,
     List<String> provides = null,
     string identifier = null,
     Version version = null)
 {
     var mod = new CkanModule
     {
         name = Generator.Next().ToString(CultureInfo.InvariantCulture),
         @abstract = Generator.Next().ToString(CultureInfo.InvariantCulture),
         identifier = identifier??Generator.Next().ToString(CultureInfo.InvariantCulture),
         spec_version = new Version(1.ToString(CultureInfo.InvariantCulture)),
         ksp_version = ksp_version ?? new KSPVersion("0." + Generator.Next()),
         version = version ?? new Version(Generator.Next().ToString(CultureInfo.InvariantCulture))
     };
     mod.ksp_version_max = mod.ksp_version_min = new KSPVersion(null);
     mod.conflicts = conflicts;
     mod.depends = depends;
     mod.suggests = sugests;
     mod.provides = provides;
     return mod;
 }
Beispiel #4
0
        public override bool SingleVersionsCompatible(KspVersion gameVersion, CkanModule module)
        {
            // Otherwise, check if it's "generally recognise as safe".

            // If we're running KSP 1.0.4, then allow the mod to run if we would have
            // considered it compatible under 1.0.3 (as 1.0.4 was "just a hotfix").
            if (gameVersion.Equals (KspVersion.Parse ("1.0.4")))
                return strict.SingleVersionsCompatible (v103, module);

            return false;
        }
Beispiel #5
0
        public void Setup()
        {
            // By setting these for every test, we can make sure our tests can change
            // them any way they like without harming other tests.

            flag_path = "DogeCoinFlag-1.01/GameData/DogeCoinFlag/Flags/dogecoin.png";
            dogezip = TestData.DogeCoinFlagZip();
            dogemod = TestData.DogeCoinFlag_101_module();

            mm_zip = TestData.ModuleManagerZip();
            mm_mod = TestData.ModuleManagerModule();
        }
Beispiel #6
0
        public override bool Compatible(KspVersionCriteria gameVersionCriteria, CkanModule module)
        {
            // If it's strictly compatible, then it's compatible.
            if (strict.Compatible (gameVersionCriteria, module))
                return true;

            // If we're in strict mode, and it's not strictly compatible, then it's
            // not compatible.
            if (module.ksp_version_strict)
                return false;

            return base.Compatible (gameVersionCriteria, module);
        }
Beispiel #7
0
        public bool HasInstallableFiles(CkanModule module, string filePath)
        {
            try
            {
                ModuleInstaller.FindInstallableFiles(module, filePath, null);
            }
            catch (BadMetadataKraken)
            {
                // TODO: DBB: Let's not use exceptions for flow control
                return false;
            }

            return true;
        }
Beispiel #8
0
        public void OnModChanged(CkanModule module, GUIModChangeType changeType)
        {
            if (changeType == GUIModChangeType.Update || changeType == GUIModChangeType.Install)
            {
                var parts = GetInstalledModParts(module.identifier);
                foreach (var part in parts.Where(part => _mDisabledParts.ContainsKey(part.Key)))
                {
                    Cache.RemovePartFromCache(part.Key);
                    Cache.MovePartToCache(part.Key);
                }
            }

            RefreshInstalledModsList();
        }
Beispiel #9
0
        public override bool SingleVersionsCompatible(KspVersion gameVersion, CkanModule module)
        {
            var gameVersionRange = gameVersion.ToVersionRange();

            var moduleRange = KspVersionRange.Any;

            if (module.ksp_version != null)
            {
                moduleRange = module.ksp_version.ToVersionRange();
            }
            else if (module.ksp_version_min != null || module.ksp_version_max != null)
            {
                if (module.ksp_version_min != null && module.ksp_version_max != null)
                {
                    if (module.ksp_version_min <= module.ksp_version_max)
                    {
                        var minRange = module.ksp_version_min.ToVersionRange();
                        var maxRange = module.ksp_version_max.ToVersionRange();

                        moduleRange = new KspVersionRange(minRange.Lower, maxRange.Upper);
                    }
                    else
                    {
                        return false;
                    }
                }
                else if (module.ksp_version_min != null)
                {
                    var minRange = module.ksp_version_min.ToVersionRange();

                    moduleRange = new KspVersionRange(minRange.Lower, KspVersionBound.Unbounded);
                }
                else if (module.ksp_version_max != null)
                {
                    var maxRange = module.ksp_version_max.ToVersionRange();

                    moduleRange = new KspVersionRange(KspVersionBound.Unbounded, maxRange.Upper);
                }
            }
            else
            {
                return true;
            }

            return gameVersionRange.IntersectWith(moduleRange) != null;
        }
        public bool Compatible(KspVersion gameVersion, CkanModule module)
        {
            var gameVersionRange = gameVersion.ToVersionRange();

            var moduleRange = KspVersionRange.Any;

            if (module.ksp_version != null)
            {
                moduleRange = module.ksp_version.ToVersionRange();
            }
            else if (module.ksp_version_min != null || module.ksp_version_max != null)
            {
                if (module.ksp_version_min != null && module.ksp_version_max != null)
                {
                    if (module.ksp_version_min <= module.ksp_version_max)
                    {
                        var minRange = module.ksp_version_min.ToVersionRange();
                        var maxRange = module.ksp_version_max.ToVersionRange();

                        moduleRange = new KspVersionRange(minRange.Lower, maxRange.Upper);
                    }
                    else
                    {
                        return false;
                    }
                }
                else if (module.ksp_version_min != null)
                {
                    var minRange = module.ksp_version_min.ToVersionRange();

                    moduleRange = new KspVersionRange(minRange.Lower, KspVersionBound.Unbounded);
                }
                else if (module.ksp_version_max != null)
                {
                    var maxRange = module.ksp_version_max.ToVersionRange();

                    moduleRange = new KspVersionRange(KspVersionBound.Unbounded, maxRange.Upper);
                }
            }
            else
            {
                return true;
            }

            return moduleRange.IsSupersetOf(gameVersionRange);
        }
Beispiel #11
0
        public bool Compatible(KSPVersion gameVersion, CkanModule module)
        {
            // If it's strictly compatible, then it's compatible.
            if (strict.Compatible(gameVersion, module))
                return true;

            // If we're in strict mode, and it's not strictly compatible, then it's
            // not compatible.
            if (module.ksp_version_strict)
                return false;

            // Otherwise, check if it's "generally recognise as safe".

            // If we're running KSP 1.0.4, then allow the mod to run if we would have
            // considered it compatible under 1.0.3 (as 1.0.4 was "just a hotfix").
            if (gameVersion.Equals("1.0.4"))
                return strict.Compatible(v103, module);

            return false;
        }
Beispiel #12
0
        /// <summary>
        /// Returns the module contents if and only if we have it
        /// available in our cache. Returns null, otherwise.
        ///
        /// Intended for previews.
        /// </summary>
        // TODO: Return files relative to GameRoot
        public IEnumerable<string> GetModuleContentsList(CkanModule module)
        {
            string filename = ksp.Cache.GetCachedZip(module.download);

            if (filename == null)
            {
                return null;
            }

            return FindInstallableFiles(module, filename, ksp)
                .Select(x => x.destination);
        }
Beispiel #13
0
 /// <summary>
 /// Check if the given module is a metapackage:
 /// if it is, throws a BadCommandKraken.
 /// </summary>
 private static void CheckMetapackageInstallationKraken(CkanModule module)
 {
     if (module.IsMetapackage)
     {
         throw new BadCommandKraken("Metapackages can not be installed!");
     }
 }
        /// <summary>
        /// Initialize the popup.
        /// </summary>
        /// <param name="title">String to be shown in the top center of the popup</param>
        /// <param name="startPath">Path of directory to start in</param>
        /// <param name="filPat">Glob-style wildcard string for matching files to show</param>
        /// <param name="toggleHeader">Header for the column with checkmarks for selected files</param>
        public ConsoleFileMultiSelectDialog(string title, string startPath, string filPat, string toggleHeader)
            : base()
        {
            CenterHeader = () => title;
            curDir       = new DirectoryInfo(startPath);
            filePattern  = filPat;

            int w = (Console.WindowWidth > idealW + 2 * hPad)
                ? idealW
                : Console.WindowWidth - 2 * hPad;
            int left  = (Console.WindowWidth - w) / 2;
            int right = -left;

            SetDimensions(left, top, right, bottom);

            AddObject(new ConsoleLabel(
                          left + 2, top + 2, left + 2 + labelW - 1,
                          () => $"Directory:",
                          th => th.PopupBg,
                          th => th.PopupFg
                          ));

            pathField = new ConsoleField(
                left + 2 + labelW, top + 2, right - 2,
                curDir.FullName
                );
            pathField.OnChange += pathFieldChanged;
            AddObject(pathField);

            AddObject(new ConsoleLabel(
                          left + 2, bottom - 1, right - 2,
                          () => $"{chosenFiles.Count} selected, {CkanModule.FmtSize(totalChosenSize())}",
                          th => th.PopupBg,
                          th => th.PopupFg
                          ));

            // ListBox showing zip files in current dir
            fileList = new ConsoleListBox <FileSystemInfo>(
                left + 2, top + 4, right - 2, bottom - 2,
                getFileList(),
                new List <ConsoleListBoxColumn <FileSystemInfo> >()
            {
                new ConsoleListBoxColumn <FileSystemInfo>()
                {
                    Header   = toggleHeader,
                    Width    = 8,
                    Renderer = getRowSymbol
                }, new ConsoleListBoxColumn <FileSystemInfo>()
                {
                    Header   = "Name",
                    Width    = 36,
                    Renderer = getRowName,
                    Comparer = compareNames
                }, new ConsoleListBoxColumn <FileSystemInfo>()
                {
                    Header = "Size",
                    // Longest: "1023.1 KB"
                    Width    = 9,
                    Renderer = (FileSystemInfo fi) => getLength(fi),
                    Comparer = (a, b) => {
                        FileInfo fa = a as FileInfo, fb = b as FileInfo;
                        return(fa == null
                                ? (fb == null ? 0 : -1)
                                : (fb == null ? 1 : fa.Length.CompareTo(fb.Length)));
                    }
                }, new ConsoleListBoxColumn <FileSystemInfo>()
                {
                    Header   = "Accessed",
                    Width    = 10,
                    Renderer = (FileSystemInfo fi) => fi.LastWriteTime.ToString("yyyy-MM-dd"),
                    Comparer = (a, b) => a.LastWriteTime.CompareTo(b.LastWriteTime)
                }
            },
                1, 1, ListSortDirection.Ascending
                );
            AddObject(fileList);

            AddTip("Esc", "Cancel");
            AddBinding(Keys.Escape, (object sender, ConsoleTheme theme) => {
                chosenFiles.Clear();
                return(false);
            });

            AddTip("F10", "Sort");
            AddBinding(Keys.F10, (object sender, ConsoleTheme theme) => {
                fileList.SortMenu().Run(theme, right - 2, top + 2);
                DrawBackground(theme);
                return(true);
            });

            AddTip("Enter", "Change directory", () => fileList.Selection != null && isDir(fileList.Selection));
            AddTip("Enter", "Select", () => fileList.Selection != null && !isDir(fileList.Selection));
            AddBinding(Keys.Enter, (object sender, ConsoleTheme theme) => selectRow());
            AddBinding(Keys.Space, (object sender, ConsoleTheme theme) => selectRow());

            AddTip("Ctrl+A", "Select all");
            AddBinding(Keys.CtrlA, (object sender, ConsoleTheme theme) => {
                foreach (FileSystemInfo fi in contents)
                {
                    if (!isDir(fi))
                    {
                        FileInfo file = fi as FileInfo;
                        if (file != null)
                        {
                            chosenFiles.Add(file);
                        }
                    }
                }
                return(true);
            });

            AddTip("Ctrl+D", "Deselect all", () => chosenFiles.Count > 0);
            AddBinding(Keys.CtrlD, (object sender, ConsoleTheme theme) => {
                if (chosenFiles.Count > 0)
                {
                    chosenFiles.Clear();
                }
                return(true);
            });

            AddTip("F9", "Import", () => chosenFiles.Count > 0);
            AddBinding(Keys.F9, (object sender, ConsoleTheme theme) => {
                return(false);
            });
        }
Beispiel #15
0
        public GUIMod(CkanModule mod, IRegistryQuerier registry, KspVersionCriteria current_ksp_version)
        {
            IsCKAN = mod is CkanModule;
            //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.author == null ? "N/A" : String.Join(",", mod.author);

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

            try
            {
                var latest_available = registry.LatestAvailable(mod.identifier, current_ksp_version);
                if (latest_available != null)
                    latest_version = latest_available.version;
            }
            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.

            CkanModule 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 = (CkanModule) mod;

            }

            // If there's known information for this mod in any form, calculate the highest compatible
            // KSP.
            if (latest_available_for_any_ksp != null)
            {
                KSPCompatibility = KSPCompatibilityLong = latest_available_for_any_ksp.HighestCompatibleKSP();

                // 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 || !latest_available_for_any_ksp.version.IsEqualTo(installed_version))
                {
                    KSPCompatibilityLong = string.Format("{0} (using mod version {1})",
                        KSPCompatibility, latest_available_for_any_ksp.version);
                }
            }
            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.version.ToString();
            }
            else
            {
                LatestVersion = "-";
            }

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

            Abstract = mod.@abstract;

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

            Homepage = "N/A";
            if (mod.resources != null)
            {
                if (mod.resources.homepage != null)
                {
                    Homepage = mod.resources.homepage.ToString();
                }
                else if (mod.resources.spacedock != null)
                {
                    Homepage = mod.resources.spacedock.ToString();
                }
                else if (mod.resources.curse != null)
                {
                    Homepage = mod.resources.curse.ToString();
                }
                else if (mod.resources.repository != null)
                {
                    Homepage = mod.resources.repository.ToString();
                }
            }

            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.name.Split(' ').
                Where(s => s.Length > 0).Select(s => s[0]).ToArray());

            UpdateIsCached();
        }
Beispiel #16
0
        /// <summary>
        /// Adds the specified module to the list of modules we're installing.
        /// This also adds its provides list to what we have available.
        /// </summary>
        private void Add(CkanModule module, SelectionReason reason)
        {
            if (module.IsMetapackage)
                return;

            log.DebugFormat("Adding {0} {1}", module.identifier, module.version);

            if (modlist.ContainsKey(module.identifier))
            {
                // We should never be adding something twice!
                log.ErrorFormat("Assertion failed: Adding {0} twice in relationship resolution", module.identifier);
                throw new ArgumentException("Already contains module:" + module.identifier);
            }
            modlist.Add(module.identifier, module);
            if(!reasons.ContainsKey(module)) reasons.Add(module, reason);

            log.DebugFormat("Added {0}", module.identifier);
            // Stop here if it doesn't have any provide aliases.
            if (module.provides == null)
            {
                return;
            }

            // Handle provides/aliases if it does.

            // It's okay if there's already a key for one of our aliases
            // in the resolution list. In which case, we don't do anything.
            var aliases = module.provides.Where(alias => !modlist.ContainsKey(alias));
            foreach (string alias in aliases)
            {
                log.DebugFormat("Adding {0} providing {1}", module.identifier, alias);
                modlist.Add(alias, module);
            }
        }
Beispiel #17
0
 public Recommended(CkanModule module)
 {
     if (module == null) throw new ArgumentNullException();
     Parent = module;
 }
Beispiel #18
0
        private int addVersionDisplay()
        {
            int boxLeft        = Console.WindowWidth / 2 + 1,
                boxTop         = 3;
            const int boxRight = -1,
                      boxH     = 5;

            if (ChangePlan.IsAnyAvailable(registry, mod.identifier))
            {
                List <CkanModule> avail  = registry.AvailableByIdentifier(mod.identifier).ToList();
                CkanModule        inst   = registry.GetInstalledVersion(mod.identifier);
                CkanModule        latest = registry.LatestAvailable(mod.identifier, null);
                bool installed           = registry.IsInstalled(mod.identifier, false);
                bool latestIsInstalled   = inst?.Equals(latest) ?? false;
                List <CkanModule> others = avail;

                others.Remove(inst);
                others.Remove(latest);

                if (installed)
                {
                    DateTime?instTime = InstalledOn(mod.identifier);

                    if (latestIsInstalled)
                    {
                        ModuleReplacement mr = registry.GetReplacement(
                            mod.identifier,
                            manager.CurrentInstance.VersionCriteria()
                            );

                        if (mr != null)
                        {
                            // Show replaced_by
                            addVersionBox(
                                boxLeft, boxTop, boxRight, boxTop + boxH - 1,
                                () => $"Replaced by {mr.ReplaceWith.identifier}",
                                th => th.AlertFrameFg,
                                false,
                                new List <CkanModule>()
                            {
                                mr.ReplaceWith
                            }
                                );
                            boxTop += boxH;

                            addVersionBox(
                                boxLeft, boxTop, boxRight, boxTop + boxH - 1,
                                () => $"Installed {instTime?.ToString("d") ?? "manually"}",
                                th => th.ActiveFrameFg,
                                true,
                                new List <CkanModule>()
                            {
                                inst
                            }
                                );
                            boxTop += boxH;
                        }
                        else
                        {
                            addVersionBox(
                                boxLeft, boxTop, boxRight, boxTop + boxH - 1,
                                () => $"Latest/Installed {instTime?.ToString("d") ?? "manually"}",
                                th => th.ActiveFrameFg,
                                true,
                                new List <CkanModule>()
                            {
                                inst
                            }
                                );
                            boxTop += boxH;
                        }
                    }
                    else
                    {
                        addVersionBox(
                            boxLeft, boxTop, boxRight, boxTop + boxH - 1,
                            () => "Latest Version",
                            th => th.AlertFrameFg,
                            false,
                            new List <CkanModule>()
                        {
                            latest
                        }
                            );
                        boxTop += boxH;

                        addVersionBox(
                            boxLeft, boxTop, boxRight, boxTop + boxH - 1,
                            () => $"Installed {instTime?.ToString("d") ?? "manually"}",
                            th => th.ActiveFrameFg,
                            true,
                            new List <CkanModule>()
                        {
                            inst
                        }
                            );
                        boxTop += boxH;
                    }
                }
                else
                {
                    addVersionBox(
                        boxLeft, boxTop, boxRight, boxTop + boxH - 1,
                        () => "Latest Version",
                        th => th.NormalFrameFg,
                        false,
                        new List <CkanModule>()
                    {
                        latest
                    }
                        );
                    boxTop += boxH;
                }

                if (others.Count > 0)
                {
                    addVersionBox(
                        boxLeft, boxTop, boxRight, boxTop + boxH - 1,
                        () => "Other Versions",
                        th => th.NormalFrameFg,
                        false,
                        others
                        );
                    boxTop += boxH;
                }
            }
            else
            {
                DateTime?instTime = InstalledOn(mod.identifier);
                // Mod is no longer indexed, but we can generate a display
                // of the old info about it from when we installed it
                addVersionBox(
                    boxLeft, boxTop, boxRight, boxTop + boxH - 1,
                    () => $"UNAVAILABLE/Installed {instTime?.ToString("d") ?? "manually"}",
                    th => th.AlertFrameFg,
                    true,
                    new List <CkanModule>()
                {
                    mod
                }
                    );
                boxTop += boxH;
            }

            return(boxTop - 1);
        }
Beispiel #19
0
 /// <summary>
 /// Return the symbol to use to represent a mod's StatusSymbol.
 /// This can't be static because the user's installation plans are part of the object.
 /// </summary>
 /// <param name="m">The mod</param>
 /// <returns>
 /// String containing symbol to use
 /// </returns>
 public string StatusSymbol(CkanModule m)
 {
     return(StatusSymbol(plan.GetModStatus(manager, registry, m.identifier)));
 }
Beispiel #20
0
        private const string version_token = "$vref"; // It'd be nice if we could have repeated $krefs.

        public static int Main(string[] args)
        {
            BasicConfigurator.Configure();
            LogManager.GetRepository().Threshold = Level.Error;
            var user = new ConsoleUser(false);

            var options = new CmdLineOptions();

            Parser.Default.ParseArgumentsStrict(args, options);

            if (options.Verbose)
            {
                LogManager.GetRepository().Threshold = Level.Info;
            }
            else if (options.Debug)
            {
                LogManager.GetRepository().Threshold = Level.Debug;
            }

            if (options.NetUserAgent != null)
            {
                Net.UserAgentString = options.NetUserAgent;
            }

            if (options.File == null)
            {
                log.Fatal("Usage: netkan [--verbose|--debug] [--prerelease] [--outputdir=...] <filename>");
                return(EXIT_BADOPT);
            }

            NetFileCache cache = FindCache(options, new KSPManager(user), user);

            log.InfoFormat("Processing {0}", options.File);

            JObject      json   = JsonFromFile(options.File);
            NetKanRemote remote = FindRemote(json);

            JObject metadata;

            switch (remote.source)
            {
            case "kerbalstuff":
                metadata = KerbalStuff(json, remote.id, cache);
                break;

            case "jenkins":
                metadata = Jenkins(json, remote.id, cache);
                break;

            case "github":
                if (options.GitHubToken != null)
                {
                    GithubAPI.SetCredentials(options.GitHubToken);
                }

                metadata = GitHub(json, remote.id, options.PreRelease, cache);
                break;

            case "http":
                metadata = HTTP(json, remote.id, cache, user);
                break;

            default:
                log.FatalFormat("Unknown remote source: {0}", remote.source);
                return(EXIT_ERROR);
            }

            if (metadata == null)
            {
                log.Error("There was an error, aborting");
                return(EXIT_ERROR);
            }

            // Make sure that at the very least this validates against our own
            // internal model.

            CkanModule mod = CkanModule.FromJson(metadata.ToString());

            // Make sure our identifiers match.
            if (mod.identifier != (string)json["identifier"])
            {
                log.FatalFormat("Error: Have metadata for {0}, but wanted {1}", mod.identifier, json["identifier"]);
                return(EXIT_ERROR);
            }

            // Find our cached file, we'll need it later.
            string file = cache.GetCachedZip(mod.download);

            if (file == null)
            {
                log.FatalFormat("Error: Unable to find {0} in the cache", mod.identifier);
                return(EXIT_ERROR);
            }

            // Make sure this would actually generate an install
            try
            {
                ModuleInstaller.FindInstallableFiles(mod, file, null);
            }
            catch (BadMetadataKraken kraken)
            {
                log.FatalFormat("Error: Bad metadata for {0}: {1}", kraken.module, kraken.Message);
                return(EXIT_ERROR);
            }

            // Now inflate our original metadata from AVC, if we have it.
            // The reason we inflate our metadata and not the module is that in the module we can't
            // tell if there's been an override of the version fields or not.
            foreach (string vref in vrefs(metadata))
            {
                log.DebugFormat("Expanding vref {0}", vref);

                if (vref.StartsWith("#/ckan/ksp-avc"))
                {
                    // HTTP has already included the KSP-AVC data as it needs it earlier in the process
                    if (remote.source != "http")
                    {
                        var versionRemote = FindVersionRemote(metadata, vref);

                        try
                        {
                            AVC avc = AVC.FromZipFile(mod, file, versionRemote.id);
                            // TODO check why the AVC file can be null...
                            if (avc != null)
                            {
                                avc.InflateMetadata(metadata, null, null);
                            }
                        }
                        catch (JsonReaderException)
                        {
                            user.RaiseMessage("Bad embedded KSP-AVC file for {0}, halting.", mod);
                            return(EXIT_ERROR);
                        }
                    }
                }

                if (vref.StartsWith("#/ckan/kerbalstuff"))
                {
                    log.DebugFormat("Kerbalstuff vref: {0}", vref);
                    Match match = Regex.Match(vref, @"^#/ckan/([^/]+)/(.+)");

                    if (!match.Success)
                    {
                        // TODO: Have a proper kraken class!
                        user.RaiseMessage("Cannot find remote and ID in vref: {0}, halting.", vref);
                        return(EXIT_ERROR);
                    }

                    string remote_id = match.Groups [2].ToString();
                    log.DebugFormat("Kerbalstuff id  : {0}", remote_id);
                    try
                    {
                        KSMod ks = KSAPI.Mod(Convert.ToInt32(remote_id));
                        if (ks != null)
                        {
                            KSVersion version = new KSVersion();
                            version.friendly_version = mod.version;
                            ks.InflateMetadata(metadata, file, version);
                        }
                    }
                    catch (JsonReaderException)
                    {
                        user.RaiseMessage("Cannot find remote and ID in vref: {0}, halting.", vref);
                        return(EXIT_ERROR);
                    }
                }
            }

            // Fix our version string, if required.
            metadata = FixVersionStrings(metadata);

            // Re-inflate our mod, in case our vref or FixVersionString routines have
            // altered it at all.
            mod = CkanModule.FromJson(metadata.ToString());

            // All done! Write it out!

            string final_path = Path.Combine(options.OutputDir, String.Format("{0}-{1}.ckan", mod.identifier, mod.version));

            log.InfoFormat("Writing final metadata to {0}", final_path);

            StringBuilder sb = new StringBuilder();
            StringWriter  sw = new StringWriter(sb);

            using (JsonTextWriter writer = new JsonTextWriter(sw))
            {
                writer.Formatting  = Formatting.Indented;
                writer.Indentation = 4;
                writer.IndentChar  = ' ';

                JsonSerializer serializer = new JsonSerializer();
                serializer.Serialize(writer, metadata);
            }

            File.WriteAllText(final_path, sw.ToString() + Environment.NewLine);

            return(EXIT_OK);
        }
Beispiel #21
0
        public void CompatibleWith()
        {
            CkanModule module = CkanModule.FromJson(TestData.kOS_014());

            Assert.IsTrue(module.IsCompatibleKSP("0.24.2"));
        }
Beispiel #22
0
        /// <summary>
        /// Locates a version file in the zipfile specified, and returns an AVC object.
        /// This requires a module object as we *first* search files we might install,
        /// falling back to a search of all files in the archive.
        ///
        /// Returns null if no version is found.
        /// Throws a Kraken if too many versions are found.
        /// </summary>
        private static AvcVersion GetInternalAvc(CkanModule module, ZipFile zipfile, string internalFilePath)
        {
            Log.DebugFormat("Finding AVC .version file for {0}", module);

            const string versionExt = ".version";

            // Get all our version files.
            var files = ModuleInstaller.FindInstallableFiles(module, zipfile, null)
                        .Select(x => x.source)
                        .Where(source => source.Name.EndsWith(versionExt))
                        .ToList();

            if (files.Count == 0)
            {
                // Oh dear, no version file at all? Let's see if we can find *any* to use.
                var versionFiles = zipfile.Cast <ZipEntry>().Where(file => file.Name.EndsWith(versionExt));
                files.AddRange(versionFiles);

                // Okay, there's *really* nothing there.
                if (files.Count == 0)
                {
                    return(null);
                }
            }

            var remoteIndex = 0;

            if (!string.IsNullOrWhiteSpace(internalFilePath))
            {
                remoteIndex = -1;

                for (var i = 0; i < files.Count; i++)
                {
                    Log.DebugFormat("Testing file '{0}' against path '{1}'", files[i].Name, internalFilePath);
                    // Test for either an exact match or using the filespec as a regexp
                    if (internalFilePath.Equals(files[i]?.Name) || Regex.IsMatch(files[i]?.Name, internalFilePath))
                    {
                        remoteIndex = i;
                        break;
                    }
                }

                if (remoteIndex == -1)
                {
                    var remotes = files.Aggregate("", (current, file) => current + (file.Name + ", "));

                    throw new Kraken(string.Format("AVC: Invalid path to remote {0}, doesn't match any of: {1}",
                                                   internalFilePath,
                                                   remotes
                                                   ));
                }
            }
            else if (files.Count > 1)
            {
                throw new Kraken(
                          string.Format("Too many .version files located: {0}",
                                        string.Join(", ", files.Select(x => x.Name))));
            }

            Log.DebugFormat("Using AVC data from {0}", files[remoteIndex].Name);

            // Hooray, found our entry. Extract and return it.
            using (var zipstream = zipfile.GetInputStream(files[remoteIndex]))
                using (var stream = new StreamReader(zipstream))
                {
                    var json = stream.ReadToEnd();

                    Log.DebugFormat("Parsing {0}", json);
                    return(JsonConvert.DeserializeObject <AvcVersion>(json));
                }
        }
Beispiel #23
0
 public IEnumerable <InstallableFile> GetConfigFiles(CkanModule module, ZipFile zip)
 {
     return(ModuleInstaller
            .FindInstallableFiles(module, zip, null)
            .Where(instF => cfgRegex.IsMatch(instF.source.Name)));
 }
Beispiel #24
0
        public Metadata Transform(Metadata metadata)
        {
            if (metadata.Vref != null && metadata.Vref.Source == "ksp-avc")
            {
                var json = metadata.Json();

                Log.InfoFormat("Executing Interal AVC transformation with {0}", metadata.Kref);
                Log.DebugFormat("Input metadata:{0}{1}", Environment.NewLine, json);

                var noVersion = metadata.Version == null;

                if (noVersion)
                {
                    json["version"] = "0"; // TODO: DBB: Dummy version necessary to the next statement doesn't throw
                }

                var mod = CkanModule.FromJson(json.ToString());

                if (noVersion)
                {
                    json.Remove("version");
                }

                var file = _http.DownloadPackage(metadata.Download, metadata.Identifier);
                var avc  = _moduleService.GetInternalAvc(mod, file, metadata.Vref.Id);

                if (avc != null)
                {
                    Log.Info("Found internal AVC version file");

                    var remoteUri = GetRemoteAvcUri(avc);

                    if (remoteUri != null)
                    {
                        try
                        {
                            var remoteJson = Net.DownloadText(remoteUri);
                            var remoteAvc  = JsonConvert.DeserializeObject <AvcVersion>(remoteJson);

                            if (avc.version.CompareTo(remoteAvc.version) == 0)
                            {
                                // Local AVC and Remote AVC describe the same version, prefer
                                Log.Info("Remote AVC version file describes same version as local AVC version file, using it preferrentially.");
                                avc = remoteAvc;
                            }
                        }
                        catch (Exception e)
                        {
                            Log.InfoFormat("An error occured fetching the remote AVC version file, ignoring: {0}", e.Message);
                            Log.Debug(e);
                        }
                    }

                    // Get the minimum and maximum KSP versions that already exist in the metadata.
                    // Use specific KSP version if min/max don't exist.
                    var existingKspMinStr = (string)json["ksp_version_min"] ?? (string)json["ksp_version"];
                    var existingKspMaxStr = (string)json["ksp_version_max"] ?? (string)json["ksp_version"];

                    var existingKspMin = existingKspMinStr == null ? null : KspVersion.Parse(existingKspMinStr);
                    var existingKspMax = existingKspMaxStr == null ? null : KspVersion.Parse(existingKspMaxStr);

                    // Get the minimum and maximum KSP versions that are in the AVC file.
                    // Use specific KSP version if min/max don't exist.
                    var avcKspMin = avc.ksp_version_min ?? avc.ksp_version;
                    var avcKspMax = avc.ksp_version_max ?? avc.ksp_version;

                    // Now calculate the minimum and maximum KSP versions between both the existing metadata and the
                    // AVC file.
                    var kspMins  = new List <KspVersion>();
                    var kspMaxes = new List <KspVersion>();

                    if (existingKspMin != null)
                    {
                        kspMins.Add(existingKspMin);
                    }

                    if (avcKspMin != null)
                    {
                        kspMins.Add(avcKspMin);
                    }

                    if (existingKspMax != null)
                    {
                        kspMaxes.Add(existingKspMax);
                    }

                    if (avcKspMax != null)
                    {
                        kspMaxes.Add(avcKspMax);
                    }

                    var kspMin = kspMins.Any() ? kspMins.Min() : null;
                    var kspMax = kspMaxes.Any() ? kspMaxes.Max() : null;

                    if (kspMin != null || kspMax != null)
                    {
                        // If we have either a minimum or maximum KSP version, remove all existing KSP version
                        // information from the metadata.
                        json.Remove("ksp_version");
                        json.Remove("ksp_version_min");
                        json.Remove("ksp_version_max");

                        if (kspMin != null && kspMax != null)
                        {
                            // If we have both a minimum and maximum KSP version...
                            if (kspMin.CompareTo(kspMax) == 0)
                            {
                                // ...and they are equal, then just set ksp_version
                                json["ksp_version"] = kspMin.ToString();
                            }
                            else
                            {
                                // ...otherwise set both ksp_version_min and ksp_version_max
                                json["ksp_version_min"] = kspMin.ToString();
                                json["ksp_version_max"] = kspMax.ToString();
                            }
                        }
                        else
                        {
                            // If we have only one or the other then set which ever is applicable

                            if (kspMin != null)
                            {
                                json["ksp_version_min"] = kspMin.ToString();
                            }

                            if (kspMax != null)
                            {
                                json["ksp_version_max"] = kspMax.ToString();
                            }
                        }
                    }

                    if (avc.version != null)
                    {
                        // In practice, the version specified in .version files tends to be unreliable, with authors
                        // forgetting to update it when new versions are released. Therefore if we have a version
                        // specified from another source such as SpaceDock, curse or a GitHub tag, don't overwrite it.
                        json.SafeAdd("version", avc.version.ToString());
                    }

                    // It's cool if we don't have version info at all, it's optional in the AVC spec.

                    Log.DebugFormat("Transformed metadata:{0}{1}", Environment.NewLine, json);
                }

                return(new Metadata(json));
            }
            else
            {
                return(metadata);
            }
        }
Beispiel #25
0
        /// <summary>
        /// Given a module and an open zipfile, return all the files that would be installed
        /// for this module.
        ///
        /// If a KSP instance is provided, it will be used to generate output paths, otherwise these will be null.
        ///
        /// Throws a BadMetadataKraken if the stanza resulted in no files being returned.
        /// </summary>
        public static List<InstallableFile> FindInstallableFiles(CkanModule module, ZipFile zipfile, KSP ksp)
        {
            var files = new List<InstallableFile> ();

            try
            {
                // Use the provided stanzas, or use the default install stanza if they're absent.
                if (module.install != null && module.install.Length != 0)
                {
                    foreach (ModuleInstallDescriptor stanza in module.install)
                    {
                        files.AddRange(FindInstallableFiles(stanza, zipfile, ksp));
                    }
                }
                else
                {
                    ModuleInstallDescriptor default_stanza = ModuleInstallDescriptor.DefaultInstallStanza(module.identifier, zipfile);
                    files.AddRange(FindInstallableFiles(default_stanza, zipfile, ksp));
                }
            }
            catch (BadMetadataKraken kraken)
            {
                // Decorate our kraken with the current module, as the lower-level
                // methods won't know it.
                kraken.module = module;
                throw;
            }

            return files;
        }
Beispiel #26
0
        public void CompatibleWith()
        {
            CkanModule module = CkanModule.FromJson(TestData.kOS_014());

            Assert.IsTrue(module.IsCompatibleKSP(new GameVersionCriteria(GameVersion.Parse("0.24.2"))));
        }
Beispiel #27
0
 /// <summary>
 /// Add or remove a mod from the upgrade list
 /// </summary>
 /// <param name="mod">The mod to add or remove</param>
 public void ToggleUpgrade(CkanModule mod)
 {
     Install.Remove(mod);
     Remove.Remove(mod.identifier);
     toggleContains(Upgrade, mod.identifier);
 }
Beispiel #28
0
        public void SpacesPreservedInDownload()
        {
            CkanModule module = CkanModule.FromJson(TestData.DogeCoinFlag_101());

            Assert.AreEqual("https://kerbalstuff.com/mod/269/Dogecoin%20Flag/download/1.01", module.download.OriginalString);
        }
Beispiel #29
0
        /// <summary>
        /// Mark a given module as available.
        /// </summary>
        public void AddAvailable(CkanModule module)
        {
            SealionTransaction();

            var identifier = module.identifier;
            // If we've never seen this module before, create an entry for it.
            if (! available_modules.ContainsKey(identifier))
            {
                log.DebugFormat("Adding new available module {0}", identifier);
                available_modules[identifier] = new AvailableModule(identifier);
            }

            // Now register the actual version that we have.
            // (It's okay to have multiple versions of the same mod.)

            log.DebugFormat("Available: {0} version {1}", identifier, module.version);
            available_modules[identifier].Add(module);
        }
Beispiel #30
0
 public static CkanModule DogeCoinFlag_101_module()
 {
     return(CkanModule.FromJson(DogeCoinFlag_101()));
 }
Beispiel #31
0
        /// <summary>
        /// Resolves all relationships for a module.
        /// May recurse to ResolveStanza, which may add additional modules to be installed.
        /// </summary>
        private void Resolve(CkanModule module, RelationshipResolverOptions options)
        {
            // Even though we may resolve top-level suggests for our module,
            // we don't install suggestions all the down unless with_all_suggests
            // is true.
            var sub_options = (RelationshipResolverOptions) options.Clone();
            sub_options.with_suggests = false;

            log.DebugFormat("Resolving dependencies for {0}", module.identifier);
            ResolveStanza(module.depends, new SelectionReason.Depends(module), sub_options);

            if (options.with_recommends)
            {
                log.DebugFormat("Resolving recommends for {0}", module.identifier);
                ResolveStanza(module.recommends, new SelectionReason.Recommended(module), sub_options, true);
            }

            if (options.with_suggests || options.with_all_suggests)
            {
                log.DebugFormat("Resolving suggests for {0}", module.identifier);
                ResolveStanza(module.suggests, new SelectionReason.Suggested(module), sub_options, true);
            }
        }
Beispiel #32
0
 public static CkanModule DogeCoinPlugin_module()
 {
     return(CkanModule.FromJson(DogeCoinPlugin()));
 }
Beispiel #33
0
        /// <summary>
        /// Initialize the screen
        /// </summary>
        /// <param name="mgr">Game instance manager object containing the current instance</param>
        /// <param name="dbg">True if debug options should be available, false otherwise</param>
        /// <param name="regTheme">The theme to use for the registry update flow, if needed</param>
        public ModListScreen(GameInstanceManager mgr, bool dbg, ConsoleTheme regTheme)
        {
            debug    = dbg;
            manager  = mgr;
            registry = RegistryManager.Instance(manager.CurrentInstance).registry;

            moduleList = new ConsoleListBox <CkanModule>(
                1, 4, -1, -2,
                GetAllMods(regTheme),
                new List <ConsoleListBoxColumn <CkanModule> >()
            {
                new ConsoleListBoxColumn <CkanModule>()
                {
                    Header   = "",
                    Width    = 1,
                    Renderer = StatusSymbol
                }, new ConsoleListBoxColumn <CkanModule>()
                {
                    Header   = "Name",
                    Width    = 44,
                    Renderer = m => m.name ?? ""
                }, new ConsoleListBoxColumn <CkanModule>()
                {
                    Header   = "Version",
                    Width    = 10,
                    Renderer = m => ModuleInstaller.StripEpoch(m.version?.ToString() ?? ""),
                    Comparer = (a, b) => a.version.CompareTo(b.version)
                }, new ConsoleListBoxColumn <CkanModule>()
                {
                    Header   = "Max game version",
                    Width    = 17,
                    Renderer = m => registry.LatestCompatibleKSP(m.identifier)?.ToString() ?? "",
                    Comparer = (a, b) => registry.LatestCompatibleKSP(a.identifier).CompareTo(registry.LatestCompatibleKSP(b.identifier))
                }
            },
                1, 0, ListSortDirection.Descending,
                (CkanModule m, string filter) => {
                // Search for author
                if (filter.StartsWith("@"))
                {
                    string authorFilt = filter.Substring(1);
                    if (string.IsNullOrEmpty(authorFilt))
                    {
                        return(true);
                    }
                    else
                    {
                        // Remove special characters from search term
                        authorFilt = CkanModule.nonAlphaNums.Replace(authorFilt, "");
                        return(m.SearchableAuthors.Any((author) => author.IndexOf(authorFilt, StringComparison.CurrentCultureIgnoreCase) == 0));
                    }
                    // Other special search params: installed, updatable, new, conflicting and dependends
                }
                else if (filter.StartsWith("~"))
                {
                    if (filter.Length <= 1)
                    {
                        // Don't blank the list for just "~" by itself
                        return(true);
                    }
                    else
                    {
                        switch (filter.Substring(1, 1))
                        {
                        case "i":
                            return(registry.IsInstalled(m.identifier, false));

                        case "u":
                            return(registry.HasUpdate(m.identifier, manager.CurrentInstance.VersionCriteria()));

                        case "n":
                            // Filter new
                            return(recent.Contains(m.identifier));

                        case "c":
                            if (m.conflicts != null)
                            {
                                string conflictsWith = filter.Substring(2);
                                // Search for mods depending on a given mod
                                foreach (var rel in m.conflicts)
                                {
                                    if (rel.StartsWith(conflictsWith))
                                    {
                                        return(true);
                                    }
                                }
                            }
                            return(false);

                        case "d":
                            if (m.depends != null)
                            {
                                string dependsOn = filter.Substring(2);
                                // Search for mods depending on a given mod
                                foreach (var rel in m.depends)
                                {
                                    if (rel.StartsWith(dependsOn))
                                    {
                                        return(true);
                                    }
                                }
                            }
                            return(false);
                        }
                    }
                    return(false);
                }
                else
                {
                    filter = CkanModule.nonAlphaNums.Replace(filter, "");

                    return(m.SearchableIdentifier.IndexOf(filter, StringComparison.CurrentCultureIgnoreCase) >= 0 ||
                           m.SearchableName.IndexOf(filter, StringComparison.CurrentCultureIgnoreCase) >= 0 ||
                           m.SearchableAbstract.IndexOf(filter, StringComparison.CurrentCultureIgnoreCase) >= 0 ||
                           m.SearchableDescription.IndexOf(filter, StringComparison.CurrentCultureIgnoreCase) >= 0);
                }
            }
                );

            searchBox = new ConsoleField(-searchWidth, 2, -1)
            {
                GhostText = () => Focused() == searchBox
                    ? "<Type to search>"
                    : "<Ctrl+F to search>"
            };
            searchBox.OnChange += (ConsoleField sender, string newValue) => {
                moduleList.FilterString = newValue;
            };

            AddObject(new ConsoleLabel(
                          1, 2, -searchWidth - 2,
                          () => $"{moduleList.VisibleRowCount()} mods"
                          ));
            AddObject(searchBox);
            AddObject(moduleList);

            AddBinding(Keys.CtrlQ, (object sender, ConsoleTheme theme) => false);
            AddBinding(Keys.AltX, (object sender, ConsoleTheme theme) => false);
            AddBinding(Keys.F1, (object sender, ConsoleTheme theme) => Help(theme));
            AddBinding(Keys.AltH, (object sender, ConsoleTheme theme) => Help(theme));
            AddBinding(Keys.F5, (object sender, ConsoleTheme theme) => UpdateRegistry(theme));
            AddBinding(Keys.CtrlR, (object sender, ConsoleTheme theme) => UpdateRegistry(theme));
            AddBinding(Keys.CtrlU, (object sender, ConsoleTheme theme) => UpgradeAll(theme));

            // Now a bunch of convenience shortcuts so you don't get stuck in the search box
            searchBox.AddBinding(Keys.PageUp, (object sender, ConsoleTheme theme) => {
                SetFocus(moduleList);
                return(true);
            });
            searchBox.AddBinding(Keys.PageDown, (object sender, ConsoleTheme theme) => {
                SetFocus(moduleList);
                return(true);
            });
            searchBox.AddBinding(Keys.Enter, (object sender, ConsoleTheme theme) => {
                SetFocus(moduleList);
                return(true);
            });

            moduleList.AddBinding(Keys.CtrlF, (object sender, ConsoleTheme theme) => {
                SetFocus(searchBox);
                return(true);
            });
            moduleList.AddBinding(Keys.Escape, (object sender, ConsoleTheme theme) => {
                searchBox.Clear();
                return(true);
            });

            moduleList.AddTip("Enter", "Details",
                              () => moduleList.Selection != null
                              );
            moduleList.AddBinding(Keys.Enter, (object sender, ConsoleTheme theme) => {
                if (moduleList.Selection != null)
                {
                    LaunchSubScreen(theme, new ModInfoScreen(manager, plan, moduleList.Selection, debug));
                }
                return(true);
            });

            // Conditionally show only one of these based on selected mod status

            moduleList.AddTip("+", "Install",
                              () => moduleList.Selection != null && !moduleList.Selection.IsDLC &&
                              !registry.IsInstalled(moduleList.Selection.identifier, false)
                              );
            moduleList.AddTip("+", "Upgrade",
                              () => moduleList.Selection != null && !moduleList.Selection.IsDLC &&
                              registry.HasUpdate(moduleList.Selection.identifier, manager.CurrentInstance.VersionCriteria())
                              );
            moduleList.AddTip("+", "Replace",
                              () => moduleList.Selection != null &&
                              registry.GetReplacement(moduleList.Selection.identifier, manager.CurrentInstance.VersionCriteria()) != null
                              );
            moduleList.AddBinding(Keys.Plus, (object sender, ConsoleTheme theme) => {
                if (moduleList.Selection != null && !moduleList.Selection.IsDLC)
                {
                    if (!registry.IsInstalled(moduleList.Selection.identifier, false))
                    {
                        plan.ToggleInstall(moduleList.Selection);
                    }
                    else if (registry.IsInstalled(moduleList.Selection.identifier, false) &&
                             registry.HasUpdate(moduleList.Selection.identifier, manager.CurrentInstance.VersionCriteria()))
                    {
                        plan.ToggleUpgrade(moduleList.Selection);
                    }
                    else if (registry.GetReplacement(moduleList.Selection.identifier, manager.CurrentInstance.VersionCriteria()) != null)
                    {
                        plan.ToggleReplace(moduleList.Selection.identifier);
                    }
                }
                return(true);
            });

            moduleList.AddTip("-", "Remove",
                              () => moduleList.Selection != null && !moduleList.Selection.IsDLC &&
                              registry.IsInstalled(moduleList.Selection.identifier, false) &&
                              !registry.IsAutodetected(moduleList.Selection.identifier)
                              );
            moduleList.AddBinding(Keys.Minus, (object sender, ConsoleTheme theme) => {
                if (moduleList.Selection != null && !moduleList.Selection.IsDLC &&
                    registry.IsInstalled(moduleList.Selection.identifier, false) &&
                    !registry.IsAutodetected(moduleList.Selection.identifier))
                {
                    plan.ToggleRemove(moduleList.Selection);
                }
                return(true);
            });

            moduleList.AddTip("F8", "Mark auto-installed",
                              () => moduleList.Selection != null && !moduleList.Selection.IsDLC &&
                              (!registry.InstalledModule(moduleList.Selection.identifier)?.AutoInstalled ?? false)
                              );
            moduleList.AddTip("F8", "Mark user-selected",
                              () => moduleList.Selection != null && !moduleList.Selection.IsDLC &&
                              (registry.InstalledModule(moduleList.Selection.identifier)?.AutoInstalled ?? false)
                              );
            moduleList.AddBinding(Keys.F8, (object sender, ConsoleTheme theme) => {
                InstalledModule im = registry.InstalledModule(moduleList.Selection.identifier);
                if (im != null && !moduleList.Selection.IsDLC)
                {
                    im.AutoInstalled = !im.AutoInstalled;
                    RegistryManager.Instance(manager.CurrentInstance).Save(false);
                }
                return(true);
            });

            AddTip("F9", "Apply changes", plan.NonEmpty);
            AddBinding(Keys.F9, (object sender, ConsoleTheme theme) => {
                ApplyChanges(theme);
                return(true);
            });

            // Show total download size of all installed mods
            AddObject(new ConsoleLabel(
                          1, -1, searchWidth,
                          () => $"{CkanModule.FmtSize(totalInstalledDownloadSize())} installed",
                          null,
                          th => th.DimLabelFg
                          ));

            AddObject(new ConsoleLabel(
                          -searchWidth, -1, -2,
                          () => {
                int days = daysSinceUpdated(registryFilePath());
                return(days < 1 ? ""
                        :  days == 1 ? $"Updated at least {days} day ago"
                        :              $"Updated at least {days} days ago");
            },
                          null,
                          (ConsoleTheme th) => {
                int daysSince = daysSinceUpdated(registryFilePath());
                if (daysSince < daysTillStale)
                {
                    return(th.RegistryUpToDate);
                }
                else if (daysSince < daystillVeryStale)
                {
                    return(th.RegistryStale);
                }
                else
                {
                    return(th.RegistryVeryStale);
                }
            }
                          ));

            List <ConsoleMenuOption> opts = new List <ConsoleMenuOption>()
            {
                new ConsoleMenuOption("Sort...", "",
                                      "Change the sorting of the list of mods",
                                      true, null, null, moduleList.SortMenu()),
                null,
                new ConsoleMenuOption("Refresh mod list", "F5, Ctrl+R",
                                      "Refresh the list of mods",
                                      true, (ConsoleTheme th) => UpdateRegistry(th)),
                new ConsoleMenuOption("Upgrade all", "Ctrl+U",
                                      "Mark all available updates for installation",
                                      true, UpgradeAll, null, null, HasAnyUpgradeable()),
                new ConsoleMenuOption("Audit recommendations", "",
                                      "List mods suggested and recommended by installed mods",
                                      true, ViewSuggestions),
                new ConsoleMenuOption("Import downloads...", "",
                                      "Select manually downloaded mods to import into CKAN",
                                      true, ImportDownloads),
                new ConsoleMenuOption("Export installed...", "",
                                      "Save your mod list",
                                      true, ExportInstalled),
                null,
                new ConsoleMenuOption("Select game instance...", "",
                                      "Switch to a different game instance",
                                      true, SelectInstall),
                new ConsoleMenuOption("Authentication tokens...", "",
                                      "Edit authentication tokens sent to download servers",
                                      true, EditAuthTokens),
                null,
                new ConsoleMenuOption("Help", helpKey,
                                      "Tips & tricks",
                                      true, Help),
                null,
                new ConsoleMenuOption("Quit", "Ctrl+Q",
                                      "Exit to DOS",
                                      true, (ConsoleTheme th) => false)
            };

            if (debug)
            {
                opts.Add(null);
                opts.Add(new ConsoleMenuOption("DEBUG: Capture key...", "",
                                               "Print details of how your system reports a keystroke for debugging",
                                               true, CaptureKey));
            }
            mainMenu = new ConsolePopupMenu(opts);
        }
Beispiel #34
0
 public static CkanModule RandSCapsuleDyneModule()
 {
     return(CkanModule.FromJson(RandSCapsuleDyne()));
 }
Beispiel #35
0
 public IEnumerable <string> FileDestinations(CkanModule module, string filePath)
 {
     return(ModuleInstaller
            .FindInstallableFiles(module, filePath, new KSP("/", "dummy", null, false))
            .Select(f => f.destination));
 }
Beispiel #36
0
 public static CkanModule kOS_014_epoch_module()
 {
     return(CkanModule.FromJson(kOS_014_epoch()));
 }
Beispiel #37
0
 /// <summary>
 /// Returns the path to a cached copy of a module if it exists, or downloads
 /// and returns the downloaded copy otherwise.
 ///
 /// If no filename is provided, the module's standard name will be used.
 /// Chcecks the CKAN cache first.
 /// </summary>
 public string CachedOrDownload(CkanModule module, string filename = null)
 {
     return CachedOrDownload(module.identifier, module.version, module.download, Cache, filename);
 }
Beispiel #38
0
 public static CkanModule FireSpitterModule()
 {
     return(CkanModule.FromFile(Path.Combine(DataDir(), "Firespitter-6.3.5.ckan")));
 }
Beispiel #39
0
        /// <summary>
        ///     Install our mod from the filename supplied.
        ///     If no file is supplied, we will check the cache or throw FileNotFoundKraken.
        ///     Does *not* resolve dependencies; this actually does the heavy listing.
        ///     Does *not* save the registry.
        ///     Do *not* call this directly, use InstallList() instead.
        ///
        /// Propagates a BadMetadataKraken if our install metadata is bad.
        /// Propagates a FileExistsKraken if we were going to overwrite a file.
        /// Throws a FileNotFoundKraken if we can't find the downloaded module.
        ///
        /// </summary>
        //
        // TODO: The name of this and InstallModule() need to be made more distinctive.

        private void Install(CkanModule module, string filename = null)
        {
            CheckMetapackageInstallationKraken(module);

            Version version = registry_manager.registry.InstalledVersion(module.identifier);

            // TODO: This really should be handled by higher-up code.
            if (version != null)
            {
                User.RaiseMessage("    {0} {1} already installed, skipped", module.identifier, version);
                return;
            }

            // Find our in the cache if we don't already have it.
            filename = filename ?? Cache.GetCachedZip(module.download,true);

            // If we *still* don't have a file, then kraken bitterly.
            if (filename == null)
            {
                throw new FileNotFoundKraken(
                    null,
                    String.Format("Trying to install {0}, but it's not downloaded or download is corrupted", module)
                );
            }

            // We'll need our registry to record which files we've installed.
            Registry registry = registry_manager.registry;

            using (var transaction = CkanTransaction.CreateTransactionScope())
            {
                // Install all the things!
                IEnumerable<string> files = InstallModule(module, filename);

                // Register our module and its files.
                registry.RegisterModule(module, files, ksp);

                // Finish our transaction, but *don't* save the registry; we may be in an
                // intermediate, inconsistent state.
                // This is fine from a transaction standpoint, as we may not have an enclosing
                // transaction, and if we do, they can always roll us back.
                transaction.Complete();
            }

            // Fire our callback that we've installed a module, if we have one.
            if (onReportModInstalled != null)
            {
                onReportModInstalled(module);
            }

        }
Beispiel #40
0
 public static CkanModule ModuleManagerModule()
 {
     return(CkanModule.FromFile(DataDir("ModuleManager-2.5.1.ckan")));
 }
Beispiel #41
0
        /// <summary>
        /// Installs the module from the zipfile provided.
        /// Returns a list of files installed.
        /// Propagates a BadMetadataKraken if our install metadata is bad.
        /// Propagates a FileExistsKraken if we were going to overwrite a file.
        /// </summary>
        private IEnumerable<string> InstallModule(CkanModule module, string zip_filename)
        {
            CheckMetapackageInstallationKraken(module);

            using (ZipFile zipfile = new ZipFile(zip_filename))
            {
                IEnumerable<InstallableFile> files = FindInstallableFiles(module, zipfile, ksp);

                try
                {
                    foreach (InstallableFile file in files)
                    {
                        log.InfoFormat("Copying {0}", file.source.Name);
                        CopyZipEntry(zipfile, file.source, file.destination, file.makedir);
                    }
                }
                catch (FileExistsKraken kraken)
                {
                    // Decorate the kraken with our module and re-throw
                    kraken.filename = ksp.ToRelativeGameDir(kraken.filename);
                    kraken.installing_module = module;
                    kraken.owning_module = registry_manager.registry.FileOwner(kraken.filename);
                    throw;
                }

                return files.Select(x => x.destination);
            }
        }
Beispiel #42
0
 public static CkanModule MissionModule()
 {
     return(CkanModule.FromFile(DataDir("MissionTest-1.0.ckan")));
 }
Beispiel #43
0
 /// <summary>
 /// Given a module and a path to a zipfile, returns all the files that would be installed
 /// from that zip for this module.
 ///
 /// This *will* throw an exception if the file does not exist.
 ///
 /// Throws a BadMetadataKraken if the stanza resulted in no files being returned.
 ///
 /// If a KSP instance is provided, it will be used to generate output paths, otherwise these will be null.
 /// </summary>
 // TODO: Document which exception!
 public static List<InstallableFile> FindInstallableFiles(CkanModule module, string zip_filename, KSP ksp)
 {
     // `using` makes sure our zipfile gets closed when we exit this block.
     using (ZipFile zipfile = new ZipFile(zip_filename))
     {
         log.DebugFormat("Searching {0} using {1} as module", zip_filename, module);
         return FindInstallableFiles(module, zipfile, ksp);
     }
 }
Beispiel #44
0
        /// <summary>
        /// Initialize the Screen
        /// </summary>
        /// <param name="mgr">KSP manager containing game instances</param>
        /// <param name="cp">Plan of other mods to be added or removed</param>
        /// <param name="m">The module to display</param>
        /// <param name="dbg">True if debug options should be available, false otherwise</param>
        public ModInfoScreen(KSPManager mgr, ChangePlan cp, CkanModule m, bool dbg)
        {
            debug    = dbg;
            mod      = m;
            manager  = mgr;
            plan     = cp;
            registry = RegistryManager.Instance(manager.CurrentInstance).registry;

            int midL = Console.WindowWidth / 2 - 1;

            AddObject(new ConsoleLabel(
                          1, 1, -1,
                          () => mod.name == mod.identifier ? mod.name : $"{mod.name} ({mod.identifier})",
                          null,
                          () => ConsoleTheme.Current.ActiveFrameFg
                          ));
            AddObject(new ConsoleLabel(
                          1, 2, -1,
                          () => $"By {string.Join(", ", mod.author)}"
                          ));

            AddObject(new ConsoleFrame(
                          1, 3, midL, 7,
                          () => "",
                          () => ConsoleTheme.Current.NormalFrameFg,
                          false
                          ));
            AddObject(new ConsoleLabel(
                          3, 4, 11,
                          () => "License:",
                          null,
                          () => ConsoleTheme.Current.DimLabelFg
                          ));
            AddObject(new ConsoleLabel(
                          13, 4, midL - 2,
                          () => string.Join(", ", Array.ConvertAll <License, string>(
                                                mod.license.ToArray(), (l => l.ToString())))
                          ));
            AddObject(new ConsoleLabel(
                          3, 5, 12,
                          () => "Download:",
                          null,
                          () => ConsoleTheme.Current.DimLabelFg
                          ));
            AddObject(new ConsoleLabel(
                          13, 5, midL - 2,
                          () => Formatting.FmtSize(mod.download_size)
                          ));
            AddObject(new ConsoleLabel(
                          3, 6, midL - 2,
                          HostedOn
                          ));

            int depsBot = addDependencies();
            int versBot = addVersionDisplay();

            AddObject(new ConsoleFrame(
                          1, Math.Max(depsBot, versBot) + 1, -1, -1,
                          () => "Description",
                          () => ConsoleTheme.Current.NormalFrameFg,
                          false
                          ));
            ConsoleTextBox tb = new ConsoleTextBox(
                3, Math.Max(depsBot, versBot) + 2, -3, -2, false,
                TextAlign.Left,
                () => ConsoleTheme.Current.MainBg,
                () => ConsoleTheme.Current.LabelFg
                );

            tb.AddLine(mod.@abstract);
            if (!string.IsNullOrEmpty(mod.description) &&
                mod.description != mod.@abstract)
            {
                tb.AddLine(mod.description);
            }
            AddObject(tb);
            if (!ChangePlan.IsAnyAvailable(registry, mod.identifier))
            {
                tb.AddLine("\r\nNOTE: This mod is installed but no longer available.");
                tb.AddLine("If you uninstall it, CKAN will not be able to re-install it.");
            }
            tb.AddScrollBindings(this);

            AddTip("Esc", "Back");
            AddBinding(Keys.Escape, (object sender) => false);

            AddTip("Ctrl+D", "Download",
                   () => !manager.CurrentInstance.Cache.IsMaybeCachedZip(mod)
                   );
            AddBinding(Keys.CtrlD, (object sender) => {
                Download();
                return(true);
            });

            if (mod.resources != null)
            {
                List <ConsoleMenuOption> opts = new List <ConsoleMenuOption>();

                if (mod.resources.homepage != null)
                {
                    opts.Add(new ConsoleMenuOption(
                                 "Home page", "", "Open the home page URL in a browser",
                                 true,
                                 () => LaunchURL(mod.resources.homepage)
                                 ));
                }
                if (mod.resources.repository != null)
                {
                    opts.Add(new ConsoleMenuOption(
                                 "Repository", "", "Open the repository URL in a browser",
                                 true,
                                 () => LaunchURL(mod.resources.repository)
                                 ));
                }
                if (mod.resources.bugtracker != null)
                {
                    opts.Add(new ConsoleMenuOption(
                                 "Bugtracker", "", "Open the bug tracker URL in a browser",
                                 true,
                                 () => LaunchURL(mod.resources.bugtracker)
                                 ));
                }
                if (mod.resources.spacedock != null)
                {
                    opts.Add(new ConsoleMenuOption(
                                 "SpaceDock", "", "Open the SpaceDock URL in a browser",
                                 true,
                                 () => LaunchURL(mod.resources.spacedock)
                                 ));
                }
                if (mod.resources.curse != null)
                {
                    opts.Add(new ConsoleMenuOption(
                                 "Curse", "", "Open the Curse URL in a browser",
                                 true,
                                 () => LaunchURL(mod.resources.curse)
                                 ));
                }
                if (debug)
                {
                    opts.Add(null);
                    opts.Add(new ConsoleMenuOption(
                                 "DEBUG: View metadata", "", "Display the full registry data for this mod",
                                 true,
                                 ViewMetadata
                                 ));
                }

                if (opts.Count > 0)
                {
                    mainMenu = new ConsolePopupMenu(opts);
                }
            }

            LeftHeader   = () => $"CKAN {Meta.GetVersion()}";
            CenterHeader = () => "Mod Details";
        }
Beispiel #45
0
 /// <summary>
 /// Add or remove a mod from the install list
 /// </summary>
 /// <param name="mod">The mod to add or remove</param>
 public void ToggleInstall(CkanModule mod)
 {
     Upgrade.Remove(mod.identifier);
     Remove.Remove(mod.identifier);
     toggleContains(Install, mod);
 }
Beispiel #46
0
 public void OnModChanged(CkanModule module, GUIModChangeType changeType)
 {
     if (changeType == GUIModChangeType.Update || changeType == GUIModChangeType.Install)
     {
         // Todo: logic that will handle an updated mod, check all of its part files against the modified versions and propogate the changes if it can or alert the user if it can't.
     }
 }
Beispiel #47
0
        /// <summary>
        /// Shows information about the mod.
        /// </summary>
        /// <returns>Success status.</returns>
        /// <param name="module">The module to show.</param>
        public int ShowMod(CkanModule module)
        {
            #region Abstract and description
            if (!string.IsNullOrEmpty(module.@abstract))
            {
                user.RaiseMessage("{0}: {1}", module.name, module.@abstract);
            }
            else
            {
                user.RaiseMessage("{0}", module.name);
            }

            if (!string.IsNullOrEmpty(module.description))
            {
                user.RaiseMessage("\n{0}\n", module.description);
            }
            #endregion

            #region General info (author, version...)
            user.RaiseMessage("\nModule info:");
            user.RaiseMessage("- version:\t{0}", module.version);

            if (module.author != null)
            {
                user.RaiseMessage("- authors:\t{0}", string.Join(", ", module.author));
            }
            else
            {
                // Did you know that authors are optional in the spec?
                // You do now. #673.
                user.RaiseMessage("- authors:\tUNKNOWN");
            }

            user.RaiseMessage("- status:\t{0}", module.release_status);
            user.RaiseMessage("- license:\t{0}", string.Join(", ", module.license)); 
            #endregion

            #region Relationships
            if (module.depends != null && module.depends.Count > 0)
            {
                user.RaiseMessage("\nDepends:");
                foreach (RelationshipDescriptor dep in module.depends)
                    user.RaiseMessage("- {0}", RelationshipToPrintableString(dep));
            }

            if (module.recommends != null && module.recommends.Count > 0)
            {
                user.RaiseMessage("\nRecommends:");
                foreach (RelationshipDescriptor dep in module.recommends)
                    user.RaiseMessage("- {0}", RelationshipToPrintableString(dep));
            }

            if (module.suggests != null && module.suggests.Count > 0)
            {
                user.RaiseMessage("\nSuggests:");
                foreach (RelationshipDescriptor dep in module.suggests)
                    user.RaiseMessage("- {0}", RelationshipToPrintableString(dep));
            }

            if (module.ProvidesList != null && module.ProvidesList.Count > 0)
            {
                user.RaiseMessage("\nProvides:");
                foreach (string prov in module.ProvidesList)
                    user.RaiseMessage("- {0}", prov);
            } 
            #endregion

            user.RaiseMessage("\nResources:");
            if (module.resources != null)
            {
                if (module.resources.bugtracker != null)
                    user.RaiseMessage("- bugtracker: {0}", Uri.EscapeUriString(module.resources.bugtracker.ToString()));
                if (module.resources.homepage != null)
                    user.RaiseMessage("- homepage: {0}", Uri.EscapeUriString(module.resources.homepage.ToString()));
                if (module.resources.kerbalstuff != null)
                    user.RaiseMessage("- kerbalstuff: {0}", Uri.EscapeUriString(module.resources.kerbalstuff.ToString()));
                if (module.resources.repository != null)
                    user.RaiseMessage("- repository: {0}", Uri.EscapeUriString(module.resources.repository.ToString()));
            }

            // Compute the CKAN filename.
            string file_uri_hash = NetFileCache.CreateURLHash(module.download);
            string file_name = CkanModule.StandardName(module.identifier, module.version);

            user.RaiseMessage("\nFilename: {0}", file_uri_hash + "-" + file_name);

            return Exit.OK;
        }
Beispiel #48
0
        /// <summary>
        /// Run the screen
        /// </summary>
        /// <param name="theme">The visual theme to use to draw the dialog</param>
        /// <param name="process">Framework parameter not used by this object</param>
        public override void Run(ConsoleTheme theme, Action <ConsoleTheme> process = null)
        {
            HashSet <string> rejected = new HashSet <string>();

            DrawBackground(theme);
            using (TransactionScope trans = CkanTransaction.CreateTransactionScope()) {
                bool retry = false;
                do
                {
                    Draw(theme);
                    try {
                        // Reset this so we stop unless an exception sets it to true
                        retry = false;

                        // GUI prompts user to choose recs/sugs,
                        // CmdLine assumes recs and ignores sugs
                        if (plan.Install.Count > 0)
                        {
                            // Track previously rejected optional dependencies and don't prompt for them again.
                            DependencyScreen ds = new DependencyScreen(manager, plan, rejected, debug);
                            if (ds.HaveOptions())
                            {
                                LaunchSubScreen(theme, ds);
                            }
                        }

                        // FUTURE: BackgroundWorker

                        HashSet <string> possibleConfigOnlyDirs = null;

                        RegistryManager regMgr = RegistryManager.Instance(manager.CurrentInstance);
                        ModuleInstaller inst   = ModuleInstaller.GetInstance(manager.CurrentInstance, manager.Cache, this);
                        inst.onReportModInstalled = OnModInstalled;
                        if (plan.Remove.Count > 0)
                        {
                            inst.UninstallList(plan.Remove, ref possibleConfigOnlyDirs, regMgr, true, plan.Install);
                            plan.Remove.Clear();
                        }
                        NetAsyncModulesDownloader dl = new NetAsyncModulesDownloader(this, manager.Cache);
                        if (plan.Upgrade.Count > 0)
                        {
                            inst.Upgrade(plan.Upgrade, dl, ref possibleConfigOnlyDirs, regMgr);
                            plan.Upgrade.Clear();
                        }
                        if (plan.Install.Count > 0)
                        {
                            List <CkanModule> iList = new List <CkanModule>(plan.Install);
                            inst.InstallList(iList, resolvOpts, regMgr, ref possibleConfigOnlyDirs, dl);
                            plan.Install.Clear();
                        }
                        if (plan.Replace.Count > 0)
                        {
                            inst.Replace(AllReplacements(plan.Replace), resolvOpts, dl, ref possibleConfigOnlyDirs, regMgr, true);
                        }

                        trans.Complete();
                        // Don't let the installer re-use old screen references
                        inst.User = null;
                        inst.onReportModInstalled = null;
                    } catch (CancelledActionKraken) {
                        // Don't need to tell the user they just cancelled out.
                    } catch (FileNotFoundKraken ex) {
                        // Possible file corruption
                        RaiseError(ex.Message);
                    } catch (DirectoryNotFoundKraken ex) {
                        RaiseError(ex.Message);
                    } catch (FileExistsKraken ex) {
                        if (ex.owningModule != null)
                        {
                            RaiseMessage($"{ex.installingModule} tried to install {ex.filename}, but {ex.owningModule} has already installed it.");
                            RaiseMessage($"Please report this problem at https://github.com/KSP-CKAN/NetKAN/issues/new/choose");
                        }
                        else
                        {
                            RaiseMessage($"{ex.installingModule} tried to install {ex.filename}, but it is already installed.");
                            RaiseMessage($"Please manually uninstall the mod that owns this file to install {ex.installingModule}.");
                        }
                        RaiseError("Game files reverted.");
                    } catch (DownloadErrorsKraken ex) {
                        RaiseError(ex.ToString());
                    } catch (ModuleDownloadErrorsKraken ex) {
                        RaiseError(ex.ToString());
                    } catch (DownloadThrottledKraken ex) {
                        if (RaiseYesNoDialog($"{ex.ToString()}\n\nEdit authentication tokens now?"))
                        {
                            if (ex.infoUrl != null)
                            {
                                ModInfoScreen.LaunchURL(theme, ex.infoUrl);
                            }
                            LaunchSubScreen(theme, new AuthTokenScreen());
                        }
                    } catch (MissingCertificateKraken ex) {
                        RaiseError(ex.ToString());
                    } catch (InconsistentKraken ex) {
                        RaiseError(ex.InconsistenciesPretty);
                    } catch (TooManyModsProvideKraken ex) {
                        ConsoleChoiceDialog <CkanModule> ch = new ConsoleChoiceDialog <CkanModule>(
                            $"Module {ex.requested} is provided by multiple modules. Which would you like to install?",
                            "Name",
                            ex.modules,
                            (CkanModule mod) => mod.ToString()
                            );
                        CkanModule chosen = ch.Run(theme);
                        DrawBackground(theme);
                        if (chosen != null)
                        {
                            // Use chosen to continue installing
                            plan.Install.Add(chosen);
                            retry = true;
                        }
                    } catch (BadMetadataKraken ex) {
                        RaiseError($"Bad metadata detected for {ex.module}: {ex.Message}");
                    } catch (DependencyNotSatisfiedKraken ex) {
                        RaiseError($"{ex.parent} requires {ex.module}, but it is not listed in the index, or not available for your version of the game.\r\n{ex.Message}");
                    } catch (ModuleNotFoundKraken ex) {
                        RaiseError($"Module {ex.module} required but it is not listed in the index, or not available for your version of the game.\r\n{ex.Message}");
                    } catch (ModNotInstalledKraken ex) {
                        RaiseError($"{ex.mod} is not installed, can't remove");
                    } catch (DllLocationMismatchKraken ex) {
                        RaiseError(ex.Message);
                    }
                } while (retry);
            }
        }
Beispiel #49
0
 internal SelectionReason ReasonFor(CkanModule mod)
 {
     if (!ModList().Contains(mod))
     {
         throw new ArgumentException("Mod " + mod.StandardName() + " is not in the list");
     }
     return reasons[mod];
 }
Beispiel #50
0
        private static readonly string version_token = "$vref"; // It'd be nice if we could have repeated $krefs.

        public static int Main(string[] args)
        {
            BasicConfigurator.Configure();
            LogManager.GetRepository().Threshold = Level.Error;

            var options = new CmdLineOptions();

            Parser.Default.ParseArgumentsStrict(args, options);

            if (options.Verbose)
            {
                LogManager.GetRepository().Threshold = Level.Info;
            }
            else if (options.Debug)
            {
                LogManager.GetRepository().Threshold = Level.Debug;
            }

            if (options.File == null)
            {
                log.Fatal("Usage: netkan [--verbose|--debug] [--outputdir=...] <filename>");
                return(EXIT_BADOPT);
            }

            NetFileCache cache = FindCache(options);

            log.InfoFormat("Processing {0}", options.File);

            JObject      json   = JsonFromFile(options.File);
            NetKanRemote remote = FindRemote(json);

            JObject metadata;

            if (remote.source == "kerbalstuff")
            {
                metadata = KerbalStuff(json, remote.id, cache);
            }
            else if (remote.source == "github")
            {
                metadata = GitHub(json, remote.id, cache);
            }
            else
            {
                log.FatalFormat("Unknown remote source: {0}", remote.source);
                return(EXIT_ERROR);
            }

            // Make sure that at the very least this validates against our own
            // internal model.

            CkanModule mod = CkanModule.FromJson(metadata.ToString());

            // Make sure our identifiers match.
            if (mod.identifier != (string)json["identifier"])
            {
                log.FatalFormat("Error: Have metadata for {0}, but wanted {1}", mod.identifier, json["identifier"]);
                return(EXIT_ERROR);
            }

            // Find our cached file, we'll need it later.
            string file = cache.GetCachedZip(mod.download);

            if (file == null)
            {
                log.FatalFormat("Error: Unable to find {0} in the cache", mod.identifier);
                return(EXIT_ERROR);
            }

            // Make sure this would actually generate an install
            try
            {
                ModuleInstaller.FindInstallableFiles(mod, file, null);
            }
            catch (BadMetadataKraken kraken)
            {
                log.FatalFormat("Error: Bad metadata for {0}: {1}", kraken.module, kraken.Message);
                return(EXIT_ERROR);
            }

            // Now inflate our original metadata from AVC, if we have it.
            // The reason we inflate our metadata and not the module is that in the module we can't
            // tell if there's been an override of the version fields or not.

            // TODO: Remove magic string "#/ckan/ksp-avc"
            if (metadata[version_token] != null && (string)metadata[version_token] == "#/ckan/ksp-avc")
            {
                metadata.Remove(version_token);

                try {
                    AVC avc = AVC.FromZipFile(mod, file);
                    avc.InflateMetadata(metadata, null, null);
                }
                catch (Newtonsoft.Json.JsonReaderException)
                {
                    User.WriteLine("Bad embedded KSP-AVC file for {0}, halting.", mod);
                    return(EXIT_ERROR);
                }

                // If we've done this, we need to re-inflate our mod, too.
                mod = CkanModule.FromJson(metadata.ToString());
            }

            // All done! Write it out!

            string final_path = Path.Combine(options.OutputDir, String.Format("{0}-{1}.ckan", mod.identifier, mod.version));

            log.InfoFormat("Writing final metadata to {0}", final_path);
            File.WriteAllText(final_path, metadata.ToString());

            return(EXIT_OK);
        }
Beispiel #51
0
        /// <summary>
        /// Tests that a module might be able to be installed via checking if dependencies
        /// exist for current version.
        /// </summary>
        /// <param name="module">The module to consider</param>
        /// <param name="compatible">For internal use</param>
        /// <returns>If it has dependencies compatible for the current version</returns>
        private bool MightBeInstallable(CkanModule module, List<string> compatible = null)
        {
            if (module.depends == null) return true;
            if (compatible == null)
            {
                compatible = new List<string>();
            }
            else if (compatible.Contains(module.identifier))
            {
                return true;
            }
            //When checking the dependencies we assume that this module is installable
            // in case a dependent depends on it
            compatible.Add(module.identifier);

            var needed = module.depends.Select(depend => registry.LatestAvailableWithProvides(depend.name, kspversion));
            //We need every dependency to have at least one possible module
            var installable = needed.All(need => need.Any(mod => MightBeInstallable(mod, compatible)));
            compatible.Remove(module.identifier);
            return installable;
        }
Beispiel #52
0
        public Metadata Transform(Metadata metadata)
        {
            if (metadata.Vref != null && metadata.Vref.Source == "ksp-avc")
            {
                var json = metadata.Json();

                Log.InfoFormat("Executing internal AVC transformation with {0}", metadata.Kref);
                Log.DebugFormat("Input metadata:{0}{1}", Environment.NewLine, json);

                var noVersion = metadata.Version == null;

                if (noVersion)
                {
                    json["version"] = "0"; // TODO: DBB: Dummy version necessary to the next statement doesn't throw
                }

                var mod = CkanModule.FromJson(json.ToString());

                if (noVersion)
                {
                    json.Remove("version");
                }

                var file = _http.DownloadPackage(metadata.Download, metadata.Identifier, metadata.RemoteTimestamp);
                var avc  = _moduleService.GetInternalAvc(mod, file, metadata.Vref.Id);

                if (avc != null)
                {
                    Log.Info("Found internal AVC version file");

                    var remoteUri = GetRemoteAvcUri(avc);

                    if (remoteUri != null)
                    {
                        try
                        {
                            var remoteJson = Net.DownloadText(remoteUri);
                            var remoteAvc  = JsonConvert.DeserializeObject <AvcVersion>(remoteJson);

                            if (avc.version.CompareTo(remoteAvc.version) == 0)
                            {
                                // Local AVC and Remote AVC describe the same version, prefer
                                Log.Info("Remote AVC version file describes same version as local AVC version file, using it preferrentially.");
                                avc = remoteAvc;
                            }
                        }
                        catch (Exception e)
                        {
                            Log.InfoFormat("An error occured fetching the remote AVC version file, ignoring: {0}", e.Message);
                            Log.Debug(e);
                        }
                    }

                    ApplyVersions(json, avc);

                    // It's cool if we don't have version info at all, it's optional in the AVC spec.

                    Log.DebugFormat("Transformed metadata:{0}{1}", Environment.NewLine, json);
                }

                return(new Metadata(json));
            }
            else
            {
                return(metadata);
            }
        }
Beispiel #53
0
 public Depends(CkanModule module)
 {
     if (module == null) throw new ArgumentNullException();
     Parent = module;
 }
Beispiel #54
0
        public int RunCommand(CKAN.KSP ksp, object raw_options)
        {
            ShowOptions options = (ShowOptions)raw_options;

            if (options.Modname == null)
            {
                // empty argument
                user.RaiseMessage("show <module> - module name argument missing, perhaps you forgot it?");
                return(Exit.BADOPT);
            }

            // Check installed modules for an exact match.
            var registry = RegistryManager.Instance(ksp).registry;
            var installedModuleToShow = registry.InstalledModule(options.Modname);

            if (installedModuleToShow != null)
            {
                // Show the installed module.
                return(ShowMod(installedModuleToShow));
            }

            // Module was not installed, look for an exact match in the available modules,
            // either by "name" (the user-friendly display name) or by identifier
            CkanModule moduleToShow = registry
                                      .Available(ksp.VersionCriteria())
                                      .SingleOrDefault(
                mod => mod.name == options.Modname ||
                mod.identifier == options.Modname
                );

            if (moduleToShow == null)
            {
                // No exact match found. Try to look for a close match for this KSP version.
                user.RaiseMessage("{0} not found or installed.", options.Modname);
                user.RaiseMessage("Looking for close matches in available mods for KSP {0}.", ksp.Version());

                Search search  = new Search(user);
                var    matches = search.PerformSearch(ksp, options.Modname);

                // Display the results of the search.
                if (!matches.Any())
                {
                    // No matches found.
                    user.RaiseMessage("No close matches found.");
                    return(Exit.BADOPT);
                }
                else if (matches.Count() == 1)
                {
                    // If there is only 1 match, display it.
                    user.RaiseMessage("Found 1 close match: {0}", matches[0].name);
                    user.RaiseMessage("");

                    moduleToShow = matches[0];
                }
                else
                {
                    // Display the found close matches.
                    string[] strings_matches = new string[matches.Count];

                    for (int i = 0; i < matches.Count; i++)
                    {
                        strings_matches[i] = matches[i].name;
                    }

                    int selection = user.RaiseSelectionDialog("Close matches", strings_matches);

                    if (selection < 0)
                    {
                        return(Exit.BADOPT);
                    }

                    // Mark the selection as the one to show.
                    moduleToShow = matches[selection];
                }
            }

            return(ShowMod(moduleToShow));
        }
Beispiel #55
0
 public Suggested(CkanModule module)
 {
     if (module == null) throw new ArgumentNullException();
     Parent = module;
 }
Beispiel #56
0
        /// <summary>
        /// Shows information about the mod.
        /// </summary>
        /// <returns>Success status.</returns>
        /// <param name="module">The module to show.</param>
        public int ShowMod(CkanModule module)
        {
            #region Abstract and description
            if (!string.IsNullOrEmpty(module.@abstract))
            {
                user.RaiseMessage("{0}: {1}", module.name, module.@abstract);
            }
            else
            {
                user.RaiseMessage("{0}", module.name);
            }

            if (!string.IsNullOrEmpty(module.description))
            {
                user.RaiseMessage("\r\n{0}\r\n", module.description);
            }
            #endregion

            #region General info (author, version...)
            user.RaiseMessage("\r\nModule info:");
            user.RaiseMessage("- version:\t{0}", module.version);

            if (module.author != null)
            {
                user.RaiseMessage("- authors:\t{0}", string.Join(", ", module.author));
            }
            else
            {
                // Did you know that authors are optional in the spec?
                // You do now. #673.
                user.RaiseMessage("- authors:\tUNKNOWN");
            }

            user.RaiseMessage("- status:\t{0}", module.release_status);
            user.RaiseMessage("- license:\t{0}", string.Join(", ", module.license));
            #endregion

            #region Relationships
            if (module.depends != null && module.depends.Count > 0)
            {
                user.RaiseMessage("\r\nDepends:");
                foreach (RelationshipDescriptor dep in module.depends)
                {
                    user.RaiseMessage("- {0}", RelationshipToPrintableString(dep));
                }
            }

            if (module.recommends != null && module.recommends.Count > 0)
            {
                user.RaiseMessage("\r\nRecommends:");
                foreach (RelationshipDescriptor dep in module.recommends)
                {
                    user.RaiseMessage("- {0}", RelationshipToPrintableString(dep));
                }
            }

            if (module.suggests != null && module.suggests.Count > 0)
            {
                user.RaiseMessage("\r\nSuggests:");
                foreach (RelationshipDescriptor dep in module.suggests)
                {
                    user.RaiseMessage("- {0}", RelationshipToPrintableString(dep));
                }
            }

            if (module.ProvidesList != null && module.ProvidesList.Count > 0)
            {
                user.RaiseMessage("\r\nProvides:");
                foreach (string prov in module.ProvidesList)
                {
                    user.RaiseMessage("- {0}", prov);
                }
            }
            #endregion

            user.RaiseMessage("\r\nResources:");
            if (module.resources != null)
            {
                if (module.resources.bugtracker != null)
                {
                    user.RaiseMessage("- bugtracker: {0}", Uri.EscapeUriString(module.resources.bugtracker.ToString()));
                }
                if (module.resources.homepage != null)
                {
                    user.RaiseMessage("- homepage: {0}", Uri.EscapeUriString(module.resources.homepage.ToString()));
                }
                if (module.resources.spacedock != null)
                {
                    user.RaiseMessage("- spacedock: {0}", Uri.EscapeUriString(module.resources.spacedock.ToString()));
                }
                if (module.resources.repository != null)
                {
                    user.RaiseMessage("- repository: {0}", Uri.EscapeUriString(module.resources.repository.ToString()));
                }
                if (module.resources.curse != null)
                {
                    user.RaiseMessage("- curse: {0}", Uri.EscapeUriString(module.resources.curse.ToString()));
                }
            }

            // Compute the CKAN filename.
            string file_uri_hash = NetFileCache.CreateURLHash(module.download);
            string file_name     = CkanModule.StandardName(module.identifier, module.version);

            user.RaiseMessage("\r\nFilename: {0}", file_uri_hash + "-" + file_name);

            return(Exit.OK);
        }
Beispiel #57
0
        private int addVersionDisplay()
        {
            int boxLeft        = Console.WindowWidth / 2 + 1,
                boxTop         = 3;
            const int boxRight = -1,
                      boxH     = 5;

            if (ChangePlan.IsAnyAvailable(registry, mod.identifier))
            {
                List <CkanModule> avail  = registry.AllAvailable(mod.identifier);
                CkanModule        inst   = registry.GetInstalledVersion(mod.identifier);
                CkanModule        latest = registry.LatestAvailable(mod.identifier, null);
                bool installed           = registry.IsInstalled(mod.identifier, false);
                bool latestIsInstalled   = inst?.Equals(latest) ?? false;
                List <CkanModule> others = avail;

                others.Remove(inst);
                others.Remove(latest);

                if (installed)
                {
                    DateTime instTime = InstalledOn(mod.identifier);

                    if (latestIsInstalled)
                    {
                        addVersionBox(
                            boxLeft, boxTop, boxRight, boxTop + boxH - 1,
                            () => $"Latest/Installed {instTime.ToString("d")}",
                            () => ConsoleTheme.Current.ActiveFrameFg,
                            true,
                            new List <CkanModule>()
                        {
                            inst
                        }
                            );
                        boxTop += boxH;
                    }
                    else
                    {
                        addVersionBox(
                            boxLeft, boxTop, boxRight, boxTop + boxH - 1,
                            () => "Latest Version",
                            () => ConsoleTheme.Current.AlertFrameFg,
                            false,
                            new List <CkanModule>()
                        {
                            latest
                        }
                            );
                        boxTop += boxH;

                        addVersionBox(
                            boxLeft, boxTop, boxRight, boxTop + boxH - 1,
                            () => $"Installed {instTime.ToString("d")}",
                            () => ConsoleTheme.Current.ActiveFrameFg,
                            true,
                            new List <CkanModule>()
                        {
                            inst
                        }
                            );
                        boxTop += boxH;
                    }
                }
                else
                {
                    addVersionBox(
                        boxLeft, boxTop, boxRight, boxTop + boxH - 1,
                        () => "Latest Version",
                        () => ConsoleTheme.Current.NormalFrameFg,
                        false,
                        new List <CkanModule>()
                    {
                        latest
                    }
                        );
                    boxTop += boxH;
                }

                if (others.Count > 0)
                {
                    addVersionBox(
                        boxLeft, boxTop, boxRight, boxTop + boxH - 1,
                        () => "Other Versions",
                        () => ConsoleTheme.Current.NormalFrameFg,
                        false,
                        others
                        );
                    boxTop += boxH;
                }
            }
            else
            {
                DateTime instTime = InstalledOn(mod.identifier);
                // Mod is no longer indexed, but we can generate a display
                // of the old info about it from when we installed it
                addVersionBox(
                    boxLeft, boxTop, boxRight, boxTop + boxH - 1,
                    () => $"UNAVAILABLE/Installed {instTime.ToString("d")}",
                    () => ConsoleTheme.Current.AlertFrameFg,
                    true,
                    new List <CkanModule>()
                {
                    mod
                }
                    );
                boxTop += boxH;
            }

            return(boxTop - 1);
        }
Beispiel #58
0
        public void StandardName()
        {
            CkanModule module = CkanModule.FromJson(TestData.kOS_014());

            Assert.AreEqual(module.StandardName(), "kOS-0.14.zip");
        }
Beispiel #59
0
 public void UpdateModContentsTree(CkanModule module, bool force = false)
 {
     ModInfoTabControl.UpdateModContentsTree(module, force);
 }
Beispiel #60
0
 private void OnModInstalled(CkanModule mod)
 {
     RaiseMessage($"{Symbols.checkmark} Successfully installed {mod.name} {ModuleInstaller.StripEpoch(mod.version)}");
 }