github.com/dahs81/otto@v0.2.1-0.20160126165905-6400716cf085/foundation/vars.go (about)

     1  package foundation
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"fmt"
     7  	"io"
     8  	"log"
     9  	"os"
    10  	"path/filepath"
    11  
    12  	"github.com/hashicorp/otto/context"
    13  	"github.com/hashicorp/otto/directory"
    14  )
    15  
    16  // WriteVars will write the outputs from a foundation and put them into
    17  // a key/value file within the foundation directories that is available
    18  // when uploaded. This allows the build scripts to access the outputs
    19  // at runtime.
    20  //
    21  // Ideally this sort of thing would be possible at compile-time but the
    22  // values of these variables come at runtime so we need to populate this
    23  // at runtime.
    24  //
    25  // By having a var file, it removes the burden of knowing what variables
    26  // to send in to the foundation from the App implementation. They just need
    27  // to call this function, upload the folder, and call main.sh.
    28  func WriteVars(ctx *context.Shared) error {
    29  	infra := ctx.Appfile.ActiveInfrastructure()
    30  	if infra == nil {
    31  		panic("no active infra")
    32  	}
    33  
    34  	log.Printf("[DEBUG] infra.Foundations: %#v", infra.Foundations)
    35  	log.Printf("[DEBUG] ctx.FoundationDirs: %#v", ctx.FoundationDirs)
    36  
    37  	if len(ctx.FoundationDirs) < len(infra.Foundations) {
    38  		panic("foundationDirs is missing entries")
    39  	}
    40  
    41  	// subdirs are the directories to write the vars file to. For now
    42  	// we just write it to one but we put this here because I can see
    43  	// a future where more may need it.
    44  	subdirs := []string{"app-build"}
    45  
    46  	// Go through each foundation, grab its infrastructure data, and
    47  	// write it out to the proper path.
    48  	for i, f := range infra.Foundations {
    49  		entry, err := ctx.Directory.GetInfra(&directory.Infra{
    50  			Lookup: directory.Lookup{Infra: infra.Type, Foundation: f.Name}})
    51  		if err != nil {
    52  			return err
    53  		}
    54  		if entry == nil {
    55  			continue
    56  		}
    57  
    58  		// Get the var file contents into an in-memory buffer
    59  		var buf bytes.Buffer
    60  		if err := varFile(&buf, entry); err != nil {
    61  			return fmt.Errorf(
    62  				"error generating var file for %s: %s",
    63  				f.Name, err)
    64  		}
    65  
    66  		// Get a reader around the buffer so we can seek
    67  		r := bytes.NewReader(buf.Bytes())
    68  		for _, subdir := range subdirs {
    69  			if _, err := r.Seek(0, 0); err != nil {
    70  				return err
    71  			}
    72  
    73  			path := filepath.Join(ctx.FoundationDirs[i], subdir)
    74  			if _, err := os.Stat(path); err != nil {
    75  				if os.IsNotExist(err) {
    76  					// Ignore directories that don't exist
    77  					continue
    78  				}
    79  
    80  				return err
    81  			}
    82  			path = filepath.Join(path, "vars")
    83  
    84  			log.Printf(
    85  				"[DEBUG] writing foundation %s var file to: %s",
    86  				f.Name, path)
    87  			w, err := os.Create(path)
    88  			if err != nil {
    89  				return err
    90  			}
    91  			_, err = io.Copy(w, r)
    92  			w.Close()
    93  			if err != nil {
    94  				return err
    95  			}
    96  		}
    97  	}
    98  
    99  	return nil
   100  }
   101  
   102  func varFile(w io.Writer, entry *directory.Infra) error {
   103  	bufW := bufio.NewWriter(w)
   104  	for k, v := range entry.Outputs {
   105  		_, err := bufW.WriteString(fmt.Sprintf("%s=%s\n", k, v))
   106  		if err != nil {
   107  			return err
   108  		}
   109  	}
   110  
   111  	return bufW.Flush()
   112  }