@@ -5,13 +5,14 @@ use std::{
5
5
6
6
use anyhow:: { anyhow, Context } ;
7
7
use indexmap:: IndexMap ;
8
+ use itertools:: Itertools ;
8
9
use regex:: Regex ;
9
10
10
11
use crate :: {
11
12
constraints:: StringConstraints ,
12
13
reader:: {
13
- RawExtraOutput , RawParameter , RawTemplateManifest , RawTemplateManifestV1 ,
14
- RawTemplateVariant ,
14
+ RawCondition , RawConditional , RawExtraOutput , RawParameter , RawTemplateManifest ,
15
+ RawTemplateManifestV1 , RawTemplateVariant ,
15
16
} ,
16
17
run:: { Run , RunOptions } ,
17
18
store:: TemplateLayout ,
@@ -96,6 +97,20 @@ pub(crate) struct TemplateVariant {
96
97
skip_files : Vec < String > ,
97
98
skip_parameters : Vec < String > ,
98
99
snippets : HashMap < String , String > ,
100
+ conditions : Vec < Conditional > ,
101
+ }
102
+
103
+ #[ derive( Clone , Debug ) ]
104
+ pub ( crate ) struct Conditional {
105
+ condition : Condition ,
106
+ skip_files : Vec < String > ,
107
+ skip_parameters : Vec < String > ,
108
+ skip_snippets : Vec < String > ,
109
+ }
110
+
111
+ #[ derive( Clone , Debug ) ]
112
+ pub ( crate ) enum Condition {
113
+ ManifestEntryExists ( Vec < String > ) ,
99
114
}
100
115
101
116
#[ derive( Clone , Debug , Eq , PartialEq , Hash ) ]
@@ -241,9 +256,12 @@ impl Template {
241
256
}
242
257
}
243
258
244
- fn variant ( & self , variant_info : & TemplateVariantInfo ) -> Option < & TemplateVariant > {
259
+ // TODO: we should resolve this once at the start of Run and then use that forever
260
+ fn variant ( & self , variant_info : & TemplateVariantInfo ) -> Option < TemplateVariant > {
245
261
let kind = variant_info. kind ( ) ;
246
- self . variants . get ( & kind)
262
+ self . variants
263
+ . get ( & kind)
264
+ . map ( |vt| vt. resolve_conditions ( variant_info) )
247
265
}
248
266
249
267
pub ( crate ) fn parameters (
@@ -253,7 +271,7 @@ impl Template {
253
271
let variant = self . variant ( variant_kind) . unwrap ( ) ; // TODO: for now
254
272
self . parameters
255
273
. iter ( )
256
- . filter ( |p| !variant. skip_parameter ( p) )
274
+ . filter ( move |p| !variant. skip_parameter ( p) )
257
275
}
258
276
259
277
pub ( crate ) fn parameter ( & self , name : impl AsRef < str > ) -> Option < & TemplateParameter > {
@@ -277,9 +295,9 @@ impl Template {
277
295
self . variants . contains_key ( & variant. kind ( ) )
278
296
}
279
297
280
- pub ( crate ) fn snippets ( & self , variant_kind : & TemplateVariantInfo ) -> & HashMap < String , String > {
298
+ pub ( crate ) fn snippets ( & self , variant_kind : & TemplateVariantInfo ) -> HashMap < String , String > {
281
299
let variant = self . variant ( variant_kind) . unwrap ( ) ; // TODO: for now
282
- & variant. snippets
300
+ variant. snippets
283
301
}
284
302
285
303
/// Creates a runner for the template, governed by the given options. Call
@@ -355,6 +373,29 @@ impl Template {
355
373
skip_files : raw. skip_files . unwrap_or_default ( ) ,
356
374
skip_parameters : raw. skip_parameters . unwrap_or_default ( ) ,
357
375
snippets : raw. snippets . unwrap_or_default ( ) ,
376
+ conditions : raw
377
+ . conditions
378
+ . unwrap_or_default ( )
379
+ . into_values ( )
380
+ . map ( Self :: parse_conditional)
381
+ . collect ( ) ,
382
+ }
383
+ }
384
+
385
+ fn parse_conditional ( conditional : RawConditional ) -> Conditional {
386
+ Conditional {
387
+ condition : Self :: parse_condition ( conditional. condition ) ,
388
+ skip_files : conditional. skip_files . unwrap_or_default ( ) ,
389
+ skip_parameters : conditional. skip_parameters . unwrap_or_default ( ) ,
390
+ skip_snippets : conditional. skip_snippets . unwrap_or_default ( ) ,
391
+ }
392
+ }
393
+
394
+ fn parse_condition ( condition : RawCondition ) -> Condition {
395
+ match condition {
396
+ RawCondition :: ManifestEntryExists ( path) => {
397
+ Condition :: ManifestEntryExists ( path. split ( '.' ) . map ( |s| s. to_string ( ) ) . collect_vec ( ) )
398
+ }
358
399
}
359
400
}
360
401
@@ -528,6 +569,43 @@ impl TemplateVariant {
528
569
pub ( crate ) fn skip_parameter ( & self , parameter : & TemplateParameter ) -> bool {
529
570
self . skip_parameters . iter ( ) . any ( |p| & parameter. id == p)
530
571
}
572
+
573
+ fn resolve_conditions ( & self , variant_info : & TemplateVariantInfo ) -> Self {
574
+ let mut resolved = self . clone ( ) ;
575
+ for condition in & self . conditions {
576
+ if condition. condition . is_true ( variant_info) {
577
+ resolved
578
+ . skip_files
579
+ . append ( & mut condition. skip_files . clone ( ) ) ;
580
+ resolved
581
+ . skip_parameters
582
+ . append ( & mut condition. skip_parameters . clone ( ) ) ;
583
+ resolved
584
+ . snippets
585
+ . retain ( |id, _| !condition. skip_snippets . contains ( id) ) ;
586
+ }
587
+ }
588
+ resolved
589
+ }
590
+ }
591
+
592
+ impl Condition {
593
+ fn is_true ( & self , variant_info : & TemplateVariantInfo ) -> bool {
594
+ match self {
595
+ Self :: ManifestEntryExists ( path) => match variant_info {
596
+ TemplateVariantInfo :: NewApplication => false ,
597
+ TemplateVariantInfo :: AddComponent { manifest_path } => {
598
+ let Ok ( toml_text) = std:: fs:: read_to_string ( manifest_path) else {
599
+ return false ;
600
+ } ;
601
+ let Ok ( table) = toml:: from_str :: < toml:: Value > ( & toml_text) else {
602
+ return false ;
603
+ } ;
604
+ get_at ( table, path) . is_some ( )
605
+ }
606
+ } ,
607
+ }
608
+ }
531
609
}
532
610
533
611
fn parse_string_constraints ( raw : & RawParameter ) -> anyhow:: Result < StringConstraints > {
@@ -559,3 +637,20 @@ fn validate_v1_manifest(raw: &RawTemplateManifestV1) -> anyhow::Result<()> {
559
637
}
560
638
Ok ( ( ) )
561
639
}
640
+
641
+ fn get_at ( value : toml:: Value , path : & [ String ] ) -> Option < toml:: Value > {
642
+ match path. split_first ( ) {
643
+ None => Some ( value) , // we are at the end of the path and we have a thing
644
+ Some ( ( first, rest) ) => {
645
+ match value. as_table ( ) {
646
+ None => None , // we need to key into it and we can't
647
+ Some ( t) => {
648
+ match t. get ( first) {
649
+ None => None , // we tried to key into it and no match
650
+ Some ( v) => get_at ( v. clone ( ) , rest) , // we pathed into it! keep pathing
651
+ }
652
+ }
653
+ }
654
+ }
655
+ }
656
+ }
0 commit comments