diff --git a/cmd/build.go b/cmd/build.go new file mode 100644 index 000000000..2d9991820 --- /dev/null +++ b/cmd/build.go @@ -0,0 +1,213 @@ +// Copyright 2013 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" + "github.com/Unknwon/com" + "github.com/gpmgo/gopm/doc" + "go/build" + "os" + "path/filepath" + //"syscall" + "os/exec" + "strings" +) + +var CmdBuild = &Command{ + UsageLine: "build", + Short: "build according a gopmfile", + Long: ` +build +`, +} + +func init() { + CmdBuild.Run = runBuild + CmdBuild.Flags = map[string]bool{} +} + +func printBuildPrompt(flag string) { +} + +func getGopmPkgs(path string, inludeSys bool) (map[string]*doc.Pkg, error) { + abs, err := filepath.Abs(doc.GopmFileName) + if err != nil { + return nil, err + } + + // load import path + gf := doc.NewGopmfile() + if com.IsExist(abs) { + err := gf.Load(abs) + if err != nil { + return nil, err + } + } else { + sec := doc.NewSection() + sec.Name = "build" + gf.Sections[sec.Name] = sec + } + + var builds *doc.Section + var ok bool + if builds, ok = gf.Sections["build"]; !ok { + return nil, errors.New("no found build section\n") + } + + pkg, err := build.ImportDir(path, build.AllowBinary) + if err != nil { + return map[string]*doc.Pkg{}, err + } + + pkgs := make(map[string]*doc.Pkg) + for _, name := range pkg.Imports { + if inludeSys || !isStdPkg(name) { + if dep, ok := builds.Deps[name]; ok { + pkgs[name] = dep.Pkg + } else { + pkgs[name] = doc.NewDefaultPkg(name) + } + } + } + return pkgs, nil +} + +func pkgInCache(name string, cachePkgs map[string]*doc.Pkg) bool { + //pkgs := strings.Split(name, "/") + _, ok := cachePkgs[name] + return ok +} + +func getChildPkgs(cpath string, ppkg *doc.Pkg, cachePkgs map[string]*doc.Pkg) error { + pkgs, err := getGopmPkgs(cpath, false) + if err != nil { + return err + } + for name, pkg := range pkgs { + if !pkgInCache(name, cachePkgs) { + newPath := filepath.Join(installRepoPath, pkg.ImportPath) + if !com.IsExist(newPath) { + var t, ver string = doc.BRANCH, "" + node := doc.NewNode(pkg.ImportPath, pkg.ImportPath, t, ver, true) + //node := new(doc.Node) + //node.Pkg = *pkg + + nodes := []*doc.Node{node} + downloadPackages(nodes) + // should handler download failed + } + err = getChildPkgs(newPath, pkg, cachePkgs) + if err != nil { + return err + } + } + } + if ppkg != nil { + cachePkgs[ppkg.ImportPath] = ppkg + } + return nil +} + +func makeLink(oldPath, newPath string) error { + cmd := exec.Command("ln", "-s", oldPath, newPath) + return cmd.Run() +} + +func runBuild(cmd *Command, args []string) { + curPath, err := os.Getwd() + if err != nil { + com.ColorLog("[ERRO] %v\n", err) + return + } + + hd, err := com.HomeDir() + if err != nil { + com.ColorLog("[ERRO] Fail to get current user[ %s ]\n", err) + return + } + + installRepoPath = strings.Replace(reposDir, "~", hd, -1) + + cachePkgs := make(map[string]*doc.Pkg) + err = getChildPkgs(curPath, nil, cachePkgs) + if err != nil { + com.ColorLog("[ERRO] %v\n", err) + return + } + + newGoPath := filepath.Join(curPath, "vendor") + os.RemoveAll(newGoPath) + newGoPathSrc := filepath.Join(newGoPath, "src") + os.MkdirAll(newGoPathSrc, os.ModePerm) + + for name, pkg := range cachePkgs { + oldPath := filepath.Join(installRepoPath, name) + newPath := filepath.Join(newGoPathSrc, name) + paths := strings.Split(name, "/") + var isExistP bool + for i := 0; i < len(paths)-1; i++ { + pName := filepath.Join(paths[:len(paths)-1-i]...) + if _, ok := cachePkgs[pName]; ok { + isExistP = true + break + } + } + + if !isExistP { + pName := filepath.Join(paths[:len(paths)-1]...) + newPPath := filepath.Join(newGoPathSrc, pName) + com.ColorLog("[TRAC] create dirs %v\n", newPPath) + os.MkdirAll(newPPath, os.ModePerm) + + com.ColorLog("[INFO] linked %v\n", name) + + err = makeLink(oldPath, newPath) + + if err != nil { + com.ColorLog("[ERRO] make link error %v\n", err) + return + } + } + } + + gopath := build.Default.GOPATH + com.ColorLog("[TRAC] set GOPATH=%v\n", newGoPath) + err = os.Setenv("GOPATH", newGoPath) + if err != nil { + com.ColorLog("[ERRO] %v\n", err) + return + } + + cmdArgs := []string{"go", "build"} + cmdArgs = append(cmdArgs, args...) + bCmd := exec.Command(cmdArgs[0], cmdArgs[1:]...) + bCmd.Stdout = os.Stdout + bCmd.Stderr = os.Stderr + err = bCmd.Run() + if err != nil { + com.ColorLog("[ERRO] build failed: %v\n", err) + return + } + + com.ColorLog("[TRAC] set GOPATH=%v\n", gopath) + err = os.Setenv("GOPATH", gopath) + if err != nil { + com.ColorLog("[ERRO] %v\n", err) + return + } + + com.ColorLog("[SUCC] build successfully!\n") +} diff --git a/cmd/get.go b/cmd/get.go index 6ae456e8c..c678c9118 100644 --- a/cmd/get.go +++ b/cmd/get.go @@ -141,13 +141,8 @@ func runGet(cmd *Command, args []string) { } } - nodes = append(nodes, &doc.Node{ - ImportPath: args[0], - DownloadURL: args[0], - Type: t, - Value: ver, - IsGetDeps: true, - }) + node := doc.NewNode(args[0], args[0], t, ver, true) + nodes = append(nodes, node) // Download package(s). downloadPackages(nodes) @@ -185,12 +180,7 @@ func downloadPackages(nodes []*doc.Node) { // Generate temporary nodes. nodes := make([]*doc.Node, len(imports)) for i := range nodes { - nodes[i] = &doc.Node{ - ImportPath: imports[i], - DownloadURL: imports[i], - Type: doc.BRANCH, - IsGetDeps: true, - } + nodes[i] = doc.NewNode(imports[i], imports[i], doc.BRANCH, "", true) } downloadPackages(nodes) } diff --git a/cmd/service.go b/cmd/service.go index 11f0bf19e..b6d56dba1 100644 --- a/cmd/service.go +++ b/cmd/service.go @@ -29,11 +29,11 @@ package cmd // PkgExt() string // } -// type Pkg struct { -// Name string -// Ver string -// VerId string -// } +//type Pkg struct { +// Name string +// Ver string +// VerId string +//} // func NewPkg(pkgName string, ver string) *Pkg { // vers := strings.Split(ver, ":") diff --git a/doc/doc b/doc/doc new file mode 120000 index 000000000..9be75f6a1 --- /dev/null +++ b/doc/doc @@ -0,0 +1 @@ +/Users/lunny/go/src/github.com/gpmgo/gopm/doc \ No newline at end of file diff --git a/doc/gopmfile.go b/doc/gopmfile.go new file mode 100644 index 000000000..f08101116 --- /dev/null +++ b/doc/gopmfile.go @@ -0,0 +1,99 @@ +package doc + +import ( + "bufio" + "errors" + "os" + "strings" +) + +const ( + Greater = ">" + GreaterOrEq = ">=" + Equeal = "=" + Lesser = "<" + LesserOrEq = "<=" +) + +var ( + Ops = []string{GreaterOrEq, LesserOrEq, Greater, Equeal, Lesser} +) + +const ( + GopmFileName = ".gopmfile" +) + +type Depend struct { + Pkg *Pkg + Op string + Ver string +} + +type Section struct { + Name string + Deps map[string]*Depend +} + +func NewSection() *Section { + return &Section{Deps: make(map[string]*Depend)} +} + +type Gopmfile struct { + Sections map[string]*Section +} + +func NewGopmfile() *Gopmfile { + return &Gopmfile{Sections: make(map[string]*Section)} +} + +func (this *Gopmfile) Load(path string) error { + f, err := os.Open(path) + if err != nil { + return err + } + + scanner := bufio.NewScanner(f) + for scanner.Scan() { + var sec *Section + text := strings.TrimSpace(scanner.Text()) + if strings.HasPrefix(text, "[") { + sec = NewSection() + if strings.HasSuffix(text, "]") { + sec.Name = text[1 : len(text)-1] + } else { + return errors.New("need section") + } + this.Sections[sec.Name] = sec + } else { + if sec == nil { + continue + } + + var dep *Depend + for _, op := range Ops { + if strings.Contains(text, op) { + ss := strings.Split(text, op) + pkver := strings.Split(ss[1], ":") + var tp, value string + tp = pkver[0] + if len(pkver) == 2 { + value = pkver[1] + } + dep = &Depend{NewPkg(ss[0], tp, value), ss[1], value} + break + } + } + + if dep == nil { + dep = &Depend{NewDefaultPkg(text), Equeal, ""} + } + sec.Deps[dep.Pkg.ImportPath] = dep + } + } + + return nil +} + +func (this *Gopmfile) Save(path string) error { + return nil +} diff --git a/doc/struct.go b/doc/struct.go index c8e3e2077..94ca77b16 100644 --- a/doc/struct.go +++ b/doc/struct.go @@ -32,20 +32,43 @@ const ( COMMIT = "commit" ) +type Pkg struct { + ImportPath string + Type string + Value string // Branch, tag or commit. +} + +func (pkg *Pkg) VerString() string { + if pkg.Value == "" { + return pkg.Type + } + return fmt.Sprintf("%v:%v", pkg.Type, pkg.Value) +} + +func NewPkg(importPath, tp, value string) *Pkg { + return &Pkg{importPath, tp, value} +} + +func NewDefaultPkg(importPath string) *Pkg { + return NewPkg(importPath, BRANCH, "") +} + type Node struct { - ImportPath string + Pkg DownloadURL string - Type string - Value string // Branch, tag or commit. Synopsis string IsGetDeps bool } -func (nod *Node) VerString() string { - if nod.Value == "" { - return nod.Type +func NewNode(importPath, downloadUrl, tp, value string, isGetDeps bool) *Node { + return &Node{ + Pkg: Pkg{ImportPath: importPath, + Type: tp, + Value: value, + }, + DownloadURL: downloadUrl, + IsGetDeps: isGetDeps, } - return fmt.Sprintf("%v:%v", nod.Type, nod.Value) } // source is source code file. diff --git a/gopm.go b/gopm.go index 13a91f1c0..55a5d273a 100644 --- a/gopm.go +++ b/gopm.go @@ -46,8 +46,8 @@ var commands = []*cmd.Command{ cmd.CmdSearch, cmd.CmdServe, cmd.CmdGen, + cmd.CmdBuild, /* - cmdBuild, cmdClean, cmdDoc, cmdEnv, @@ -140,7 +140,7 @@ Use "gopm help [topic]" for more information about that topic. ` -var helpTemplate = `{{if .Runnable}}usage: go {{.UsageLine}} +var helpTemplate = `{{if .Runnable}}usage: gopm {{.UsageLine}} {{end}}{{.Long | trim}} `