예제 #1
0
        /// <summary>
        ///     Register the supplied module as having been installed, thereby keeping
        ///     track of its metadata and files.
        /// </summary>
        public void RegisterModule(Module mod, IEnumerable <string> absolute_files, KSP ksp)
        {
            SealionTransaction();

            // But we also want to keep track of all its files.
            // We start by checking to see if any files are owned by another mod,
            // if so, we abort with a list of errors.

            var inconsistencies = new List <string>();

            // We always work with relative files, so let's get some!
            IEnumerable <string> relative_files = absolute_files.Select(x => ksp.ToRelativeGameDir(x));

            foreach (string file in relative_files)
            {
                // For now, it's always cool if a module wants to register a directory.
                // We have to flip back to absolute paths to actually test this.
                if (Directory.Exists(ksp.ToAbsoluteGameDir(file)))
                {
                    continue;
                }

                if (this.installed_files.ContainsKey(file))
                {
                    // Woah! Registering an already owned file? Not cool!
                    // (Although if it existed, we should have thrown a kraken well before this.)
                    string owner = this.installed_files[file];
                    inconsistencies.Add(
                        string.Format("{0} wishes to install {1}, but this file is registered to {2}",
                                      mod.identifier, file, owner
                                      ));
                }
            }

            if (inconsistencies.Count > 0)
            {
                throw new InconsistentKraken(inconsistencies);
            }

            // If everything is fine, then we copy our files across. By not doing this
            // in the loop above, we make sure we don't have a half-registered module
            // when we throw our exceptinon.

            // This *will* result in us overwriting who owns a directory, and that's cool,
            // directories aren't really owned like files are. However because each mod maintains
            // its own list of files, we'll remove directories when the last mod using them
            // is uninstalled.
            foreach (string file in relative_files)
            {
                this.installed_files[file] = mod.identifier;
            }

            // Finally, register our module proper.
            var installed = new InstalledModule(ksp, mod, relative_files);

            installed_modules.Add(mod.identifier, installed);
        }
예제 #2
0
        /// <summary>
        /// Initiate the GUI installer flow for one specific module
        /// </summary>
        /// <param name="registry">Reference to the registry</param>
        /// <param name="module">Module to install</param>
        public async void InstallModuleDriver(IRegistryQuerier registry, CkanModule module)
        {
            RelationshipResolverOptions install_ops = RelationshipResolver.DefaultOpts();

            install_ops.with_recommends = false;

            try
            {
                var initialChangeSet = new HashSet <ModChange>();
                // Install the selected mod
                initialChangeSet.Add(new ModChange(
                                         new GUIMod(module, registry, CurrentInstance.VersionCriteria()),
                                         GUIModChangeType.Install,
                                         null
                                         ));
                InstalledModule installed = registry.InstalledModule(module.identifier);
                if (installed != null)
                {
                    // Already installed, remove it first
                    initialChangeSet.Add(new ModChange(
                                             new GUIMod(installed.Module, registry, CurrentInstance.VersionCriteria()),
                                             GUIModChangeType.Remove,
                                             null
                                             ));
                }
                List <ModChange> fullChangeSet = new List <ModChange>(
                    await mainModList.ComputeChangeSetFromModList(
                        registry,
                        initialChangeSet,
                        ModuleInstaller.GetInstance(CurrentInstance, Manager.Cache, GUI.user),
                        CurrentInstance.VersionCriteria()
                        )
                    );
                if (fullChangeSet != null && fullChangeSet.Count > 0)
                {
                    // Resolve the provides relationships in the dependencies
                    installWorker.RunWorkerAsync(
                        new KeyValuePair <List <ModChange>, RelationshipResolverOptions>(
                            fullChangeSet,
                            install_ops
                            )
                        );
                }
            }
            catch
            {
                // If we failed, do the clean-up normally done by PostInstallMods.
                HideWaitDialog(false);
                menuStrip1.Enabled = true;
            }
            finally
            {
                changeSet = null;
            }
        }
예제 #3
0
        /// <summary>
        /// Upgrades or installs the mods listed to the specified versions for the user's KSP.
        /// Will *re-install* or *downgrade* (with a warning) as well as upgrade.
        /// Throws ModuleNotFoundKraken if a module is not installed.
        /// </summary>
        public void Upgrade(IEnumerable <CkanModule> modules, IDownloader netAsyncDownloader, bool enforceConsistency = true)
        {
            // Start by making sure we've downloaded everything.
            DownloadModules(modules, netAsyncDownloader);

            // Our upgrade involves removing everything that's currently installed, then
            // adding everything that needs installing (which may involve new mods to
            // satisfy dependencies). We always know the list passed in is what we need to
            // install, but we need to calculate what needs to be removed.
            var to_remove = new List <string>();

            // Let's discover what we need to do with each module!
            foreach (CkanModule module in modules)
            {
                string          ident         = module.identifier;
                InstalledModule installed_mod = registry_manager.registry.InstalledModule(ident);

                if (installed_mod == null)
                {
                    //Maybe ModuleNotInstalled ?
                    if (registry_manager.registry.IsAutodetected(ident))
                    {
                        throw new ModuleNotFoundKraken(ident, module.version.ToString(), String.Format("Can't upgrade {0} as it was not installed by CKAN. \r\n Please remove manually before trying to install it.", ident));
                    }

                    User.RaiseMessage("Installing previously uninstalled mod {0}", ident);
                }
                else
                {
                    // Module already installed. We'll need to remove it first.
                    to_remove.Add(module.identifier);

                    CkanModule installed = installed_mod.Module;
                    if (installed.version.IsEqualTo(module.version))
                    {
                        log.InfoFormat("{0} is already at the latest version, reinstalling", installed.identifier);
                    }
                    else if (installed.version.IsGreaterThan(module.version))
                    {
                        log.WarnFormat("Downgrading {0} from {1} to {2}", ident, installed.version, module.version);
                    }
                    else
                    {
                        log.InfoFormat("Upgrading {0} to {1}", ident, module.version);
                    }
                }
            }

            AddRemove(
                modules,
                to_remove,
                enforceConsistency
                );
        }
예제 #4
0
파일: GUIMod.cs 프로젝트: yadenisyur/CKAN
 /// <summary>
 /// Initialize a GUIMod based on an InstalledModule
 /// </summary>
 /// <param name="instMod">The installed module to represent</param>
 /// <param name="registry">CKAN registry object for current game instance</param>
 /// <param name="current_ksp_version">Current game version</param>
 /// <param name="incompatible">If true, mark this module as incompatible</param>
 public GUIMod(InstalledModule instMod, IRegistryQuerier registry, KspVersionCriteria current_ksp_version, bool incompatible = false)
     : this(instMod.Module, registry, current_ksp_version, incompatible)
 {
     IsInstalled      = true;
     IsInstallChecked = true;
     InstallDate      = instMod.InstallTime;
     InstalledVersion = instMod.Module.version.ToString();
     if (LatestVersion == null || LatestVersion.Equals("-"))
     {
         LatestVersion = InstalledVersion;
     }
 }
예제 #5
0
        /// <summary>
        /// Uninstalls all the mods provided, including things which depend upon them.
        /// This *DOES* save the registry.
        /// Preferred over Uninstall.
        /// </summary>
        public void UninstallList(IEnumerable <string> mods)
        {
            // Pre-check, have they even asked for things which are installed?

            foreach (string mod in mods.Where(mod => registry_manager.registry.InstalledModule(mod) == null))
            {
                throw new ModNotInstalledKraken(mod);
            }

            // Find all the things which need uninstalling.
            IEnumerable <string> goners = registry_manager.registry.FindReverseDependencies(mods);

            // If there us nothing to uninstall, skip out.
            if (!goners.Any())
            {
                return;
            }

            User.RaiseMessage("About to remove:\n");

            foreach (string mod in goners)
            {
                InstalledModule module = registry_manager.registry.InstalledModule(mod);
                User.RaiseMessage(" * {0} {1}", module.Module.identifier, module.Module.modVersion);
            }

            bool ok = User.RaiseYesNoDialog("\nContinue?");

            if (!ok)
            {
                User.RaiseMessage("Mod removal aborted at user request.");
                return;
            }

            using (var transaction = CkanTransaction.CreateTransactionScope())
            {
                foreach (string mod in goners)
                {
                    User.RaiseMessage("Removing {0}...", mod);
                    Uninstall(mod);
                }

                registry_manager.Save();
                ksp.RebuildFactorioModlist();

                transaction.Complete();
            }

            User.RaiseMessage("Done!\n");
        }
예제 #6
0
파일: GUIMod.cs 프로젝트: zxasqwsss/CKAN
 /// <summary>
 /// Initialize a GUIMod based on an InstalledModule
 /// </summary>
 /// <param name="instMod">The installed module to represent</param>
 /// <param name="registry">CKAN registry object for current game instance</param>
 /// <param name="current_game_version">Current game version</param>
 /// <param name="incompatible">If true, mark this module as incompatible</param>
 public GUIMod(InstalledModule instMod, IRegistryQuerier registry, GameVersionCriteria current_game_version, bool?incompatible = null)
     : this(instMod.Module, registry, current_game_version, incompatible)
 {
     IsInstalled      = true;
     IsInstallChecked = true;
     InstalledMod     = instMod;
     selectedMod      = instMod.Module;
     IsAutoInstalled  = instMod.AutoInstalled;
     InstallDate      = instMod.InstallTime;
     InstalledVersion = instMod.Module.version.ToString();
     if (LatestVersion == null || LatestVersion.Equals("-"))
     {
         LatestVersion = InstalledVersion;
     }
 }
예제 #7
0
 /// <summary>
 /// Initialize a GUIMod based on an InstalledModule
 /// </summary>
 /// <param name="instMod">The installed module to represent</param>
 /// <param name="registry">CKAN registry object for current game instance</param>
 /// <param name="current_game_version">Current game version</param>
 /// <param name="incompatible">If true, mark this module as incompatible</param>
 public GUIMod(InstalledModule instMod, IRegistryQuerier registry, GameVersionCriteria current_game_version, bool?incompatible = null)
     : this(instMod.Module, registry, current_game_version, incompatible)
 {
     IsInstalled      = true;
     IsInstallChecked = true;
     InstalledMod     = instMod;
     selectedMod      = instMod.Module;
     IsAutoInstalled  = instMod.AutoInstalled;
     InstallDate      = instMod.InstallTime;
     InstalledVersion = instMod.Module.version.ToString();
     if (LatestVersion == null || LatestVersion.Equals("-"))
     {
         LatestVersion = InstalledVersion;
     }
     // For mods not known to the registry LatestCompatibleMod is null, however the installed module might be compatible
     IsIncompatible = incompatible ?? LatestCompatibleMod == null && !instMod.Module.IsCompatibleKSP(current_game_version);
 }
예제 #8
0
 /// <summary>
 /// Initiate the GUI installer flow for one specific module
 /// </summary>
 /// <param name="registry">Reference to the registry</param>
 /// <param name="module">Module to install</param>
 public async void InstallModuleDriver(IRegistryQuerier registry, CkanModule module)
 {
     try
     {
         var             userChangeSet = new List <ModChange>();
         InstalledModule installed     = registry.InstalledModule(module.identifier);
         if (installed != null)
         {
             // Already installed, remove it first
             userChangeSet.Add(new ModChange(
                                   new GUIMod(installed.Module, registry, CurrentInstance.VersionCriteria()),
                                   GUIModChangeType.Remove,
                                   null
                                   ));
         }
         // Install the selected mod
         userChangeSet.Add(new ModChange(
                               new GUIMod(module, registry, CurrentInstance.VersionCriteria()),
                               GUIModChangeType.Install,
                               null
                               ));
         if (userChangeSet.Count > 0)
         {
             // Resolve the provides relationships in the dependencies
             installWorker.RunWorkerAsync(
                 new KeyValuePair <List <ModChange>, RelationshipResolverOptions>(
                     userChangeSet,
                     RelationshipResolver.DependsOnlyOpts()
                     )
                 );
         }
     }
     catch
     {
         // If we failed, do the clean-up normally done by PostInstallMods.
         HideWaitDialog(false);
         menuStrip1.Enabled = true;
     }
     finally
     {
         changeSet = null;
     }
 }
예제 #9
0
        /// <summary>
        /// Upgrades the mods listed to the specified versions for the user's KSP.
        /// Will *re-install* or *downgrade* (with a warning) as well as upgrade.
        /// Throws ModuleNotFoundKraken if a module is not installed.
        /// </summary>
        public void Upgrade(IEnumerable <CkanModule> modules, NetAsyncDownloader netAsyncDownloader)
        {
            // Start by making sure we've downloaded everything.
            DownloadModules(modules, netAsyncDownloader);

            foreach (CkanModule module in modules)
            {
                string          ident         = module.identifier;
                InstalledModule installed_mod = registry_manager.registry.InstalledModule(ident);

                if (installed_mod == null)
                {
                    //Maybe ModuleNotInstalled ?
                    if (registry_manager.registry.IsAutodetected(ident))
                    {
                        throw new ModuleNotFoundKraken(ident, module.version.ToString(), String.Format("Can't upgrade {0} as it was not installed by CKAN. \n Please remove manually before trying to install it.", ident));
                    }
                    throw new ModuleNotFoundKraken(
                              ident, module.version.ToString(),
                              String.Format("Can't upgrade {0}, it is not installed", ident)
                              );
                }
                Module installed = installed_mod.Module;
                if (installed.version.IsEqualTo(module.version))
                {
                    log.WarnFormat("{0} is already at the latest version, reinstalling", installed.identifier);
                }
                else if (installed.version.IsGreaterThan(module.version))
                {
                    log.WarnFormat("Downgrading {0} from {1} to {2}", ident, installed.version, module.version);
                }
                else
                {
                    log.InfoFormat("Upgrading {0} to {1}", ident, module.version);
                }
            }

            AddRemove(
                modules,
                modules.Select(x => x.identifier)
                );
        }
예제 #10
0
        static int Show(ShowOptions options)
        {
            RegistryManager registry_manager = RegistryManager.Instance();
            InstalledModule module           = registry_manager.registry.installed_modules [options.Modname];

            if (module != null)
            {
                // TODO: Print *lots* of information out; I should never have to dig through JSON

                Console.WriteLine("{0} version {1}", module.source_module.name, module.source_module.version);

                Console.WriteLine("\n== Files ==\n");

                Dictionary <string, InstalledModuleFile> files = module.installed_files;

                foreach (string file in files.Keys)
                {
                    Console.WriteLine(file);
                }
            }
            return(EXIT_OK);
        }
예제 #11
0
        private void DeSerialisationFixes(StreamingContext context)
        {
            // Our context is our KSP install.
            KSP ksp = (KSP)context.Context;


            // Older registries didn't have the installed_files list, so we create one
            // if absent.

            if (installed_files == null)
            {
                log.Warn("Older registry format detected, adding installed files manifest...");
                ReindexInstalled();
            }

            // If we have no registry version at all, then we're from the pre-release period.
            // We would check for a null here, but ints *can't* be null.
            if (registry_version == 0)
            {
                log.Warn("Older registry format detected, normalising paths...");

                var normalised_installed_files = new Dictionary <string, string>();

                foreach (KeyValuePair <string, string> tuple in installed_files)
                {
                    string path = KSPPathUtils.NormalizePath(tuple.Key);

                    if (Path.IsPathRooted(path))
                    {
                        path = ksp.ToRelativeGameDir(path);
                        normalised_installed_files[path] = tuple.Value;
                    }
                    else
                    {
                        // Already relative.
                        normalised_installed_files[path] = tuple.Value;
                    }
                }

                installed_files = normalised_installed_files;

                // Now update all our module file manifests.

                foreach (InstalledModule module in installed_modules.Values)
                {
                    module.Renormalise(ksp);
                }

                // Our installed dlls have contained relative paths since forever,
                // and the next `ckan scan` will fix them anyway. (We can't scan here,
                // because that needs a registry, and we chicken-egg.)

                log.Warn("Registry upgrade complete");
            }

            // Fix control lock, which previously was indexed with an invalid identifier.
            if (registry_version < 2)
            {
                InstalledModule control_lock_entry;
                const string    old_ident = "001ControlLock";
                const string    new_ident = "ControlLock";

                if (installed_modules.TryGetValue("001ControlLock", out control_lock_entry))
                {
                    if (ksp == null)
                    {
                        throw new Kraken("Internal bug: No KSP instance provided on registry deserialisation");
                    }

                    log.WarnFormat("Older registry detected. Reindexing {0} as {1}. This may take a moment.", old_ident, new_ident);

                    // Remove old record.
                    installed_modules.Remove(old_ident);

                    // Extract the old module metadata
                    CkanModule control_lock_mod = control_lock_entry.Module;

                    // Change to the correct ident.
                    control_lock_mod.identifier = new_ident;

                    // Prepare to re-index.
                    var new_control_lock_installed = new InstalledModule(
                        ksp,
                        control_lock_mod,
                        control_lock_entry.Files
                        );

                    // Re-insert into registry.
                    installed_modules[new_control_lock_installed.identifier] = new_control_lock_installed;

                    // Re-index files.
                    ReindexInstalled();
                }
            }

            // If we spot a default repo with the old .zip URL, flip it to the new .tar.gz URL
            // Any other repo we leave *as-is*, even if it's the github meta-repo, as it's been
            // custom-added by our user.

            Repository default_repo;
            var        oldDefaultRepo = new Uri("https://github.com/KSP-CKAN/CKAN-meta/archive/master.zip");

            if (repositories != null && repositories.TryGetValue(Repository.default_ckan_repo_name, out default_repo) && default_repo.uri == oldDefaultRepo)
            {
                log.InfoFormat("Updating default metadata URL from {0} to {1}", oldDefaultRepo, Repository.default_ckan_repo_uri);
                repositories["default"].uri = Repository.default_ckan_repo_uri;
            }

            registry_version = LATEST_REGISTRY_VERSION;
        }
예제 #12
0
        /// <summary>
        /// Uninstall the module provided. For internal use only.
        /// Use UninstallList for user queries, it also does dependency handling.
        /// This does *NOT* save the registry.
        /// </summary>

        private void Uninstall(string modName)
        {
            using (var transaction = new TransactionScope())
            {
                InstalledModule mod = registry_manager.registry.InstalledModule(modName);

                if (mod == null)
                {
                    log.ErrorFormat("Trying to uninstall {0} but it's not installed", modName);
                    throw new ModNotInstalledKraken(modName);
                }

                // Walk our registry to find all files for this mod.
                IEnumerable <string> files = mod.Files;

                var directoriesToDelete = new HashSet <string>();

                foreach (string file in files)
                {
                    string path = ksp.ToAbsoluteGameDir(file);

                    try
                    {
                        FileAttributes attr = File.GetAttributes(path);

                        if ((attr & FileAttributes.Directory) == FileAttributes.Directory)
                        {
                            directoriesToDelete.Add(path);
                        }
                        else
                        {
                            log.InfoFormat("Removing {0}", file);
                            file_transaction.Delete(path);
                        }
                    }
                    catch (Exception ex)
                    {
                        // XXX: This is terrible, we're catching all exceptions.
                        log.ErrorFormat("Failure in locating file {0} : {1}", path, ex.Message);
                    }
                }

                // Remove from registry.

                registry_manager.registry.DeregisterModule(ksp, modName);

                // Sort our directories from longest to shortest, to make sure we remove child directories
                // before parents. GH #78.
                foreach (string directory in directoriesToDelete.OrderBy(dir => dir.Length).Reverse())
                {
                    if (!Directory.EnumerateFileSystemEntries(directory).Any())
                    {
                        // We *don't* use our file_transaction to delete files here, because
                        // it fails if the system's temp directory is on a different device
                        // to KSP. However we *can* safely delete it now we know it's empty,
                        // because the TxFileMgr *will* put it back if there's a file inside that
                        // needs it.
                        //
                        // This works around GH #251.
                        // The filesystem boundry bug is described in https://transactionalfilemgr.codeplex.com/workitem/20

                        log.InfoFormat("Removing {0}", directory);
                        Directory.Delete(directory);
                    }
                    else
                    {
                        User.WriteLine("Not removing directory {0}, it's not empty", directory);
                    }
                }
                transaction.Complete();
            }

            return;
        }
예제 #13
0
        private void DeSerialisationFixes(StreamingContext context)
        {
            // Our context is our KSP install.
            KSP ksp = (KSP) context.Context;

            // Older registries didn't have the installed_files list, so we create one
            // if absent.

            if (installed_files == null)
            {
                log.Warn("Older registry format detected, adding installed files manifest...");
                ReindexInstalled();
            }

            // If we have no registry version at all, then we're from the pre-release period.
            // We would check for a null here, but ints *can't* be null.
            if (registry_version == 0)
            {
                log.Warn("Older registry format detected, normalising paths...");

                var normalised_installed_files = new Dictionary<string,string>();

                foreach (KeyValuePair<string,string> tuple in installed_files)
                {
                    string path = KSPPathUtils.NormalizePath(tuple.Key);

                    if (Path.IsPathRooted(path))
                    {
                        path = ksp.ToRelativeGameDir(path);
                        normalised_installed_files[path] = tuple.Value;
                    }
                    else
                    {
                        // Already relative.
                        normalised_installed_files[path] = tuple.Value;
                    }
                }

                installed_files = normalised_installed_files;

                // Now update all our module file manifests.

                foreach (InstalledModule module in installed_modules.Values)
                {
                    module.Renormalise(ksp);
                }

                // Our installed dlls have contained relative paths since forever,
                // and the next `ckan scan` will fix them anyway. (We can't scan here,
                // because that needs a registry, and we chicken-egg.)

                log.Warn("Registry upgrade complete");
            }

            // Fix control lock, which previously was indexed with an invalid identifier.
            if (registry_version < 2)
            {
                InstalledModule control_lock_entry;
                const string old_ident = "001ControlLock";
                const string new_ident = "ControlLock";

                if (installed_modules.TryGetValue("001ControlLock", out control_lock_entry))
                {
                    if (ksp == null)
                    {
                        throw new Kraken("Internal bug: No KSP instance provided on registry deserialisation");
                    }

                    log.WarnFormat("Older registry detected. Reindexing {0} as {1}. This may take a moment.", old_ident, new_ident);

                    // Remove old record.
                    installed_modules.Remove(old_ident);

                    // Extract the old module metadata
                    Module control_lock_mod = control_lock_entry.Module;

                    // Change to the correct ident.
                    control_lock_mod.identifier = new_ident;

                    // Prepare to re-index.
                    var new_control_lock_installed = new InstalledModule(
                        ksp,
                        control_lock_mod,
                        control_lock_entry.Files
                    );

                    // Re-insert into registry.
                    installed_modules[new_control_lock_installed.identifier] = new_control_lock_installed;

                    // Re-index files.
                    ReindexInstalled();
                }
            }

            registry_version = LATEST_REGISTRY_VERSION;
        }
예제 #14
0
        /// <summary>
        ///     Register the supplied module as having been installed, thereby keeping
        ///     track of its metadata and files.
        /// </summary>
        public void RegisterModule(Module mod, IEnumerable<string> absolute_files, KSP ksp)
        {
            SealionTransaction();

            // But we also want to keep track of all its files.
            // We start by checking to see if any files are owned by another mod,
            // if so, we abort with a list of errors.

            var inconsistencies = new List<string>();

            // We always work with relative files, so let's get some!
            IEnumerable<string> relative_files = absolute_files.Select(x => ksp.ToRelativeGameDir(x));

            // For now, it's always cool if a module wants to register a directory.
            // We have to flip back to absolute paths to actually test this.
            foreach (string file in relative_files.Where(file => !Directory.Exists(ksp.ToAbsoluteGameDir(file))))
            {
                string owner;
                if (installed_files.TryGetValue(file, out owner))
                {
                    // Woah! Registering an already owned file? Not cool!
                    // (Although if it existed, we should have thrown a kraken well before this.)
                    inconsistencies.Add(
                        string.Format("{0} wishes to install {1}, but this file is registered to {2}",
                            mod.identifier, file, owner
                            ));
                }
            }

            if (inconsistencies.Count > 0)
            {
                throw new InconsistentKraken(inconsistencies);
            }

            // If everything is fine, then we copy our files across. By not doing this
            // in the loop above, we make sure we don't have a half-registered module
            // when we throw our exceptinon.

            // This *will* result in us overwriting who owns a directory, and that's cool,
            // directories aren't really owned like files are. However because each mod maintains
            // its own list of files, we'll remove directories when the last mod using them
            // is uninstalled.
            foreach (string file in relative_files)
            {
                installed_files[file] = mod.identifier;
            }

            // Finally, register our module proper.
            var installed = new InstalledModule(ksp, mod, relative_files);
            installed_modules.Add(mod.identifier, installed);
        }
예제 #15
0
        /// <summary>
        /// Uninstall the module provided. For internal use only.
        /// Use UninstallList for user queries, it also does dependency handling.
        /// This does *NOT* save the registry.
        /// </summary>

        private void Uninstall(string modName)
        {
            using (var transaction = CkanTransaction.CreateTransactionScope())
            {
                InstalledModule mod = registry_manager.registry.InstalledModule(modName);

                if (mod == null)
                {
                    log.ErrorFormat("Trying to uninstall {0} but it's not installed", modName);
                    throw new ModNotInstalledKraken(modName);
                }

                // Walk our registry to find all files for this mod.
                IEnumerable <string> files = mod.Files;

                var directoriesToDelete = new HashSet <string>();

                foreach (string file in files)
                {
                    string path = ksp.ToAbsoluteGameDir(file);

                    try
                    {
                        FileAttributes attr = File.GetAttributes(path);

                        // [This is] bitwise math. Basically, attr is some binary value with one bit meaning
                        // "this is a directory". The bitwise and & operator will return a binary value where
                        // only the bits that are on (1) in both the operands are turned on. In this case
                        // doing a bitwise and operation against attr and the FileAttributes.Directory value
                        // will return the value of FileAttributes.Directory if the Directory file attribute
                        // bit is turned on. See en.wikipedia.org/wiki/Bitwise_operation for a better
                        // explanation. – Kyle Trauberman Aug 30 '12 at 21:28
                        // (https://stackoverflow.com/questions/1395205/better-way-to-check-if-path-is-a-file-or-a-directory)
                        // This is the fastest way to do this test.
                        if ((attr & FileAttributes.Directory) == FileAttributes.Directory)
                        {
                            if (!directoriesToDelete.Contains(path))
                            {
                                directoriesToDelete.Add(path);
                            }
                        }
                        else
                        {
                            // Add this files' directory to the list for deletion if it isn't already there.
                            // Helps clean up directories when modules are uninstalled out of dependency order
                            // Since we check for directory contents when deleting, this should purge empty
                            // dirs, making less ModuleManager headaches for people.
                            var directoryName = Path.GetDirectoryName(path);
                            if (!(directoriesToDelete.Contains(directoryName)))
                            {
                                directoriesToDelete.Add(directoryName);
                            }

                            log.DebugFormat("Removing {0}", file);
                            file_transaction.Delete(path);
                        }
                    }
                    catch (Exception ex)
                    {
                        // XXX: This is terrible, we're catching all exceptions.
                        // We don't consider this problem serious enough to abort and revert,
                        // so treat it as a "--verbose" level log message.
                        log.InfoFormat("Failure in locating file {0} : {1}", path, ex.Message);
                    }
                }

                // Remove from registry.
                registry_manager.registry.DeregisterModule(ksp, modName);

                // Our collection of directories may leave empty parent directories.
                directoriesToDelete = AddParentDirectories(directoriesToDelete);

                // Sort our directories from longest to shortest, to make sure we remove child directories
                // before parents. GH #78.
                foreach (string directory in directoriesToDelete.OrderBy(dir => dir.Length).Reverse())
                {
                    if (!Directory.EnumerateFileSystemEntries(directory).Any())
                    {
                        // It is bad if any of this directories gets removed
                        // So we protect them
                        if (IsReservedDirectory(directory))
                        {
                            continue;
                        }

                        // We *don't* use our file_transaction to delete files here, because
                        // it fails if the system's temp directory is on a different device
                        // to KSP. However we *can* safely delete it now we know it's empty,
                        // because the TxFileMgr *will* put it back if there's a file inside that
                        // needs it.
                        //
                        // This works around GH #251.
                        // The filesystem boundry bug is described in https://transactionalfilemgr.codeplex.com/workitem/20

                        log.DebugFormat("Removing {0}", directory);
                        Directory.Delete(directory);
                    }
                    else
                    {
                        log.InfoFormat("Not removing directory {0}, it's not empty", directory);
                    }
                }
                log.InfoFormat("Removed {0}", modName);
                transaction.Complete();
            }
        }
예제 #16
0
        /// <summary>
        /// Register the supplied module as having been installed, thereby keeping
        /// track of its metadata and files.
        /// </summary>
        /// <param name="mod">Mod.</param>

        public void RegisterModule (InstalledModule mod) {
            installed_modules.Add (mod.source_module.identifier, mod);
        }