profile
viewpoint
Devon H. O'Dell dhobsd Google United States https://9vx.org/ Debugger and concurrency nut; systems engineer at Google. Usually confused about something.

dhobsd/asciitosvg 353

DANGER, WILL ROBINSON: THIS REPOSITORY IS IN MAINTENANCE MODE! I will not be continuing feature development or fixing bugs in this codebase. I will continue to review and accept pull requests that do this. Please click the following link to view the actively developed ASCIIToSVG codebase, which is written in Go.

katef/libfsm 141

DFA regular expression library & friends

dhobsd/castty 59

A CLI tool to record audio-enabled screencasts of your terminal, for the web.

dhobsd/sbst 10

Benchmark various data structures / algorithms for string searching.

dhobsd/vstring 4

A simple string building API for C.

dhobsd/lacquer 3

Making network servers shinier

varialus/godfly 2

Golang on DragonFly BSD

dhobsd/bcd 0

Simple out-of-process invoker

pull request commentGoogleCloudPlatform/cloud-foundation-toolkit

[dm][cli] Spring 15 and 16 stories

That's not the case; os.IsNotExist/IsExist/IsPermission/IsTimeout all properly handle a nil error: https://github.com/golang/go/issues/31065

kopachevsky

comment created time in 5 months

Pull request review commentGoogleCloudPlatform/cloud-foundation-toolkit

[dm][cli] Spring 15 and 16 stories

 import ( 	"gopkg.in/yaml.v2" ) +// Status represent Deployment status in enum/numerical format+type Status int++const (+	Done     Status = 0

Sorry for not catching all of these. Please add doc comments for exported const values as well.

kopachevsky

comment created time in 5 months

Pull request review commentGoogleCloudPlatform/cloud-foundation-toolkit

[dm][cli] Spring 15 and 16 stories

+package cmd++import (+	"encoding/json"+	"fmt"+	"io/ioutil"+	"log"+	"os"+	"path"+	"path/filepath"+	"strings"++	"github.com/spf13/cobra"+	"gopkg.in/yaml.v2"++	"github.com/GoogleCloudPlatform/cloud-foundation-toolkit/cli/deployment"+)++// --project flag value will be mapped during app initialization+var projectFlag string+var previewFlag bool = false+var showStagesFlag bool = false+var formatFlag string++var supportedExt = []string{"*.yaml", "*.yml", "*.jinja"}++func initCommon(command *cobra.Command) {+	command.PersistentFlags().StringVarP(&projectFlag, "project", "p", "", "project id")+	command.PersistentFlags().BoolVar(&previewFlag, "preview", false, "preview before apply changes")+	command.PersistentFlags().BoolVar(&showStagesFlag, "show-stages", false, "print deployment stages")+	command.PersistentFlags().StringVar(&formatFlag, "format", "", "formattedConfig for stages display, used in conjunction wiht --show-stages")+	rootCmd.AddCommand(command)+}++// common code for create/update/apply and delete actions+func execute(action string, cmd *cobra.Command, args []string) {+	setDefaultProjectID()+	cmd.Printf("%s deployment(s), configs %v, project %s\n", action, args, projectFlag)+	configs := loadConfigs(args)+	stages, err := deployment.Order(configs)+	if err != nil {+		log.Fatalf("Error ordering deployments in dependency order: %v", err)+	}+	isDelete := action == deployment.ActionDelete+	if isDelete {+		// reverse order, dependent goes first for deletion+		for i := len(stages)/2 - 1; i >= 0; i-- {+			opp := len(stages) - 1 - i+			stages[i], stages[opp] = stages[opp], stages[i]+		}+	}+	log.Printf("Ordered dependencies: %v", stages)++	if showStagesFlag {+		showStages(stages)+	} else {+		executeStages(action, stages, isDelete)+	}+}++func showStages(stages [][]deployment.Config) {+	switch formatFlag {+	case "":+		for i, level := range stages {+			log.Printf("---------- Stage %d ----------\n", i)+			for _, config := range level {+				log.Printf("- project: %s, deployment: %s, source: %s", config.GetProject(), config.Name, config.Source())+			}+		}+		log.Printf("------------------------------")+	case "yaml":+		output, _ := yaml.Marshal(formatedConfig(stages))+		log.Println("\n" + string(output))+	case "json":+		output, _ := json.MarshalIndent(formatedConfig(stages), "", "    ")+		log.Println("\n" + string(output))+	}+}++func executeStages(action string, stages [][]deployment.Config, isDelete bool) map[string]map[string]interface{} {+	outputs := make(map[string]map[string]interface{})+	for i, level := range stages {+		for _, config := range level {+			dep := deployment.NewDeployment(config, outputs, !isDelete)+			log.Printf("---------- Stage %d ----------\n", i)+			output, err := dep.Execute(action, previewFlag)+			log.Print(output)+			if err != nil {+				if action == deployment.ActionDelete {+					status, _ := deployment.GetStatus(dep)+					if status == deployment.NotFound {+						// for Delete action, Deployment might not exist, in this case just skip+						log.Printf("Deployment %v does not exist, skip deletion\n", dep)+						continue+					}+				}+				log.Fatalf("Error %s deployment: %v, erro: %v", action, dep, err)+			}+			if previewFlag {+				choice := deployment.GetUserInput("Update(u), Skip (s), or Abort(a) Deployment?", []string{"u", "s", "a"}, os.Stdin)+				switch choice {+				case "u":+					output, err := deployment.ApplyPreview(dep)+					log.Print(output)+					if err != nil {+						log.Fatalf("error %s deployment: %v, error: %v", action, dep, err)+					}+				case "s":+					output, err = deployment.CancelPreview(dep)+					if err != nil {+						log.Fatalf("error cancel-preuvew action for deployment: %v, error: %v", dep, err)
						log.Fatalf("error cancel-preview action for deployment: %v, error: %v", dep, err)
kopachevsky

comment created time in 5 months

Pull request review commentGoogleCloudPlatform/cloud-foundation-toolkit

[dm][cli] Spring 15 and 16 stories

+package cmd++import (+	"encoding/json"+	"errors"+	"fmt"+	"io/ioutil"+	"log"+	"os"+	"path"+	"path/filepath"+	"strings"++	"github.com/spf13/cobra"+	"gopkg.in/yaml.v2"++	"github.com/GoogleCloudPlatform/cloud-foundation-toolkit/cli/deployment"+)++// --project flag value will be mapped during app initialization+var projectFlag string+var previewFlag bool = false+var showStagesFlag bool = false+var formatFlag string++var supportedExt = []string{"*.yaml", "*.yml", "*.jinja"}++func initCommon(command *cobra.Command) {+	command.PersistentFlags().StringVarP(&projectFlag, "project", "p", "", "project id")+	command.PersistentFlags().BoolVar(&previewFlag, "preview", false, "preview before apply changes")+	command.PersistentFlags().BoolVar(&showStagesFlag, "show-stages", false, "print deployment stages")+	command.PersistentFlags().StringVar(&formatFlag, "format", "", "formattedConfig for stages display, used in conjunction wiht --show-stages")+	rootCmd.AddCommand(command)+}++// common code for create/update/apply and delete actions+func execute(action string, cmd *cobra.Command, args []string) {+	setDefaultProjectID()+	cmd.Printf("%s deployment(s), configs %v, project %s\n", action, args, projectFlag)+	configs := loadConfigs(args)+	stages, err := deployment.Order(configs)+	if err != nil {+		log.Fatalf("Error ordering deployments in dependency order: %v", err)+	}+	isDelete := action == deployment.ActionDelete+	if isDelete {+		// reverse order, dependent goes first for deletion+		for i := len(stages)/2 - 1; i >= 0; i-- {+			opp := len(stages) - 1 - i+			stages[i], stages[opp] = stages[opp], stages[i]+		}+	}+	log.Printf("Ordered dependencies: %v", stages)++	outputs := make(map[string]map[string]interface{})++	if showStagesFlag {+		showStages(stages)+	} else {+		executeStages(action, stages, outputs, isDelete)+	}+}++func showStages(stages [][]deployment.Config) {+	switch formatFlag {+	case "":+		for i, level := range stages {+			log.Printf("---------- Stage %d ----------\n", i)+			for _, config := range level {+				log.Printf("- project: %s, deployment: %s, source: %s", config.GetProject(), config.Name, config.Source())+			}+		}+		log.Printf("------------------------------")+	case "yaml":+		output, _ := yaml.Marshal(formatedConfig(stages))+		log.Println("\n" + string(output))+	case "json":+		output, _ := json.MarshalIndent(formatedConfig(stages), "", "    ")+		log.Println("\n" + string(output))+	}+}++func executeStages(action string, stages [][]deployment.Config, outputs map[string]map[string]interface{}, isDelete bool) {+	for i, level := range stages {+		for _, config := range level {+			dep := deployment.NewDeployment(config, outputs, !isDelete)+			log.Printf("---------- Stage %d ----------\n", i)+			output, err := dep.Execute(action, previewFlag)+			log.Print(output)+			if err != nil {+				if action == deployment.ActionDelete {+					status, _ := deployment.GetStatus(dep)+					if status == deployment.NotFound {+						// for Delete action, Deployment might not exists, in this case just skip+						log.Printf("Deployment %v does not exists, skip deletion\n", dep)+						continue+					}+				}+				log.Fatalf("Error %s deployment: %v, erro: %v", action, dep, err)+			}+			if previewFlag {+				choise := deployment.GetUserInput("Update(u), Skip (s), or Abort(a) Deployment?", []string{"u", "s", "a"}, os.Stdin)+				switch choise {+				case "u":+					output, err := deployment.ApplyPreview(dep)+					log.Print(output)+					if err != nil {+						log.Fatalf("error %s deployment: %v, error: %v", action, dep, err)+					}+				case "s":+					output, err = deployment.CancelPreview(dep)+					if err != nil {+						log.Fatalf("error cancel-preuvew action for deployment: %v, error: %v", dep, err)+					}+					log.Printf("canceled %s action for deployment: %v", action, dep)+					if action == deployment.ActionCreate {+						log.Printf("delete canceled creation for deployment: %v", dep)+						deployment.Delete(dep, false)+					}+				case "a":+					log.Print("Aborting deployment run!")+					os.Exit(0)+				}+			}+			// after create/update/apply actions - put deployment outputs to global map fro cross-deployment+			// reference variables substitutions, after delete - remove deployment outputs from map, to avoid its usage+			if action != deployment.ActionDelete {+				outputs[dep.FullName()] = dep.Outputs+			} else {+				delete(outputs, dep.FullName())+			}+		}+	}+}++/**+ listConfigs search for config files according rules described in CLL usage section of following doc:+https://github.com/GoogleCloudPlatform/cloud-foundation-toolkit/blob/master/dm/docs/userguide.md#syntax+listConfigs returns map[fileName: fileContent] for files, and list of strings for yamls passed as string parameters to cli+*/+func listConfigs(args []string, errs map[string]error) (map[string]string, []string) {+	resFiles := map[string]string{}+	var resYamls []string+	for _, arg := range args {+		stat, err := os.Stat(arg)+		if err == nil {

Apologies! I oversimplified when I said return, but I think you can still restructure this to outdent the normal flow from the error flow:

for ... {
  stat, err := os.Stat(arg)
  if os.IsNotExist(err) {
    // os.IsNotExist branch logic
  } else if err != nil {
    log.Fatalf(...)
  }

  // regular, non-error logic
}

return resFiles, resYamls
kopachevsky

comment created time in 5 months

Pull request review commentGoogleCloudPlatform/cloud-foundation-toolkit

[dm][cli] Spring 15 and 16 stories

 import ( 	"gopkg.in/yaml.v2" ) +// Status represent Deployment status in enum/numerical format+type Status int++const (+	Done     Status = 0+	Pending  Status = 1+	Running  Status = 2+	NotFound Status = 3+	Error    Status = -1+)++const (+	ActionApply  string = "apply"+	ActionDelete string = "delete"+	ActionCreate string = "create"+	ActionUpdate string = "update"+)++var actions = []string{ActionApply, ActionDelete, ActionCreate, ActionUpdate}+ // The runGCloud function runs the gcloud tool with the specified arguments. It is implemented // as a variable so that it can be mocked in tests of its exported consumers. var runGCloud = func(args ...string) (result string, err error) {-	args = append(args, "--format", "yaml") 	log.Println("gcloud", strings.Join(args, " ")) 	cmd := exec.Command("gcloud", args...)-	outBuff := &bytes.Buffer{}-	errBuff := &bytes.Buffer{}-	cmd.Stdout = outBuff-	cmd.Stderr = errBuff 	// pass user's PATH env variable, expected gcloud executable can be found in PATH 	cmd.Env = append(cmd.Env, fmt.Sprintf("PATH=%s", os.Getenv("PATH"))) -	if err := cmd.Start(); err != nil {-		log.Printf("Failed to start cmd: %v, \n Output:\n %v", err, errBuff.String())-		return "", err-	}+	output, err := cmd.CombinedOutput() -	if err := cmd.Wait(); err != nil {-		log.Printf("Cmd returned error: %v, \n Output:\n %v", err, errBuff.String())-		return errBuff.String(), err+	if err != nil {+		log.Printf("failed to start cmd: %v, output: %v", err, string(output))+		return string(output), err 	} -	return outBuff.String(), err+	return string(output), err } -// GetOutputs retrive existing Deployment outputs using gcloud and store result in map[string]string-// where "resourceName.propertyName" is key, and value is string representation of the output value.-func GetOutputs(name string, project string) (map[string]string, error) {-	data, err := runGCloud("deployment-manager", "manifests", "describe", "--deployment", name, "--project", project)+// GetOutputs retrieves existing Deployment outputs using gcloud and store result in map[string]interface{}+// where "resourceName.propertyName" is key, and value is string (in case of flat value) or JSON object.+func GetOutputs(project string, name string) (map[string]interface{}, error) {+	data, err := runGCloud("deployment-manager", "manifests", "describe", "--deployment", name, "--project", project, "--format", "yaml") 	if err != nil { 		log.Printf("Failed to get deployment manifest: %v", err) 		return nil, err 	} 	return parseOutputs(data) } -// Create creates a new Deployment based on a Deployment object passed into it.-func Create(deployment *Deployment) (*Deployment, error) {+// returns project id taken from local gcloud configuration
// GCloudDefaultProjectID returns the default project id taken from local gcloud configuration.
kopachevsky

comment created time in 5 months

Pull request review commentGoogleCloudPlatform/cloud-foundation-toolkit

[dm][cli] Spring 15 and 16 stories

+package cmd++import (+	"encoding/json"+	"fmt"+	"io/ioutil"+	"log"+	"os"+	"path"+	"path/filepath"+	"strings"++	"github.com/spf13/cobra"+	"gopkg.in/yaml.v2"++	"github.com/GoogleCloudPlatform/cloud-foundation-toolkit/cli/deployment"+)++// --project flag value will be mapped during app initialization+var projectFlag string+var previewFlag bool = false+var showStagesFlag bool = false+var formatFlag string++var supportedExt = []string{"*.yaml", "*.yml", "*.jinja"}++func initCommon(command *cobra.Command) {+	command.PersistentFlags().StringVarP(&projectFlag, "project", "p", "", "project id")+	command.PersistentFlags().BoolVar(&previewFlag, "preview", false, "preview before apply changes")+	command.PersistentFlags().BoolVar(&showStagesFlag, "show-stages", false, "print deployment stages")+	command.PersistentFlags().StringVar(&formatFlag, "format", "", "formattedConfig for stages display, used in conjunction wiht --show-stages")+	rootCmd.AddCommand(command)+}++// common code for create/update/apply and delete actions+func execute(action string, cmd *cobra.Command, args []string) {+	setDefaultProjectID()+	cmd.Printf("%s deployment(s), configs %v, project %s\n", action, args, projectFlag)+	configs := loadConfigs(args)+	stages, err := deployment.Order(configs)+	if err != nil {+		log.Fatalf("Error ordering deployments in dependency order: %v", err)+	}+	isDelete := action == deployment.ActionDelete+	if isDelete {+		// reverse order, dependent goes first for deletion+		for i := len(stages)/2 - 1; i >= 0; i-- {+			opp := len(stages) - 1 - i+			stages[i], stages[opp] = stages[opp], stages[i]+		}+	}+	log.Printf("Ordered dependencies: %v", stages)++	if showStagesFlag {+		showStages(stages)+	} else {+		executeStages(action, stages, isDelete)+	}+}++func showStages(stages [][]deployment.Config) {+	switch formatFlag {+	case "":+		for i, level := range stages {+			log.Printf("---------- Stage %d ----------\n", i)+			for _, config := range level {+				log.Printf("- project: %s, deployment: %s, source: %s", config.GetProject(), config.Name, config.Source())+			}+		}+		log.Printf("------------------------------")+	case "yaml":+		output, _ := yaml.Marshal(formatedConfig(stages))+		log.Println("\n" + string(output))+	case "json":+		output, _ := json.MarshalIndent(formatedConfig(stages), "", "    ")+		log.Println("\n" + string(output))+	}+}++func executeStages(action string, stages [][]deployment.Config, isDelete bool) map[string]map[string]interface{} {+	outputs := make(map[string]map[string]interface{})+	for i, level := range stages {+		for _, config := range level {+			dep := deployment.NewDeployment(config, outputs, !isDelete)+			log.Printf("---------- Stage %d ----------\n", i)+			output, err := dep.Execute(action, previewFlag)+			log.Print(output)+			if err != nil {+				if action == deployment.ActionDelete {+					status, _ := deployment.GetStatus(dep)+					if status == deployment.NotFound {+						// for Delete action, Deployment might not exist, in this case just skip+						log.Printf("Deployment %v does not exist, skip deletion\n", dep)+						continue+					}+				}+				log.Fatalf("Error %s deployment: %v, erro: %v", action, dep, err)+			}+			if previewFlag {+				choice := deployment.GetUserInput("Update(u), Skip (s), or Abort(a) Deployment?", []string{"u", "s", "a"}, os.Stdin)+				switch choice {+				case "u":+					output, err := deployment.ApplyPreview(dep)+					log.Print(output)+					if err != nil {+						log.Fatalf("error %s deployment: %v, error: %v", action, dep, err)+					}+				case "s":+					output, err = deployment.CancelPreview(dep)+					if err != nil {+						log.Fatalf("error cancel-preuvew action for deployment: %v, error: %v", dep, err)+					}+					log.Printf("canceled %s action for deployment: %v", action, dep)+					if action == deployment.ActionCreate {+						log.Printf("delete canceled creation for deployment: %v", dep)+						output, err = deployment.Delete(dep, false)+						if err != nil {+							log.Fatalf("error cancel-preuvew action for deployment: %v, error: %v", dep, err)
							log.Fatalf("error cancel-preview action for deployment: %v, error: %v", dep, err)
kopachevsky

comment created time in 5 months

more