github.com/derekparker/go-pear@v1.3.2/main.go (about) 1 package main 2 3 import ( 4 "bufio" 5 "fmt" 6 "io/ioutil" 7 "log" 8 "os" 9 "os/user" 10 "path" 11 "sort" 12 "strings" 13 14 "github.com/jessevdk/go-flags" 15 "github.com/libgit2/git2go" 16 "gopkg.in/v1/yaml" 17 ) 18 19 const version = "1.3.2" 20 21 type Config struct { 22 Email string 23 Devs map[string]string 24 } 25 26 type options struct { 27 File string `short:"f" long:"file" description:"Optional alternative git config file"` 28 Email string `short:"e" long:"email" description:"Base author email"` 29 Global bool `short:"g" long:"global" description:"Modify global git settings"` 30 Unset bool `short:"u" long:"unset" description:"Unset local pear information"` 31 Version bool `short:"v" long:"version" description:"Print version string"` 32 } 33 34 func pearrcpath() string { 35 return path.Join(os.Getenv("HOME"), ".pearrc") 36 } 37 38 func parseFlags() ([]string, *options, error) { 39 opts := &options{} 40 devs, err := flags.ParseArgs(opts, os.Args[1:]) 41 if err != nil { 42 return nil, nil, err 43 } 44 45 return devs, opts, nil 46 } 47 48 func initGitConfig(opts *options) (*git.Config, error) { 49 wd, err := os.Getwd() 50 if err != nil { 51 return nil, err 52 } 53 54 usr, err := user.Current() 55 if err != nil { 56 return nil, err 57 } 58 59 repopath, err := git.Discover(wd, false, []string{usr.HomeDir}) 60 if err != nil { 61 return nil, err 62 } 63 64 repo, err := git.OpenRepository(repopath) 65 if err != nil { 66 return nil, err 67 } 68 69 gitconf, err := repo.Config() 70 if err != nil { 71 return nil, err 72 } 73 74 if opts.File != "" { 75 err = gitconf.AddFile(opts.File, git.ConfigLevelApp, false) 76 if err != nil { 77 return nil, err 78 } 79 } 80 81 if opts.Global { 82 glconfpath := path.Join(usr.HomeDir, ".gitconfig") 83 84 err = gitconf.AddFile(glconfpath, git.ConfigLevelGlobal, false) 85 if err != nil { 86 return nil, err 87 } 88 } 89 90 return gitconf, nil 91 } 92 93 func printStderrAndDie(err error) { 94 os.Stderr.WriteString(err.Error()) 95 os.Exit(1) 96 } 97 98 func main() { 99 devs, opts, err := parseFlags() 100 if err != nil { 101 return 102 } 103 104 if opts.Version { 105 fmt.Printf("Pear version %s\n", version) 106 os.Exit(0) 107 } 108 109 gitconfig, err := initGitConfig(opts) 110 if err != nil { 111 printStderrAndDie(err) 112 } 113 114 defer gitconfig.Free() 115 116 if len(os.Args) == 1 { 117 fmt.Println(username(gitconfig)) 118 os.Exit(0) 119 } 120 121 conf, err := readPearrc(pearrcpath()) 122 if err != nil { 123 printStderrAndDie(err) 124 } 125 126 sanitizeDevNames(devs) 127 128 if opts.Unset { 129 removePair(gitconfig) 130 os.Exit(0) 131 } 132 133 var ( 134 fullnames = checkPair(devs, conf) 135 email = formatEmail(checkEmail(conf), devs) 136 ) 137 138 setPair(email, fullnames, gitconfig) 139 savePearrc(conf, pearrcpath()) 140 } 141 142 func username(gitconfig *git.Config) string { 143 name, err := gitconfig.LookupString("user.name") 144 if err != nil { 145 printStderrAndDie(err) 146 } 147 148 return name 149 } 150 151 func email(gitconfig *git.Config) string { 152 email, err := gitconfig.LookupString("user.email") 153 if err != nil { 154 printStderrAndDie(err) 155 } 156 157 return email 158 } 159 160 func setPair(email string, pairs []string, gitconfig *git.Config) { 161 pair := strings.Join(pairs, " and ") 162 163 err := gitconfig.SetString("user.name", pair) 164 if err != nil { 165 printStderrAndDie(err) 166 } 167 168 err = gitconfig.SetString("user.email", email) 169 if err != nil { 170 printStderrAndDie(err) 171 } 172 } 173 174 func removePair(gitconfig *git.Config) { 175 err := gitconfig.Delete("user.name") 176 if err != nil { 177 os.Stderr.WriteString(err.Error() + "\n") 178 } 179 180 err = gitconfig.Delete("user.email") 181 if err != nil { 182 os.Stderr.WriteString(err.Error()) 183 } 184 } 185 186 func checkEmail(conf *Config) string { 187 if conf.Email == "" { 188 conf.Email = getEmail() 189 } 190 191 return conf.Email 192 } 193 194 func checkPair(pair []string, conf *Config) []string { 195 var fullnames []string 196 for _, dev := range pair { 197 if _, ok := conf.Devs[dev]; !ok { 198 conf.Devs[dev] = getName(dev) 199 } 200 201 fullnames = append(fullnames, conf.Devs[dev]) 202 } 203 204 return fullnames 205 } 206 207 func getName(devName string) string { 208 prompt := fmt.Sprintf("Please enter a full name for %s:", devName) 209 return promptForInput(prompt) 210 } 211 212 func getEmail() string { 213 return promptForInput("Please provide base author email:") 214 } 215 216 func promptForInput(prompt string) string { 217 _, err := fmt.Println(prompt) 218 if err != nil { 219 log.Fatal(err) 220 } 221 222 return readInput() 223 } 224 225 func readInput() string { 226 buf := bufio.NewReader(os.Stdin) 227 inputString, err := buf.ReadString('\n') 228 if err != nil { 229 log.Fatal("Could not read from stdin: ", err) 230 } 231 232 return trimNewline(inputString) 233 } 234 235 func savePearrc(conf *Config, path string) error { 236 contents, err := yaml.Marshal(conf) 237 if err != nil { 238 return err 239 } 240 241 err = ioutil.WriteFile(path, contents, os.ModeExclusive) 242 if err != nil { 243 return err 244 } 245 246 return nil 247 } 248 249 func readPearrc(path string) (*Config, error) { 250 conf := &Config{ 251 Devs: make(map[string]string), 252 } 253 254 file, err := os.Open(path) 255 if err != nil { 256 file, err = os.Create(path) 257 if err != nil { 258 return nil, err 259 } 260 } 261 262 defer file.Close() 263 264 contents, err := ioutil.ReadAll(file) 265 if err != nil { 266 return nil, err 267 } 268 269 err = yaml.Unmarshal(contents, conf) 270 if err != nil { 271 return nil, err 272 } 273 274 return conf, nil 275 } 276 277 func formatEmail(email string, devs []string) string { 278 parts := strings.Split(email, "@") 279 devlist := strings.Join(devs, "+") 280 return fmt.Sprintf("%s+%s@%s", parts[0], devlist, parts[1]) 281 } 282 283 func trimNewline(s string) string { 284 return strings.TrimSuffix(s, "\n") 285 } 286 287 func sanitizeDevNames(devs []string) { 288 for i, dev := range devs { 289 devs[i] = strings.ToLower(dev) 290 } 291 292 sort.Strings(devs) 293 }