github.com/mkideal/godep@v0.0.0-20160710170555-3c0ccb9a2415/go.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"os"
     7  	"os/exec"
     8  	"path/filepath"
     9  	"strings"
    10  )
    11  
    12  var cmdGo = &Command{
    13  	Name:  "go",
    14  	Args:  "command [arguments]",
    15  	Short: "run the go tool with saved dependencies",
    16  	Long: `
    17  Go runs the go tool with a modified GOPATH giving access to
    18  dependencies saved in Godeps.
    19  
    20  Any go tool command can run this way, but "godep go get"
    21  is unnecessary and has been disabled. Instead, use
    22  "godep go install".
    23  `,
    24  	Run:          runGo,
    25  	OnlyInGOPATH: true,
    26  }
    27  
    28  // Find the godep GOPATH for this file tree and run the go tool.
    29  func runGo(cmd *Command, args []string) {
    30  	gopath := prepareGopath()
    31  	if s := os.Getenv("GOPATH"); s != "" {
    32  		gopath += string(os.PathListSeparator) + os.Getenv("GOPATH")
    33  	}
    34  	if len(args) > 0 && args[0] == "get" {
    35  		log.Printf("invalid subcommand: %q", "go get")
    36  		fmt.Fprintln(os.Stderr, "Use 'godep go install' instead.")
    37  		fmt.Fprintln(os.Stderr, "Run 'godep help go' for usage.")
    38  		os.Exit(2)
    39  	}
    40  	c := exec.Command("go", args...)
    41  	c.Env = append(envNoGopath(), "GOPATH="+gopath)
    42  	c.Stdin = os.Stdin
    43  	c.Stdout = os.Stdout
    44  	c.Stderr = os.Stderr
    45  	err := c.Run()
    46  	if err != nil {
    47  		log.Fatalln("go", err)
    48  	}
    49  }
    50  
    51  // prepareGopath reads dependency information from the filesystem
    52  // entry name, fetches any necessary code, and returns a gopath
    53  // causing the specified dependencies to be used.
    54  func prepareGopath() (gopath string) {
    55  	dir, isDir := findGodeps()
    56  	if dir == "" {
    57  		log.Fatalln("No Godeps found (or in any parent directory)")
    58  	}
    59  	if !isDir {
    60  		log.Fatalln(strings.TrimSpace(needSource))
    61  	}
    62  	return filepath.Join(dir, "Godeps", "_workspace")
    63  }
    64  
    65  // findGodeps looks for a directory entry "Godeps" in the
    66  // current directory or any parent, and returns the containing
    67  // directory and whether the entry itself is a directory.
    68  // If Godeps can't be found, findGodeps returns "".
    69  // For any other error, it exits the program.
    70  func findGodeps() (dir string, isDir bool) {
    71  	wd, err := os.Getwd()
    72  	if err != nil {
    73  		log.Fatalln(err)
    74  	}
    75  	return findInParents(wd, "Godeps")
    76  }
    77  
    78  // isRoot returns true iff a path is a root.
    79  // On Unix: "/".
    80  // On Windows: "C:\", "D:\", ...
    81  func isRoot(p string) bool {
    82  	p = filepath.Clean(p)
    83  	volume := filepath.VolumeName(p)
    84  
    85  	p = strings.TrimPrefix(p, volume)
    86  	p = filepath.ToSlash(p)
    87  
    88  	return p == "/"
    89  }
    90  
    91  // findInParents returns the path to the directory containing name
    92  // in dir or any ancestor, and whether name itself is a directory.
    93  // If name cannot be found, findInParents returns the empty string.
    94  func findInParents(dir, name string) (container string, isDir bool) {
    95  	for {
    96  		fi, err := os.Stat(filepath.Join(dir, name))
    97  		if os.IsNotExist(err) && isRoot(dir) {
    98  			return "", false
    99  		}
   100  		if os.IsNotExist(err) {
   101  			dir = filepath.Dir(dir)
   102  			continue
   103  		}
   104  		if err != nil {
   105  			log.Fatalln(err)
   106  		}
   107  		return dir, fi.IsDir()
   108  	}
   109  }
   110  
   111  func envNoGopath() (a []string) {
   112  	for _, s := range os.Environ() {
   113  		if !strings.HasPrefix(s, "GOPATH=") {
   114  			a = append(a, s)
   115  		}
   116  	}
   117  	return a
   118  }
   119  
   120  const needSource = `
   121  outdated Godeps missing source code
   122  
   123  This dependency list was created with an old version of godep.
   124  
   125  To work around this, you have two options:
   126  1. Run 'godep restore', and try again.
   127  2. Ask the maintainer to switch to a newer version of godep,
   128  then try again with the updated package.
   129  `