Example #1
0
File: new.go Project: wallyqs/gcli
// Run generates a new cli project. It returns exit code
func (c *NewCommand) Run(args []string) int {

	var (
		commands     []skeleton.Command
		flags        []skeleton.Flag
		frameworkStr string
		owner        string
		skipTest     bool
		verbose      bool
	)

	uflag := c.Meta.NewFlagSet("new", c.Help())

	uflag.Var((*CommandFlag)(&commands), "command", "command")
	uflag.Var((*CommandFlag)(&commands), "c", "command (short)")

	uflag.Var((*FlagFlag)(&flags), "flag", "flag")
	uflag.Var((*FlagFlag)(&flags), "f", "flag (short)")

	uflag.StringVar(&frameworkStr, "framework", defaultFrameworkString, "framework")
	uflag.StringVar(&frameworkStr, "F", defaultFrameworkString, "framework (short)")

	uflag.StringVar(&owner, "owner", "", "owner")
	uflag.StringVar(&owner, "o", "", "owner (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)")

	if err := uflag.Parse(args); err != nil {
		return 1
	}

	parsedArgs := uflag.Args()
	if len(parsedArgs) != 1 {
		msg := fmt.Sprintf("Invalid arguments: %s", strings.Join(parsedArgs, " "))
		c.UI.Error(msg)
		return 1
	}

	name := parsedArgs[0]

	// TODO, should be configurable
	// or chagne direcotry to GOPATH/github.com/owner/output
	// Some gcli template assume command is executed
	// from GOPATH/github.com/owner
	output := 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
	}

	framework, err := skeleton.FrameworkByName(frameworkStr)
	if err != nil {
		c.UI.Error(fmt.Sprintf("Failed to generate %q: %s", name, err.Error()))
		return 1
	}

	// Use .gitconfig value.
	if owner == "" {
		owner, err = gitconfig.GithubUser()
		if err != nil {
			owner, err = gitconfig.Username()
			if err != nil {
				msg := "Cannot find owner name\n" +
					"By default, owener name is retrieved from `~/.gitcofig` file.\n" +
					"Please set one via -owner option or `~/.gitconfig` file."
				c.UI.Error(msg)
				return 1
			}
		}
	}

	// Define Executable
	executable := &skeleton.Executable{
		Name:        name,
		Owner:       owner,
		Commands:    commands,
		Flags:       flags,
		Version:     skeleton.DefaultVersion,
		Description: skeleton.DefaultDescription,
	}

	// 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", name))
			return ExitCodeOK
		}
	}
}
Example #2
0
// Run generates a new cli project. It returns exit code
func (c *NewCommand) Run(args []string) int {

	var (
		commands     []*skeleton.Command
		flags        []*skeleton.Flag
		frameworkStr string
		owner        string
		staticDir    string
		vcsHost      string
		current      bool
		skipTest     bool
		verbose      bool
	)

	uflag := c.Meta.NewFlagSet("new", c.Help())

	uflag.Var((*CommandFlag)(&commands), "command", "command")
	uflag.Var((*CommandFlag)(&commands), "c", "command (short)")

	uflag.Var((*FlagFlag)(&flags), "flag", "flag")
	uflag.Var((*FlagFlag)(&flags), "f", "flag (short)")

	uflag.StringVar(&frameworkStr, "framework", defaultFrameworkString, "framework")
	uflag.StringVar(&frameworkStr, "F", defaultFrameworkString, "framework (short)")

	uflag.StringVar(&owner, "owner", "", "owner")
	uflag.StringVar(&owner, "o", "", "owner (short)")

	uflag.StringVar(&staticDir, "static-dir", "", "")

	uflag.StringVar(&vcsHost, "vcs", DefaultVCSHost, "")

	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)")

	if err := uflag.Parse(args); err != nil {
		return 1
	}

	parsedArgs := uflag.Args()
	if len(parsedArgs) != 1 {
		msg := fmt.Sprintf("Invalid arguments: %s", strings.Join(parsedArgs, " "))
		c.UI.Error(msg)
		return 1
	}

	name := parsedArgs[0]

	// If owner is not provided, use .gitconfig value.
	if owner == "" {
		var err error
		owner, err = gitconfig.GithubUser()
		if err != nil {
			owner, err = gitconfig.Username()
			if err != nil {
				msg := "Cannot find owner name\n" +
					"By default, owener name is retrieved from `~/.gitcofig` file.\n" +
					"Please set one via -owner option or `~/.gitconfig` file."
				c.UI.Error(msg)
				return 1
			}
		}
	}

	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", vcsHost, owner)

	output := 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/%s/%s.", vcsHost, 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
	}

	framework, err := skeleton.FrameworkByName(frameworkStr)
	if err != nil {
		c.UI.Error(fmt.Sprintf("Failed to generate %q: %s", name, err.Error()))
		return 1
	}

	if staticDir == "" {
		localDir, err := c.LocalDir()
		if err != nil {
			c.UI.Error(err.Error())
			return ExitCodeFailed
		}
		staticDir = filepath.Join(localDir, DefaultLocalStaticDir)
	}

	// Define Executable
	executable := &skeleton.Executable{
		Name:        name,
		Owner:       owner,
		VCSHost:     vcsHost,
		Commands:    commands,
		Flags:       flags,
		Version:     skeleton.DefaultVersion,
		Description: skeleton.DefaultDescription,
	}

	// Channels to receive artifact path (result) and error
	artifactCh, errCh := make(chan string), make(chan error)

	// Define Skeleton
	skeleton := &skeleton.Skeleton{
		Path:       output,
		StaticDir:  staticDir,
		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", name))
			return ExitCodeOK
		}
	}
}
Example #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
		}
	}
}
Example #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
		}
	}
}