Skip to content

Commit

Permalink
Prompt user to delete non-empty folders after uninstall
Browse files Browse the repository at this point in the history
  • Loading branch information
HebaruSan committed Jan 15, 2020
1 parent ed86a72 commit 0838ee7
Show file tree
Hide file tree
Showing 20 changed files with 862 additions and 143 deletions.
3 changes: 2 additions & 1 deletion Cmdline/Action/Remove.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,10 @@ public int RunCommand(CKAN.KSP ksp, object raw_options)
{
try
{
HashSet<string> possibleConfigOnlyDirs = null;
var installer = ModuleInstaller.GetInstance(ksp, manager.Cache, user);
Search.AdjustModulesCase(ksp, options.modules);
installer.UninstallList(options.modules);
installer.UninstallList(options.modules, ref possibleConfigOnlyDirs);
}
catch (ModNotInstalledKraken kraken)
{
Expand Down
3 changes: 2 additions & 1 deletion Cmdline/Action/Replace.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,8 @@ public int RunCommand(CKAN.KSP ksp, object raw_options)
// TODO: These instances all need to go.
try
{
ModuleInstaller.GetInstance(ksp, manager.Cache, User).Replace(to_replace, replace_ops, new NetAsyncModulesDownloader(User, manager.Cache));
HashSet<string> possibleConfigOnlyDirs = null;
ModuleInstaller.GetInstance(ksp, manager.Cache, User).Replace(to_replace, replace_ops, new NetAsyncModulesDownloader(User, manager.Cache), ref possibleConfigOnlyDirs);
User.RaiseMessage("\r\nDone!\r\n");
}
catch (DependencyNotSatisfiedKraken ex)
Expand Down
5 changes: 3 additions & 2 deletions Cmdline/Action/Upgrade.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ public int RunCommand(CKAN.KSP ksp, object raw_options)

try
{
HashSet<string> possibleConfigOnlyDirs = null;
if (options.upgrade_all)
{
var registry = RegistryManager.Instance(ksp).registry;
Expand Down Expand Up @@ -129,13 +130,13 @@ public int RunCommand(CKAN.KSP ksp, object raw_options)

}

ModuleInstaller.GetInstance(ksp, manager.Cache, User).Upgrade(to_upgrade, new NetAsyncModulesDownloader(User, manager.Cache));
ModuleInstaller.GetInstance(ksp, manager.Cache, User).Upgrade(to_upgrade, new NetAsyncModulesDownloader(User, manager.Cache), ref possibleConfigOnlyDirs);
}
else
{
// TODO: These instances all need to go.
Search.AdjustModulesCase(ksp, options.modules);
ModuleInstaller.GetInstance(ksp, manager.Cache, User).Upgrade(options.modules, new NetAsyncModulesDownloader(User, manager.Cache));
ModuleInstaller.GetInstance(ksp, manager.Cache, User).Upgrade(options.modules, new NetAsyncModulesDownloader(User, manager.Cache), ref possibleConfigOnlyDirs);
}
}
catch (ModuleNotFoundKraken kraken)
Expand Down
8 changes: 5 additions & 3 deletions ConsoleUI/InstallScreen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,18 @@ public override void Run(Action process = null)
}

// FUTURE: BackgroundWorker

HashSet<string> possibleConfigOnlyDirs = null;

ModuleInstaller inst = ModuleInstaller.GetInstance(manager.CurrentInstance, manager.Cache, this);
inst.onReportModInstalled = OnModInstalled;
if (plan.Remove.Count > 0) {
inst.UninstallList(plan.Remove);
inst.UninstallList(plan.Remove, ref possibleConfigOnlyDirs);
plan.Remove.Clear();
}
NetAsyncModulesDownloader dl = new NetAsyncModulesDownloader(this, manager.Cache);
if (plan.Upgrade.Count > 0) {
inst.Upgrade(plan.Upgrade, dl);
inst.Upgrade(plan.Upgrade, dl, ref possibleConfigOnlyDirs);
plan.Upgrade.Clear();
}
if (plan.Install.Count > 0) {
Expand All @@ -72,7 +74,7 @@ public override void Run(Action process = null)
plan.Install.Clear();
}
if (plan.Replace.Count > 0) {
inst.Replace(AllReplacements(plan.Replace), resolvOpts, dl, true);
inst.Replace(AllReplacements(plan.Replace), resolvOpts, dl, ref possibleConfigOnlyDirs, true);
}

trans.Complete();
Expand Down
63 changes: 42 additions & 21 deletions Core/ModuleInstaller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -732,7 +732,7 @@ internal static void CopyZipEntry(ZipFile zipfile, ZipEntry entry, string fullPa
/// This *DOES* save the registry.
/// Preferred over Uninstall.
/// </summary>
public void UninstallList(IEnumerable<string> mods, bool ConfirmPrompt = true, IEnumerable<string> installing = null)
public void UninstallList(IEnumerable<string> mods, ref HashSet<string> possibleConfigOnlyDirs, bool ConfirmPrompt = true, IEnumerable<string> installing = null)
{
mods = mods.Memoize();
// Pre-check, have they even asked for things which are installed?
Expand Down Expand Up @@ -788,7 +788,7 @@ public void UninstallList(IEnumerable<string> mods, bool ConfirmPrompt = true, I
foreach (string mod in goners)
{
User.RaiseMessage("Removing {0}...", mod);
Uninstall(mod);
Uninstall(mod, ref possibleConfigOnlyDirs);
}

// Enforce consistency if we're not installing anything,
Expand All @@ -801,19 +801,20 @@ public void UninstallList(IEnumerable<string> mods, bool ConfirmPrompt = true, I
User.RaiseMessage("Done!\r\n");
}

public void UninstallList(string mod)
public void UninstallList(string mod, ref HashSet<string> possibleConfigOnlyDirs)
{
var list = new List<string> { mod };
UninstallList(list);
UninstallList(list, ref possibleConfigOnlyDirs);
}

/// <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)
/// <param name="modName">Identifier of module to uninstall</param>
/// <param name="possibleConfigOnlyDirs">Directories that the user might want to remove after uninstall</param>
private void Uninstall(string modName, ref HashSet<string> possibleConfigOnlyDirs)
{
TxFileManager file_transaction = new TxFileManager();

Expand Down Expand Up @@ -870,8 +871,6 @@ private void Uninstall(string modName)

log.DebugFormat("Removing {0}", file);
file_transaction.Delete(path);


}
}
catch (Exception ex)
Expand All @@ -893,14 +892,25 @@ private void Uninstall(string modName)
// before parents. GH #78.
foreach (string directory in directoriesToDelete.OrderBy(dir => dir.Length).Reverse())
{
if (!Directory.EnumerateFileSystemEntries(directory).Any())
log.DebugFormat("Checking {0}...", directory);
// It is bad if any of this directories gets removed
// So we protect them
// A few string comparisons will be cheaper than hitting the disk, so do this first
if (IsReservedDirectory(directory))
{
log.DebugFormat("Directory {0} is reserved, skipping", directory);
continue;
}

var contents = Directory
.EnumerateFileSystemEntries(directory, "*", SearchOption.AllDirectories)
.Select(f => ksp.ToRelativeGameDir(f))
.Memoize();
log.DebugFormat("Got contents: {0}", string.Join(", ", contents));
var owners = contents.Select(f => registry_manager.registry.FileOwner(f));
log.DebugFormat("Got owners: {0}", string.Join(", ", owners));
if (!contents.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
Expand All @@ -914,6 +924,15 @@ private void Uninstall(string modName)
log.DebugFormat("Removing {0}", directory);
Directory.Delete(directory);
}
else if (contents.All(f => registry_manager.registry.FileOwner(f) == null))
{
log.DebugFormat("Directory {0} contains only non-registered files, ask user about it later");
if (possibleConfigOnlyDirs == null)
{
possibleConfigOnlyDirs = new HashSet<string>();
}
possibleConfigOnlyDirs.Add(directory);
}
else
{
log.InfoFormat("Not removing directory {0}, it's not empty", directory);
Expand Down Expand Up @@ -986,7 +1005,7 @@ public HashSet<string> AddParentDirectories(HashSet<string> directories)
/// </summary>
/// <param name="add">Add.</param>
/// <param name="remove">Remove.</param>
public void AddRemove(IEnumerable<CkanModule> add = null, IEnumerable<InstalledModule> remove = null, bool enforceConsistency = true)
public void AddRemove(ref HashSet<string> possibleConfigOnlyDirs, IEnumerable<CkanModule> add = null, IEnumerable<InstalledModule> remove = null, bool enforceConsistency = true)
{
// TODO: We should do a consistency check up-front, rather than relying
// upon our registry catching inconsistencies at the end.
Expand All @@ -1003,7 +1022,7 @@ public void AddRemove(IEnumerable<CkanModule> add = null, IEnumerable<InstalledM
// The post-install steps start at 80%, so count up to 70% for installation
int percent_complete = (step++ * 70) / totSteps;
User.RaiseProgress($"Removing \"{instMod}\"", percent_complete);
Uninstall(instMod.Module.identifier);
Uninstall(instMod.Module.identifier, ref possibleConfigOnlyDirs);
}

foreach (CkanModule module in add)
Expand All @@ -1029,18 +1048,18 @@ public void AddRemove(IEnumerable<CkanModule> add = null, IEnumerable<InstalledM
/// Will *re-install* with warning even if an upgrade is not available.
/// Throws ModuleNotFoundKraken if module is not installed, or not available.
/// </summary>
public void Upgrade(IEnumerable<string> identifiers, IDownloader netAsyncDownloader, bool enforceConsistency = true)
public void Upgrade(IEnumerable<string> identifiers, IDownloader netAsyncDownloader, ref HashSet<string> possibleConfigOnlyDirs, bool enforceConsistency = true)
{
var resolver = new RelationshipResolver(identifiers.ToList(), null, RelationshipResolver.DependsOnlyOpts(), registry_manager.registry, ksp.VersionCriteria());
Upgrade(resolver.ModList(), netAsyncDownloader, enforceConsistency);
Upgrade(resolver.ModList(), netAsyncDownloader, ref possibleConfigOnlyDirs, enforceConsistency);
}

/// <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)
public void Upgrade(IEnumerable<CkanModule> modules, IDownloader netAsyncDownloader, ref HashSet<string> possibleConfigOnlyDirs, bool enforceConsistency = true)
{
modules = modules.Memoize();
User.RaiseMessage("About to upgrade...\r\n");
Expand Down Expand Up @@ -1092,6 +1111,7 @@ public void Upgrade(IEnumerable<CkanModule> modules, IDownloader netAsyncDownloa
}

AddRemove(
ref possibleConfigOnlyDirs,
modules,
to_remove,
enforceConsistency
Expand All @@ -1104,7 +1124,7 @@ public void Upgrade(IEnumerable<CkanModule> modules, IDownloader netAsyncDownloa
/// Will *re-install* or *downgrade* (with a warning) as well as upgrade.
/// Throws ModuleNotFoundKraken if a module is not installed.
/// </summary>
public void Replace(IEnumerable<ModuleReplacement> replacements, RelationshipResolverOptions options, IDownloader netAsyncDownloader, bool enforceConsistency = true)
public void Replace(IEnumerable<ModuleReplacement> replacements, RelationshipResolverOptions options, IDownloader netAsyncDownloader, ref HashSet<string> possibleConfigOnlyDirs, bool enforceConsistency = true)
{
replacements = replacements.Memoize();
log.Debug("Using Replace method");
Expand Down Expand Up @@ -1181,6 +1201,7 @@ public void Replace(IEnumerable<ModuleReplacement> replacements, RelationshipRes
{
var resolvedModsToInstall = resolver.ModList().ToList();
AddRemove(
ref possibleConfigOnlyDirs,
resolvedModsToInstall,
modsToRemove,
enforceConsistency
Expand Down
2 changes: 2 additions & 0 deletions Core/Net/Repo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,9 +209,11 @@ private static void HandleModuleChanges(List<CkanModule> metadataChanges, IUser
{
try
{
HashSet<string> possibleConfigOnlyDirs = null;
installer.Upgrade(
new[] { changedIdentifier },
new NetAsyncModulesDownloader(new NullUser(), cache),
ref possibleConfigOnlyDirs,
enforceConsistency: false
);
}
Expand Down
15 changes: 15 additions & 0 deletions GUI/CKAN-GUI.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@
</Compile>
<Compile Include="GUIConfiguration.cs" />
<Compile Include="ControlFactory.cs" />
<Compile Include="DeleteDirectories.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="DeleteDirectories.Designer.cs">
<DependentUpon>DeleteDirectories.cs</DependentUpon>
</Compile>
<Compile Include="DropdownMenuButton.cs">
<SubType>Component</SubType>
</Compile>
Expand Down Expand Up @@ -170,6 +176,9 @@
<Compile Include="MainDialogs.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="MainProvides.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="MainImport.cs">
<SubType>Form</SubType>
</Compile>
Expand Down Expand Up @@ -298,6 +307,12 @@
<EmbeddedResource Include="Localization\de-DE\CompatibleKspVersionsDialog.de-DE.resx">
<DependentUpon>..\..\CompatibleKspVersionsDialog.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="DeleteDirectories.resx">
<DependentUpon>DeleteDirectories.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Localization\de-DE\DeleteDirectories.de-DE.resx">
<DependentUpon>..\..\DeleteDirectories.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="EditLabelsDialog.resx">
<DependentUpon>EditLabelsDialog.cs</DependentUpon>
</EmbeddedResource>
Expand Down
Loading

0 comments on commit 0838ee7

Please sign in to comment.