Skip to content

Commit

Permalink
Global install filters
Browse files Browse the repository at this point in the history
  • Loading branch information
HebaruSan committed Apr 6, 2022
1 parent 04484a6 commit dc4b0bb
Show file tree
Hide file tree
Showing 23 changed files with 1,083 additions and 8 deletions.
289 changes: 289 additions & 0 deletions Cmdline/Action/Filter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,289 @@
using System.Linq;
using System.Collections.Generic;

using Autofac;
using CommandLine;
using CommandLine.Text;
using log4net;

namespace CKAN.CmdLine
{
/// <summary>
/// Subcommand for managing installation filters
/// </summary>
public class Filter : ISubCommand
{
/// <summary>
/// Initialize the subcommand
/// </summary>
public Filter() { }

/// <summary>
/// Run the subcommand
/// </summary>
/// <param name="mgr">Manager to provide game instances</param>
/// <param name="opts">Command line parameters paritally handled by parser</param>
/// <param name="unparsed">Command line parameters not yet handled by parser</param>
/// <returns>
/// Exit code
/// </returns>
public int RunSubCommand(GameInstanceManager mgr, CommonOptions opts, SubCommandOptions unparsed)
{
string[] args = unparsed.options.ToArray();
int exitCode = Exit.OK;
// Parse and process our sub-verbs
Parser.Default.ParseArgumentsStrict(args, new FilterSubOptions(), (string option, object suboptions) =>
{
// ParseArgumentsStrict calls us unconditionally, even with bad arguments
if (!string.IsNullOrEmpty(option) && suboptions != null)
{
CommonOptions options = (CommonOptions)suboptions;
options.Merge(opts);
user = new ConsoleUser(options.Headless);
manager = mgr ?? new GameInstanceManager(user);
exitCode = options.Handle(manager, user);
if (exitCode != Exit.OK)
return;
switch (option)
{
case "list":
exitCode = ListFilters((FilterListOptions)suboptions, option);
break;
case "add":
exitCode = AddFilters((FilterAddOptions)suboptions, option);
break;
case "remove":
exitCode = RemoveFilters((FilterRemoveOptions)suboptions, option);
break;
default:
user.RaiseMessage("Unknown command: filter {0}", option);
exitCode = Exit.BADOPT;
break;
}
}
}, () => { exitCode = MainClass.AfterHelp(); });
return exitCode;
}

private int ListFilters(FilterListOptions opts, string verb)
{
int exitCode = opts.Handle(manager, user);
if (exitCode != Exit.OK)
{
return exitCode;
}

var cfg = ServiceLocator.Container.Resolve<Configuration.IConfiguration>();
user.RaiseMessage("Global filters:");
foreach (string filter in cfg.GlobalInstallFilters)
{
user.RaiseMessage("\t- {0}", filter);
}
user.RaiseMessage("");

var instance = MainClass.GetGameInstance(manager);
user.RaiseMessage("Instance filters:");
foreach (string filter in instance.InstallFilters)
{
user.RaiseMessage("\t- {0}", filter);
}
return Exit.OK;
}

private int AddFilters(FilterAddOptions opts, string verb)
{
if (opts.filters.Count < 1)
{
user.RaiseMessage("Usage: ckan filter {0} filter1 [filter2 ...]", verb);
return Exit.BADOPT;
}

int exitCode = opts.Handle(manager, user);
if (exitCode != Exit.OK)
{
return exitCode;
}

if (opts.global)
{
var cfg = ServiceLocator.Container.Resolve<Configuration.IConfiguration>();
var duplicates = cfg.GlobalInstallFilters
.Intersect(opts.filters)
.ToArray();
if (duplicates.Length > 0)
{
user.RaiseError(
"Global filters already set: {0}",
string.Join(", ", duplicates)
);
return Exit.BADOPT;
}
else
{
cfg.GlobalInstallFilters = cfg.GlobalInstallFilters
.Concat(opts.filters)
.Distinct()
.ToArray();
}
}
else
{
var instance = MainClass.GetGameInstance(manager);
var duplicates = instance.InstallFilters
.Intersect(opts.filters)
.ToArray();
if (duplicates.Length > 0)
{
user.RaiseError(
"Instance filters already set: {0}",
string.Join(", ", duplicates)
);
return Exit.BADOPT;
}
else
{
instance.InstallFilters = instance.InstallFilters
.Concat(opts.filters)
.Distinct()
.ToArray();
}
}
return Exit.OK;
}

private int RemoveFilters(FilterRemoveOptions opts, string verb)
{
if (opts.filters.Count < 1)
{
user.RaiseMessage("Usage: ckan filter {0} filter1 [filter2 ...]", verb);
return Exit.BADOPT;
}

int exitCode = opts.Handle(manager, user);
if (exitCode != Exit.OK)
{
return exitCode;
}

if (opts.global)
{
var cfg = ServiceLocator.Container.Resolve<Configuration.IConfiguration>();
var notFound = opts.filters
.Except(cfg.GlobalInstallFilters)
.ToArray();
if (notFound.Length > 0)
{
user.RaiseError(
"Global filters not found: {0}",
string.Join(", ", notFound)
);
return Exit.BADOPT;
}
else
{
cfg.GlobalInstallFilters = cfg.GlobalInstallFilters
.Except(opts.filters)
.ToArray();
}
}
else
{
var instance = MainClass.GetGameInstance(manager);
var notFound = opts.filters
.Except(instance.InstallFilters)
.ToArray();
if (notFound.Length > 0)
{
user.RaiseError(
"Instance filters not found: {0}",
string.Join(", ", notFound)
);
return Exit.BADOPT;
}
else
{
instance.InstallFilters = instance.InstallFilters
.Except(opts.filters)
.ToArray();
}
}
return Exit.OK;
}

private GameInstanceManager manager { get; set; }
private IUser user { get; set; }

private static readonly ILog log = LogManager.GetLogger(typeof(Filter));
}

internal class FilterSubOptions : VerbCommandOptions
{
[VerbOption("list", HelpText = "List install filters")]
public FilterListOptions FilterListOptions { get; set; }

[VerbOption("add", HelpText = "Add install filters")]
public FilterAddOptions FilterAddOptions { get; set; }

[VerbOption("remove", HelpText = "Remove install filters")]
public FilterRemoveOptions FilterRemoveOptions { get; set; }

[HelpVerbOption]
public string GetUsage(string verb)
{
HelpText ht = HelpText.AutoBuild(this, verb);
// Add a usage prefix line
ht.AddPreOptionsLine(" ");
if (string.IsNullOrEmpty(verb))
{
ht.AddPreOptionsLine("ckan filter - View or edit installation filters");
ht.AddPreOptionsLine($"Usage: ckan filter <command> [options]");
}
else
{
ht.AddPreOptionsLine("filter " + verb + " - " + GetDescription(verb));
switch (verb)
{
case "list":
ht.AddPreOptionsLine($"Usage: ckan filter {verb}");
break;

case "add":
ht.AddPreOptionsLine($"Usage: ckan filter {verb} [options] filter1 [filter2 ...]");
break;

case "remove":
ht.AddPreOptionsLine($"Usage: ckan filter {verb} [options] filter1 [filter2 ...]");
break;
}
}
return ht;
}
}

internal class FilterListOptions : InstanceSpecificOptions
{
}

internal class FilterAddOptions : InstanceSpecificOptions
{
[Option("global", DefaultValue = false, HelpText = "Add global filters")]
public bool global { get; set; }

[ValueList(typeof(List<string>))]
public List<string> filters { get; set; }
}

internal class FilterRemoveOptions : InstanceSpecificOptions
{
[Option("global", DefaultValue = false, HelpText = "Remove global filters")]
public bool global { get; set; }

[ValueList(typeof(List<string>))]
public List<string> filters { get; set; }
}

}
1 change: 1 addition & 0 deletions Cmdline/CKAN-cmdline.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
<Compile Include="Action\Cache.cs" />
<Compile Include="Action\Compare.cs" />
<Compile Include="Action\Compat.cs" />
<Compile Include="Action\Filter.cs" />
<Compile Include="Action\ICommand.cs" />
<Compile Include="Action\Import.cs" />
<Compile Include="Action\Install.cs" />
Expand Down
6 changes: 5 additions & 1 deletion Cmdline/Main.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,13 @@ public static int Execute(GameInstanceManager manager, CommonOptions opts, strin

case "cache":
return (new Cache()).RunSubCommand(manager, opts, new SubCommandOptions(args));

case "mark":
return (new Mark()).RunSubCommand(manager, opts, new SubCommandOptions(args));

case "filter":
return (new Filter()).RunSubCommand(manager, opts, new SubCommandOptions(args));

}
}
catch (NoGameInstanceKraken)
Expand Down
3 changes: 3 additions & 0 deletions Cmdline/Options.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ internal class Actions : VerbCommandOptions
[VerbOption("version", HelpText = "Show the version of the CKAN client being used")]
public VersionOptions Version { get; set; }

[VerbOption("filter", HelpText = "View or edit installation filters")]
public SubCommandOptions Filter { get; set; }

[HelpVerbOption]
public string GetUsage(string verb)
{
Expand Down
2 changes: 2 additions & 0 deletions ConsoleUI/CKAN-ConsoleUI.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@
<Compile Include="DependencyScreen.cs" />
<Compile Include="DownloadImportDialog.cs" />
<Compile Include="ExitScreen.cs" />
<Compile Include="InstallFilterAddDialog.cs" />
<Compile Include="InstallFiltersScreen.cs" />
<Compile Include="InstallScreen.cs" />
<Compile Include="GameInstanceAddScreen.cs" />
<Compile Include="GameInstanceEditScreen.cs" />
Expand Down
66 changes: 66 additions & 0 deletions ConsoleUI/InstallFilterAddDialog.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using CKAN.Versioning;
using CKAN.Games;
using CKAN.GameVersionProviders;
using CKAN.ConsoleUI.Toolkit;
using Autofac;

namespace CKAN.ConsoleUI {

/// <summary>
/// Popup letting user enter an installation filter
/// </summary>
public class InstallFilterAddDialog : ConsoleDialog {

/// <summary>
/// Initialize the popup
/// </summary>
public InstallFilterAddDialog() : base()
{
int l = GetLeft(),
r = GetRight();
int t = GetTop(),
b = t + 4;
SetDimensions(l, t, r, b);

manualEntry = new ConsoleField(
l + 2, b - 2, r - 2
) {
GhostText = () => "<Enter a filter>"
};
AddObject(manualEntry);
manualEntry.AddTip("Enter", "Accept value");
manualEntry.AddBinding(Keys.Enter, (object sender, ConsoleTheme theme) => {
choice = manualEntry.Value;
return false;
});

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

CenterHeader = () => "Add Filter";
}

/// <summary>
/// Display the dialog and handle its interaction
/// </summary>
/// <param name="process">Function to control the dialog, default is normal user interaction</param>
/// <param name="theme">The visual theme to use to draw the dialog</param>
/// <returns>
/// User input
/// </returns>
public new string Run(ConsoleTheme theme, Action<ConsoleTheme> process = null)
{
base.Run(theme, process);
return choice;
}

private ConsoleField manualEntry;
private string choice;
}
}
Loading

0 comments on commit dc4b0bb

Please sign in to comment.