Skip to content

Commit

Permalink
Use collection initializers
Browse files Browse the repository at this point in the history
  • Loading branch information
mikem8361 committed Dec 6, 2019
1 parent fb9c783 commit 649875f
Show file tree
Hide file tree
Showing 10 changed files with 136 additions and 102 deletions.
22 changes: 6 additions & 16 deletions src/Tools/Common/CommandExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,19 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Invocation;

namespace Microsoft.Tools.Common
{
public static class CommandExtenions
{
public static Command AddOptions(this Command command, params Option[] options)
/// <summary>
/// Allows the command handler to be included in the collection initializer.
/// </summary>
public static void Add(this Command command, ICommandHandler handler)
{
foreach (Option option in options)
{
command.AddOption(option);
}
return command;
}

public static Command AddArguments(this Command command, params Argument[] arguments)
{
foreach (Argument argument in arguments)
{
command.AddArgument(argument);
}
return command;
command.Handler = handler;
}
}
}
3 changes: 2 additions & 1 deletion src/Tools/Common/Commands/ProcessStatus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ namespace Microsoft.Internal.Common.Commands
public class ProcessStatusCommandHandler
{
public static Command ProcessStatusCommand(string description) =>
new Command(name: "ps", description) {
new Command(name: "ps", description)
{
Handler = CommandHandler.Create<IConsole>(PrintProcessStatus)
};

Expand Down
47 changes: 30 additions & 17 deletions src/Tools/dotnet-counters/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,18 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Microsoft.Diagnostics.NETCore.Client;
using Microsoft.Internal.Common.Commands;
using Microsoft.Tools.Common;
using System;
using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Binding;
using System.CommandLine.Builder;
using System.CommandLine.Invocation;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
using Microsoft.Diagnostics.NETCore.Client;
using Microsoft.Internal.Common.Commands;
using Microsoft.Tools.Common;
using System.Security.Cryptography;

namespace Microsoft.Diagnostics.Tools.Counters
{
Expand All @@ -27,55 +26,69 @@ internal class Program
private static Command MonitorCommand() =>
new Command(
name: "monitor",
description: "Start monitoring a .NET application") {
Handler = CommandHandler.Create<CancellationToken, List<string>, IConsole, int, int>(new CounterMonitor().Monitor)
}.AddOptions(new Option[] { ProcessIdOption(), RefreshIntervalOption() }).AddArguments(CounterList());
description: "Start monitoring a .NET application")
{
// Handler
CommandHandler.Create<CancellationToken, List<string>, IConsole, int, int>(new CounterMonitor().Monitor),
// Arguments and Options
CounterList(), ProcessIdOption(), RefreshIntervalOption()
};

private static Command CollectCommand() =>
new Command(
name: "collect",
description: "Monitor counters in a .NET application and export the result into a file") {
Handler = HandlerDescriptor.FromDelegate((ExportDelegate)new CounterMonitor().Collect).GetCommandHandler()
}.AddOptions(new Option[] { ProcessIdOption(), RefreshIntervalOption(), ExportFormatOption(), ExportFileNameOption() }).AddArguments(CounterList());
description: "Monitor counters in a .NET application and export the result into a file")
{
// Handler
HandlerDescriptor.FromDelegate((ExportDelegate)new CounterMonitor().Collect).GetCommandHandler(),
// Arguments and Options
CounterList(), ProcessIdOption(), RefreshIntervalOption(), ExportFormatOption(), ExportFileNameOption()
};

private static Option ProcessIdOption() =>
new Option(
aliases: new[] { "-p", "--process-id" },
description: "The process id that will be monitored.") {
description: "The process id that will be monitored.")
{
Argument = new Argument<int>(name: "pid")
};

private static Option RefreshIntervalOption() =>
new Option(
alias: "--refresh-interval",
description: "The number of seconds to delay between updating the displayed counters.") {
description: "The number of seconds to delay between updating the displayed counters.")
{
Argument = new Argument<int>(name: "refresh-interval", defaultValue: 1)
};

private static Option ExportFormatOption() =>
new Option(
alias: "--format",
description: "The format of exported counter data.") {
description: "The format of exported counter data.")
{
Argument = new Argument<CountersExportFormat>(name: "format", defaultValue: CountersExportFormat.csv)
};

private static Option ExportFileNameOption() =>
new Option(
aliases: new[] { "-o", "--output" },
description: "The output file name.") {
description: "The output file name.")
{
Argument = new Argument<string>(name: "output", defaultValue: "counter")
};

private static Argument CounterList() =>
new Argument<List<string>>(name: "counter_list", defaultValue: new List<string>()) {
new Argument<List<string>>(name: "counter_list", defaultValue: new List<string>())
{
Description = @"A space separated list of counters. Counters can be specified provider_name[:counter_name]. If the provider_name is used without a qualifying counter_name then all counters will be shown. To discover provider and counter names, use the list command.",
Arity = ArgumentArity.ZeroOrMore
};

private static Command ListCommand() =>
new Command(
name: "list",
description: "Display a list of counter names and descriptions, grouped by provider.") {
description: "Display a list of counter names and descriptions, grouped by provider.")
{
Handler = CommandHandler.Create<IConsole>(List)
};

Expand Down
44 changes: 28 additions & 16 deletions src/Tools/dotnet-dump/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
using System.CommandLine.Builder;
using System.CommandLine.Invocation;
using System.IO;
using System.Security.Cryptography;
using System.Threading.Tasks;

namespace Microsoft.Diagnostics.Tools.Dump
Expand All @@ -29,31 +28,36 @@ public static Task<int> Main(string[] args)
}

private static Command CollectCommand() =>
new Command(
name: "collect",
description: "Capture dumps from a process") {
Handler = CommandHandler.Create<IConsole, int, string, bool, Dumper.DumpTypeOption>(new Dumper().Collect)
}.AddOptions(new Option[] { ProcessIdOption(), OutputOption(), DiagnosticLoggingOption(), TypeOption() });
new Command( name: "collect", description: "Capture dumps from a process")
{
// Handler
CommandHandler.Create<IConsole, int, string, bool, Dumper.DumpTypeOption>(new Dumper().Collect),
// Options
ProcessIdOption(), OutputOption(), DiagnosticLoggingOption(), TypeOption()
};

private static Option ProcessIdOption() =>
new Option(
aliases: new[] { "-p", "--process-id" },
description: "The process id to collect a memory dump.") {
description: "The process id to collect a memory dump.")
{
Argument = new Argument<int>(name: "pid")
};

private static Option OutputOption() =>
new Option(
aliases: new[] { "-o", "--output" },
description: @"The path where collected dumps should be written. Defaults to '.\dump_YYYYMMDD_HHMMSS.dmp' on Windows and './core_YYYYMMDD_HHMMSS'
on Linux where YYYYMMDD is Year/Month/Day and HHMMSS is Hour/Minute/Second. Otherwise, it is the full path and file name of the dump.") {
on Linux where YYYYMMDD is Year/Month/Day and HHMMSS is Hour/Minute/Second. Otherwise, it is the full path and file name of the dump.")
{
Argument = new Argument<string>(name: "output_dump_path")
};

private static Option DiagnosticLoggingOption() =>
new Option(
alias: "--diag",
description: "Enable dump collection diagnostic logging.") {
description: "Enable dump collection diagnostic logging.")
{
Argument = new Argument<bool>(name: "diag")
};

Expand All @@ -62,27 +66,35 @@ private static Option TypeOption() =>
alias: "--type",
description: @"The dump type determines the kinds of information that are collected from the process. There are two types: heap - A large and
relatively comprehensive dump containing module lists, thread lists, all stacks, exception information, handle information, and all memory except for mapped
images. mini - A small dump containing module lists, thread lists, exception information and all stacks. If not specified 'heap' is the default.") {
images. mini - A small dump containing module lists, thread lists, exception information and all stacks. If not specified 'heap' is the default.")
{
Argument = new Argument<Dumper.DumpTypeOption>(name: "dump_type", defaultValue: Dumper.DumpTypeOption.Heap)
};

private static Command AnalyzeCommand() =>
new Command(
name: "analyze",
description: "Starts an interactive shell with debugging commands to explore a dump") {
Handler = CommandHandler.Create<FileInfo, string[]>(new Analyzer().Analyze)
}.AddOptions(RunCommand()).AddArguments(DumpPath());
description: "Starts an interactive shell with debugging commands to explore a dump")
{
// Handler
CommandHandler.Create<FileInfo, string[]>(new Analyzer().Analyze),
// Arguments and Options
DumpPath(),
RunCommand()
};

private static Argument DumpPath() =>
new Argument<FileInfo> {
Name = "dump_path",
new Argument<FileInfo>(
name: "dump_path")
{
Description = "Name of the dump file to analyze."
}.ExistingOnly();

private static Option RunCommand() =>
new Option(
aliases: new[] { "-c", "--command" },
description: "Run the command on start.") {
description: "Run the command on start.")
{
Argument = new Argument<string[]>(name: "command", defaultValue: new string[0]) { Arity = ArgumentArity.ZeroOrMore }
};
}
Expand Down
26 changes: 15 additions & 11 deletions src/Tools/dotnet-gcdump/CommandLine/CollectCommandHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,9 @@

using Microsoft.Tools.Common;
using System;
using System.Collections.Generic;
using System.CommandLine;
using System.CommandLine.Binding;
using System.CommandLine.Rendering;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

Expand Down Expand Up @@ -101,36 +97,44 @@ private static async Task<int> Collect(CancellationToken ct, IConsole console, i
public static Command CollectCommand() =>
new Command(
name: "collect",
description: "Collects a diagnostic trace from a currently running process") {
Handler = HandlerDescriptor.FromDelegate((CollectDelegate)Collect).GetCommandHandler()
}.AddOptions(new Option[] { ProcessIdOption(), OutputPathOption(), VerboseOption(), TimeoutOption() });
description: "Collects a diagnostic trace from a currently running process")
{
// Handler
HandlerDescriptor.FromDelegate((CollectDelegate)Collect).GetCommandHandler(),
// Options
ProcessIdOption(), OutputPathOption(), VerboseOption(), TimeoutOption()
};

public static Option ProcessIdOption() =>
new Option(
aliases: new[] { "-p", "--process-id" },
description: "The process id to collect the trace.") {
description: "The process id to collect the trace.")
{
Argument = new Argument<int>(name: "pid", defaultValue: 0),
};

private static Option OutputPathOption() =>
new Option(
aliases: new[] { "-o", "--output" },
description: $@"The path where collected gcdumps should be written. Defaults to '.\YYYYMMDD_HHMMSS_<pid>.gcdump' where YYYYMMDD is Year/Month/Day and HHMMSS is Hour/Minute/Second. Otherwise, it is the full path and file name of the dump.") {
description: $@"The path where collected gcdumps should be written. Defaults to '.\YYYYMMDD_HHMMSS_<pid>.gcdump' where YYYYMMDD is Year/Month/Day and HHMMSS is Hour/Minute/Second. Otherwise, it is the full path and file name of the dump.")
{
Argument = new Argument<string>(name: "gcdump-file-path", defaultValue: "")
};

private static Option VerboseOption() =>
new Option(
aliases: new[] { "-v", "--verbose" },
description: $"Output the log while collecting the gcdump.") {
description: $"Output the log while collecting the gcdump.")
{
Argument = new Argument<bool>(name: "verbose", defaultValue: false)
};

private static int DefaultTimeout = 30;
private static Option TimeoutOption() =>
new Option(
aliases: new[] { "-t", "--timeout" },
description: $"Give up on collecting the gcdump if it takes longer than this many seconds. The default value is {DefaultTimeout}s.") {
description: $"Give up on collecting the gcdump if it takes longer than this many seconds. The default value is {DefaultTimeout}s.")
{
Argument = new Argument<int>(name: "timeout", defaultValue: DefaultTimeout)
};
}
Expand Down
18 changes: 11 additions & 7 deletions src/Tools/dotnet-sos/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@

using Microsoft.Tools.Common;
using SOS;
using System;
using System.CommandLine;
using System.CommandLine.Builder;
using System.CommandLine.Invocation;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading.Tasks;

Expand All @@ -30,21 +28,27 @@ public static Task<int> Main(string[] args)
private static Command InstallCommand() =>
new Command(
name: "install",
description: "Installs SOS and configures LLDB to load it on startup.") {
Handler = CommandHandler.Create<IConsole, Architecture?>((console, architecture) => InvokeAsync(console, architecture, install: true))
}.AddOptions(ArchitectureOption());
description: "Installs SOS and configures LLDB to load it on startup.")
{
// Handler
CommandHandler.Create<IConsole, Architecture?>((console, architecture) => InvokeAsync(console, architecture, install: true)),
// Options
ArchitectureOption()
};

private static Option ArchitectureOption() =>
new Option(
alias: "--architecture",
description: "The processor architecture to install.") {
description: "The processor architecture to install.")
{
Argument = new Argument<Architecture>(name: "architecture")
};

private static Command UninstallCommand() =>
new Command(
name: "uninstall",
description: "Uninstalls SOS and reverts any configuration changes to LLDB.") {
description: "Uninstalls SOS and reverts any configuration changes to LLDB.")
{
Handler = CommandHandler.Create<IConsole>((console) => InvokeAsync(console, architecture: null, install: false))
};

Expand Down
Loading

0 comments on commit 649875f

Please sign in to comment.