You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -110,43 +110,10 @@ Its command-line signature looks like this:
110
110
$ ./myapp <value> [--base <base>]
111
111
```
112
112
113
-
To expose your command as an entry point and turn the program into a command-line interface, modify the `Main()` method so that it delegates its execution to an instance of `CommandLineApplication`.
114
-
Use the `CommandLineApplicationBuilder` helper to create and configure an application in a series of fluent instructions:
113
+
That's all you need — **CliFx** uses source generators to discover commands and produce the `Main()` method automatically, so you don't have to write any boilerplate.
114
+
If you wish to customize the application's behavior, you can provide your own `Main()` method as described in the [application configuration](#application-configuration) section.
115
115
116
-
```csharp
117
-
usingCliFx;
118
-
119
-
publicstaticclassProgram
120
-
{
121
-
// This Main() method will be generated automatically if you don't implement one yourself
122
-
publicstaticasyncTask<int> Main() =>
123
-
awaitnewCommandLineApplicationBuilder()
124
-
// Registers all accessible commands from the current assembly
125
-
.AddCommandsFromThisAssembly()
126
-
// Creates the application instance
127
-
.Build()
128
-
// Runs the application, resolving command-line arguments and
129
-
// environment variables automatically.
130
-
.RunAsync();
131
-
}
132
-
```
133
-
134
-
> [!TIP]
135
-
> If your program does not have a `Main()` method, **CliFx** will generate one for you automatically.
136
-
> You only need to implement your own if you wish to customize the configuration of the application.
137
-
138
-
> [!IMPORTANT]
139
-
> Ensure that your `Main()` method returns the integer exit code provided by `CommandLineApplication.RunAsync()`, as shown in the example.
140
-
> Exit code is used to communicate execution result to the parent process, so it's important that your program properly propagates it.
141
-
142
-
> [!NOTE]
143
-
> When calling `CommandLineApplication.RunAsync()`, **CliFx** resolves command-line arguments and environment variables from `Environment.GetCommandLineArgs()` and `Environment.GetEnvironmentVariables()` respectively.
144
-
> You can also provide them explicitly using one of the other available overloads.
145
-
146
-
For the command to be available for execution, it needs to be registered with the application.
147
-
The above example relies on `AddCommandsFromThisAssembly()` for that, which automatically detects and registers all accessible commands from the current assembly.
148
-
149
-
Now, the user can execute `LogCommand` by running the application and passing an argument to the `value` parameter:
116
+
With the above command defined, the user can execute it by running the application and passing an argument to the `value` parameter:
150
117
151
118
```console
152
119
$ ./myapp 10000
@@ -690,63 +657,6 @@ These rules also make the order of arguments important — the command-line stri
690
657
$ ./myapp [command] [...parameters] [...options]
691
658
```
692
659
693
-
### Command instantiation
694
-
695
-
Because **CliFx** takes responsibility for the application's entire lifecycle, it needs to be capable of instantiating commands at run time.
696
-
To facilitate that, it uses an interface called `ITypeInstantiator` that determines how to create a new instance of a given type.
697
-
698
-
The default implementation of `ITypeInstantiator` only supports types that have public parameter-less constructors, which is sufficient for most common scenarios.
699
-
However, in some cases you may want to define a custom instantiator, for example when integrating with an external dependency container.
700
-
701
-
To do that, pass a custom `ITypeInstantiator` or a factory delegate to the `UseTypeInstantiator(...)` method when building the application:
702
-
703
-
```csharp
704
-
publicstaticclassProgram
705
-
{
706
-
publicstaticasyncTask<int> Main() =>
707
-
awaitnewCommandLineApplicationBuilder()
708
-
.AddCommandsFromThisAssembly()
709
-
.UseTypeInstantiator(type=>
710
-
{
711
-
varinstance=MyTypeFactory.Create(type);
712
-
returninstance;
713
-
})
714
-
.Build()
715
-
.RunAsync();
716
-
}
717
-
```
718
-
719
-
This method also supports `IServiceProvider` through various overloads, which allows you to directly integrate dependency containers that implement this interface.
720
-
For example, this is how to configure your application to use [`Microsoft.Extensions.DependencyInjection`](https://nuget.org/packages/Microsoft.Extensions.DependencyInjection) as the type instantiator in **CliFx**:
721
-
722
-
```csharp
723
-
publicstaticclassProgram
724
-
{
725
-
publicstaticasyncTask<int> Main() =>
726
-
awaitnewCommandLineApplicationBuilder()
727
-
.AddCommandsFromThisAssembly()
728
-
.UseTypeInstantiator(commands=>
729
-
{
730
-
varservices=newServiceCollection();
731
-
732
-
// Register services
733
-
services.AddSingleton<MyService>();
734
-
735
-
// Register commands
736
-
foreach (varcommandincommands)
737
-
services.AddTransient(command.Type);
738
-
739
-
returnservices.BuildServiceProvider();
740
-
})
741
-
.Build()
742
-
.RunAsync();
743
-
}
744
-
```
745
-
746
-
> [!NOTE]
747
-
> If you want to use certain advanced features provided by `Microsoft.Extensions.DependencyInjection`, you may need to do a bit of extra work to configure the container properly.
748
-
> For example, to leverage support for keyed services, you need to [manually register an implementation of `IKeyedServiceProvider`](https://github.com/Tyrrrz/CliFx/issues/148).
749
-
750
660
### Command routing
751
661
752
662
Command-line applications often provide the user with more than just a single command, facilitating a variety of different workflows.
@@ -836,7 +746,7 @@ You can run `myapp cmd1 [command] --help` to show help for a specific command.
836
746
> Defining the default (unnamed) command is not required.
837
747
> If it's absent, **CliFx** will generate one for you automatically.
838
748
839
-
### Reporting errors
749
+
### Error reporting
840
750
841
751
Commands in **CliFx** do not directly return exit codes, but instead communicate execution errors via `CommandException`.
842
752
This special exception type can be used to print an error message to the console, return a specific exit code, and also optionally show help text for the current command:
@@ -1001,19 +911,110 @@ public async Task ConcatCommand_executes_successfully()
1001
911
}
1002
912
```
1003
913
1004
-
### Debug and preview mode
914
+
### Application configuration
915
+
916
+
By default, **CliFx** source-generates a `Main()` method that builds and runs the application with standard settings.
917
+
If you need to customize this behavior, provide your own `Main()` method and use `CommandLineApplicationBuilder` to configure the application:
918
+
919
+
```csharp
920
+
usingCliFx;
921
+
922
+
publicstaticclassProgram
923
+
{
924
+
publicstaticasyncTask<int> Main() =>
925
+
awaitnewCommandLineApplicationBuilder()
926
+
.AddCommandsFromThisAssembly()
927
+
.SetTitle("My App")
928
+
.SetVersion("1.0.0")
929
+
.Build()
930
+
.RunAsync();
931
+
}
932
+
```
933
+
934
+
> [!IMPORTANT]
935
+
> Ensure that your `Main()` method returns the integer exit code provided by `CommandLineApplication.RunAsync()`, as shown in the example.
936
+
> Exit code is used to communicate execution result to the parent process, so it's important that your program properly propagates it.
937
+
938
+
By default, `CommandLineApplication.RunAsync()` resolves command-line arguments and environment variables from `Environment.GetCommandLineArgs()` and `Environment.GetEnvironmentVariables()` respectively, but you can also provide them explicitly using one of the other available overloads.
939
+
940
+
The following configuration methods are available on `CommandLineApplicationBuilder`:
941
+
942
+
-`AddCommand(...)` / `AddCommands(...)` — registers one or more commands with the application. Alternatively, `AddCommandsFromThisAssembly()` detects and registers all accessible commands from the current assembly.
943
+
-`SetTitle(...)` — sets the application title displayed in the help text. Defaults to the assembly name.
944
+
-`SetExecutableName(...)` — sets the executable name displayed in the help text. Defaults to the assembly file name.
945
+
-`SetVersion(...)` — sets the version displayed in the help text and when version info is requested. Defaults to the assembly version.
946
+
-`SetDescription(...)` — sets the application description displayed in the help text.
947
+
-`UseConsole(...)` — provides a custom `IConsole` implementation, useful for [testing](#testing).
948
+
-`UseTypeInstantiator(...)` — provides a custom type instantiator for creating command instances. See [dependency injection](#dependency-injection).
949
+
-`AllowDebugMode(...)` / `AllowPreviewMode(...)` — enables diagnostic modes. See [debug and preview mode](#debug-and-preview-mode).
950
+
951
+
#### Dependency injection
952
+
953
+
Because **CliFx** takes responsibility for the application's entire lifecycle, it needs to be capable of instantiating commands at run time.
954
+
By default, only types with public parameter-less constructors are supported, which is sufficient for most common scenarios.
955
+
956
+
When integrating with an external dependency container, pass a custom `ITypeInstantiator` or a factory delegate to `UseTypeInstantiator(...)`:
957
+
958
+
```csharp
959
+
publicstaticclassProgram
960
+
{
961
+
publicstaticasyncTask<int> Main() =>
962
+
awaitnewCommandLineApplicationBuilder()
963
+
.AddCommandsFromThisAssembly()
964
+
.UseTypeInstantiator(type=>
965
+
{
966
+
varinstance=MyTypeFactory.Create(type);
967
+
returninstance;
968
+
})
969
+
.Build()
970
+
.RunAsync();
971
+
}
972
+
```
973
+
974
+
This method also supports `IServiceProvider` through various overloads, which allows you to directly integrate dependency containers that implement this interface.
975
+
For example, this is how to configure your application to use [`Microsoft.Extensions.DependencyInjection`](https://nuget.org/packages/Microsoft.Extensions.DependencyInjection) as the type instantiator in **CliFx**:
976
+
977
+
```csharp
978
+
publicstaticclassProgram
979
+
{
980
+
publicstaticasyncTask<int> Main() =>
981
+
awaitnewCommandLineApplicationBuilder()
982
+
.AddCommandsFromThisAssembly()
983
+
.UseTypeInstantiator(commands=>
984
+
{
985
+
varservices=newServiceCollection();
986
+
987
+
// Register services
988
+
services.AddSingleton<MyService>();
989
+
990
+
// Register commands
991
+
foreach (varcommandincommands)
992
+
services.AddTransient(command.Type);
993
+
994
+
returnservices.BuildServiceProvider();
995
+
})
996
+
.Build()
997
+
.RunAsync();
998
+
}
999
+
```
1000
+
1001
+
> [!NOTE]
1002
+
> If you want to use certain advanced features provided by `Microsoft.Extensions.DependencyInjection`, you may need to do a bit of extra work to configure the container properly.
1003
+
> For example, to leverage support for keyed services, you need to [manually register an implementation of `IKeyedServiceProvider`](https://github.com/Tyrrrz/CliFx/issues/148).
1004
+
1005
+
#### Debug and preview mode
1005
1006
1006
1007
When troubleshooting issues, you may find it useful to run your application in debug or preview mode.
1007
-
These modes are activated through environment variables, which you can configure using `AllowDebugMode(...)` and `AllowPreviewMode(...)` methods on `CommandLineApplicationBuilder`:
1008
+
These modes are activated through environment variables, configured using `AllowDebugMode(...)` and `AllowPreviewMode(...)`:
1008
1009
1009
1010
```csharp
1010
-
varapplication=newCommandLineApplicationBuilder()
1011
-
.AddCommandsFromThisAssembly()
1012
-
// Enable debug mode via the CLIFX_DEBUG environment variable
1013
-
.AllowDebugMode("CLIFX_DEBUG")
1014
-
// Enable preview mode via the CLIFX_PREVIEW environment variable
0 commit comments