SmolFennec.SpeCLI 1.1.1

There is a newer version of this package available.
See the version list below for details.
dotnet add package SmolFennec.SpeCLI --version 1.1.1                
NuGet\Install-Package SmolFennec.SpeCLI -Version 1.1.1                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="SmolFennec.SpeCLI" Version="1.1.1" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add SmolFennec.SpeCLI --version 1.1.1                
#r "nuget: SmolFennec.SpeCLI, 1.1.1"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install SmolFennec.SpeCLI as a Cake Addin
#addin nuget:?package=SmolFennec.SpeCLI&version=1.1.1

// Install SmolFennec.SpeCLI as a Cake Tool
#tool nuget:?package=SmolFennec.SpeCLI&version=1.1.1                

SmolFennec.SpeCLI

SmolFennec is a collective name for small libraries and tools released by Levi licensed under MIT and hosted on github. SpeCLI provides a way to describe CLI behaviour of external processes.

<img src="https://raw.githubusercontent.com/Levi--G/SmolFennec.SpeCLI/master/SpeCLI/SmolFennec.png" width="300" height="300">

NuGet version (SmolFennec.SpeCLI)

Support

Supported platforms: .Net Standard 2.0+

When in trouble: Submit an issue

Usage

EZ mode:

(The ping command was used below for short instructional purposes, ofcourse it is not meant to be used like this, use the ping class instead!)

Create a class for input and a class for output. Usable attributes:

  • Parameter: Defines a parameter with name and value, like: -n 50
  • Switch: Defines a switch with name only, like: -6
  • HideName: Defines a parameter with value only, like: Hostname
  • When nothing is supplied a parameter with the property name and a value is created
class PingArguments
{
    [Switch("t")]
    public bool Continuous { get; set; }
    [Parameter("n")]
    public int? Count { get; set; }
    [Parameter("i")]
    public int? TTL { get; set; }
    [Parameter("w")]
    public int? Timeout { get; set; }
    [Switch("4")]
    public bool IPV4 { get; set; }
    [Switch("6")]
    public bool IPV6 { get; set; }
    [HideName]
    public string Host { get; set; }
}

class PingResult
{
    public string ip { get; set; }
    public string fail { get; set; }
    public bool Success => !string.IsNullOrEmpty(ip) && string.IsNullOrEmpty(fail);
    public int bytes { get; set; }
    public TimeSpan time { get; set; }
    public int ttl { get; set; }
}

Create an Executable with Commands Usable OutputProcessors at this time:

  • JsonOutputProcessor: Parses the outputted lines as json
  • RegexCaptureOutputProcessor: Populates an object with matched regex groups
  • RegexSplitOutputProcessor: Splits the lines matching regexes over different OutputProcessors
  • CloneOutputProcessor: Clones the output and sends it to other OutputProcessors
  • Interface to write your own!

For the individual configuration please look at the configuration properties and methods.

 // The regex we will use later
const string regex = @"Reply from (?<ip>[^:]+): (?:bytes=(?<bytes>\d+) time[^\d]*(?<time>[^ ]+) TTL=(?<ttl>\d+)|(?<fail>.+))";
 // Create an executable to hold commands to be reused
var exe = new Executable("ping");
 // Add a new command
exe.Add("ping")
     // Add all parameters from this type
    .AddParametersFromType(typeof(PingArguments))
    .WithProcessor(
         // Use this processor to handle regex output
        new RegexCaptureOutputProcessor()
         // Map this regex to the output type we made, this can be done multiple times
        .AddRegex<PingResult>(new Regex(regex))
         // Add a manual mapping for the non-standard timespan conversion
        .AddPropertyMapping(s => TimeSpan.FromMilliseconds(int.Parse(s.TrimEnd('m', 's'))))
     );

Use the constructed Executable:

List<PingResult> matches = exe.ExecuteCommandAndParseList<PingResult>("ping", new PingArguments() {
    Count = 8,
    Host = "Hostname",
    Timeout = 50
});

Full sample can be found in the source.

Manual/Advanced mode:

IAsyncEnumerables can be obtained like this:

var iae = exe.ExecuteCommandAndParseIAsyncEnumerable<PingResult>("ping", new PingArguments() { Host = "Hostname" });

Parameters can also be declared manually. When invoking a nameless type, a Dictionary<string, object> or another type with similar properties can also be used. When you specify a List<object> any objects generated from whatever type will be returned

exe.Add("ping")
    .AddParameter<int?>("n")
    .AddParameter(new Parameter<string>("host").WithHideName());
    .AddParameter(new Switch("6"))

var objs = exe.ExecuteCommandAndParseList<object>("ping", new { Host = "Hostname" });

An Execution object can also be obtained, altho short-lived (pun intended) these can allow more low-level access to the process, events and Stdin.

var exec = exe.CreateExecution("ping", new PingArguments() { Host = "Hostname" });
exec.OutputDataReceived += (s, e) => { }; // raw stdout
exec.ErrorDataReceived += (s, e) => { }; // raw stderr
exec.OnOutput += (s, e) => { }; // Parsed objects
exec.OnError += (s, e) => { }; // Exceptions during parsing
exec.Start(); // Needs to be started manually;
exec.SendInputLine("Hello World!"); // Can send stdin
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on SmolFennec.SpeCLI:

Package Downloads
SmolFennec.SpeCLI.Proxy

A proxy generator for SmolFennec.SpeCLI

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.2.3 487 12/12/2022
1.2.2 299 12/12/2022
1.2.1 617 10/23/2022
1.2.0 549 1/3/2021
1.1.4 587 1/3/2021
1.1.3 503 12/30/2020
1.1.2 578 12/22/2020
1.1.1 452 12/21/2020
1.1.0 385 12/21/2020
1.0.0 395 11/10/2020

Better consistency with default behaviour across classes
Removed generic parameter
Removed per type command parameter mapping
Split configure and create logic in attributes
Fixed bug in RegexCaptureOutputProcessor not finding mapping
Versioned as 1.1.0, might break existing code