// Run validates template file func (c *ValidateCommand) Run(args []string) int { uflag := c.Meta.NewFlagSet("validate", c.Help()) if err := uflag.Parse(args); err != nil { return 1 } parsedArgs := uflag.Args() if len(parsedArgs) != 1 { c.UI.Error("Invalid argument") c.UI.Error(c.Help()) return 1 } designFile := parsedArgs[0] // Check file is exist or not if _, err := os.Stat(designFile); os.IsNotExist(err) { c.UI.Error(fmt.Sprintf( "Design file %q does not exsit: %s", designFile, err)) return 1 } // Decode design file as skeleton.Executable executable := skeleton.NewExecutable() if _, err := toml.DecodeFile(designFile, executable); err != nil { c.UI.Error(fmt.Sprintf( "Failed to decode design file %q: %s", designFile, err)) return 1 } errs := executable.Validate() if len(errs) != 0 { c.UI.Error(fmt.Sprintf( "%q is not valid template file. It has %d errors:", designFile, len(errs))) for _, err := range errs { c.UI.Error(fmt.Sprintf( " * %s", err.Error())) } return ExitCodeFailed } c.UI.Info(fmt.Sprintf( "%q is valid template file.\n"+ "You can generate cli project based on this file via `gcli apply` command", designFile)) return ExitCodeOK }
func TestDesignCommand(t *testing.T) { ui := new(cli.MockUi) c := &DesignCommand{ Meta: Meta{ UI: ui, }, } // Create temp directory to output file tmpDir, err := ioutil.TempDir("", "design_command") if err != nil { t.Fatal(err) } backFunc, err := TmpChdir(tmpDir) if err != nil { t.Fatal(err) } defer backFunc() name := "todo" if code := c.Run([]string{name}); code != 0 { t.Fatalf("bad status code: %d\n\n%s", code, ui.ErrorWriter.String()) } // Inspect generated file outputFile := filepath.Join(tmpDir, fmt.Sprintf(defaultOutputFmt, name)) executable := skeleton.NewExecutable() if _, err := toml.DecodeFile(outputFile, executable); err != nil { t.Fatal(err) } if executable.Name != name { t.Errorf("expects %q to be eq %q", executable.Name, name) } if executable.Version != skeleton.DefaultVersion { t.Errorf("expects %q to be eq %q", executable.Version, skeleton.DefaultVersion) } if executable.FrameworkStr != defaultFrameworkString { t.Errorf("expects %q to be eq %q", executable.FrameworkStr, defaultFrameworkString) } }
// Run generates a new cli project. It returns exit code func (c *ApplyCommand) Run(args []string) int { var ( frameworkStr string owner string name string current bool skipTest bool verbose bool ) uflag := c.Meta.NewFlagSet("apply", c.Help()) uflag.StringVar(&frameworkStr, "framework", "", "framework") uflag.StringVar(&frameworkStr, "F", "", "framework (short)") uflag.BoolVar(¤t, "current", false, "current") uflag.BoolVar(¤t, "C", false, "current") uflag.BoolVar(&skipTest, "skip-test", false, "skip-test") uflag.BoolVar(&skipTest, "T", false, "skip-test (short)") uflag.BoolVar(&verbose, "verbose", false, "verbose") uflag.BoolVar(&verbose, "V", false, "verbose (short)") // These flags are supposed only to use in test uflag.StringVar(&owner, "owner", "", "owner (Should only for test)") uflag.StringVar(&name, "name", "", "name (Should only for test)") if err := uflag.Parse(args); err != nil { return 1 } parsedArgs := uflag.Args() if len(parsedArgs) != 1 { c.UI.Error("Invalid argument: Usage glic apply [options] FILE") return 1 } designFile := parsedArgs[0] c.UI.Info(fmt.Sprintf( "Use design template %q for generating new cli project", designFile)) // Check file is exist or not if _, err := os.Stat(designFile); os.IsNotExist(err) { c.UI.Error(fmt.Sprintf( "Design file does not exsit")) return 1 } // Decode design file as skeleton.Executable executable := skeleton.NewExecutable() if _, err := toml.DecodeFile(designFile, executable); err != nil { c.UI.Error(fmt.Sprintf( "Failed to decode design file %q: %s", designFile, err)) return 1 } if err := executable.Fix(); err != nil { c.UI.Error(fmt.Sprintf( "Failed to fix input value: %s", err)) return 1 } // validate executable if errs := executable.Validate(); len(errs) > 0 { c.UI.Error(fmt.Sprintf( "%q is not valid template file. It has %d errors:", designFile, len(errs))) for _, err := range errs { c.UI.Error(fmt.Sprintf( " * %s", err.Error())) } return ExitCodeFailed } currentDir, err := os.Getwd() if err != nil { c.UI.Error(fmt.Sprintf( "Failed to get current directroy: %s", err)) return ExitCodeFailed } gopath := os.Getenv(EnvGoPath) if gopath == "" { c.UI.Error(fmt.Sprintf( "Failed to read GOPATH: it should not be empty")) return ExitCodeFailed } idealDir := filepath.Join(gopath, "src", "github.com", owner) output := executable.Name if currentDir != idealDir && !current { c.UI.Output("") c.UI.Output(fmt.Sprintf("====> WARNING: You are not in the directory gcli expects.")) c.UI.Output(fmt.Sprintf(" The codes will be generated be in $GOPATH/src/github.com/%s.", owner)) c.UI.Output(fmt.Sprintf(" Not in the current directory. This is because the output")) c.UI.Output(fmt.Sprintf(" codes use import path based on that path.")) c.UI.Output("") output = filepath.Join(idealDir, name) } if _, err := os.Stat(output); !os.IsNotExist(err) { msg := fmt.Sprintf("Cannot create directory %s: file exists", output) c.UI.Error(msg) return 1 } // Check option input first and if it's specified use it if len(frameworkStr) == 0 { if len(executable.FrameworkStr) != 0 { // If FrameworStr is specified from design file use it frameworkStr = executable.FrameworkStr } else { frameworkStr = defaultFrameworkString } } fmt.Println(frameworkStr) framework, err := skeleton.FrameworkByName(frameworkStr) if err != nil { c.UI.Error(fmt.Sprintf("Failed to generate %q: %s", executable.Name, err.Error())) return 1 } if len(name) != 0 { executable.Name = name output = name } if len(owner) != 0 { executable.Owner = owner } // Channels to receive artifact path (result) and error artifactCh, errCh := make(chan string), make(chan error) // Define Skeleton skeleton := &skeleton.Skeleton{ Path: output, Framework: framework, SkipTest: skipTest, Executable: executable, ArtifactCh: artifactCh, ErrCh: errCh, Verbose: verbose, LogWriter: os.Stdout, } // Create project directory doneCh := skeleton.Generate() for { select { case artifact := <-artifactCh: c.UI.Output(fmt.Sprintf(" Created %s", artifact)) case err := <-errCh: c.UI.Error(fmt.Sprintf("Failed to generate %s: %s", output, err.Error())) // If some file are created before error happend // Should be cleanuped if _, err := os.Stat(output); !os.IsNotExist(err) { c.UI.Output(fmt.Sprintf("Cleanup %s", output)) os.RemoveAll(output) } return ExitCodeFailed case <-doneCh: c.UI.Info(fmt.Sprintf("====> Successfully generated %s", executable.Name)) return ExitCodeOK } } }
// Run generates a new cli project. It returns exit code func (c *ApplyCommand) Run(args []string) int { var ( frameworkStr string skipTest bool verbose bool owner string name string ) uflag := flag.NewFlagSet("apply", flag.ContinueOnError) uflag.Usage = func() { c.UI.Error(c.Help()) } uflag.StringVar(&frameworkStr, "framework", "", "framework") uflag.StringVar(&frameworkStr, "F", "", "framework (short)") uflag.BoolVar(&skipTest, "skip-test", false, "skip-test") uflag.BoolVar(&skipTest, "T", false, "skip-test (short)") uflag.BoolVar(&verbose, "verbose", false, "verbose") uflag.BoolVar(&verbose, "V", false, "verbose (short)") // These flags are supposed only to use in test uflag.StringVar(&owner, "owner", "", "owner (Should only for test)") uflag.StringVar(&name, "name", "", "name (Should only for test)") errR, errW := io.Pipe() errScanner := bufio.NewScanner(errR) uflag.SetOutput(errW) go func() { for errScanner.Scan() { c.UI.Error(errScanner.Text()) } }() if err := uflag.Parse(args); err != nil { return 1 } parsedArgs := uflag.Args() if len(parsedArgs) != 1 { c.UI.Error("Invalid argument: Usage glic apply [options] FILE") return 1 } designFile := parsedArgs[0] c.UI.Info(fmt.Sprintf( "Use design template %q for generating new cli project", designFile)) // Check file is exist or not if _, err := os.Stat(designFile); os.IsNotExist(err) { c.UI.Error(fmt.Sprintf( "Design file does not exsit")) return 1 } // Decode design file as skeleton.Executable executable := skeleton.NewExecutable() if _, err := toml.DecodeFile(designFile, executable); err != nil { c.UI.Error(fmt.Sprintf( "Failed to decode design file %q: %s", designFile, err)) return 1 } // validate executable if errs := executable.Validate(); len(errs) > 0 { c.UI.Error(fmt.Sprintf( "%q is not valid template file. It has %d errors:", designFile, len(errs))) for _, err := range errs { c.UI.Error(fmt.Sprintf( " * %s", err.Error())) } return ExitCodeFailed } output := executable.Name if _, err := os.Stat(output); !os.IsNotExist(err) { msg := fmt.Sprintf("Cannot create directory %s: file exists", output) c.UI.Error(msg) return 1 } // Check option input first and if it's specified use it if len(frameworkStr) == 0 { if len(executable.FrameworkStr) != 0 { // If FrameworStr is specified from design file use it frameworkStr = executable.FrameworkStr } else { frameworkStr = defaultFrameworkString } } fmt.Println(frameworkStr) framework, err := skeleton.FrameworkByName(frameworkStr) if err != nil { c.UI.Error(fmt.Sprintf("Failed to generate %q: %s", executable.Name, err.Error())) return 1 } // Run fix flag struct. complement empty variable. if len(executable.Flags) > 0 { fixedFlags := []skeleton.Flag{} for _, f := range executable.Flags { if err := f.Fix(); err != nil { c.UI.Error(fmt.Sprintf( "Failed to fix flag struct: %s", err.Error())) return 1 } fixedFlags = append(fixedFlags, f) } executable.Flags = fixedFlags } if len(name) != 0 { executable.Name = name output = name } if len(owner) != 0 { executable.Owner = owner } // Channels to receive artifact path (result) and error artifactCh, errCh := make(chan string), make(chan error) // Define Skeleton skeleton := &skeleton.Skeleton{ Path: output, Framework: framework, SkipTest: skipTest, Executable: executable, ArtifactCh: artifactCh, ErrCh: errCh, Verbose: verbose, LogWriter: os.Stdout, } // Create project directory doneCh := skeleton.Generate() for { select { case artifact := <-artifactCh: c.UI.Output(fmt.Sprintf(" Created %s", artifact)) case err := <-errCh: c.UI.Error(fmt.Sprintf("Failed to generate %s: %s", output, err.Error())) // If some file are created before error happend // Should be cleanuped if _, err := os.Stat(output); !os.IsNotExist(err) { c.UI.Output(fmt.Sprintf("Cleanup %s", output)) os.RemoveAll(output) } return ExitCodeFailed case <-doneCh: c.UI.Info(fmt.Sprintf("====> Successfully generated %s", executable.Name)) return ExitCodeOK } } }