gopkg.in/tools/godep.v70@v70.0.0-20160520184947-56b9657fec2f/main.go (about) 1 package main 2 3 import ( 4 "flag" 5 "fmt" 6 "go/build" 7 "io" 8 "log" 9 "os" 10 "path/filepath" 11 "runtime/pprof" 12 "strings" 13 "text/template" 14 ) 15 16 var ( 17 cpuprofile string 18 verbose bool // Verbose flag for commands that support it 19 debug bool // Debug flag for commands that support it 20 majorGoVersion string 21 VendorExperiment bool 22 sep string 23 ) 24 25 // Command is an implementation of a godep command 26 // like godep save or godep go. 27 type Command struct { 28 // Run runs the command. 29 // The args are the arguments after the command name. 30 Run func(cmd *Command, args []string) 31 32 // Name of the command 33 Name string 34 35 // Args the command would expect 36 Args string 37 38 // Short is the short description shown in the 'godep help' output. 39 Short string 40 41 // Long is the long message shown in the 42 // 'godep help <this-command>' output. 43 Long string 44 45 // Flag is a set of flags specific to this command. 46 Flag flag.FlagSet 47 48 // OnlyInGOPATH limits this command to being run only while inside of a GOPATH 49 OnlyInGOPATH bool 50 } 51 52 // UsageExit prints usage information and exits. 53 func (c *Command) UsageExit() { 54 fmt.Fprintf(os.Stderr, "Args: godep %s [-v] [-d] %s\n\n", c.Name, c.Args) 55 fmt.Fprintf(os.Stderr, "Run 'godep help %s' for help.\n", c.Name) 56 os.Exit(2) 57 } 58 59 // Commands lists the available commands and help topics. 60 // The order here is the order in which they are printed 61 // by 'godep help'. 62 var commands = []*Command{ 63 cmdSave, 64 cmdGo, 65 cmdGet, 66 cmdPath, 67 cmdRestore, 68 cmdUpdate, 69 cmdDiff, 70 cmdVersion, 71 } 72 73 // VendorExperiment is the Go 1.5 vendor directory experiment flag, see 74 // https://github.com/golang/go/commit/183cc0cd41f06f83cb7a2490a499e3f9101befff 75 // Honor the env var unless the project already has an old school godep workspace 76 func determineVendor(v string) bool { 77 go15ve := os.Getenv("GO15VENDOREXPERIMENT") 78 ev := (v == "go1.5" && go15ve == "1") || 79 (v == "go1.6" && go15ve != "0") || 80 (strings.HasPrefix(v, "devel") && go15ve != "0") 81 82 ws := filepath.Join("Godeps", "_workspace") 83 s, err := os.Stat(ws) 84 if err == nil && s.IsDir() { 85 if ev { 86 log.Printf("WARNING: Go version (%s) & $GO15VENDOREXPERIMENT=%s wants to enable the vendor experiment, but disabling because a Godep workspace (%s) exists\n", v, go15ve, ws) 87 } 88 return false 89 } 90 91 return ev 92 } 93 94 func main() { 95 log.SetFlags(0) 96 log.SetPrefix("godep: ") 97 log.SetOutput(os.Stderr) 98 99 flag.Usage = usageExit 100 flag.Parse() 101 args := flag.Args() 102 if len(args) < 1 { 103 usageExit() 104 } 105 106 if args[0] == "help" { 107 help(args[1:]) 108 return 109 } 110 111 var err error 112 majorGoVersion, err = goVersion() 113 if err != nil { 114 log.Fatal(err) 115 } 116 117 for _, cmd := range commands { 118 if cmd.Name == args[0] { 119 if cmd.OnlyInGOPATH { 120 checkInGOPATH() 121 } 122 123 VendorExperiment = determineVendor(majorGoVersion) 124 // sep is the signature set of path elements that 125 // precede the original path of an imported package. 126 sep = defaultSep(VendorExperiment) 127 128 cmd.Flag.BoolVar(&verbose, "v", false, "enable verbose output") 129 cmd.Flag.BoolVar(&debug, "d", false, "enable debug output") 130 cmd.Flag.StringVar(&cpuprofile, "cpuprofile", "", "Write cpu profile to this file") 131 cmd.Flag.Usage = func() { cmd.UsageExit() } 132 cmd.Flag.Parse(args[1:]) 133 134 debugln("versionString()", versionString()) 135 debugln("majorGoVersion", majorGoVersion) 136 debugln("VendorExperiment", VendorExperiment) 137 debugln("sep", sep) 138 139 if cpuprofile != "" { 140 f, err := os.Create(cpuprofile) 141 if err != nil { 142 log.Fatal(err) 143 } 144 pprof.StartCPUProfile(f) 145 defer pprof.StopCPUProfile() 146 } 147 cmd.Run(cmd, cmd.Flag.Args()) 148 return 149 } 150 } 151 152 fmt.Fprintf(os.Stderr, "godep: unknown command %q\n", args[0]) 153 fmt.Fprintf(os.Stderr, "Run 'godep help' for usage.\n") 154 os.Exit(2) 155 } 156 157 func subPath(sub, path string) bool { 158 ls := strings.ToLower(sub) 159 lp := strings.ToLower(path) 160 if ls == lp { 161 return false 162 } 163 return strings.HasPrefix(ls, lp) 164 } 165 166 func checkInGOPATH() { 167 pwd, err := os.Getwd() 168 if err != nil { 169 log.Fatal("Unable to determine current working directory", err) 170 } 171 dirs := build.Default.SrcDirs() 172 for _, p := range dirs { 173 if ok := subPath(pwd, p); ok { 174 return 175 } 176 } 177 178 log.Println("[WARNING]: godep should only be used inside a valid go package directory and") 179 log.Println("[WARNING]: may not function correctly. You are probably outside of your $GOPATH.") 180 log.Printf("[WARNING]:\tCurrent Directory: %s\n", pwd) 181 log.Printf("[WARNING]:\t$GOPATH: %s\n", os.Getenv("GOPATH")) 182 } 183 184 var usageTemplate = ` 185 Godep is a tool for managing Go package dependencies. 186 187 Usage: 188 189 godep command [arguments] 190 191 The commands are: 192 {{range .}} 193 {{.Name | printf "%-8s"}} {{.Short}}{{end}} 194 195 Use "godep help [command]" for more information about a command. 196 ` 197 198 var helpTemplate = ` 199 Args: godep {{.Name}} [-v] [-d] {{.Args}} 200 201 {{.Long | trim}} 202 203 If -v is given, verbose output is enabled. 204 205 If -d is given, debug output is enabled (you probably don't want this, see -v). 206 207 ` 208 209 func help(args []string) { 210 if len(args) == 0 { 211 printUsage(os.Stdout) 212 return 213 } 214 if len(args) != 1 { 215 fmt.Fprintf(os.Stderr, "usage: godep help command\n\n") 216 fmt.Fprintf(os.Stderr, "Too many arguments given.\n") 217 os.Exit(2) 218 } 219 for _, cmd := range commands { 220 if cmd.Name == args[0] { 221 tmpl(os.Stdout, helpTemplate, cmd) 222 return 223 } 224 } 225 } 226 227 func usageExit() { 228 printUsage(os.Stderr) 229 os.Exit(2) 230 } 231 232 func printUsage(w io.Writer) { 233 tmpl(w, usageTemplate, commands) 234 } 235 236 // tmpl executes the given template text on data, writing the result to w. 237 func tmpl(w io.Writer, text string, data interface{}) { 238 t := template.New("top") 239 t.Funcs(template.FuncMap{ 240 "trim": strings.TrimSpace, 241 }) 242 template.Must(t.Parse(strings.TrimSpace(text) + "\n\n")) 243 if err := t.Execute(w, data); err != nil { 244 panic(err) 245 } 246 }