// Copyright 2013-2014 gopm authors. // // Licensed under the Apache License, Version 2.0 (the "License"): you may // not use this file except in compliance with the License. You may obtain // a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. package cmd import ( "errors" "go/build" "os" "os/exec" "path/filepath" "runtime" "strings" "github.com/Unknwon/com" "github.com/codegangsta/cli" "github.com/gpmgo/gopm/doc" "github.com/gpmgo/gopm/log" ) var isWindowsXP = false func getGopmPkgs(dirPath string, isTest bool) (pkgs map[string]*doc.Pkg, err error) { absPath, err := filepath.Abs(dirPath) if err != nil { log.Error("", "Fail to get absolute path of work directory:") log.Fatal("", "\t"+err.Error()) } var builds map[string]string if com.IsFile(absPath + "/" + doc.GOPM_FILE_NAME) { gf := doc.NewGopmfile(absPath) if builds, err = gf.GetSection("deps"); err != nil { builds = nil } } imports := doc.GetAllImports([]string{dirPath}, ".", false, false) pkgs = make(map[string]*doc.Pkg) for _, name := range imports { if name == "C" { continue } if !doc.IsGoRepoPath(name) { if builds != nil { if info, ok := builds[name]; ok { // Check version. there should chek // local first because d:\ contains : if com.IsDir(info) { pkgs[name] = &doc.Pkg{ ImportPath: name, Type: doc.LOCAL, Value: info, } continue } else if i := strings.Index(info, ":"); i > -1 { pkgs[name] = &doc.Pkg{ ImportPath: name, Type: info[:i], Value: info[i+1:], } continue } } } pkgs[name] = doc.NewDefaultPkg(name) } } return pkgs, nil } func pkgInCache(name string, cachePkgs map[string]*doc.Pkg) bool { _, ok := cachePkgs[name] return ok } func autoLink(oldPath, newPath string) error { newPPath, _ := filepath.Split(newPath) os.MkdirAll(newPPath, os.ModePerm) return makeLink(oldPath, newPath) } func getChildPkgs(ctx *cli.Context, cpath string, ppkg *doc.Pkg, cachePkgs map[string]*doc.Pkg, isTest bool) error { pkgs, err := getGopmPkgs(cpath, isTest) if err != nil { return errors.New("Fail to get gopmfile deps: " + err.Error()) } for name, pkg := range pkgs { pkg.RootPath = doc.GetProjectPath(pkg.ImportPath) if !pkgInCache(pkg.RootPath, cachePkgs) { var newPath string if !build.IsLocalImport(name) && pkg.Type != doc.LOCAL { suf := versionSuffix(pkg.Value) pkgPath := strings.Replace( pkg.ImportPath, pkg.RootPath, pkg.RootPath+suf, 1) newPath = filepath.Join(installRepoPath, pkgPath) if len(suf) == 0 && !ctx.Bool("remote") && com.IsDir(filepath.Join(installGopath, pkgPath)) { newPath = filepath.Join(installGopath, pkgPath) } if pkgName != "" && strings.HasPrefix(pkg.ImportPath, pkgName) { newPath = filepath.Join(curPath, strings.TrimPrefix(pkg.ImportPath, pkgName)) } else { if !com.IsExist(newPath) || ctx.Bool("update") { node := doc.NewNode(pkg.ImportPath, pkg.ImportPath, pkg.Type, pkg.Value, true) nodes := []*doc.Node{node} downloadPackages(ctx, nodes) // TODO: Should handler download failed } } } else { if pkg.Type == doc.LOCAL { newPath, err = filepath.Abs(pkg.Value) } else { newPath, err = filepath.Abs(name) } if err != nil { return err } } cachePkgs[pkg.RootPath] = pkg err = getChildPkgs(ctx, newPath, pkg, cachePkgs, false) if err != nil { return err } } } return nil } var pkgName string var curPath string var newCurPath string var newGoPath string var oldGoPath string func execCmd(gopath, curPath string, args ...string) error { cwd, err := os.Getwd() if err != nil { log.Error("", "Fail to get work directory:") log.Fatal("", "\t"+err.Error()) } log.Log("Changing work directory to %s", curPath) err = os.Chdir(curPath) if err != nil { log.Error("", "Fail to change work directory:") log.Fatal("", "\t"+err.Error()) } defer func() { log.Log("Changing work directory back to %s", cwd) os.Chdir(cwd) }() err = os.Chdir(curPath) if err != nil { log.Error("", "Fail to change work directory:") log.Fatal("", "\t"+err.Error()) } oldGoPath = os.Getenv("GOPATH") log.Log("Setting GOPATH to %s", gopath) sep := ":" if runtime.GOOS == "windows" { sep = ";" } err = os.Setenv("GOPATH", gopath+sep+oldGoPath) if err != nil { log.Error("", "Fail to setting GOPATH:") log.Fatal("", "\t"+err.Error()) } defer func() { log.Log("Setting GOPATH back to %s", oldGoPath) os.Setenv("GOPATH", oldGoPath) }() cmd := exec.Command(args[0], args[1:]...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr log.Log("===== application outputs start =====\n") err = cmd.Run() log.Log("====== application outputs end ======") return err } func genNewGoPath(ctx *cli.Context, isTest bool) { var err error curPath, err = os.Getwd() if err != nil { log.Error("", "Fail to get work directory:") log.Fatal("", "\t"+err.Error()) } installRepoPath = doc.HomeDir + "/repos" if com.IsFile(curPath + "/" + doc.GOPM_FILE_NAME) { log.Trace("Loading gopmfile...") gf := doc.NewGopmfile(curPath) var err error pkgName, err = gf.GetValue("target", "path") if err == nil { log.Log("Target name: %s", pkgName) } } if len(pkgName) == 0 { _, pkgName = filepath.Split(curPath) } cachePkgs := make(map[string]*doc.Pkg) err = getChildPkgs(ctx, curPath, nil, cachePkgs, isTest) if err != nil { log.Error("", "Fail to get child pakcages:") log.Fatal("", "\t"+err.Error()) } newGoPath = filepath.Join(curPath, doc.VENDOR) newGoPathSrc := filepath.Join(newGoPath, "src") os.RemoveAll(newGoPathSrc) os.MkdirAll(newGoPathSrc, os.ModePerm) for name, pkg := range cachePkgs { suf := versionSuffix(pkg.Value) var oldPath string if pkg.Type == doc.LOCAL { oldPath, _ = filepath.Abs(pkg.Value) } else { oldPath = filepath.Join(installRepoPath, name) + suf } newPath := filepath.Join(newGoPathSrc, name) paths := strings.Split(name, "/") var isExistP, isCurChild bool if name == pkgName { continue } for i := 0; i < len(paths)-1; i++ { pName := strings.Join(paths[:len(paths)-1-i], "/") if _, ok := cachePkgs[pName]; ok { isExistP = true break } if pkgName == pName { isCurChild = true break } } if isCurChild { continue } if !isExistP && (len(pkg.Value) > 0 || ctx.Bool("remote") || !com.IsDir(filepath.Join(installGopath, pkg.ImportPath))) { log.Log("Linking %s", name+suf) err = autoLink(oldPath, newPath) if err != nil { log.Error("", "Fail to make link:") log.Fatal("", "\t"+err.Error()) } } } newCurPath = filepath.Join(newGoPathSrc, pkgName) log.Log("Linking %s", pkgName) err = autoLink(curPath, newCurPath) if err != nil { log.Error("", "Fail to make link:") log.Fatal("", "\t"+err.Error()) } }