github.com/goonzoid/gcli@v0.2.3-0.20150926213610-155587606ea1/command/design.go (about)

     1  package command
     2  
     3  import (
     4  	"bufio"
     5  	"flag"
     6  	"fmt"
     7  	"io"
     8  	"os"
     9  	"strings"
    10  
    11  	"github.com/BurntSushi/toml"
    12  	"github.com/tcnksm/gcli/skeleton"
    13  	"github.com/tcnksm/go-gitconfig"
    14  )
    15  
    16  const (
    17  	defaultOutputFmt = "%s-design.toml"
    18  )
    19  
    20  // DesignCommand is a Command that generates a new cli project
    21  type DesignCommand struct {
    22  	Meta
    23  }
    24  
    25  // Run generates a new cli project. It returns exit code
    26  func (c *DesignCommand) Run(args []string) int {
    27  
    28  	var (
    29  		output       string
    30  		owner        string
    31  		commands     []skeleton.Command
    32  		flags        []skeleton.Flag
    33  		frameworkStr string
    34  	)
    35  
    36  	uflag := flag.NewFlagSet("design", flag.ContinueOnError)
    37  	uflag.Usage = func() { c.UI.Error(c.Help()) }
    38  
    39  	uflag.Var((*CommandFlag)(&commands), "command", "command")
    40  	uflag.Var((*CommandFlag)(&commands), "c", "command (short)")
    41  
    42  	uflag.Var((*FlagFlag)(&flags), "flag", "flag")
    43  	uflag.Var((*FlagFlag)(&flags), "f", "flag (short)")
    44  
    45  	uflag.StringVar(&frameworkStr, "framework", defaultFrameworkString, "framework")
    46  	uflag.StringVar(&frameworkStr, "F", defaultFrameworkString, "framework (short)")
    47  
    48  	uflag.StringVar(&owner, "owner", "", "owner")
    49  	uflag.StringVar(&owner, "o", "", "owner (short)")
    50  
    51  	uflag.StringVar(&output, "output", "", "output")
    52  	uflag.StringVar(&output, "O", "", "output (short)")
    53  
    54  	errR, errW := io.Pipe()
    55  	errScanner := bufio.NewScanner(errR)
    56  	uflag.SetOutput(errW)
    57  
    58  	go func() {
    59  		for errScanner.Scan() {
    60  			c.UI.Error(errScanner.Text())
    61  		}
    62  	}()
    63  
    64  	if err := uflag.Parse(args); err != nil {
    65  		return 1
    66  	}
    67  
    68  	parsedArgs := uflag.Args()
    69  	if len(parsedArgs) != 1 {
    70  		msg := fmt.Sprintf("Invalid arguments: usage gcli design [option] NAME")
    71  		c.UI.Error(msg)
    72  		return 1
    73  	}
    74  
    75  	name := parsedArgs[0]
    76  
    77  	// If output file name is not provided use default one
    78  	if len(output) == 0 {
    79  		output = fmt.Sprintf(defaultOutputFmt, name)
    80  	}
    81  
    82  	if _, err := os.Stat(output); !os.IsNotExist(err) {
    83  		msg := fmt.Sprintf("Cannot create design file %s: file exists", output)
    84  		c.UI.Error(msg)
    85  		return 1
    86  	}
    87  
    88  	outputFile, err := os.Create(output)
    89  	if err != nil {
    90  		msg := fmt.Sprintf("Cannot create design file %s: %s", output, err)
    91  		c.UI.Error(msg)
    92  		return 1
    93  	}
    94  
    95  	if owner == "" {
    96  		owner, err = gitconfig.GithubUser()
    97  		if err != nil {
    98  			owner, _ = gitconfig.Username()
    99  		}
   100  	}
   101  
   102  	// If no commands are specified, set emply value so that
   103  	// user can understand how to write
   104  	if len(commands) < 1 && len(flags) < 1 {
   105  		commands = []skeleton.Command{
   106  			{
   107  				Name: "",
   108  			},
   109  		}
   110  	}
   111  
   112  	// Define Executable
   113  	executable := &skeleton.Executable{
   114  		Name:         name,
   115  		Owner:        owner,
   116  		Commands:     commands,
   117  		Flags:        flags,
   118  		Version:      skeleton.DefaultVersion,
   119  		Description:  skeleton.DefaultDescription,
   120  		FrameworkStr: frameworkStr,
   121  	}
   122  
   123  	if err := toml.NewEncoder(outputFile).Encode(executable); err != nil {
   124  		msg := fmt.Sprintf("Failed to generate design file: %s", err)
   125  		c.UI.Error(msg)
   126  		return 1
   127  	}
   128  
   129  	c.UI.Info(fmt.Sprintf("====> Successfully generated %s", output))
   130  	return ExitCodeOK
   131  }
   132  
   133  // Synopsis is a one-line, short synopsis of the command.
   134  func (c *DesignCommand) Synopsis() string {
   135  	return "Generate project design template"
   136  }
   137  
   138  // Help is a long-form help text that includes the command-line
   139  // usage, a brief few sentences explaining the function of the command,
   140  // and the complete list of flags the command accepts.
   141  func (c *DesignCommand) Help() string {
   142  	helpText := `
   143  Usage: gcli design [option] NAME
   144  
   145    Generate project design template (as toml file). You can pass that file to 'gcli apply'
   146    command and generate CLI tool based on template file. You can define what command
   147    and what flag you need on that file.
   148  
   149  Options:
   150  
   151    -command=name, -c           Command name which you want to add.
   152                                This is valid only when cli pacakge support commands.
   153                                This can be specified multiple times. Synopsis can be
   154                                set after ":". Namely, you can specify command by 
   155                                -command=NAME:SYNOPSYS. Only NAME is required.
   156                                You can set multiple variables at same time with ","
   157                                separator.
   158  
   159    -flag=name, -f              Global flag option name which you want to add.
   160                                This can be specified multiple times. By default, flag type
   161                                is string and its description is empty. You can set them,
   162                                with ":" separator. Namaly, you can specify flag by
   163                                -flag=NAME:TYPE:DESCIRPTION. Order must be flow  this and
   164                                TYPE must be string, bool or int. Only NAME is required.
   165                                You can set multiple variables at same time with ","
   166                                separator.
   167  
   168    -framework=name, -F         Cli framework name. By default, gcli use "codegangsta/cli"
   169                                To check cli framework you can use, run 'gcli list'.
   170                                If you set invalid framework, it will be failed.
   171  
   172    -owner=name, -o             Command owner (author) name. This value is also used for
   173                                import path name. By default, owner name is extracted from
   174                                ~/.gitconfig variable.
   175  
   176  
   177    -output, -O                 Change output file name. By default, gcli use "NAME-design.toml"
   178  `
   179  	return strings.TrimSpace(helpText)
   180  }