1
1
// Copyright (c) Microsoft Corporation.
2
2
// Licensed under the MIT License.
3
3
4
- use crate :: args:: { ConfigSubCommand , DscType , ExtensionSubCommand , GetOutputFormat , ListOutputFormat , OutputFormat , ResourceSubCommand } ;
4
+ use crate :: args:: { ConfigSubCommand , SchemaType , ExtensionSubCommand , FunctionSubCommand , GetOutputFormat , ListOutputFormat , OutputFormat , ResourceSubCommand } ;
5
5
use crate :: resolve:: { get_contents, Include } ;
6
6
use crate :: resource_command:: { get_resource, self } ;
7
7
use crate :: tablewriter:: Table ;
8
8
use crate :: util:: { get_input, get_schema, in_desired_state, set_dscconfigroot, validate_json, write_object, DSC_CONFIG_ROOT , EXIT_DSC_ASSERTION_FAILED , EXIT_DSC_ERROR , EXIT_INVALID_ARGS , EXIT_INVALID_INPUT , EXIT_JSON_ERROR } ;
9
+ use dsc_lib:: functions:: AcceptedArgKind ;
9
10
use dsc_lib:: {
10
11
configure:: {
11
12
config_doc:: {
@@ -28,8 +29,11 @@ use dsc_lib::{
28
29
dscresources:: dscresource:: { Capability , ImplementedAs , Invoke } ,
29
30
dscresources:: resource_manifest:: { import_manifest, ResourceManifest } ,
30
31
extensions:: dscextension:: Capability as ExtensionCapability ,
32
+ functions:: FunctionDispatcher ,
31
33
progress:: ProgressFormat ,
34
+ util:: convert_wildcard_to_regex,
32
35
} ;
36
+ use regex:: RegexBuilder ;
33
37
use rust_i18n:: t;
34
38
use std:: {
35
39
collections:: HashMap ,
@@ -473,7 +477,7 @@ pub fn config(subcommand: &ConfigSubCommand, parameters: &Option<String>, parame
473
477
pub fn validate_config ( config : & Configuration , progress_format : ProgressFormat ) -> Result < ( ) , DscError > {
474
478
// first validate against the config schema
475
479
debug ! ( "{}" , t!( "subcommand.validatingConfiguration" ) ) ;
476
- let schema = serde_json:: to_value ( get_schema ( DscType :: Configuration ) ) ?;
480
+ let schema = serde_json:: to_value ( get_schema ( SchemaType :: Configuration ) ) ?;
477
481
let config_value = serde_json:: to_value ( config) ?;
478
482
validate_json ( "Configuration" , & schema, & config_value) ?;
479
483
let mut dsc = DscManager :: new ( ) ?;
@@ -562,6 +566,15 @@ pub fn extension(subcommand: &ExtensionSubCommand, progress_format: ProgressForm
562
566
}
563
567
}
564
568
569
+ pub fn function ( subcommand : & FunctionSubCommand ) {
570
+ let functions = FunctionDispatcher :: new ( ) ;
571
+ match subcommand {
572
+ FunctionSubCommand :: List { function_name, output_format } => {
573
+ list_functions ( & functions, function_name. as_ref ( ) , output_format. as_ref ( ) ) ;
574
+ } ,
575
+ }
576
+ }
577
+
565
578
#[ allow( clippy:: too_many_lines) ]
566
579
pub fn resource ( subcommand : & ResourceSubCommand , progress_format : ProgressFormat ) {
567
580
let mut dsc = match DscManager :: new ( ) {
@@ -632,10 +645,10 @@ fn list_extensions(dsc: &mut DscManager, extension_name: Option<&String>, format
632
645
let mut include_separator = false ;
633
646
for manifest_resource in dsc. list_available ( & DiscoveryKind :: Extension , extension_name. unwrap_or ( & String :: from ( "*" ) ) , "" , progress_format) {
634
647
if let ImportedManifest :: Extension ( extension) = manifest_resource {
635
- let mut capabilities = "-" . to_string ( ) ;
636
648
let capability_types = [
637
649
( ExtensionCapability :: Discover , "d" ) ,
638
650
] ;
651
+ let mut capabilities = "-" . repeat ( capability_types. len ( ) ) ;
639
652
640
653
for ( i, ( capability, letter) ) in capability_types. iter ( ) . enumerate ( ) {
641
654
if extension. capabilities . contains ( capability) {
@@ -680,6 +693,97 @@ fn list_extensions(dsc: &mut DscManager, extension_name: Option<&String>, format
680
693
}
681
694
}
682
695
696
+ fn list_functions ( functions : & FunctionDispatcher , function_name : Option < & String > , output_format : Option < & ListOutputFormat > ) {
697
+ let mut write_table = false ;
698
+ let mut table = Table :: new ( & [
699
+ t ! ( "subcommand.tableHeader_functionCategory" ) . to_string ( ) . as_ref ( ) ,
700
+ t ! ( "subcommand.tableHeader_functionName" ) . to_string ( ) . as_ref ( ) ,
701
+ t ! ( "subcommand.tableHeader_minArgs" ) . to_string ( ) . as_ref ( ) ,
702
+ t ! ( "subcommand.tableHeader_maxArgs" ) . to_string ( ) . as_ref ( ) ,
703
+ t ! ( "subcommand.tableHeader_argTypes" ) . to_string ( ) . as_ref ( ) ,
704
+ t ! ( "subcommand.tableHeader_description" ) . to_string ( ) . as_ref ( ) ,
705
+ ] ) ;
706
+ if output_format. is_none ( ) && io:: stdout ( ) . is_terminal ( ) {
707
+ // write as table if format is not specified and interactive
708
+ write_table = true ;
709
+ }
710
+ let mut include_separator = false ;
711
+ let accepted_arg_types= [
712
+ ( AcceptedArgKind :: Array , "a" ) ,
713
+ ( AcceptedArgKind :: Boolean , "b" ) ,
714
+ ( AcceptedArgKind :: Number , "n" ) ,
715
+ ( AcceptedArgKind :: String , "s" ) ,
716
+ ( AcceptedArgKind :: Object , "o" ) ,
717
+ ] ;
718
+
719
+ let asterisks = String :: from ( "*" ) ;
720
+ let name = function_name. unwrap_or ( & asterisks) ;
721
+ let regex_str = convert_wildcard_to_regex ( name) ;
722
+ let mut regex_builder = RegexBuilder :: new ( & regex_str) ;
723
+ regex_builder. case_insensitive ( true ) ;
724
+ let Ok ( regex) = regex_builder. build ( ) else {
725
+ error ! ( "{}: {}" , t!( "subcommand.invalidFunctionFilter" ) , regex_str) ;
726
+ exit ( EXIT_INVALID_ARGS ) ;
727
+ } ;
728
+
729
+ let mut functions_list = functions. list ( ) ;
730
+ functions_list. sort ( ) ;
731
+ for function in functions_list. into_iter ( ) {
732
+ if !regex. is_match ( & function. name ) {
733
+ continue ;
734
+ }
735
+
736
+ if write_table {
737
+ // construct arg_types from '-' times number of accepted_arg_types
738
+ let mut arg_types = "-" . repeat ( accepted_arg_types. len ( ) ) ;
739
+ for ( i, ( arg_type, letter) ) in accepted_arg_types. iter ( ) . enumerate ( ) {
740
+ if function. accepted_arg_types . contains ( arg_type) {
741
+ arg_types. replace_range ( i..=i, letter) ;
742
+ }
743
+ }
744
+
745
+ let max_args = if function. max_args == usize:: MAX {
746
+ t ! ( "subcommand.maxInt" ) . to_string ( )
747
+ } else {
748
+ function. max_args . to_string ( )
749
+ } ;
750
+
751
+ table. add_row ( vec ! [
752
+ function. category. to_string( ) ,
753
+ function. name,
754
+ function. min_args. to_string( ) ,
755
+ max_args,
756
+ arg_types,
757
+ function. description
758
+ ] ) ;
759
+ }
760
+ else {
761
+ let json = match serde_json:: to_string ( & function) {
762
+ Ok ( json) => json,
763
+ Err ( err) => {
764
+ error ! ( "JSON: {err}" ) ;
765
+ exit ( EXIT_JSON_ERROR ) ;
766
+ }
767
+ } ;
768
+ let format = match output_format {
769
+ Some ( ListOutputFormat :: Json ) => Some ( OutputFormat :: Json ) ,
770
+ Some ( ListOutputFormat :: PrettyJson ) => Some ( OutputFormat :: PrettyJson ) ,
771
+ Some ( ListOutputFormat :: Yaml ) => Some ( OutputFormat :: Yaml ) ,
772
+ _ => None ,
773
+ } ;
774
+ write_object ( & json, format. as_ref ( ) , include_separator) ;
775
+ include_separator = true ;
776
+ // insert newline separating instances if writing to console
777
+ if io:: stdout ( ) . is_terminal ( ) { println ! ( ) ; }
778
+ }
779
+ }
780
+
781
+ if write_table {
782
+ let truncate = output_format != Some ( & ListOutputFormat :: TableNoTruncate ) ;
783
+ table. print ( truncate) ;
784
+ }
785
+ }
786
+
683
787
fn list_resources ( dsc : & mut DscManager , resource_name : Option < & String > , adapter_name : Option < & String > , description : Option < & String > , tags : Option < & Vec < String > > , format : Option < & ListOutputFormat > , progress_format : ProgressFormat ) {
684
788
let mut write_table = false ;
685
789
let mut table = Table :: new ( & [
@@ -697,7 +801,6 @@ fn list_resources(dsc: &mut DscManager, resource_name: Option<&String>, adapter_
697
801
let mut include_separator = false ;
698
802
for manifest_resource in dsc. list_available ( & DiscoveryKind :: Resource , resource_name. unwrap_or ( & String :: from ( "*" ) ) , adapter_name. unwrap_or ( & String :: new ( ) ) , progress_format) {
699
803
if let ImportedManifest :: Resource ( resource) = manifest_resource {
700
- let mut capabilities = "--------" . to_string ( ) ;
701
804
let capability_types = [
702
805
( Capability :: Get , "g" ) ,
703
806
( Capability :: Set , "s" ) ,
@@ -708,6 +811,7 @@ fn list_resources(dsc: &mut DscManager, resource_name: Option<&String>, adapter_
708
811
( Capability :: Export , "e" ) ,
709
812
( Capability :: Resolve , "r" ) ,
710
813
] ;
814
+ let mut capabilities = "-" . repeat ( capability_types. len ( ) ) ;
711
815
712
816
for ( i, ( capability, letter) ) in capability_types. iter ( ) . enumerate ( ) {
713
817
if resource. capabilities . contains ( capability) {
0 commit comments