Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update CommandLineParser #3131

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
268 changes: 139 additions & 129 deletions Cmdline/Action/AuthToken.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,180 +3,190 @@
using Autofac;
using CKAN.Configuration;
using CommandLine;
using CommandLine.Text;
using log4net;

namespace CKAN.CmdLine
namespace CKAN.CmdLine.Action
{
/// <summary>
/// Subcommand for managing authentication tokens
/// Class for managing authentication tokens.
/// </summary>
public class AuthToken : ISubCommand
{
/// <summary>
/// Initialize the subcommand
/// </summary>
public AuthToken() { }
private GameInstanceManager _manager;
private IUser _user;

/// <summary>
/// Run the subcommand
/// Run the 'authtoken' command.
/// </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 manager, CommonOptions opts, SubCommandOptions unparsed)
/// <inheritdoc cref="ISubCommand.RunCommand"/>
public int RunCommand(GameInstanceManager manager, object args)
{
string[] args = unparsed.options.ToArray();
int exitCode = Exit.OK;
var s = args.ToString();
var opts = s.Replace(s.Substring(0, s.LastIndexOf('.') + 1), "").Split('+');

CommonOptions options = new CommonOptions();
_user = new ConsoleUser(options.Headless);
_manager = manager ?? new GameInstanceManager(_user);
var exitCode = options.Handle(_manager, _user);

if (exitCode != Exit.Ok)
return exitCode;

Parser.Default.ParseArgumentsStrict(args, new AuthTokenSubOptions(), (string option, object suboptions) =>
switch (opts[1])
{
if (!string.IsNullOrEmpty(option) && suboptions != null)
{
CommonOptions options = (CommonOptions)suboptions;
options.Merge(opts);
user = new ConsoleUser(options.Headless);
if (manager == null)
{
manager = new GameInstanceManager(user);
}
exitCode = options.Handle(manager, user);
if (exitCode == Exit.OK)
{
switch (option)
{
case "list":
exitCode = listAuthTokens(options);
break;
case "add":
exitCode = addAuthToken((AddAuthTokenOptions)options);
break;
case "remove":
exitCode = removeAuthToken((RemoveAuthTokenOptions)options);
break;
}
}
}
}, () => { exitCode = MainClass.AfterHelp(); });
case "AddAuthToken":
exitCode = AddAuthToken(args);
break;
case "ListAuthToken":
exitCode = ListAuthTokens();
break;
case "RemoveAuthToken":
exitCode = RemoveAuthToken(args);
break;
default:
exitCode = Exit.BadOpt;
break;
}

return exitCode;
}

private int listAuthTokens(CommonOptions opts)
/// <inheritdoc cref="ISubCommand.GetUsage"/>
public string GetUsage(string prefix, string[] args)
{
List<string> hosts = new List<string>(ServiceLocator.Container.Resolve<IConfiguration>().GetAuthTokenHosts());
if (hosts.Count > 0)
if (args.Length == 1)
return $"{prefix} {args[0]} <command> [options]";

switch (args[1])
{
int longestHostLen = hostHeader.Length;
int longestTokenLen = tokenHeader.Length;
foreach (string host in hosts)
{
longestHostLen = Math.Max(longestHostLen, host.Length);
string token;
if (ServiceLocator.Container.Resolve<IConfiguration>().TryGetAuthToken(host, out token))
{
longestTokenLen = Math.Max(longestTokenLen, token.Length);
}
}
// Create format string: {0,-longestHostLen} {1,-longestTokenLen}
string fmt = string.Format("{0}0,-{2}{1} {0}1,-{3}{1}",
"{", "}", longestHostLen, longestTokenLen);
user.RaiseMessage(fmt, hostHeader, tokenHeader);
user.RaiseMessage(fmt,
new string('-', longestHostLen),
new string('-', longestTokenLen)
);
foreach (string host in hosts)
{
string token;
if (ServiceLocator.Container.Resolve<IConfiguration>().TryGetAuthToken(host, out token))
{
user.RaiseMessage(fmt, host, token);
}
}
case "add":
return $"{prefix} {args[0]} {args[1]} [options] <host> <token>";
case "list":
return $"{prefix} {args[0]} {args[1]} [options]";
case "remove":
return $"{prefix} {args[0]} {args[1]} [options] <host>";
default:
return $"{prefix} {args[0]} <command> [options]";
}
return Exit.OK;
}

private int addAuthToken(AddAuthTokenOptions opts)
private int AddAuthToken(object args)
{
if (Uri.CheckHostName(opts.host) != UriHostNameType.Unknown)
var opts = (AuthTokenOptions.AddAuthToken)args;
if (opts.Host == null || opts.Token == null)
{
ServiceLocator.Container.Resolve<IConfiguration>().SetAuthToken(opts.host, opts.token);
_user.RaiseMessage("add <host> <token> - argument(s) missing, perhaps you forgot it?");
return Exit.BadOpt;
}

if (Uri.CheckHostName(opts.Host) != UriHostNameType.Unknown)
{
ServiceLocator.Container.Resolve<IConfiguration>().SetAuthToken(opts.Host, opts.Token);
_user.RaiseMessage("Successfully added \"{0}\".", opts.Host);
}
else
{
user.RaiseError("Invalid host name: {0}", opts.host);
_user.RaiseMessage("Invalid host name.");
return Exit.BadOpt;
}
return Exit.OK;

return Exit.Ok;
}

private int removeAuthToken(RemoveAuthTokenOptions opts)
private int ListAuthTokens()
{
ServiceLocator.Container.Resolve<IConfiguration>().SetAuthToken(opts.host, null);
return Exit.OK;
}
const string hostHeader = "Host";
const string tokenHeader = "Token";

private const string hostHeader = "Host";
private const string tokenHeader = "Token";
var hosts = new List<string>(ServiceLocator.Container.Resolve<IConfiguration>().GetAuthTokenHosts());
if (hosts.Count > 0)
{
var hostWidth = hostHeader.Length;
var tokenWidth = tokenHeader.Length;
foreach (var host in hosts)
{
hostWidth = Math.Max(hostWidth, host.Length);
if (ServiceLocator.Container.Resolve<IConfiguration>().TryGetAuthToken(host, out string token) && token != null)
{
tokenWidth = Math.Max(tokenWidth, token.Length);
}
}

private IUser user;
private static readonly ILog log = LogManager.GetLogger(typeof(AuthToken));
}
_user.RaiseMessage("{0} {1}",
hostHeader.PadRight(hostWidth),
tokenHeader.PadRight(tokenWidth)
);

internal class AuthTokenSubOptions : VerbCommandOptions
{
[VerbOption("list", HelpText = "List auth tokens")]
public CommonOptions ListOptions { get; set; }
_user.RaiseMessage("{0} {1}",
new string('-', hostWidth),
new string('-', tokenWidth)
);

[VerbOption("add", HelpText = "Add an auth token")]
public AddAuthTokenOptions AddOptions { get; set; }
foreach (var host in hosts)
{
if (ServiceLocator.Container.Resolve<IConfiguration>().TryGetAuthToken(host, out string token))
{
_user.RaiseMessage("{0} {1}",
host.PadRight(hostWidth),
token.PadRight(tokenWidth)
);
}
}
}

[VerbOption("remove", HelpText = "Delete an auth token")]
public RemoveAuthTokenOptions RemoveOptions { get; set; }
return Exit.Ok;
}

[HelpVerbOption]
public string GetUsage(string verb)
private int RemoveAuthToken(object args)
{
HelpText ht = HelpText.AutoBuild(this, verb);
// Add a usage prefix line
ht.AddPreOptionsLine(" ");
if (string.IsNullOrEmpty(verb))
var opts = (AuthTokenOptions.RemoveAuthToken)args;
if (opts.Host == null)
{
ht.AddPreOptionsLine("ckan authtoken - Manage authentication tokens");
ht.AddPreOptionsLine($"Usage: ckan authtoken <command> [options]");
_user.RaiseMessage("remove <host> - argument missing, perhaps you forgot it?");
return Exit.BadOpt;
}

var hosts = new List<string>(ServiceLocator.Container.Resolve<IConfiguration>().GetAuthTokenHosts());
if (hosts.Contains(opts.Host))
{
ServiceLocator.Container.Resolve<IConfiguration>().SetAuthToken(opts.Host, null);
_user.RaiseMessage("Successfully removed \"{0}\".", opts.Host);
}
else
{
ht.AddPreOptionsLine("authtoken " + verb + " - " + GetDescription(verb));
switch (verb)
{
case "add":
ht.AddPreOptionsLine($"Usage: ckan authtoken {verb} [options] host token");
break;
case "remove":
ht.AddPreOptionsLine($"Usage: ckan authtoken {verb} [options] host");
break;
case "list":
ht.AddPreOptionsLine($"Usage: ckan authtoken {verb} [options]");
break;
}
_user.RaiseMessage("There is no host with the name \"{0}\".", opts.Host);
_user.RaiseMessage("Use 'ckan authtoken list' to view a list of hosts.");
return Exit.BadOpt;
}
return ht;

return Exit.Ok;
}
}

internal class AddAuthTokenOptions : CommonOptions
[Verb("authtoken", HelpText = "Manage authentication tokens")]
[ChildVerbs(typeof(AddAuthToken), typeof(ListAuthToken), typeof(RemoveAuthToken))]
internal class AuthTokenOptions
{
[ValueOption(0)] public string host { get; set; }
[ValueOption(1)] public string token { get; set; }
}
[VerbExclude]
[Verb("add", HelpText = "Add an authentication token")]
internal class AddAuthToken : CommonOptions
{
[Value(0, MetaName = "Host", HelpText = "The host (DNS / IP) to authenticate with")]
public string Host { get; set; }

internal class RemoveAuthTokenOptions : CommonOptions
{
[ValueOption(0)] public string host { get; set; }
}
[Value(1, MetaName = "Token", HelpText = "The token to authenticate with")]
public string Token { get; set; }
}

[VerbExclude]
[Verb("list", HelpText = "List authentication tokens")]
internal class ListAuthToken : CommonOptions { }

[VerbExclude]
[Verb("remove", HelpText = "Remove an authentication token")]
internal class RemoveAuthToken : CommonOptions
{
[Value(0, MetaName = "Host", HelpText = "The host (DNS / IP) to remove")]
public string Host { get; set; }
}
}
}
51 changes: 34 additions & 17 deletions Cmdline/Action/Available.cs
Original file line number Diff line number Diff line change
@@ -1,45 +1,62 @@
using System.Linq;
using System.Collections.Generic;
using CommandLine;

namespace CKAN.CmdLine
namespace CKAN.CmdLine.Action
{
/// <summary>
/// Class for listing the available mods.
/// </summary>
public class Available : ICommand
{
public IUser user { get; set; }
private readonly IUser _user;

/// <summary>
/// Initializes a new instance of the <see cref="CKAN.CmdLine.Action.Available"/> class.
/// </summary>
/// <param name="user">The current <see cref="CKAN.IUser"/> to raise messages to the user.</param>
public Available(IUser user)
{
this.user = user;
_user = user;
}

public int RunCommand(CKAN.GameInstance ksp, object raw_options)
/// <summary>
/// Run the 'available' command.
/// </summary>
/// <inheritdoc cref="ICommand.RunCommand"/>
public int RunCommand(CKAN.GameInstance inst, object args)
{
AvailableOptions opts = (AvailableOptions)raw_options;
IRegistryQuerier registry = RegistryManager.Instance(ksp).registry;
var opts = (AvailableOptions)args;
IRegistryQuerier registry = RegistryManager.Instance(inst).registry;

var compatible = registry
.CompatibleModules(ksp.VersionCriteria())
.CompatibleModules(inst.VersionCriteria())
.Where(m => !m.IsDLC);

user.RaiseMessage("Modules compatible with KSP {0}", ksp.Version());
user.RaiseMessage("");
_user.RaiseMessage("Mods compatible with {0} {1}\r\n", inst.game.ShortName, inst.Version());

if (opts.detail)
if (opts.Detail)
{
foreach (CkanModule module in compatible)
foreach (var module in compatible)
{
user.RaiseMessage("* {0} ({1}) - {2} - {3}", module.identifier, module.version, module.name, module.@abstract);
_user.RaiseMessage("* {0} ({1}) - {2} - {3}", module.identifier, module.version, module.name, module.@abstract);
}
}
else
{
foreach (CkanModule module in compatible)
foreach (var module in compatible)
{
user.RaiseMessage("* {0} ({1}) - {2}", module.identifier, module.version, module.name);
_user.RaiseMessage("* {0} ({1}) - {2}", module.identifier, module.version, module.name);
}
}

return Exit.OK;
return Exit.Ok;
}
}

[Verb("available", HelpText = "List available mods")]
internal class AvailableOptions : InstanceSpecificOptions
{
[Option("detail", HelpText = "Shows a short description of each mod")]
public bool Detail { get; set; }
}
}
Loading