github.com/github/skeema@v1.2.6/cmd_add_env.go (about) 1 package main 2 3 import ( 4 "os" 5 "strconv" 6 "strings" 7 8 log "github.com/sirupsen/logrus" 9 "github.com/skeema/mybase" 10 "github.com/skeema/skeema/fs" 11 "github.com/skeema/tengo" 12 ) 13 14 func init() { 15 summary := "Add a new named environment to an existing host directory" 16 desc := `Modifies the .skeema file in an existing host directory to add a new named 17 environment. For example, if ` + "`" + `skeema init` + "`" + ` was previously used to create a dir 18 for a host with the default "production" environment, ` + "`" + `skeema add-environment` + "`" + ` 19 could be used to define a "staging" or "development" environment pointing at a 20 different host and port, or perhaps a "local" environment pointing at localhost 21 and a socket path. 22 23 This command currently only handles very simple cases. For many situations, 24 editing .skeema files directly is a better approach.` 25 26 cmd := mybase.NewCommand("add-environment", summary, desc, AddEnvHandler) 27 cmd.AddOption(mybase.StringOption("host", 'h', "", "Database hostname or IP address")) 28 cmd.AddOption(mybase.StringOption("port", 'P', "3306", "Port to use for database host")) 29 cmd.AddOption(mybase.StringOption("socket", 'S', "/tmp/mysql.sock", "Absolute path to Unix socket file used if host is localhost")) 30 cmd.AddOption(mybase.StringOption("dir", 'd', ".", "Base dir for this host's schemas")) 31 cmd.AddArg("environment", "", true) 32 CommandSuite.AddSubCommand(cmd) 33 } 34 35 // AddEnvHandler is the handler method for `skeema add-environment` 36 func AddEnvHandler(cfg *mybase.Config) error { 37 dirPath := cfg.Get("dir") 38 fi, err := os.Stat(dirPath) 39 if err == nil && !fi.IsDir() { 40 return NewExitValue(CodeBadConfig, "--dir=%s already exists but is not a directory", dirPath) 41 } else if os.IsNotExist(err) { 42 return NewExitValue(CodeBadConfig, "In add-environment, --dir must refer to a directory that already exists") 43 } else if err != nil { 44 return err 45 } 46 47 dir, err := fs.ParseDir(dirPath, cfg) 48 if err != nil { 49 return err 50 } 51 if dir.OptionFile == nil { 52 return NewExitValue(CodeBadConfig, "Dir %s does not have an existing .skeema file! Can only use `skeema add-environment` on a dir previously created by `skeema init`", dir) 53 } 54 55 environment := cfg.Get("environment") 56 if environment == "" || strings.ContainsAny(environment, "[]\n\r") { 57 return NewExitValue(CodeBadConfig, "Environment name \"%s\" is invalid", environment) 58 } 59 if dir.OptionFile.HasSection(environment) { 60 return NewExitValue(CodeBadConfig, "Environment name \"%s\" already defined in %s", environment, dir.OptionFile.Path()) 61 } 62 if !dir.OptionFile.SomeSectionHasOption("host") { 63 return NewExitValue(CodeBadConfig, "This command should be run against a --dir whose .skeema file already defines a host for another environment") 64 } 65 66 // Create a tengo.Instance representing the supplied host. We intentionally 67 // don't actually test connectivity here though, since this command only 68 // manipulates the option file. We can't use dir.FirstInstance() here since 69 // that checks connectivity. 70 var inst *tengo.Instance 71 if !cfg.OnCLI("host") { 72 return NewExitValue(CodeBadConfig, "`skeema add-environment` requires --host to be supplied on CLI") 73 } 74 if instances, err := dir.Instances(); err != nil { 75 return err 76 } else if len(instances) == 0 { 77 return NewExitValue(CodeBadConfig, "Command line did not specify which instance to connect to") 78 } else { 79 inst = instances[0] 80 } 81 82 dir.OptionFile.SetOptionValue(environment, "host", inst.Host) 83 if inst.Host == "localhost" && inst.SocketPath != "" { 84 dir.OptionFile.SetOptionValue(environment, "socket", inst.SocketPath) 85 } else { 86 dir.OptionFile.SetOptionValue(environment, "port", strconv.Itoa(inst.Port)) 87 } 88 if flavor := inst.Flavor(); !flavor.Known() { 89 log.Warnf("Unable to automatically determine database vendor or version. To set manually, use the \"flavor\" option in %s", dir.OptionFile) 90 } else { 91 dir.OptionFile.SetOptionValue(environment, "flavor", flavor.String()) 92 } 93 for _, persistOpt := range []string{"user", "ignore-schema", "ignore-table", "connect-options"} { 94 if cfg.OnCLI(persistOpt) { 95 dir.OptionFile.SetOptionValue(environment, persistOpt, cfg.Get(persistOpt)) 96 } 97 } 98 99 // Write the option file 100 if err := dir.OptionFile.Write(true); err != nil { 101 return err 102 } 103 104 log.Infof("Added environment [%s] to %s", environment, dir.OptionFile.Path()) 105 return nil 106 }