@@ -342,3 +342,175 @@ func newConstructResult(resource ComponentResource) (URNInput, Input, error) {
342
342
343
343
return resource .URN (), state , nil
344
344
}
345
+
346
+ type callFunc func (ctx * Context , tok string , args map [string ]interface {}) (Input , error )
347
+
348
+ // call adapts the gRPC CallRequest/CallResponse to/from the Pulumi Go SDK programming model.
349
+ func call (ctx context.Context , req * pulumirpc.CallRequest , engineConn * grpc.ClientConn ,
350
+ callF callFunc ) (* pulumirpc.CallResponse , error ) {
351
+
352
+ // Configure the RunInfo.
353
+ runInfo := RunInfo {
354
+ Project : req .GetProject (),
355
+ Stack : req .GetStack (),
356
+ Config : req .GetConfig (),
357
+ Parallel : int (req .GetParallel ()),
358
+ DryRun : req .GetDryRun (),
359
+ MonitorAddr : req .GetMonitorEndpoint (),
360
+ engineConn : engineConn ,
361
+ }
362
+ pulumiCtx , err := NewContext (ctx , runInfo )
363
+ if err != nil {
364
+ return nil , errors .Wrap (err , "constructing run context" )
365
+ }
366
+
367
+ // Deserialize the inputs and apply appropriate dependencies.
368
+ argDependencies := req .GetArgDependencies ()
369
+ deserializedArgs , err := plugin .UnmarshalProperties (
370
+ req .GetArgs (),
371
+ plugin.MarshalOptions {KeepSecrets : true , KeepResources : true , KeepUnknowns : req .GetDryRun ()},
372
+ )
373
+ if err != nil {
374
+ return nil , errors .Wrap (err , "unmarshaling inputs" )
375
+ }
376
+ args := make (map [string ]interface {}, len (deserializedArgs ))
377
+ for key , value := range deserializedArgs {
378
+ k := string (key )
379
+ var deps []Resource
380
+ if inputDeps , ok := argDependencies [k ]; ok {
381
+ deps = make ([]Resource , len (inputDeps .GetUrns ()))
382
+ for i , depURN := range inputDeps .GetUrns () {
383
+ deps [i ] = pulumiCtx .newDependencyResource (URN (depURN ))
384
+ }
385
+ }
386
+
387
+ args [k ] = & constructInput {
388
+ value : value ,
389
+ deps : deps ,
390
+ }
391
+ }
392
+
393
+ result , err := callF (pulumiCtx , req .GetTok (), args )
394
+ if err != nil {
395
+ return nil , err
396
+ }
397
+
398
+ // Wait for async work to finish.
399
+ if err = pulumiCtx .wait (); err != nil {
400
+ return nil , err
401
+ }
402
+
403
+ // Serialize all result properties, first by awaiting them, and then marshaling them to the requisite gRPC values.
404
+ resolvedProps , propertyDeps , _ , err := marshalInputs (result )
405
+ if err != nil {
406
+ return nil , errors .Wrap (err , "marshaling properties" )
407
+ }
408
+
409
+ // Marshal all properties for the RPC call.
410
+ keepUnknowns := req .GetDryRun ()
411
+ rpcProps , err := plugin .MarshalProperties (
412
+ resolvedProps ,
413
+ plugin.MarshalOptions {KeepSecrets : true , KeepUnknowns : keepUnknowns , KeepResources : pulumiCtx .keepResources })
414
+ if err != nil {
415
+ return nil , errors .Wrap (err , "marshaling properties" )
416
+ }
417
+
418
+ // Convert the property dependencies map for RPC and remove duplicates.
419
+ rpcPropertyDeps := make (map [string ]* pulumirpc.CallResponse_ReturnDependencies )
420
+ for k , deps := range propertyDeps {
421
+ sort .Slice (deps , func (i , j int ) bool { return deps [i ] < deps [j ] })
422
+
423
+ urns := make ([]string , 0 , len (deps ))
424
+ for i , d := range deps {
425
+ if i > 0 && urns [i - 1 ] == string (d ) {
426
+ continue
427
+ }
428
+ urns = append (urns , string (d ))
429
+ }
430
+
431
+ rpcPropertyDeps [k ] = & pulumirpc.CallResponse_ReturnDependencies {
432
+ Urns : urns ,
433
+ }
434
+ }
435
+
436
+ return & pulumirpc.CallResponse {
437
+ Return : rpcProps ,
438
+ ReturnDependencies : rpcPropertyDeps ,
439
+ }, nil
440
+ }
441
+
442
+ // callArgsCopyTo sets the args on the given args struct. If there is a `__self__` argument, it will be
443
+ // returned, otherwise it will return nil.
444
+ func callArgsCopyTo (ctx * Context , source map [string ]interface {}, args interface {}) (Resource , error ) {
445
+ // Use the same implementation as construct.
446
+ if err := constructInputsCopyTo (ctx , source , args ); err != nil {
447
+ return nil , err
448
+ }
449
+
450
+ // Retrieve the `__self__` arg.
451
+ self , err := callArgsSelf (ctx , source )
452
+ if err != nil {
453
+ return nil , err
454
+ }
455
+
456
+ return self , nil
457
+ }
458
+
459
+ // callArgsSelf retrieves the `__self__` argument. If `__self__` is present the value is returned,
460
+ // otherwise the returned value will be nil.
461
+ func callArgsSelf (ctx * Context , source map [string ]interface {}) (Resource , error ) {
462
+ v , ok := source ["__self__" ]
463
+ if ! ok {
464
+ return nil , nil
465
+ }
466
+
467
+ ci := v .(* constructInput )
468
+ if ci .value .ContainsUnknowns () {
469
+ return nil , errors .New ("__self__ is unknown" )
470
+ }
471
+
472
+ value , secret , err := unmarshalPropertyValue (ctx , ci .value )
473
+ if err != nil {
474
+ return nil , errors .Wrap (err , "unmarshaling __self__" )
475
+ }
476
+ if secret {
477
+ return nil , errors .New ("__self__ is a secret" )
478
+ }
479
+
480
+ return value .(Resource ), nil
481
+ }
482
+
483
+ // newCallResult converts a result struct into an input Map that can be marshalled.
484
+ func newCallResult (result interface {}) (Input , error ) {
485
+ if result == nil {
486
+ return nil , errors .New ("result must not be nil" )
487
+ }
488
+
489
+ resultV := reflect .ValueOf (result )
490
+ typ := resultV .Type ()
491
+ if typ .Kind () != reflect .Ptr || typ .Elem ().Kind () != reflect .Struct {
492
+ return nil , errors .New ("result must be a pointer to a struct" )
493
+ }
494
+ resultV , typ = resultV .Elem (), typ .Elem ()
495
+
496
+ ret := make (Map )
497
+ for i := 0 ; i < typ .NumField (); i ++ {
498
+ fieldV := resultV .Field (i )
499
+ if ! fieldV .CanInterface () {
500
+ continue
501
+ }
502
+ field := typ .Field (i )
503
+ tag , has := field .Tag .Lookup ("pulumi" )
504
+ if ! has {
505
+ continue
506
+ }
507
+ val := fieldV .Interface ()
508
+ if v , ok := val .(Input ); ok {
509
+ ret [tag ] = v
510
+ } else {
511
+ ret [tag ] = ToOutput (val )
512
+ }
513
+ }
514
+
515
+ return ret , nil
516
+ }
0 commit comments