Browse Source

Merge branch 'master' of https://github.com/gpmgo/gopm

pull/103/head
Unknown 11 years ago
parent
commit
deb4a7bc93
  1. 30
      README.md
  2. 153
      cmd/bin.go
  3. 4
      cmd/build.go
  4. 4
      cmd/gen.go
  5. 69
      cmd/get.go
  6. 40
      cmd/gopath.go
  7. 10
      doc/conf.go
  8. 199
      docs/features_CN.md
  9. BIN
      docs/images/arch.png
  10. 23
      docs/usage.md
  11. 3
      gopm.go

30
README.md

@ -5,30 +5,7 @@ gopm - Go Package Manager
Gopm(Go Package Manager) is a Go package manage tool for search, install, update and share packages in Go.
Current Version: **v0.5.5**
# Requirement
- Go Development Environment >= 1.1.
- Command `ln -s` support on Mac OS and Unix-like systems.
- Command `mklink -j` support on Windows( **Windows Vista and later** ).
# Installation
Because we do NOT offer binaries for now, so before you install the gopm, you should have already installed Go Development Environment with version 1.1 and later.
```
go get github.com/gpmgo/gopm
```
The executable will be produced under `$GOPATH/bin` in your file system; for global use purpose, we recommand you to add this path into your `PATH` environment variable.
# Features
- No requirement for installing any version control system tool like `git`, `svn` or `hg` in order to download packages(although you have to install git for installing gopm though `go get` for now).
- Download, install or build your packages with specific revisions.
- When build program with `gopm build` or `gopm install`, everything just happen in its own GOPATH and do not bother anything you've done.
* Put your Go project on anywhere you want.
**[Documentation](https://github.com/gpmgo/docs)**
# Commands
@ -40,13 +17,14 @@ USAGE:
gopm [global options] command [command options] [arguments...]
VERSION:
0.5.5.1111
0.5.6.1130
COMMANDS:
get fetch remote package(s) and dependencies to local repository
bin download and link dependencies and build executable binary
gen generate a gopmfile according current go project
run link dependencies and go run
build link dependencies and go build
build link dependencies and go build
install link dependencies and go install
help, h Shows a list of commands or help for one command

153
cmd/bin.go

@ -0,0 +1,153 @@
// 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 (
"os"
"path"
"strings"
"github.com/Unknwon/com"
"github.com/codegangsta/cli"
"github.com/gpmgo/gopm/doc"
"github.com/gpmgo/gopm/log"
)
var CmdBin = cli.Command{
Name: "bin",
Usage: "download and link dependencies and build executable binary",
Description: `Command bin downloads and links dependencies according to gopmfile,
and build executable binary to work directory
gopm bin <import path>@[<tag|commit|branch>:<value>]
gopm bin <package name>@[<tag|commit|branch>:<value>]
Can only specify one each time, and only works for projects that
contains main package`,
Action: runBin,
Flags: []cli.Flag{
cli.BoolFlag{"dir", "build binary to given directory(second argument)"},
},
}
func runBin(ctx *cli.Context) {
if len(ctx.Args()) == 0 {
log.Error("Bin", "Fail to start command")
log.Fatal("", "No package specified")
}
doc.LoadPkgNameList(doc.HomeDir + "/data/pkgname.list")
installRepoPath = doc.HomeDir + "/repos"
// Check arguments.
num := 1
if ctx.Bool("dir") {
num = 2
}
if len(ctx.Args()) != num {
log.Error("Bin", "Fail to start command")
log.Fatal("", "Invalid argument number")
}
// Check if given directory exists.
if ctx.Bool("dir") && !com.IsDir(ctx.Args()[1]) {
log.Error("Bin", "Fail to start command")
log.Fatal("", "Given directory does not exist")
}
// Parse package version.
info := ctx.Args()[0]
pkgName := info
ver := ""
var err error
if i := strings.Index(info, "@"); i > -1 {
pkgName = info[:i]
_, ver, err = validPath(info[i+1:])
if err != nil {
log.Error("Bin", "Fail to parse version")
log.Fatal("", err.Error())
}
}
// Check package name.
if !strings.Contains(pkgName, "/") {
name, ok := doc.PackageNameList[pkgName]
if !ok {
log.Error("Bin", "Invalid package name: "+pkgName)
log.Fatal("", "No match in the package name list")
}
pkgName = name
}
// Get code.
com.ExecCmd("gopm", "get", ctx.Args()[0])
// Check if previous steps were successful.
pkgPath := installRepoPath + "/" + pkgName
if len(ver) > 0 {
pkgPath += "." + ver
}
if !com.IsDir(pkgPath) {
log.Error("Bin", "Fail to continue command")
log.Fatal("", "Previous steps weren't successful")
}
wd, err := os.Getwd()
if err != nil {
log.Error("Bin", "Fail to get work directory")
log.Fatal("", err.Error())
}
// Change to repository path.
log.Log("Changing work directory to %s", pkgPath)
err = os.Chdir(pkgPath)
if err != nil {
log.Error("Bin", "Fail to change work directory")
log.Fatal("", err.Error())
}
// Build application.
com.ExecCmd("gopm", "build")
defer func() {
// Clean files.
os.RemoveAll(pkgPath + "/vendor")
}()
// Check if previous steps were successful.
binName := path.Base(pkgName)
if !com.IsFile(binName) {
log.Error("Bin", "Fail to continue command")
log.Fatal("", "Previous steps weren't successful or the project does not contain main package")
}
// Move binary to given directory.
movePath := wd
if ctx.Bool("dir") {
movePath = ctx.Args()[1]
}
_, err = com.Move(binName, movePath+"/"+binName)
if err != nil {
log.Error("Bin", "Fail to move binary")
log.Fatal("", err.Error())
}
os.Chmod(movePath+"/"+binName, os.ModePerm)
log.Log("Changing work directory back to %s", wd)
os.Chdir(wd)
log.Success("SUCC", "Bin", "Command execute successfully!")
}

4
cmd/build.go

@ -15,8 +15,11 @@
package cmd
import (
//"os"
"github.com/codegangsta/cli"
"github.com/gpmgo/gopm/doc"
"github.com/gpmgo/gopm/log"
)
@ -31,6 +34,7 @@ gopm build <go build commands>`,
}
func runBuild(ctx *cli.Context) {
doc.LoadLocalNodes()
genNewGoPath(ctx, false)
log.Trace("Building...")

4
cmd/gen.go

@ -27,7 +27,7 @@ import (
var CmdGen = cli.Command{
Name: "gen",
Usage: "generate a gopmfile according current go project",
Usage: "generate a gopmfile according current Go project",
Description: `Command gen gets dependencies and generates a gopmfile
gopm gen
@ -35,7 +35,7 @@ gopm gen
Make sure you run this command in the root path of a go project.`,
Action: runGen,
Flags: []cli.Flag{
cli.BoolFlag{"example", "download dependencies for example(s)"},
cli.BoolFlag{"example", "check dependencies for example(s)"},
},
}

69
cmd/get.go

@ -18,6 +18,7 @@ import (
"errors"
"fmt"
"os"
"path"
"path/filepath"
"strings"
@ -31,6 +32,7 @@ import (
var (
installRepoPath string
installGopath string
downloadCache map[string]bool // Saves packages that have been downloaded.
downloadCount int
failConut int
@ -51,6 +53,7 @@ Can specify one or more: gopm get beego@tag:v0.9.0 github.com/beego/bee
If no argument is supplied, then gopmfile must be present`,
Action: runGet,
Flags: []cli.Flag{
cli.BoolFlag{"gopath", "download package(s) to GOPATH"},
cli.BoolFlag{"force", "force to update pakcage(s) and dependencies"},
cli.BoolFlag{"example", "download dependencies for example(s)"},
},
@ -61,15 +64,19 @@ func init() {
}
func runGet(ctx *cli.Context) {
hd, err := com.HomeDir()
if err != nil {
log.Error("get", "Fail to get current user")
log.Fatal("", err.Error())
}
doc.HomeDir = strings.Replace(doc.RawHomeDir, "~", hd, -1)
doc.LoadPkgNameList(doc.HomeDir + "/data/pkgname.list")
if ctx.Bool("gopath") {
installGopath = com.GetGOPATHs()[0]
if !com.IsDir(installGopath) {
log.Error("Get", "Fail to start command")
log.Fatal("", "GOPATH does not exist: "+installGopath)
}
log.Log("Indicate GOPATH: %s", installGopath)
installGopath += "/src"
}
installRepoPath = doc.HomeDir + "/repos"
log.Log("Local repository path: %s", installRepoPath)
@ -80,6 +87,7 @@ func runGet(ctx *cli.Context) {
default:
getByPath(ctx)
}
}
func getByGopmfile(ctx *cli.Context) {
@ -134,27 +142,27 @@ func getByGopmfile(ctx *cli.Context) {
func getByPath(ctx *cli.Context) {
nodes := make([]*doc.Node, 0, len(ctx.Args()))
for _, info := range ctx.Args() {
pkg := info
node := doc.NewNode(pkg, pkg, doc.BRANCH, "", true)
pkgName := info
node := doc.NewNode(pkgName, pkgName, doc.BRANCH, "", true)
if i := strings.Index(info, "@"); i > -1 {
pkg = info[:i]
pkgName = info[:i]
tp, ver, err := validPath(info[i+1:])
if err != nil {
log.Error("", "Fail to parse version")
log.Error("Get", "Fail to parse version")
log.Fatal("", err.Error())
}
node = doc.NewNode(pkg, pkg, tp, ver, true)
node = doc.NewNode(pkgName, pkgName, tp, ver, true)
}
// Cheeck package name.
if !strings.Contains(pkg, "/") {
name, ok := doc.PackageNameList[pkg]
// Check package name.
if !strings.Contains(pkgName, "/") {
name, ok := doc.PackageNameList[pkgName]
if !ok {
log.Error("", "Invalid package name: "+pkg)
log.Error("Get", "Invalid package name: "+pkgName)
log.Fatal("", "No match in the package name list")
}
pkg = name
pkgName = name
}
nodes = append(nodes, node)
@ -174,6 +182,16 @@ func getByPath(ctx *cli.Context) {
downloadCount, failConut)
}
func copyToGopath(srcPath, destPath string) {
fmt.Println(destPath)
os.RemoveAll(destPath)
err := com.CopyDir(srcPath, destPath)
if err != nil {
log.Error("Download", "Fail to copy to GOPATH")
log.Fatal("", err.Error())
}
}
// downloadPackages downloads packages with certain commit,
// if the commit is empty string, then it downloads all dependencies,
// otherwise, it only downloada package with specific commit only.
@ -182,7 +200,8 @@ func downloadPackages(ctx *cli.Context, nodes []*doc.Node) {
for _, n := range nodes {
// Check if it is a valid remote path.
if doc.IsValidRemotePath(n.ImportPath) {
installPath := installRepoPath + "/" + doc.GetProjectPath(n.ImportPath)
gopathDir := path.Join(installGopath, n.ImportPath)
installPath := path.Join(installRepoPath, doc.GetProjectPath(n.ImportPath))
if len(n.Value) > 0 {
installPath += "." + n.Value
}
@ -192,8 +211,14 @@ func downloadPackages(ctx *cli.Context, nodes []*doc.Node) {
if com.IsExist(installPath) {
log.Trace("Skipped installed package: %s@%s:%s",
n.ImportPath, n.Type, doc.CheckNodeValue(n.Value))
if ctx.Bool("gopath") {
copyToGopath(installPath, gopathDir)
}
continue
}
} else if !com.IsExist(installPath) {
doc.LocalNodes.SetValue(doc.GetProjectPath(n.ImportPath), "value", "")
}
if !downloadCache[n.ImportPath] {
@ -244,7 +269,11 @@ func downloadPackages(ctx *cli.Context, nodes []*doc.Node) {
// Only save non-commit node.
if len(nod.Value) == 0 && len(nod.Revision) > 0 {
doc.LocalNodes.SetValue(nod.ImportPath, "value", nod.Revision)
doc.LocalNodes.SetValue(doc.GetProjectPath(nod.ImportPath), "value", nod.Revision)
}
if ctx.Bool("gopath") {
copyToGopath(installPath, gopathDir)
}
}
} else {
@ -269,7 +298,7 @@ func downloadPackage(ctx *cli.Context, nod *doc.Node) (*doc.Node, []string) {
// Mark as donwloaded.
downloadCache[nod.ImportPath] = true
nod.Revision = doc.LocalNodes.MustValue(nod.ImportPath, "value")
nod.Revision = doc.LocalNodes.MustValue(doc.GetProjectPath(nod.ImportPath), "value")
imports, err := doc.PureDownload(nod, installRepoPath, ctx) //CmdGet.Flags)
if err != nil {

40
cmd/gopath.go

@ -49,10 +49,16 @@ func getGopmPkgs(dirPath string, isTest bool) (pkgs map[string]*doc.Pkg, err err
}
if !doc.IsGoRepoPath(name) {
if builds != nil {
if dep, ok := builds[name]; ok {
// TODO: need version
pkgs[name] = &doc.Pkg{ImportPath: dep}
continue
if info, ok := builds[name]; ok {
// Check version.
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)
@ -82,16 +88,21 @@ func getChildPkgs(ctx *cli.Context, cpath string, ppkg *doc.Pkg, cachePkgs map[s
if !pkgInCache(name, cachePkgs) {
var newPath string
if !build.IsLocalImport(name) {
suf := "." + pkg.Value
if len(suf) == 1 {
suf = ""
}
newPath = filepath.Join(installRepoPath, pkg.ImportPath)
if pkgName != "" && strings.HasPrefix(pkg.ImportPath, pkgName) {
newPath = filepath.Join(curPath, pkg.ImportPath[len(pkgName)+1:])
newPath = filepath.Join(curPath, pkg.ImportPath[len(pkgName)+1:]+suf)
} else {
if !com.IsExist(newPath) {
var t, ver string = doc.BRANCH, ""
node := doc.NewNode(pkg.ImportPath, pkg.ImportPath, t, ver, true)
if !com.IsExist(newPath + suf) {
node := doc.NewNode(pkg.ImportPath, pkg.ImportPath,
pkg.Type, pkg.Value, true)
nodes := []*doc.Node{node}
downloadPackages(ctx, nodes)
// should handler download failed
// TODO: Should handler download failed
}
}
} else {
@ -214,8 +225,13 @@ func genNewGoPath(ctx *cli.Context, isTest bool) {
os.RemoveAll(newGoPathSrc)
os.MkdirAll(newGoPathSrc, os.ModePerm)
for name, _ := range cachePkgs {
oldPath := filepath.Join(installRepoPath, name)
for name, pkg := range cachePkgs {
suf := "." + pkg.Value
if len(suf) == 1 {
suf = ""
}
oldPath := filepath.Join(installRepoPath, name) + suf
newPath := filepath.Join(newGoPathSrc, name)
paths := strings.Split(name, "/")
var isExistP bool
@ -236,7 +252,7 @@ func genNewGoPath(ctx *cli.Context, isTest bool) {
}
if !isExistP {
log.Log("Linking %s", name)
log.Log("Linking %s", name+suf)
err = autoLink(oldPath, newPath)
if err != nil {
log.Error("", "Fail to make link")

10
doc/conf.go

@ -35,6 +35,16 @@ var (
LocalNodes *goconfig.ConfigFile
)
func init() {
hd, err := com.HomeDir()
if err != nil {
log.Error("", "Fail to get current user")
log.Fatal("", err.Error())
}
HomeDir = strings.Replace(RawHomeDir, "~", hd, -1)
}
func NewGopmfile(dirPath string) *goconfig.ConfigFile {
gf, err := goconfig.LoadConfigFile(dirPath + "/" + GopmFileName)
if err != nil {

199
docs/features_CN.md

@ -1,199 +0,0 @@
gopm
====
* [总体设计目标](#10)
* [程序结构](#11)
* [Go包版本说明](#20)
* [各命令的目标和作用](#30)
* [gopm help](#31)
* [gopm sources](#32)
* [gopm list](#33)
* [gopm get](#34)
* [gopm rm](#35)
* [gopm search](#36)
* [gopm doc](#37)
* [gopm serve](#38)
* [gopm sync](#39)
* [gopm import](#40)
* [gopm gen](#41)
* [gopm build](#42)
* [gopm run](#43)
* [gopm test](#44)
* [gopmspec文件格式](#50)
<a id="10" name="10"></a>
# 总体设计目标
1. 支持go语言的版本管理
2. 支持文档管理
3. 支持本地源服务器
4. 本地源服务器同时支持公共包和私有包
5. 支持依赖管理
6. 支持从github, code.google.com, gitLab, 等常见的源码托管服务下载
<a id="11" name="11"></a>
# 最终程序只有一个,但是通过配置,可以有三种模式:
1 独立服务器
2 子服务器
3 客户端(默认)
## 独立服务器
独立服务器就是本身的包都是直接从源服务器中获取的。
## 子服务器
子服务器就是包是从所配置的独立服务器上获取的,而不是直接从github等源服务器获取,在一个局域网中,可以通过架设子服务器来加快包的分发。
## 客户端
默认下载即为客户端模式,客户端默认是从源服务器获取包,如果要从包服务器获取包,则可在配置文件中通过配置即可。
<a id="20" name="20"></a>
#Go包版本说明
版本分为四种:
* []: 表示的是当前最新版本即trunk
* branch: 表示的是某个分支
* tag: 表示的是某个tag
* commit: 表示的是某个reversion
#配置文件说明
默认没有配置文件,当系统第一次启动时检测homedir/.gopm/config,看是否存在,如果不存在则自动创建此配置文件。
配置文件内容如下:
[sources]
http://gopm.io
[repos]
~/.gopm/repos
#数据库说明
包信息数据采用goleveldb,这是一个key/value数据库。数据库存默认放在~/.gopm/repos下。数据存放规则如下:
* "lastId" : "{lastId}" lastId中存放最大的Id,Id为自增
* "index:{packageName}": "{id}" index:中存放的是包名,value中存放的是这个包的不同版本的id,不同版本用逗号分隔
* “pkg:{id}” : "{pkg}" 某个包的名称
* “ver:{id}” : "{verString1}, {verString2}" 某个包版本对应的内容
* "desc:{id}" : "{desc}" 某个包的最新版本的描述
* "down:{id}" : "{down}" 某个包的下载url
* "deps:{id}" : "{deps}" 某个包的最新版本的描述
* “key:{keyword}:{id}” : "" 关键词及其对应的版本
* “total” :"{total}" 包总数
<a id="30" name="30"></a>
#各命令的目标和作用
<a id="31" name="31"></a>
###gopm help
显示当前可用的命令,以下命令中,[]表示可选,{}表示是参数
<a id="32" name="32"></a>
###gopm sources [add|rm [{url}]]
* [] 列出当前可用的所有源,默认为http://gopm.io/
* add url 添加一个源到本地
* rm url 删除一个源到本地,如果没有任何源,则自己成为一个独立的服务器,类似gopm.io
<a id="33" name="33"></a>
###gopm list [{packagename}[:{version}]]
* [] 列出所有本地的包
* packagename 显示指定名称的包的详细信息
<a id="34" name="34"></a>
###gopm get [-u] [{packagename}[:{version}]] [-f {gopmfile}]
* [] 查找当前目录下的所有.gopmfile文件,根据文件的描述下载所有的包
* packagename 从源中下载某个包
* -u packagename 从源中更新某个包
* -f gopmfile 根据指定的文件来下载包
<a id="35" name="35"></a>
###gopm rm {packagename}[:{version}]
去除一个包,如果不加版本标示,则删除该包的所有版本
<a id="36" name="36"></a>
###gopm search [-e] {keyword}
根据关键词查找包名或者包的描述,如果有-e开关,则完全匹配包名
<a id="37" name="37"></a>
###gopm doc [-b] {packagename}[:{version}]
* [] 显示一个包的文档
* -b 在默认浏览器中显示该包的文档
<a id="38" name="38"></a>
###gopm serve [-p {port}]
将本地仓库作为服务对外提供,如果没有-p,则端口为80,如果有,则端口为指定端口,该服务是一个web服务,通过浏览器也可以进行浏览。
<a id="39" name="39"></a>
###gopm sync [-u]
[] 如果当前配置了源,则从可用的源中同步所有的包信息和包内容的最新版本到本地仓库;
如果当前没有配置任何源,则将所有已有的包从源头进行更新
-u 仅更新本地仓库已经有的包,不包含本地仓库没有的包
<a id="40" name="40"></a>
###gopm import [{url}|{filepath}]
将某个地址或者本地的包导入到本地仓库中,url应为可支持的源码托管站点或者gitLab
<a id="41" name="41"></a>
###gopm gen [{gopmfile}]
扫描当前目录下的go工程,并自动生成一个.gopmfile的文件依赖文档,如果未指定,则文件名为.gopmfile,如果指定了,则为指定的文件名
<a id="42" name="42"></a>
###gopm build [-u]
此命令依赖于go build
1. 如果当前没有.gopmspec文件,则扫描当前的go工程的依赖,自动生成.gopmspec文档
2. 根据.gopmspec文件自动下载所有需要的包,如果加了-u参数,则同时更新所有的包
3. 根据.gopmspec文件自动切换gopath中的相关版本
4. 调用go build对工程进行编译
<a id="43" name="43"></a>
###gopm run [{gofile}]
此命令依赖于go run
调用gopm build在临时文件夹生成可执行文件,并设置程序当前目录为当前目录,并执行
<a id="44" name="44"></a>
###gopm test
此命令依赖于go test
调用gopm build在临时文件夹生成可执行的测试文件,并设置程序当前目录为当前目录,并执行
<a id="50" name="50"></a>
#gopmspec文件格式
.gopmspec文件的格式类似一个ini文件,当前分为两个section。
build段内的依赖保存的是go build所需要依赖的所有包,一行一个,可用 =, >=等等,如果什么符号都没有,就是取最新版本
```
[build]
xweb
beego = tag:0.1
xorm >= branch:0.2
[test]
testing
```

BIN
docs/images/arch.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 217 KiB

23
docs/usage.md

@ -1,23 +0,0 @@
gopm
====
gopm(Go Package Manager) is a Go package manage tool for search, install, update, share packages in Go.
usage:
gopm help show this document
gopm sources list all package source servers or add or rm a source
gopm list list all packages local or list all versions of a package
gopm get get a package or according to a gopmfile
gopm upgrade upgrade a package or all packages and gopm self
gopm rm remove a package
gopm search search a package according keywords
gopm doc show a package's document on console or web browser
gopm serve run as a package source server
gopm sync sync all packages from first avilable source server to local
gopm import import a package into local
gopm gen generate a .gopmspec file according current dir's source codes
gopm build build project according to gopmfile
gopm run build project according to gopmfile and run
gopm test test project like go test

3
gopm.go

@ -29,7 +29,7 @@ import (
// Test that go1.1 tag above is included in builds. main.go refers to this definition.
const go11tag = true
const APP_VER = "0.5.5.1129"
const APP_VER = "0.5.7.1201"
// //cmd.CmdSearch,
// cmdClean,
@ -53,6 +53,7 @@ func main() {
app.Version = APP_VER
app.Commands = []cli.Command{
cmd.CmdGet,
cmd.CmdBin,
cmd.CmdGen,
cmd.CmdRun,
cmd.CmdBuild,

Loading…
Cancel
Save