github.com/tools/godep@v0.0.0-20180126220526-ce0bfadeb516/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  	var ev bool
    79  	switch v {
    80  	case "go1", "go1.1", "go1.2", "go1.3", "go1.4":
    81  		ev = false
    82  	case "go1.5":
    83  		ev = go15ve == "1"
    84  	case "go1.6":
    85  		ev = go15ve != "0"
    86  	default: //go1.7+, devel*
    87  		ev = true
    88  	}
    89  
    90  	ws := filepath.Join("Godeps", "_workspace")
    91  	s, err := os.Stat(ws)
    92  	if err == nil && s.IsDir() {
    93  		log.Printf("WARNING: Godep workspaces (./Godeps/_workspace) are deprecated and support for them will be removed when go1.8 is released.")
    94  		if ev {
    95  			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)
    96  		}
    97  		return false
    98  	}
    99  
   100  	return ev
   101  }
   102  
   103  func main() {
   104  	log.SetFlags(0)
   105  	log.SetPrefix("godep: ")
   106  	log.SetOutput(os.Stderr)
   107  
   108  	flag.Usage = usageExit
   109  	flag.Parse()
   110  	args := flag.Args()
   111  	if len(args) < 1 {
   112  		usageExit()
   113  	}
   114  
   115  	if args[0] == "help" {
   116  		help(args[1:])
   117  		return
   118  	}
   119  
   120  	var err error
   121  	majorGoVersion, err = goVersion()
   122  	if err != nil {
   123  		log.Fatal(err)
   124  	}
   125  
   126  	for _, cmd := range commands {
   127  		if cmd.Name == args[0] {
   128  			if cmd.OnlyInGOPATH {
   129  				checkInGOPATH()
   130  			}
   131  
   132  			VendorExperiment = determineVendor(majorGoVersion)
   133  			// sep is the signature set of path elements that
   134  			// precede the original path of an imported package.
   135  			sep = defaultSep(VendorExperiment)
   136  
   137  			cmd.Flag.BoolVar(&verbose, "v", false, "enable verbose output")
   138  			cmd.Flag.BoolVar(&debug, "d", false, "enable debug output")
   139  			cmd.Flag.StringVar(&cpuprofile, "cpuprofile", "", "Write cpu profile to this file")
   140  			cmd.Flag.Usage = func() { cmd.UsageExit() }
   141  			cmd.Flag.Parse(args[1:])
   142  
   143  			debugln("versionString()", versionString())
   144  			debugln("majorGoVersion", majorGoVersion)
   145  			debugln("VendorExperiment", VendorExperiment)
   146  			debugln("sep", sep)
   147  
   148  			if cpuprofile != "" {
   149  				f, err := os.Create(cpuprofile)
   150  				if err != nil {
   151  					log.Fatal(err)
   152  				}
   153  				pprof.StartCPUProfile(f)
   154  				defer pprof.StopCPUProfile()
   155  			}
   156  			cmd.Run(cmd, cmd.Flag.Args())
   157  			return
   158  		}
   159  	}
   160  
   161  	fmt.Fprintf(os.Stderr, "godep: unknown command %q\n", args[0])
   162  	fmt.Fprintf(os.Stderr, "Run 'godep help' for usage.\n")
   163  	os.Exit(2)
   164  }
   165  
   166  func subPath(sub, path string) bool {
   167  	ls := strings.ToLower(sub)
   168  	lp := strings.ToLower(path)
   169  	if ls == lp {
   170  		return false
   171  	}
   172  	return strings.HasPrefix(ls, lp)
   173  }
   174  
   175  func checkInGOPATH() {
   176  	pwd, err := os.Getwd()
   177  	if err != nil {
   178  		log.Fatal("Unable to determine current working directory", err)
   179  	}
   180  	dirs := build.Default.SrcDirs()
   181  	for _, p := range dirs {
   182  		if ok := subPath(pwd, p); ok {
   183  			return
   184  		}
   185  	}
   186  
   187  	log.Println("[WARNING]: godep should only be used inside a valid go package directory and")
   188  	log.Println("[WARNING]: may not function correctly. You are probably outside of your $GOPATH.")
   189  	log.Printf("[WARNING]:\tCurrent Directory: %s\n", pwd)
   190  	log.Printf("[WARNING]:\t$GOPATH: %s\n", os.Getenv("GOPATH"))
   191  }
   192  
   193  var usageTemplate = `
   194  Godep is a tool for managing Go package dependencies.
   195  
   196  Usage:
   197  
   198  	godep command [arguments]
   199  
   200  The commands are:
   201  {{range .}}
   202      {{.Name | printf "%-8s"}} {{.Short}}{{end}}
   203  
   204  Use "godep help [command]" for more information about a command.
   205  `
   206  
   207  var helpTemplate = `
   208  Args: godep {{.Name}} [-v] [-d] {{.Args}}
   209  
   210  {{.Long | trim}}
   211  
   212  If -v is given, verbose output is enabled.
   213  
   214  If -d is given, debug output is enabled (you probably don't want this, see -v).
   215  
   216  `
   217  
   218  func help(args []string) {
   219  	if len(args) == 0 {
   220  		printUsage(os.Stdout)
   221  		return
   222  	}
   223  	if len(args) != 1 {
   224  		fmt.Fprintf(os.Stderr, "usage: godep help command\n\n")
   225  		fmt.Fprintf(os.Stderr, "Too many arguments given.\n")
   226  		os.Exit(2)
   227  	}
   228  	for _, cmd := range commands {
   229  		if cmd.Name == args[0] {
   230  			tmpl(os.Stdout, helpTemplate, cmd)
   231  			return
   232  		}
   233  	}
   234  }
   235  
   236  func usageExit() {
   237  	printUsage(os.Stderr)
   238  	os.Exit(2)
   239  }
   240  
   241  func printUsage(w io.Writer) {
   242  	tmpl(w, usageTemplate, commands)
   243  }
   244  
   245  // tmpl executes the given template text on data, writing the result to w.
   246  func tmpl(w io.Writer, text string, data interface{}) {
   247  	t := template.New("top")
   248  	t.Funcs(template.FuncMap{
   249  		"trim": strings.TrimSpace,
   250  	})
   251  	template.Must(t.Parse(strings.TrimSpace(text) + "\n\n"))
   252  	if err := t.Execute(w, data); err != nil {
   253  		panic(err)
   254  	}
   255  }