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 }