Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Import minimal version of gazelle, a BUILD file generator #57

Merged
merged 1 commit into from
Aug 10, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,14 @@ new_git_repository(
commit = "23def4e6c14b4da8ac2ed8007337bc5eb5007998",
remote = "https://github.com/golang/glog.git",
)

git_repository(
name = "io_bazel_buildifier",
commit = "0ca1d7991357ae7a7555589af88930d82cf07c0a",
remote = "https://github.com/bazelbuild/buildifier.git",
)

local_repository(
name = "io_bazel_rules_go",
path = ".",
)
10 changes: 10 additions & 0 deletions go/tools/gazelle/gazelle/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary")

go_binary(
name = "gazelle",
srcs = ["main.go"],
deps = [
"@io_bazel_buildifier//core:go_default_library",
"//go/tools/gazelle/generator:go_default_library",
],
)
86 changes: 86 additions & 0 deletions go/tools/gazelle/gazelle/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/* Copyright 2016 The Bazel Authors. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Command gazelle is a BUILD file generator for Go projects.
// See "gazelle --help" for more details.
package main

import (
"flag"
"fmt"
"log"
"os"

bzl "github.com/bazelbuild/buildifier/core"
"github.com/bazelbuild/rules_go/go/tools/gazelle/generator"
)

var (
repoRoot = flag.String("repo_root", "", "path to a root directory of a repository")
)

func run(dirs []string) error {
g, err := generator.New(*repoRoot)
if err != nil {
return err
}

for _, d := range dirs {
files, err := g.Generate(d)
if err != nil {
return err
}
for _, f := range files {
if _, err := os.Stdout.Write(bzl.Format(f)); err != nil {
return err
}
}
}
return nil
}

func usage() {
fmt.Fprintln(os.Stderr, `usage: gazelle [flags...] [package-dirs...]

Gazel is a BUILD file generator for Go projects.

Currently its primary usage is to generate BUILD files for external dependencies
in a go_vendor repository rule.
You can still use Gazel for other purposes, but its interface can change without
notice.

It takes a list of paths to Go package directories.
It recursively traverses its subpackages.
All the directories must be under the directory specified in -repo_root.

FLAGS:
`)
flag.PrintDefaults()
}

func main() {
flag.Usage = usage
flag.Parse()

if *repoRoot == "" {
if flag.NArg() != 1 {
log.Fatal("-repo_root is required")
}
*repoRoot = flag.Arg(0)
}
if err := run(flag.Args()); err != nil {
log.Fatal(err)
}
}
21 changes: 21 additions & 0 deletions go/tools/gazelle/generator/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")

go_library(
name = "go_default_library",
srcs = ["generator.go"],
visibility = ["//visibility:public"],
deps = [
"@io_bazel_buildifier//core:go_default_library",
"//go/tools/gazelle/packages:go_default_library",
"//go/tools/gazelle/rules:go_default_library",
],
)

go_test(
name = "go_default_test",
srcs = ["generator_test.go"],
library = ":go_default_library",
deps = [
"//go/tools/gazelle/testdata:go_default_library",
],
)
104 changes: 104 additions & 0 deletions go/tools/gazelle/generator/generator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/* Copyright 2016 The Bazel Authors. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Package generator provides core functionality of
// BUILD file generation in gazelle.
package generator

import (
"fmt"
"go/build"
"path/filepath"
"strings"

bzl "github.com/bazelbuild/buildifier/core"
"github.com/bazelbuild/rules_go/go/tools/gazelle/packages"
"github.com/bazelbuild/rules_go/go/tools/gazelle/rules"
)

// Generator generates BUILD files for a Go repository.
type Generator struct {
repoRoot string
bctx build.Context
g rules.Generator
}

// New returns a new Generator which is responsible for a Go repository.
//
// "repoRoot" is a path to the root directory of the repository.
func New(repoRoot string) (*Generator, error) {
bctx := build.Default
// Ignore source files in $GOROOT and $GOPATH
bctx.GOROOT = ""
bctx.GOPATH = ""

repoRoot, err := filepath.Abs(repoRoot)
if err != nil {
return nil, err
}
return &Generator{
repoRoot: filepath.Clean(repoRoot),
bctx: bctx,
g: rules.NewGenerator(),
}, nil
}

// Generate generates a BUILD file for each Go package found under
// the given directory.
// The directory must be the repository root directory the caller
// passed to New, or its subdirectory.
func (g *Generator) Generate(dir string) ([]*bzl.File, error) {
dir, err := filepath.Abs(dir)
if err != nil {
return nil, err
}
dir = filepath.Clean(dir)
if !isDescendingDir(dir, g.repoRoot) {
return nil, fmt.Errorf("dir %s is not under the repository root %s", dir, g.repoRoot)
}

var files []*bzl.File
err = packages.Walk(g.bctx, dir, func(pkg *build.Package) error {
rel, err := filepath.Rel(g.repoRoot, pkg.Dir)
if err != nil {
return err
}
if rel == "." {
rel = ""
}

rs, err := g.g.Generate(filepath.ToSlash(rel), pkg)
if err != nil {
return err
}
file := &bzl.File{Path: filepath.Join(rel, "BUILD")}
for _, r := range rs {
file.Stmt = append(file.Stmt, r.Call)
}
files = append(files, file)
return nil
})
if err != nil {
return nil, err
}
return files, nil
}

func isDescendingDir(dir, root string) bool {
if dir == root {
return true
}
return strings.HasPrefix(dir, fmt.Sprintf("%s%c", root, filepath.Separator))
}
105 changes: 105 additions & 0 deletions go/tools/gazelle/generator/generator_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/* Copyright 2016 The Bazel Authors. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package generator

import (
"fmt"
"go/build"
"path/filepath"
"reflect"
"sort"
"strings"
"testing"

bzl "github.com/bazelbuild/buildifier/core"
"github.com/bazelbuild/rules_go/go/tools/gazelle/testdata"
)

func TestGenerator(t *testing.T) {
stub := stubRuleGen{
fixtures: map[string][]*bzl.Rule{
"lib": {
{
Call: &bzl.CallExpr{
X: &bzl.LiteralExpr{Token: "go_library"},
},
},
},
"bin": {
{
Call: &bzl.CallExpr{
X: &bzl.LiteralExpr{Token: "go_binary"},
},
},
},
},
}

repo := filepath.Join(testdata.Dir(), "repo")
g, err := New(repo)
if err != nil {
t.Errorf("New(%q) failed with %v; want success", repo, err)
return
}
g.g = stub

got, err := g.Generate(repo)
if err != nil {
t.Errorf("g.Generate(%q) failed with %v; want success", repo, err)
}
sort.Sort(fileSlice(got))

want := []*bzl.File{
{
Path: "lib/BUILD",
Stmt: []bzl.Expr{stub.fixtures["lib"][0].Call},
},
{
Path: "bin/BUILD",
Stmt: []bzl.Expr{stub.fixtures["bin"][0].Call},
},
}
sort.Sort(fileSlice(want))

if !reflect.DeepEqual(got, want) {
t.Errorf("g.Generate(%q) = %v; want %v", repo, prettyFiles(got), prettyFiles(want))
}
}

type prettyFiles []*bzl.File

func (p prettyFiles) String() string {
var items []string
for _, f := range p {
items = append(items, fmt.Sprintf("{Path: %q, Stmt: %q", f.Path, string(bzl.Format(f))))
}
return fmt.Sprintf("[%s]", strings.Join(items, ","))
}

type fileSlice []*bzl.File

func (p fileSlice) Less(i, j int) bool { return strings.Compare(p[i].Path, p[j].Path) < 0 }
func (p fileSlice) Len() int { return len(p) }
func (p fileSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }

// stubRuleGen is a test stub implementation of rules.Generator
type stubRuleGen struct {
fixtures map[string][]*bzl.Rule
}

func (s stubRuleGen) Generate(rel string, pkg *build.Package) ([]*bzl.Rule, error) {
return s.fixtures[rel], nil
}
16 changes: 16 additions & 0 deletions go/tools/gazelle/packages/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
load("//go:def.bzl", "go_library", "go_test")

go_library(
name = "go_default_library",
srcs = [
"doc.go",
"walk.go",
],
visibility = ["//visibility:public"],
)

go_test(
name = "go_default_xtest",
srcs = ["walk_test.go"],
deps = [":go_default_library"],
)
17 changes: 17 additions & 0 deletions go/tools/gazelle/packages/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/* Copyright 2016 The Bazel Authors. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Package packages provides Go package traversal in a Bazel repository.
package packages
Loading