get.porter.sh/porter@v1.3.0/pkg/exec/builder/action.go (about)

     1  package builder
     2  
     3  import (
     4  	"bufio"
     5  	"context"
     6  	"fmt"
     7  	"io"
     8  
     9  	"get.porter.sh/porter/pkg/runtime"
    10  	"get.porter.sh/porter/pkg/tracing"
    11  	"get.porter.sh/porter/pkg/yaml"
    12  )
    13  
    14  // UnmarshalAction handles unmarshaling any action, given a pointer to a slice of Steps.
    15  // Iterate over the results and cast back to the Steps to use the results.
    16  //
    17  //	 var steps []Step
    18  //		results, err := UnmarshalAction(unmarshal, &steps)
    19  //		if err != nil {
    20  //			return err
    21  //		}
    22  //
    23  //		for _, result := range results {
    24  //			step := result.(*[]Step)
    25  //			a.Steps = append(a.Steps, *step...)
    26  //		}
    27  func UnmarshalAction(unmarshal func(interface{}) error, builder BuildableAction) (map[string][]interface{}, error) {
    28  	actionMap := map[string][]interface{}{}
    29  	err := unmarshal(&actionMap)
    30  	if err != nil {
    31  		return nil, fmt.Errorf("could not unmarshal yaml into an action map of exec steps: %w", err)
    32  	}
    33  
    34  	return unmarshalActionMap(actionMap, builder)
    35  }
    36  
    37  func unmarshalActionMap(actionMap map[string][]interface{}, builder BuildableAction) (map[string][]interface{}, error) {
    38  	results := make(map[string][]interface{})
    39  	for actionIndex, stepMaps := range actionMap {
    40  		// Figure out the string representation of the action
    41  		// examples:
    42  		//   install: -> "install"
    43  		//   true: -> "true" YAML is weird, this is why we use Sprintf and not .(string)
    44  		name := fmt.Sprintf("%v", actionIndex)
    45  
    46  		// Unmarshal the steps
    47  		b, err := yaml.Marshal(stepMaps)
    48  		if err != nil {
    49  			return nil, err
    50  		}
    51  
    52  		steps := builder.MakeSteps()
    53  		err = yaml.Unmarshal(b, steps)
    54  		if err != nil {
    55  			return nil, err
    56  		}
    57  
    58  		result, ok := results[name]
    59  		if !ok {
    60  			result = make([]interface{}, 0, 1)
    61  		}
    62  		results[name] = append(result, steps)
    63  	}
    64  
    65  	return results, nil
    66  }
    67  
    68  // LoadAction reads input from stdin or a command file and uses the specified unmarshal function
    69  // to unmarshal it into a typed Action.
    70  // The unmarshal function is responsible for calling yaml.Unmarshal and passing in a reference to an appropriate
    71  // Action instance.
    72  //
    73  // Example:
    74  //
    75  //	  var action Action
    76  //		 err := builder.LoadAction(m.Context, opts.File, func(contents []byte) (interface{}, error) {
    77  //			 err := yaml.Unmarshal(contents, &action)
    78  //			 return &action, err
    79  //		 })
    80  func LoadAction(ctx context.Context, cfg runtime.RuntimeConfig, commandFile string, unmarshal func([]byte) (interface{}, error)) error {
    81  	_, span := tracing.StartSpan(ctx)
    82  	defer span.EndSpan()
    83  
    84  	contents, err := readInputFromStdinOrFile(cfg, commandFile)
    85  	if err != nil {
    86  		return span.Error(err)
    87  	}
    88  
    89  	_, err = unmarshal(contents)
    90  	if err != nil {
    91  		return span.Error(fmt.Errorf("could not unmarshal input:\n %s: %w", string(contents), err))
    92  	}
    93  
    94  	return nil
    95  }
    96  
    97  func readInputFromStdinOrFile(cfg runtime.RuntimeConfig, commandFile string) ([]byte, error) {
    98  	var b []byte
    99  	var err error
   100  	if commandFile == "" {
   101  		reader := bufio.NewReader(cfg.In)
   102  		b, err = io.ReadAll(reader)
   103  	} else {
   104  		b, err = cfg.FileSystem.ReadFile(commandFile)
   105  	}
   106  
   107  	if err != nil {
   108  		source := "STDIN"
   109  		if commandFile == "" {
   110  			source = commandFile
   111  		}
   112  		return nil, fmt.Errorf("could not load input from %s: %w", source, err)
   113  	}
   114  	return b, nil
   115  }