code/KustoCopyConsole/Program.cs (162 lines of code) (raw):

using CommandLine; using CommandLine.Text; using KustoCopyConsole.JobParameter; using KustoCopyConsole.Runner; using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using System.Threading.Tasks; // See https://aka.ms/new-console-template for more information namespace KustoCopyConsole { internal class Program { #region Inner Types private class MultiFilter : TraceFilter { private readonly IImmutableList<TraceFilter> _filters; public MultiFilter(params TraceFilter[] filters) { _filters = filters.ToImmutableArray(); } public override bool ShouldTrace( TraceEventCache? cache, string source, TraceEventType eventType, int id, string? formatOrMessage, object?[]? args, object? data1, object?[]? data) { foreach (var filter in _filters) { if (!filter.ShouldTrace( cache, source, eventType, id, formatOrMessage, args, data1, data)) { return false; } } return true; } } #endregion public static string AssemblyVersion { get { var version = typeof(Program).Assembly.GetName().Version; var versionText = version == null ? "<VERSION MISSING>" : version.ToString(); return versionText; } } // This attributes is there to prevent an error when compiling with trimming // since CommandLineOptions is accessed by reflection [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(CommandLineOptions))] internal static async Task<int> Main(string[] args) { CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("en-US"); CultureInfo.CurrentUICulture = CultureInfo.GetCultureInfo("en-US"); Console.WriteLine(); Console.WriteLine($"Kusto Copy {AssemblyVersion}"); Console.WriteLine(); // Use CommandLineParser NuGet package to parse command line // See https://github.com/commandlineparser/commandline var parser = new Parser(with => { with.HelpWriter = null; }); try { var options = parser.ParseArguments<CommandLineOptions>(args); await options .WithNotParsed(errors => HandleParseError(options, errors)) .WithParsedAsync(RunOptionsAsync); return options.Tag == ParserResultType.Parsed ? 0 : 1; } catch (Exception ex) { ErrorHelper.DisplayException(ex); return 1; } } private static async Task RunOptionsAsync(CommandLineOptions options) { ConfigureTrace(options.Verbose); var cancellationTokenSource = new CancellationTokenSource(); var taskCompletionSource = new TaskCompletionSource(); var parameterization = MainJobParameterization.FromOptions(options); AppDomain.CurrentDomain.ProcessExit += (e, s) => { Trace.TraceInformation("Exiting process..."); cancellationTokenSource.Cancel(); taskCompletionSource.Task.Wait(); }; Trace.WriteLine(""); Trace.WriteLine("Parameterization:"); Trace.WriteLine(""); Trace.WriteLine(parameterization.ToYaml()); Trace.WriteLine(""); try { await using (var mainRunner = await MainRunner.CreateAsync( new Version(AssemblyVersion), parameterization, $"KUSTO-COPY;{AssemblyVersion}", cancellationTokenSource.Token)) { Trace.WriteLine("Processing..."); Trace.WriteLine(""); await mainRunner.RunAsync(cancellationTokenSource.Token); } } catch(Exception) { await cancellationTokenSource.CancelAsync(); throw; } finally { taskCompletionSource.SetResult(); } } private static void ConfigureTrace(bool isVerbose) { var consoleListener = new TextWriterTraceListener(Console.Out) { Filter = new EventTypeFilter( isVerbose ? SourceLevels.Information : SourceLevels.Warning) }; Trace.Listeners.Add(consoleListener); if (isVerbose) { Trace.TraceInformation("Verbose output enabled"); } } private static void HandleParseError( ParserResult<CommandLineOptions> result, IEnumerable<Error> errors) { var helpText = HelpText.AutoBuild(result, h => { h.AutoVersion = false; h.Copyright = string.Empty; h.Heading = string.Empty; return HelpText.DefaultParsingErrorsHandler(result, h); }, example => example); Console.WriteLine(helpText); } } }