github.com/devcamcar/cli@v0.0.0-20181107134215-706a05759d18/commands/migrate.go (about)

     1  package commands
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"path/filepath"
     9  
    10  	"github.com/fnproject/cli/common"
    11  	"github.com/fnproject/cli/config"
    12  	yamltojson "github.com/ghodss/yaml"
    13  	"github.com/mitchellh/mapstructure"
    14  	"github.com/urfave/cli"
    15  	yaml "gopkg.in/yaml.v2"
    16  )
    17  
    18  const (
    19  	MigrateSuccessMessage = "Successfully migrated func.yaml and created a back up func.yaml.bak"
    20  	MigrateFailureMessage = "you have an up to date func.yaml file and do not need to migrate"
    21  )
    22  
    23  type migrateFnCmd struct {
    24  	newFF *common.FuncFileV20180708
    25  }
    26  
    27  func MigrateCommand() cli.Command {
    28  	m := &migrateFnCmd{newFF: &common.FuncFileV20180708{}}
    29  
    30  	return cli.Command{
    31  		Name:        "migrate",
    32  		Usage:       "\tMigrate a local func.yaml file to the latest version",
    33  		Category:    "DEVELOPMENT COMMANDS",
    34  		Aliases:     []string{"m"},
    35  		Description: "This command will detect the version of a func.yaml file and update it to match the latest version supported by the Fn CLI.\n\tAny old or unsupported attributes will be removed, and any new ones may be added.\n\tThe current func.yaml will be renamed to func.yaml.bak and a new func.yaml created.",
    36  		Action:      m.migrate,
    37  	}
    38  }
    39  
    40  func (m *migrateFnCmd) migrate(c *cli.Context) error {
    41  	var err error
    42  	oldFF, err := common.ReadInFuncFile()
    43  	if err != nil {
    44  		return err
    45  	}
    46  
    47  	version := common.GetFuncYamlVersion(oldFF)
    48  	if version == common.LatestYamlVersion {
    49  		return errors.New(MigrateFailureMessage)
    50  	}
    51  
    52  	err = backUpYamlFile(oldFF)
    53  	if err != nil {
    54  		return err
    55  	}
    56  
    57  	b, err := m.creatFuncFileBytes(oldFF)
    58  	if err != nil {
    59  		return err
    60  	}
    61  
    62  	err = vaidateFuncFileSchema(b)
    63  	if err != nil {
    64  		return err
    65  	}
    66  
    67  	err = writeYamlFile(b, "func.yaml")
    68  	if err != nil {
    69  		return err
    70  	}
    71  
    72  	fmt.Println(MigrateSuccessMessage)
    73  	return nil
    74  }
    75  
    76  func backUpYamlFile(ff map[string]interface{}) error {
    77  	b, err := yaml.Marshal(ff)
    78  	if err != nil {
    79  		return err
    80  	}
    81  
    82  	return writeYamlFile(b, "func.yaml.bak")
    83  }
    84  
    85  func (m *migrateFnCmd) decodeFuncFile(oldFF map[string]interface{}) ([]byte, error) {
    86  	_ = mapstructure.Decode(oldFF, &m.newFF)
    87  	return yaml.Marshal(oldFF)
    88  }
    89  
    90  func (m *migrateFnCmd) creatFuncFileBytes(oldFF map[string]interface{}) ([]byte, error) {
    91  	b, err := m.decodeFuncFile(oldFF)
    92  	if err != nil {
    93  		return nil, err
    94  	}
    95  
    96  	err = vaidateFuncFileSchema(b)
    97  	if err != nil {
    98  		return nil, err
    99  	}
   100  
   101  	m.newFF.Schema_version = 20180708
   102  	trig := make([]common.Trigger, 1)
   103  
   104  	var trigName, trigSource string
   105  
   106  	if oldFF["name"] != nil {
   107  		trigName = oldFF["name"].(string)
   108  		trigSource = "/" + oldFF["name"].(string)
   109  	}
   110  
   111  	trigType := "http"
   112  
   113  	trig[0] = common.Trigger{
   114  		trigName,
   115  		trigType,
   116  		trigSource,
   117  	}
   118  	m.newFF.Triggers = trig
   119  
   120  	return yaml.Marshal(m.newFF)
   121  }
   122  
   123  func vaidateFuncFileSchema(b []byte) error {
   124  	jsonB, err := yamltojson.YAMLToJSON(b)
   125  	if err != nil {
   126  		return err
   127  	}
   128  
   129  	err = ioutil.WriteFile("temp.json", jsonB, config.ReadWritePerms)
   130  	if err != nil {
   131  		return err
   132  	}
   133  	defer os.Remove("temp.json")
   134  
   135  	err = common.ValidateFileAgainstSchema("temp.json", common.V20180708Schema)
   136  	if err != nil {
   137  		return err
   138  	}
   139  
   140  	return nil
   141  }
   142  
   143  func writeYamlFile(b []byte, filename string) error {
   144  	wd := common.GetWd()
   145  	fpath := filepath.Join(wd, filename)
   146  
   147  	return ioutil.WriteFile(fpath, b, config.ReadWritePerms)
   148  }