pax_global_header 0000666 0000000 0000000 00000000064 12625565062 0014523 g ustar 00root root 0000000 0000000 52 comment=a40e0ad20dda5dfee3465ff3615dcbf86f1aa797
gb-0.3.2/ 0000775 0000000 0000000 00000000000 12625565062 0012115 5 ustar 00root root 0000000 0000000 gb-0.3.2/.gitignore 0000664 0000000 0000000 00000000021 12625565062 0014076 0 ustar 00root root 0000000 0000000 !*
testdata/bin/
gb-0.3.2/.travis.yml 0000664 0000000 0000000 00000001116 12625565062 0014225 0 ustar 00root root 0000000 0000000 language: go
go_import_path: github.com/constabulary/gb
go:
- 1.5.1
- 1.4.3
- tip
sudo: false
addons:
apt:
packages:
- libcap-dev # integration-tests/service.v1
ssh_known_hosts:
- bitbucket.org
install:
- go get -t -v ./...
- git clone --quiet --single-branch --depth 1 https://github.com/constabulary/integration-tests.git ../integration-tests
- echo '#!/bin/bash' > "$GOPATH/bin/sudo"
&& echo 'echo >&2 attempted sudo "$@"' >> "$GOPATH/bin/sudo"
&& chmod +x "$GOPATH/bin/sudo"
script:
- go test -v ./...
- ../integration-tests/run-all.bash
gb-0.3.2/LICENSE 0000664 0000000 0000000 00000002070 12625565062 0013121 0 ustar 00root root 0000000 0000000 The MIT License (MIT)
Copyright (c) 2015 constabulary
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
gb-0.3.2/README.md 0000664 0000000 0000000 00000004132 12625565062 0013374 0 ustar 00root root 0000000 0000000 # gb
### Build status
Unix:
[](https://travis-ci.org/constabulary/gb)
Windows:
[](https://ci.appveyor.com/project/davecheney/gb/branch/master)
`gb` is a proof of concept replacement build tool for the [Go programming language](https://golang.org).
I gave a talk about `gb` and the rational for its creation at GDG Berlin in April 2015, [video](https://www.youtube.com/watch?v=c3dW80eO88I) and [slides](http://go-talks.appspot.com/github.com/davecheney/presentations/reproducible-builds.slide#1).
## Project based
`gb` operates on the concept of a project. A gb project is a workspace for all the Go code that is required to build your project.
A gb project is a folder on disk that contains a subdirectory named src/
. That's it, no environment variables to set. For the rest of this document we'll refer to your gb
project as $PROJECT
.
You can create as many projects as you like and move between them simply by changing directories.
## Installation
go get github.com/constabulary/gb/...
## Read more
gb has its own site, [getgb.io](http://getgb.io/), head over there for more information.
## Contributing
### Road map
#### Completed
- [Cross Compilation](https://github.com/constabulary/gb/milestones/cross-compilation)
- Tag handling, unify -tags, ENVVARS and GOOS/GOARCH into a single format for binary names and pkg cache
#### Todo
- 0.3 series: gb test improvements, test output, ~~flag handling~~ (done)
- [Race detector support](https://github.com/constabulary/gb/issues/96)
- 0.4 series: gb vendor updates and bug fixes
- 0.5 series: new package resolver (replace go/build)
### Big ticket items
Big ticket items that are not on the road map yet
- Package BuildID support (make stale detection work like the Go 1.5)
- `gccgo` toolchain support.
We welcome pull requests, bug fixes and issue reports.
Before proposing a large change, please discuss your change by raising an issue.
gb-0.3.2/action_test.go 0000664 0000000 0000000 00000004454 12625565062 0014767 0 ustar 00root root 0000000 0000000 package gb
import (
"reflect"
"sort"
"testing"
)
func TestBuildAction(t *testing.T) {
actions := func(a ...*Action) []*Action {
return a
}
var tests = []struct {
pkg string
action *Action
err error
}{{
pkg: "a",
action: &Action{
Name: "build: a",
Deps: actions(&Action{Name: "compile: a"}),
},
}, {
pkg: "b",
action: &Action{
Name: "build: b",
Deps: []*Action{
&Action{
Name: "link: b",
Deps: []*Action{
&Action{
Name: "compile: b",
Deps: []*Action{
&Action{
Name: "compile: a",
}},
},
}},
},
},
}, {
pkg: "c",
action: &Action{
Name: "build: c",
Deps: []*Action{
&Action{
Name: "compile: c",
Deps: []*Action{
&Action{
Name: "compile: a",
}, &Action{
Name: "compile: d.v1",
}},
}},
},
}}
for _, tt := range tests {
ctx := testContext(t)
defer ctx.Destroy()
pkg, err := ctx.ResolvePackage(tt.pkg)
if !sameErr(err, tt.err) {
t.Errorf("ctx.ResolvePackage(%v): want %v, got %v", tt.pkg, tt.err, err)
continue
}
if err != nil {
continue
}
got, err := BuildPackages(pkg)
if !sameErr(err, tt.err) {
t.Errorf("BuildAction(%v): want %v, got %v", tt.pkg, tt.err, err)
continue
}
deleteTasks(got)
if !reflect.DeepEqual(tt.action, got) {
t.Errorf("BuildAction(%v): want %#v, got %#v", tt.pkg, tt.action, got)
}
// double underpants
sameAction(t, got, tt.action)
}
}
func sameAction(t *testing.T, want, got *Action) {
if want.Name != got.Name {
t.Errorf("sameAction: names do not match, want: %v, got %v", want.Name, got.Name)
return
}
if len(want.Deps) != len(got.Deps) {
t.Errorf("sameAction(%v, %v): deps: len(want): %v, len(got): %v", want.Name, got.Name, len(want.Deps), len(got.Deps))
return
}
w, g := make(map[string]*Action), make(map[string]*Action)
for _, a := range want.Deps {
w[a.Name] = a
}
for _, a := range got.Deps {
g[a.Name] = a
}
var wk []string
for k := range w {
wk = append(wk, k)
}
sort.Strings(wk)
for _, a := range wk {
g, ok := g[a]
if !ok {
t.Errorf("sameAction(%v, %v): deps: want %v, got nil", want.Name, got.Name, a)
continue
}
sameAction(t, w[a], g)
}
}
func deleteTasks(a *Action) {
for _, d := range a.Deps {
deleteTasks(d)
}
a.Run = nil
}
gb-0.3.2/appveyor.yml 0000664 0000000 0000000 00000002053 12625565062 0014505 0 ustar 00root root 0000000 0000000 version: build-{build}.{branch}
clone_folder: C:\gopath\src\github.com\constabulary\gb
shallow_clone: true # for startup speed
environment:
GOPATH: C:\gopath
platform:
- x64
#- x86
# the "x86" platform still gives us GOARCH=amd64 :/
# TODO(tianon) we have 32bit Go installed at C:\go-x86 and 32bit mingw at both C:\msys64\mingw32 and C:\MinGW, so we could do something
# http://www.appveyor.com/docs/installed-software
install:
# some helpful output for debugging builds
- go version
- go env
# pre-installed MinGW at C:\MinGW is 32bit only
# but MSYS2 at C:\msys64 has mingw64
- set PATH=C:\msys64\mingw64\bin;%PATH%
- gcc --version
- g++ --version
# need bzr for several tests
- choco install bzr
- set PATH=C:\Program Files (x86)\Bazaar;%PATH%
- bzr --version
# TODO(tianon) - git clone --depth 1 https://github.com/constabulary/integration-tests.git
build_script:
- go install -v ./...
test_script:
- set PATH=C:\gopath\bin;%PATH%
- gb help
- go test -v ./...
#artifacts:
# - path: '%GOPATH%\bin\*.exe'
deploy: off
gb-0.3.2/build.go 0000664 0000000 0000000 00000021354 12625565062 0013550 0 ustar 00root root 0000000 0000000 package gb
import (
"fmt"
"path/filepath"
"runtime"
"strings"
"time"
"github.com/constabulary/gb/debug"
)
// Build builds each of pkgs in succession. If pkg is a command, then the results of build include
// linking the final binary into pkg.Context.Bindir().
func Build(pkgs ...*Package) error {
build, err := BuildPackages(pkgs...)
if err != nil {
return err
}
return ExecuteConcurrent(build, runtime.NumCPU(), nil)
}
// BuildPackages produces a tree of *Actions that can be executed to build
// a *Package.
// BuildPackages walks the tree of *Packages and returns a corresponding
// tree of *Actions representing the steps required to build *Package
// and any of its dependencies
func BuildPackages(pkgs ...*Package) (*Action, error) {
if len(pkgs) < 1 {
return nil, fmt.Errorf("no packages supplied")
}
targets := make(map[string]*Action) // maps package importpath to build action
names := func(pkgs []*Package) []string {
var names []string
for _, pkg := range pkgs {
names = append(names, pkg.ImportPath)
}
return names
}
// create top level build action to unify all packages
t0 := time.Now()
build := Action{
Name: fmt.Sprintf("build: %s", strings.Join(names(pkgs), ",")),
Run: func() error {
debug.Debugf("build duration: %v %v", time.Since(t0), pkgs[0].Statistics.String())
return nil
},
}
for _, pkg := range pkgs {
if len(pkg.GoFiles)+len(pkg.CgoFiles) == 0 {
debug.Debugf("skipping %v: no go files", pkg.ImportPath)
continue
}
a, err := BuildPackage(targets, pkg)
if err != nil {
return nil, err
}
if a == nil {
// nothing to do
continue
}
build.Deps = append(build.Deps, a)
}
return &build, nil
}
// BuildPackage returns an Action representing the steps required to
// build this package.
func BuildPackage(targets map[string]*Action, pkg *Package) (*Action, error) {
// if this action is already present in the map, return it
// rather than creating a new action.
if a, ok := targets[pkg.ImportPath]; ok {
return a, nil
}
// step 0. are we stale ?
// if this package is not stale, then by definition none of its
// dependencies are stale, so ignore this whole tree.
if !pkg.Stale {
return nil, nil
}
// step 1. build dependencies
deps, err := BuildDependencies(targets, pkg)
if err != nil {
return nil, err
}
// step 2. build this package
build, err := Compile(pkg, deps...)
if err != nil {
return nil, err
}
if build == nil {
panic("build action was nil") // shouldn't happen
}
// record the final action as the action that represents
// building this package.
targets[pkg.ImportPath] = build
return build, nil
}
// Compile returns an Action representing the steps required to compile this package.
func Compile(pkg *Package, deps ...*Action) (*Action, error) {
var gofiles []string
gofiles = append(gofiles, pkg.GoFiles...)
// step 1. are there any .c files that we have to run cgo on ?
var ofiles []string // additional ofiles to pack
if len(pkg.CgoFiles) > 0 {
cgoACTION, cgoOFILES, cgoGOFILES, err := cgo(pkg)
if err != nil {
return nil, err
}
gofiles = append(gofiles, cgoGOFILES...)
ofiles = append(ofiles, cgoOFILES...)
deps = append(deps, cgoACTION)
}
if len(gofiles) == 0 {
return nil, fmt.Errorf("compile %q: no go files supplied", pkg.ImportPath)
}
// step 2. compile all the go files for this package, including pkg.CgoFiles
compile := Action{
Name: fmt.Sprintf("compile: %s", pkg.ImportPath),
Deps: deps,
Run: func() error { return gc(pkg, gofiles) },
}
// step 3. are there any .s files to assemble.
var assemble []*Action
for _, sfile := range pkg.SFiles {
sfile := sfile
ofile := filepath.Join(pkg.Workdir(), pkg.ImportPath, stripext(sfile)+".6")
assemble = append(assemble, &Action{
Name: fmt.Sprintf("asm: %s/%s", pkg.ImportPath, sfile),
Run: func() error {
t0 := time.Now()
err := pkg.tc.Asm(pkg, pkg.Dir, ofile, filepath.Join(pkg.Dir, sfile))
pkg.Record("asm", time.Since(t0))
return err
},
// asm depends on compile because compile will generate the local go_asm.h
Deps: []*Action{&compile},
})
ofiles = append(ofiles, ofile)
}
build := &compile
// Do we need to pack ? Yes, replace build action with pack.
if len(ofiles) > 0 {
pack := Action{
Name: fmt.Sprintf("pack: %s", pkg.ImportPath),
Deps: []*Action{
&compile,
},
Run: func() error {
// collect .o files, ofiles always starts with the gc compiled object.
// TODO(dfc) objfile(pkg) should already be at the top of this set
ofiles = append(
[]string{objfile(pkg)},
ofiles...,
)
// pack
t0 := time.Now()
err := pkg.tc.Pack(pkg, ofiles...)
pkg.Record("pack", time.Since(t0))
return err
},
}
pack.Deps = append(pack.Deps, assemble...)
build = &pack
}
// should this package be cached
// TODO(dfc) pkg.SkipInstall should become Install
if !pkg.SkipInstall && pkg.Scope != "test" {
build = &Action{
Name: fmt.Sprintf("install: %s", pkg.ImportPath),
Deps: []*Action{build},
Run: func() error { return copyfile(pkgfile(pkg), objfile(pkg)) },
}
}
// if this is a main package, add a link stage
if pkg.isMain() {
build = &Action{
Name: fmt.Sprintf("link: %s", pkg.ImportPath),
Deps: []*Action{build},
Run: func() error { return link(pkg) },
}
}
if pkg.Scope != "test" {
// if this package is not compiled in test scope, then
// log the name of the package when complete.
build.Run = logInfoFn(build.Run, pkg.ImportPath)
}
return build, nil
}
func logInfoFn(fn func() error, s string) func() error {
return func() error {
err := fn()
fmt.Println(s)
return err
}
}
// BuildDependencies returns a slice of Actions representing the steps required
// to build all dependant packages of this package.
func BuildDependencies(targets map[string]*Action, pkg *Package) ([]*Action, error) {
var deps []*Action
pkgs := pkg.Imports()
if pkg.isMain() {
extra := []string{
// all binaries depend on runtime, even if they do not
// explicitly import it.
"runtime",
}
for _, i := range extra {
if pkg.shouldignore(i) {
continue
}
p, err := pkg.ResolvePackage(i)
if err != nil {
return nil, err
}
pkgs = append(pkgs, p)
}
}
for _, i := range pkgs {
a, err := BuildPackage(targets, i)
if err != nil {
return nil, err
}
if a == nil {
// no action required for this Package
continue
}
deps = append(deps, a)
}
return deps, nil
}
func gc(pkg *Package, gofiles []string) error {
t0 := time.Now()
includes := pkg.IncludePaths()
importpath := pkg.ImportPath
if pkg.Scope == "test" && pkg.ExtraIncludes != "" {
// TODO(dfc) gross
includes = append([]string{pkg.ExtraIncludes}, includes...)
}
for i := range gofiles {
if filepath.IsAbs(gofiles[i]) {
// terrible hack for cgo files which come with an absolute path
continue
}
fullpath := filepath.Join(pkg.Dir, gofiles[i])
path, err := filepath.Rel(pkg.Dir, fullpath)
if err == nil {
gofiles[i] = path
} else {
gofiles[i] = fullpath
}
}
err := pkg.tc.Gc(pkg, includes, importpath, pkg.Dir, objfile(pkg), gofiles)
pkg.Record("gc", time.Since(t0))
return err
}
func link(pkg *Package) error {
t0 := time.Now()
target := pkg.Binfile()
if err := mkdir(filepath.Dir(target)); err != nil {
return err
}
includes := pkg.IncludePaths()
if pkg.Scope == "test" && pkg.ExtraIncludes != "" {
// TODO(dfc) gross
includes = append([]string{pkg.ExtraIncludes}, includes...)
}
err := pkg.tc.Ld(pkg, includes, target, objfile(pkg))
pkg.Record("link", time.Since(t0))
return err
}
// Workdir returns the working directory for a package.
func Workdir(pkg *Package) string {
switch pkg.Scope {
case "test":
ip := strings.TrimSuffix(filepath.FromSlash(pkg.ImportPath), "_test")
return filepath.Join(pkg.Workdir(), ip, "_test", filepath.Dir(filepath.FromSlash(pkg.ImportPath)))
default:
return filepath.Join(pkg.Workdir(), filepath.Dir(filepath.FromSlash(pkg.ImportPath)))
}
}
// objfile returns the name of the object file for this package
func objfile(pkg *Package) string {
return filepath.Join(Workdir(pkg), objname(pkg))
}
func objname(pkg *Package) string {
if pkg.isMain() {
return filepath.Join(filepath.Base(filepath.FromSlash(pkg.ImportPath)), "main.a")
}
return filepath.Base(filepath.FromSlash(pkg.ImportPath)) + ".a"
}
func pkgname(pkg *Package) string {
switch pkg.Scope {
case "test":
return filepath.Base(filepath.FromSlash(pkg.ImportPath))
default:
if pkg.Name == "main" {
return filepath.Base(filepath.FromSlash(pkg.ImportPath))
}
return pkg.Name
}
}
func binname(pkg *Package) string {
switch {
case pkg.Scope == "test":
return pkg.Name + ".test"
case pkg.Name == "main":
return filepath.Base(filepath.FromSlash(pkg.ImportPath))
default:
panic("binname called with non main package: " + pkg.ImportPath)
}
}
gb-0.3.2/build_test.go 0000664 0000000 0000000 00000016663 12625565062 0014616 0 ustar 00root root 0000000 0000000 package gb
import (
"errors"
"fmt"
"go/build"
"io/ioutil"
"os"
"path/filepath"
"reflect"
"sort"
"testing"
)
func TestBuild(t *testing.T) {
opts := func(o ...func(*Context) error) []func(*Context) error { return o }
tests := []struct {
pkg string
opts []func(*Context) error
err error
}{{
pkg: "a",
err: nil,
}, {
pkg: "b", // actually command
err: nil,
}, {
pkg: "c",
err: nil,
}, {
pkg: "d.v1",
err: nil,
}, {
pkg: "x",
err: errors.New("import cycle detected: x -> y -> x"),
}, {
pkg: "cgomain",
err: nil,
}, {
pkg: "cgotest",
err: nil,
}, {
pkg: "notestfiles",
err: nil,
}, {
pkg: "cgoonlynotest",
err: nil,
}, {
pkg: "testonly",
err: nil,
}, {
pkg: "extestonly",
err: nil,
}, {
pkg: "mainnoruntime",
err: nil,
}, {
pkg: "h", // imports "blank", which is blank, see issue #131
err: fmt.Errorf("no buildable Go source files in %s", filepath.Join(getwd(t), "testdata", "src", "blank")),
}, {
pkg: "cppmain",
}, {
pkg: "tags1",
opts: opts(Tags("x")), // excludes the test file in package
err: fmt.Errorf("no buildable Go source files in %s", filepath.Join(getwd(t), "testdata", "src", "tags1")),
}, {
pkg: "tags2",
err: fmt.Errorf("no buildable Go source files in %s", filepath.Join(getwd(t), "testdata", "src", "tags2")),
}, {
pkg: "tags2",
opts: opts(Tags("x")),
}}
proj := testProject(t)
for _, tt := range tests {
ctx, err := proj.NewContext(tt.opts...)
ctx.Force = true
ctx.SkipInstall = true
defer ctx.Destroy()
pkg, err := ctx.ResolvePackage(tt.pkg)
if !sameErr(err, tt.err) {
t.Errorf("ctx.ResolvePackage(%v): want %v, got %v", tt.pkg, tt.err, err)
continue
}
if err != nil {
continue
}
if err := Build(pkg); !sameErr(err, tt.err) {
t.Errorf("ctx.Build(%v): want %v, got %v", tt.pkg, tt.err, err)
}
}
}
func TestBuildPackage(t *testing.T) {
tests := []struct {
pkg string
err error
}{{
pkg: "a",
err: nil,
}, {
pkg: "b", // actually command
err: nil,
}, {
pkg: "c",
err: nil,
}, {
pkg: "d.v1",
err: nil,
}, {
pkg: "cgomain",
err: nil,
}, {
pkg: "cgotest",
err: nil,
}, {
pkg: "notestfiles",
err: nil,
}, {
pkg: "cgoonlynotest",
err: nil,
}, {
pkg: "testonly",
err: errors.New(`compile "testonly": no go files supplied`),
}, {
pkg: "extestonly",
err: errors.New(`compile "extestonly": no go files supplied`),
}}
for _, tt := range tests {
ctx := testContext(t)
defer ctx.Destroy()
pkg, err := ctx.ResolvePackage(tt.pkg)
if err != nil {
t.Errorf("ctx.ResolvePackage(%v): %v", tt.pkg, err)
continue
}
targets := make(map[string]*Action)
if _, err := BuildPackage(targets, pkg); !sameErr(err, tt.err) {
t.Errorf("ctx.BuildPackage(%v): want %v, got %v", tt.pkg, tt.err, err)
}
}
}
func TestBuildPackages(t *testing.T) {
tests := []struct {
pkgs []string
actions []string
err error
}{{
pkgs: []string{"a", "b", "c"},
actions: []string{"compile: a", "compile: c", "link: b"},
}, {
pkgs: []string{"cgotest", "cgomain", "notestfiles", "cgoonlynotest", "testonly", "extestonly"},
actions: []string{"compile: notestfiles", "link: cgomain", "pack: cgoonlynotest", "pack: cgotest"},
}}
for _, tt := range tests {
ctx := testContext(t)
defer ctx.Destroy()
var pkgs []*Package
for _, pkg := range tt.pkgs {
pkg, err := ctx.ResolvePackage(pkg)
if err != nil {
t.Errorf("ctx.ResolvePackage(%v): %v", pkg, err)
continue
}
pkgs = append(pkgs, pkg)
}
a, err := BuildPackages(pkgs...)
if !sameErr(err, tt.err) {
t.Errorf("ctx.BuildPackages(%v): want %v, got %v", pkgs, tt.err, err)
}
var names []string
for _, a := range a.Deps {
names = append(names, a.Name)
}
sort.Strings(names)
if !reflect.DeepEqual(tt.actions, names) {
t.Errorf("ctx.BuildPackages(%v): want %v, got %v", pkgs, tt.actions, names)
}
}
}
func TestObjfile(t *testing.T) {
var tests = []struct {
pkg string // package name
want string // objfile result
}{
{pkg: "b", want: "b/main.a"},
{pkg: "nested/a", want: "nested/a.a"},
{pkg: "nested/b", want: "nested/b.a"},
}
for _, tt := range tests {
ctx := testContext(t)
defer ctx.Destroy()
pkg, err := ctx.ResolvePackage(tt.pkg)
if err != nil {
t.Fatal(err)
}
got := objfile(pkg)
want := filepath.Join(ctx.Workdir(), tt.want)
if want != got {
t.Errorf("(%s).Objdir(): want %s, got %s", tt.pkg, want, got)
}
}
}
func TestCgoobjdir(t *testing.T) {
var tests = []struct {
pkg string // package name
want string // objdir result
}{
{pkg: "b", want: "b/_cgo"},
{pkg: "nested/a", want: "nested/a/_cgo"},
{pkg: "nested/b", want: "nested/b/_cgo"},
}
ctx := testContext(t)
defer ctx.Destroy()
for _, tt := range tests {
pkg, err := ctx.ResolvePackage(tt.pkg)
if err != nil {
t.Fatal(err)
}
got := cgoworkdir(pkg)
want := filepath.Join(ctx.Workdir(), tt.want)
if want != got {
t.Errorf("(%s).cgoobjdir(): want %s, got %s", tt.pkg, want, got)
}
}
}
func TestWorkdir(t *testing.T) {
var tests = []struct {
pkg string // package name
want string // objdir result
}{
{pkg: "b", want: ""},
{pkg: "nested/a", want: "nested"},
{pkg: "nested/b", want: "nested"},
}
ctx := testContext(t)
defer ctx.Destroy()
for _, tt := range tests {
pkg, err := ctx.ResolvePackage(tt.pkg)
if err != nil {
t.Error(err)
continue
}
got := Workdir(pkg)
want := filepath.Join(ctx.Workdir(), tt.want)
if want != got {
t.Errorf("Workdir(Package{Name: %v, ImportPath: %v, Scope: %v}): want %s, got %s", pkg.Name, pkg.ImportPath, pkg.Scope, want, got)
}
}
}
func TestPkgname(t *testing.T) {
var tests = []struct {
pkg *Package
want string
}{{
pkg: &Package{
Package: &build.Package{
Name: "main",
ImportPath: "main",
},
},
want: "main",
}, {
pkg: &Package{
Package: &build.Package{
Name: "a",
ImportPath: "main",
},
},
want: "a",
}, {
pkg: &Package{
Package: &build.Package{
Name: "main",
ImportPath: "a",
},
},
want: "a",
}, {
pkg: &Package{
Package: &build.Package{
Name: "main",
ImportPath: "testmain",
},
},
want: "testmain",
}, {
pkg: &Package{
Package: &build.Package{
Name: "main",
ImportPath: "main",
},
Scope: "test",
},
want: "main",
}, {
pkg: &Package{
Package: &build.Package{
Name: "a",
ImportPath: "main",
},
Scope: "test",
},
want: "main",
}, {
pkg: &Package{
Package: &build.Package{
Name: "main",
ImportPath: "a",
},
Scope: "test",
},
want: "a",
}, {
pkg: &Package{
Package: &build.Package{
Name: "main",
ImportPath: "a/a",
},
Scope: "test",
},
want: "a",
}, {
pkg: &Package{
Package: &build.Package{
Name: "main",
ImportPath: "testmain",
},
Scope: "test",
},
want: "testmain",
}}
for _, tt := range tests {
got := pkgname(tt.pkg)
if got != tt.want {
t.Errorf("pkgname(Package{Name:%q, ImportPath: %q, Scope:%q}): got %v, want %v", tt.pkg.Name, tt.pkg.ImportPath, tt.pkg.Scope, got, tt.want)
}
}
}
func sameErr(e1, e2 error) bool {
if e1 != nil && e2 != nil {
return e1.Error() == e2.Error()
}
return e1 == e2
}
func getwd(t *testing.T) string {
cwd, err := os.Getwd()
if err != nil {
t.Fatal(err)
}
return cwd
}
func mktemp(t *testing.T) string {
s, err := mktmp()
if err != nil {
t.Fatal(err)
}
return s
}
func mktmp() (string, error) {
return ioutil.TempDir("", "gb-test-")
}
gb-0.3.2/cgo.go 0000664 0000000 0000000 00000034167 12625565062 0013227 0 ustar 00root root 0000000 0000000 package gb
import (
"bytes"
"fmt"
"io"
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
"time"
)
func cgo(pkg *Package) (*Action, []string, []string, error) {
switch {
case gc14:
return cgo14(pkg)
case gc15:
return cgo15(pkg)
default:
return nil, nil, nil, fmt.Errorf("unsupported Go version: %v", runtime.Version)
}
}
// cgo produces a an Action representing the cgo steps
// an ofile representing the result of the cgo steps
// a set of .go files for compilation, and an error.
func cgo14(pkg *Package) (*Action, []string, []string, error) {
// collect cflags and ldflags from the package
// the environment, and pkg-config.
cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoLDFLAGS := cflags(pkg, false)
pcCFLAGS, pcLDFLAGS, err := pkgconfig(pkg)
if err != nil {
return nil, nil, nil, err
}
cgoCFLAGS = append(cgoCFLAGS, pcCFLAGS...)
cgoLDFLAGS = append(cgoLDFLAGS, pcLDFLAGS...)
runcgo1 := []*Action{
&Action{
Name: "runcgo1: " + pkg.ImportPath,
Run: func() error { return runcgo1(pkg, cgoCFLAGS, cgoLDFLAGS) },
}}
workdir := cgoworkdir(pkg)
defun := filepath.Join(workdir, "_cgo_defun.o")
rundefun := Action{
Name: "cc: " + pkg.ImportPath + ": _cgo_defun_c",
Deps: runcgo1,
Run: func() error { return pkg.tc.Cc(pkg, defun, filepath.Join(workdir, "_cgo_defun.c")) },
}
cgofiles := []string{filepath.Join(workdir, "_cgo_gotypes.go")}
for _, f := range pkg.CgoFiles {
cgofiles = append(cgofiles, filepath.Join(workdir, stripext(f)+".cgo1.go"))
}
cfiles := []string{
filepath.Join(workdir, "_cgo_main.c"),
filepath.Join(workdir, "_cgo_export.c"),
}
cfiles = append(cfiles, pkg.CFiles...)
for _, f := range pkg.CgoFiles {
cfiles = append(cfiles, filepath.Join(workdir, stripext(f)+".cgo2.c"))
}
cflags := append(cgoCPPFLAGS, cgoCFLAGS...)
cxxflags := append(cgoCPPFLAGS, cgoCXXFLAGS...)
gcc1, ofiles := cgocc(pkg, cflags, cxxflags, cfiles, pkg.CXXFiles, runcgo1...)
ofile := filepath.Join(filepath.Dir(ofiles[0]), "_cgo_.o")
gcc2 := Action{
Name: "gccld: " + pkg.ImportPath + ": _cgo_.o",
Deps: gcc1,
Run: func() error { return gccld(pkg, cgoCFLAGS, cgoLDFLAGS, ofile, ofiles) },
}
dynout := filepath.Join(workdir, "_cgo_import.c")
imports := stripext(dynout) + ".o"
runcgo2 := Action{
Name: "runcgo2: " + pkg.ImportPath,
Deps: []*Action{&gcc2},
Run: func() error {
if err := runcgo2(pkg, dynout, ofile); err != nil {
return err
}
return pkg.tc.Cc(pkg, imports, dynout)
},
}
allo := filepath.Join(filepath.Dir(ofiles[0]), "_all.o")
action := Action{
Name: "rungcc3: " + pkg.ImportPath,
Deps: []*Action{&runcgo2, &rundefun},
Run: func() error {
return rungcc3(pkg, pkg.Dir, allo, ofiles[1:]) // skip _cgo_main.o
},
}
return &action, []string{defun, imports, allo}, cgofiles, nil
}
// cgo produces a an Action representing the cgo steps
// an ofile representing the result of the cgo steps
// a set of .go files for compilation, and an error.
func cgo15(pkg *Package) (*Action, []string, []string, error) {
// collect cflags and ldflags from the package
// the environment, and pkg-config.
cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoLDFLAGS := cflags(pkg, false)
pcCFLAGS, pcLDFLAGS, err := pkgconfig(pkg)
if err != nil {
return nil, nil, nil, err
}
cgoCFLAGS = append(cgoCFLAGS, pcCFLAGS...)
cgoLDFLAGS = append(cgoLDFLAGS, pcLDFLAGS...)
runcgo1 := []*Action{
&Action{
Name: "runcgo1: " + pkg.ImportPath,
Run: func() error { return runcgo1(pkg, cgoCFLAGS, cgoLDFLAGS) },
},
}
workdir := cgoworkdir(pkg)
cgofiles := []string{filepath.Join(workdir, "_cgo_gotypes.go")}
for _, f := range pkg.CgoFiles {
cgofiles = append(cgofiles, filepath.Join(workdir, stripext(f)+".cgo1.go"))
}
cfiles := []string{
filepath.Join(workdir, "_cgo_main.c"),
filepath.Join(workdir, "_cgo_export.c"),
}
cfiles = append(cfiles, pkg.CFiles...)
for _, f := range pkg.CgoFiles {
cfiles = append(cfiles, filepath.Join(workdir, stripext(f)+".cgo2.c"))
}
cflags := append(cgoCPPFLAGS, cgoCFLAGS...)
cxxflags := append(cgoCPPFLAGS, cgoCXXFLAGS...)
gcc1, ofiles := cgocc(pkg, cflags, cxxflags, cfiles, pkg.CXXFiles, runcgo1...)
ofile := filepath.Join(filepath.Dir(ofiles[0]), "_cgo_.o")
gcc2 := Action{
Name: "gccld: " + pkg.ImportPath + ": _cgo_.o",
Deps: gcc1,
Run: func() error { return gccld(pkg, cgoCFLAGS, cgoLDFLAGS, ofile, ofiles) },
}
dynout := filepath.Join(workdir, "_cgo_import.go")
runcgo2 := Action{
Name: "runcgo2: " + pkg.ImportPath,
Deps: []*Action{&gcc2},
Run: func() error { return runcgo2(pkg, dynout, ofile) },
}
cgofiles = append(cgofiles, dynout)
allo := filepath.Join(filepath.Dir(ofiles[0]), "_all.o")
action := Action{
Name: "rungcc3: " + pkg.ImportPath,
Deps: []*Action{&runcgo2},
Run: func() error {
return rungcc3(pkg, pkg.Dir, allo, ofiles[1:]) // skip _cgo_main.o
},
}
return &action, []string{allo}, cgofiles, nil
}
// cgocc compiles all .c files.
// TODO(dfc) cxx not done
func cgocc(pkg *Package, cflags, cxxflags, cfiles, cxxfiles []string, deps ...*Action) ([]*Action, []string) {
workdir := cgoworkdir(pkg)
var cc []*Action
var ofiles []string
for _, cfile := range cfiles {
cfile := cfile
ofile := filepath.Join(workdir, stripext(filepath.Base(cfile))+".o")
ofiles = append(ofiles, ofile)
cc = append(cc, &Action{
Name: "rungcc1: " + pkg.ImportPath + ": " + cfile,
Deps: deps,
Run: func() error { return rungcc1(pkg, cflags, ofile, cfile) },
})
}
for _, cxxfile := range cxxfiles {
cxxfile := cxxfile
ofile := filepath.Join(workdir, stripext(filepath.Base(cxxfile))+".o")
ofiles = append(ofiles, ofile)
cc = append(cc, &Action{
Name: "rung++1: " + pkg.ImportPath + ": " + cxxfile,
Deps: deps,
Run: func() error { return rungpp1(pkg, cxxflags, ofile, cxxfile) },
})
}
return cc, ofiles
}
// rungcc1 invokes gcc to compile cfile into ofile
func rungcc1(pkg *Package, cgoCFLAGS []string, ofile, cfile string) error {
args := []string{"-g", "-O2",
"-I", pkg.Dir,
"-I", filepath.Dir(ofile),
}
args = append(args, cgoCFLAGS...)
args = append(args,
"-o", ofile,
"-c", cfile,
)
t0 := time.Now()
gcc := gccCmd(pkg, pkg.Dir)
var buf bytes.Buffer
err := runOut(&buf, pkg.Dir, nil, gcc[0], append(gcc[1:], args...)...)
if err != nil {
fmt.Fprintf(os.Stderr, "# %s\n", pkg.ImportPath)
io.Copy(os.Stderr, &buf)
}
pkg.Record(gcc[0], time.Since(t0))
return err
}
// rungpp1 invokes g++ to compile cfile into ofile
func rungpp1(pkg *Package, cgoCFLAGS []string, ofile, cfile string) error {
args := []string{"-g", "-O2",
"-I", pkg.Dir,
"-I", filepath.Dir(ofile),
}
args = append(args, cgoCFLAGS...)
args = append(args,
"-o", ofile,
"-c", cfile,
)
t0 := time.Now()
gxx := gxxCmd(pkg, pkg.Dir)
var buf bytes.Buffer
err := runOut(&buf, pkg.Dir, nil, gxx[0], append(gxx[1:], args...)...)
if err != nil {
fmt.Fprintf(os.Stderr, "# %s\n", pkg.ImportPath)
io.Copy(os.Stderr, &buf)
}
pkg.Record(gxx[0], time.Since(t0))
return err
}
// gccld links the o files from rungcc1 into a single _cgo_.o.
func gccld(pkg *Package, cgoCFLAGS, cgoLDFLAGS []string, ofile string, ofiles []string) error {
args := []string{}
args = append(args, "-o", ofile)
args = append(args, ofiles...)
args = append(args, cgoLDFLAGS...) // this has to go at the end, because reasons!
t0 := time.Now()
var cmd []string
if len(pkg.CXXFiles) > 0 || len(pkg.SwigCXXFiles) > 0 {
cmd = gxxCmd(pkg, pkg.Dir)
} else {
cmd = gccCmd(pkg, pkg.Dir)
}
var buf bytes.Buffer
err := runOut(&buf, pkg.Dir, nil, cmd[0], append(cmd[1:], args...)...)
if err != nil {
fmt.Fprintf(os.Stderr, "# %s\n", pkg.ImportPath)
io.Copy(os.Stderr, &buf)
}
pkg.Record("gccld", time.Since(t0))
return err
}
// rungcc3 links all previous ofiles together with libgcc into a single _all.o.
func rungcc3(pkg *Package, dir string, ofile string, ofiles []string) error {
args := []string{}
args = append(args, "-o", ofile)
args = append(args, ofiles...)
args = append(args, "-Wl,-r", "-nostdlib")
var cmd []string
if len(pkg.CXXFiles) > 0 || len(pkg.SwigCXXFiles) > 0 {
cmd = gxxCmd(pkg, dir)
} else {
cmd = gccCmd(pkg, dir)
}
if !strings.HasPrefix(cmd[0], "clang") {
libgcc, err := libgcc(pkg.Context)
if err != nil {
return nil
}
args = append(args, libgcc)
}
t0 := time.Now()
var buf bytes.Buffer
err := runOut(&buf, dir, nil, cmd[0], append(cmd[1:], args...)...)
if err != nil {
fmt.Fprintf(os.Stderr, "# %s\n", pkg.ImportPath)
io.Copy(os.Stderr, &buf)
}
pkg.Record("gcc3", time.Since(t0))
return err
}
// libgcc returns the value of gcc -print-libgcc-file-name.
func libgcc(ctx *Context) (string, error) {
args := []string{
"-print-libgcc-file-name",
}
var buf bytes.Buffer
cmd := gccCmd(&Package{Context: ctx}, "") // TODO(dfc) hack
err := runOut(&buf, ".", nil, cmd[0], args...)
return strings.TrimSpace(buf.String()), err
}
func cgotool(ctx *Context) string {
// TODO(dfc) need ctx.GOROOT method
return filepath.Join(ctx.Context.GOROOT, "pkg", "tool", ctx.gohostos+"_"+ctx.gohostarch, "cgo")
}
// envList returns the value of the given environment variable broken
// into fields, using the default value when the variable is empty.
func envList(key, def string) []string {
v := os.Getenv(key)
if v == "" {
v = def
}
return strings.Fields(v)
}
// Return the flags to use when invoking the C or C++ compilers, or cgo.
func cflags(p *Package, def bool) (cppflags, cflags, cxxflags, ldflags []string) {
var defaults string
if def {
defaults = "-g -O2"
}
cppflags = stringList(envList("CGO_CPPFLAGS", ""), p.CgoCPPFLAGS)
cflags = stringList(envList("CGO_CFLAGS", defaults), p.CgoCFLAGS)
cxxflags = stringList(envList("CGO_CXXFLAGS", defaults), p.CgoCXXFLAGS)
ldflags = stringList(envList("CGO_LDFLAGS", defaults), p.CgoLDFLAGS)
return
}
// call pkg-config and return the cflags and ldflags.
func pkgconfig(p *Package) ([]string, []string, error) {
if len(p.CgoPkgConfig) == 0 {
return nil, nil, nil // nothing to do
}
args := []string{
"--cflags",
}
args = append(args, p.CgoPkgConfig...)
var out bytes.Buffer
err := runOut(&out, p.Dir, nil, "pkg-config", args...)
if err != nil {
return nil, nil, err
}
cflags := strings.Fields(out.String())
args = []string{
"--libs",
}
args = append(args, p.CgoPkgConfig...)
out.Reset()
err = runOut(&out, p.Dir, nil, "pkg-config", args...)
if err != nil {
return nil, nil, err
}
ldflags := strings.Fields(out.String())
return cflags, ldflags, nil
}
func quoteFlags(flags []string) []string {
quoted := make([]string, len(flags))
for i, f := range flags {
quoted[i] = strconv.Quote(f)
}
return quoted
}
// runcgo1 invokes the cgo tool to process pkg.CgoFiles.
func runcgo1(pkg *Package, cflags, ldflags []string) error {
cgo := cgotool(pkg.Context)
workdir := cgoworkdir(pkg)
if err := mkdir(workdir); err != nil {
return err
}
args := []string{"-objdir", workdir}
switch {
case gc14:
args = append(args,
"--",
"-I", pkg.Dir,
)
case gc15:
args = append(args,
"-importpath", pkg.ImportPath,
"--",
"-I", workdir,
"-I", pkg.Dir,
)
default:
return fmt.Errorf("unsupported Go version: %v", runtime.Version)
}
args = append(args, cflags...)
args = append(args, pkg.CgoFiles...)
cgoenv := []string{
"CGO_CFLAGS=" + strings.Join(quoteFlags(cflags), " "),
"CGO_LDFLAGS=" + strings.Join(quoteFlags(ldflags), " "),
}
var buf bytes.Buffer
err := runOut(&buf, pkg.Dir, cgoenv, cgo, args...)
if err != nil {
fmt.Fprintf(os.Stderr, "# %s\n", pkg.ImportPath)
io.Copy(os.Stderr, &buf)
}
return err
}
// runcgo2 invokes the cgo tool to create _cgo_import.go
func runcgo2(pkg *Package, dynout, ofile string) error {
cgo := cgotool(pkg.Context)
workdir := cgoworkdir(pkg)
args := []string{
"-objdir", workdir,
}
switch {
case gc14:
args = append(args,
"-dynimport", ofile,
"-dynout", dynout,
)
case gc15:
args = append(args,
"-dynpackage", pkg.Name,
"-dynimport", ofile,
"-dynout", dynout,
)
default:
return fmt.Errorf("unsuppored Go version: %v", runtime.Version)
}
var buf bytes.Buffer
err := runOut(&buf, pkg.Dir, nil, cgo, args...)
if err != nil {
fmt.Fprintf(os.Stderr, "# %s\n", pkg.ImportPath)
io.Copy(os.Stderr, &buf)
}
return err
}
// cgoworkdir returns the cgo working directory for this package.
func cgoworkdir(pkg *Package) string {
return filepath.Join(Workdir(pkg), pkgname(pkg), "_cgo")
}
// gccCmd returns a gcc command line prefix.
func gccCmd(pkg *Package, objdir string) []string {
return ccompilerCmd(pkg, "CC", defaultCC, objdir)
}
// gxxCmd returns a g++ command line prefix.
func gxxCmd(pkg *Package, objdir string) []string {
return ccompilerCmd(pkg, "CXX", defaultCXX, objdir)
}
// ccompilerCmd returns a command line prefix for the given environment
// variable and using the default command when the variable is empty.
func ccompilerCmd(pkg *Package, envvar, defcmd, objdir string) []string {
compiler := envList(envvar, defcmd)
a := []string{compiler[0]}
if objdir != "" {
a = append(a, "-I", objdir)
}
a = append(a, compiler[1:]...)
// Definitely want -fPIC but on Windows gcc complains
// "-fPIC ignored for target (all code is position independent)"
if pkg.gotargetos != "windows" {
a = append(a, "-fPIC")
}
a = append(a, gccArchArgs(pkg.gotargetarch)...)
// gcc-4.5 and beyond require explicit "-pthread" flag
// for multithreading with pthread library.
switch pkg.gotargetos {
case "windows":
a = append(a, "-mthreads")
default:
a = append(a, "-pthread")
}
if strings.Contains(a[0], "clang") {
// disable ASCII art in clang errors, if possible
a = append(a, "-fno-caret-diagnostics")
// clang is too smart about command-line arguments
a = append(a, "-Qunused-arguments")
}
// disable word wrapping in error messages
a = append(a, "-fmessage-length=0")
// On OS X, some of the compilers behave as if -fno-common
// is always set, and the Mach-O linker in 6l/8l assumes this.
// See https://golang.org/issue/3253.
if pkg.gotargetos == "darwin" {
a = append(a, "-fno-common")
}
return a
}
// gccArchArgs returns arguments to pass to gcc based on the architecture.
func gccArchArgs(goarch string) []string {
switch goarch {
case "386":
return []string{"-m32"}
case "amd64", "amd64p32":
return []string{"-m64"}
case "arm":
return []string{"-marm"} // not thumb
}
return nil
}
gb-0.3.2/cmd/ 0000775 0000000 0000000 00000000000 12625565062 0012660 5 ustar 00root root 0000000 0000000 gb-0.3.2/cmd/cmd.go 0000664 0000000 0000000 00000005124 12625565062 0013754 0 ustar 00root root 0000000 0000000 // Package command holds support functions and types for writing gb and gb plugins
package cmd
import (
"flag"
"fmt"
"os"
"path/filepath"
"github.com/constabulary/gb"
"github.com/constabulary/gb/debug"
)
// Command represents a subcommand, or plugin that is executed within
// a gb project.
type Command struct {
// Name of the command
Name string
// UsageLine demonstrates how to use this command
UsageLine string
// Single line description of the purpose of the command
Short string
// Description of this command
Long string
// Run is invoked with a Context derived from the Project and arguments
// left over after flag parsing.
Run func(ctx *gb.Context, args []string) error
// AddFlags installs additional flags to be parsed before Run.
AddFlags func(fs *flag.FlagSet)
// Allow plugins to modify arguments
FlagParse func(fs *flag.FlagSet, args []string) error
// ParseArgs provides an alternative method to parse arguments.
// By default, arguments will be parsed as import paths with
// ImportPaths
ParseArgs func(ctx *gb.Context, cwd string, args []string) []string
}
// Runnable indicates this is a command that can be involved.
// Non runnable commands are only informational.
func (c *Command) Runnable() bool { return c.Run != nil }
// Hidden indicates this is a command which is hidden from help / alldoc.go.
func (c *Command) Hidden() bool { return c.Name == "depset" }
// RunCommand detects the project root, parses flags and runs the Command.
func RunCommand(fs *flag.FlagSet, cmd *Command, projectroot, goroot string, args []string) error {
if cmd.AddFlags != nil {
cmd.AddFlags(fs)
}
if err := fs.Parse(args); err != nil {
fs.Usage()
os.Exit(1)
}
args = fs.Args() // reset to the remaining arguments
ctx, err := NewContext(projectroot, gb.GcToolchain())
if err != nil {
return fmt.Errorf("unable to construct context: %v", err)
}
defer ctx.Destroy()
debug.Debugf("args: %v", args)
return cmd.Run(ctx, args)
}
// NewContext creates a gb.Context for the project root.
func NewContext(projectroot string, options ...func(*gb.Context) error) (*gb.Context, error) {
if projectroot == "" {
return nil, fmt.Errorf("project root is blank")
}
root, err := FindProjectroot(projectroot)
if err != nil {
return nil, fmt.Errorf("could not locate project root: %v", err)
}
project := gb.NewProject(root,
gb.SourceDir(filepath.Join(root, "src")),
gb.SourceDir(filepath.Join(root, "vendor", "src")),
)
debug.Debugf("project root %q", project.Projectdir())
return project.NewContext(options...)
}
func mkdir(path string) error {
return os.MkdirAll(path, 0755)
}
gb-0.3.2/cmd/env.go 0000664 0000000 0000000 00000001125 12625565062 0013776 0 ustar 00root root 0000000 0000000 package cmd
import (
"fmt"
"log"
"os"
"strings"
)
func MustGetwd() string {
wd, err := os.Getwd()
if err != nil {
log.Fatalf("unable to determine current working directory: %v", err)
}
return wd
}
// MergeEnv merges args into env, overwriting entries.
func MergeEnv(env []string, args map[string]string) []string {
m := make(map[string]string)
for _, e := range env {
v := strings.SplitN(e, "=", 2)
m[v[0]] = v[1]
}
for k, v := range args {
m[k] = v
}
env = make([]string, 0, len(m))
for k, v := range m {
env = append(env, fmt.Sprintf("%s=%s", k, v))
}
return env
}
gb-0.3.2/cmd/env_test.go 0000664 0000000 0000000 00000001551 12625565062 0015040 0 ustar 00root root 0000000 0000000 package cmd
import "testing"
func TestMergeEnv(t *testing.T) {
envTests := []struct {
env []string
args map[string]string
want []string
}{
{
env: nil,
args: nil,
want: nil,
},
{
env: []string{`FOO=BAR`, `BAZ="QUXX"`},
args: nil,
want: []string{`FOO=BAR`, `BAZ="QUXX"`},
},
{
env: []string{`FOO=BAR`, `BAZ="QUXX"`},
args: map[string]string{"BLORT": "false", "BAZ": "QUXX"},
want: []string{`FOO=BAR`, `BAZ=QUXX`, `BLORT=false`},
},
}
for _, tt := range envTests {
got := MergeEnv(tt.env, tt.args)
compare(t, tt.want, got)
}
}
func compare(t *testing.T, want, got []string) {
w, g := set(want), set(got)
for k := range w {
if w[k] != g[k] {
t.Errorf("want %v, got %v", k, g[k])
}
}
}
func set(v []string) map[string]bool {
m := make(map[string]bool)
for _, s := range v {
m[s] = true
}
return m
}
gb-0.3.2/cmd/gb-vendor/ 0000775 0000000 0000000 00000000000 12625565062 0014543 5 ustar 00root root 0000000 0000000 gb-0.3.2/cmd/gb-vendor/alldocs.go 0000664 0000000 0000000 00000006234 12625565062 0016520 0 ustar 00root root 0000000 0000000 // DO NOT EDIT THIS FILE.
//go:generate gb vendor help documentation
/*
gb-vendor, a gb plugin to manage your vendored dependencies.
Usage:
gb vendor command [arguments]
The commands are:
fetch fetch a remote dependency
update update a local dependency
list lists dependencies, one per line
delete deletes a local dependency
purge purges all unreferenced dependencies
restore restore dependencies from the manifest
Use "gb vendor help [command]" for more information about a command.
Additional help topics:
Use "gb vendor help [topic]" for more information about that topic.
Fetch a remote dependency
Usage:
gb vendor fetch [-branch branch | -revision rev | -tag tag] [-precaire] [-no-recurse] importpath
fetch vendors an upstream import path.
The import path may include a url scheme. This may be useful when fetching dependencies
from private repositories that cannot be probed.
Flags:
-branch branch
fetch from the name branch. If not supplied the default upstream
branch will be used.
-no-recurse
do not fetch recursively.
-tag tag
fetch the specified tag. If not supplied the default upstream
branch will be used.
-revision rev
fetch the specific revision from the branch (if supplied). If no
revision supplied, the latest available will be supplied.
-precaire
allow the use of insecure protocols.
Update a local dependency
Usage:
gb vendor update [-all] import
gb vendor update will replaces the source with the latest available from the head of the master branch.
Updating from one copy of a dependency to another comes with several restrictions.
The first is you can only update to the head of the branch your dependency was vendered from, switching branches is not supported.
The second restriction is if you have used -tag or -revision while vendoring a dependency, your dependency is "headless"
(to borrow a term from git) and cannot be updated.
To update across branches, or from one tag/revision to another, you must first use gb vendor delete to remove the dependency, then
gb vendor fetch [-tag | -revision | -branch ] [-precaire] to replace it.
Flags:
-all
will update all dependencies in the manifest, otherwise only the dependency supplied.
-precaire
allow the use of insecure protocols.
Lists dependencies, one per line
Usage:
gb vendor list [-f format]
gb vendor list formats lists the contents of the manifest file.
The output
Flags:
-f
controls the template used for printing each manifest entry. If not supplied
the default value is "{{.Importpath}}\t{{.Repository}}{{.Path}}\t{{.Branch}}\t{{.Revision}}"
Deletes a local dependency
Usage:
gb vendor delete [-all] importpath
delete removes a dependency from $PROJECT/vendor/src and the vendor manifest
Flags:
-all
remove all dependencies
Purges all unreferenced dependencies
Usage:
gb vendor purge
gb vendor purge will remove all unreferenced dependencies
Restore dependencies from the manifest
Usage:
gb vendor restore [-precaire]
Restore vendor dependecies.
Flags:
-precaire
allow the use of insecure protocols.
*/
package main
gb-0.3.2/cmd/gb-vendor/delete.go 0000664 0000000 0000000 00000003715 12625565062 0016342 0 ustar 00root root 0000000 0000000 package main
import (
"flag"
"fmt"
"path/filepath"
"github.com/constabulary/gb"
"github.com/constabulary/gb/cmd"
"github.com/constabulary/gb/fileutils"
"github.com/constabulary/gb/vendor"
)
var (
// gb vendor delete flags
// delete all dependencies
deleteAll bool
)
func addDeleteFlags(fs *flag.FlagSet) {
fs.BoolVar(&deleteAll, "all", false, "delete all dependencies")
}
var cmdDelete = &cmd.Command{
Name: "delete",
UsageLine: "delete [-all] importpath",
Short: "deletes a local dependency",
Long: `delete removes a dependency from $PROJECT/vendor/src and the vendor manifest
Flags:
-all
remove all dependencies
`,
Run: func(ctx *gb.Context, args []string) error {
if len(args) != 1 && !deleteAll {
return fmt.Errorf("delete: import path or --all flag is missing")
} else if len(args) == 1 && deleteAll {
return fmt.Errorf("delete: you cannot specify path and --all flag at once")
}
m, err := vendor.ReadManifest(manifestFile(ctx))
if err != nil {
return fmt.Errorf("could not load manifest: %v", err)
}
var dependencies []vendor.Dependency
if deleteAll {
dependencies = make([]vendor.Dependency, len(m.Dependencies))
copy(dependencies, m.Dependencies)
} else {
p := args[0]
dependency, err := m.GetDependencyForImportpath(p)
if err != nil {
return fmt.Errorf("could not get dependency: %v", err)
}
dependencies = append(dependencies, dependency)
}
for _, d := range dependencies {
path := d.Importpath
if err := m.RemoveDependency(d); err != nil {
return fmt.Errorf("dependency could not be deleted: %v", err)
}
if err := fileutils.RemoveAll(filepath.Join(ctx.Projectdir(), "vendor", "src", filepath.FromSlash(path))); err != nil {
// TODO(dfc) need to apply vendor.cleanpath here to remove indermediate directories.
return fmt.Errorf("dependency could not be deleted: %v", err)
}
}
return vendor.WriteManifest(manifestFile(ctx), m)
},
AddFlags: addDeleteFlags,
}
gb-0.3.2/cmd/gb-vendor/fetch.go 0000664 0000000 0000000 00000014347 12625565062 0016174 0 ustar 00root root 0000000 0000000 package main
import (
"flag"
"fmt"
"net/url"
"path/filepath"
"runtime"
"sort"
"go/build"
"github.com/constabulary/gb"
"github.com/constabulary/gb/cmd"
"github.com/constabulary/gb/vendor"
)
var (
// gb vendor fetch command flags
branch string
// revision (commit)
revision string
tag string
noRecurse bool // Container variable to house the value of the no-recurse flag.
recurse bool // should we fetch recursively
insecure bool // Allow the use of insecure protocols
)
func addFetchFlags(fs *flag.FlagSet) {
fs.StringVar(&branch, "branch", "", "branch of the package")
fs.StringVar(&revision, "revision", "", "revision of the package")
fs.StringVar(&tag, "tag", "", "tag of the package")
fs.BoolVar(&noRecurse, "no-recurse", false, "do not fetch recursively")
fs.BoolVar(&insecure, "precaire", false, "allow the use of insecure protocols")
}
var cmdFetch = &cmd.Command{
Name: "fetch",
UsageLine: "fetch [-branch branch | -revision rev | -tag tag] [-precaire] [-no-recurse] importpath",
Short: "fetch a remote dependency",
Long: `fetch vendors an upstream import path.
The import path may include a url scheme. This may be useful when fetching dependencies
from private repositories that cannot be probed.
Flags:
-branch branch
fetch from the name branch. If not supplied the default upstream
branch will be used.
-no-recurse
do not fetch recursively.
-tag tag
fetch the specified tag. If not supplied the default upstream
branch will be used.
-revision rev
fetch the specific revision from the branch (if supplied). If no
revision supplied, the latest available will be supplied.
-precaire
allow the use of insecure protocols.
`,
Run: func(ctx *gb.Context, args []string) error {
switch len(args) {
case 0:
return fmt.Errorf("fetch: import path missing")
case 1:
path := args[0]
recurse = !noRecurse
return fetch(ctx, path, recurse)
default:
return fmt.Errorf("more than one import path supplied")
}
},
AddFlags: addFetchFlags,
}
func fetch(ctx *gb.Context, path string, recurse bool) error {
m, err := vendor.ReadManifest(manifestFile(ctx))
if err != nil {
return fmt.Errorf("could not load manifest: %v", err)
}
repo, extra, err := vendor.DeduceRemoteRepo(path, insecure)
if err != nil {
return err
}
// strip of any scheme portion from the path, it is already
// encoded in the repo.
path = stripscheme(path)
if m.HasImportpath(path) {
return fmt.Errorf("%s is already vendored", path)
}
wc, err := repo.Checkout(branch, tag, revision)
if err != nil {
return err
}
rev, err := wc.Revision()
if err != nil {
return err
}
branch, err := wc.Branch()
if err != nil {
return err
}
dep := vendor.Dependency{
Importpath: path,
Repository: repo.URL(),
Revision: rev,
Branch: branch,
Path: extra,
}
if err := m.AddDependency(dep); err != nil {
return err
}
dst := filepath.Join(ctx.Projectdir(), "vendor", "src", dep.Importpath)
src := filepath.Join(wc.Dir(), dep.Path)
if err := vendor.Copypath(dst, src); err != nil {
return err
}
if err := vendor.WriteManifest(manifestFile(ctx), m); err != nil {
return err
}
if err := wc.Destroy(); err != nil {
return err
}
if !recurse {
return nil
}
// if we are recursing, overwrite branch, tag and revision
// values so recursive fetching checks out from HEAD.
branch = ""
tag = ""
revision = ""
for done := false; !done; {
paths := []struct {
Root, Prefix string
}{
{filepath.Join(runtime.GOROOT(), "src"), ""},
{filepath.Join(ctx.Projectdir(), "src"), ""},
}
m, err := vendor.ReadManifest(manifestFile(ctx))
if err != nil {
return err
}
for _, d := range m.Dependencies {
paths = append(paths, struct{ Root, Prefix string }{filepath.Join(ctx.Projectdir(), "vendor", "src", filepath.FromSlash(d.Importpath)), filepath.FromSlash(d.Importpath)})
}
dsm, err := vendor.LoadPaths(paths...)
if err != nil {
return err
}
is, ok := dsm[filepath.Join(ctx.Projectdir(), "vendor", "src", path)]
if !ok {
return fmt.Errorf("unable to locate depset for %q", path)
}
missing := findMissing(pkgs(is.Pkgs), dsm)
switch len(missing) {
case 0:
done = true
default:
// sort keys in ascending order, so the shortest missing import path
// with be fetched first.
keys := keys(missing)
sort.Strings(keys)
pkg := keys[0]
fmt.Println("fetching recursive dependency", pkg)
if err := fetch(ctx, pkg, false); err != nil {
return err
}
}
}
return nil
}
func keys(m map[string]bool) []string {
var s []string
for k := range m {
s = append(s, k)
}
return s
}
func pkgs(m map[string]*vendor.Pkg) []*vendor.Pkg {
var p []*vendor.Pkg
for _, v := range m {
p = append(p, v)
}
return p
}
func findMissing(pkgs []*vendor.Pkg, dsm map[string]*vendor.Depset) map[string]bool {
missing := make(map[string]bool)
imports := make(map[string]*vendor.Pkg)
for _, s := range dsm {
for _, p := range s.Pkgs {
imports[p.ImportPath] = p
}
}
// make fake C package for cgo
imports["C"] = &vendor.Pkg{
Depset: nil, // probably a bad idea
Package: &build.Package{
Name: "C",
},
}
stk := make(map[string]bool)
push := func(v string) {
if stk[v] {
panic(fmt.Sprintln("import loop:", v, stk))
}
stk[v] = true
}
pop := func(v string) {
if !stk[v] {
panic(fmt.Sprintln("impossible pop:", v, stk))
}
delete(stk, v)
}
// checked records import paths who's dependencies are all present
checked := make(map[string]bool)
var fn func(string)
fn = func(importpath string) {
p, ok := imports[importpath]
if !ok {
missing[importpath] = true
return
}
// have we already walked this arm, if so, skip it
if checked[importpath] {
return
}
sz := len(missing)
push(importpath)
for _, i := range p.Imports {
if i == importpath {
continue
}
fn(i)
}
// if the size of the missing map has not changed
// this entire subtree is complete, mark it as such
if len(missing) == sz {
checked[importpath] = true
}
pop(importpath)
}
for _, pkg := range pkgs {
fn(pkg.ImportPath)
}
return missing
}
// stripscheme removes any scheme components from url like paths.
func stripscheme(path string) string {
u, err := url.Parse(path)
if err != nil {
panic(err)
}
return u.Host + u.Path
}
gb-0.3.2/cmd/gb-vendor/help.go 0000664 0000000 0000000 00000004675 12625565062 0016036 0 ustar 00root root 0000000 0000000 package main
import (
"bufio"
"bytes"
"fmt"
"io"
"os"
"strings"
"text/template"
"unicode"
"unicode/utf8"
"github.com/constabulary/gb/cmd"
)
var helpTemplate = `{{if .Runnable}}usage: gb vendor {{.UsageLine}}
{{end}}{{.Long | trim}}
`
// help implements the 'help' command.
func help(args []string) {
if len(args) == 0 {
printUsage(os.Stdout)
return
}
if len(args) != 1 {
fmt.Fprintf(os.Stderr, "usage: gb vendor help command\n\nToo many arguments given.\n")
os.Exit(2)
}
arg := args[0]
// 'gb vendor help documentation' generates alldocs.go.
if arg == "documentation" {
var buf bytes.Buffer
printUsage(&buf)
usage := &cmd.Command{Long: buf.String()}
f, _ := os.Create("alldocs.go")
tmpl(f, documentationTemplate, append([]*cmd.Command{usage}, commands...))
f.Close()
return
}
for _, cmd := range commands {
if cmd.Name == arg {
tmpl(os.Stdout, helpTemplate, cmd)
// not exit 2: succeeded at 'gb help cmd'.
return
}
}
fmt.Fprintf(os.Stderr, "Unknown help topic %#q. Run 'gb help'.\n", arg)
os.Exit(2) // failed at 'gb help cmd'
}
var usageTemplate = `gb-vendor, a gb plugin to manage your vendored dependencies.
Usage:
gb vendor command [arguments]
The commands are:
{{range .}}{{if .Runnable}}
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
Use "gb vendor help [command]" for more information about a command.
Additional help topics:
{{range .}}{{if not .Runnable}}
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
Use "gb vendor help [topic]" for more information about that topic.
`
var documentationTemplate = `// DO NOT EDIT THIS FILE.
//go:generate gb vendor help documentation
/*
{{range .}}{{if .Short}}{{.Short | capitalize}}
{{end}}{{if .Runnable}}Usage:
gb vendor {{.UsageLine}}
{{end}}{{.Long | trim}}
{{end}}*/
package main
`
// tmpl executes the given template text on data, writing the result to w.
func tmpl(w io.Writer, text string, data interface{}) {
t := template.New("top")
t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize})
template.Must(t.Parse(text))
if err := t.Execute(w, data); err != nil {
panic(err)
}
}
func capitalize(s string) string {
if s == "" {
return s
}
r, n := utf8.DecodeRuneInString(s)
return string(unicode.ToTitle(r)) + s[n:]
}
func printUsage(w io.Writer) {
bw := bufio.NewWriter(w)
tmpl(bw, usageTemplate, commands)
bw.Flush()
}
func usage() {
printUsage(os.Stderr)
os.Exit(2)
}
gb-0.3.2/cmd/gb-vendor/list.go 0000664 0000000 0000000 00000002500 12625565062 0016042 0 ustar 00root root 0000000 0000000 package main
import (
"flag"
"fmt"
"html/template"
"os"
"text/tabwriter"
"github.com/constabulary/gb"
"github.com/constabulary/gb/cmd"
"github.com/constabulary/gb/vendor"
)
var format string
var cmdList = &cmd.Command{
Name: "list",
UsageLine: "list [-f format]",
Short: "lists dependencies, one per line",
Long: `gb vendor list formats lists the contents of the manifest file.
The output
Flags:
-f
controls the template used for printing each manifest entry. If not supplied
the default value is "{{.Importpath}}\t{{.Repository}}{{.Path}}\t{{.Branch}}\t{{.Revision}}"
`,
Run: func(ctx *gb.Context, args []string) error {
m, err := vendor.ReadManifest(manifestFile(ctx))
if err != nil {
return fmt.Errorf("could not load manifest: %v", err)
}
tmpl, err := template.New("list").Parse(format)
if err != nil {
return fmt.Errorf("unable to parse template %q: %v", format, err)
}
w := tabwriter.NewWriter(os.Stdout, 1, 2, 1, ' ', 0)
for _, dep := range m.Dependencies {
if err := tmpl.Execute(w, dep); err != nil {
return fmt.Errorf("unable to execute template: %v", err)
}
fmt.Fprintln(w)
}
return w.Flush()
},
AddFlags: func(fs *flag.FlagSet) {
fs.StringVar(&format, "f", "{{.Importpath}}\t{{.Repository}}{{.Path}}\t{{.Branch}}\t{{.Revision}}", "format template")
},
}
gb-0.3.2/cmd/gb-vendor/main.go 0000664 0000000 0000000 00000004132 12625565062 0016016 0 ustar 00root root 0000000 0000000 package main
import (
"flag"
"fmt"
"os"
"path/filepath"
"github.com/constabulary/gb"
"github.com/constabulary/gb/cmd"
"github.com/constabulary/gb/debug"
)
var (
fs = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
projectroot = os.Getenv("GB_PROJECT_DIR")
args []string
)
func init() {
fs.Usage = usage
}
var commands = []*cmd.Command{
cmdFetch,
cmdUpdate,
cmdList,
cmdDelete,
cmdPurge,
cmdRestore,
}
func main() {
fatalf := func(format string, args ...interface{}) {
fmt.Fprintf(os.Stderr, "FATAL: "+format+"\n", args...)
os.Exit(1)
}
args := os.Args[1:]
switch {
case len(args) < 1, args[0] == "-h", args[0] == "-help":
printUsage(os.Stdout)
os.Exit(0)
case args[0] == "help":
help(args[1:])
return
case projectroot == "":
fatalf("don't run this binary directly, it is meant to be run as 'gb vendor ...'")
default:
}
root, err := cmd.FindProjectroot(projectroot)
if err != nil {
fatalf("could not locate project root: %v", err)
}
project := gb.NewProject(root,
gb.SourceDir(filepath.Join(root, "src")),
gb.SourceDir(filepath.Join(root, "vendor", "src")),
)
debug.Debugf("project root %q", project.Projectdir())
for _, command := range commands {
if command.Name == args[0] && command.Runnable() {
// add extra flags if necessary
if command.AddFlags != nil {
command.AddFlags(fs)
}
if command.FlagParse != nil {
err = command.FlagParse(fs, args)
} else {
err = fs.Parse(args[1:])
}
if err != nil {
fatalf("could not parse flags: %v", err)
}
args = fs.Args() // reset args to the leftovers from fs.Parse
debug.Debugf("args: %v", args)
ctx, err := project.NewContext(
gb.GcToolchain(),
)
if err != nil {
fatalf("unable to construct context: %v", err)
}
defer ctx.Destroy()
if err := command.Run(ctx, args); err != nil {
fatalf("command %q failed: %v", command.Name, err)
}
return
}
}
fatalf("unknown command %q ", args[0])
}
const manifestfile = "manifest"
func manifestFile(ctx *gb.Context) string {
return filepath.Join(ctx.Projectdir(), "vendor", manifestfile)
}
gb-0.3.2/cmd/gb-vendor/purge.go 0000664 0000000 0000000 00000003240 12625565062 0016213 0 ustar 00root root 0000000 0000000 package main
import (
"fmt"
"path/filepath"
"strings"
"github.com/constabulary/gb"
"github.com/constabulary/gb/cmd"
"github.com/constabulary/gb/fileutils"
"github.com/constabulary/gb/vendor"
)
var cmdPurge = &cmd.Command{
Name: "purge",
UsageLine: "purge",
Short: "purges all unreferenced dependencies",
Long: `gb vendor purge will remove all unreferenced dependencies
`,
Run: func(ctx *gb.Context, args []string) error {
m, err := vendor.ReadManifest(manifestFile(ctx))
if err != nil {
return fmt.Errorf("could not load manifest: %v", err)
}
imports, err := vendor.ParseImports(ctx.Projectdir())
if err != nil {
return fmt.Errorf("import could not be parsed: %v", err)
}
var hasImportWithPrefix = func(d string) bool {
for i := range imports {
if strings.HasPrefix(i, d) {
return true
}
}
return false
}
dependencies := make([]vendor.Dependency, len(m.Dependencies))
copy(dependencies, m.Dependencies)
for _, d := range dependencies {
if !hasImportWithPrefix(d.Importpath) {
dep, err := m.GetDependencyForImportpath(d.Importpath)
if err != nil {
return fmt.Errorf("could not get get dependency: %v", err)
}
if err := m.RemoveDependency(dep); err != nil {
return fmt.Errorf("dependency could not be removed: %v", err)
}
if err := fileutils.RemoveAll(filepath.Join(ctx.Projectdir(), "vendor", "src", filepath.FromSlash(d.Importpath))); err != nil {
// TODO(dfc) need to apply vendor.cleanpath here to remove indermediate directories.
return fmt.Errorf("dependency could not be deleted: %v", err)
}
}
}
return vendor.WriteManifest(manifestFile(ctx), m)
},
}
gb-0.3.2/cmd/gb-vendor/restore.go 0000664 0000000 0000000 00000002630 12625565062 0016556 0 ustar 00root root 0000000 0000000 package main
import (
"flag"
"fmt"
"path/filepath"
"github.com/constabulary/gb"
"github.com/constabulary/gb/cmd"
"github.com/constabulary/gb/vendor"
)
func addRestoreFlags(fs *flag.FlagSet) {
fs.BoolVar(&insecure, "precaire", false, "allow the use of insecure protocols")
}
var cmdRestore = &cmd.Command{
Name: "restore",
UsageLine: "restore [-precaire]",
Short: "restore dependencies from the manifest",
Long: `Restore vendor dependecies.
Flags:
-precaire
allow the use of insecure protocols.
`,
Run: func(ctx *gb.Context, args []string) error {
return restore(ctx)
},
AddFlags: addRestoreFlags,
}
func restore(ctx *gb.Context) error {
m, err := vendor.ReadManifest(manifestFile(ctx))
if err != nil {
return fmt.Errorf("could not load manifest: %v", err)
}
for _, dep := range m.Dependencies {
fmt.Printf("Getting %s\n", dep.Importpath)
repo, _, err := vendor.DeduceRemoteRepo(dep.Importpath, insecure)
if err != nil {
return fmt.Errorf("Could not process dependency: %s", err)
}
wc, err := repo.Checkout("", "", dep.Revision)
if err != nil {
return fmt.Errorf("Could not retrieve dependency: %s", err)
}
dst := filepath.Join(ctx.Projectdir(), "vendor", "src", dep.Importpath)
src := filepath.Join(wc.Dir(), dep.Path)
if err := vendor.Copypath(dst, src); err != nil {
return err
}
if err := wc.Destroy(); err != nil {
return err
}
}
return nil
}
gb-0.3.2/cmd/gb-vendor/update.go 0000664 0000000 0000000 00000007265 12625565062 0016366 0 ustar 00root root 0000000 0000000 package main
import (
"flag"
"fmt"
"path/filepath"
"github.com/constabulary/gb"
"github.com/constabulary/gb/cmd"
"github.com/constabulary/gb/fileutils"
"github.com/constabulary/gb/vendor"
)
var (
// gb vendor update flags
// update all dependencies
updateAll bool
)
func addUpdateFlags(fs *flag.FlagSet) {
fs.BoolVar(&updateAll, "all", false, "update all dependencies")
fs.BoolVar(&insecure, "precaire", false, "allow the use of insecure protocols")
}
var cmdUpdate = &cmd.Command{
Name: "update",
UsageLine: "update [-all] import",
Short: "update a local dependency",
Long: `gb vendor update will replaces the source with the latest available from the head of the master branch.
Updating from one copy of a dependency to another comes with several restrictions.
The first is you can only update to the head of the branch your dependency was vendered from, switching branches is not supported.
The second restriction is if you have used -tag or -revision while vendoring a dependency, your dependency is "headless"
(to borrow a term from git) and cannot be updated.
To update across branches, or from one tag/revision to another, you must first use gb vendor delete to remove the dependency, then
gb vendor fetch [-tag | -revision | -branch ] [-precaire] to replace it.
Flags:
-all
will update all dependencies in the manifest, otherwise only the dependency supplied.
-precaire
allow the use of insecure protocols.
`,
Run: func(ctx *gb.Context, args []string) error {
if len(args) != 1 && !updateAll {
return fmt.Errorf("update: import path or --all flag is missing")
} else if len(args) == 1 && updateAll {
return fmt.Errorf("update: you cannot specify path and --all flag at once")
}
m, err := vendor.ReadManifest(manifestFile(ctx))
if err != nil {
return fmt.Errorf("could not load manifest: %v", err)
}
var dependencies []vendor.Dependency
if updateAll {
dependencies = make([]vendor.Dependency, len(m.Dependencies))
copy(dependencies, m.Dependencies)
} else {
p := args[0]
dependency, err := m.GetDependencyForImportpath(p)
if err != nil {
return fmt.Errorf("could not get dependency: %v", err)
}
dependencies = append(dependencies, dependency)
}
for _, d := range dependencies {
err = m.RemoveDependency(d)
if err != nil {
return fmt.Errorf("dependency could not be deleted from manifest: %v", err)
}
repo, extra, err := vendor.DeduceRemoteRepo(d.Importpath, insecure)
if err != nil {
return fmt.Errorf("could not determine repository for import %q", d.Importpath)
}
wc, err := repo.Checkout(d.Branch, "", "")
if err != nil {
return err
}
rev, err := wc.Revision()
if err != nil {
return err
}
branch, err := wc.Branch()
if err != nil {
return err
}
dep := vendor.Dependency{
Importpath: d.Importpath,
Repository: repo.URL(),
Revision: rev,
Branch: branch,
Path: extra,
}
if err := fileutils.RemoveAll(filepath.Join(ctx.Projectdir(), "vendor", "src", filepath.FromSlash(d.Importpath))); err != nil {
// TODO(dfc) need to apply vendor.cleanpath here to remove indermediate directories.
return fmt.Errorf("dependency could not be deleted: %v", err)
}
dst := filepath.Join(ctx.Projectdir(), "vendor", "src", filepath.FromSlash(dep.Importpath))
src := filepath.Join(wc.Dir(), dep.Path)
if err := vendor.Copypath(dst, src); err != nil {
return err
}
if err := m.AddDependency(dep); err != nil {
return err
}
if err := vendor.WriteManifest(manifestFile(ctx), m); err != nil {
return err
}
if err := wc.Destroy(); err != nil {
return err
}
}
return nil
},
AddFlags: addUpdateFlags,
}
gb-0.3.2/cmd/gb/ 0000775 0000000 0000000 00000000000 12625565062 0013250 5 ustar 00root root 0000000 0000000 gb-0.3.2/cmd/gb/alldocs.go 0000664 0000000 0000000 00000012023 12625565062 0015216 0 ustar 00root root 0000000 0000000 // DO NOT EDIT THIS FILE.
//go:generate gb help documentation
/*
gb, a project based build tool for the Go programming language.
Usage:
gb command [arguments]
The commands are:
build build a package
doc show documentation for a package or symbol
env print project environment variables
generate generate Go files by processing source
info info returns information about this project
list list the packages named by the importpaths
test test packages
Use "gb help [command]" for more information about a command.
Additional help topics:
plugin plugin information
project gb project layout
Use "gb help [topic]" for more information about that topic.
Build a package
Usage:
gb build [build flags] [packages]
Build compiles the packages named by the import paths, along with their
dependencies.
Flags:
-f
ignore cached packages if present, new packages built will overwrite
any cached packages. This effectively disables incremental
compilation.
-F
do not cache packages, cached packages will still be used for
incremental compilation. -f -F is advised to disable the package
caching system.
-q
decreases verbosity, effectively raising the output level to ERROR.
In a successful build, no output will be displayed.
-P
The number of build jobs to run in parallel, including test execution.
By default this is the number of CPUs visible to gb.
-R
sets the base of the project root search path from the current working
directory to the value supplied. Effectively gb changes working
directory to this path before searching for the project root.
-dotfile
if provided, gb will output a dot formatted file of the build steps to
be performed.
-ldflags 'flag list'
arguments to pass on each linker invocation.
-gcflags 'arg list'
arguments to pass on each compile invocation.
-tags 'tag list'
additional build tags.
The list flags accept a space-separated list of strings. To embed spaces in an
element in the list, surround it with either single or double quotes.
For more about where packages and binaries are installed, run 'gb help project'.
Show documentation for a package or symbol
Usage:
gb doc [.]
Doc shows documentation for a package or symbol.
See 'go help doc'.
Print project environment variables
Usage:
gb env
Env prints project environment variables.
Generate Go files by processing source
Usage:
gb generate [-run regexp] [file.go... | packages]
Generate runs commands described by directives within existing files.
Those commands can run any process, but the intent is to create or update Go
source files, for instance by running yacc.
See 'go help generate'.
Info returns information about this project
Usage:
gb info
info returns information about this project.
info returns 0 if the project is well formed, and non zero otherwise.
List the packages named by the importpaths
Usage:
gb list [-s] [-f format] [-json] [packages]
List lists packages imported by the project.
The default output shows the package import paths:
% gb list github.com/constabulary/...
github.com/constabulary/gb
github.com/constabulary/gb/cmd
github.com/constabulary/gb/cmd/gb
github.com/constabulary/gb/cmd/gb-env
github.com/constabulary/gb/cmd/gb-list
Flags:
-f
alternate format for the list, using the syntax of package template.
The default output is equivalent to -f '{{.ImportPath}}'. The struct
being passed to the template is currently an instance of gb.Package.
This structure is under active development and it's contents are not
guaranteed to be stable.
-s
read format template from STDIN.
-json
prints output in structured JSON format. WARNING: gb.Package
structure is not stable and will change in the future!
Plugin information
gb supports git style plugins.
A gb plugin is anything in the $PATH with the prefix gb-. In other words
gb-something, becomes gb something.
gb plugins are executed from the parent gb process with the environment
variable, GB_PROJECT_DIR set to the root of the current project.
gb plugins can be executed directly but this is rarely useful, so authors
should attempt to diagnose this by looking for the presence of the
GB_PROJECT_DIR environment key.
Gb project layout
A gb project is defined as any directory that contains a src/ subdirectory.
gb automatically detects the root of the project by looking at the current
working directory and walking backwards until it finds a directory that
contains a src/ subdirectory.
In the event you wish to override this auto detection mechanism, the -R flag
can be used to supply a project root.
See http://getgb.io/docs/project for details
Test packages
Usage:
gb test [build flags] [packages] [flags for test binary]
Test automates testing the packages named by the import paths.
'gb test' recompiles each package along with any files with names matching
the file pattern "*_test.go".
See 'go help test'.
*/
package main
gb-0.3.2/cmd/gb/build.go 0000664 0000000 0000000 00000006447 12625565062 0014711 0 ustar 00root root 0000000 0000000 package main
import (
"flag"
"os"
"runtime"
"github.com/constabulary/gb"
"github.com/constabulary/gb/cmd"
)
func init() {
registerCommand(BuildCmd)
}
var (
// build flags
// should we build all packages in this project.
// defaults to true when build is invoked from the project root.
A bool
// should we perform a release build +release tag ?
// defaults to false, +debug.
R bool
// force rebuild of packages
F bool
// skip caching of packages
FF bool
ldflags, gcflags []string
P int // number of executors to run in parallel
dotfile string // path to dot output file
buildtags []string
)
func addBuildFlags(fs *flag.FlagSet) {
// TODO(dfc) this should accept a *gb.Context
fs.BoolVar(&A, "a", false, "build all packages in this project")
fs.BoolVar(&R, "r", false, "perform a release build")
fs.BoolVar(&F, "f", false, "rebuild up-to-date packages")
fs.BoolVar(&FF, "F", false, "do not cache built packages")
fs.IntVar(&P, "P", runtime.NumCPU(), "number of parallel jobs")
fs.Var((*stringsFlag)(&ldflags), "ldflags", "flags passed to the linker")
fs.Var((*stringsFlag)(&gcflags), "gcflags", "flags passed to the compiler")
fs.StringVar(&dotfile, "dotfile", "", "path to dot output file")
fs.Var((*stringsFlag)(&buildtags), "tags", "")
}
var BuildCmd = &cmd.Command{
Name: "build",
Short: "build a package",
UsageLine: "build [build flags] [packages]",
Long: `
Build compiles the packages named by the import paths, along with their
dependencies.
Flags:
-f
ignore cached packages if present, new packages built will overwrite
any cached packages. This effectively disables incremental
compilation.
-F
do not cache packages, cached packages will still be used for
incremental compilation. -f -F is advised to disable the package
caching system.
-q
decreases verbosity, effectively raising the output level to ERROR.
In a successful build, no output will be displayed.
-P
The number of build jobs to run in parallel, including test execution.
By default this is the number of CPUs visible to gb.
-R
sets the base of the project root search path from the current working
directory to the value supplied. Effectively gb changes working
directory to this path before searching for the project root.
-dotfile
if provided, gb will output a dot formatted file of the build steps to
be performed.
-ldflags 'flag list'
arguments to pass on each linker invocation.
-gcflags 'arg list'
arguments to pass on each compile invocation.
-tags 'tag list'
additional build tags.
The list flags accept a space-separated list of strings. To embed spaces in an
element in the list, surround it with either single or double quotes.
For more about where packages and binaries are installed, run 'gb help project'.
`,
Run: func(ctx *gb.Context, args []string) error {
// TODO(dfc) run should take a *gb.Context not a *gb.Project
ctx.Force = F
ctx.SkipInstall = FF
pkgs, err := gb.ResolvePackages(ctx, args...)
if err != nil {
return err
}
build, err := gb.BuildPackages(pkgs...)
if err != nil {
return err
}
if dotfile != "" {
f, err := os.Create(dotfile)
if err != nil {
return err
}
defer f.Close()
printActions(f, build)
}
startSigHandlers()
return gb.ExecuteConcurrent(build, P, interrupted)
},
AddFlags: addBuildFlags,
}
gb-0.3.2/cmd/gb/depset.go 0000664 0000000 0000000 00000010642 12625565062 0015066 0 ustar 00root root 0000000 0000000 package main
import (
"fmt"
"go/build"
"path/filepath"
"runtime"
"github.com/constabulary/gb"
"github.com/constabulary/gb/cmd"
"github.com/constabulary/gb/vendor"
)
func init() {
registerCommand(&cmd.Command{
Name: "depset",
Run: depset,
})
}
func depset(ctx *gb.Context, args []string) error {
paths := []struct {
Root, Prefix string
}{
{filepath.Join(runtime.GOROOT(), "src"), ""},
{filepath.Join(ctx.Projectdir(), "src"), ""},
}
m, err := vendor.ReadManifest(filepath.Join("vendor", "manifest"))
if err != nil {
return err
}
for _, d := range m.Dependencies {
paths = append(paths, struct{ Root, Prefix string }{filepath.Join(ctx.Projectdir(), "vendor", "src", filepath.FromSlash(d.Importpath)), filepath.FromSlash(d.Importpath)})
}
dsm, err := vendor.LoadPaths(paths...)
if err != nil {
return err
}
for _, set := range dsm {
fmt.Printf("%s (%s)\n", set.Root, set.Prefix)
for _, p := range set.Pkgs {
fmt.Printf("\t%s (%s)\n", p.ImportPath, p.Name)
fmt.Printf("\t\timports: %s\n", p.Imports)
}
}
root := paths[1] // $PROJECT/src
rs := dsm[root.Root].Pkgs
fmt.Println("missing:")
for missing := range findMissing(pkgs(rs), dsm) {
fmt.Printf("\t%s\n", missing)
}
fmt.Println("orphaned:")
for orphan := range findOrphaned(pkgs(rs), dsm) {
fmt.Printf("\t%s\n", orphan)
}
return nil
}
func keys(m map[string]bool) []string {
var s []string
for k := range m {
s = append(s, k)
}
return s
}
func pkgs(m map[string]*vendor.Pkg) []*vendor.Pkg {
var p []*vendor.Pkg
for _, v := range m {
p = append(p, v)
}
return p
}
func findMissing(pkgs []*vendor.Pkg, dsm map[string]*vendor.Depset) map[string]bool {
missing := make(map[string]bool)
imports := make(map[string]*vendor.Pkg)
for _, s := range dsm {
for _, p := range s.Pkgs {
imports[p.ImportPath] = p
}
}
// make fake C package for cgo
imports["C"] = &vendor.Pkg{
Depset: nil, // probably a bad idea
Package: &build.Package{
Name: "C",
},
}
stk := make(map[string]bool)
push := func(v string) {
if stk[v] {
panic(fmt.Sprintln("import loop:", v, stk))
}
stk[v] = true
}
pop := func(v string) {
if !stk[v] {
panic(fmt.Sprintln("impossible pop:", v, stk))
}
delete(stk, v)
}
// checked records import paths who's dependencies are all present
checked := make(map[string]bool)
var fn func(string)
fn = func(importpath string) {
p, ok := imports[importpath]
if !ok {
missing[importpath] = true
return
}
// have we already walked this arm, if so, skip it
if checked[importpath] {
return
}
sz := len(missing)
push(importpath)
for _, i := range p.Imports {
if i == importpath {
continue
}
fn(i)
}
// if the size of the missing map has not changed
// this entire subtree is complete, mark it as such
if len(missing) == sz {
checked[importpath] = true
}
pop(importpath)
}
for _, pkg := range pkgs {
fn(pkg.ImportPath)
}
return missing
}
func findOrphaned(pkgs []*vendor.Pkg, dsm map[string]*vendor.Depset) map[string]bool {
missing := make(map[string]bool)
imports := make(map[string]*vendor.Pkg)
for _, s := range dsm {
for _, p := range s.Pkgs {
imports[p.ImportPath] = p
}
}
orphans := make(map[string]bool)
for k := range dsm {
orphans[k] = true
}
// make fake C package for cgo
imports["C"] = &vendor.Pkg{
Depset: new(vendor.Depset),
Package: &build.Package{
Name: "C",
},
}
stk := make(map[string]bool)
push := func(v string) {
if stk[v] {
panic(fmt.Sprintln("import loop:", v, stk))
}
stk[v] = true
}
pop := func(v string) {
if !stk[v] {
panic(fmt.Sprintln("impossible pop:", v, stk))
}
delete(stk, v)
}
// checked records import paths who's dependencies are all present
checked := make(map[string]bool)
var fn func(string)
fn = func(importpath string) {
p, ok := imports[importpath]
if !ok {
missing[importpath] = true
return
}
// delete the pkg's depset, as it is referenced
delete(orphans, p.Depset.Root)
// have we already walked this arm, if so, skip it
if checked[importpath] {
return
}
sz := len(missing)
push(importpath)
for _, i := range p.Imports {
if i == importpath {
continue
}
fn(i)
}
// if the size of the missing map has not changed
// this entire subtree is complete, mark it as such
if len(missing) == sz {
checked[importpath] = true
}
pop(importpath)
}
for _, pkg := range pkgs {
fn(pkg.ImportPath)
}
return orphans
}
gb-0.3.2/cmd/gb/doc.go 0000664 0000000 0000000 00000001744 12625565062 0014352 0 ustar 00root root 0000000 0000000 package main
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"github.com/constabulary/gb"
"github.com/constabulary/gb/cmd"
)
func init() {
registerCommand(&cmd.Command{
Name: "doc",
UsageLine: `doc [.]`,
Short: "show documentation for a package or symbol",
Long: `
Doc shows documentation for a package or symbol.
See 'go help doc'.
`,
Run: func(ctx *gb.Context, args []string) error {
env := cmd.MergeEnv(os.Environ(), map[string]string{
"GOPATH": fmt.Sprintf("%s:%s", ctx.Projectdir(), filepath.Join(ctx.Projectdir(), "vendor")),
})
if len(args) == 0 {
args = append(args, ".")
}
args = append([]string{filepath.Join(ctx.Context.GOROOT, "bin", "godoc")}, args...)
cmd := exec.Cmd{
Path: args[0],
Args: args,
Env: env,
Stdin: os.Stdin,
Stdout: os.Stdout,
Stderr: os.Stderr,
}
return cmd.Run()
},
ParseArgs: func(_ *gb.Context, _ string, args []string) []string { return args },
})
}
gb-0.3.2/cmd/gb/dot.go 0000664 0000000 0000000 00000001120 12625565062 0014357 0 ustar 00root root 0000000 0000000 package main
import (
"fmt"
"io"
"strings"
"github.com/constabulary/gb"
)
func printActions(w io.Writer, a *gb.Action) {
fmt.Fprintf(w, "digraph %q {\n", a.Name)
seen := make(map[*gb.Action]bool)
print0(w, seen, a)
fmt.Fprintf(w, "}\n")
}
func print0(w io.Writer, seen map[*gb.Action]bool, a *gb.Action) {
if seen[a] {
return
}
split := func(s string) string {
return strings.Replace(strings.Replace(s, ": ", "\n", -1), ",", "\n", -1)
}
for _, d := range a.Deps {
print0(w, seen, d)
fmt.Fprintf(w, "%q -> %q;\n", split(a.Name), split(d.Name))
}
seen[a] = true
}
gb-0.3.2/cmd/gb/env.go 0000664 0000000 0000000 00000001363 12625565062 0014372 0 ustar 00root root 0000000 0000000 package main
import (
"fmt"
"github.com/constabulary/gb"
"github.com/constabulary/gb/cmd"
)
func init() {
registerCommand(EnvCmd)
}
var EnvCmd = &cmd.Command{
Name: "env",
UsageLine: `env`,
Short: "print project environment variables",
Long: `
Env prints project environment variables.
`,
Run: env,
}
func env(ctx *gb.Context, args []string) error {
env := makeenv(ctx)
for _, e := range env {
fmt.Printf("%s=%q\n", e.name, e.val)
}
return nil
}
type envvar struct {
name, val string
}
func findenv(env []envvar, name string) string {
for _, e := range env {
if e.name == name {
return e.val
}
}
return ""
}
func makeenv(ctx *gb.Context) []envvar {
return []envvar{
{"GB_PROJECT_DIR", ctx.Projectdir()},
}
}
gb-0.3.2/cmd/gb/flag.go 0000664 0000000 0000000 00000002314 12625565062 0014510 0 ustar 00root root 0000000 0000000 // Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import "fmt"
type stringsFlag []string
func (v *stringsFlag) Set(s string) error {
var err error
*v, err = splitQuotedFields(s)
if *v == nil {
*v = []string{}
}
return err
}
func splitQuotedFields(s string) ([]string, error) {
// Split fields allowing '' or "" around elements.
// Quotes further inside the string do not count.
var f []string
for len(s) > 0 {
for len(s) > 0 && isSpaceByte(s[0]) {
s = s[1:]
}
if len(s) == 0 {
break
}
// Accepted quoted string. No unescaping inside.
if s[0] == '"' || s[0] == '\'' {
quote := s[0]
s = s[1:]
i := 0
for i < len(s) && s[i] != quote {
i++
}
if i >= len(s) {
return nil, fmt.Errorf("unterminated %c string", quote)
}
f = append(f, s[:i])
s = s[i+1:]
continue
}
i := 0
for i < len(s) && !isSpaceByte(s[i]) {
i++
}
f = append(f, s[:i])
s = s[i:]
}
return f, nil
}
func (v *stringsFlag) String() string {
return ""
}
func isSpaceByte(c byte) bool {
return c == ' ' || c == '\t' || c == '\n' || c == '\r'
}
gb-0.3.2/cmd/gb/generate.go 0000664 0000000 0000000 00000002026 12625565062 0015371 0 ustar 00root root 0000000 0000000 package main
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"github.com/constabulary/gb"
"github.com/constabulary/gb/cmd"
)
func init() {
registerCommand(GenerateCmd)
}
var GenerateCmd = &cmd.Command{
Name: "generate",
UsageLine: "generate [-run regexp] [file.go... | packages]",
Short: "generate Go files by processing source",
Long: `
Generate runs commands described by directives within existing files.
Those commands can run any process, but the intent is to create or update Go
source files, for instance by running yacc.
See 'go help generate'.
`,
Run: func(ctx *gb.Context, args []string) error {
env := cmd.MergeEnv(os.Environ(), map[string]string{
"GOPATH": fmt.Sprintf("%s:%s", ctx.Projectdir(), filepath.Join(ctx.Projectdir(), "vendor")),
})
args = append([]string{filepath.Join(ctx.Context.GOROOT, "bin", "go"), "generate"}, args...)
cmd := exec.Cmd{
Path: args[0],
Args: args,
Env: env,
Stdin: os.Stdin,
Stdout: os.Stdout,
Stderr: os.Stderr,
}
return cmd.Run()
},
}
gb-0.3.2/cmd/gb/help.go 0000664 0000000 0000000 00000006640 12625565062 0014535 0 ustar 00root root 0000000 0000000 package main
import (
"bufio"
"bytes"
"fmt"
"io"
"os"
"sort"
"strings"
"text/template"
"unicode"
"unicode/utf8"
"github.com/constabulary/gb/cmd"
)
func init() {
registerCommand(helpProject)
}
var helpProject = &cmd.Command{
Name: "project",
Short: "gb project layout",
Long: `A gb project is defined as any directory that contains a src/ subdirectory.
gb automatically detects the root of the project by looking at the current
working directory and walking backwards until it finds a directory that
contains a src/ subdirectory.
In the event you wish to override this auto detection mechanism, the -R flag
can be used to supply a project root.
See http://getgb.io/docs/project for details`,
}
var helpTemplate = `{{if .Runnable}}usage: gb {{.UsageLine}}
{{end}}{{.Long | trim}}
`
// help implements the 'help' command.
func help(args []string) {
if len(args) == 0 {
printUsage(os.Stdout)
// not exit 2: succeeded at 'gb help'.
return
}
if len(args) != 1 {
fmt.Fprintf(os.Stderr, "usage: gb help command\n\nToo many arguments given.\n")
os.Exit(2) // failed at 'gb help'
}
arg := args[0]
// 'gb help documentation' generates alldocs.go.
if arg == "documentation" {
var buf bytes.Buffer
printUsage(&buf)
usage := &cmd.Command{Long: buf.String()}
f, _ := os.Create("alldocs.go")
tmpl(f, documentationTemplate, append([]*cmd.Command{usage}, sortedCommands()...))
f.Close()
return
}
for _, cmd := range commands {
if cmd.Name == arg {
tmpl(os.Stdout, helpTemplate, cmd)
// not exit 2: succeeded at 'gb help cmd'.
return
}
}
fmt.Fprintf(os.Stderr, "Unknown help topic %#q. Run 'gb help'.\n", arg)
os.Exit(2) // failed at 'gb help cmd'
}
var usageTemplate = `gb, a project based build tool for the Go programming language.
Usage:
gb command [arguments]
The commands are:
{{range .}}{{if .Runnable}}
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
Use "gb help [command]" for more information about a command.
Additional help topics:
{{range .}}{{if not .Runnable}}
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
Use "gb help [topic]" for more information about that topic.
`
var documentationTemplate = `// DO NOT EDIT THIS FILE.
//go:generate gb help documentation
/*
{{range .}}{{if .Short}}{{.Short | capitalize}}
{{end}}{{if .Runnable}}Usage:
gb {{.UsageLine}}
{{end}}{{.Long | trim}}
{{end}}*/
package main
`
// tmpl executes the given template text on data, writing the result to w.
func tmpl(w io.Writer, text string, data interface{}) {
t := template.New("top")
t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize})
template.Must(t.Parse(text))
if err := t.Execute(w, data); err != nil {
panic(err)
}
}
func capitalize(s string) string {
if s == "" {
return s
}
r, n := utf8.DecodeRuneInString(s)
return string(unicode.ToTitle(r)) + s[n:]
}
func printUsage(w io.Writer) {
bw := bufio.NewWriter(w)
tmpl(bw, usageTemplate, sortedCommands())
bw.Flush()
}
func sortedCommands() []*cmd.Command {
// TODO(dfc) drop this and make main.commands a []*cmd.Command
var sortedKeys []string
for k := range commands {
sortedKeys = append(sortedKeys, k)
}
sort.Strings(sortedKeys)
var cmds []*cmd.Command
for _, c := range sortedKeys {
// skip hidden commands
if commands[c].Hidden() {
continue
}
cmds = append(cmds, commands[c])
}
return cmds
}
func usage() {
printUsage(os.Stderr)
os.Exit(2)
}
gb-0.3.2/cmd/gb/info.go 0000664 0000000 0000000 00000001706 12625565062 0014536 0 ustar 00root root 0000000 0000000 package main
import (
"fmt"
"path/filepath"
"strings"
"github.com/constabulary/gb"
"github.com/constabulary/gb/cmd"
)
func init() {
registerCommand(&cmd.Command{
Name: "info",
UsageLine: `info`,
Short: "info returns information about this project",
Long: `info returns information about this project.
info returns 0 if the project is well formed, and non zero otherwise.
`,
Run: info,
AddFlags: addBuildFlags,
})
}
func info(ctx *gb.Context, args []string) error {
fmt.Printf("GB_PROJECT_DIR=%q\n", ctx.Projectdir())
fmt.Printf("GB_SRC_PATH=%q\n", joinlist(ctx.Srcdirs()...))
fmt.Printf("GB_PKG_DIR=%q\n", ctx.Pkgdir())
fmt.Printf("GB_BIN_SUFFIX=%q\n", ctx.Suffix())
return nil
}
// joinlist joins path elements using the os specific separator.
// TODO(dfc) it probably gets this wrong on windows in some circumstances.
func joinlist(paths ...string) string {
return strings.Join(paths, string(filepath.ListSeparator))
}
gb-0.3.2/cmd/gb/list.go 0000664 0000000 0000000 00000006315 12625565062 0014557 0 ustar 00root root 0000000 0000000 package main
import (
"bytes"
"encoding/json"
"flag"
"fmt"
"io"
"log"
"os"
"strings"
"text/template"
"github.com/constabulary/gb"
"github.com/constabulary/gb/cmd"
)
var (
projectroot string
format string
formatStdin bool
jsonOutput bool
)
func init() {
registerCommand(&cmd.Command{
Name: "list",
UsageLine: `list [-s] [-f format] [-json] [packages]`,
Short: "list the packages named by the importpaths",
Long: `
List lists packages imported by the project.
The default output shows the package import paths:
% gb list github.com/constabulary/...
github.com/constabulary/gb
github.com/constabulary/gb/cmd
github.com/constabulary/gb/cmd/gb
github.com/constabulary/gb/cmd/gb-env
github.com/constabulary/gb/cmd/gb-list
Flags:
-f
alternate format for the list, using the syntax of package template.
The default output is equivalent to -f '{{.ImportPath}}'. The struct
being passed to the template is currently an instance of gb.Package.
This structure is under active development and it's contents are not
guaranteed to be stable.
-s
read format template from STDIN.
-json
prints output in structured JSON format. WARNING: gb.Package
structure is not stable and will change in the future!
`,
Run: list,
AddFlags: func(fs *flag.FlagSet) {
fs.StringVar(&format, "f", "{{.ImportPath}}", "format template")
fs.BoolVar(&formatStdin, "s", false, "read format from stdin")
fs.BoolVar(&jsonOutput, "json", false, "outputs json. WARNING: gb.Package structure is not stable and will change in future")
},
})
}
func list(ctx *gb.Context, args []string) error {
if formatStdin {
var formatBuffer bytes.Buffer
io.Copy(&formatBuffer, os.Stdin)
format = formatBuffer.String()
}
pkgs, err := gb.ResolvePackages(ctx, args...)
if err != nil {
log.Fatalf("unable to resolve: %v", err)
}
if jsonOutput {
views := make([]*PackageView, 0, len(pkgs))
for _, pkg := range pkgs {
views = append(views, NewPackageView(pkg))
}
encoder := json.NewEncoder(os.Stdout)
if err := encoder.Encode(views); err != nil {
return fmt.Errorf("Error occurred during json encoding: %v", err)
}
} else {
fm := template.FuncMap{
"join": strings.Join,
}
tmpl, err := template.New("list").Funcs(fm).Parse(format)
if err != nil {
return fmt.Errorf("unable to parse template %q: %v", format, err)
}
for _, pkg := range pkgs {
if err := tmpl.Execute(os.Stdout, pkg); err != nil {
return fmt.Errorf("unable to execute template: %v", err)
}
fmt.Fprintln(os.Stdout)
}
}
return nil
}
// PackageView represents a package shown by list command in JSON format.
// It is not stable and may be subject to change.
type PackageView struct {
Dir string
ImportPath string
Name string
Root string
GoFiles []string
Imports []string
TestGoFiles []string
TestImports []string
}
// NewPackageView creates a *PackageView from gb Package.
func NewPackageView(pkg *gb.Package) *PackageView {
return &PackageView{
Dir: pkg.Dir,
ImportPath: pkg.ImportPath,
Name: pkg.Name,
Root: pkg.Root,
GoFiles: pkg.GoFiles,
Imports: pkg.Package.Imports,
TestGoFiles: pkg.TestGoFiles,
TestImports: pkg.TestImports,
}
}
gb-0.3.2/cmd/gb/main.go 0000664 0000000 0000000 00000005666 12625565062 0014540 0 ustar 00root root 0000000 0000000 package main
import (
"flag"
"fmt"
"os"
"os/exec"
"path/filepath"
"github.com/constabulary/gb"
"github.com/constabulary/gb/cmd"
"github.com/constabulary/gb/debug"
)
var (
fs = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
cwd string
args []string
)
const (
// enable to keep working directory
noDestroyContext = false
)
func init() {
fs.StringVar(&cwd, "R", cmd.MustGetwd(), "set the project root") // actually the working directory to start the project root search
fs.Usage = usage
}
var commands = make(map[string]*cmd.Command)
// registerCommand registers a command for main.
// registerCommand should only be called from init().
func registerCommand(command *cmd.Command) {
commands[command.Name] = command
}
func fatalf(format string, args ...interface{}) {
fmt.Fprintf(os.Stderr, "FATAL: "+format+"\n", args...)
os.Exit(1)
}
func main() {
args := os.Args
if len(args) < 2 || args[1] == "-h" {
fs.Usage()
os.Exit(1)
}
name := args[1]
if name == "help" {
help(args[2:])
return
}
command, ok := commands[name]
if (command != nil && !command.Runnable()) || !ok {
plugin, err := lookupPlugin(name)
if err != nil {
fmt.Fprintf(os.Stderr, "FATAL: unknown command %q\n", name)
fs.Usage()
os.Exit(1)
}
command = &cmd.Command{
Run: func(ctx *gb.Context, args []string) error {
args = append([]string{plugin}, args...)
env := cmd.MergeEnv(os.Environ(), map[string]string{
"GB_PROJECT_DIR": ctx.Projectdir(),
})
cmd := exec.Cmd{
Path: plugin,
Args: args,
Env: env,
Stdin: os.Stdin,
Stdout: os.Stdout,
Stderr: os.Stderr,
}
return cmd.Run()
},
// plugin should not interpret arguments
ParseArgs: func(_ *gb.Context, _ string, args []string) []string { return args },
}
}
// add extra flags if necessary
if command.AddFlags != nil {
command.AddFlags(fs)
}
var err error
if command.FlagParse != nil {
err = command.FlagParse(fs, args)
} else {
err = fs.Parse(args[2:])
}
if err != nil {
fatalf("could not parse flags: %v", err)
}
args = fs.Args() // reset args to the leftovers from fs.Parse
if command == commands["plugin"] {
args = append([]string{name}, args...)
}
cwd, err := filepath.Abs(cwd) // if cwd was passed in via -R, make sure it is absolute
if err != nil {
fatalf("could not make project root absolute: %v", err)
}
ctx, err := cmd.NewContext(
cwd, // project root
gb.GcToolchain(),
gb.Gcflags(gcflags...),
gb.Ldflags(ldflags...),
gb.Tags(buildtags...),
)
if err != nil {
fatalf("unable to construct context: %v", err)
}
if !noDestroyContext {
defer ctx.Destroy()
}
if command.ParseArgs != nil {
args = command.ParseArgs(ctx, ctx.Projectdir(), args)
} else {
args = cmd.ImportPaths(ctx, cwd, args)
}
debug.Debugf("args: %v", args)
if err := command.Run(ctx, args); err != nil {
if !noDestroyContext {
defer ctx.Destroy()
}
fatalf("command %q failed: %v", name, err)
}
return
}
gb-0.3.2/cmd/gb/plugin.go 0000664 0000000 0000000 00000001571 12625565062 0015101 0 ustar 00root root 0000000 0000000 package main
import (
"fmt"
"os/exec"
"github.com/constabulary/gb/cmd"
)
func init() {
registerCommand(PluginCmd)
}
var PluginCmd = &cmd.Command{
Name: "plugin",
Short: "plugin information",
Long: `gb supports git style plugins.
A gb plugin is anything in the $PATH with the prefix gb-. In other words
gb-something, becomes gb something.
gb plugins are executed from the parent gb process with the environment
variable, GB_PROJECT_DIR set to the root of the current project.
gb plugins can be executed directly but this is rarely useful, so authors
should attempt to diagnose this by looking for the presence of the
GB_PROJECT_DIR environment key.
`,
}
func lookupPlugin(arg string) (string, error) {
plugin := "gb-" + arg
path, err := exec.LookPath(plugin)
if err != nil {
return "", fmt.Errorf("plugin: unable to locate %q: %v", plugin, err)
}
return path, nil
}
gb-0.3.2/cmd/gb/signal.go 0000664 0000000 0000000 00000001174 12625565062 0015057 0 ustar 00root root 0000000 0000000 // Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"os"
"os/signal"
"sync"
)
// interrupted is closed, if go process is interrupted.
var interrupted = make(chan struct{})
// processSignals setups signal handler.
func processSignals() {
sig := make(chan os.Signal)
signal.Notify(sig, signalsToIgnore...)
go func() {
<-sig
close(interrupted)
}()
}
var onceProcessSignals sync.Once
// startSigHandlers start signal handlers.
func startSigHandlers() {
onceProcessSignals.Do(processSignals)
}
gb-0.3.2/cmd/gb/signal_notunix.go 0000664 0000000 0000000 00000000601 12625565062 0016635 0 ustar 00root root 0000000 0000000 // Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build plan9 windows
package main
import (
"os"
)
var signalsToIgnore = []os.Signal{os.Interrupt}
// signalTrace is the signal to send to make a Go program
// crash with a stack trace.
var signalTrace os.Signal = nil
gb-0.3.2/cmd/gb/signal_unix.go 0000664 0000000 0000000 00000000726 12625565062 0016124 0 ustar 00root root 0000000 0000000 // Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package main
import (
"os"
"syscall"
)
var signalsToIgnore = []os.Signal{os.Interrupt, syscall.SIGQUIT}
// signalTrace is the signal to send to make a Go program
// crash with a stack trace.
var signalTrace os.Signal = syscall.SIGQUIT
gb-0.3.2/cmd/gb/stringset.go 0000664 0000000 0000000 00000001603 12625565062 0015621 0 ustar 00root root 0000000 0000000 package main
// union returns the union of a and b.
func union(a, b map[string]bool) map[string]bool {
r := make(map[string]bool)
for k := range a {
r[k] = true
}
for k := range b {
r[k] = true
}
return r
}
// intersection returns the intersection of a and b.
func intersection(a, b map[string]bool) map[string]bool {
r := make(map[string]bool)
for k := range a {
if b[k] {
r[k] = true
}
}
return r
}
// difference returns the symetric difference of a and b.
func difference(a, b map[string]bool) map[string]bool {
r := make(map[string]bool)
for k := range a {
if !b[k] {
r[k] = true
}
}
for k := range b {
if !a[k] {
r[k] = true
}
}
return r
}
// contains returns true if a contains all the elements in s.
func contains(a map[string]bool, s ...string) bool {
var r bool
for _, e := range s {
if !a[e] {
return false
}
r = true
}
return r
}
gb-0.3.2/cmd/gb/stringset_test.go 0000664 0000000 0000000 00000005214 12625565062 0016662 0 ustar 00root root 0000000 0000000 package main
import "testing"
import "reflect"
func set(args ...string) map[string]bool {
r := make(map[string]bool)
for _, a := range args {
r[a] = true
}
return r
}
func TestUnion(t *testing.T) {
tests := []struct {
a, b map[string]bool
want map[string]bool
}{{
a: nil, b: nil,
want: set(),
}, {
a: nil, b: set("b"),
want: set("b"),
}, {
a: set("a"), b: nil,
want: set("a"),
}, {
a: set("a"), b: set("b"),
want: set("b", "a"),
}, {
a: set("c"), b: set("c"),
want: set("c"),
}}
for _, tt := range tests {
got := union(tt.a, tt.b)
if !reflect.DeepEqual(tt.want, got) {
t.Errorf("union(%v, %v) want: %v, got %v", tt.a, tt.b, tt.want, got)
}
}
}
func TestIntersection(t *testing.T) {
tests := []struct {
a, b map[string]bool
want map[string]bool
}{{
a: nil, b: nil,
want: set(),
}, {
a: nil, b: set("b"),
want: set(),
}, {
a: set("a"), b: nil,
want: set(),
}, {
a: set("a"), b: set("b"),
want: set(),
}, {
a: set("c"), b: set("c"),
want: set("c"),
}, {
a: set("a", "c"), b: set("b", "c"),
want: set("c"),
}}
for _, tt := range tests {
got := intersection(tt.a, tt.b)
if !reflect.DeepEqual(tt.want, got) {
t.Errorf("intersection(%v, %v) want: %v, got %v", tt.a, tt.b, tt.want, got)
}
}
}
func TestDifference(t *testing.T) {
tests := []struct {
a, b map[string]bool
want map[string]bool
}{{
a: nil, b: nil,
want: set(),
}, {
a: nil, b: set("b"),
want: set("b"),
}, {
a: set("a"), b: nil,
want: set("a"),
}, {
a: set("a"), b: set("b"),
want: set("a", "b"),
}, {
a: set("c"), b: set("c"),
want: set(),
}, {
a: set("a", "c"), b: set("b", "c"),
want: set("a", "b"),
}}
for _, tt := range tests {
got := difference(tt.a, tt.b)
if !reflect.DeepEqual(tt.want, got) {
t.Errorf("difference(%v, %v) want: %v, got %v", tt.a, tt.b, tt.want, got)
}
}
}
func TestContains(t *testing.T) {
tests := []struct {
a map[string]bool
s []string
want bool
}{{
a: nil, s: nil,
want: false,
}, {
a: set("a"), s: nil,
want: false,
}, {
a: set("a"), s: []string{"a"},
want: true,
}, {
a: set("a"), s: []string{"b"},
want: false,
}, {
a: set("a", "b"), s: []string{"b"},
want: true,
}, {
a: set("a"), s: []string{"a", "b"},
want: false,
}, {
a: set("a", "b", "c"), s: []string{"a", "b"},
want: true,
}, {
a: set("a", "b", "c"), s: []string{"x", "b"},
want: false,
}, {
a: set("a", "b", "c"), s: []string{"b", "c", "d"},
want: false,
}}
for _, tt := range tests {
got := contains(tt.a, tt.s...)
if !reflect.DeepEqual(tt.want, got) {
t.Errorf("contains(%v, %v) want: %v, got %v", tt.a, tt.s, tt.want, got)
}
}
}
gb-0.3.2/cmd/gb/test.go 0000664 0000000 0000000 00000004066 12625565062 0014564 0 ustar 00root root 0000000 0000000 package main
import (
"flag"
"fmt"
"os"
"sort"
"github.com/constabulary/gb"
"github.com/constabulary/gb/cmd"
"github.com/constabulary/gb/test"
)
func init() {
registerCommand(TestCmd)
}
var (
tfs []string // Arguments passed to the test binary
testProfile bool
testCover bool
testCoverMode string
testCoverPkg string
)
func addTestFlags(fs *flag.FlagSet) {
addBuildFlags(fs)
fs.BoolVar(&testCover, "cover", false, "enable coverage analysis")
fs.StringVar(&testCoverMode, "covermode", "set", "Set covermode: set (default), count, atomic")
fs.StringVar(&testCoverPkg, "coverpkg", "", "enable coverage analysis")
}
var TestCmd = &cmd.Command{
Name: "test",
UsageLine: "test [build flags] [packages] [flags for test binary]",
Short: "test packages",
Long: `
Test automates testing the packages named by the import paths.
'gb test' recompiles each package along with any files with names matching
the file pattern "*_test.go".
See 'go help test'.
`,
Run: func(ctx *gb.Context, args []string) error {
ctx.Force = F
ctx.SkipInstall = FF
r := test.TestResolver(ctx)
// gb build builds packages in dependency order, however
// gb test tests packages in alpha order. This matches the
// expected behaviour from go test; tests are executed in
// stable order.
sort.Strings(args)
pkgs, err := gb.ResolvePackages(r, args...)
if err != nil {
return err
}
test, err := test.TestPackages(TestFlags(tfs), pkgs...)
if err != nil {
return err
}
if dotfile != "" {
f, err := os.Create(dotfile)
if err != nil {
return err
}
defer f.Close()
printActions(f, test)
}
startSigHandlers()
return gb.ExecuteConcurrent(test, P, interrupted)
},
AddFlags: addTestFlags,
FlagParse: func(flags *flag.FlagSet, args []string) error {
var err error
args, tfs, err = TestFlagsExtraParse(args[2:])
if err != nil {
fmt.Fprintf(os.Stderr, "gb test: %s\n", err)
fmt.Fprintf(os.Stderr, `run "go help test" or "go help testflag" for more information`+"\n")
os.Exit(2)
}
return flags.Parse(args)
},
}
gb-0.3.2/cmd/gb/testflag.go 0000664 0000000 0000000 00000011605 12625565062 0015413 0 ustar 00root root 0000000 0000000 package main
import (
"errors"
"fmt"
"strconv"
"strings"
)
// testFlagSpec defines a flag we know about.
type testFlagSpec struct {
boolVar bool // True if the flag is type bool
passToTest bool // pass to Test
passToAll bool // pass to test plugin and test binary
present bool // The flag has been seen
}
// testFlagDefn is the set of flags we process.
var testFlagDefn = map[string]*testFlagSpec{
// local to the test plugin
"cover": {boolVar: true},
"coverpkg": {},
"covermode": {},
"a": {boolVar: true},
"r": {boolVar: true},
"f": {boolVar: true},
"F": {boolVar: true},
"P": {},
"ldflags": {},
"gcflags": {},
"dotfile": {},
// Passed to the test binary
"q": {boolVar: true, passToTest: true},
"v": {boolVar: true, passToTest: true},
"bench": {passToTest: true},
"benchmem": {boolVar: true, passToTest: true},
"benchtime": {passToTest: true},
"coverprofile": {passToTest: true},
"cpu": {passToTest: true},
"cpuprofile": {passToTest: true},
"memprofile": {passToTest: true},
"memprofilerate": {passToTest: true},
"blockprofile": {passToTest: true},
"blockprofilerate": {passToTest: true},
"outputdir": {passToTest: true},
"parallel": {passToTest: true},
"run": {passToTest: true},
"short": {boolVar: true, passToTest: true},
"timeout": {passToTest: true},
}
// TestFlags appends "-test." for flags that are passed to the test binary.
func TestFlags(testArgs []string) []string {
var targs []string
for _, arg := range testArgs {
var nArg, nVal, fArg string
fArg = arg
if !strings.Contains(arg, "-test.") {
nArg = strings.TrimPrefix(arg, "-")
if strings.Contains(nArg, "=") {
nArgVal := strings.Split(nArg, "=")
nArg, nVal = nArgVal[0], nArgVal[1]
}
if val, ok := testFlagDefn[nArg]; ok {
// Special handling for -q, needs to be -test.v when passed to the test
if nArg == "q" {
nArg = "v"
}
if val.passToTest || val.passToAll {
fArg = "-test." + nArg
}
}
if nVal != "" {
fArg = fArg + "=" + nVal
}
}
targs = append(targs, fArg)
}
return targs
}
// TestFlagsExtraParse is used to separate known arguments from unknown
// arguments passed on the command line. Returns a string slice of test plugin
// arguments (parseArgs), and a slice of string arguments for the test binary
// (extraArgs). An error is returned if an argument is used twice, or an
// argument value is incorrect.
func TestFlagsExtraParse(args []string) (parseArgs []string, extraArgs []string, err error) {
argsLen := len(args)
for x := 0; x < argsLen; x++ {
nArg := args[x]
val, ok := testFlagDefn[strings.TrimPrefix(nArg, "-")]
if !strings.HasPrefix(nArg, "-") || (ok && !val.passToTest) {
err = setArgFound(nArg)
if err != nil {
return
}
parseArgs = append(parseArgs, nArg)
if ok && val.passToAll {
extraArgs = append(extraArgs, nArg)
}
continue
}
var hadTestPrefix bool
hasEqual := strings.Contains(nArg, "=")
if !hasEqual && (x+1 < argsLen && !strings.HasPrefix(args[x+1], "-")) {
if strings.Contains(nArg, "-test.") {
hadTestPrefix = true
nArg = strings.TrimPrefix(nArg, "-test.")
} else {
nArg = strings.TrimPrefix(nArg, "-")
}
err = setArgFound(nArg)
if err != nil {
return
}
// Check the spec for arguments that consume the next argument
if val, ok := testFlagDefn[nArg]; ok {
if !val.boolVar {
nArg = nArg + "=" + args[x+1]
x++
}
}
} else if hasEqual {
// The argument has an embedded value, here we can do some basic
// checking.
sArgs := strings.Split(nArg, "=")
tArg, tVal := strings.TrimPrefix(sArgs[0], "-"), sArgs[1]
if val, ok := testFlagDefn[tArg]; ok {
if val.boolVar {
if err = checkBoolFlag(tVal); err != nil {
return
}
}
if !val.passToTest {
parseArgs = append(parseArgs, nArg)
continue
}
}
}
// Append "-" to the argument, and "-test." if "-test." was previously
// trimmed.
if nArg[0] != '-' {
pre := "-"
if hadTestPrefix {
pre = "-test."
}
nArg = pre + nArg
}
extraArgs = append(extraArgs, nArg)
}
return
}
// setArgFound checks the argument spec to see if arg has already been
// encountered. If it has, then an error is returned.
func setArgFound(arg string) error {
var err error
nArg := strings.TrimPrefix(arg, "-")
if val, ok := testFlagDefn[nArg]; ok {
if val.present {
err = fmt.Errorf("%q flag may be set only once", arg)
} else {
testFlagDefn[nArg].present = true
}
}
return err
}
// checkBoolFlag checks the value to ensure it is a boolean, if not an error is
// returned.
func checkBoolFlag(value string) error {
var nErr error
_, err := strconv.ParseBool(value)
if err != nil {
nErr = errors.New("illegal bool flag value " + value)
}
return nErr
}
gb-0.3.2/cmd/gb/testflag_test.go 0000664 0000000 0000000 00000012626 12625565062 0016456 0 ustar 00root root 0000000 0000000 package main
import (
"errors"
"reflect"
"testing"
)
func TestTestFlagsPreParse(t *testing.T) {
tests := []struct {
args []string // The command line arguments to parse
pargs []string // The expected arguments for flag.Parse
eargs []string // The expected "extra" arguments to pass to the test binary
err error
}{
{
args: []string{"-q", "-test", "-debug"},
eargs: []string{"-q", "-test", "-debug"},
}, {
args: []string{"-v", "-debug", "package_name"},
pargs: []string{"package_name"},
eargs: []string{"-v", "-debug"},
}, {
args: []string{"-q", "-debug", "package_name"},
pargs: []string{"package_name"},
eargs: []string{"-q", "-debug"},
}, {
args: []string{"-bench"},
eargs: []string{"-bench"},
}, {
args: []string{"-bench=."},
eargs: []string{"-bench=."},
}, {
args: []string{"-bench", "."},
eargs: []string{"-bench=."},
}, {
args: []string{"-bench", "Test*"},
eargs: []string{"-bench=Test*"},
}, {
args: []string{"-benchmem"},
eargs: []string{"-benchmem"},
}, {
args: []string{"-benchtime", "2s"},
eargs: []string{"-benchtime=2s"},
}, {
args: []string{"-blockprofile", "profile"},
eargs: []string{"-blockprofile=profile"},
}, {
args: []string{"-blockprofile", "profile", "-cover"},
pargs: []string{"-cover"},
eargs: []string{"-blockprofile=profile"},
}, {
args: []string{"-blockprofilerate", "2"},
eargs: []string{"-blockprofilerate=2"},
}, {
args: []string{"-coverprofile", "c.out"},
eargs: []string{"-coverprofile=c.out"},
}, {
args: []string{"-cpu", "1"},
eargs: []string{"-cpu=1"},
}, {
args: []string{"-cpu", "1"},
eargs: []string{"-cpu=1"},
}, {
args: []string{"-timeout"},
eargs: []string{"-timeout"},
}, {
args: []string{"-timeout", "2s"},
eargs: []string{"-timeout=2s"},
}, {
args: []string{"-test.run", "test"},
eargs: []string{"-test.run=test"},
}, {
args: []string{"-test.bench", "Test*"},
eargs: []string{"-test.bench=Test*"},
}, {
args: []string{"-test.bench=Test*"},
eargs: []string{"-test.bench=Test*"},
}, {
args: []string{"-test.run", "Test*", "-test.run", "Test2*"},
err: errors.New("\"run\" flag may be set only once"),
}, {
args: []string{"-cover=true"},
pargs: []string{"-cover=true"},
}, {
args: []string{"-cover=false"},
pargs: []string{"-cover=false"},
}, {
args: []string{"-cover=notabool"},
err: errors.New("illegal bool flag value notabool"),
}, {
args: []string{"-run", "Test*", "-run", "Test2*"},
err: errors.New("\"run\" flag may be set only once"),
}, {
args: []string{"-short"},
eargs: []string{"-short"},
}, {
args: []string{"-memprofilerate", "1"},
eargs: []string{"-memprofilerate=1"},
}, {
args: []string{"-coverpkg", "package"},
pargs: []string{"-coverpkg", "package"},
}, {
args: []string{"-P", "1"},
pargs: []string{"-P", "1"},
}, {
args: []string{"-P=1", "-short"},
pargs: []string{"-P=1"},
eargs: []string{"-short"},
}}
for _, tt := range tests {
for k, v := range testFlagDefn {
if v.present {
testFlagDefn[k].present = false
}
}
pargs, eargs, err := TestFlagsExtraParse(tt.args)
if tt.err != nil && (err == nil || (err != nil && tt.err.Error() != err.Error())) {
t.Errorf("TestExtraFlags(%v): want err = '%v', got = '%v'", tt.args, tt.err, err)
} else if tt.err == nil && (!reflect.DeepEqual(pargs, tt.pargs) || !reflect.DeepEqual(eargs, tt.eargs)) {
t.Errorf("TestExtraFlags(%v): want (%v,%v), got (%v,%v)", tt.args, tt.pargs, tt.eargs, pargs, eargs)
}
}
}
func TestTestFlags(t *testing.T) {
tests := []struct {
eargs []string // Extra test binary arguments
targs []string // The expected test binary arguments
}{
{
eargs: []string{"-q", "-debug"},
targs: []string{"-test.v", "-debug"},
}, {
eargs: []string{"-v", "-debug"},
targs: []string{"-test.v", "-debug"},
}, {
eargs: []string{"-bench"},
targs: []string{"-test.bench"},
}, {
eargs: []string{"-bench", "."},
targs: []string{"-test.bench", "."},
}, {
eargs: []string{"-bench='Test*'"},
targs: []string{"-test.bench='Test*'"},
}, {
eargs: []string{"-benchmem"},
targs: []string{"-test.benchmem"},
}, {
eargs: []string{"-benchtime"},
targs: []string{"-test.benchtime"},
}, {
eargs: []string{"-benchtime", "2s"},
targs: []string{"-test.benchtime", "2s"},
}, {
eargs: []string{"-benchtime=2s"},
targs: []string{"-test.benchtime=2s"},
}, {
eargs: []string{"-blockprofile", "profile"},
targs: []string{"-test.blockprofile", "profile"},
}, {
eargs: []string{"-blockprofile=profile"},
targs: []string{"-test.blockprofile=profile"},
}, {
eargs: []string{"-blockprofile"},
targs: []string{"-test.blockprofile"},
}, {
eargs: []string{"-cpuprofile"},
targs: []string{"-test.cpuprofile"},
}, {
eargs: []string{"-memprofile"},
targs: []string{"-test.memprofile"},
}, {
eargs: []string{"-short"},
targs: []string{"-test.short"},
}, {
eargs: []string{"-memprofilerate", "1"},
targs: []string{"-test.memprofilerate", "1"},
}, {
eargs: []string{"-test.run=test"},
targs: []string{"-test.run=test"},
}, {
eargs: []string{"-test.short"},
targs: []string{"-test.short"},
}}
for _, tt := range tests {
targs := TestFlags(tt.eargs)
if !reflect.DeepEqual(targs, tt.targs) {
t.Errorf("TestFlags(%v): want %v, got %v", tt.eargs, tt.targs, targs)
}
}
}
gb-0.3.2/cmd/import.go 0000664 0000000 0000000 00000002442 12625565062 0014523 0 ustar 00root root 0000000 0000000 package cmd
import (
"path"
"path/filepath"
"strings"
)
type Context interface {
Srcdirs() []string
AllPackages(string) []string
}
// importPathsNoDotExpansion returns the import paths to use for the given
// command line, but it does no ... expansion.
func importPathsNoDotExpansion(ctx Context, cwd string, args []string) []string {
srcdir, _ := filepath.Rel(ctx.Srcdirs()[0], cwd)
if srcdir == ".." {
srcdir = "."
}
if len(args) == 0 {
args = []string{"..."}
}
var out []string
for _, a := range args {
// Arguments are supposed to be import paths, but
// as a courtesy to Windows developers, rewrite \ to /
// in command-line arguments. Handles .\... and so on.
if filepath.Separator == '\\' {
a = strings.Replace(a, `\`, `/`, -1)
}
if a == "all" || a == "std" {
out = append(out, ctx.AllPackages(a)...)
continue
}
a = path.Join(srcdir, path.Clean(a))
out = append(out, a)
}
return out
}
// importPaths returns the import paths to use for the given command line.
func ImportPaths(ctx Context, cwd string, args []string) []string {
args = importPathsNoDotExpansion(ctx, cwd, args)
var out []string
for _, a := range args {
if strings.Contains(a, "...") {
out = append(out, ctx.AllPackages(a)...)
continue
}
out = append(out, a)
}
return out
}
gb-0.3.2/cmd/import_test.go 0000664 0000000 0000000 00000003642 12625565062 0015565 0 ustar 00root root 0000000 0000000 package cmd
import (
"os"
"path/filepath"
"reflect"
"testing"
)
type context struct {
srcdirs, allpkgs []string
}
func (c *context) Srcdirs() []string {
return c.srcdirs
}
func (c *context) AllPackages(pattern string) []string {
return c.allpkgs
}
func testdata(args ...string) string {
cwd, _ := os.Getwd()
return filepath.Join(append([]string{cwd, "testdata"}, args...)...)
}
// l constructs a []string
func l(args ...string) []string {
return args
}
// p constructs a path
func p(args ...string) string {
return filepath.Join(args...)
}
func TestImportPaths(t *testing.T) {
var tests = []struct {
ctx context
cwd string
args []string
want []string
}{
{
ctx: context{
srcdirs: l(testdata("src")),
allpkgs: l("a", "b", "c", p("c", "d")),
},
cwd: testdata("src"),
args: nil,
want: l("a", "b", "c", p("c", "d")),
}, {
ctx: context{
srcdirs: l(testdata("src")),
allpkgs: l("a", "b", "c", p("c", "d")),
},
cwd: testdata("src"),
args: l("..."),
want: l("a", "b", "c", p("c", "d")),
}, {
ctx: context{
srcdirs: l(testdata("src")),
allpkgs: l("c", p("c", "d")),
},
cwd: testdata("src", "c"),
args: nil,
want: l("c", p("c", "d")),
}, {
ctx: context{
srcdirs: l(testdata("src")),
allpkgs: l("a", "b", "c", p("c", "d")),
},
cwd: testdata("src"),
args: l("c"),
want: l("c"),
}, {
ctx: context{
srcdirs: l(testdata("src")),
allpkgs: l("a", "b", "c", p("c", "d")),
},
cwd: testdata("src"),
args: l("c", "b"),
want: l("c", "b"),
}, {
ctx: context{
srcdirs: l(testdata("src")),
allpkgs: l("c", p("c", "d")),
},
cwd: testdata("src"),
args: l("c/..."),
want: l("c", p("c", "d")),
},
}
for _, tt := range tests {
got := ImportPaths(&tt.ctx, tt.cwd, tt.args)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("ImportPaths(%v): got %v, want %v", tt.args, got, tt.want)
}
}
}
gb-0.3.2/cmd/path.go 0000664 0000000 0000000 00000001300 12625565062 0014135 0 ustar 00root root 0000000 0000000 package cmd
import (
"fmt"
"os"
"path/filepath"
)
// FindProjectroot works upwards from path seaching for the
// src/ directory which identifies the project root.
func FindProjectroot(path string) (string, error) {
if path == "" {
return "", fmt.Errorf("project root is blank")
}
start := path
for path != filepath.Dir(path) {
root := filepath.Join(path, "src")
if _, err := os.Stat(root); err != nil {
if os.IsNotExist(err) {
path = filepath.Dir(path)
continue
}
return "", err
}
path, err := filepath.EvalSymlinks(path)
if err != nil {
return "", err
}
return path, nil
}
return "", fmt.Errorf("could not find project root in %q or its parents", start)
}
gb-0.3.2/cmd/path_test.go 0000664 0000000 0000000 00000002712 12625565062 0015204 0 ustar 00root root 0000000 0000000 package cmd
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"testing"
)
var join = filepath.Join
// makeTestData constructs
func makeTestdata(t *testing.T) string {
tempdir, err := filepath.EvalSymlinks(os.TempDir())
if err != nil {
t.Fatal(err)
}
root, err := ioutil.TempDir(tempdir, "path-test")
if err != nil {
t.Fatal(err)
}
mkdir := func(args ...string) string {
path := join(args...)
if err := os.MkdirAll(path, 0777); err != nil {
t.Fatal(err)
}
return path
}
mkfile := func(path string, content string) {
if err := ioutil.WriteFile(path, []byte(content), 0755); err != nil {
t.Fatal(err)
}
}
srcdir := mkdir(root, "src")
mkfile(join(mkdir(srcdir, "a"), "a.go"), "package a")
return root
}
func TestFindProjectroot(t *testing.T) {
root := makeTestdata(t)
defer os.RemoveAll(root)
tests := []struct {
path string
want string
err error
}{
{path: root, want: root},
{path: join(root, "src"), want: root},
{path: join(join(root, "src"), "a"), want: root},
{path: join(root, ".."), err: fmt.Errorf("could not find project root in %q or its parents", join(root, ".."))},
}
for _, tt := range tests {
got, err := FindProjectroot(tt.path)
if got != tt.want || !sameErr(err, tt.err) {
t.Errorf("FindProjectroot(%v): want: %v, %v, got %v, %v", tt.path, tt.want, tt.err, got, err)
}
}
}
func sameErr(e1, e2 error) bool {
if e1 != nil && e2 != nil {
return e1.Error() == e2.Error()
}
return e1 == e2
}
gb-0.3.2/context.go 0000664 0000000 0000000 00000023426 12625565062 0014137 0 ustar 00root root 0000000 0000000 package gb
import (
"fmt"
"go/build"
"io"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"regexp"
"runtime"
"sort"
"strings"
"sync"
"time"
"github.com/constabulary/gb/debug"
)
// Context represents an execution of one or more Targets inside a Project.
type Context struct {
*Project
Context *build.Context
workdir string
tc Toolchain
gohostos, gohostarch string // GOOS and GOARCH for this host
gotargetos, gotargetarch string // GOOS and GOARCH for the target
Statistics
Force bool // force rebuild of packages
SkipInstall bool // do not cache compiled packages
pkgs map[string]*Package // map of package paths to resolved packages
gcflags []string // flags passed to the compiler
ldflags []string // flags passed to the linker
linkmode, buildmode string // link and build modes
buildtags []string // build tags
}
// GOOS configures the Context to use goos as the target os.
func GOOS(goos string) func(*Context) error {
return func(c *Context) error {
if goos == "" {
return fmt.Errorf("goos cannot be blank")
}
c.gotargetos = goos
return nil
}
}
// GOARCH configures the Context to use goarch as the target arch.
func GOARCH(goarch string) func(*Context) error {
return func(c *Context) error {
if goarch == "" {
return fmt.Errorf("goarch cannot be blank")
}
c.gotargetarch = goarch
return nil
}
}
// Tags configured the context to use these additional build tags
func Tags(tags ...string) func(*Context) error {
return func(c *Context) error {
c.buildtags = make([]string, len(tags))
copy(c.buildtags, tags)
return nil
}
}
// NewContext returns a new build context from this project.
// By default this context will use the gc toolchain with the
// host's GOOS and GOARCH values.
func (p *Project) NewContext(opts ...func(*Context) error) (*Context, error) {
if len(p.srcdirs) == 0 {
return nil, fmt.Errorf("no source directories supplied")
}
envOr := func(key, def string) string {
if v := os.Getenv(key); v != "" {
return v
} else {
return def
}
}
defaults := []func(*Context) error{
// must come before GcToolchain()
func(c *Context) error {
c.gohostos = runtime.GOOS
c.gohostarch = runtime.GOARCH
c.gotargetos = envOr("GOOS", runtime.GOOS)
c.gotargetarch = envOr("GOARCH", runtime.GOARCH)
return nil
},
GcToolchain(),
}
workdir, err := ioutil.TempDir("", "gb")
if err != nil {
return nil, err
}
ctx := Context{
Project: p,
workdir: workdir,
pkgs: make(map[string]*Package),
buildmode: "exe",
}
for _, opt := range append(defaults, opts...) {
err := opt(&ctx)
if err != nil {
return nil, err
}
}
// sort build tags to ensure the ctxSring and Suffix is stable
sort.Strings(ctx.buildtags)
// backfill enbedded go/build.Context
ctx.Context = &build.Context{
GOOS: ctx.gotargetos,
GOARCH: ctx.gotargetarch,
GOROOT: runtime.GOROOT(),
GOPATH: togopath(p.Srcdirs()),
Compiler: runtime.Compiler, // TODO(dfc) probably unused
// Make sure we use the same set of release tags as go/build
ReleaseTags: build.Default.ReleaseTags,
BuildTags: ctx.buildtags,
CgoEnabled: build.Default.CgoEnabled,
}
return &ctx, nil
}
// Gcflags sets options passed to the compiler.
func Gcflags(flags ...string) func(*Context) error {
return func(c *Context) error {
c.gcflags = flags
return nil
}
}
// Ldflags sets options passed to the linker.
func Ldflags(flags ...string) func(*Context) error {
return func(c *Context) error {
c.ldflags = flags
return nil
}
}
// IncludePaths returns the include paths visible in this context.
func (c *Context) IncludePaths() []string {
return []string{
c.workdir,
c.Pkgdir(),
}
}
// Pkgdir returns the path to precompiled packages.
func (c *Context) Pkgdir() string {
return filepath.Join(c.Project.Pkgdir(), c.ctxString())
}
// Suffix returns the suffix (if any) for binaries produced
// by this context.
func (c *Context) Suffix() string {
suffix := c.ctxString()
if suffix != "" {
suffix = "-" + suffix
}
return suffix
}
// Workdir returns the path to this Context's working directory.
func (c *Context) Workdir() string { return c.workdir }
// ResolvePackage resolves the package at path using the current context.
func (c *Context) ResolvePackage(path string) (*Package, error) {
if path == "." {
return nil, fmt.Errorf("%q is not a package", filepath.Join(c.rootdir, "src"))
}
path, err := relImportPath(filepath.Join(c.rootdir, "src"), path)
if err != nil {
return nil, err
}
return loadPackage(c, nil, path)
}
// Destroy removes the temporary working files of this context.
func (c *Context) Destroy() error {
debug.Debugf("removing work directory: %v", c.workdir)
return os.RemoveAll(c.workdir)
}
// ctxString returns a string representation of the unique properties
// of the context.
func (c *Context) ctxString() string {
v := []string{
c.gotargetos,
c.gotargetarch,
}
v = append(v, c.buildtags...)
return strings.Join(v, "-")
}
func runOut(output io.Writer, dir string, env []string, command string, args ...string) error {
cmd := exec.Command(command, args...)
cmd.Dir = dir
cmd.Stdout = output
cmd.Stderr = os.Stderr
cmd.Env = mergeEnvLists(env, envForDir(cmd.Dir))
debug.Debugf("cd %s; %s", cmd.Dir, cmd.Args)
err := cmd.Run()
return err
}
// Statistics records the various Durations
type Statistics struct {
sync.Mutex
stats map[string]time.Duration
}
func (s *Statistics) Record(name string, d time.Duration) {
s.Lock()
defer s.Unlock()
if s.stats == nil {
s.stats = make(map[string]time.Duration)
}
s.stats[name] += d
}
func (s *Statistics) Total() time.Duration {
s.Lock()
defer s.Unlock()
var d time.Duration
for _, v := range s.stats {
d += v
}
return d
}
func (s *Statistics) String() string {
s.Lock()
defer s.Unlock()
return fmt.Sprintf("%v", s.stats)
}
// matchPattern(pattern)(name) reports whether
// name matches pattern. Pattern is a limited glob
// pattern in which '...' means 'any string' and there
// is no other special syntax.
func matchPattern(pattern string) func(name string) bool {
re := regexp.QuoteMeta(pattern)
re = strings.Replace(re, `\.\.\.`, `.*`, -1)
// Special case: foo/... matches foo too.
if strings.HasSuffix(re, `/.*`) {
re = re[:len(re)-len(`/.*`)] + `(/.*)?`
}
reg := regexp.MustCompile(`^` + re + `$`)
return func(name string) bool {
return reg.MatchString(name)
}
}
// hasPathPrefix reports whether the path s begins with the
// elements in prefix.
func hasPathPrefix(s, prefix string) bool {
switch {
default:
return false
case len(s) == len(prefix):
return s == prefix
case len(s) > len(prefix):
if prefix != "" && prefix[len(prefix)-1] == '/' {
return strings.HasPrefix(s, prefix)
}
return s[len(prefix)] == '/' && s[:len(prefix)] == prefix
}
}
// treeCanMatchPattern(pattern)(name) reports whether
// name or children of name can possibly match pattern.
// Pattern is the same limited glob accepted by matchPattern.
func treeCanMatchPattern(pattern string) func(name string) bool {
wildCard := false
if i := strings.Index(pattern, "..."); i >= 0 {
wildCard = true
pattern = pattern[:i]
}
return func(name string) bool {
return len(name) <= len(pattern) && hasPathPrefix(pattern, name) ||
wildCard && strings.HasPrefix(name, pattern)
}
}
// AllPackages returns all the packages that can be found under the $PROJECT/src directory.
// The pattern is a path including "...".
func (c *Context) AllPackages(pattern string) []string {
return matchPackages(c, pattern)
}
// shouldignore tests if the package should be ignored.
func (c *Context) shouldignore(p string) bool {
if c.isCrossCompile() {
return p == "C" || p == "unsafe"
}
return stdlib[p]
}
func (c *Context) isCrossCompile() bool {
return c.gohostos != c.gotargetos || c.gohostarch != c.gotargetarch
}
func matchPackages(c *Context, pattern string) []string {
debug.Debugf("matchPackages: %v %v", c.srcdirs[0].Root, pattern)
match := func(string) bool { return true }
treeCanMatch := func(string) bool { return true }
if pattern != "all" && pattern != "std" {
match = matchPattern(pattern)
treeCanMatch = treeCanMatchPattern(pattern)
}
var pkgs []string
for _, dir := range c.srcdirs[:1] {
src := filepath.Clean(dir.Root) + string(filepath.Separator)
filepath.Walk(src, func(path string, fi os.FileInfo, err error) error {
if err != nil || !fi.IsDir() || path == src {
return nil
}
// Avoid .foo, _foo, and testdata directory trees.
_, elem := filepath.Split(path)
if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
return filepath.SkipDir
}
name := filepath.ToSlash(path[len(src):])
if pattern == "std" && strings.Contains(name, ".") {
return filepath.SkipDir
}
if !treeCanMatch(name) {
return filepath.SkipDir
}
if !match(name) {
return nil
}
_, err = c.Context.Import(".", path, 0)
if err != nil {
if _, noGo := err.(*build.NoGoError); noGo {
return nil
}
}
pkgs = append(pkgs, name)
return nil
})
}
return pkgs
}
// envForDir returns a copy of the environment
// suitable for running in the given directory.
// The environment is the current process's environment
// but with an updated $PWD, so that an os.Getwd in the
// child will be faster.
func envForDir(dir string) []string {
env := os.Environ()
// Internally we only use rooted paths, so dir is rooted.
// Even if dir is not rooted, no harm done.
return mergeEnvLists([]string{"PWD=" + dir}, env)
}
// mergeEnvLists merges the two environment lists such that
// variables with the same name in "in" replace those in "out".
func mergeEnvLists(in, out []string) []string {
NextVar:
for _, inkv := range in {
k := strings.SplitAfterN(inkv, "=", 2)[0]
for i, outkv := range out {
if strings.HasPrefix(outkv, k) {
out[i] = inkv
continue NextVar
}
}
out = append(out, inkv)
}
return out
}
gb-0.3.2/context_test.go 0000664 0000000 0000000 00000003314 12625565062 0015170 0 ustar 00root root 0000000 0000000 package gb
import (
"runtime"
"runtime/debug"
"strings"
"testing"
)
func testImportCycle(pkg string, t *testing.T) {
ctx := testContext(t)
debug.SetMaxStack(1 << 18)
_, err := ctx.ResolvePackage(pkg)
if strings.Index(err.Error(), "cycle detected") == -1 {
t.Errorf("ctx.ResolvePackage returned wrong error. Expected cycle detection, got: %v", err)
}
if err == nil {
t.Errorf("ctx.ResolvePackage should have returned an error for cycle, returned nil")
}
}
func TestOneElementCycleDetection(t *testing.T) {
testImportCycle("cycle0", t)
}
func TestSimpleCycleDetection(t *testing.T) {
testImportCycle("cycle1/a", t)
}
func TestLongCycleDetection(t *testing.T) {
testImportCycle("cycle2/a", t)
}
func TestContextCtxString(t *testing.T) {
opts := func(o ...func(*Context) error) []func(*Context) error { return o }
join := func(s ...string) string { return strings.Join(s, "-") }
tests := []struct {
opts []func(*Context) error
want string
}{
{nil, join(runtime.GOOS, runtime.GOARCH)},
{opts(GOOS("windows")), join("windows", runtime.GOARCH)},
{opts(GOARCH("arm64")), join(runtime.GOOS, "arm64")},
{opts(GOARCH("arm64"), GOOS("plan9")), join("plan9", "arm64")},
{opts(Tags()), join(runtime.GOOS, runtime.GOARCH)},
{opts(Tags("sphinx", "leon")), join(runtime.GOOS, runtime.GOARCH, "leon", "sphinx")},
{opts(Tags("sphinx", "leon"), GOARCH("ppc64le")), join(runtime.GOOS, "ppc64le", "leon", "sphinx")},
}
proj := testProject(t)
for _, tt := range tests {
ctx, err := proj.NewContext(tt.opts...)
if err != nil {
t.Fatal(err)
}
defer ctx.Destroy()
got := ctx.ctxString()
if got != tt.want {
t.Errorf("NewContext(%q).ctxString(): got %v, want %v", tt.opts, got, tt.want)
}
}
}
gb-0.3.2/debug/ 0000775 0000000 0000000 00000000000 12625565062 0013203 5 ustar 00root root 0000000 0000000 gb-0.3.2/debug/debug.go 0000664 0000000 0000000 00000001366 12625565062 0014626 0 ustar 00root root 0000000 0000000 // debug provides a light weight debug facility.
// Usage is via the DEBUG environment variable. Any non empty value will
// enable debug logging. For example
//
// DEBUG=. gb
//
// The period is a hint that the value passed to DEBUG is a regex, which matches
// files, or packages present in the file part of the file/line pair logged as a
// prefix of the log line. (not implemented yet)
//
// Debug output is send to os.Stderr, there is no facility to change this.
package debug
import (
"fmt"
"log"
"os"
)
var debug = os.Getenv("DEBUG")
var logger = log.New(os.Stderr, "", log.Ldate|log.Ltime|log.Lshortfile)
func Debugf(format string, args ...interface{}) {
if len(debug) == 0 {
return
}
logger.Output(2, fmt.Sprintf(format, args...))
}
gb-0.3.2/defaultcc.go 0000664 0000000 0000000 00000000131 12625565062 0014371 0 ustar 00root root 0000000 0000000 // +build !darwin,!freebsd
package gb
const defaultCC = "gcc"
const defaultCXX = "g++"
gb-0.3.2/defaultcc_bsd.go 0000664 0000000 0000000 00000000135 12625565062 0015225 0 ustar 00root root 0000000 0000000 // +build darwin freebsd
package gb
const defaultCC = "clang"
const defaultCXX = "clang++"
gb-0.3.2/example_test.go 0000664 0000000 0000000 00000001474 12625565062 0015144 0 ustar 00root root 0000000 0000000 package gb_test
import (
"log"
"path/filepath"
"github.com/constabulary/gb"
)
func ExampleNewPackage() {
// Every project begins with a project root.
// Normally you'd check this out of source control.
root := filepath.Join("home", "dfc", "devel", "demo")
// Create a new Project passing in the source directories
// under this project's root.
proj := gb.NewProject(root,
gb.SourceDir(filepath.Join(root, "src")), // $PROJECT/src
gb.SourceDir(filepath.Join(root, "vendor", "src")), // $PROJECT/vendor/src
)
// Create a new Context from the Project. A Context holds
// the state of a specific compilation or test within the Project.
ctx, err := proj.NewContext()
if err != nil {
log.Fatal("Could not create new context:", err)
}
// Always remember to clean up your Context
ctx.Destroy()
}
gb-0.3.2/executor.go 0000664 0000000 0000000 00000004146 12625565062 0014307 0 ustar 00root root 0000000 0000000 package gb
import (
"errors"
"sync"
)
// Execute executes a tree of *Actions sequentually in depth first order.
func Execute(a *Action) error {
seen := make(map[*Action]error)
return execute(seen, a)
}
func execute(seen map[*Action]error, a *Action) error {
// step 0, have we been here before
if err, ok := seen[a]; ok {
return err
}
// step 1, build all dependencies
for _, d := range a.Deps {
if err := execute(seen, d); err != nil {
return err
}
}
// step 2, now execute ourselves
err := a.Run()
seen[a] = err
return err
}
// ExecuteConcurrent executes all actions in a tree concurrently.
// Each Action will wait until its dependant actions are complete.
func ExecuteConcurrent(a *Action, n int, interrupt <-chan struct{}) error {
var mu sync.Mutex // protects seen
seen := make(map[*Action]chan error)
get := func(result chan error) error {
err := <-result
result <- err
return err
}
permits := make(chan bool, n)
for i := 0; i < cap(permits); i++ {
permits <- true
}
// wg tracks all the outstanding actions
var wg sync.WaitGroup
var execute func(map[*Action]chan error, *Action) chan error
execute = func(seen map[*Action]chan error, a *Action) chan error {
// step 0, have we seen this action before ?
mu.Lock()
if result, ok := seen[a]; ok {
// yes! return the result channel so others can wait
// on our action
mu.Unlock()
return result
}
// step 1, we're the first to run this action
result := make(chan error, 1)
seen[a] = result
mu.Unlock()
// queue all dependant actions.
var results []chan error
for _, dep := range a.Deps {
results = append(results, execute(seen, dep))
}
wg.Add(1)
go func() {
defer wg.Done()
// wait for dependant actions
for _, r := range results {
if err := get(r); err != nil {
result <- err
return
}
}
// wait for a permit and execute our action
select {
case <-permits:
result <- a.Run()
permits <- true
case <-interrupt:
result <- errors.New("interrupted")
return
}
}()
return result
}
err := get(execute(seen, a))
wg.Wait()
return err
}
gb-0.3.2/executor_test.go 0000664 0000000 0000000 00000007704 12625565062 0015351 0 ustar 00root root 0000000 0000000 package gb
import (
"errors"
"fmt"
"io"
"path/filepath"
"reflect"
"testing"
)
func TestExecuteBuildAction(t *testing.T) {
tests := []struct {
pkg string
err error
}{{
pkg: "a",
err: nil,
}, {
pkg: "b", // actually command
err: nil,
}, {
pkg: "c",
err: nil,
}, {
pkg: "d.v1",
err: nil,
}, {
pkg: "x",
err: errors.New("import cycle detected: x -> y -> x"),
}, {
pkg: "h", // imports "blank", which is blank, see issue #131
err: fmt.Errorf("no buildable Go source files in %s", filepath.Join(getwd(t), "testdata", "src", "blank")),
}}
for _, tt := range tests {
ctx := testContext(t)
defer ctx.Destroy()
pkg, err := ctx.ResolvePackage(tt.pkg)
if !sameErr(err, tt.err) {
t.Errorf("ctx.ResolvePackage(%v): want %v, got %v", tt.pkg, tt.err, err)
continue
}
if err != nil {
continue
}
action, err := BuildPackages(pkg)
if err != nil {
t.Errorf("BuildAction(%v): ", tt.pkg, err)
continue
}
if err := Execute(action); !sameErr(err, tt.err) {
t.Errorf("Execute(%v): want: %v, got %v", action.Name, tt.err, err)
}
}
}
func niltask() error { return nil }
var executorTests = []struct {
action *Action // root action
err error // expected error
}{{
action: &Action{
Name: "no error",
Run: niltask,
},
}, {
action: &Action{
Name: "root error",
Run: func() error { return io.EOF },
},
err: io.EOF,
}, {
action: &Action{
Name: "child, child, error",
Run: func() error { return fmt.Errorf("I should not have been called") },
Deps: []*Action{&Action{
Name: "child, error",
Run: niltask,
Deps: []*Action{&Action{
Name: "error",
Run: func() error { return io.EOF },
}},
}},
},
err: io.EOF,
}, {
action: &Action{
Name: "once only",
Run: func() error {
if c1 != 1 || c2 != 1 || c3 != 1 {
return fmt.Errorf("unexpected count, c1: %v, c2: %v, c3: %v", c1, c2, c3)
}
return nil
},
Deps: []*Action{createDag()},
},
}, {
action: &Action{
Name: "failure count",
Run: func() error { return fmt.Errorf("I should not have been called") },
Deps: []*Action{createFailDag()},
},
err: fmt.Errorf("task3 called 1 time"),
}}
func createDag() *Action {
task1 := func() error { c1++; return nil }
task2 := func() error { c2++; return nil }
task3 := func() error { c3++; return nil }
action1 := Action{Name: "c1", Run: task1}
action2 := Action{Name: "c2", Run: task2}
action3 := Action{Name: "c3", Run: task3}
action1.Deps = append(action1.Deps, &action2, &action3)
action2.Deps = append(action2.Deps, &action3)
return &action1
}
func createFailDag() *Action {
task1 := func() error { c1++; return nil }
task2 := func() error { c2++; return fmt.Errorf("task2 called %v time", c2) }
task3 := func() error { c3++; return fmt.Errorf("task3 called %v time", c3) }
action1 := Action{Name: "c1", Run: task1}
action2 := Action{Name: "c2", Run: task2}
action3 := Action{Name: "c3", Run: task3}
action1.Deps = append(action1.Deps, &action2, &action3)
action2.Deps = append(action2.Deps, &action3)
return &action1
}
var c1, c2, c3 int
func executeReset() {
c1 = 0
c2 = 0
c3 = 0
// reset executor test variables
}
func TestExecute(t *testing.T) {
for _, tt := range executorTests {
executeReset()
got := Execute(tt.action)
if !reflect.DeepEqual(got, tt.err) {
t.Errorf("Execute: %v: want err: %v, got err %v", tt.action.Name, tt.err, got)
}
}
}
func testExecuteConcurrentN(t *testing.T, n int) {
for _, tt := range executorTests {
executeReset()
got := ExecuteConcurrent(tt.action, n, nil) // no interrupt ch
if !reflect.DeepEqual(got, tt.err) {
t.Errorf("ExecuteConcurrent(%v): %v: want err: %v, got err %v", n, tt.action.Name, tt.err, got)
}
}
}
func TestExecuteConcurrent1(t *testing.T) { testExecuteConcurrentN(t, 1) }
func TestExecuteConcurrent2(t *testing.T) { testExecuteConcurrentN(t, 2) }
func TestExecuteConcurrent4(t *testing.T) { testExecuteConcurrentN(t, 4) }
func TestExecuteConcurrent7(t *testing.T) { testExecuteConcurrentN(t, 7) }
gb-0.3.2/fileutils/ 0000775 0000000 0000000 00000000000 12625565062 0014115 5 ustar 00root root 0000000 0000000 gb-0.3.2/fileutils/_testdata/ 0000775 0000000 0000000 00000000000 12625565062 0016065 5 ustar 00root root 0000000 0000000 gb-0.3.2/fileutils/_testdata/copyfile/ 0000775 0000000 0000000 00000000000 12625565062 0017677 5 ustar 00root root 0000000 0000000 gb-0.3.2/fileutils/_testdata/copyfile/a/ 0000775 0000000 0000000 00000000000 12625565062 0020117 5 ustar 00root root 0000000 0000000 gb-0.3.2/fileutils/_testdata/copyfile/a/rick 0000777 0000000 0000000 00000000000 12625565062 0026025 2/never/going/to/give/you/up ustar 00root root 0000000 0000000 gb-0.3.2/fileutils/fileutils.go 0000664 0000000 0000000 00000004304 12625565062 0016445 0 ustar 00root root 0000000 0000000 // package fileutils provides utililty methods to copy and move files and directories.
package fileutils
import (
"fmt"
"io"
"os"
"path/filepath"
"runtime"
"strings"
)
const debugCopypath = true
const debugCopyfile = false
// Copypath copies the contents of src to dst, excluding any file or
// directory that starts with a period.
func Copypath(dst string, src string) error {
err := filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if strings.HasPrefix(filepath.Base(path), ".") {
if info.IsDir() {
return filepath.SkipDir
}
return nil
}
if info.IsDir() {
return nil
}
if info.Mode()&os.ModeSymlink != 0 {
if debugCopypath {
fmt.Printf("skipping symlink: %v\n", path)
}
return nil
}
dst := filepath.Join(dst, path[len(src):])
return copyfile(dst, path)
})
if err != nil {
// if there was an error during copying, remove the partial copy.
RemoveAll(dst)
}
return err
}
func copyfile(dst, src string) error {
err := mkdir(filepath.Dir(dst))
if err != nil {
return fmt.Errorf("copyfile: mkdirall: %v", err)
}
r, err := os.Open(src)
if err != nil {
return fmt.Errorf("copyfile: open(%q): %v", src, err)
}
defer r.Close()
w, err := os.Create(dst)
if err != nil {
return fmt.Errorf("copyfile: create(%q): %v", dst, err)
}
defer w.Close()
if debugCopyfile {
fmt.Printf("copyfile(dst: %v, src: %v)\n", dst, src)
}
_, err = io.Copy(w, r)
return err
}
// RemoveAll removes path and any children it contains. Unlike os.RemoveAll it
// deletes read only files on Windows.
func RemoveAll(path string) error {
if runtime.GOOS == "windows" {
// Simple case: if Remove works, we're done.
err := os.Remove(path)
if err == nil || os.IsNotExist(err) {
return nil
}
// make sure all files are writable so we can delete them
filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
if err != nil {
// walk gave us some error, give it back.
return err
}
mode := info.Mode()
if mode|0200 == mode {
return nil
}
return os.Chmod(path, mode|0200)
})
}
return os.RemoveAll(path)
}
func mkdir(path string) error {
return os.MkdirAll(path, 0755)
}
gb-0.3.2/fileutils/fileutils_test.go 0000664 0000000 0000000 00000001020 12625565062 0017474 0 ustar 00root root 0000000 0000000 package fileutils
import (
"io/ioutil"
"path/filepath"
"runtime"
"testing"
)
func TestCopypathSkipsSymlinks(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("no symlinks on windows y'all")
}
dst := mktemp(t)
defer RemoveAll(dst)
src := filepath.Join("_testdata", "copyfile", "a")
if err := Copypath(dst, src); err != nil {
t.Fatalf("copypath(%s, %s): %v", dst, src, err)
}
}
func mktemp(t *testing.T) string {
s, err := ioutil.TempDir("", "fileutils_test")
if err != nil {
t.Fatal(err)
}
return s
}
gb-0.3.2/fileutils/path_test.go 0000664 0000000 0000000 00000005461 12625565062 0016445 0 ustar 00root root 0000000 0000000 // Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fileutils
import (
"os"
"runtime"
"testing"
)
var isReadonlyError = func(error) bool { return false }
func TestRemoveAll(t *testing.T) {
tmpDir := os.TempDir()
// Work directory.
path := tmpDir + "/_TestRemoveAll_"
fpath := path + "/file"
dpath := path + "/dir"
// Make directory with 1 file and remove.
if err := os.MkdirAll(path, 0777); err != nil {
t.Fatalf("MkdirAll %q: %s", path, err)
}
fd, err := os.Create(fpath)
if err != nil {
t.Fatalf("create %q: %s", fpath, err)
}
fd.Close()
if err = RemoveAll(path); err != nil {
t.Fatalf("RemoveAll %q (first): %s", path, err)
}
if _, err = os.Lstat(path); err == nil {
t.Fatalf("Lstat %q succeeded after RemoveAll (first)", path)
}
// Make directory with file and subdirectory and remove.
if err = os.MkdirAll(dpath, 0777); err != nil {
t.Fatalf("MkdirAll %q: %s", dpath, err)
}
fd, err = os.Create(fpath)
if err != nil {
t.Fatalf("create %q: %s", fpath, err)
}
fd.Close()
fd, err = os.Create(dpath + "/file")
if err != nil {
t.Fatalf("create %q: %s", fpath, err)
}
fd.Close()
if err = RemoveAll(path); err != nil {
t.Fatalf("RemoveAll %q (second): %s", path, err)
}
if _, err := os.Lstat(path); err == nil {
t.Fatalf("Lstat %q succeeded after RemoveAll (second)", path)
}
// Determine if we should run the following test.
testit := true
if runtime.GOOS == "windows" {
// Chmod is not supported under windows.
testit = false
} else {
// Test fails as root.
testit = os.Getuid() != 0
}
if testit {
// Make directory with file and subdirectory and trigger error.
if err = os.MkdirAll(dpath, 0777); err != nil {
t.Fatalf("MkdirAll %q: %s", dpath, err)
}
for _, s := range []string{fpath, dpath + "/file1", path + "/zzz"} {
fd, err = os.Create(s)
if err != nil {
t.Fatalf("create %q: %s", s, err)
}
fd.Close()
}
if err = os.Chmod(dpath, 0); err != nil {
t.Fatalf("Chmod %q 0: %s", dpath, err)
}
// No error checking here: either RemoveAll
// will or won't be able to remove dpath;
// either way we want to see if it removes fpath
// and path/zzz. Reasons why RemoveAll might
// succeed in removing dpath as well include:
// * running as root
// * running on a file system without permissions (FAT)
RemoveAll(path)
os.Chmod(dpath, 0777)
for _, s := range []string{fpath, path + "/zzz"} {
if _, err = os.Lstat(s); err == nil {
t.Fatalf("Lstat %q succeeded after partial RemoveAll", s)
}
}
}
if err = RemoveAll(path); err != nil {
t.Fatalf("RemoveAll %q after partial RemoveAll: %s", path, err)
}
if _, err = os.Lstat(path); err == nil {
t.Fatalf("Lstat %q succeeded after RemoveAll (final)", path)
}
}
gb-0.3.2/gb.go 0000664 0000000 0000000 00000005762 12625565062 0013046 0 ustar 00root root 0000000 0000000 // Package gb is a tool kit for building Go packages and programs.
//
// The executable, cmd/gb, is located in the respective subdirectory
// along with several plugin programs.
package gb
import (
"fmt"
"io"
"os"
"path/filepath"
"strings"
"github.com/constabulary/gb/debug"
)
// Toolchain represents a standardised set of command line tools
// used to build and test Go programs.
type Toolchain interface {
Gc(pkg *Package, searchpaths []string, importpath, srcdir, outfile string, files []string) error
Asm(pkg *Package, srcdir, ofile, sfile string) error
Pack(pkg *Package, afiles ...string) error
Ld(*Package, []string, string, string) error
Cc(pkg *Package, ofile string, cfile string) error
// compiler returns the location of the compiler for .go source code
compiler() string
// linker returns the location of the linker for this toolchain
linker() string
}
// Actions and Tasks.
//
// Actions and Tasks allow gb to separate the role of describing the
// order in which work will be done, from the work itself.
// Actions are the former, they describe the graph of dependencies
// between actions, and thus the work to be done. By traversing the action
// graph, we can do the work, executing Tasks in a sane order.
//
// Tasks describe the work to be done, without being concerned with
// the order in which the work is done -- that is up to the code that
// places Tasks into actions. Tasks also know more intimate details about
// filesystems, processes, file lists, etc, that Actions do not.
//
// Action graphs (they are not strictly trees as branchs converge on base actions)
// contain only work to be performed, there are no Actions with empty Tasks
// or Tasks which do no work.
//
// Actions are executed by Executors, but can also be transformed, mutated,
// or even graphed.
// An Action describes a task to be performed and a set
// of Actions that the task depends on.
type Action struct {
// Name describes the action.
Name string
// Deps identifies the Actions that this Action depends.
Deps []*Action
// Run identifies the task that this action represents.
Run func() error
}
func mkdir(path string) error {
return os.MkdirAll(path, 0755)
}
func copyfile(dst, src string) error {
err := mkdir(filepath.Dir(dst))
if err != nil {
return fmt.Errorf("copyfile: mkdirall: %v", err)
}
r, err := os.Open(src)
if err != nil {
return fmt.Errorf("copyfile: open(%q): %v", src, err)
}
defer r.Close()
w, err := os.Create(dst)
if err != nil {
return fmt.Errorf("copyfile: create(%q): %v", dst, err)
}
defer w.Close()
debug.Debugf("copyfile(dst: %v, src: %v)", dst, src)
_, err = io.Copy(w, r)
return err
}
// joinlist joins a []string representing path items
// using the operating system specific list separator.
func joinlist(l []string) string {
return strings.Join(l, string(filepath.ListSeparator))
}
// stripext strips the extension from a filename.
// The extension is defined by filepath.Ext.
func stripext(path string) string {
return path[:len(path)-len(filepath.Ext(path))]
}
gb-0.3.2/gb14.go 0000664 0000000 0000000 00000000103 12625565062 0013173 0 ustar 00root root 0000000 0000000 // +build !go1.5
package gb
const (
gc14 = true
gc15 = false
)
gb-0.3.2/gb15.go 0000664 0000000 0000000 00000000102 12625565062 0013173 0 ustar 00root root 0000000 0000000 // +build go1.5
package gb
const (
gc14 = false
gc15 = true
)
gb-0.3.2/gb_test.go 0000664 0000000 0000000 00000000553 12625565062 0014076 0 ustar 00root root 0000000 0000000 package gb
import "testing"
func TestStripext(t *testing.T) {
tests := []struct {
path, want string
}{
{"a.txt", "a"},
{"a.a.txt", "a.a"},
{"Makefile", "Makefile"},
{"", ""},
{"/", "/"},
}
for _, tt := range tests {
got := stripext(tt.path)
if got != tt.want {
t.Errorf("stripext(%q): want: %v, got: %v", tt.path, tt.want, got)
}
}
}
gb-0.3.2/gc.go 0000664 0000000 0000000 00000012311 12625565062 0013033 0 ustar 00root root 0000000 0000000 package gb
import (
"bytes"
"fmt"
"go/build"
"io"
"io/ioutil"
"os"
"path/filepath"
"runtime"
)
// gc toolchain
type gcToolchain struct {
gc, cc, ld, as, pack string
}
func GcToolchain() func(c *Context) error {
return func(c *Context) error {
// TODO(dfc) this should come from the context, not the runtime.
goroot := runtime.GOROOT()
if gc14 && (c.gohostos != c.gotargetos || c.gohostarch != c.gotargetarch) {
// cross-compliation is not supported yet #31
return fmt.Errorf("cross compilation from host %s/%s to target %s/%s not supported with Go 1.4", c.gohostos, c.gohostarch, c.gotargetos, c.gotargetarch)
}
tooldir := filepath.Join(goroot, "pkg", "tool", c.gohostos+"_"+c.gohostarch)
exe := ""
if c.gohostos == "windows" {
exe += ".exe"
}
switch {
case gc14:
archchar, err := build.ArchChar(c.gotargetarch)
if err != nil {
return err
}
c.tc = &gcToolchain{
gc: filepath.Join(tooldir, archchar+"g"+exe),
ld: filepath.Join(tooldir, archchar+"l"+exe),
as: filepath.Join(tooldir, archchar+"a"+exe),
cc: filepath.Join(tooldir, archchar+"c"+exe),
pack: filepath.Join(tooldir, "pack"+exe),
}
case gc15:
c.tc = &gcToolchain{
gc: filepath.Join(tooldir, "compile"+exe),
ld: filepath.Join(tooldir, "link"+exe),
as: filepath.Join(tooldir, "asm"+exe),
pack: filepath.Join(tooldir, "pack"+exe),
}
default:
return fmt.Errorf("unsupported Go version: %v", runtime.Version)
}
return nil
}
}
func (t *gcToolchain) Asm(pkg *Package, srcdir, ofile, sfile string) error {
args := []string{"-o", ofile, "-D", "GOOS_" + pkg.gotargetos, "-D", "GOARCH_" + pkg.gotargetarch}
switch {
case gc14:
includedir := filepath.Join(pkg.Context.Context.GOROOT, "pkg", pkg.gotargetos+"_"+pkg.gotargetarch)
args = append(args, "-I", includedir)
case gc15:
odir := filepath.Join(filepath.Dir(ofile))
includedir := filepath.Join(runtime.GOROOT(), "pkg", "include")
args = append(args, "-I", odir, "-I", includedir)
default:
return fmt.Errorf("unsupported Go version: %v", runtime.Version)
}
args = append(args, sfile)
if err := mkdir(filepath.Dir(ofile)); err != nil {
return fmt.Errorf("gc:asm: %v", err)
}
var buf bytes.Buffer
err := runOut(&buf, srcdir, nil, t.as, args...)
if err != nil {
fmt.Fprintf(os.Stderr, "# %s\n", pkg.ImportPath)
io.Copy(os.Stderr, &buf)
}
return err
}
func (t *gcToolchain) Ld(pkg *Package, searchpaths []string, outfile, afile string) error {
// to ensure we don't write a partial binary, link the binary to a temporary file in
// in the target directory, then rename.
dir := filepath.Dir(outfile)
tmp, err := ioutil.TempFile(dir, ".gb-link")
if err != nil {
return err
}
tmp.Close()
args := append(pkg.ldflags, "-o", tmp.Name())
for _, d := range searchpaths {
args = append(args, "-L", d)
}
if gc15 {
args = append(args, "-buildmode", pkg.buildmode)
}
args = append(args, afile)
if err := mkdir(dir); err != nil {
return err
}
var buf bytes.Buffer
if err = runOut(&buf, ".", nil, t.ld, args...); err != nil {
os.Remove(tmp.Name()) // remove partial file
fmt.Fprintf(os.Stderr, "# %s\n", pkg.ImportPath)
io.Copy(os.Stderr, &buf)
return err
}
return os.Rename(tmp.Name(), outfile)
}
func (t *gcToolchain) Cc(pkg *Package, ofile, cfile string) error {
if gc15 {
return fmt.Errorf("gc15 does not support cc")
}
args := []string{
"-F", "-V", "-w",
"-trimpath", pkg.Workdir(),
"-I", Workdir(pkg),
"-I", filepath.Join(pkg.Context.Context.GOROOT, "pkg", pkg.gohostos+"_"+pkg.gohostarch), // for runtime.h
"-o", ofile,
"-D", "GOOS_" + pkg.gotargetos,
"-D", "GOARCH_" + pkg.gotargetarch,
cfile,
}
var buf bytes.Buffer
err := runOut(&buf, pkg.Dir, nil, t.cc, args...)
if err != nil {
fmt.Fprintf(os.Stderr, "# %s\n", pkg.ImportPath)
io.Copy(os.Stderr, &buf)
}
return err
}
func (t *gcToolchain) Pack(pkg *Package, afiles ...string) error {
args := []string{"r"}
args = append(args, afiles...)
dir := filepath.Dir(afiles[0])
var buf bytes.Buffer
err := runOut(&buf, dir, nil, t.pack, args...)
if err != nil {
fmt.Fprintf(os.Stderr, "# %s\n", pkg.ImportPath)
io.Copy(os.Stderr, &buf)
}
return err
}
func (t *gcToolchain) compiler() string { return t.gc }
func (t *gcToolchain) linker() string { return t.ld }
func (t *gcToolchain) Gc(pkg *Package, searchpaths []string, importpath, srcdir, outfile string, files []string) error {
args := append(pkg.gcflags, "-p", importpath, "-pack")
args = append(args, "-o", outfile)
for _, d := range searchpaths {
args = append(args, "-I", d)
}
if pkg.Standard && pkg.ImportPath == "runtime" {
// runtime compiles with a special gc flag to emit
// additional reflect type data.
args = append(args, "-+")
}
if pkg.Complete() {
args = append(args, "-complete")
} else if gc15 {
asmhdr := filepath.Join(filepath.Dir(outfile), pkg.Name, "go_asm.h")
args = append(args, "-asmhdr", asmhdr)
}
args = append(args, files...)
if err := mkdir(filepath.Join(filepath.Dir(outfile), pkg.Name)); err != nil {
return fmt.Errorf("gc:gc: %v", err)
}
var buf bytes.Buffer
err := runOut(&buf, srcdir, nil, t.gc, args...)
if err != nil {
fmt.Fprintf(os.Stderr, "# %s\n", pkg.ImportPath)
io.Copy(os.Stderr, &buf)
}
return err
}
gb-0.3.2/install.go 0000664 0000000 0000000 00000004457 12625565062 0014124 0 ustar 00root root 0000000 0000000 package gb
import (
"os"
"path/filepath"
"time"
)
// pkgdir returns the destination for object cached for this Package.
func pkgdir(pkg *Package) string {
if pkg.Scope == "test" {
panic("pkgdir called with test scope")
}
return filepath.Join(pkg.Pkgdir(), filepath.Dir(filepath.FromSlash(pkg.ImportPath)))
}
func pkgfile(pkg *Package) string {
return filepath.Join(pkgdir(pkg), filepath.Base(filepath.FromSlash(pkg.ImportPath))+".a")
}
// isStale returns true if the source pkg is considered to be stale with
// respect to its installed version.
func isStale(pkg *Package) bool {
if pkg.Force {
return true
}
// tests are always stale, they are never installed
if pkg.Scope == "test" {
return true
}
// Package is stale if completely unbuilt.
var built time.Time
if fi, err := os.Stat(pkgfile(pkg)); err == nil {
built = fi.ModTime()
}
if built.IsZero() {
return true
}
olderThan := func(file string) bool {
fi, err := os.Stat(file)
return err != nil || fi.ModTime().After(built)
}
newerThan := func(file string) bool {
fi, err := os.Stat(file)
return err != nil || fi.ModTime().Before(built)
}
// As a courtesy to developers installing new versions of the compiler
// frequently, define that packages are stale if they are
// older than the compiler, and commands if they are older than
// the linker. This heuristic will not work if the binaries are
// back-dated, as some binary distributions may do, but it does handle
// a very common case.
if olderThan(pkg.tc.compiler()) {
return true
}
if pkg.IsCommand() && olderThan(pkg.tc.linker()) {
return true
}
// Package is stale if a dependency is newer.
for _, p := range pkg.Imports() {
if olderThan(pkgfile(p)) {
return true
}
}
// if the main package is up to date but _newer_ than the binary (which
// could have been removed), then consider it stale.
if pkg.isMain() && newerThan(pkg.Binfile()) {
return true
}
srcs := stringList(pkg.GoFiles, pkg.CFiles, pkg.CXXFiles, pkg.MFiles, pkg.HFiles, pkg.SFiles, pkg.CgoFiles, pkg.SysoFiles, pkg.SwigFiles, pkg.SwigCXXFiles)
for _, src := range srcs {
if olderThan(filepath.Join(pkg.Dir, src)) {
return true
}
}
return false
}
func stringList(args ...[]string) []string {
var l []string
for _, arg := range args {
l = append(l, arg...)
}
return l
}
gb-0.3.2/install_test.go 0000664 0000000 0000000 00000002360 12625565062 0015152 0 ustar 00root root 0000000 0000000 package gb
import (
"os"
"path/filepath"
"testing"
)
func TestStale(t *testing.T) {
var tests = []struct {
pkgs []string
stale map[string]bool
}{{
pkgs: []string{"a"},
stale: map[string]bool{
"a": true,
},
}, {
pkgs: []string{"a", "b"},
stale: map[string]bool{
"a": false,
"b": true,
},
}, {
pkgs: []string{"a", "b"},
stale: map[string]bool{
"a": false,
"b": false,
},
}}
root := mktemp(t)
defer os.RemoveAll(root)
proj := Project{
rootdir: root,
srcdirs: []Srcdir{{
Root: filepath.Join(getwd(t), "testdata", "src"),
}},
}
newctx := func() *Context {
ctx, err := proj.NewContext(
GcToolchain(),
)
if err != nil {
t.Fatal(err)
}
return ctx
}
resolve := func(ctx *Context, pkg string) *Package {
p, err := ctx.ResolvePackage(pkg)
if err != nil {
t.Fatal(err)
}
return p
}
for _, tt := range tests {
ctx := newctx()
defer ctx.Destroy()
for _, pkg := range tt.pkgs {
resolve(ctx, pkg)
}
for p, s := range tt.stale {
pkg := resolve(ctx, p)
if pkg.Stale != s {
t.Errorf("%q.Stale: got %v, want %v", pkg.Name, pkg.Stale, s)
}
}
for _, pkg := range tt.pkgs {
if err := Build(resolve(ctx, pkg)); err != nil {
t.Fatal(err)
}
}
}
}
gb-0.3.2/package.go 0000664 0000000 0000000 00000010137 12625565062 0014041 0 ustar 00root root 0000000 0000000 package gb
import (
"fmt"
"go/build"
"path/filepath"
"strings"
)
// Package represents a resolved package from the Project with respect to the Context.
type Package struct {
*Context
*build.Package
Scope string // scope: build, test, etc
ExtraIncludes string // hook for test
Stale bool // is the package out of date wrt. its cached copy
Standard bool // is this package part of the standard library
}
// NewPackage creates a resolved Package.
func NewPackage(ctx *Context, p *build.Package) *Package {
pkg := Package{
Context: ctx,
Package: p,
}
// seed pkg.c so calling result never blocks
pkg.Stale = isStale(&pkg)
return &pkg
}
// isMain returns true if this is a command, not being built in test scope, and
// not the testmain itself.
func (p *Package) isMain() bool {
switch p.Scope {
case "test":
return strings.HasSuffix(p.ImportPath, "testmain")
default:
return p.Name == "main"
}
}
// Imports returns the Pacakges that this Package depends on.
func (p *Package) Imports() []*Package {
pkgs := make([]*Package, 0, len(p.Package.Imports))
for _, i := range p.Package.Imports {
if p.shouldignore(i) {
continue
}
pkg, ok := p.pkgs[i]
if !ok {
panic("could not locate package: " + i)
}
pkgs = append(pkgs, pkg)
}
return pkgs
}
func (p *Package) String() string {
return fmt.Sprintf("%v", struct {
Name, ImportPath, Dir string
}{
p.Name, p.ImportPath, p.Dir,
})
}
// Complete indicates if this is a pure Go package
func (p *Package) Complete() bool {
// If we're giving the compiler the entire package (no C etc files), tell it that,
// so that it can give good error messages about forward declarations.
// Exceptions: a few standard packages have forward declarations for
// pieces supplied behind-the-scenes by package runtime.
extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.MFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles)
if p.Standard {
switch p.ImportPath {
case "bytes", "net", "os", "runtime/pprof", "sync", "time":
extFiles++
}
}
return extFiles == 0
}
// Binfile returns the destination of the compiled target of this command.
func (pkg *Package) Binfile() string {
// TODO(dfc) should have a check for package main, or should be merged in to objfile.
var target string
switch pkg.Scope {
case "test":
target = filepath.Join(pkg.Workdir(), filepath.FromSlash(pkg.ImportPath), "_test", binname(pkg))
default:
target = filepath.Join(pkg.Bindir(), binname(pkg))
}
// if this is a cross compile or there are build tags, add ctxString.
if pkg.isCrossCompile() {
target += "-" + pkg.ctxString()
} else if len(pkg.buildtags) > 0 {
target += "-" + strings.Join(pkg.buildtags, "-")
}
if pkg.gotargetos == "windows" {
target += ".exe"
}
return target
}
// loadPackage recursively resolves path and its imports and if successful
// stores those packages in the Context's internal package cache.
func loadPackage(c *Context, stack []string, path string) (*Package, error) {
if build.IsLocalImport(path) {
// sanity check
return nil, fmt.Errorf("%q is not a valid import path", path)
}
if pkg, ok := c.pkgs[path]; ok {
// already loaded, just return
return pkg, nil
}
push := func(path string) {
stack = append(stack, path)
}
pop := func(path string) {
stack = stack[:len(stack)-1]
}
onStack := func(path string) bool {
for _, p := range stack {
if p == path {
return true
}
}
return false
}
p, err := c.Context.Import(path, c.Projectdir(), 0)
if err != nil {
return nil, err
}
standard := p.Goroot && p.ImportPath != "" && !strings.Contains(p.ImportPath, ".")
push(path)
var stale bool
for _, i := range p.Imports {
if c.shouldignore(i) {
continue
}
if onStack(i) {
push(i)
return nil, fmt.Errorf("import cycle detected: %s", strings.Join(stack, " -> "))
}
pkg, err := loadPackage(c, stack, i)
if err != nil {
return nil, err
}
stale = stale || pkg.Stale
}
pop(path)
pkg := Package{
Context: c,
Package: p,
Standard: standard,
}
pkg.Stale = stale || isStale(&pkg)
c.pkgs[path] = &pkg
return &pkg, nil
}
gb-0.3.2/package_test.go 0000664 0000000 0000000 00000006530 12625565062 0015102 0 ustar 00root root 0000000 0000000 package gb
import (
"fmt"
"go/build"
"path/filepath"
"runtime"
"testing"
)
func testProject(t *testing.T) *Project {
cwd := getwd(t)
root := filepath.Join(cwd, "testdata")
return NewProject(root,
SourceDir(filepath.Join(root, "src")),
)
}
func testContext(t *testing.T) *Context {
prj := testProject(t)
ctx, err := prj.NewContext()
if err != nil {
t.Fatal(err)
}
ctx.Force = true
ctx.SkipInstall = true
return ctx
}
func TestResolvePackage(t *testing.T) {
ctx := testContext(t)
defer ctx.Destroy()
_, err := ctx.ResolvePackage("a")
if err != nil {
t.Fatal(err)
}
}
func TestPackageBinfile(t *testing.T) {
opts := func(o ...func(*Context) error) []func(*Context) error { return o }
gotargetos := "windows"
if runtime.GOOS == "windows" {
gotargetos = "linux"
}
gotargetarch := "386"
if runtime.GOARCH == "386" {
gotargetarch = "amd64"
}
var tests = []struct {
pkg string // package name
opts []func(*Context) error
want string // binfile result
}{{
pkg: "b",
want: "b",
}, {
pkg: "b",
opts: opts(GOOS(gotargetos)),
want: fmt.Sprintf("b-%v-%v", gotargetos, runtime.GOARCH),
}, {
pkg: "b",
opts: opts(GOARCH(gotargetarch)),
want: fmt.Sprintf("b-%v-%v", runtime.GOOS, gotargetarch),
}, {
pkg: "b",
opts: opts(GOARCH(gotargetarch), GOOS(gotargetos)),
want: fmt.Sprintf("b-%v-%v", gotargetos, gotargetarch),
}, {
pkg: "b",
opts: opts(Tags("lol")),
want: "b-lol",
}, {
pkg: "b",
opts: opts(GOARCH(gotargetarch), GOOS(gotargetos), Tags("lol")),
want: fmt.Sprintf("b-%v-%v-lol", gotargetos, gotargetarch),
}}
proj := testProject(t)
for i, tt := range tests {
ctx, err := proj.NewContext(tt.opts...)
defer ctx.Destroy()
pkg, err := ctx.ResolvePackage(tt.pkg)
if err != nil {
t.Fatal(err)
}
got := pkg.Binfile()
want := filepath.Join(ctx.Bindir(), tt.want)
if pkg.gotargetos == "windows" {
want += ".exe"
}
if want != got {
t.Errorf("test %v: (%s).Binfile(): want %s, got %s", i+1, tt.pkg, want, got)
}
}
}
func TestPackageIsMain(t *testing.T) {
var tests = []struct {
pkg *Package
want bool
}{{
pkg: &Package{
Package: &build.Package{
Name: "main",
ImportPath: "main",
},
},
want: true,
}, {
pkg: &Package{
Package: &build.Package{
Name: "a",
ImportPath: "main",
},
},
want: false,
}, {
pkg: &Package{
Package: &build.Package{
Name: "main",
ImportPath: "a",
},
},
want: true,
}, {
pkg: &Package{
Package: &build.Package{
Name: "main",
ImportPath: "testmain",
},
},
want: true,
}, {
pkg: &Package{
Package: &build.Package{
Name: "main",
ImportPath: "main",
},
Scope: "test",
},
want: false,
}, {
pkg: &Package{
Package: &build.Package{
Name: "a",
ImportPath: "main",
},
Scope: "test",
},
want: false,
}, {
pkg: &Package{
Package: &build.Package{
Name: "main",
ImportPath: "a",
},
Scope: "test",
},
want: false,
}, {
pkg: &Package{
Package: &build.Package{
Name: "main",
ImportPath: "testmain",
},
Scope: "test",
},
want: true,
}}
for _, tt := range tests {
got := tt.pkg.isMain()
if got != tt.want {
t.Errorf("Package{Name:%q, ImportPath: %q, Scope:%q}.isMain(): got %v, want %v", tt.pkg.Name, tt.pkg.ImportPath, tt.pkg.Scope, got, tt.want)
}
}
}
gb-0.3.2/project.go 0000664 0000000 0000000 00000003227 12625565062 0014116 0 ustar 00root root 0000000 0000000 package gb
import (
"path/filepath"
)
// Project represents a gb project. A gb project has a simlar layout to
// a $GOPATH workspace. Each gb project has a standard directory layout
// starting at the project root, which we'll refer too as $PROJECT.
//
// $PROJECT/ - the project root
// $PROJECT/src/ - base directory for the source of packages
// $PROJECT/bin/ - base directory for the compiled binaries
type Project struct {
rootdir string
srcdirs []Srcdir
}
func togopath(srcdirs []string) string {
var s []string
for _, srcdir := range srcdirs {
s = append(s, filepath.Dir(srcdir))
}
return joinlist(s)
}
func SourceDir(root string) func(*Project) {
return func(p *Project) {
p.srcdirs = append(p.srcdirs, Srcdir{Root: root})
}
}
func NewProject(root string, options ...func(*Project)) *Project {
proj := Project{
rootdir: root,
}
for _, opt := range options {
opt(&proj)
}
return &proj
}
// Pkgdir returns the path to precompiled packages.
func (p *Project) Pkgdir() string {
return filepath.Join(p.rootdir, "pkg")
}
// Projectdir returns the path root of this project.
func (p *Project) Projectdir() string {
return p.rootdir
}
// Srcdirs returns the path to the source directories.
// The first source directory will always be
// filepath.Join(Projectdir(), "src")
// but there may be additional directories.
func (p *Project) Srcdirs() []string {
var dirs []string
for _, s := range p.srcdirs {
dirs = append(dirs, s.Root)
}
return dirs
}
// Bindir returns the path for compiled programs.
func (p *Project) Bindir() string {
return filepath.Join(p.rootdir, "bin")
}
gb-0.3.2/resolve.go 0000664 0000000 0000000 00000001554 12625565062 0014130 0 ustar 00root root 0000000 0000000 package gb
import (
"fmt"
"path/filepath"
)
// Resolver resolves packages.
type Resolver interface {
// ResolvePackage resolves the import path to a *Package
ResolvePackage(path string) (*Package, error)
}
// ResolvePackages resolves import paths to packages.
func ResolvePackages(r Resolver, paths ...string) ([]*Package, error) {
var pkgs []*Package
for _, path := range paths {
pkg, err := r.ResolvePackage(path)
if err != nil {
return pkgs, fmt.Errorf("failed to resolve import path %q: %v", path, err)
}
pkgs = append(pkgs, pkg)
}
return pkgs, nil
}
func relImportPath(root, path string) (string, error) {
if isRel(path) {
return filepath.Rel(root, path)
}
return path, nil
}
// isRel returns if an import path is relative or absolute.
func isRel(path string) bool {
// TODO(dfc) should this be strings.StartsWith(".")
return path == "."
}
gb-0.3.2/resolve_test.go 0000664 0000000 0000000 00000004243 12625565062 0015165 0 ustar 00root root 0000000 0000000 package gb
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"testing"
)
func TestResolvePackages(t *testing.T) {
cwd := getwd(t)
root := filepath.Join(cwd, "testdata", "src")
tests := []struct {
paths []string
err error
}{
{paths: []string{"a"}},
{paths: []string{"."}, err: fmt.Errorf("failed to resolve import path %q: %q is not a package", ".", root)},
{paths: []string{"h"}, err: fmt.Errorf("failed to resolve import path %q: no buildable Go source files in %s", "h", filepath.Join(root, "blank"))},
}
for _, tt := range tests {
ctx := testContext(t)
defer ctx.Destroy()
_, err := ResolvePackages(ctx, tt.paths...)
if !sameErr(err, tt.err) {
t.Errorf("ResolvePackage(%v): want: %v, got %v", tt.paths, tt.err, err)
}
}
}
var join = filepath.Join
// makeTestData constructs
func makeTestdata(t *testing.T) string {
tempdir, err := filepath.EvalSymlinks(os.TempDir())
if err != nil {
t.Fatal(err)
}
root, err := ioutil.TempDir(tempdir, "path-test")
if err != nil {
t.Fatal(err)
}
mkdir := func(args ...string) string {
path := join(args...)
if err := os.MkdirAll(path, 0777); err != nil {
t.Fatal(err)
}
return path
}
mkfile := func(path string, content string) {
if err := ioutil.WriteFile(path, []byte(content), 0755); err != nil {
t.Fatal(err)
}
}
srcdir := mkdir(root, "src")
mkfile(join(mkdir(srcdir, "a"), "a.go"), "package a")
return root
}
func TestRelImportPath(t *testing.T) {
tests := []struct {
root, path, want string
}{
{"/project/src", "a", "a"},
// { "/project/src", "./a", "a"}, // TODO(dfc) this is relative
// { "/project/src", "a/../b", "a"}, // TODO(dfc) so is this
}
for _, tt := range tests {
got, _ := relImportPath(tt.root, tt.path)
if got != tt.want {
t.Errorf("relImportPath(%q, %q): want: %v, got: %v", tt.root, tt.path, tt.want, got)
}
}
}
func TestIsRel(t *testing.T) {
tests := []struct {
path string
want bool
}{
{".", true},
{"..", false}, // TODO(dfc) this is relative
{"a/../b", false}, // TODO(dfc) this too
}
for _, tt := range tests {
got := isRel(tt.path)
if got != tt.want {
t.Errorf("isRel(%q): want: %v, got: %v", tt.want, got)
}
}
}
gb-0.3.2/src.go 0000664 0000000 0000000 00000000321 12625565062 0013227 0 ustar 00root root 0000000 0000000 package gb
type Srcdir struct {
// Root is the root directory of this Srcdir.
Root string
// Prefix is an optional import path prefix applied
// to any package resolved via this Srcdir.
Prefix string
}
gb-0.3.2/stdlib.go 0000664 0000000 0000000 00000007762 12625565062 0013741 0 ustar 00root root 0000000 0000000 package gb
// packages from the standard lib. They are excluded
// from the package map.
var stdlib = map[string]bool{
"C": true,
"archive/tar": true,
"archive/zip": true,
"bufio": true,
"bytes": true,
"compress/bzip2": true,
"compress/flate": true,
"compress/gzip": true,
"compress/lzw": true,
"compress/zlib": true,
"container/heap": true,
"container/list": true,
"container/ring": true,
"crypto": true,
"crypto/aes": true,
"crypto/cipher": true,
"crypto/des": true,
"crypto/dsa": true,
"crypto/ecdsa": true,
"crypto/elliptic": true,
"crypto/hmac": true,
"crypto/md5": true,
"crypto/rand": true,
"crypto/rc4": true,
"crypto/rsa": true,
"crypto/sha1": true,
"crypto/sha256": true,
"crypto/sha512": true,
"crypto/subtle": true,
"crypto/tls": true,
"crypto/x509": true,
"crypto/x509/pkix": true,
"database/sql": true,
"database/sql/driver": true,
"debug/dwarf": true,
"debug/elf": true,
"debug/gosym": true,
"debug/macho": true,
"debug/pe": true,
"encoding": true,
"encoding/ascii85": true,
"encoding/asn1": true,
"encoding/base32": true,
"encoding/base64": true,
"encoding/binary": true,
"encoding/csv": true,
"encoding/gob": true,
"encoding/hex": true,
"encoding/json": true,
"encoding/pem": true,
"encoding/xml": true,
"errors": true,
"expvar": true,
"flag": true,
"fmt": true,
"go/ast": true,
"go/build": true,
"go/doc": true,
"go/format": true,
"go/parser": true,
"go/printer": true,
"go/scanner": true,
"go/token": true,
"hash": true,
"hash/adler32": true,
"hash/crc32": true,
"hash/crc64": true,
"hash/fnv": true,
"html": true,
"html/template": true,
"image": true,
"image/color": true,
"image/draw": true,
"image/gif": true,
"image/jpeg": true,
"image/png": true,
"index/suffixarray": true,
"io": true,
"io/ioutil": true,
"log": true,
"log/syslog": true,
"math": true,
"math/big": true,
"math/cmplx": true,
"math/rand": true,
"mime": true,
"mime/multipart": true,
"net": true,
"net/http": true,
"net/http/cgi": true,
"net/http/cookiejar": true,
"net/http/fcgi": true,
"net/http/httptest": true,
"net/http/httputil": true,
"net/http/pprof": true,
"net/mail": true,
"net/rpc": true,
"net/rpc/jsonrpc": true,
"net/smtp": true,
"net/textproto": true,
"net/url": true,
"os": true,
"os/exec": true,
"os/signal": true,
"os/user": true,
"path": true,
"path/filepath": true,
"reflect": true,
"regexp": true,
"regexp/syntax": true,
"runtime": true,
"runtime/cgo": true,
"runtime/debug": true,
"runtime/pprof": true,
"sort": true,
"strconv": true,
"strings": true,
"sync": true,
"sync/atomic": true,
"syscall": true,
"testing": true,
"testing/iotest": true,
"testing/quick": true,
"text/scanner": true,
"text/tabwriter": true,
"text/template": true,
"text/template/parse": true,
"time": true,
"unicode": true,
"unicode/utf16": true,
"unicode/utf8": true,
"unsafe": true,
}
gb-0.3.2/test/ 0000775 0000000 0000000 00000000000 12625565062 0013074 5 ustar 00root root 0000000 0000000 gb-0.3.2/test/gotest.go 0000664 0000000 0000000 00000021161 12625565062 0014731 0 ustar 00root root 0000000 0000000 // Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package test
// imported from $GOROOT/src/cmd/go/test.go
import (
"bytes"
"errors"
"go/ast"
"go/build"
"go/doc"
"go/parser"
"go/scanner"
"go/token"
"os"
"path/filepath"
"sort"
"strings"
"text/template"
"unicode"
"unicode/utf8"
"github.com/constabulary/gb"
"github.com/constabulary/gb/debug"
)
type coverInfo struct {
Package *gb.Package
Vars map[string]*CoverVar
}
// CoverVar holds the name of the generated coverage variables targeting the named file.
type CoverVar struct {
File string // local file name
Var string // name of count struct
}
var cwd, _ = os.Getwd()
// shortPath returns an absolute or relative name for path, whatever is shorter.
func shortPath(path string) string {
if rel, err := filepath.Rel(cwd, path); err == nil && len(rel) < len(path) {
return rel
}
return path
}
// isTestMain tells whether fn is a TestMain(m *testing.M) function.
func isTestMain(fn *ast.FuncDecl) bool {
if fn.Name.String() != "TestMain" ||
fn.Type.Results != nil && len(fn.Type.Results.List) > 0 ||
fn.Type.Params == nil ||
len(fn.Type.Params.List) != 1 ||
len(fn.Type.Params.List[0].Names) > 1 {
return false
}
ptr, ok := fn.Type.Params.List[0].Type.(*ast.StarExpr)
if !ok {
return false
}
// We can't easily check that the type is *testing.M
// because we don't know how testing has been imported,
// but at least check that it's *M or *something.M.
if name, ok := ptr.X.(*ast.Ident); ok && name.Name == "M" {
return true
}
if sel, ok := ptr.X.(*ast.SelectorExpr); ok && sel.Sel.Name == "M" {
return true
}
return false
}
// isTest tells whether name looks like a test (or benchmark, according to prefix).
// It is a Test (say) if there is a character after Test that is not a lower-case letter.
// We don't want TesticularCancer.
func isTest(name, prefix string) bool {
if !strings.HasPrefix(name, prefix) {
return false
}
if len(name) == len(prefix) { // "Test" is ok
return true
}
rune, _ := utf8.DecodeRuneInString(name[len(prefix):])
return !unicode.IsLower(rune)
}
// loadTestFuncs returns the testFuncs describing the tests that will be run.
func loadTestFuncs(ptest *build.Package) (*testFuncs, error) {
t := &testFuncs{
Package: ptest,
}
debug.Debugf("loadTestFuncs: %v, %v", ptest.TestGoFiles, ptest.XTestGoFiles)
for _, file := range ptest.TestGoFiles {
if err := t.load(filepath.Join(ptest.Dir, file), "_test", &t.ImportTest, &t.NeedTest); err != nil {
return nil, err
}
}
for _, file := range ptest.XTestGoFiles {
if err := t.load(filepath.Join(ptest.Dir, file), "_xtest", &t.ImportXtest, &t.NeedXtest); err != nil {
return nil, err
}
}
return t, nil
}
// writeTestmain writes the _testmain.go file for t to the file named out.
func writeTestmain(out string, t *testFuncs) error {
f, err := os.Create(out)
if err != nil {
return err
}
defer f.Close()
if err := testmainTmpl.Execute(f, t); err != nil {
return err
}
return nil
}
// expandScanner expands a scanner.List error into all the errors in the list.
// The default Error method only shows the first error.
func expandScanner(err error) error {
// Look for parser errors.
if err, ok := err.(scanner.ErrorList); ok {
// Prepare error with \n before each message.
// When printed in something like context: %v
// this will put the leading file positions each on
// its own line. It will also show all the errors
// instead of just the first, as err.Error does.
var buf bytes.Buffer
for _, e := range err {
e.Pos.Filename = shortPath(e.Pos.Filename)
buf.WriteString("\n")
buf.WriteString(e.Error())
}
return errors.New(buf.String())
}
return err
}
type testFuncs struct {
Tests []testFunc
Benchmarks []testFunc
Examples []testFunc
TestMain *testFunc
Package *build.Package
ImportTest bool
NeedTest bool
ImportXtest bool
NeedXtest bool
NeedCgo bool
Cover []coverInfo
}
func (t *testFuncs) CoverMode() string {
return ""
}
func (t *testFuncs) CoverEnabled() bool {
return false
}
// Covered returns a string describing which packages are being tested for coverage.
// If the covered package is the same as the tested package, it returns the empty string.
// Otherwise it is a comma-separated human-readable list of packages beginning with
// " in", ready for use in the coverage message.
func (t *testFuncs) Covered() string {
return ""
}
// Tested returns the name of the package being tested.
func (t *testFuncs) Tested() string {
return t.Package.Name
}
type testFunc struct {
Package string // imported package name (_test or _xtest)
Name string // function name
Output string // output, for examples
}
var testFileSet = token.NewFileSet()
func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error {
f, err := parser.ParseFile(testFileSet, filename, nil, parser.ParseComments)
if err != nil {
return expandScanner(err)
}
for _, d := range f.Decls {
n, ok := d.(*ast.FuncDecl)
if !ok {
continue
}
if n.Recv != nil {
continue
}
name := n.Name.String()
switch {
case isTestMain(n):
if t.TestMain != nil {
return errors.New("multiple definitions of TestMain")
}
t.TestMain = &testFunc{pkg, name, ""}
*doImport, *seen = true, true
case isTest(name, "Test"):
t.Tests = append(t.Tests, testFunc{pkg, name, ""})
*doImport, *seen = true, true
case isTest(name, "Benchmark"):
t.Benchmarks = append(t.Benchmarks, testFunc{pkg, name, ""})
*doImport, *seen = true, true
}
}
ex := doc.Examples(f)
sort.Sort(byOrder(ex))
for _, e := range ex {
*doImport = true // import test file whether executed or not
if e.Output == "" && !e.EmptyOutput {
// Don't run examples with no output.
continue
}
t.Examples = append(t.Examples, testFunc{pkg, "Example" + e.Name, e.Output})
*seen = true
}
return nil
}
type byOrder []*doc.Example
func (x byOrder) Len() int { return len(x) }
func (x byOrder) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x byOrder) Less(i, j int) bool { return x[i].Order < x[j].Order }
var testmainTmpl = template.Must(template.New("main").Parse(`
package main
import (
{{if not .TestMain}}
"os"
{{end}}
"regexp"
"testing"
{{if .ImportTest}}
{{if .NeedTest}}_test{{else}}_{{end}} {{.Package.ImportPath | printf "%q"}}
{{end}}
{{if .ImportXtest}}
{{if .NeedXtest}}_xtest{{else}}_{{end}} {{.Package.ImportPath | printf "%s_test" | printf "%q"}}
{{end}}
{{range $i, $p := .Cover}}
_cover{{$i}} {{$p.Package.ImportPath | printf "%q"}}
{{end}}
{{if .NeedCgo}}
_ "runtime/cgo"
{{end}}
)
var tests = []testing.InternalTest{
{{range .Tests}}
{"{{.Name}}", {{.Package}}.{{.Name}}},
{{end}}
}
var benchmarks = []testing.InternalBenchmark{
{{range .Benchmarks}}
{"{{.Name}}", {{.Package}}.{{.Name}}},
{{end}}
}
var examples = []testing.InternalExample{
{{range .Examples}}
{"{{.Name}}", {{.Package}}.{{.Name}}, {{.Output | printf "%q"}}},
{{end}}
}
var matchPat string
var matchRe *regexp.Regexp
func matchString(pat, str string) (result bool, err error) {
if matchRe == nil || matchPat != pat {
matchPat = pat
matchRe, err = regexp.Compile(matchPat)
if err != nil {
return
}
}
return matchRe.MatchString(str), nil
}
{{if .CoverEnabled}}
// Only updated by init functions, so no need for atomicity.
var (
coverCounters = make(map[string][]uint32)
coverBlocks = make(map[string][]testing.CoverBlock)
)
func init() {
{{range $i, $p := .Cover}}
{{range $file, $cover := $p.Vars}}
coverRegisterFile({{printf "%q" $cover.File}}, _cover{{$i}}.{{$cover.Var}}.Count[:], _cover{{$i}}.{{$cover.Var}}.Pos[:], _cover{{$i}}.{{$cover.Var}}.NumStmt[:])
{{end}}
{{end}}
}
func coverRegisterFile(fileName string, counter []uint32, pos []uint32, numStmts []uint16) {
if 3*len(counter) != len(pos) || len(counter) != len(numStmts) {
panic("coverage: mismatched sizes")
}
if coverCounters[fileName] != nil {
// Already registered.
return
}
coverCounters[fileName] = counter
block := make([]testing.CoverBlock, len(counter))
for i := range counter {
block[i] = testing.CoverBlock{
Line0: pos[3*i+0],
Col0: uint16(pos[3*i+2]),
Line1: pos[3*i+1],
Col1: uint16(pos[3*i+2]>>16),
Stmts: numStmts[i],
}
}
coverBlocks[fileName] = block
}
{{end}}
func main() {
{{if .CoverEnabled}}
testing.RegisterCover(testing.Cover{
Mode: {{printf "%q" .CoverMode}},
Counters: coverCounters,
Blocks: coverBlocks,
CoveredPackages: {{printf "%q" .Covered}},
})
{{end}}
m := testing.MainStart(matchString, tests, benchmarks, examples)
{{with .TestMain}}
{{.Package}}.{{.Name}}(m)
{{else}}
os.Exit(m.Run())
{{end}}
}
`))
gb-0.3.2/test/resolve.go 0000664 0000000 0000000 00000001327 12625565062 0015105 0 ustar 00root root 0000000 0000000 package test
import (
"github.com/constabulary/gb"
)
// TestResolver returns a gb.Resolver that resolves packages, their
// dependencies including any internal or external test dependencies.
func TestResolver(r gb.Resolver) gb.Resolver {
return &testResolver{r}
}
type testResolver struct {
gb.Resolver
}
func (r *testResolver) ResolvePackage(path string) (*gb.Package, error) {
p, err := r.Resolver.ResolvePackage(path)
if err != nil {
return nil, err
}
var imports []string
imports = append(imports, p.Package.TestImports...)
imports = append(imports, p.Package.XTestImports...)
for _, i := range imports {
_, err := r.Resolver.ResolvePackage(i)
if err != nil {
return nil, err
}
}
return p, nil
}
gb-0.3.2/test/test.go 0000664 0000000 0000000 00000014741 12625565062 0014411 0 ustar 00root root 0000000 0000000 package test
import (
"bytes"
"fmt"
"go/build"
"io"
"os"
"os/exec"
"path"
"path/filepath"
"strings"
"time"
"github.com/constabulary/gb"
"github.com/constabulary/gb/debug"
)
// Test returns a Target representing the result of compiling the
// package pkg, and its dependencies, and linking it with the
// test runner.
func Test(flags []string, pkgs ...*gb.Package) error {
test, err := TestPackages(flags, pkgs...)
if err != nil {
return err
}
return gb.Execute(test)
}
// TestPackages produces a graph of Actions that when executed build
// and test the supplied packages.
func TestPackages(flags []string, pkgs ...*gb.Package) (*gb.Action, error) {
if len(pkgs) < 1 {
return nil, fmt.Errorf("no test packages provided")
}
targets := make(map[string]*gb.Action) // maps package import paths to their test run action
names := func(pkgs []*gb.Package) []string {
var names []string
for _, pkg := range pkgs {
names = append(names, pkg.ImportPath)
}
return names
}
// create top level test action to root all test actions
t0 := time.Now()
test := gb.Action{
Name: fmt.Sprintf("test: %s", strings.Join(names(pkgs), ",")),
Run: func() error {
debug.Debugf("test duration: %v %v", time.Since(t0), pkgs[0].Statistics.String())
return nil
},
}
for _, pkg := range pkgs {
a, err := TestPackage(targets, pkg, flags)
if err != nil {
return nil, err
}
if a == nil {
// nothing to do ?? not even a test action ?
continue
}
test.Deps = append(test.Deps, a)
}
return &test, nil
}
// TestPackage returns an Action representing the steps required to build
// and test this Package.
func TestPackage(targets map[string]*gb.Action, pkg *gb.Package, flags []string) (*gb.Action, error) {
var gofiles []string
gofiles = append(gofiles, pkg.GoFiles...)
gofiles = append(gofiles, pkg.TestGoFiles...)
var cgofiles []string
cgofiles = append(cgofiles, pkg.CgoFiles...)
var imports []string
imports = append(imports, pkg.Package.Imports...)
imports = append(imports, pkg.Package.TestImports...)
name := pkg.Name
if name == "main" {
// rename the main package to its package name for testing.
name = filepath.Base(filepath.FromSlash(pkg.ImportPath))
}
// internal tests
testpkg := gb.NewPackage(pkg.Context, &build.Package{
Name: name,
ImportPath: pkg.ImportPath,
Dir: pkg.Dir,
SrcRoot: pkg.SrcRoot,
GoFiles: gofiles,
CFiles: pkg.CFiles,
CgoFiles: cgofiles,
TestGoFiles: pkg.TestGoFiles, // passed directly to buildTestMain
XTestGoFiles: pkg.XTestGoFiles, // passed directly to buildTestMain
CgoCFLAGS: pkg.CgoCFLAGS,
CgoCPPFLAGS: pkg.CgoCPPFLAGS,
CgoCXXFLAGS: pkg.CgoCXXFLAGS,
CgoLDFLAGS: pkg.CgoLDFLAGS,
CgoPkgConfig: pkg.CgoPkgConfig,
Imports: imports,
})
testpkg.Scope = "test"
testpkg.Stale = true
// only build the internal test if there is Go source or
// internal test files.
var testobj *gb.Action
if len(testpkg.GoFiles)+len(testpkg.CgoFiles)+len(testpkg.TestGoFiles) > 0 {
// build internal testpkg dependencies
deps, err := gb.BuildDependencies(targets, testpkg)
if err != nil {
return nil, err
}
testobj, err = gb.Compile(testpkg, deps...)
if err != nil {
return nil, err
}
}
// external tests
if len(pkg.XTestGoFiles) > 0 {
xtestpkg := gb.NewPackage(pkg.Context, &build.Package{
Name: name,
ImportPath: pkg.ImportPath + "_test",
Dir: pkg.Dir,
GoFiles: pkg.XTestGoFiles,
Imports: pkg.XTestImports,
})
// build external test dependencies
deps, err := gb.BuildDependencies(targets, xtestpkg)
if err != nil {
return nil, err
}
xtestpkg.Scope = "test"
xtestpkg.Stale = true
xtestpkg.ExtraIncludes = filepath.Join(pkg.Workdir(), filepath.FromSlash(pkg.ImportPath), "_test")
// if there is an internal test object, add it as a dependency.
if testobj != nil {
deps = append(deps, testobj)
}
testobj, err = gb.Compile(xtestpkg, deps...)
if err != nil {
return nil, err
}
}
testmainpkg, err := buildTestMain(testpkg)
if err != nil {
return nil, err
}
testmain, err := gb.Compile(testmainpkg, testobj)
if err != nil {
return nil, err
}
return &gb.Action{
Name: fmt.Sprintf("run: %s", testmainpkg.Binfile()),
Deps: testmain.Deps,
Run: func() error {
// When used with the concurrent executor, building deps and
// linking the test binary can cause a lot of disk space to be
// pinned as linking will tend to occur more frequenty than retiring
// tests.
//
// To solve this, we merge the testmain compile step (which includes
// linking) and the test run and cleanup steps so they are executed
// as one atomic operation.
var output bytes.Buffer
err := testmain.Run() // compile and link
if err == nil {
cmd := exec.Command(testmainpkg.Binfile(), flags...)
cmd.Dir = pkg.Dir // tests run in the original source directory
cmd.Stdout = &output
cmd.Stderr = &output
err = cmd.Run() // run test
// test binaries can be very large, so always unlink the
// binary after the test has run to free up temporary space
// technically this is done by ctx.Destroy(), but freeing
// the space earlier is important for projects with many
// packages
os.Remove(testmainpkg.Binfile())
}
if err != nil {
fmt.Fprintf(os.Stderr, "# %s\n", pkg.ImportPath)
io.Copy(os.Stdout, &output)
} else {
fmt.Println(pkg.ImportPath)
}
return err
},
}, nil
}
func buildTestMain(pkg *gb.Package) (*gb.Package, error) {
if pkg.Scope != "test" {
return nil, fmt.Errorf("package %q is not test scoped", pkg.Name)
}
dir := gb.Workdir(pkg)
if err := mkdir(dir); err != nil {
return nil, fmt.Errorf("buildTestmain: %v", err)
}
tests, err := loadTestFuncs(pkg.Package)
if err != nil {
return nil, err
}
if len(pkg.Package.XTestGoFiles) > 0 {
// if there are external tests ensure that we import the
// test package into the final binary for side effects.
tests.ImportXtest = true
}
if err := writeTestmain(filepath.Join(dir, "_testmain.go"), tests); err != nil {
return nil, err
}
testmain := gb.NewPackage(pkg.Context, &build.Package{
Name: pkg.Name,
ImportPath: path.Join(pkg.ImportPath, "testmain"),
Dir: dir,
SrcRoot: pkg.SrcRoot,
GoFiles: []string{"_testmain.go"},
Imports: pkg.Package.Imports,
})
testmain.Scope = "test"
testmain.ExtraIncludes = filepath.Join(pkg.Workdir(), filepath.FromSlash(pkg.ImportPath), "_test")
return testmain, nil
}
func mkdir(path string) error {
return os.MkdirAll(path, 0755)
}
gb-0.3.2/test/test_test.go 0000664 0000000 0000000 00000011461 12625565062 0015444 0 ustar 00root root 0000000 0000000 package test
import (
"os"
"path/filepath"
"reflect"
"sort"
"strings"
"testing"
"time"
"github.com/constabulary/gb"
)
func TestTest(t *testing.T) {
tests := []struct {
pkg string
testArgs []string
ldflags []string
err error
}{
{
pkg: "a",
err: nil,
}, {
pkg: "b",
err: nil,
}, {
pkg: "c",
err: nil,
}, {
pkg: "e",
err: nil,
}, {
pkg: "cmd/f",
err: nil,
}, {
pkg: "extest", // test external tests
err: nil,
}, {
pkg: "external_only_test", // issue 312
err: nil,
}, {
pkg: "notestfiles",
err: nil,
}, {
pkg: "cgoonlynotest",
err: nil,
}, {
pkg: "testonly",
err: nil,
}, {
pkg: "extestonly",
err: nil,
}, {
pkg: "g", // test that _test files can modify the internal package under test
err: nil,
}, {
pkg: "ldflags",
ldflags: []string{"-X", "ldflags.gitTagInfo", "banana", "-X", "ldflags.gitRevision", "f7926af2"},
}, {
pkg: "cgotest",
}, {
pkg: "testflags",
testArgs: []string{"-debug"},
}, {
pkg: "main", // issue 375, a package called main
}}
for _, tt := range tests {
ctx := testContext(t, gb.Ldflags(tt.ldflags...))
defer ctx.Destroy()
r := TestResolver(ctx)
pkg, err := r.ResolvePackage(tt.pkg)
if err != nil {
t.Errorf("ResolvePackage(%v): want %v, got %v", tt.pkg, tt.err, err)
continue
}
if err := Test(tt.testArgs, pkg); err != tt.err {
t.Errorf("Test(%v): want %v, got %v", tt.pkg, tt.err, err)
time.Sleep(500 * time.Millisecond)
}
}
}
func TestTestPackage(t *testing.T) {
tests := []struct {
pkg string
err error
}{{
pkg: "a",
err: nil,
}, {
pkg: "b", // actually command
err: nil,
}, {
pkg: "c",
err: nil,
}, {
pkg: "d.v1",
err: nil,
}, {
pkg: "cgomain",
err: nil,
}, {
pkg: "cgotest",
err: nil,
}, {
pkg: "notestfiles",
err: nil,
}, {
pkg: "cgoonlynotest",
err: nil,
}, {
pkg: "testonly",
err: nil,
}, {
pkg: "extestonly",
err: nil,
}}
for _, tt := range tests {
ctx := testContext(t)
defer ctx.Destroy()
pkg, err := ctx.ResolvePackage(tt.pkg)
if err != nil {
t.Errorf("ctx.ResolvePackage(%v): %v", tt.pkg, err)
continue
}
targets := make(map[string]*gb.Action)
if _, err := TestPackage(targets, pkg, nil); !sameErr(err, tt.err) {
t.Errorf("TestPackage(%v): want %v, got %v", tt.pkg, tt.err, err)
}
}
}
func TestTestPackages(t *testing.T) {
tests := []struct {
pkgs []string
actions []string
err error
}{{
pkgs: []string{"a", "b", "c"},
actions: []string{
"run: $WORKDIR/a/testmain/_test/a.test$EXE",
"run: $WORKDIR/b/testmain/_test/b.test$EXE",
"run: $WORKDIR/c/testmain/_test/c.test$EXE",
},
}, {
pkgs: []string{"cgotest", "cgomain", "notestfiles", "cgoonlynotest", "testonly", "extestonly"},
actions: []string{
"run: $WORKDIR/cgomain/testmain/_test/cgomain.test$EXE",
"run: $WORKDIR/cgoonlynotest/testmain/_test/cgoonly.test$EXE",
"run: $WORKDIR/cgotest/testmain/_test/cgotest.test$EXE",
"run: $WORKDIR/extestonly/testmain/_test/extestonly.test$EXE",
"run: $WORKDIR/notestfiles/testmain/_test/notest.test$EXE",
"run: $WORKDIR/testonly/testmain/_test/testonly.test$EXE",
},
}}
for _, tt := range tests {
ctx := testContext(t)
defer ctx.Destroy()
var pkgs []*gb.Package
for _, pkg := range tt.pkgs {
pkg, err := ctx.ResolvePackage(pkg)
if err != nil {
t.Errorf("ctx.ResolvePackage(%v): %v", pkg, err)
continue
}
pkgs = append(pkgs, pkg)
}
a, err := TestPackages(nil, pkgs...)
if !sameErr(err, tt.err) {
t.Errorf("TestPackages(%v): want %v, got %v", pkgs, tt.err, err)
}
var actual []string
for _, a := range a.Deps {
actual = append(actual, a.Name)
}
sort.Strings(actual)
var expected []string
exe := ""
if ctx.Context.GOOS == "windows" {
exe = ".exe"
}
for _, s := range tt.actions {
s = filepath.FromSlash(s)
s = strings.Replace(s, "$WORKDIR", ctx.Workdir(), -1)
s = strings.Replace(s, "$EXE", exe, -1)
expected = append(expected, s)
}
if !reflect.DeepEqual(expected, actual) {
t.Errorf("TestBuildPackages(%v): want %v, got %v", pkgs, expected, actual)
}
}
}
func getwd(t *testing.T) string {
cwd, err := os.Getwd()
if err != nil {
t.Fatal(err)
}
return cwd
}
func testProject(t *testing.T) *gb.Project {
cwd := getwd(t)
root := filepath.Join(cwd, "..", "testdata")
return gb.NewProject(root,
gb.SourceDir(filepath.Join(root, "src")),
)
}
func testContext(t *testing.T, opts ...func(*gb.Context) error) *gb.Context {
prj := testProject(t)
opts = append([]func(*gb.Context) error{gb.GcToolchain()}, opts...)
ctx, err := prj.NewContext(opts...)
if err != nil {
t.Fatal(err)
}
ctx.Force = true
ctx.SkipInstall = true
return ctx
}
func sameErr(e1, e2 error) bool {
if e1 != nil && e2 != nil {
return e1.Error() == e2.Error()
}
return e1 == e2
}
gb-0.3.2/testdata/ 0000775 0000000 0000000 00000000000 12625565062 0013726 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/ 0000775 0000000 0000000 00000000000 12625565062 0014515 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/a/ 0000775 0000000 0000000 00000000000 12625565062 0014735 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/a/a.go 0000664 0000000 0000000 00000000031 12625565062 0015476 0 ustar 00root root 0000000 0000000 package a
const A = "A"
gb-0.3.2/testdata/src/a/a_test.go 0000664 0000000 0000000 00000000106 12625565062 0016540 0 ustar 00root root 0000000 0000000 package a
import "testing"
func TestA(t *testing.T) {
t.Log("A")
}
gb-0.3.2/testdata/src/aprime/ 0000775 0000000 0000000 00000000000 12625565062 0015772 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/aprime/a.go 0000664 0000000 0000000 00000000031 12625565062 0016533 0 ustar 00root root 0000000 0000000 package a
const A = "A"
gb-0.3.2/testdata/src/b/ 0000775 0000000 0000000 00000000000 12625565062 0014736 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/b/b.go 0000664 0000000 0000000 00000000070 12625565062 0015503 0 ustar 00root root 0000000 0000000 package main
import "a"
func main() {
println(a.A)
}
gb-0.3.2/testdata/src/blank/ 0000775 0000000 0000000 00000000000 12625565062 0015604 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/blank/.turd 0000664 0000000 0000000 00000000000 12625565062 0016551 0 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/c/ 0000775 0000000 0000000 00000000000 12625565062 0014737 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/c/c.go 0000664 0000000 0000000 00000000100 12625565062 0015477 0 ustar 00root root 0000000 0000000 package c
import "a"
import "d.v1"
const C = a.A
var D = d.D
gb-0.3.2/testdata/src/c/c_test.go 0000664 0000000 0000000 00000000104 12625565062 0016542 0 ustar 00root root 0000000 0000000 package c
import "testing"
func TestC(t *testing.T) {
t.Log(C)
}
gb-0.3.2/testdata/src/cgomain/ 0000775 0000000 0000000 00000000000 12625565062 0016132 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/cgomain/main.go 0000664 0000000 0000000 00000000433 12625565062 0017405 0 ustar 00root root 0000000 0000000 package main
// typedef int (*intFunc) ();
//
// int
// bridge_int_func(intFunc f)
// {
// return f();
// }
//
// int fortytwo()
// {
// return 42;
// }
import "C"
import "fmt"
func main() {
f := C.intFunc(C.fortytwo)
fmt.Println(int(C.bridge_int_func(f)))
// Output: 42
}
gb-0.3.2/testdata/src/cgoonlynotest/ 0000775 0000000 0000000 00000000000 12625565062 0017424 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/cgoonlynotest/cgoonly.go 0000664 0000000 0000000 00000000237 12625565062 0021427 0 ustar 00root root 0000000 0000000 package cgoonly
/*
int add(int x, int y) {
return x+y;
};
*/
import "C"
func Add(x, y int) int {
return int(C.add(_Ctype_int(x), _Ctype_int(y)))
}
gb-0.3.2/testdata/src/cgotest/ 0000775 0000000 0000000 00000000000 12625565062 0016165 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/cgotest/basic.go 0000664 0000000 0000000 00000005600 12625565062 0017576 0 ustar 00root root 0000000 0000000 // Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Basic test cases for cgo.
package cgotest
/*
#include
#include
#include
#include
#define SHIFT(x, y) ((x)<<(y))
#define KILO SHIFT(1, 10)
#define UINT32VAL 0xc008427bU
enum E {
Enum1 = 1,
Enum2 = 2,
};
typedef unsigned char cgo_uuid_t[20];
void uuid_generate(cgo_uuid_t x) {
x[0] = 0;
}
struct S {
int x;
};
extern enum E myConstFunc(struct S* const ctx, int const id, struct S **const filter);
enum E myConstFunc(struct S *const ctx, int const id, struct S **const filter) { return 0; }
// issue 1222
typedef union {
long align;
} xxpthread_mutex_t;
struct ibv_async_event {
union {
int x;
} element;
};
struct ibv_context {
xxpthread_mutex_t mutex;
};
int add(int x, int y) {
return x+y;
};
*/
import "C"
import (
"runtime"
"syscall"
"testing"
"unsafe"
)
const EINVAL = C.EINVAL /* test #define */
var KILO = C.KILO
func uuidgen() {
var uuid C.cgo_uuid_t
C.uuid_generate(&uuid[0])
}
func Strtol(s string, base int) (int, error) {
p := C.CString(s)
n, err := C.strtol(p, nil, C.int(base))
C.free(unsafe.Pointer(p))
return int(n), err
}
func Atol(s string) int {
p := C.CString(s)
n := C.atol(p)
C.free(unsafe.Pointer(p))
return int(n)
}
func testConst(t *testing.T) {
C.myConstFunc(nil, 0, nil)
}
func testEnum(t *testing.T) {
if C.Enum1 != 1 || C.Enum2 != 2 {
t.Error("bad enum", C.Enum1, C.Enum2)
}
}
func testAtol(t *testing.T) {
l := Atol("123")
if l != 123 {
t.Error("Atol 123: ", l)
}
}
func testErrno(t *testing.T) {
p := C.CString("no-such-file")
m := C.CString("r")
f, err := C.fopen(p, m)
C.free(unsafe.Pointer(p))
C.free(unsafe.Pointer(m))
if err == nil {
C.fclose(f)
t.Fatalf("C.fopen: should fail")
}
if err != syscall.ENOENT {
t.Fatalf("C.fopen: unexpected error: %v", err)
}
}
func testMultipleAssign(t *testing.T) {
p := C.CString("234")
n, m := C.strtol(p, nil, 345), C.strtol(p, nil, 10)
if runtime.GOOS == "openbsd" {
// Bug in OpenBSD strtol(3) - base > 36 succeeds.
if (n != 0 && n != 239089) || m != 234 {
t.Fatal("Strtol x2: ", n, m)
}
} else if n != 0 || m != 234 {
t.Fatal("Strtol x2: ", n, m)
}
C.free(unsafe.Pointer(p))
}
var (
cuint = (C.uint)(0)
culong C.ulong
cchar C.char
)
type Context struct {
ctx *C.struct_ibv_context
}
func benchCgoCall(b *testing.B) {
const x = C.int(2)
const y = C.int(3)
for i := 0; i < b.N; i++ {
C.add(x, y)
}
}
// Issue 2470.
func testUnsignedInt(t *testing.T) {
a := (int64)(C.UINT32VAL)
b := (int64)(0xc008427b)
if a != b {
t.Errorf("Incorrect unsigned int - got %x, want %x", a, b)
}
}
// Static (build-time) test that syntax traversal visits all operands of s[i:j:k].
func sliceOperands(array [2000]int) {
_ = array[C.KILO:C.KILO:C.KILO] // no type error
}
gb-0.3.2/testdata/src/cgotest/cgo_test.go 0000664 0000000 0000000 00000007336 12625565062 0020334 0 ustar 00root root 0000000 0000000 // Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package cgotest
import "testing"
// The actual test functions are in non-_test.go files
// so that they can use cgo (import "C").
// These wrappers are here for gotest to find.
// func TestAlign(t *testing.T) { testAlign(t) }
func TestConst(t *testing.T) { testConst(t) }
func TestEnum(t *testing.T) { testEnum(t) }
func TestAtol(t *testing.T) { testAtol(t) }
func TestErrno(t *testing.T) { testErrno(t) }
func TestMultipleAssign(t *testing.T) { testMultipleAssign(t) }
func TestUnsignedInt(t *testing.T) { testUnsignedInt(t) }
/*func TestCallback(t *testing.T) { testCallback(t) }
func TestCallbackGC(t *testing.T) { testCallbackGC(t) }
func TestCallbackPanic(t *testing.T) { testCallbackPanic(t) }
func TestCallbackPanicLoop(t *testing.T) { testCallbackPanicLoop(t) }
func TestCallbackPanicLocked(t *testing.T) { testCallbackPanicLocked(t) }
func TestPanicFromC(t *testing.T) { testPanicFromC(t) }
func TestZeroArgCallback(t *testing.T) { testZeroArgCallback(t) }
func TestBlocking(t *testing.T) { testBlocking(t) }
func Test1328(t *testing.T) { test1328(t) }
func TestParallelSleep(t *testing.T) { testParallelSleep(t) }
func TestSetEnv(t *testing.T) { testSetEnv(t) }
func TestHelpers(t *testing.T) { testHelpers(t) }
func TestLibgcc(t *testing.T) { testLibgcc(t) }
func Test1635(t *testing.T) { test1635(t) }
func TestPrintf(t *testing.T) { testPrintf(t) }
func Test4029(t *testing.T) { test4029(t) }
func TestBoolAlign(t *testing.T) { testBoolAlign(t) }
func Test3729(t *testing.T) { test3729(t) }
func Test3775(t *testing.T) { test3775(t) }
func TestCthread(t *testing.T) { testCthread(t) }
func TestCallbackCallers(t *testing.T) { testCallbackCallers(t) }
func Test5227(t *testing.T) { test5227(t) }
func TestCflags(t *testing.T) { testCflags(t) }
func Test5337(t *testing.T) { test5337(t) }
func Test5548(t *testing.T) { test5548(t) }
func Test5603(t *testing.T) { test5603(t) }
func Test6833(t *testing.T) { test6833(t) }
func Test3250(t *testing.T) { test3250(t) }
func TestCallbackStack(t *testing.T) { testCallbackStack(t) }
func TestFpVar(t *testing.T) { testFpVar(t) }
func Test4339(t *testing.T) { test4339(t) }
func Test6390(t *testing.T) { test6390(t) }
func Test5986(t *testing.T) { test5986(t) }
func Test7665(t *testing.T) { test7665(t) }
func TestNaming(t *testing.T) { testNaming(t) }
func Test7560(t *testing.T) { test7560(t) }
func Test5242(t *testing.T) { test5242(t) }
func Test8092(t *testing.T) { test8092(t) }
func Test7978(t *testing.T) { test7978(t) }
func Test8694(t *testing.T) { test8694(t) }
func Test8517(t *testing.T) { test8517(t) }
func Test8811(t *testing.T) { test8811(t) }
func TestReturnAfterGrow(t *testing.T) { testReturnAfterGrow(t) }
func TestReturnAfterGrowFromGo(t *testing.T) { testReturnAfterGrowFromGo(t) }
func Test9026(t *testing.T) { test9026(t) }
func Test9557(t *testing.T) { test9557(t) }
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
*/
gb-0.3.2/testdata/src/cmd/ 0000775 0000000 0000000 00000000000 12625565062 0015260 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/cmd/f/ 0000775 0000000 0000000 00000000000 12625565062 0015505 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/cmd/f/main.go 0000664 0000000 0000000 00000000032 12625565062 0016753 0 ustar 00root root 0000000 0000000 package main
const X = 7
gb-0.3.2/testdata/src/cmd/f/main_test.go 0000664 0000000 0000000 00000000141 12625565062 0020013 0 ustar 00root root 0000000 0000000 package main
import "testing"
func TestX(t *testing.T) {
if X != 7 {
t.Fatal("X != 7")
}
}
gb-0.3.2/testdata/src/cppmain/ 0000775 0000000 0000000 00000000000 12625565062 0016144 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/cppmain/main.cpp 0000664 0000000 0000000 00000000267 12625565062 0017601 0 ustar 00root root 0000000 0000000 typedef int (*intFunc) ();
extern "C" int bridge_int_func(intFunc f);
extern "C" int fortytwo();
int
bridge_int_func(intFunc f)
{
return f();
}
int fortytwo()
{
return 42;
}
gb-0.3.2/testdata/src/cppmain/main.go 0000664 0000000 0000000 00000000335 12625565062 0017420 0 ustar 00root root 0000000 0000000 package main
/*
typedef int (*intFunc) ();
int bridge_int_func(intFunc f);
int fortytwo();
*/
import "C"
import "fmt"
func main() {
f := C.intFunc(C.fortytwo)
fmt.Println(int(C.bridge_int_func(f)))
// Output: 42
}
gb-0.3.2/testdata/src/cycle0/ 0000775 0000000 0000000 00000000000 12625565062 0015674 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/cycle0/cycle.go 0000664 0000000 0000000 00000000037 12625565062 0017322 0 ustar 00root root 0000000 0000000 package cycle
import "cycle0"
gb-0.3.2/testdata/src/cycle1/ 0000775 0000000 0000000 00000000000 12625565062 0015675 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/cycle1/a/ 0000775 0000000 0000000 00000000000 12625565062 0016115 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/cycle1/a/a.go 0000664 0000000 0000000 00000000042 12625565062 0016660 0 ustar 00root root 0000000 0000000 package cyclea
import "cycle1/b"
gb-0.3.2/testdata/src/cycle1/b/ 0000775 0000000 0000000 00000000000 12625565062 0016116 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/cycle1/b/b.go 0000664 0000000 0000000 00000000042 12625565062 0016662 0 ustar 00root root 0000000 0000000 package cycleb
import "cycle1/b"
gb-0.3.2/testdata/src/cycle2/ 0000775 0000000 0000000 00000000000 12625565062 0015676 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/cycle2/a/ 0000775 0000000 0000000 00000000000 12625565062 0016116 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/cycle2/a/a.go 0000664 0000000 0000000 00000000043 12625565062 0016662 0 ustar 00root root 0000000 0000000 package cycle2a
import "cycle2/b"
gb-0.3.2/testdata/src/cycle2/b/ 0000775 0000000 0000000 00000000000 12625565062 0016117 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/cycle2/b/b.go 0000664 0000000 0000000 00000000043 12625565062 0016664 0 ustar 00root root 0000000 0000000 package cycle2b
import "cycle2/c"
gb-0.3.2/testdata/src/cycle2/c/ 0000775 0000000 0000000 00000000000 12625565062 0016120 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/cycle2/c/c.go 0000664 0000000 0000000 00000000043 12625565062 0016666 0 ustar 00root root 0000000 0000000 package cycle2c
import "cycle2/d"
gb-0.3.2/testdata/src/cycle2/d/ 0000775 0000000 0000000 00000000000 12625565062 0016121 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/cycle2/d/d.go 0000664 0000000 0000000 00000000043 12625565062 0016670 0 ustar 00root root 0000000 0000000 package cycle2d
import "cycle2/a"
gb-0.3.2/testdata/src/d.v1/ 0000775 0000000 0000000 00000000000 12625565062 0015265 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/d.v1/d.go 0000664 0000000 0000000 00000000027 12625565062 0016036 0 ustar 00root root 0000000 0000000 package d
var D = "d"
gb-0.3.2/testdata/src/e/ 0000775 0000000 0000000 00000000000 12625565062 0014741 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/e/e.go 0000664 0000000 0000000 00000000031 12625565062 0015506 0 ustar 00root root 0000000 0000000 package e
const E = "e"
gb-0.3.2/testdata/src/e/e_test.go 0000664 0000000 0000000 00000000177 12625565062 0016560 0 ustar 00root root 0000000 0000000 package e
import "testing"
import "f" // only imported in internal test scope
func TestE(t *testing.T) {
t.Log(f.F > 0.9)
}
gb-0.3.2/testdata/src/external_only_test/ 0000775 0000000 0000000 00000000000 12625565062 0020437 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/external_only_test/x_test.go 0000664 0000000 0000000 00000000126 12625565062 0022273 0 ustar 00root root 0000000 0000000 package x_test
import "testing"
func TestT(t *testing.T) { t.Log("all good brah") }
gb-0.3.2/testdata/src/extest/ 0000775 0000000 0000000 00000000000 12625565062 0016031 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/extest/q.go 0000664 0000000 0000000 00000000032 12625565062 0016613 0 ustar 00root root 0000000 0000000 package extest
var V = 1
gb-0.3.2/testdata/src/extest/q_test.go 0000664 0000000 0000000 00000000166 12625565062 0017662 0 ustar 00root root 0000000 0000000 package extest
import "testing"
func TestV(t *testing.T) {
if V != 0 {
t.Fatalf("V: got %v, expected 0", V)
}
}
gb-0.3.2/testdata/src/extest/q_test_test.go 0000664 0000000 0000000 00000000104 12625565062 0020711 0 ustar 00root root 0000000 0000000 package extest_test
import "extest"
func init() {
extest.V = 0
}
gb-0.3.2/testdata/src/extestonly/ 0000775 0000000 0000000 00000000000 12625565062 0016733 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/extestonly/x_test.go 0000664 0000000 0000000 00000000124 12625565062 0020565 0 ustar 00root root 0000000 0000000 package extestonly_test
import "testing"
func TestT(t *testing.T) { t.Log("ok") }
gb-0.3.2/testdata/src/f/ 0000775 0000000 0000000 00000000000 12625565062 0014742 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/f/f.go 0000664 0000000 0000000 00000000031 12625565062 0015510 0 ustar 00root root 0000000 0000000 package f
const F = 1.0
gb-0.3.2/testdata/src/g/ 0000775 0000000 0000000 00000000000 12625565062 0014743 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/g/export_test.go 0000664 0000000 0000000 00000000045 12625565062 0017651 0 ustar 00root root 0000000 0000000 package g
const WHATEVER = whatever
gb-0.3.2/testdata/src/g/g.go 0000664 0000000 0000000 00000000036 12625565062 0015517 0 ustar 00root root 0000000 0000000 package g
const whatever = 0
gb-0.3.2/testdata/src/g/g_test.go 0000664 0000000 0000000 00000000144 12625565062 0016556 0 ustar 00root root 0000000 0000000 package g_test
import "g"
import "testing"
func TestWhatever(t *testing.T) {
t.Log(g.WHATEVER)
}
gb-0.3.2/testdata/src/h/ 0000775 0000000 0000000 00000000000 12625565062 0014744 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/h/h.go 0000664 0000000 0000000 00000000136 12625565062 0015522 0 ustar 00root root 0000000 0000000 package h
import "blank" // go/build.NoGoErr
const b = blank.Blank // should be build error
gb-0.3.2/testdata/src/ldflags/ 0000775 0000000 0000000 00000000000 12625565062 0016131 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/ldflags/ldflags.go 0000664 0000000 0000000 00000000072 12625565062 0020073 0 ustar 00root root 0000000 0000000 package ldflags
var gitRevision string // set by linker
gb-0.3.2/testdata/src/ldflags/ldflags_test.go 0000664 0000000 0000000 00000000375 12625565062 0021140 0 ustar 00root root 0000000 0000000 package ldflags
import "testing"
var gitTagInfo string // set by linker
func TestLdflags(t *testing.T) {
if gitTagInfo != "banana" {
t.Error("gitTagInfo:", gitTagInfo)
}
if gitRevision != "f7926af2" {
t.Error("gitRevision:", gitRevision)
}
}
gb-0.3.2/testdata/src/main/ 0000775 0000000 0000000 00000000000 12625565062 0015441 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/main/main.go 0000664 0000000 0000000 00000000015 12625565062 0016710 0 ustar 00root root 0000000 0000000 package main
gb-0.3.2/testdata/src/mainnoruntime/ 0000775 0000000 0000000 00000000000 12625565062 0017402 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/mainnoruntime/main.go 0000664 0000000 0000000 00000000260 12625565062 0020653 0 ustar 00root root 0000000 0000000 package main
// no imports, so nothing imports runtime directly or transitively
// however the runtime contains the code for println.
func main() {
println("hello world")
}
gb-0.3.2/testdata/src/nested/ 0000775 0000000 0000000 00000000000 12625565062 0015777 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/nested/a/ 0000775 0000000 0000000 00000000000 12625565062 0016217 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/nested/a/a.go 0000664 0000000 0000000 00000000031 12625565062 0016760 0 ustar 00root root 0000000 0000000 package a
const A = `a`
gb-0.3.2/testdata/src/nested/b/ 0000775 0000000 0000000 00000000000 12625565062 0016220 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/nested/b/b.go 0000664 0000000 0000000 00000000031 12625565062 0016762 0 ustar 00root root 0000000 0000000 package b
const A = `b`
gb-0.3.2/testdata/src/notestfiles/ 0000775 0000000 0000000 00000000000 12625565062 0017054 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/notestfiles/notest.go 0000664 0000000 0000000 00000000036 12625565062 0020716 0 ustar 00root root 0000000 0000000 package notest
const X = "y"
gb-0.3.2/testdata/src/tags1/ 0000775 0000000 0000000 00000000000 12625565062 0015534 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/tags1/t.go 0000664 0000000 0000000 00000000051 12625565062 0016322 0 ustar 00root root 0000000 0000000 // +build !x
package tags1
const X = 1
gb-0.3.2/testdata/src/tags2/ 0000775 0000000 0000000 00000000000 12625565062 0015535 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/tags2/t.go 0000664 0000000 0000000 00000000050 12625565062 0016322 0 ustar 00root root 0000000 0000000 // +build x
package tags2
const X = 2
gb-0.3.2/testdata/src/testflags/ 0000775 0000000 0000000 00000000000 12625565062 0016511 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/testflags/testflags.go 0000664 0000000 0000000 00000000022 12625565062 0021026 0 ustar 00root root 0000000 0000000 package testflags
gb-0.3.2/testdata/src/testflags/testflags_test.go 0000664 0000000 0000000 00000000355 12625565062 0022076 0 ustar 00root root 0000000 0000000 package testflags
import (
"flag"
"testing"
)
var debug bool
func init() {
flag.BoolVar(&debug, "debug", false, "Enable debug output.")
flag.Parse()
}
func TestDebug(t *testing.T) {
if !debug {
t.Error("debug not true!")
}
}
gb-0.3.2/testdata/src/testonly/ 0000775 0000000 0000000 00000000000 12625565062 0016376 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/testonly/x_test.go 0000664 0000000 0000000 00000000115 12625565062 0020230 0 ustar 00root root 0000000 0000000 package testonly
import "testing"
func TestT(t *testing.T) { t.Log("ok") }
gb-0.3.2/testdata/src/x/ 0000775 0000000 0000000 00000000000 12625565062 0014764 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/x/x.go 0000664 0000000 0000000 00000000026 12625565062 0015560 0 ustar 00root root 0000000 0000000 package x
import "y"
gb-0.3.2/testdata/src/y/ 0000775 0000000 0000000 00000000000 12625565062 0014765 5 ustar 00root root 0000000 0000000 gb-0.3.2/testdata/src/y/y.go 0000664 0000000 0000000 00000000026 12625565062 0015562 0 ustar 00root root 0000000 0000000 package y
import "x"
gb-0.3.2/vendor/ 0000775 0000000 0000000 00000000000 12625565062 0013412 5 ustar 00root root 0000000 0000000 gb-0.3.2/vendor/_testdata/ 0000775 0000000 0000000 00000000000 12625565062 0015362 5 ustar 00root root 0000000 0000000 gb-0.3.2/vendor/_testdata/src/ 0000775 0000000 0000000 00000000000 12625565062 0016151 5 ustar 00root root 0000000 0000000 gb-0.3.2/vendor/_testdata/src/github.com/ 0000775 0000000 0000000 00000000000 12625565062 0020210 5 ustar 00root root 0000000 0000000 gb-0.3.2/vendor/_testdata/src/github.com/foo/ 0000775 0000000 0000000 00000000000 12625565062 0020773 5 ustar 00root root 0000000 0000000 gb-0.3.2/vendor/_testdata/src/github.com/foo/bar/ 0000775 0000000 0000000 00000000000 12625565062 0021537 5 ustar 00root root 0000000 0000000 gb-0.3.2/vendor/_testdata/src/github.com/foo/bar/main.go 0000664 0000000 0000000 00000000413 12625565062 0023010 0 ustar 00root root 0000000 0000000 package main
import (
"fmt"
"github.com/quux/flobble"
// "bitbucket.org/fwoop/ftang" // commented out, this is deliberate
moo "github.com/lypo/moopo"
)
import "github.com/hoo/wuu"
func main() {
fmt.Println(flobble.Q)
fmt.Prinln(moo.Q)
fmt.Println(wuu.Q)
}
gb-0.3.2/vendor/_testdata/vendor/ 0000775 0000000 0000000 00000000000 12625565062 0016657 5 ustar 00root root 0000000 0000000 gb-0.3.2/vendor/_testdata/vendor/src/ 0000775 0000000 0000000 00000000000 12625565062 0017446 5 ustar 00root root 0000000 0000000 gb-0.3.2/vendor/_testdata/vendor/src/bitbucket.org/ 0000775 0000000 0000000 00000000000 12625565062 0022210 5 ustar 00root root 0000000 0000000 gb-0.3.2/vendor/_testdata/vendor/src/bitbucket.org/fwoop/ 0000775 0000000 0000000 00000000000 12625565062 0023342 5 ustar 00root root 0000000 0000000 gb-0.3.2/vendor/_testdata/vendor/src/bitbucket.org/fwoop/ftang/ 0000775 0000000 0000000 00000000000 12625565062 0024441 5 ustar 00root root 0000000 0000000 gb-0.3.2/vendor/_testdata/vendor/src/bitbucket.org/fwoop/ftang/kthulu.go 0000664 0000000 0000000 00000000042 12625565062 0026300 0 ustar 00root root 0000000 0000000 package ftang
const CAT = "ack!"
gb-0.3.2/vendor/_testdata/vendor/src/github.com/ 0000775 0000000 0000000 00000000000 12625565062 0021505 5 ustar 00root root 0000000 0000000 gb-0.3.2/vendor/_testdata/vendor/src/github.com/hoo/ 0000775 0000000 0000000 00000000000 12625565062 0022272 5 ustar 00root root 0000000 0000000 gb-0.3.2/vendor/_testdata/vendor/src/github.com/hoo/wuu/ 0000775 0000000 0000000 00000000000 12625565062 0023112 5 ustar 00root root 0000000 0000000 gb-0.3.2/vendor/_testdata/vendor/src/github.com/hoo/wuu/goo.go 0000664 0000000 0000000 00000000035 12625565062 0024223 0 ustar 00root root 0000000 0000000 package wuu
const Q = "hey"
gb-0.3.2/vendor/_testdata/vendor/src/github.com/lypo/ 0000775 0000000 0000000 00000000000 12625565062 0022470 5 ustar 00root root 0000000 0000000 gb-0.3.2/vendor/_testdata/vendor/src/github.com/lypo/moopo/ 0000775 0000000 0000000 00000000000 12625565062 0023621 5 ustar 00root root 0000000 0000000 gb-0.3.2/vendor/_testdata/vendor/src/github.com/lypo/moopo/tropo.go 0000664 0000000 0000000 00000000036 12625565062 0025312 0 ustar 00root root 0000000 0000000 package moopo
const Q = "hi"
gb-0.3.2/vendor/_testdata/vendor/src/github.com/quux/ 0000775 0000000 0000000 00000000000 12625565062 0022507 5 ustar 00root root 0000000 0000000 gb-0.3.2/vendor/_testdata/vendor/src/github.com/quux/flobble/ 0000775 0000000 0000000 00000000000 12625565062 0024114 5 ustar 00root root 0000000 0000000 gb-0.3.2/vendor/_testdata/vendor/src/github.com/quux/flobble/wobble.go 0000664 0000000 0000000 00000000043 12625565062 0025712 0 ustar 00root root 0000000 0000000 package flobble
const Q = "hello"
gb-0.3.2/vendor/copy.go 0000664 0000000 0000000 00000002646 12625565062 0014723 0 ustar 00root root 0000000 0000000 package vendor
import (
"fmt"
"io"
"os"
"path/filepath"
"strings"
"github.com/constabulary/gb/fileutils"
)
const debugCopypath = true
const debugCopyfile = false
// Copypath copies the contents of src to dst, excluding any file or
// directory that starts with a period.
func Copypath(dst string, src string) error {
err := filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if strings.HasPrefix(filepath.Base(path), ".") {
if info.IsDir() {
return filepath.SkipDir
}
return nil
}
if info.IsDir() {
return nil
}
if info.Mode()&os.ModeSymlink != 0 {
if debugCopypath {
fmt.Printf("skipping symlink: %v\n", path)
}
return nil
}
dst := filepath.Join(dst, path[len(src):])
return copyfile(dst, path)
})
if err != nil {
// if there was an error during copying, remove the partial copy.
fileutils.RemoveAll(dst)
}
return err
}
func copyfile(dst, src string) error {
err := mkdir(filepath.Dir(dst))
if err != nil {
return fmt.Errorf("copyfile: mkdirall: %v", err)
}
r, err := os.Open(src)
if err != nil {
return fmt.Errorf("copyfile: open(%q): %v", src, err)
}
defer r.Close()
w, err := os.Create(dst)
if err != nil {
return fmt.Errorf("copyfile: create(%q): %v", dst, err)
}
defer w.Close()
if debugCopyfile {
fmt.Printf("copyfile(dst: %v, src: %v)\n", dst, src)
}
_, err = io.Copy(w, r)
return err
}
gb-0.3.2/vendor/depset.go 0000664 0000000 0000000 00000004363 12625565062 0015233 0 ustar 00root root 0000000 0000000 package vendor
import (
"fmt"
"go/build"
"os"
"path/filepath"
"strings"
)
// Pkg describes a Go package.
type Pkg struct {
*Depset
*build.Package
}
// Depset describes a set of related Go packages.
type Depset struct {
Root string
Prefix string
Pkgs map[string]*Pkg
}
// LoadPaths returns a map of paths to Depsets.
func LoadPaths(paths ...struct{ Root, Prefix string }) (map[string]*Depset, error) {
m := make(map[string]*Depset)
for _, p := range paths {
set, err := LoadTree(p.Root, p.Prefix)
if err != nil {
return nil, err
}
m[set.Root] = set
}
return m, nil
}
// LoadTree parses a tree of source files into a map of *pkgs.
func LoadTree(root string, prefix string) (*Depset, error) {
d := Depset{
Root: root,
Prefix: prefix,
Pkgs: make(map[string]*Pkg),
}
fn := func(dir string, fi os.FileInfo) error {
importpath := filepath.Join(prefix, dir[len(root)+1:])
// if we're at the root of a tree, skip it
if importpath == "" {
return nil
}
p, err := loadPackage(&d, dir)
if err != nil {
if _, ok := err.(*build.NoGoError); ok {
return nil
}
return fmt.Errorf("loadPackage(%q, %q): %v", dir, importpath, err)
}
p.ImportPath = filepath.ToSlash(importpath)
if p != nil {
d.Pkgs[p.ImportPath] = p
}
return nil
}
// handle root of the tree
fi, err := os.Stat(root)
if err != nil {
return nil, err
}
if err := fn(root+string(filepath.Separator), fi); err != nil {
return nil, err
}
// walk sub directories
err = eachDir(root, fn)
return &d, err
}
func loadPackage(d *Depset, dir string) (*Pkg, error) {
p := Pkg{
Depset: d,
}
var err error
// expolit local import logic
p.Package, err = build.ImportDir(dir, build.ImportComment)
return &p, err
}
func eachDir(dir string, fn func(string, os.FileInfo) error) error {
f, err := os.Open(dir)
if err != nil {
return err
}
defer f.Close()
files, err := f.Readdir(-1)
for _, fi := range files {
if !fi.IsDir() {
continue
}
if strings.HasPrefix(fi.Name(), "_") || strings.HasPrefix(fi.Name(), ".") || fi.Name() == "testdata" {
continue
}
path := filepath.Join(dir, fi.Name())
if err := fn(path, fi); err != nil {
return err
}
if err := eachDir(path, fn); err != nil {
return err
}
}
return nil
}
gb-0.3.2/vendor/discovery.go 0000664 0000000 0000000 00000004175 12625565062 0015757 0 ustar 00root root 0000000 0000000 // Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package vendor
import (
"encoding/xml"
"fmt"
"io"
"strings"
)
// charsetReader returns a reader for the given charset. Currently
// it only supports UTF-8 and ASCII. Otherwise, it returns a meaningful
// error which is printed by go get, so the user can find why the package
// wasn't downloaded if the encoding is not supported. Note that, in
// order to reduce potential errors, ASCII is treated as UTF-8 (i.e. characters
// greater than 0x7f are not rejected).
func charsetReader(charset string, input io.Reader) (io.Reader, error) {
switch strings.ToLower(charset) {
case "ascii":
return input, nil
default:
return nil, fmt.Errorf("can't decode XML document using charset %q", charset)
}
}
type metaImport struct {
Prefix, VCS, RepoRoot string
}
// parseMetaGoImports returns meta imports from the HTML in r.
// Parsing ends at the end of the section or the beginning of the .
func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) {
d := xml.NewDecoder(r)
d.CharsetReader = charsetReader
d.Strict = false
var t xml.Token
for {
t, err = d.Token()
if err != nil {
if err == io.EOF {
err = nil
}
return
}
if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") {
return
}
if e, ok := t.(xml.EndElement); ok && strings.EqualFold(e.Name.Local, "head") {
return
}
e, ok := t.(xml.StartElement)
if !ok || !strings.EqualFold(e.Name.Local, "meta") {
continue
}
if attrValue(e.Attr, "name") != "go-import" {
continue
}
if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 {
imports = append(imports, metaImport{
Prefix: f[0],
VCS: f[1],
RepoRoot: f[2],
})
}
}
}
// attrValue returns the attribute value for the case-insensitive key
// `name', or the empty string if nothing is found.
func attrValue(attrs []xml.Attr, name string) string {
for _, a := range attrs {
if strings.EqualFold(a.Name.Local, name) {
return a.Value
}
}
return ""
}
gb-0.3.2/vendor/imports.go 0000664 0000000 0000000 00000004717 12625565062 0015447 0 ustar 00root root 0000000 0000000 package vendor
import (
"fmt"
"go/parser"
"go/token"
"io"
"net/http"
"os"
"path/filepath"
"strings"
)
// ParseImports parses Go packages from a specific root returning a set of import paths.
func ParseImports(root string) (map[string]bool, error) {
pkgs := make(map[string]bool)
var walkFn = func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
name := info.Name()
if strings.HasPrefix(name, ".") || strings.HasPrefix(name, "_") || name == "testdata" {
return filepath.SkipDir
}
return nil
}
if filepath.Ext(path) != ".go" { // Parse only go source files
return nil
}
fs := token.NewFileSet()
f, err := parser.ParseFile(fs, path, nil, parser.ImportsOnly)
if err != nil {
return err
}
for _, s := range f.Imports {
p := strings.Replace(s.Path.Value, "\"", "", -1)
if !contains(stdlib, p) {
pkgs[p] = true
}
}
return nil
}
err := filepath.Walk(root, walkFn)
return pkgs, err
}
// FetchMetadata fetchs the remote metadata for path.
func FetchMetadata(path string, insecure bool) (rc io.ReadCloser, err error) {
defer func() {
if err != nil {
err = fmt.Errorf("unable to determine remote metadata protocol: %s", err)
}
}()
// try https first
rc, err = fetchMetadata("https", path)
if err == nil {
return
}
// try http if supported
if insecure {
rc, err = fetchMetadata("http", path)
}
return
}
func fetchMetadata(scheme, path string) (io.ReadCloser, error) {
url := fmt.Sprintf("%s://%s?go-get=1", scheme, path)
switch scheme {
case "https", "http":
resp, err := http.Get(url)
if err != nil {
return nil, fmt.Errorf("failed to access url %q", url)
}
return resp.Body, nil
default:
return nil, fmt.Errorf("unknown remote protocol scheme: %q", scheme)
}
}
// ParseMetadata fetchs and decodes remote metadata for path.
func ParseMetadata(path string, insecure bool) (string, string, string, error) {
rc, err := FetchMetadata(path, insecure)
if err != nil {
return "", "", "", err
}
defer rc.Close()
imports, err := parseMetaGoImports(rc)
if err != nil {
return "", "", "", err
}
match := -1
for i, im := range imports {
if !strings.HasPrefix(path, im.Prefix) {
continue
}
if match != -1 {
return "", "", "", fmt.Errorf("multiple meta tags match import path %q", path)
}
match = i
}
if match == -1 {
return "", "", "", fmt.Errorf("go-import metadata not found")
}
return imports[match].Prefix, imports[match].VCS, imports[match].RepoRoot, nil
}
gb-0.3.2/vendor/imports_test.go 0000664 0000000 0000000 00000010225 12625565062 0016475 0 ustar 00root root 0000000 0000000 package vendor
import (
"bytes"
"fmt"
"io"
"os"
"path/filepath"
"reflect"
"testing"
)
func TestParseImports(t *testing.T) {
root := filepath.Join(getwd(t), "_testdata", "src")
got, err := ParseImports(root)
if err != nil {
t.Fatalf("ParseImports(%q): %v", root, err)
}
want := set("github.com/quux/flobble", "github.com/lypo/moopo", "github.com/hoo/wuu")
if !reflect.DeepEqual(got, want) {
t.Fatalf("ParseImports(%q): want: %v, got %v", root, want, got)
}
}
func TestFetchMetadata(t *testing.T) {
if testing.Short() {
t.Skipf("skipping network tests in -short mode")
}
type testParams struct {
path string
want string
insecure bool
}
tests := []testParams{{
path: "golang.org/x/tools/cmd/godoc",
want: `
Nothing to see here; move along.
`,
}, {
path: "gopkg.in/check.v1",
want: `
go get gopkg.in/check.v1
`,
}}
for _, tt := range tests {
r, err := FetchMetadata(tt.path, tt.insecure)
if err != nil {
t.Error(err)
continue
}
var buf bytes.Buffer
if _, err := io.Copy(&buf, r); err != nil {
t.Error(err)
r.Close()
continue
}
r.Close()
got := buf.String()
if got != tt.want {
t.Errorf("FetchMetadata(%q): want %q, got %q", tt.path, tt.want, got)
}
}
// Test for error catch.
errTests := []testParams{{
path: "any.inaccessible.server/the.project",
want: `unable to determine remote metadata protocol: failed to access url "http://any.inaccessible.server/the.project?go-get=1"`,
insecure: true,
}, {
path: "any.inaccessible.server/the.project",
want: `unable to determine remote metadata protocol: failed to access url "https://any.inaccessible.server/the.project?go-get=1"`,
insecure: false,
}}
for _, ett := range errTests {
r, err := FetchMetadata(ett.path, ett.insecure)
if err == nil {
t.Errorf("Access to url %q without any error, but the error should be happen.", ett.path)
if r != nil {
r.Close()
}
continue
}
got := err.Error()
if got != ett.want {
t.Errorf("FetchMetadata(%q): want %q, got %q", ett.path, ett.want, got)
}
}
}
func TestParseMetadata(t *testing.T) {
if testing.Short() {
t.Skipf("skipping network tests in -short mode")
}
tests := []struct {
path string
importpath string
vcs string
reporoot string
insecure bool
err error
}{{
path: "golang.org/x/tools/cmd/godoc",
importpath: "golang.org/x/tools",
vcs: "git",
reporoot: "https://go.googlesource.com/tools",
}, {
path: "gopkg.in/check.v1",
importpath: "gopkg.in/check.v1",
vcs: "git",
reporoot: "https://gopkg.in/check.v1",
}, {
path: "gopkg.in/mgo.v2/bson",
importpath: "gopkg.in/mgo.v2",
vcs: "git",
reporoot: "https://gopkg.in/mgo.v2",
}, {
path: "speter.net/go/exp",
err: fmt.Errorf("go-import metadata not found"),
}}
for _, tt := range tests {
importpath, vcs, reporoot, err := ParseMetadata(tt.path, tt.insecure)
if !reflect.DeepEqual(err, tt.err) {
t.Error(err)
continue
}
if importpath != tt.importpath || vcs != tt.vcs || reporoot != tt.reporoot {
t.Errorf("ParseMetadata(%q): want %s %s %s, got %s %s %s ", tt.path, tt.importpath, tt.vcs, tt.reporoot, importpath, vcs, reporoot)
}
}
}
func getwd(t *testing.T) string {
cwd, err := os.Getwd()
if err != nil {
t.Fatal(err)
}
return cwd
}
gb-0.3.2/vendor/manifest.go 0000664 0000000 0000000 00000010017 12625565062 0015546 0 ustar 00root root 0000000 0000000 package vendor
import (
"bytes"
"encoding/json"
"fmt"
"io"
"os"
"reflect"
"sort"
)
// gb-vendor manifest support
// Manifest describes the layout of $PROJECT/vendor/manifest.
type Manifest struct {
// Manifest version. Current manifest version is 0.
Version int `json:"version"`
// Depenencies is a list of vendored dependencies.
Dependencies []Dependency `json:"dependencies"`
}
// AddDependency adds a Dependency to the current Manifest.
// If the dependency exists already then it returns and error.
func (m *Manifest) AddDependency(dep Dependency) error {
if m.HasImportpath(dep.Importpath) {
return fmt.Errorf("already registered")
}
m.Dependencies = append(m.Dependencies, dep)
return nil
}
// RemoveDependency removes a Dependency from the current Manifest.
// If the dependency does not exist then it returns an error.
func (m *Manifest) RemoveDependency(dep Dependency) error {
for i, d := range m.Dependencies {
if reflect.DeepEqual(d, dep) {
m.Dependencies = append(m.Dependencies[:i], m.Dependencies[i+1:]...)
return nil
}
}
return fmt.Errorf("dependency does not exist")
}
// HasImportpath reports whether the Manifest contains the import path.
func (m *Manifest) HasImportpath(path string) bool {
_, err := m.GetDependencyForImportpath(path)
return err == nil
}
// GetDependencyForRepository return a dependency for specified URL
// If the dependency does not exist it returns an error
func (m *Manifest) GetDependencyForImportpath(path string) (Dependency, error) {
for _, d := range m.Dependencies {
if d.Importpath == path {
return d, nil
}
}
return Dependency{}, fmt.Errorf("dependency for %s does not exist", path)
}
// Dependency describes one vendored import path of code
// A Dependency is an Importpath sources from a Respository
// at Revision from Path.
type Dependency struct {
// Importpath is name by which this dependency is known.
Importpath string `json:"importpath"`
// Repository is the remote DVCS location that this
// dependency was fetched from.
Repository string `json:"repository"`
// Revision is the revision that describes the dependency's
// remote revision.
Revision string `json:"revision"`
// Branch is the branch the Revision was located on.
// Can be blank if not needed.
Branch string `json:"branch"`
// Path is the path inside the Repository where the
// dependency was fetched from.
Path string `json:"path,omitempty"`
}
// WriteManifest writes a Manifest to the path. If the manifest does
// not exist, it is created. If it does exist, it will be overwritten.
// If the manifest file is empty (0 dependencies) it will be deleted.
// The dependencies will be ordered by import path to reduce churn when making
// changes.
// TODO(dfc) write to temporary file and move atomically to avoid
// destroying a working vendorfile.
func WriteManifest(path string, m *Manifest) error {
if len(m.Dependencies) == 0 {
err := os.Remove(path)
if !os.IsNotExist(err) {
return err
}
return nil
}
f, err := os.Create(path)
if err != nil {
return err
}
if err := writeManifest(f, m); err != nil {
f.Close()
return err
}
return f.Close()
}
func writeManifest(w io.Writer, m *Manifest) error {
sort.Sort(byImportpath(m.Dependencies))
buf, err := json.MarshalIndent(m, "", "\t")
if err != nil {
return err
}
_, err = io.Copy(w, bytes.NewReader(buf))
return err
}
// ReadManifest reads a Manifest from path. If the Manifest is not
// found, a blank Manifest will be returned.
func ReadManifest(path string) (*Manifest, error) {
f, err := os.Open(path)
if err != nil {
if os.IsNotExist(err) {
return new(Manifest), nil
}
return nil, err
}
defer f.Close()
return readManifest(f)
}
func readManifest(r io.Reader) (*Manifest, error) {
var m Manifest
d := json.NewDecoder(r)
err := d.Decode(&m)
return &m, err
}
type byImportpath []Dependency
func (s byImportpath) Len() int { return len(s) }
func (s byImportpath) Less(i, j int) bool { return s[i].Importpath < s[j].Importpath }
func (s byImportpath) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
gb-0.3.2/vendor/manifest_test.go 0000664 0000000 0000000 00000004151 12625565062 0016607 0 ustar 00root root 0000000 0000000 package vendor
import (
"bytes"
"os"
"path/filepath"
"testing"
"github.com/constabulary/gb/fileutils"
)
func mktemp(t *testing.T) string {
s, err := mktmp()
if err != nil {
t.Fatal(err)
}
return s
}
func assertNotExists(t *testing.T, path string) {
_, err := os.Stat(path)
if err == nil || !os.IsNotExist(err) {
t.Fatalf("expected %q to be not found, got %v", path, err)
}
}
func assertExists(t *testing.T, path string) {
_, err := os.Stat(path)
if err != nil {
t.Fatalf("expected %q to be found, got %v", path, err)
}
}
func TestManifest(t *testing.T) {
root := mktemp(t)
defer fileutils.RemoveAll(root)
mf := filepath.Join(root, "vendor")
// check that reading an non existant manifest
// does not return an error
m, err := ReadManifest(mf)
if err != nil {
t.Fatalf("reading a non existant manifest should not fail: %v", err)
}
// check that no manifest file was created
assertNotExists(t, mf)
// add a dep
m.Dependencies = append(m.Dependencies, Dependency{
Importpath: "github.com/foo/bar/baz",
Repository: "https://github.com/foo/bar",
Revision: "cafebad",
Branch: "master",
Path: "/baz",
})
// write it back
if err := WriteManifest(mf, m); err != nil {
t.Fatalf("WriteManifest failed: %v", err)
}
// check the manifest was written
assertExists(t, mf)
// remove it
m.Dependencies = nil
if err := WriteManifest(mf, m); err != nil {
t.Fatalf("WriteManifest failed: %v", err)
}
// check that no manifest file was removed
assertNotExists(t, mf)
}
func TestEmptyPathIsNotWritten(t *testing.T) {
m := Manifest{
Version: 0,
Dependencies: []Dependency{{
Importpath: "github.com/foo/bar",
Repository: "https://github.com/foo/bar",
Revision: "abcdef",
Branch: "master",
}},
}
var buf bytes.Buffer
if err := writeManifest(&buf, &m); err != nil {
t.Fatal(err)
}
want := `{
"version": 0,
"dependencies": [
{
"importpath": "github.com/foo/bar",
"repository": "https://github.com/foo/bar",
"revision": "abcdef",
"branch": "master"
}
]
}`
got := buf.String()
if want != got {
t.Fatalf("want: %s, got %s", want, got)
}
}
gb-0.3.2/vendor/repo.go 0000664 0000000 0000000 00000032066 12625565062 0014715 0 ustar 00root root 0000000 0000000 package vendor
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"net/url"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
"github.com/constabulary/gb/fileutils"
)
// RemoteRepo describes a remote dvcs repository.
type RemoteRepo interface {
// Checkout checks out a specific branch, tag, or revision.
// The interpretation of these three values is impementation
// specific.
Checkout(branch, tag, revision string) (WorkingCopy, error)
// URL returns the URL the clone was taken from. It should
// only be called after Clone.
URL() string
}
// WorkingCopy represents a local copy of a remote dvcs repository.
type WorkingCopy interface {
// Dir is the root of this working copy.
Dir() string
// Revision returns the revision of this working copy.
Revision() (string, error)
// Branch returns the branch to which this working copy belongs.
Branch() (string, error)
// Destroy removes the working copy and cleans path to the working copy.
Destroy() error
}
var (
ghregex = regexp.MustCompile(`^(?Pgithub\.com/([A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`)
bbregex = regexp.MustCompile(`^(?Pbitbucket\.org/(?P[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`)
lpregex = regexp.MustCompile(`^launchpad.net/([A-Za-z0-9-._]+)(/[A-Za-z0-9-._]+)?(/.+)?`)
gcregex = regexp.MustCompile(`^(?Pcode\.google\.com/[pr]/(?P[a-z0-9\-]+)(\.(?P[a-z0-9\-]+))?)(/[A-Za-z0-9_.\-]+)*$`)
genericre = regexp.MustCompile(`^(?P(?P([a-z0-9.\-]+\.)+[a-z0-9.\-]+(:[0-9]+)?/[A-Za-z0-9_.\-/]*?)\.(?Pbzr|git|hg|svn))([/A-Za-z0-9_.\-]+)*$`)
)
// DeduceRemoteRepo takes a potential import path and returns a RemoteRepo
// representing the remote location of the source of an import path.
// Remote repositories can be bare import paths, or urls including a checkout scheme.
// If deduction would cause traversal of an insecure host, a message will be
// printed and the travelsal path will be ignored.
func DeduceRemoteRepo(path string, insecure bool) (RemoteRepo, string, error) {
u, err := url.Parse(path)
if err != nil {
return nil, "", fmt.Errorf("%q is not a valid import path", path)
}
var schemes []string
if u.Scheme != "" {
schemes = append(schemes, u.Scheme)
}
path = u.Host + u.Path
if !regexp.MustCompile(`^([A-Za-z0-9-]+)(.[A-Za-z0-9-]+)+(/[A-Za-z0-9-_.]+)+$`).MatchString(path) {
return nil, "", fmt.Errorf("%q is not a valid import path", path)
}
switch {
case ghregex.MatchString(path):
v := ghregex.FindStringSubmatch(path)
url := &url.URL{
Host: "github.com",
Path: v[2],
}
repo, err := Gitrepo(url, insecure, schemes...)
return repo, v[0][len(v[1]):], err
case bbregex.MatchString(path):
v := bbregex.FindStringSubmatch(path)
url := &url.URL{
Host: "bitbucket.org",
Path: v[2],
}
repo, err := Gitrepo(url, insecure, schemes...)
if err == nil {
return repo, v[0][len(v[1]):], nil
}
repo, err = Hgrepo(url, insecure)
if err == nil {
return repo, v[0][len(v[1]):], nil
}
return nil, "", fmt.Errorf("unknown repository type")
case gcregex.MatchString(path):
v := gcregex.FindStringSubmatch(path)
url := &url.URL{
Host: "code.google.com",
Path: "p/" + v[2],
}
repo, err := Hgrepo(url, insecure, schemes...)
if err == nil {
return repo, v[0][len(v[1]):], nil
}
repo, err = Gitrepo(url, insecure, schemes...)
if err == nil {
return repo, v[0][len(v[1]):], nil
}
return nil, "", fmt.Errorf("unknown repository type")
case lpregex.MatchString(path):
v := lpregex.FindStringSubmatch(path)
v = append(v, "", "")
if v[2] == "" {
// launchpad.net/project"
repo, err := Bzrrepo(fmt.Sprintf("https://launchpad.net/%v", v[1]))
return repo, "", err
}
// launchpad.net/project/series"
repo, err := Bzrrepo(fmt.Sprintf("https://launchpad.net/%s/%s", v[1], v[2]))
return repo, v[3], err
}
// try the general syntax
if genericre.MatchString(path) {
v := genericre.FindStringSubmatch(path)
switch v[5] {
case "git":
x := strings.SplitN(v[1], "/", 2)
url := &url.URL{
Host: x[0],
Path: x[1],
}
repo, err := Gitrepo(url, insecure, schemes...)
return repo, v[6], err
case "hg":
x := strings.SplitN(v[1], "/", 2)
url := &url.URL{
Host: x[0],
Path: x[1],
}
repo, err := Hgrepo(url, insecure, schemes...)
return repo, v[6], err
case "bzr":
repo, err := Bzrrepo("https://" + v[1])
return repo, v[6], err
default:
return nil, "", fmt.Errorf("unknown repository type: %q", v[5])
}
}
// no idea, try to resolve as a vanity import
importpath, vcs, reporoot, err := ParseMetadata(path, insecure)
if err != nil {
return nil, "", err
}
u, err = url.Parse(reporoot)
if err != nil {
return nil, "", err
}
extra := path[len(importpath):]
switch vcs {
case "git":
u.Path = u.Path[1:]
repo, err := Gitrepo(u, insecure, u.Scheme)
return repo, extra, err
case "hg":
u.Path = u.Path[1:]
repo, err := Hgrepo(u, insecure, u.Scheme)
return repo, extra, err
case "bzr":
repo, err := Bzrrepo(reporoot)
return repo, extra, err
default:
return nil, "", fmt.Errorf("unknown repository type: %q", vcs)
}
}
// Gitrepo returns a RemoteRepo representing a remote git repository.
func Gitrepo(url *url.URL, insecure bool, schemes ...string) (RemoteRepo, error) {
if len(schemes) == 0 {
schemes = []string{"https", "git", "ssh", "http"}
}
u, err := probeGitUrl(url, insecure, schemes)
if err != nil {
return nil, err
}
return &gitrepo{
url: u,
}, nil
}
func probeGitUrl(u *url.URL, insecure bool, schemes []string) (string, error) {
git := func(url *url.URL) error {
out, err := run("git", "ls-remote", url.String(), "HEAD")
if err != nil {
return err
}
if !bytes.Contains(out, []byte("HEAD")) {
return fmt.Errorf("not a git repo")
}
return nil
}
return probe(git, u, insecure, schemes...)
}
func probeHgUrl(u *url.URL, insecure bool, schemes []string) (string, error) {
hg := func(url *url.URL) error {
_, err := run("hg", "identify", url.String())
return err
}
return probe(hg, u, insecure, schemes...)
}
func probeBzrUrl(u string) error {
bzr := func(url *url.URL) error {
_, err := run("bzr", "info", url.String())
return err
}
url, err := url.Parse(u)
if err != nil {
return err
}
_, err = probe(bzr, url, false, "https")
return err
}
// probe calls the supplied vcs function to probe a variety of url constructions.
// If vcs returns non nil, it is assumed that the url is not a valid repo.
func probe(vcs func(*url.URL) error, url *url.URL, insecure bool, schemes ...string) (string, error) {
var unsuccessful []string
for _, scheme := range schemes {
// make copy of url and apply scheme
url := *url
url.Scheme = scheme
switch url.Scheme {
case "https", "ssh":
if err := vcs(&url); err == nil {
return url.String(), nil
}
case "http", "git":
if !insecure {
fmt.Println("skipping insecure protocol:", url.String())
continue
}
if err := vcs(&url); err == nil {
return url.String(), nil
}
default:
return "", fmt.Errorf("unsupported scheme: %v", url.Scheme)
}
unsuccessful = append(unsuccessful, url.String())
}
return "", fmt.Errorf("vcs probe failed, tried: %s", strings.Join(unsuccessful, ","))
}
// gitrepo is a git RemoteRepo.
type gitrepo struct {
// remote repository url, see man 1 git-clone
url string
}
func (g *gitrepo) URL() string {
return g.url
}
// Checkout fetchs the remote branch, tag, or revision. If more than one is
// supplied, an error is returned. If the branch is blank,
// then the default remote branch will be used. If the branch is "HEAD", an
// error will be returned.
func (g *gitrepo) Checkout(branch, tag, revision string) (WorkingCopy, error) {
if branch == "HEAD" {
return nil, fmt.Errorf("cannot update %q as it has been previously fetched with -tag or -revision. Please use gb vendor delete then fetch again.", g.url)
}
if !atMostOne(branch, tag, revision) {
return nil, fmt.Errorf("only one of branch, tag or revision may be supplied")
}
dir, err := mktmp()
if err != nil {
return nil, err
}
wc := workingcopy{
path: dir,
}
args := []string{
"clone",
"-q", // silence progress report to stderr
g.url,
dir,
}
if branch != "" {
args = append(args, "--branch", branch)
}
if _, err := run("git", args...); err != nil {
wc.Destroy()
return nil, err
}
if revision != "" || tag != "" {
if err := runOutPath(os.Stderr, dir, "git", "checkout", "-q", oneOf(revision, tag)); err != nil {
wc.Destroy()
return nil, err
}
}
return &GitClone{wc}, nil
}
type workingcopy struct {
path string
}
func (w workingcopy) Dir() string { return w.path }
func (w workingcopy) Destroy() error {
if err := fileutils.RemoveAll(w.path); err != nil {
return err
}
parent := filepath.Dir(w.path)
return cleanPath(parent)
}
// GitClone is a git WorkingCopy.
type GitClone struct {
workingcopy
}
func (g *GitClone) Revision() (string, error) {
rev, err := runPath(g.path, "git", "rev-parse", "HEAD")
return strings.TrimSpace(string(rev)), err
}
func (g *GitClone) Branch() (string, error) {
rev, err := runPath(g.path, "git", "rev-parse", "--abbrev-ref", "HEAD")
return strings.TrimSpace(string(rev)), err
}
// Hgrepo returns a RemoteRepo representing a remote git repository.
func Hgrepo(u *url.URL, insecure bool, schemes ...string) (RemoteRepo, error) {
if len(schemes) == 0 {
schemes = []string{"https", "http"}
}
url, err := probeHgUrl(u, insecure, schemes)
if err != nil {
return nil, err
}
return &hgrepo{
url: url,
}, nil
}
// hgrepo is a Mercurial repo.
type hgrepo struct {
// remote repository url, see man 1 hg
url string
}
func (h *hgrepo) URL() string { return h.url }
func (h *hgrepo) Checkout(branch, tag, revision string) (WorkingCopy, error) {
if !atMostOne(tag, revision) {
return nil, fmt.Errorf("only one of tag or revision may be supplied")
}
dir, err := mktmp()
if err != nil {
return nil, err
}
args := []string{
"clone",
h.url,
dir,
"--noninteractive",
}
if branch != "" {
args = append(args, "--branch", branch)
}
if err := runOut(os.Stderr, "hg", args...); err != nil {
fileutils.RemoveAll(dir)
return nil, err
}
if revision != "" {
if err := runOut(os.Stderr, "hg", "--cwd", dir, "update", "-r", revision); err != nil {
fileutils.RemoveAll(dir)
return nil, err
}
}
return &HgClone{
workingcopy{
path: dir,
},
}, nil
}
// HgClone is a mercurial WorkingCopy.
type HgClone struct {
workingcopy
}
func (h *HgClone) Revision() (string, error) {
rev, err := run("hg", "--cwd", h.path, "id", "-i")
return strings.TrimSpace(string(rev)), err
}
func (h *HgClone) Branch() (string, error) {
rev, err := run("hg", "--cwd", h.path, "branch")
return strings.TrimSpace(string(rev)), err
}
// Bzrrepo returns a RemoteRepo representing a remote bzr repository.
func Bzrrepo(url string) (RemoteRepo, error) {
if err := probeBzrUrl(url); err != nil {
return nil, err
}
return &bzrrepo{
url: url,
}, nil
}
// bzrrepo is a bzr RemoteRepo.
type bzrrepo struct {
// remote repository url
url string
}
func (b *bzrrepo) URL() string {
return b.url
}
func (b *bzrrepo) Checkout(branch, tag, revision string) (WorkingCopy, error) {
if !atMostOne(tag, revision) {
return nil, fmt.Errorf("only one of tag or revision may be supplied")
}
dir, err := mktmp()
if err != nil {
return nil, err
}
wc := filepath.Join(dir, "wc")
if err := runOut(os.Stderr, "bzr", "branch", b.url, wc); err != nil {
fileutils.RemoveAll(dir)
return nil, err
}
return &BzrClone{
workingcopy{
path: wc,
},
}, nil
}
// BzrClone is a bazaar WorkingCopy.
type BzrClone struct {
workingcopy
}
func (b *BzrClone) Revision() (string, error) {
return "1", nil
}
func (b *BzrClone) Branch() (string, error) {
return "master", nil
}
func cleanPath(path string) error {
if files, _ := ioutil.ReadDir(path); len(files) > 0 || filepath.Base(path) == "src" {
return nil
}
parent := filepath.Dir(path)
if err := fileutils.RemoveAll(path); err != nil {
return err
}
return cleanPath(parent)
}
func mkdir(path string) error {
return os.MkdirAll(path, 0755)
}
func mktmp() (string, error) {
return ioutil.TempDir("", "gb-vendor-")
}
func run(c string, args ...string) ([]byte, error) {
var buf bytes.Buffer
err := runOut(&buf, c, args...)
return buf.Bytes(), err
}
func runOut(w io.Writer, c string, args ...string) error {
cmd := exec.Command(c, args...)
cmd.Stdin = nil
cmd.Stdout = w
cmd.Stderr = os.Stderr
return cmd.Run()
}
func runPath(path string, c string, args ...string) ([]byte, error) {
var buf bytes.Buffer
err := runOutPath(&buf, path, c, args...)
return buf.Bytes(), err
}
func runOutPath(w io.Writer, path string, c string, args ...string) error {
cmd := exec.Command(c, args...)
cmd.Dir = path
cmd.Stdin = nil
cmd.Stdout = w
cmd.Stderr = os.Stderr
return cmd.Run()
}
// atMostOne returns true if no more than one string supplied is not empty.
func atMostOne(args ...string) bool {
var c int
for _, arg := range args {
if arg != "" {
c++
}
}
return c < 2
}
// oneof returns the first non empty string
func oneOf(args ...string) string {
for _, arg := range args {
if arg != "" {
return arg
}
}
return ""
}
gb-0.3.2/vendor/repo_test.go 0000664 0000000 0000000 00000006265 12625565062 0015756 0 ustar 00root root 0000000 0000000 package vendor
import (
"fmt"
"reflect"
"testing"
)
func TestDeduceRemoteRepo(t *testing.T) {
if testing.Short() {
t.Skipf("skipping network tests in -short mode")
}
tests := []struct {
path string
want RemoteRepo
extra string
err error
insecure bool
}{{
path: "",
err: fmt.Errorf(`"" is not a valid import path`),
}, {
path: "corporate",
err: fmt.Errorf(`"corporate" is not a valid import path`),
}, {
path: "github.com/cznic/b",
want: &gitrepo{
url: "https://github.com/cznic/b",
},
}, {
path: "github.com/pkg/sftp",
want: &gitrepo{
url: "https://github.com/pkg/sftp",
},
}, {
path: "github.com/pkg/sftp/examples/gsftp",
want: &gitrepo{
url: "https://github.com/pkg/sftp",
},
extra: "/examples/gsftp",
}, {
path: "github.com/coreos/go-etcd",
want: &gitrepo{
url: "https://github.com/coreos/go-etcd",
},
}, {
path: "bitbucket.org/davecheney/gitrepo/cmd/main",
want: &gitrepo{
url: "https://bitbucket.org/davecheney/gitrepo",
},
extra: "/cmd/main",
}, {
path: "bitbucket.org/davecheney/hgrepo/cmd/main",
want: &hgrepo{
url: "https://bitbucket.org/davecheney/hgrepo",
},
extra: "/cmd/main",
}, {
path: "code.google.com/p/goauth2/oauth",
want: &hgrepo{
url: "https://code.google.com/p/goauth2",
},
extra: "/oauth",
}, {
path: "code.google.com/p/gami",
want: &gitrepo{
url: "https://code.google.com/p/gami",
},
}, {
path: "git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git",
want: &gitrepo{
url: "https://git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git",
},
}, {
path: "git.apache.org/thrift.git/lib/go/thrift",
want: &gitrepo{
url: "https://git.apache.org/thrift.git",
},
extra: "/lib/go/thrift",
}, {
path: "gopkg.in/check.v1",
want: &gitrepo{
url: "https://gopkg.in/check.v1",
},
extra: "",
}, {
path: "golang.org/x/tools/go/vcs",
want: &gitrepo{
url: "https://go.googlesource.com/tools",
},
extra: "/go/vcs",
}, {
path: "labix.org/v2/mgo",
want: &bzrrepo{
url: "https://launchpad.net/mgo/v2",
},
insecure: true,
}, {
path: "launchpad.net/gnuflag",
want: &bzrrepo{
url: "https://launchpad.net/gnuflag",
},
}, {
path: "https://github.com/pkg/sftp",
want: &gitrepo{
url: "https://github.com/pkg/sftp",
},
}, {
path: "git://github.com/pkg/sftp",
want: &gitrepo{
url: "git://github.com/pkg/sftp",
},
insecure: true,
}, {
path: "code.google.com/p/google-api-go-client/bigquery/v2",
want: &hgrepo{
url: "https://code.google.com/p/google-api-go-client",
},
extra: "/bigquery/v2",
}, {
path: "code.google.com/p/go-sqlite/go1/sqlite3",
want: &hgrepo{
url: "https://code.google.com/p/go-sqlite",
},
extra: "/go1/sqlite3",
}}
for _, tt := range tests {
t.Logf("DeduceRemoteRepo(%q, %v)", tt.path, tt.insecure)
got, extra, err := DeduceRemoteRepo(tt.path, tt.insecure)
if !reflect.DeepEqual(err, tt.err) {
t.Errorf("DeduceRemoteRepo(%q): want err: %v, got err: %v", tt.path, tt.err, err)
continue
}
if !reflect.DeepEqual(got, tt.want) || extra != tt.extra {
t.Errorf("DeduceRemoteRepo(%q): want %#v, %v, got %#v, %v", tt.path, tt.want, tt.extra, got, extra)
}
}
}
gb-0.3.2/vendor/stdlib.go 0000664 0000000 0000000 00000007766 12625565062 0015242 0 ustar 00root root 0000000 0000000 package vendor
// packages from the standard lib. They are excluded
// from the package map.
var stdlib = map[string]bool{
"C": true,
"archive/tar": true,
"archive/zip": true,
"bufio": true,
"bytes": true,
"compress/bzip2": true,
"compress/flate": true,
"compress/gzip": true,
"compress/lzw": true,
"compress/zlib": true,
"container/heap": true,
"container/list": true,
"container/ring": true,
"crypto": true,
"crypto/aes": true,
"crypto/cipher": true,
"crypto/des": true,
"crypto/dsa": true,
"crypto/ecdsa": true,
"crypto/elliptic": true,
"crypto/hmac": true,
"crypto/md5": true,
"crypto/rand": true,
"crypto/rc4": true,
"crypto/rsa": true,
"crypto/sha1": true,
"crypto/sha256": true,
"crypto/sha512": true,
"crypto/subtle": true,
"crypto/tls": true,
"crypto/x509": true,
"crypto/x509/pkix": true,
"database/sql": true,
"database/sql/driver": true,
"debug/dwarf": true,
"debug/elf": true,
"debug/gosym": true,
"debug/macho": true,
"debug/pe": true,
"encoding": true,
"encoding/ascii85": true,
"encoding/asn1": true,
"encoding/base32": true,
"encoding/base64": true,
"encoding/binary": true,
"encoding/csv": true,
"encoding/gob": true,
"encoding/hex": true,
"encoding/json": true,
"encoding/pem": true,
"encoding/xml": true,
"errors": true,
"expvar": true,
"flag": true,
"fmt": true,
"go/ast": true,
"go/build": true,
"go/doc": true,
"go/format": true,
"go/parser": true,
"go/printer": true,
"go/scanner": true,
"go/token": true,
"hash": true,
"hash/adler32": true,
"hash/crc32": true,
"hash/crc64": true,
"hash/fnv": true,
"html": true,
"html/template": true,
"image": true,
"image/color": true,
"image/draw": true,
"image/gif": true,
"image/jpeg": true,
"image/png": true,
"index/suffixarray": true,
"io": true,
"io/ioutil": true,
"log": true,
"log/syslog": true,
"math": true,
"math/big": true,
"math/cmplx": true,
"math/rand": true,
"mime": true,
"mime/multipart": true,
"net": true,
"net/http": true,
"net/http/cgi": true,
"net/http/cookiejar": true,
"net/http/fcgi": true,
"net/http/httptest": true,
"net/http/httputil": true,
"net/http/pprof": true,
"net/mail": true,
"net/rpc": true,
"net/rpc/jsonrpc": true,
"net/smtp": true,
"net/textproto": true,
"net/url": true,
"os": true,
"os/exec": true,
"os/signal": true,
"os/user": true,
"path": true,
"path/filepath": true,
"reflect": true,
"regexp": true,
"regexp/syntax": true,
"runtime": true,
"runtime/cgo": true,
"runtime/debug": true,
"runtime/pprof": true,
"sort": true,
"strconv": true,
"strings": true,
"sync": true,
"sync/atomic": true,
"syscall": true,
"testing": true,
"testing/iotest": true,
"testing/quick": true,
"text/scanner": true,
"text/tabwriter": true,
"text/template": true,
"text/template/parse": true,
"time": true,
"unicode": true,
"unicode/utf16": true,
"unicode/utf8": true,
"unsafe": true,
}
gb-0.3.2/vendor/stringset.go 0000664 0000000 0000000 00000001605 12625565062 0015765 0 ustar 00root root 0000000 0000000 package vendor
// union returns the union of a and b.
func union(a, b map[string]bool) map[string]bool {
r := make(map[string]bool)
for k := range a {
r[k] = true
}
for k := range b {
r[k] = true
}
return r
}
// intersection returns the intersection of a and b.
func intersection(a, b map[string]bool) map[string]bool {
r := make(map[string]bool)
for k := range a {
if b[k] {
r[k] = true
}
}
return r
}
// difference returns the symetric difference of a and b.
func difference(a, b map[string]bool) map[string]bool {
r := make(map[string]bool)
for k := range a {
if !b[k] {
r[k] = true
}
}
for k := range b {
if !a[k] {
r[k] = true
}
}
return r
}
// contains returns true if a contains all the elements in s.
func contains(a map[string]bool, s ...string) bool {
var r bool
for _, e := range s {
if !a[e] {
return false
}
r = true
}
return r
}
gb-0.3.2/vendor/stringset_test.go 0000664 0000000 0000000 00000005216 12625565062 0017026 0 ustar 00root root 0000000 0000000 package vendor
import "testing"
import "reflect"
func set(args ...string) map[string]bool {
r := make(map[string]bool)
for _, a := range args {
r[a] = true
}
return r
}
func TestUnion(t *testing.T) {
tests := []struct {
a, b map[string]bool
want map[string]bool
}{{
a: nil, b: nil,
want: set(),
}, {
a: nil, b: set("b"),
want: set("b"),
}, {
a: set("a"), b: nil,
want: set("a"),
}, {
a: set("a"), b: set("b"),
want: set("b", "a"),
}, {
a: set("c"), b: set("c"),
want: set("c"),
}}
for _, tt := range tests {
got := union(tt.a, tt.b)
if !reflect.DeepEqual(tt.want, got) {
t.Errorf("union(%v, %v) want: %v, got %v", tt.a, tt.b, tt.want, got)
}
}
}
func TestIntersection(t *testing.T) {
tests := []struct {
a, b map[string]bool
want map[string]bool
}{{
a: nil, b: nil,
want: set(),
}, {
a: nil, b: set("b"),
want: set(),
}, {
a: set("a"), b: nil,
want: set(),
}, {
a: set("a"), b: set("b"),
want: set(),
}, {
a: set("c"), b: set("c"),
want: set("c"),
}, {
a: set("a", "c"), b: set("b", "c"),
want: set("c"),
}}
for _, tt := range tests {
got := intersection(tt.a, tt.b)
if !reflect.DeepEqual(tt.want, got) {
t.Errorf("intersection(%v, %v) want: %v, got %v", tt.a, tt.b, tt.want, got)
}
}
}
func TestDifference(t *testing.T) {
tests := []struct {
a, b map[string]bool
want map[string]bool
}{{
a: nil, b: nil,
want: set(),
}, {
a: nil, b: set("b"),
want: set("b"),
}, {
a: set("a"), b: nil,
want: set("a"),
}, {
a: set("a"), b: set("b"),
want: set("a", "b"),
}, {
a: set("c"), b: set("c"),
want: set(),
}, {
a: set("a", "c"), b: set("b", "c"),
want: set("a", "b"),
}}
for _, tt := range tests {
got := difference(tt.a, tt.b)
if !reflect.DeepEqual(tt.want, got) {
t.Errorf("difference(%v, %v) want: %v, got %v", tt.a, tt.b, tt.want, got)
}
}
}
func TestContains(t *testing.T) {
tests := []struct {
a map[string]bool
s []string
want bool
}{{
a: nil, s: nil,
want: false,
}, {
a: set("a"), s: nil,
want: false,
}, {
a: set("a"), s: []string{"a"},
want: true,
}, {
a: set("a"), s: []string{"b"},
want: false,
}, {
a: set("a", "b"), s: []string{"b"},
want: true,
}, {
a: set("a"), s: []string{"a", "b"},
want: false,
}, {
a: set("a", "b", "c"), s: []string{"a", "b"},
want: true,
}, {
a: set("a", "b", "c"), s: []string{"x", "b"},
want: false,
}, {
a: set("a", "b", "c"), s: []string{"b", "c", "d"},
want: false,
}}
for _, tt := range tests {
got := contains(tt.a, tt.s...)
if !reflect.DeepEqual(tt.want, got) {
t.Errorf("contains(%v, %v) want: %v, got %v", tt.a, tt.s, tt.want, got)
}
}
}