How to get command line parameters in specific format? - c#

For example, we have option "--date".
I use System.CommandLine library to get options from command line and it works with such format:
"--date 2023-02-06", but I want it to work with format kind of: "--date=2023-02-06". Is there a way to do this?

If you don't mind using a beta Microsoft library you could use System.CommandLine.
From Option-argument delimiters:
Option-argument delimiters
System.CommandLine lets you use a space, '=', or ':' as the delimiter between an option name and its argument. For example, the following commands are equivalent:
dotnet build -v quiet
dotnet build -v=quiet
dotnet build -v:quiet
For example (This is modified Tutorial: Get started with System.CommandLine):
// dotnet add package System.CommandLine --prerelease
using System.CommandLine;
internal class Program
{
static async Task<int> Main(string[] args)
{
var date = new Option<string?>(
name: "--date",
description: "TODO");
var rootCommand = new RootCommand("TODO");
rootCommand.AddOption(date);
rootCommand.SetHandler((date) =>
{
Run(date!);
},
date);
return await rootCommand.InvokeAsync(args);
}
static void Run(string date)
{
Console.WriteLine(date);
}
}
Then we can:
PS C:\git\games\bin\Release\net6.0\win10-x64\publish> .\games.exe --date 2023-02-06
2023-02-06
PS C:\git\games\bin\Release\net6.0\win10-x64\publish> .\games.exe --date:2023-02-06
2023-02-06
PS C:\git\games\bin\Release\net6.0\win10-x64\publish> .\games.exe --date=2023-02-06
2023-02-06

Related

Tests on strings fails inside docker container

I'm using dotnet core and running a couple os tests on customized string extensions inside a docker container and it fail always, but it works well on a windows machine.
i've tryed to enforce the portuguese culture but it does not work, what am i missing here?
As example, i'm trying to remove diacritics from a string using as follows:
public static string RemoveDiacritics(this string input)
{
var normalizedString = input.Normalize(NormalizationForm.FormD);
var stringBuilder = new StringBuilder();
foreach (var c in normalizedString)
{
var unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c);
if (unicodeCategory != UnicodeCategory.NonSpacingMark)
{
stringBuilder.Append(c);
}
}
return stringBuilder.ToString().Normalize(NormalizationForm.FormC);
}
Here is the test example (NUnit)
[Test]
public void StringExtensions_RemoveDiacritics_SUCCESS()
{
string originalStr = "amahã deverá ser çábado";
string cleanStr = originalStr.RemoveDiacritics();
Assert.AreEqual("amaha devera ser cabado", cleanStr);
}
Here is the dockerfile example:
FROM mcr.microsoft.com/dotnet/sdk:3.1-focal
WORKDIR /
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false
ENV TZ Europe/Lisbon
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN dpkg-reconfigure --frontend noninteractive tzdata
For better undertanding how to reproduce, i've created the following repo:
https://github.com/FlavioCFOliveira/TestsOnStrings
Take a look at the behaviour described here: https://github.com/dotnet/dotnet-docker/issues/1360
Basically the base .NET images run in a globalization invariant mode by default. You have to manually disable it by doing the following in your Dockerfile:
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false
RUN apk add --no-cache icu-libs
Ran into this issue myself when a .ToLower() of an "Ë" character didn't correctly transform it into "ë": it remained "Ë".
Doing these Dockerfile modifications fixed it for my case.

System.CommandLine parsed values don't match input

I am trying to use System.CommandLine and I haven't been able to get my handler to see any of the values that I'm passing in. I've tried the simplest command line program just to see if any values make it through and so far I haven't been successful. I am targeting .NET 4.7.2 and I'm using System.CommandLine 2.0.0-beta1.20574.7
using System;
using System.CommandLine;
using System.CommandLine.Invocation;
static class Program
{
public static void Main(string[] args)
{
var rootCommand = new RootCommand
{
new Option("--continue", "continue option")
};
rootCommand.Description = "Testing System.CommandLine";
rootCommand.Handler = CommandHandler.Create<bool>
((willContinue) => run(willContinue));
rootCommand.Invoke(args);
}
private static void run(bool willContinue)
{
Console.WriteLine(willContinue);
}
}
No matter how I call my application, I am not seeing the value of willContinue come across as true.
myapp.exe --continue -> False
myapp.exe --cont -> Unrecognized command or argument '--cont' (my options are at least getting recognized)
myapp.exe --continue true -> Unrecognized command or argument 'true'
myapp.exe --help ->
myapp:
Testing System.CommandLine
Usage:
myapp [options]
Options:
--continue continue option
--version Show version information
-?, -h, --help Show help and usage information
You need to fix 2 things:
add the option type, which is bool
change the name of the option to match the parameter name
the following command works:
var rootCommand = new RootCommand
{
new Option<bool>("--willContinue", "continue option")
};
and call it like so
myapp.exe --willContinue true
the option name and parameter name don't always have to match-up, but in this case it doesn't work because 'continue' is a reserved word
I wanted to add an answer to be very clear about exactly what resolved my problem
using System;
using System.CommandLine;
using System.CommandLine.Invocation;
static class Program
{
public static void Main(string[] args)
{
var rootCommand = new RootCommand
{
new Option("--willContinue", "continue option")
// ^This option name
};
rootCommand.Description = "Testing System.CommandLine";
rootCommand.Handler = CommandHandler.Create<bool>
((WiLLCoNtInUe) => run(WiLLCoNtInUe));
// ^ HAS to match this parameter name where the command handler is created.
// but does not have to match case
rootCommand.Invoke(args);
}
private static void run(bool canBeSomethingElse)
// Because of how this is called ^ this does not have to match
{
Console.WriteLine(canBeSomethingElse);
}
}
Because the Argument/Option/Command/anything else that can be added to a Command object has to match the name of the parameter used when creating the CommandHandler, the names used can't have spaces, begin with numbers, or use a C# keyword (not having spaces is not a problem for most items because it would be silly/impossible to have an option --will continue, but with arguments you don't have to put the name of the argument into your command line call because it is listed in the usage as <argument name> and the argument is read in by position, so I was wanting to use an argument name like <file directory>, but that doesn't work because you can't have a variable name with spaces in it)

Compile using babel in a C#/.NET project

Trying to use babel to compile some code in C#/.NET project, following the example https://babeljs.io/setup#installation for C#/.NET.
Installed the package React.Core using NuGet Package Manager (Install-Package React.Core) in a simple Hello world project (https://learn.microsoft.com/en-us/dotnet/core/tutorials/with-visual-studio-code).
using System;
using React;
//using React.Web;
//using React.TinyIoC;
//using React.Web.Mvc4;
//using React.Web.TinyIoC;
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
// Console.WriteLine("Hello World!");
var babel = ReactEnvironment.Current.Babel;
// Transpiles a file
// You can instead use `TransformFileWithSourceMap` if you want a source map too.
// var result = babel.TransformFile("foo.js");
// Transpiles a piece of code
var result = babel.Transform("class Foo { }");
Console.WriteLine(result);
}
}
}
Alls getting error at: Unhandled Exception: React.TinyIoC.TinyIoCResolutionException: Unable to resolve type: React.IReactEnvironment
at React.TinyIoC.TinyIoCContainer.ResolveInternal
following this post tried adding the package React.Web and React.Web.Mvc4 but still get the same error, am importing the wrong packages?? or what is it? the version of the packages React.Core and the other are 5.1.0

Creating a command line in C# that includes file path

I am trying to create a project that accepts a configuration file and 2 comparison files using a command line arguments with the paths to these files included. Would I construct this the same way you would pass any command line argument? Sorry I am new to this so I am not sure if there is an exception when trying to pass files.
Can I get an example of how this would be done? Here is a picture of the directions of what exactly I have been asked.
Accept the following command line arguments:
Configuration file (with path) (described below)
Comparison File 1 (with path)
Comparison File 2 (with path)
Take a look at the documentation of Main function arguments
Assuming this is your main function and you want to accept 3 parameters:
static int Main(string[] args)
{
// check the length of args for validation.
// args[0] -> Configuration file
// args[1] -> Comparison File 1
// args[2] -> Comparison File 2
..... DO SOMETHING...
return 0;
}
Usage (from command line or debugger):
SomeProgram.exe "ConfigFilePath" "ComparisonFile1" "ComparisonFile2".
Because I really like this nuget(No association just a fan). Here is an example of it using CommandLineUtils
First add an new project with dotnet new consol TestConsolUtils then add the nuget dotnet add package McMaster.Extensions.CommandLineUtils then copy this code to the program class.
using McMaster.Extensions.CommandLineUtils;
using System;
namespace ConsolUtilsTest
{
class Program
{
public static int Main(string[] args)
=> CommandLineApplication.Execute<Program>(args);
[Argument(0, Description = "Configuration file")]
[FileExists]
public string ConfigurationFile { get; }
[Argument(1, Description = "Comparison file 1")]
[FileExists]
public string ComparisonFile1 { get; }
[Argument(2, Description = "Comparison File 2")]
[FileExists]
public string ComparisonFile2 { get; }
private void OnExecute()
{
Console.WriteLine(ConfigurationFile);
Console.WriteLine(ComparisonFile1);
Console.WriteLine(ComparisonFile2);
}
}
}
do a dotnet build
Go to the dll folder that was just build most likely in Debug\netcoreapp2.2\
Create a fake file A.json this is required because the utility will check if the file exists.
Run it with dotnet command
dotnet TestConsolUtils.dll A.json A.json A.json
There are a lot more you can do with this utill just look at the documentation.

Implementing a command line interpreter

In terminal or cmd, you can write commands, in which there is a main command and then sub-commands, or arguments and stuff...like this:
cd Desktop\Folder
lst
Format E: /fs:FAT32
I want to create a C# console application that could execute predefined commands like this, but which could also split up main commands and sub-commands, in which some could be optional and some not. I have tried just taking all as string and then splitting it to array and creating if(s) and switch and cases, but it looks really bad and hardly manageable. I'm sure that in the OS's terminal or cmd it's build in another way. Could you help me understand the basic structure of such an application?
Here, have a look at this concept.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SharpConsole
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Welcome to SharpConsole. Type in a command.");
while (true)
{
Console.Write("$ ");
string command = Console.ReadLine();
string command_main = command.Split(new char[] { ' ' }).First();
string[] arguments = command.Split(new char[] { ' ' }).Skip(1).ToArray();
if (lCommands.ContainsKey(command_main))
{
Action<string[]> function_to_execute = null;
lCommands.TryGetValue(command_main, out function_to_execute);
function_to_execute(arguments);
}
else
Console.WriteLine("Command '" + command_main + "' not found");
}
}
private static Dictionary<string, Action<string[]>> lCommands =
new Dictionary<string, Action<string[]>>()
{
{ "help", HelpFunc },
{ "cp" , CopyFunc }
};
private static void CopyFunc(string[] obj)
{
if (obj.Length != 2) return;
Console.WriteLine("Copying " + obj[0] + " to " + obj[1]);
}
public static void HelpFunc(string[] args)
{
Console.WriteLine("===== SOME MEANINGFULL HELP ==== ");
}
}
}
The basic idea is to generalize the idea of a command. We have a Dictionary, where the key is a string (the command's name), and the value you get from the dictionary is a function of type Action<string[]>. Any function which has the signature void Function(string[]) can be used as this type. Then, you can set up this dictionary with a bunch of commands and route them to the functions you want. Each of these functions will receive an array of optional arguments. So here, the command "help" will be routed to the HelpFunc(). And the "cp" command e.g. will receive an array of filenames. The parsing of the command is always the same. We read a line, split it a space. The first string is the program's name, command_main here. If you skip the first string, you'll get an enumeration of all the other subcommands or switches you typed in. Then, a lookup in the dictionary is being done to see if there is such a command. If yes, we get the function and execute it with the arguments. If not, you should display "command not found" or something. All in all, this exercise can be minimized to looking up a function in a dictionary of possible command strings, then executing it. So a possible output is
Welcome to SharpConsole. Type in a command.
$ help
===== SOME MEANINGFULL HELP ====
$ cp file1 otherfile2
Copying file1 to otherfile2
$ python --version
Command 'python' not found
$ ...
LXSH
It's a command interpreter similar to CMD or Bash.
We've distributed it under MIT license, a shell with some functionalities in C# (.NET Core). You can contribute if you wish on
GitHub.
To solve the problem of matching a given token (part of the command line) with a builtin or a command, we use a dictionary.
However, we don't index the programs in the path for the moment. We just combine the name of the program with all the paths in the %PATH% variable.
Capture input
Expand environment variables, expand aliases
Try to match a builtin and run it if there is a match
Try to match with a program in %PATH% / $PATH
Run the program or display error
While you are unlikely to find the internal working of CMD (because it's closed source), you can find easily unix shell (bash, sh, zsh, etc..) information.
Links:
Bash Reference
Zsh Reference
TCSH Reference

Categories