1
1
// Copyright (c) Microsoft Corporation.
2
2
// Licensed under the MIT License.
3
3
4
- use crate :: discovery:: discovery_trait:: { DiscoveryFilter , DiscoveryKind , ResourceDiscovery } ;
4
+ use crate :: discovery:: {
5
+ discovery_trait:: { DiscoveryFilter , DiscoveryKind , ResourceDiscovery }
6
+ } ;
7
+ use crate :: { locked_is_empty, locked_extend, locked_clone, locked_get} ;
5
8
use crate :: dscresources:: dscresource:: { Capability , DscResource , ImplementedAs } ;
6
9
use crate :: dscresources:: resource_manifest:: { import_manifest, validate_semver, Kind , ResourceManifest , SchemaKind } ;
7
10
use crate :: dscresources:: command_resource:: invoke_command;
@@ -15,7 +18,7 @@ use rust_i18n::t;
15
18
use semver:: { Version , VersionReq } ;
16
19
use schemars:: JsonSchema ;
17
20
use serde:: { Deserialize , Serialize } ;
18
- use std:: collections:: { BTreeMap , HashSet , HashMap } ;
21
+ use std:: { collections:: { BTreeMap , HashMap , HashSet } , sync :: { LazyLock , RwLock } } ;
19
22
use std:: env;
20
23
use std:: ffi:: OsStr ;
21
24
use std:: fs;
@@ -30,19 +33,21 @@ use crate::util::get_exe_path;
30
33
const DSC_RESOURCE_EXTENSIONS : [ & str ; 3 ] = [ ".dsc.resource.json" , ".dsc.resource.yaml" , ".dsc.resource.yml" ] ;
31
34
const DSC_EXTENSION_EXTENSIONS : [ & str ; 3 ] = [ ".dsc.extension.json" , ".dsc.extension.yaml" , ".dsc.extension.yml" ] ;
32
35
36
+ // use BTreeMap so that the results are sorted by the typename, the Vec is sorted by version
37
+ static ADAPTERS : LazyLock < RwLock < BTreeMap < String , Vec < DscResource > > > > = LazyLock :: new ( || RwLock :: new ( BTreeMap :: new ( ) ) ) ;
38
+ static RESOURCES : LazyLock < RwLock < BTreeMap < String , Vec < DscResource > > > > = LazyLock :: new ( || RwLock :: new ( BTreeMap :: new ( ) ) ) ;
39
+ static EXTENSIONS : LazyLock < RwLock < BTreeMap < String , DscExtension > > > = LazyLock :: new ( || RwLock :: new ( BTreeMap :: new ( ) ) ) ;
40
+ static ADAPTED_RESOURCES : LazyLock < RwLock < BTreeMap < String , Vec < DscResource > > > > = LazyLock :: new ( || RwLock :: new ( BTreeMap :: new ( ) ) ) ;
41
+
33
42
#[ derive( Clone , Serialize , Deserialize , JsonSchema ) ]
34
43
pub enum ImportedManifest {
35
44
Resource ( DscResource ) ,
36
45
Extension ( DscExtension ) ,
37
46
}
38
47
48
+
39
49
#[ derive( Clone ) ]
40
50
pub struct CommandDiscovery {
41
- // use BTreeMap so that the results are sorted by the typename, the Vec is sorted by version
42
- adapters : BTreeMap < String , Vec < DscResource > > ,
43
- resources : BTreeMap < String , Vec < DscResource > > ,
44
- extensions : BTreeMap < String , DscExtension > ,
45
- adapted_resources : BTreeMap < String , Vec < DscResource > > ,
46
51
progress_format : ProgressFormat ,
47
52
}
48
53
@@ -72,18 +77,12 @@ impl CommandDiscovery {
72
77
#[ must_use]
73
78
pub fn new ( progress_format : ProgressFormat ) -> CommandDiscovery {
74
79
CommandDiscovery {
75
- adapters : BTreeMap :: new ( ) ,
76
- resources : BTreeMap :: new ( ) ,
77
- extensions : BTreeMap :: new ( ) ,
78
- adapted_resources : BTreeMap :: new ( ) ,
79
80
progress_format,
80
81
}
81
82
}
82
83
83
84
#[ must_use]
84
- pub fn get_extensions ( & self ) -> & BTreeMap < String , DscExtension > {
85
- & self . extensions
86
- }
85
+ pub fn get_extensions ( & self ) -> BTreeMap < String , DscExtension > { locked_clone ! ( EXTENSIONS ) }
87
86
88
87
fn get_resource_path_setting ( ) -> Result < ResourcePathSetting , DscError >
89
88
{
@@ -307,7 +306,7 @@ impl ResourceDiscovery for CommandDiscovery {
307
306
match kind {
308
307
DiscoveryKind :: Resource => {
309
308
// Now we need to call discover extensions and add those resource to the list of resources
310
- for extension in self . extensions . values ( ) {
309
+ for extension in locked_clone ! ( EXTENSIONS ) . values ( ) {
311
310
if extension. capabilities . contains ( & ExtensionCapability :: Discover ) {
312
311
debug ! ( "{}" , t!( "discovery.commandDiscovery.callingExtension" , extension = extension. type_name) ) ;
313
312
let discovered_resources = match extension. discover ( ) {
@@ -326,26 +325,27 @@ impl ResourceDiscovery for CommandDiscovery {
326
325
}
327
326
}
328
327
}
329
- self . adapters = adapters;
330
- self . resources = resources;
328
+ locked_extend ! ( ADAPTERS , adapters) ;
329
+ locked_extend ! ( RESOURCES , resources) ;
331
330
} ,
332
331
DiscoveryKind :: Extension => {
333
- self . extensions = extensions;
332
+ locked_extend ! ( EXTENSIONS , extensions) ;
334
333
}
335
334
}
336
335
337
336
Ok ( ( ) )
338
337
}
339
338
340
339
fn discover_adapted_resources ( & mut self , name_filter : & str , adapter_filter : & str ) -> Result < ( ) , DscError > {
341
- if self . resources . is_empty ( ) && self . adapters . is_empty ( ) {
340
+ if locked_is_empty ! ( RESOURCES ) && locked_is_empty ! ( ADAPTERS ) {
342
341
self . discover ( & DiscoveryKind :: Resource , "*" ) ?;
343
342
}
344
343
345
- if self . adapters . is_empty ( ) {
344
+ if locked_is_empty ! ( ADAPTERS ) {
346
345
return Ok ( ( ) ) ;
347
346
}
348
347
348
+ let adapters = locked_clone ! ( ADAPTERS ) ;
349
349
let regex_str = convert_wildcard_to_regex ( adapter_filter) ;
350
350
debug ! ( "Using regex {regex_str} as filter for adapter name" ) ;
351
351
let mut regex_builder = RegexBuilder :: new ( & regex_str) ;
@@ -362,13 +362,13 @@ impl ResourceDiscovery for CommandDiscovery {
362
362
return Err ( DscError :: Operation ( "Could not build Regex filter for resource name" . to_string ( ) ) ) ;
363
363
} ;
364
364
365
- let mut progress = ProgressBar :: new ( self . adapters . len ( ) as u64 , self . progress_format ) ?;
365
+ let mut progress = ProgressBar :: new ( adapters. len ( ) as u64 , self . progress_format ) ?;
366
366
progress. write_activity ( "Searching for adapted resources" ) ;
367
367
368
368
let mut adapted_resources = BTreeMap :: < String , Vec < DscResource > > :: new ( ) ;
369
369
370
370
let mut found_adapter: bool = false ;
371
- for ( adapter_name, adapters) in & self . adapters {
371
+ for ( adapter_name, adapters) in & adapters {
372
372
for adapter in adapters {
373
373
progress. write_increment ( 1 ) ;
374
374
@@ -437,7 +437,7 @@ impl ResourceDiscovery for CommandDiscovery {
437
437
return Err ( DscError :: AdapterNotFound ( adapter_filter. to_string ( ) ) ) ;
438
438
}
439
439
440
- self . adapted_resources = adapted_resources;
440
+ locked_extend ! ( ADAPTED_RESOURCES , adapted_resources) ;
441
441
442
442
Ok ( ( ) )
443
443
}
@@ -447,26 +447,27 @@ impl ResourceDiscovery for CommandDiscovery {
447
447
if * kind == DiscoveryKind :: Resource {
448
448
if adapter_name_filter. is_empty ( ) {
449
449
self . discover ( kind, type_name_filter) ?;
450
- for ( resource_name, resources_vec) in & self . resources {
450
+ for ( resource_name, resources_vec) in & locked_clone ! ( RESOURCES ) {
451
451
resources. insert ( resource_name. clone ( ) , resources_vec. iter ( ) . map ( |r| ImportedManifest :: Resource ( r. clone ( ) ) ) . collect ( ) ) ;
452
452
}
453
- for ( adapter_name, adapter_vec) in & self . adapters {
453
+ for ( adapter_name, adapter_vec) in & locked_clone ! ( ADAPTERS ) {
454
454
resources. insert ( adapter_name. clone ( ) , adapter_vec. iter ( ) . map ( |r| ImportedManifest :: Resource ( r. clone ( ) ) ) . collect ( ) ) ;
455
455
}
456
456
} else {
457
457
self . discover ( kind, "*" ) ?;
458
458
self . discover_adapted_resources ( type_name_filter, adapter_name_filter) ?;
459
459
460
460
// add/update found adapted resources to the lookup_table
461
- add_resources_to_lookup_table ( & self . adapted_resources ) ;
461
+ let adapted_resources = locked_clone ! ( ADAPTED_RESOURCES ) ;
462
+ add_resources_to_lookup_table ( & adapted_resources) ;
462
463
463
- for ( adapted_name, adapted_vec) in & self . adapted_resources {
464
+ for ( adapted_name, adapted_vec) in & adapted_resources {
464
465
resources. insert ( adapted_name. clone ( ) , adapted_vec. iter ( ) . map ( |r| ImportedManifest :: Resource ( r. clone ( ) ) ) . collect ( ) ) ;
465
466
}
466
467
}
467
468
} else {
468
469
self . discover ( kind, type_name_filter) ?;
469
- for ( extension_name, extension) in & self . extensions {
470
+ for ( extension_name, extension) in & locked_clone ! ( EXTENSIONS ) {
470
471
resources. insert ( extension_name. clone ( ) , vec ! [ ImportedManifest :: Extension ( extension. clone( ) ) ] ) ;
471
472
}
472
473
}
@@ -476,16 +477,18 @@ impl ResourceDiscovery for CommandDiscovery {
476
477
477
478
fn find_resources ( & mut self , required_resource_types : & [ DiscoveryFilter ] ) -> Result < BTreeMap < String , Vec < DscResource > > , DscError > {
478
479
debug ! ( "{}" , t!( "discovery.commandDiscovery.searchingForResources" , resources = required_resource_types : { : ?} ) ) ;
479
- self . discover ( & DiscoveryKind :: Resource , "*" ) ?;
480
+ if locked_is_empty ! ( RESOURCES ) {
481
+ self . discover ( & DiscoveryKind :: Resource , "*" ) ?;
482
+ }
480
483
let mut found_resources = BTreeMap :: < String , Vec < DscResource > > :: new ( ) ;
481
484
let mut required_resources = HashMap :: < DiscoveryFilter , bool > :: new ( ) ;
482
485
for filter in required_resource_types {
483
486
required_resources. insert ( filter. clone ( ) , false ) ;
484
487
}
485
488
486
489
for filter in required_resource_types {
487
- if let Some ( resources) = self . resources . get ( filter. resource_type ( ) ) {
488
- filter_resources ( & mut found_resources, & mut required_resources, resources, filter) ;
490
+ if let Some ( resources) = locked_get ! ( RESOURCES , filter. resource_type( ) ) {
491
+ filter_resources ( & mut found_resources, & mut required_resources, & resources, filter) ;
489
492
}
490
493
if required_resources. values ( ) . all ( |& v| v) {
491
494
break ;
@@ -498,12 +501,12 @@ impl ResourceDiscovery for CommandDiscovery {
498
501
}
499
502
500
503
// now go through the adapters, this is for implicit adapters so version can't be specified so use latest version
501
- for adapter_name in self . adapters . clone ( ) . keys ( ) {
504
+ for adapter_name in locked_clone ! ( ADAPTERS ) . keys ( ) {
502
505
self . discover_adapted_resources ( "*" , adapter_name) ?;
503
- add_resources_to_lookup_table ( & self . adapted_resources ) ;
506
+ add_resources_to_lookup_table ( & locked_clone ! ( ADAPTED_RESOURCES ) ) ;
504
507
for filter in required_resource_types {
505
- if let Some ( adapted_resources) = self . adapted_resources . get ( filter. resource_type ( ) ) {
506
- filter_resources ( & mut found_resources, & mut required_resources, adapted_resources, filter) ;
508
+ if let Some ( adapted_resources) = locked_get ! ( ADAPTED_RESOURCES , filter. resource_type( ) ) {
509
+ filter_resources ( & mut found_resources, & mut required_resources, & adapted_resources, filter) ;
507
510
}
508
511
if required_resources. values ( ) . all ( |& v| v) {
509
512
break ;
@@ -518,10 +521,10 @@ impl ResourceDiscovery for CommandDiscovery {
518
521
}
519
522
520
523
fn get_extensions ( & mut self ) -> Result < BTreeMap < String , DscExtension > , DscError > {
521
- if self . extensions . is_empty ( ) {
524
+ if locked_is_empty ! ( EXTENSIONS ) {
522
525
self . discover ( & DiscoveryKind :: Extension , "*" ) ?;
523
526
}
524
- Ok ( self . extensions . clone ( ) )
527
+ Ok ( locked_clone ! ( EXTENSIONS ) )
525
528
}
526
529
}
527
530
0 commit comments