PSRule-vscode/dotnet/PSRule.EditorServices/ClientBuilder.cs

349 строки
12 KiB
C#

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System.CommandLine;
using System.CommandLine.Invocation;
using System.Reflection;
using PSRule.CommandLine;
using PSRule.CommandLine.Commands;
using PSRule.CommandLine.Models;
using PSRule.Rules;
using PSRule.EditorServices.Resources;
using System.IO;
using System;
using PSRule.Pipeline;
namespace PSRule.EditorServices;
/// <summary>
/// A helper to build the command-line commands and options offered to the caller.
/// </summary>
internal sealed class ClientBuilder
{
private const string ARG_FORCE = "--force";
private static readonly string? _Version = typeof(PipelineBuilder).Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion;
private readonly Option<string> _Global_Option;
private readonly Option<bool> _Global_Verbose;
private readonly Option<bool> _Global_Debug;
private readonly Option<bool> _Module_Restore_Force;
private readonly Option<bool> _Module_Init_Force;
private readonly Option<string> _Module_Add_Version;
private readonly Option<bool> _Module_Add_Force;
private readonly Option<bool> _Module_Add_SkipVerification;
private readonly Option<string[]> _Global_Path;
private readonly Option<DirectoryInfo> _Run_OutputPath;
private readonly Option<string> _Run_OutputFormat;
private readonly Option<string[]> _Run_InputPath;
private readonly Option<string[]> _Run_Module;
private readonly Option<string> _Run_Baseline;
private readonly Option<string[]> _Run_Outcome;
private ClientBuilder(RootCommand cmd)
{
Command = cmd;
// Global options.
_Global_Option = new Option<string>(
["--option"],
getDefaultValue: () => "ps-rule.yaml",
description: CmdStrings.Global_Option_Description
);
_Global_Verbose = new Option<bool>(
["--verbose"],
description: CmdStrings.Global_Verbose_Description
);
_Global_Debug = new Option<bool>(
["--debug"],
description: CmdStrings.Global_Debug_Description
);
_Global_Path = new Option<string[]>(
["-p", "--path"],
description: CmdStrings.Global_Path_Description
);
// Options for the run command.
_Run_OutputPath = new Option<DirectoryInfo>(
["--output-path"],
description: CmdStrings.Run_OutputPath_Description
);
_Run_OutputFormat = new Option<string>(
["-o", "--output"],
description: CmdStrings.Run_OutputFormat_Description
);
_Run_InputPath = new Option<string[]>(
["-f", "--input-path"],
description: CmdStrings.Run_InputPath_Description
);
_Run_Module = new Option<string[]>(
["-m", "--module"],
description: CmdStrings.Run_Module_Description
);
_Run_Baseline = new Option<string>(
["--baseline"],
description: CmdStrings.Run_Baseline_Description
);
_Run_Outcome = new Option<string[]>(
["--outcome"],
description: CmdStrings.Run_Outcome_Description
).FromAmong("Pass", "Fail", "Error", "Processed", "Problem");
_Run_Outcome.Arity = ArgumentArity.ZeroOrMore;
// Options for the module command.
_Module_Init_Force = new Option<bool>(
[ARG_FORCE],
description: CmdStrings.Module_Init_Force_Description
);
_Module_Add_Version = new Option<string>
(
["--version"],
description: CmdStrings.Module_Add_Version_Description
);
_Module_Add_Force = new Option<bool>(
[ARG_FORCE],
description: CmdStrings.Module_Add_Force_Description
);
_Module_Add_SkipVerification = new Option<bool>(
["--skip-verification"],
description: CmdStrings.Module_Add_SkipVerification_Description
);
_Module_Restore_Force = new Option<bool>(
[ARG_FORCE],
description: CmdStrings.Module_Restore_Force_Description
);
cmd.AddGlobalOption(_Global_Option);
cmd.AddGlobalOption(_Global_Verbose);
cmd.AddGlobalOption(_Global_Debug);
}
public RootCommand Command { get; }
public static Command New()
{
var cmd = new RootCommand(string.Concat(CmdStrings.Cmd_Description, " v", _Version))
{
Name = "ps-rule"
};
var builder = new ClientBuilder(cmd);
builder.AddRun();
builder.AddModule();
return builder.Command;
}
/// <summary>
/// Add the <c>run</c> command.
/// </summary>
private void AddRun()
{
var cmd = new Command("run", CmdStrings.Run_Description);
cmd.AddOption(_Global_Path);
cmd.AddOption(_Run_OutputPath);
cmd.AddOption(_Run_OutputFormat);
cmd.AddOption(_Run_InputPath);
cmd.AddOption(_Run_Module);
cmd.AddOption(_Run_Baseline);
cmd.AddOption(_Run_Outcome);
cmd.SetHandler((invocation) =>
{
var option = new RunOptions
{
Path = invocation.ParseResult.GetValueForOption(_Global_Path),
InputPath = invocation.ParseResult.GetValueForOption(_Run_InputPath),
Module = invocation.ParseResult.GetValueForOption(_Run_Module),
Baseline = invocation.ParseResult.GetValueForOption(_Run_Baseline),
Outcome = ParseOutcome(invocation.ParseResult.GetValueForOption(_Run_Outcome)),
};
var client = GetClientContext(invocation);
Environment.TryPathEnvironmentVariable("PSModulePath", out var searchPaths);
var sp = searchPaths == null ? string.Empty : string.Join(',', searchPaths);
if (client.Verbose)
{
invocation.Console.WriteLine($"VERBOSE: Using workspace: {Environment.GetWorkingPath()}");
invocation.Console.WriteLine($"VERBOSE: Using module search path: {sp}");
invocation.Console.WriteLine($"VERBOSE: Using language server: {client.Path}");
}
invocation.ExitCode = RunCommand.Run(option, client);
});
Command.AddCommand(cmd);
}
/// <summary>
/// Add the <c>module</c> command.
/// </summary>
private void AddModule()
{
var cmd = new Command("module", CmdStrings.Module_Description);
var moduleArg = new Argument<string[]>
(
"module",
CmdStrings.Module_Module_Description
);
moduleArg.Arity = ArgumentArity.OneOrMore;
// Init
var init = new Command
(
"init",
CmdStrings.Module_Init_Description
);
init.AddOption(_Module_Init_Force);
init.SetHandler(async (invocation) =>
{
var option = new ModuleOptions
{
Path = invocation.ParseResult.GetValueForOption(_Global_Path),
Version = invocation.ParseResult.GetValueForOption(_Module_Add_Version),
Force = invocation.ParseResult.GetValueForOption(_Module_Add_Force),
SkipVerification = invocation.ParseResult.GetValueForOption(_Module_Add_SkipVerification),
};
var client = GetClientContext(invocation);
invocation.ExitCode = await ModuleCommand.ModuleInitAsync(option, client);
});
// List
var list = new Command
(
"list",
CmdStrings.Module_List_Description
);
list.SetHandler(async (invocation) =>
{
var option = new ModuleOptions
{
Path = invocation.ParseResult.GetValueForOption(_Global_Path),
Version = invocation.ParseResult.GetValueForOption(_Module_Add_Version),
Force = invocation.ParseResult.GetValueForOption(_Module_Add_Force),
SkipVerification = invocation.ParseResult.GetValueForOption(_Module_Add_SkipVerification),
};
var client = GetClientContext(invocation);
invocation.ExitCode = await ModuleCommand.ModuleListAsync(option, client);
});
// Add
var add = new Command
(
"add",
CmdStrings.Module_Add_Description
);
add.AddArgument(moduleArg);
add.AddOption(_Module_Add_Version);
add.AddOption(_Module_Add_Force);
add.AddOption(_Module_Add_SkipVerification);
add.SetHandler(async (invocation) =>
{
var option = new ModuleOptions
{
Path = invocation.ParseResult.GetValueForOption(_Global_Path),
Module = invocation.ParseResult.GetValueForArgument(moduleArg),
Version = invocation.ParseResult.GetValueForOption(_Module_Add_Version),
Force = invocation.ParseResult.GetValueForOption(_Module_Add_Force),
SkipVerification = invocation.ParseResult.GetValueForOption(_Module_Add_SkipVerification),
};
var client = GetClientContext(invocation);
invocation.ExitCode = await ModuleCommand.ModuleAddAsync(option, client);
});
// Remove
var remove = new Command
(
"remove",
CmdStrings.Module_Remove_Description
);
remove.AddArgument(moduleArg);
remove.SetHandler(async (invocation) =>
{
var option = new ModuleOptions
{
Path = invocation.ParseResult.GetValueForOption(_Global_Path),
Module = invocation.ParseResult.GetValueForArgument(moduleArg),
};
var client = GetClientContext(invocation);
invocation.ExitCode = await ModuleCommand.ModuleRemoveAsync(option, client);
});
// Upgrade
var upgrade = new Command
(
"upgrade",
CmdStrings.Module_Upgrade_Description
);
upgrade.SetHandler(async (invocation) =>
{
var option = new ModuleOptions
{
Path = invocation.ParseResult.GetValueForOption(_Global_Path),
};
var client = GetClientContext(invocation);
invocation.ExitCode = await ModuleCommand.ModuleUpgradeAsync(option, client);
});
// Restore
var restore = new Command("restore", CmdStrings.Module_Restore_Description);
// restore.AddOption(_Path);
restore.AddOption(_Module_Restore_Force);
restore.SetHandler(async (invocation) =>
{
var option = new RestoreOptions
{
Path = invocation.ParseResult.GetValueForOption(_Global_Path),
Force = invocation.ParseResult.GetValueForOption(_Module_Restore_Force),
};
var client = GetClientContext(invocation);
invocation.ExitCode = await ModuleCommand.ModuleRestoreAsync(option, client);
});
cmd.AddCommand(init);
cmd.AddCommand(list);
cmd.AddCommand(add);
cmd.AddCommand(remove);
cmd.AddCommand(upgrade);
cmd.AddCommand(restore);
cmd.AddOption(_Global_Path);
Command.AddCommand(cmd);
}
private ClientContext GetClientContext(InvocationContext invocation)
{
var option = invocation.ParseResult.GetValueForOption(_Global_Option);
var verbose = invocation.ParseResult.GetValueForOption(_Global_Verbose);
var debug = invocation.ParseResult.GetValueForOption(_Global_Debug);
option ??= Path.Combine(Environment.GetWorkingPath(), "ps-rule.yaml");
return new ClientContext
(
invocation: invocation,
option: option,
verbose: verbose,
debug: debug
);
}
/// <summary>
/// Convert string arguments to flags of <see cref="RuleOutcome"/>.
/// </summary>
private static RuleOutcome? ParseOutcome(string[]? s)
{
var result = RuleOutcome.None;
for (var i = 0; s != null && i < s.Length; i++)
{
if (Enum.TryParse(s[i], ignoreCase: true, result: out RuleOutcome flag))
result |= flag;
}
return result == RuleOutcome.None ? null : result;
}
}