github.com/Xenoex/gopm@v0.6.5/cmd/gopath.go (about)

     1  // Copyright 2013-2014 gopm authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License"): you may
     4  // not use this file except in compliance with the License. You may obtain
     5  // a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    11  // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    12  // License for the specific language governing permissions and limitations
    13  // under the License.
    14  
    15  package cmd
    16  
    17  import (
    18  	"errors"
    19  	"go/build"
    20  	"os"
    21  	"os/exec"
    22  	"path/filepath"
    23  	"runtime"
    24  	"strings"
    25  
    26  	"github.com/Unknwon/com"
    27  	"github.com/codegangsta/cli"
    28  
    29  	"github.com/gpmgo/gopm/doc"
    30  	"github.com/gpmgo/gopm/log"
    31  )
    32  
    33  var isWindowsXP = false
    34  
    35  func getGopmPkgs(dirPath string, isTest bool) (pkgs map[string]*doc.Pkg, err error) {
    36  	absPath, err := filepath.Abs(dirPath)
    37  	if err != nil {
    38  		log.Error("", "Fail to get absolute path of work directory:")
    39  		log.Fatal("", "\t"+err.Error())
    40  	}
    41  
    42  	var builds map[string]string
    43  
    44  	if com.IsFile(absPath + "/" + doc.GOPM_FILE_NAME) {
    45  		gf := doc.NewGopmfile(absPath)
    46  
    47  		if builds, err = gf.GetSection("deps"); err != nil {
    48  			builds = nil
    49  		}
    50  	}
    51  
    52  	imports := doc.GetAllImports([]string{dirPath}, ".", false, false)
    53  	pkgs = make(map[string]*doc.Pkg)
    54  	for _, name := range imports {
    55  		if name == "C" {
    56  			continue
    57  		}
    58  		if !doc.IsGoRepoPath(name) {
    59  			if builds != nil {
    60  				if info, ok := builds[name]; ok {
    61  					// Check version. there should chek
    62  					// local first because d:\ contains :
    63  					if com.IsDir(info) {
    64  						pkgs[name] = &doc.Pkg{
    65  							ImportPath: name,
    66  							Type:       doc.LOCAL,
    67  							Value:      info,
    68  						}
    69  						continue
    70  					} else if i := strings.Index(info, ":"); i > -1 {
    71  						pkgs[name] = &doc.Pkg{
    72  							ImportPath: name,
    73  							Type:       info[:i],
    74  							Value:      info[i+1:],
    75  						}
    76  						continue
    77  					}
    78  				}
    79  			}
    80  			pkgs[name] = doc.NewDefaultPkg(name)
    81  		}
    82  	}
    83  	return pkgs, nil
    84  }
    85  
    86  func pkgInCache(name string, cachePkgs map[string]*doc.Pkg) bool {
    87  	_, ok := cachePkgs[name]
    88  	return ok
    89  }
    90  
    91  func autoLink(oldPath, newPath string) error {
    92  	newPPath, _ := filepath.Split(newPath)
    93  	os.MkdirAll(newPPath, os.ModePerm)
    94  	return makeLink(oldPath, newPath)
    95  }
    96  
    97  func getChildPkgs(ctx *cli.Context, cpath string, ppkg *doc.Pkg, cachePkgs map[string]*doc.Pkg, isTest bool) error {
    98  	log.Trace("Current Path: 1 %s", cpath)
    99  	pkgs, err := getGopmPkgs(cpath, isTest)
   100  	if err != nil {
   101  		return errors.New("Fail to get gopmfile deps: " + err.Error())
   102  	}
   103  	for name, pkg := range pkgs {
   104  		pkg.RootPath = doc.GetProjectPath(pkg.ImportPath)
   105  		if !pkgInCache(pkg.RootPath, cachePkgs) {
   106  			var newPath string
   107  			if !build.IsLocalImport(name) && pkg.Type != doc.LOCAL {
   108  				suf := versionSuffix(pkg.Value)
   109  				pkgPath := strings.Replace(
   110  					pkg.ImportPath, pkg.RootPath, pkg.RootPath+suf, 1)
   111  				newPath = filepath.Join(installRepoPath, pkgPath)
   112  				if len(suf) == 0 && !ctx.Bool("remote") &&
   113  					com.IsDir(filepath.Join(installGopath, pkgPath)) {
   114  					newPath = filepath.Join(installGopath, pkgPath)
   115  				}
   116  				if pkgName != "" && strings.HasPrefix(pkg.ImportPath, pkgName) {
   117  					newPath = filepath.Join(curPath, strings.TrimPrefix(pkg.ImportPath, pkgName))
   118  				} else {
   119  					if !com.IsExist(newPath) || ctx.Bool("update") {
   120  						node := doc.NewNode(pkg.ImportPath, pkg.ImportPath,
   121  							pkg.Type, pkg.Value, true)
   122  						nodes := []*doc.Node{node}
   123  						downloadPackages(ctx, nodes)
   124  						// TODO: Should handler download failed
   125  					}
   126  				}
   127  			} else {
   128  				if pkg.Type == doc.LOCAL {
   129  					newPath, err = filepath.Abs(pkg.Value)
   130  				} else {
   131  					newPath, err = filepath.Abs(name)
   132  				}
   133  				if err != nil {
   134  					return err
   135  				}
   136  			}
   137  			cachePkgs[pkg.RootPath] = pkg
   138  			err = getChildPkgs(ctx, newPath, pkg, cachePkgs, false)
   139  			if err != nil {
   140  				return err
   141  			}
   142  		}
   143  	}
   144  	return nil
   145  }
   146  
   147  var pkgName string
   148  var curPath string
   149  var newCurPath string
   150  var newGoPath string
   151  var oldGoPath string
   152  
   153  func execCmd(gopath, curPath string, args ...string) error {
   154  	cwd, err := os.Getwd()
   155  	if err != nil {
   156  		log.Error("", "Fail to get work directory:")
   157  		log.Fatal("", "\t"+err.Error())
   158  	}
   159  
   160  	log.Log("Changing work directory to %s", curPath)
   161  	err = os.Chdir(curPath)
   162  	if err != nil {
   163  		log.Error("", "Fail to change work directory:")
   164  		log.Fatal("", "\t"+err.Error())
   165  	}
   166  	defer func() {
   167  		log.Log("Changing work directory back to %s", cwd)
   168  		os.Chdir(cwd)
   169  	}()
   170  
   171  	err = os.Chdir(curPath)
   172  	if err != nil {
   173  		log.Error("", "Fail to change work directory:")
   174  		log.Fatal("", "\t"+err.Error())
   175  	}
   176  
   177  	oldGoPath = os.Getenv("GOPATH")
   178  	log.Log("Setting GOPATH to %s", gopath)
   179  
   180  	sep := ":"
   181  	if runtime.GOOS == "windows" {
   182  		sep = ";"
   183  	}
   184  	err = os.Setenv("GOPATH", gopath+sep+oldGoPath)
   185  	if err != nil {
   186  		log.Error("", "Fail to setting GOPATH:")
   187  		log.Fatal("", "\t"+err.Error())
   188  	}
   189  	defer func() {
   190  		log.Log("Setting GOPATH back to %s", oldGoPath)
   191  		os.Setenv("GOPATH", oldGoPath)
   192  	}()
   193  
   194  	cmd := exec.Command(args[0], args[1:]...)
   195  	cmd.Stdout = os.Stdout
   196  	cmd.Stderr = os.Stderr
   197  
   198  	log.Log("===== application outputs start =====\n")
   199  
   200  	err = cmd.Run()
   201  
   202  	log.Log("====== application outputs end ======")
   203  	return err
   204  }
   205  
   206  func genNewGoPath(ctx *cli.Context, isTest bool) {
   207  	var err error
   208  	curPath, err = os.Getwd()
   209  	if err != nil {
   210  		log.Error("", "Fail to get work directory:")
   211  		log.Fatal("", "\t"+err.Error())
   212  	}
   213  	log.Trace("Current Path: 0 %s", curPath)
   214  
   215  	installRepoPath = doc.HomeDir + "/repos"
   216  
   217  	if com.IsFile(curPath + "/" + doc.GOPM_FILE_NAME) {
   218  		log.Trace("Loading gopmfile...")
   219  		gf := doc.NewGopmfile(curPath)
   220  
   221  		var err error
   222  		pkgName, err = gf.GetValue("target", "path")
   223  		if err == nil {
   224  			log.Log("Target name: %s", pkgName)
   225  		}
   226  	}
   227  
   228  	if len(pkgName) == 0 {
   229  		_, pkgName = filepath.Split(curPath)
   230  	}
   231  
   232  	cachePkgs := make(map[string]*doc.Pkg)
   233  	if err = getChildPkgs(ctx, curPath, nil, cachePkgs, isTest); err != nil {
   234  		log.Error("", "Fail to get child pakcages:")
   235  		log.Fatal("", "\t"+err.Error())
   236  	}
   237  
   238  	newGoPath = filepath.Join(curPath, doc.VENDOR)
   239  	newGoPathSrc := filepath.Join(newGoPath, "src")
   240  	os.RemoveAll(newGoPathSrc)
   241  	os.MkdirAll(newGoPathSrc, os.ModePerm)
   242  
   243  	for name, pkg := range cachePkgs {
   244  		suf := versionSuffix(pkg.Value)
   245  
   246  		var oldPath string
   247  		if pkg.Type == doc.LOCAL {
   248  			oldPath, _ = filepath.Abs(pkg.Value)
   249  		} else {
   250  			oldPath = filepath.Join(installRepoPath, name) + suf
   251  		}
   252  
   253  		newPath := filepath.Join(newGoPathSrc, name)
   254  		paths := strings.Split(name, "/")
   255  		var isExistP, isCurChild bool
   256  		if name == pkgName {
   257  			continue
   258  		}
   259  
   260  		for i := 0; i < len(paths)-1; i++ {
   261  			pName := strings.Join(paths[:len(paths)-1-i], "/")
   262  			if _, ok := cachePkgs[pName]; ok {
   263  				isExistP = true
   264  				break
   265  			}
   266  			if pkgName == pName {
   267  				isCurChild = true
   268  				break
   269  			}
   270  		}
   271  		if isCurChild {
   272  			continue
   273  		}
   274  
   275  		if !isExistP && (len(pkg.Value) > 0 || ctx.Bool("remote") ||
   276  			!com.IsDir(filepath.Join(installGopath, pkg.ImportPath))) {
   277  			log.Log("Linking %s", name+suf)
   278  			err = autoLink(oldPath, newPath)
   279  			if err != nil {
   280  				log.Error("", "Fail to make link:")
   281  				log.Fatal("", "\t"+err.Error())
   282  			}
   283  		}
   284  	}
   285  
   286  	newCurPath = filepath.Join(newGoPathSrc, pkgName)
   287  	log.Log("Linking %s", pkgName)
   288  	err = autoLink(curPath, newCurPath)
   289  	if err != nil {
   290  		log.Error("", "Fail to make link:")
   291  		log.Fatal("", "\t"+err.Error())
   292  	}
   293  }