7
7
"fmt"
8
8
"strings"
9
9
10
+ "github.com/hashicorp/hcl/v2"
11
+ "github.com/hashicorp/hcl/v2/hclsyntax"
12
+
10
13
"github.com/hashicorp/terraform/internal/tfdiags"
11
14
)
12
15
@@ -284,7 +287,7 @@ func (a AbsActionInstance) UniqueKey() UniqueKey {
284
287
return absActionInstanceKey (a .String ())
285
288
}
286
289
287
- func (r absActionInstanceKey ) uniqueKeySigil () {}
290
+ func (a absActionInstanceKey ) uniqueKeySigil () {}
288
291
289
292
// ConfigAction is the address for an action within the configuration.
290
293
type ConfigAction struct {
@@ -337,7 +340,7 @@ type AbsActionInvocationInstance struct {
337
340
TriggerIndex int
338
341
339
342
// TriggerBlockSourceRange is the location of the action_trigger block
340
- // within the resources lifecyclye block that triggered this action.
343
+ // within the resources lifecycle block that triggered this action.
341
344
TriggerBlockSourceRange * tfdiags.SourceRange
342
345
343
346
// ActionReferenceSourceRange is the location of the action reference
@@ -348,3 +351,152 @@ type AbsActionInvocationInstance struct {
348
351
func (a AbsActionInvocationInstance ) String () string {
349
352
return fmt .Sprintf ("%s.%d.%s" , a .TriggeringResource .String (), a .TriggerIndex , a .Action .String ())
350
353
}
354
+
355
+ // ParseAbsActionInstanceStr is a helper wrapper around
356
+ // ParseAbsActionInstance that takes a string and parses it with the HCL
357
+ // native syntax traversal parser before interpreting it.
358
+ //
359
+ // Error diagnostics are returned if either the parsing fails or the analysis
360
+ // of the traversal fails. There is no way for the caller to distinguish the
361
+ // two kinds of diagnostics programmatically. If error diagnostics are returned
362
+ // the returned address may be incomplete.
363
+ //
364
+ // Since this function has no context about the source of the given string,
365
+ // any returned diagnostics will not have meaningful source location
366
+ // information.
367
+ func ParseAbsActionInstanceStr (str string ) (AbsActionInstance , tfdiags.Diagnostics ) {
368
+ var diags tfdiags.Diagnostics
369
+
370
+ traversal , parseDiags := hclsyntax .ParseTraversalAbs ([]byte (str ), "" , hcl.Pos {Line : 1 , Column : 1 })
371
+ diags = diags .Append (parseDiags )
372
+ if parseDiags .HasErrors () {
373
+ return AbsActionInstance {}, diags
374
+ }
375
+
376
+ addr , addrDiags := ParseAbsActionInstance (traversal )
377
+ diags = diags .Append (addrDiags )
378
+ return addr , diags
379
+ }
380
+
381
+ // ParseAbsActionInstance attempts to interpret the given traversal as an
382
+ // absolute action instance address, using the same syntax as expected by
383
+ // ParseTarget.
384
+ //
385
+ // If no error diagnostics are returned, the returned target includes the
386
+ // address that was extracted and the source range it was extracted from.
387
+ //
388
+ // If error diagnostics are returned then the AbsResource value is invalid and
389
+ // must not be used.
390
+ func ParseAbsActionInstance (traversal hcl.Traversal ) (AbsActionInstance , tfdiags.Diagnostics ) {
391
+ moduleAddr , remain , diags := parseModuleInstancePrefix (traversal , false )
392
+ if diags .HasErrors () {
393
+ return AbsActionInstance {}, diags
394
+ }
395
+
396
+ if remain .IsRelative () {
397
+ // (relative means that there's either nothing left or what's next isn't an identifier)
398
+ diags = diags .Append (& hcl.Diagnostic {
399
+ Severity : hcl .DiagError ,
400
+ Summary : "Invalid action address" ,
401
+ Detail : "Module path must be followed by an action instance address." ,
402
+ Subject : remain .SourceRange ().Ptr (),
403
+ })
404
+ return AbsActionInstance {}, diags
405
+ }
406
+
407
+ if remain .RootName () != "action" {
408
+ diags = diags .Append (& hcl.Diagnostic {
409
+ Severity : hcl .DiagError ,
410
+ Summary : "Invalid address" ,
411
+ Detail : "Action address must start with \" action.\" ." ,
412
+ Subject : remain [0 ].SourceRange ().Ptr (),
413
+ })
414
+ return AbsActionInstance {}, diags
415
+ }
416
+ remain = remain [1 :]
417
+
418
+ if len (remain ) < 2 {
419
+ diags = diags .Append (& hcl.Diagnostic {
420
+ Severity : hcl .DiagError ,
421
+ Summary : "Invalid address" ,
422
+ Detail : "Action specification must include an action type and name." ,
423
+ Subject : remain .SourceRange ().Ptr (),
424
+ })
425
+ return AbsActionInstance {}, diags
426
+ }
427
+
428
+ var actionType , name string
429
+ switch tt := remain [0 ].(type ) {
430
+ case hcl.TraverseRoot :
431
+ actionType = tt .Name
432
+ case hcl.TraverseAttr :
433
+ actionType = tt .Name
434
+ default :
435
+ diags = diags .Append (& hcl.Diagnostic {
436
+ Severity : hcl .DiagError ,
437
+ Summary : "Invalid action address" ,
438
+ Detail : "An action name is required." ,
439
+ Subject : remain [0 ].SourceRange ().Ptr (),
440
+ })
441
+ return AbsActionInstance {}, diags
442
+ }
443
+
444
+ switch tt := remain [1 ].(type ) {
445
+ case hcl.TraverseAttr :
446
+ name = tt .Name
447
+ default :
448
+ diags = diags .Append (& hcl.Diagnostic {
449
+ Severity : hcl .DiagError ,
450
+ Summary : "Invalid address" ,
451
+ Detail : "An action name is required." ,
452
+ Subject : remain [1 ].SourceRange ().Ptr (),
453
+ })
454
+ return AbsActionInstance {}, diags
455
+ }
456
+
457
+ remain = remain [2 :]
458
+ switch len (remain ) {
459
+ case 0 :
460
+ return moduleAddr .ActionInstance (actionType , name , NoKey ), diags
461
+ case 1 :
462
+ switch tt := remain [0 ].(type ) {
463
+ case hcl.TraverseIndex :
464
+ key , err := ParseInstanceKey (tt .Key )
465
+ if err != nil {
466
+ diags = diags .Append (& hcl.Diagnostic {
467
+ Severity : hcl .DiagError ,
468
+ Summary : "Invalid address" ,
469
+ Detail : fmt .Sprintf ("Invalid resource instance key: %s." , err ),
470
+ Subject : remain [0 ].SourceRange ().Ptr (),
471
+ })
472
+ return AbsActionInstance {}, diags
473
+ }
474
+ return moduleAddr .ActionInstance (actionType , name , key ), diags
475
+ case hcl.TraverseSplat :
476
+ // Not yet supported!
477
+ diags = diags .Append (& hcl.Diagnostic {
478
+ Severity : hcl .DiagError ,
479
+ Summary : "Invalid address" ,
480
+ Detail : "Action instance key must be given in square brackets." ,
481
+ Subject : remain [0 ].SourceRange ().Ptr (),
482
+ })
483
+ return AbsActionInstance {}, diags
484
+ default :
485
+ diags = diags .Append (& hcl.Diagnostic {
486
+ Severity : hcl .DiagError ,
487
+ Summary : "Invalid address" ,
488
+ Detail : "Action instance key must be given in square brackets." ,
489
+ Subject : remain [0 ].SourceRange ().Ptr (),
490
+ })
491
+ return AbsActionInstance {}, diags
492
+ }
493
+ default :
494
+ diags = diags .Append (& hcl.Diagnostic {
495
+ Severity : hcl .DiagError ,
496
+ Summary : "Invalid address" ,
497
+ Detail : "Unexpected extra operators after address." ,
498
+ Subject : remain [1 ].SourceRange ().Ptr (),
499
+ })
500
+ return AbsActionInstance {}, diags
501
+ }
502
+ }
0 commit comments