Пример #1
0
// 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

}
Пример #2
0
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)
	}
}
Пример #3
0
// 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(&current, "current", false, "current")
	uflag.BoolVar(&current, "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
		}
	}
}
Пример #4
0
// 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
		}
	}
}