github.com/jenspinney/cli@v6.42.1-0.20190207184520-7450c600020e+incompatible/util/manifest/manifest.go (about)

     1  package manifest
     2  
     3  import (
     4  	"io/ioutil"
     5  	"path/filepath"
     6  
     7  	"github.com/cloudfoundry/bosh-cli/director/template"
     8  	yaml "gopkg.in/yaml.v2"
     9  )
    10  
    11  type Manifest struct {
    12  	Applications []Application `yaml:"applications"`
    13  }
    14  
    15  func (manifest *Manifest) UnmarshalYAML(unmarshal func(interface{}) error) error {
    16  	var raw rawManifest
    17  	err := unmarshal(&raw)
    18  	if err != nil {
    19  		return err
    20  	}
    21  
    22  	if raw.containsInheritanceField() {
    23  		return InheritanceFieldError{}
    24  	}
    25  
    26  	if globals := raw.containsGlobalFields(); len(globals) > 0 {
    27  		return GlobalFieldsError{Fields: globals}
    28  	}
    29  
    30  	manifest.Applications = raw.Applications
    31  	return nil
    32  }
    33  
    34  // ReadAndInterpolateManifest reads the manifest at the provided paths,
    35  // interpolates variables if a vars file is provided, and returns a fully
    36  // merged set of applications.
    37  func ReadAndInterpolateManifest(pathToManifest string, pathsToVarsFiles []string, vars []template.VarKV) ([]Application, error) {
    38  	rawManifest, err := ReadAndInterpolateRawManifest(pathToManifest, pathsToVarsFiles, vars)
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  
    43  	var manifest Manifest
    44  	err = yaml.Unmarshal(rawManifest, &manifest)
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  
    49  	for i, app := range manifest.Applications {
    50  		if app.Path != "" && !filepath.IsAbs(app.Path) {
    51  			manifest.Applications[i].Path = filepath.Join(filepath.Dir(pathToManifest), app.Path)
    52  		}
    53  	}
    54  
    55  	return manifest.Applications, err
    56  }
    57  
    58  // ReadAndInterpolateRawManifest reads the manifest at the provided paths,
    59  // interpolates variables if a vars file is provided, and returns the
    60  // Unmarshalled result.
    61  func ReadAndInterpolateRawManifest(pathToManifest string, pathsToVarsFiles []string, vars []template.VarKV) ([]byte, error) {
    62  	rawManifest, err := ioutil.ReadFile(pathToManifest)
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  
    67  	tpl := template.NewTemplate(rawManifest)
    68  	fileVars := template.StaticVariables{}
    69  
    70  	for _, path := range pathsToVarsFiles {
    71  		rawVarsFile, ioerr := ioutil.ReadFile(path)
    72  		if ioerr != nil {
    73  			return nil, ioerr
    74  		}
    75  
    76  		var sv template.StaticVariables
    77  
    78  		err = yaml.Unmarshal(rawVarsFile, &sv)
    79  		if err != nil {
    80  			return nil, InvalidYAMLError{Err: err}
    81  		}
    82  
    83  		for k, v := range sv {
    84  			fileVars[k] = v
    85  		}
    86  	}
    87  
    88  	for _, kv := range vars {
    89  		fileVars[kv.Name] = kv.Value
    90  	}
    91  
    92  	rawManifest, err = tpl.Evaluate(fileVars, nil, template.EvaluateOpts{ExpectAllKeys: true})
    93  	if err != nil {
    94  		return nil, InterpolationError{Err: err}
    95  	}
    96  	return rawManifest, nil
    97  }
    98  
    99  // WriteApplicationManifest writes the provided application to the given
   100  // filepath. If the filepath does not exist, it will create it.
   101  func WriteApplicationManifest(application Application, filePath string) error {
   102  	manifest := Manifest{Applications: []Application{application}}
   103  	manifestBytes, err := yaml.Marshal(manifest)
   104  	if err != nil {
   105  		return ManifestCreationError{Err: err}
   106  	}
   107  
   108  	err = ioutil.WriteFile(filePath, manifestBytes, 0644)
   109  	if err != nil {
   110  		return ManifestCreationError{Err: err}
   111  	}
   112  
   113  	return nil
   114  }