feat: fix-visibility (#34)
Signed-off-by: Thulio Ferraz Assis <3149049+f0rmiga@users.noreply.github.com>
diff --git a/cmd/aspect/build/BUILD.bazel b/cmd/aspect/build/BUILD.bazel
index 6176f45..2acd656 100644
--- a/cmd/aspect/build/BUILD.bazel
+++ b/cmd/aspect/build/BUILD.bazel
@@ -9,7 +9,9 @@
"//pkg/aspect/build",
"//pkg/aspect/build/bep",
"//pkg/bazel",
+ "//pkg/hooks",
"//pkg/ioutils",
+ "//pkg/plugins/fix_visibility",
"@com_github_spf13_cobra//:cobra",
],
)
diff --git a/cmd/aspect/build/build.go b/cmd/aspect/build/build.go
index 670654b..e7a88ca 100644
--- a/cmd/aspect/build/build.go
+++ b/cmd/aspect/build/build.go
@@ -12,13 +12,20 @@
"aspect.build/cli/pkg/aspect/build"
"aspect.build/cli/pkg/aspect/build/bep"
"aspect.build/cli/pkg/bazel"
+ "aspect.build/cli/pkg/hooks"
"aspect.build/cli/pkg/ioutils"
+ "aspect.build/cli/pkg/plugins/fix_visibility"
)
// NewDefaultBuildCmd creates a new build cobra command with the default
// dependencies.
func NewDefaultBuildCmd() *cobra.Command {
- return NewBuildCmd(ioutils.DefaultStreams, bazel.New(), bep.NewBESBackend())
+ return NewBuildCmd(
+ ioutils.DefaultStreams,
+ bazel.New(),
+ bep.NewBESBackend(),
+ hooks.New(),
+ )
}
// NewBuildCmd creates a new build cobra command.
@@ -26,15 +33,24 @@
streams ioutils.Streams,
bzl bazel.Spawner,
besBackend bep.BESBackend,
+ hooks *hooks.Hooks,
) *cobra.Command {
- b := build.New(streams, bzl, besBackend)
+ // TODO(f0rmiga): this should also be part of the plugin design, as
+ // registering BEP event subscribers should not be hardcoded here.
+ var fixVisibilityPlugin build.Plugin = fix_visibility.NewDefaultPlugin()
+ besBackend.RegisterSubscriber(fixVisibilityPlugin.BEPEventCallback)
+ hooks.RegisterPostBuild(fixVisibilityPlugin.PostBuildHook)
+
+ b := build.New(streams, bzl, besBackend, hooks)
cmd := &cobra.Command{
Use: "build",
Short: "Builds the specified targets, using the options.",
Long: "Invokes bazel build on the specified targets. " +
"See 'bazel help target-syntax' for details and examples on how to specify targets to build.",
- RunE: b.Run,
+ RunE: func(cmd *cobra.Command, args []string) (exitErr error) {
+ return b.Run(cmd.Context(), cmd, args)
+ },
}
return cmd
diff --git a/cmd/aspect/main.go b/cmd/aspect/main.go
index 0e62da7..b7c645c 100644
--- a/cmd/aspect/main.go
+++ b/cmd/aspect/main.go
@@ -7,6 +7,7 @@
package main
import (
+ "context"
"errors"
"fmt"
"os"
@@ -28,7 +29,7 @@
// - tools/bazel file and put our bootstrap code in there
//
cmd := root.NewDefaultRootCmd()
- if err := cmd.Execute(); err != nil {
+ if err := cmd.ExecuteContext(context.Background()); err != nil {
var exitErr *aspecterrors.ExitError
if errors.As(err, &exitErr) {
if exitErr.Err != nil {
diff --git a/go.bzl b/go.bzl
index 31c8773..55ea223 100644
--- a/go.bzl
+++ b/go.bzl
@@ -41,6 +41,13 @@
version = "v0.0.0-20180808171621-7fddfc383310",
)
go_repository(
+ name = "com_github_bazelbuild_bazel_gazelle",
+ importpath = "github.com/bazelbuild/bazel-gazelle",
+ sum = "h1:Ks6YN+WkOv2lYWlvf7ksxUpLvrDbBHPBXXUrBFQ3BZM=",
+ version = "v0.23.0",
+ )
+
+ go_repository(
name = "com_github_bazelbuild_bazelisk",
build_naming_convention = "go_default_library",
importpath = "github.com/bazelbuild/bazelisk",
@@ -48,6 +55,13 @@
version = "v1.10.1",
)
go_repository(
+ name = "com_github_bazelbuild_buildtools",
+ importpath = "github.com/bazelbuild/buildtools",
+ sum = "h1:Et1IIXrXwhpDvR5wH9REPEZ0sUtzUoJSq19nfmBqzBY=",
+ version = "v0.0.0-20200718160251-b1667ff58f71",
+ )
+
+ go_repository(
name = "com_github_bazelbuild_rules_go",
importpath = "github.com/bazelbuild/rules_go",
sum = "h1:fNtx0dJpG5ENGdMj3/GICoi/7z+ixB3IIW5rERTzOgM=",
@@ -72,6 +86,13 @@
version = "v0.0.3-0.20200106085610-5cbc8cc4026c",
)
go_repository(
+ name = "com_github_bmatcuk_doublestar",
+ importpath = "github.com/bmatcuk/doublestar",
+ sum = "h1:oC24CykoSAB8zd7XgruHo33E0cHJf/WhQA/7BeXj+x0=",
+ version = "v1.2.2",
+ )
+
+ go_repository(
name = "com_github_burntsushi_toml",
importpath = "github.com/BurntSushi/toml",
sum = "h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=",
@@ -96,6 +117,25 @@
version = "v1.1.0",
)
go_repository(
+ name = "com_github_chzyer_logex",
+ importpath = "github.com/chzyer/logex",
+ sum = "h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=",
+ version = "v1.1.10",
+ )
+ go_repository(
+ name = "com_github_chzyer_readline",
+ importpath = "github.com/chzyer/readline",
+ sum = "h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=",
+ version = "v0.0.0-20180603132655-2972be24d48e",
+ )
+ go_repository(
+ name = "com_github_chzyer_test",
+ importpath = "github.com/chzyer/test",
+ sum = "h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=",
+ version = "v0.0.0-20180213035817-a1ea475d72b1",
+ )
+
+ go_repository(
name = "com_github_client9_misspell",
importpath = "github.com/client9/misspell",
sum = "h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=",
@@ -462,6 +502,13 @@
version = "v4.20.0+incompatible",
)
go_repository(
+ name = "com_github_juju_ansiterm",
+ importpath = "github.com/juju/ansiterm",
+ sum = "h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU=",
+ version = "v0.0.0-20180109212912-720a0952cc2a",
+ )
+
+ go_repository(
name = "com_github_julienschmidt_httprouter",
importpath = "github.com/julienschmidt/httprouter",
sum = "h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g=",
@@ -516,12 +563,26 @@
version = "v0.1.0",
)
go_repository(
+ name = "com_github_lunixbochs_vtclean",
+ importpath = "github.com/lunixbochs/vtclean",
+ sum = "h1:weJVJJRzAJBFRlAiJQROKQs8oC9vOxvm4rZmBBk0ONw=",
+ version = "v0.0.0-20180621232353-2d01aacdc34a",
+ )
+
+ go_repository(
name = "com_github_magiconair_properties",
importpath = "github.com/magiconair/properties",
sum = "h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=",
version = "v1.8.5",
)
go_repository(
+ name = "com_github_manifoldco_promptui",
+ importpath = "github.com/manifoldco/promptui",
+ sum = "h1:R95mMF+McvXZQ7j1g8ucVZE1gLP3Sv6j9vlF9kyRqQo=",
+ version = "v0.8.0",
+ )
+
+ go_repository(
name = "com_github_mattn_go_colorable",
importpath = "github.com/mattn/go-colorable",
sum = "h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=",
@@ -1012,8 +1073,8 @@
go_repository(
name = "org_golang_x_mod",
importpath = "golang.org/x/mod",
- sum = "h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=",
- version = "v0.3.0",
+ sum = "h1:Kvvh58BN8Y9/lBi7hTekvtMpm07eUZ0ck5pRHpsMWrY=",
+ version = "v0.4.1",
)
go_repository(
name = "org_golang_x_net",
diff --git a/go.mod b/go.mod
index 95b6572..c669003 100644
--- a/go.mod
+++ b/go.mod
@@ -3,12 +3,14 @@
go 1.16
require (
+ github.com/bazelbuild/bazel-gazelle v0.23.0
github.com/bazelbuild/bazelisk v1.10.1
github.com/bazelbuild/rules_go v0.28.0
github.com/fatih/color v1.12.0
github.com/golang/mock v1.3.1
github.com/golang/protobuf v1.5.2
github.com/magiconair/properties v1.8.5 // indirect
+ github.com/manifoldco/promptui v0.8.0
github.com/mattn/go-isatty v0.0.13
github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/mapstructure v1.4.1 // indirect
diff --git a/go.sum b/go.sum
index 59cbf2e..3c4d288 100644
--- a/go.sum
+++ b/go.sum
@@ -19,16 +19,27 @@
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/bazelbuild/bazel-gazelle v0.23.0 h1:Ks6YN+WkOv2lYWlvf7ksxUpLvrDbBHPBXXUrBFQ3BZM=
+github.com/bazelbuild/bazel-gazelle v0.23.0/go.mod h1:3mHi4TYn0QxwdMKPJfj3FKhZxYgWm46DjWQQPOg20BY=
github.com/bazelbuild/bazelisk v1.10.1 h1:2EWA2lRrt/k8B5ASt0mlTDQ+7mnzvKdF6ShNWLbk0o0=
github.com/bazelbuild/bazelisk v1.10.1/go.mod h1:s3ZIQZj3l9iCk/03rBgjhYvqz0c5SPRvoQCZuz8Lw/4=
+github.com/bazelbuild/buildtools v0.0.0-20200718160251-b1667ff58f71/go.mod h1:5JP0TXzWDHXv8qvxRC4InIazwdyDseBDbzESUMKk1yU=
+github.com/bazelbuild/rules_go v0.0.0-20190719190356-6dae44dc5cab/go.mod h1:MC23Dc/wkXEyk3Wpq6lCqz0ZAYOZDw2DR5y3N1q2i7M=
github.com/bazelbuild/rules_go v0.28.0 h1:fNtx0dJpG5ENGdMj3/GICoi/7z+ixB3IIW5rERTzOgM=
github.com/bazelbuild/rules_go v0.28.0/go.mod h1:MC23Dc/wkXEyk3Wpq6lCqz0ZAYOZDw2DR5y3N1q2i7M=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
+github.com/bmatcuk/doublestar v1.2.2/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
@@ -85,6 +96,7 @@
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
@@ -130,6 +142,8 @@
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU=
+github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
@@ -141,13 +155,18 @@
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a h1:weJVJJRzAJBFRlAiJQROKQs8oC9vOxvm4rZmBBk0ONw=
+github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
+github.com/manifoldco/promptui v0.8.0 h1:R95mMF+McvXZQ7j1g8ucVZE1gLP3Sv6j9vlF9kyRqQo=
+github.com/manifoldco/promptui v0.8.0/go.mod h1:n4zTdgP0vr0S3w7/O/g98U+e0gwLScEXGwov2nIKuGQ=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA=
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
@@ -278,6 +297,7 @@
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -306,6 +326,7 @@
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -314,6 +335,7 @@
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/pkg/aspect/build/BUILD.bazel b/pkg/aspect/build/BUILD.bazel
index 15ff92c..fe73fd8 100644
--- a/pkg/aspect/build/BUILD.bazel
+++ b/pkg/aspect/build/BUILD.bazel
@@ -9,8 +9,10 @@
"//pkg/aspect/build/bep",
"//pkg/aspecterrors",
"//pkg/bazel",
+ "//pkg/hooks",
"//pkg/ioutils",
"@com_github_spf13_cobra//:cobra",
+ "@go_googleapis//google/devtools/build/v1:build_go_proto",
],
)
@@ -22,6 +24,7 @@
"//pkg/aspect/build/bep/mock",
"//pkg/aspecterrors",
"//pkg/bazel/mock",
+ "//pkg/hooks",
"//pkg/ioutils",
"@com_github_golang_mock//gomock",
"@com_github_onsi_gomega//:gomega",
diff --git a/pkg/aspect/build/bep/bes_backend.go b/pkg/aspect/build/bep/bes_backend.go
index 7acb21d..dfb37e1 100644
--- a/pkg/aspect/build/bep/bes_backend.go
+++ b/pkg/aspect/build/bep/bes_backend.go
@@ -190,10 +190,3 @@
next *subscriberNode
callback CallbackFn
}
-
-// Plugin is the interface that wraps the BEPEventsSubscriber used to verify
-// whether an Aspect plugin registers itself to receive the Build Event Protocol
-// events.
-type Plugin interface {
- BEPEventsSubscriber() CallbackFn
-}
diff --git a/pkg/aspect/build/build.go b/pkg/aspect/build/build.go
index edb2297..65cb217 100644
--- a/pkg/aspect/build/build.go
+++ b/pkg/aspect/build/build.go
@@ -8,14 +8,17 @@
import (
"context"
+ "errors"
"fmt"
"time"
"github.com/spf13/cobra"
+ buildv1 "google.golang.org/genproto/googleapis/devtools/build/v1"
"aspect.build/cli/pkg/aspect/build/bep"
"aspect.build/cli/pkg/aspecterrors"
"aspect.build/cli/pkg/bazel"
+ "aspect.build/cli/pkg/hooks"
"aspect.build/cli/pkg/ioutils"
)
@@ -24,6 +27,7 @@
ioutils.Streams
bzl bazel.Spawner
besBackend bep.BESBackend
+ hooks *hooks.Hooks
}
// New creates a Build command.
@@ -31,19 +35,34 @@
streams ioutils.Streams,
bzl bazel.Spawner,
besBackend bep.BESBackend,
+ hooks *hooks.Hooks,
) *Build {
return &Build{
Streams: streams,
bzl: bzl,
besBackend: besBackend,
+ hooks: hooks,
}
}
// Run runs the aspect build command, calling `bazel build` with a local Build
// Event Protocol backend used by Aspect plugins to subscribe to build events.
-func (b *Build) Run(_ *cobra.Command, args []string) error {
- // TODO: register the BEP subscribers here with:
- // besBackend.RegisterSubscriber(plugin.BEPEventsSubscriber())
+func (b *Build) Run(ctx context.Context, cmd *cobra.Command, args []string) (exitErr error) {
+ // TODO(f0rmiga): this is a hook for the build command and should be discussed
+ // as part of the plugin design.
+ defer func(ctx context.Context) {
+ errs := b.hooks.ExecutePostBuild(ctx).Errors()
+ if len(errs) > 0 {
+ for _, err := range errs {
+ fmt.Fprintf(b.Streams.Stderr, "Error: failed to run build command: %v\n", err)
+ }
+ var err *aspecterrors.ExitError
+ if errors.As(exitErr, &err) {
+ err.ExitCode = 1
+ }
+ }
+ }(ctx)
+
if err := b.besBackend.Setup(); err != nil {
return fmt.Errorf("failed to run build command: %w", err)
}
@@ -55,22 +74,33 @@
defer b.besBackend.GracefulStop()
besBackendFlag := fmt.Sprintf("--bes_backend=grpc://%s", b.besBackend.Addr())
- cmd := append([]string{"build", besBackendFlag}, args...)
- if exitCode, err := b.bzl.Spawn(cmd); exitCode != 0 {
- err = &aspecterrors.ExitError{
- Err: err, // err can be nil, so don't wrap it with the full context.
- ExitCode: exitCode,
- }
- return err
- }
+ exitCode, bazelErr := b.bzl.Spawn(append([]string{"build", besBackendFlag}, args...))
+ // Process the subscribers errors before the Bazel one.
subscriberErrors := b.besBackend.Errors()
if len(subscriberErrors) > 0 {
for _, err := range subscriberErrors {
fmt.Fprintf(b.Streams.Stderr, "Error: failed to run build command: %v\n", err)
}
- return &aspecterrors.ExitError{ExitCode: 1}
+ exitCode = 1
+ }
+
+ if exitCode != 0 {
+ err := &aspecterrors.ExitError{ExitCode: exitCode}
+ if bazelErr != nil {
+ err.Err = bazelErr
+ }
+ return err
}
return nil
}
+
+// Plugin defines only the methods for the build command.
+type Plugin interface {
+ // BEPEventsSubscriber is used to verify whether an Aspect plugin registers
+ // itself to receive the Build Event Protocol events.
+ BEPEventCallback(event *buildv1.BuildEvent) error
+ // TODO(f0rmiga): test the build hooks after implementing the plugin system.
+ PostBuildHook(ctx context.Context) error
+}
diff --git a/pkg/aspect/build/build_test.go b/pkg/aspect/build/build_test.go
index 3a916eb..1cd88c4 100644
--- a/pkg/aspect/build/build_test.go
+++ b/pkg/aspect/build/build_test.go
@@ -7,6 +7,7 @@
package build_test
import (
+ "context"
"fmt"
"strings"
"testing"
@@ -18,6 +19,7 @@
bep_mock "aspect.build/cli/pkg/aspect/build/bep/mock"
"aspect.build/cli/pkg/aspecterrors"
bazel_mock "aspect.build/cli/pkg/bazel/mock"
+ "aspect.build/cli/pkg/hooks"
"aspect.build/cli/pkg/ioutils"
)
@@ -57,8 +59,10 @@
Errors().
Times(0)
- b := build.New(streams, spawner, besBackend)
- err := b.Run(nil, []string{"//..."})
+ hooks := hooks.New()
+ b := build.New(streams, spawner, besBackend, hooks)
+ ctx := context.Background()
+ err := b.Run(ctx, nil, []string{"//..."})
g.Expect(err).To(MatchError(fmt.Errorf("failed to run build command: %w", setupErr)))
})
@@ -99,8 +103,10 @@
Errors().
Times(0)
- b := build.New(streams, spawner, besBackend)
- err := b.Run(nil, []string{"//..."})
+ hooks := hooks.New()
+ b := build.New(streams, spawner, besBackend, hooks)
+ ctx := context.Background()
+ err := b.Run(ctx, nil, []string{"//..."})
g.Expect(err).To(MatchError(fmt.Errorf("failed to run build command: %w", serveWaitErr)))
})
@@ -143,10 +149,12 @@
besBackend.
EXPECT().
Errors().
- Times(0)
+ Times(1)
- b := build.New(streams, spawner, besBackend)
- err := b.Run(nil, []string{"//..."})
+ hooks := hooks.New()
+ b := build.New(streams, spawner, besBackend, hooks)
+ ctx := context.Background()
+ err := b.Run(ctx, nil, []string{"//..."})
g.Expect(err).To(MatchError(expectErr))
})
@@ -192,8 +200,10 @@
}).
Times(1)
- b := build.New(streams, spawner, besBackend)
- err := b.Run(nil, []string{"//..."})
+ hooks := hooks.New()
+ b := build.New(streams, spawner, besBackend, hooks)
+ ctx := context.Background()
+ err := b.Run(ctx, nil, []string{"//..."})
g.Expect(err).To(MatchError(&aspecterrors.ExitError{ExitCode: 1}))
g.Expect(stderr.String()).To(Equal("Error: failed to run build command: error 1\nError: failed to run build command: error 2\n"))
@@ -236,8 +246,10 @@
Return([]error{}).
Times(1)
- b := build.New(streams, spawner, besBackend)
- err := b.Run(nil, []string{"//..."})
+ hooks := hooks.New()
+ b := build.New(streams, spawner, besBackend, hooks)
+ ctx := context.Background()
+ err := b.Run(ctx, nil, []string{"//..."})
g.Expect(err).To(BeNil())
})
diff --git a/pkg/hooks/BUILD.bazel b/pkg/hooks/BUILD.bazel
new file mode 100644
index 0000000..182b928
--- /dev/null
+++ b/pkg/hooks/BUILD.bazel
@@ -0,0 +1,9 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "hooks",
+ srcs = ["hooks.go"],
+ importpath = "aspect.build/cli/pkg/hooks",
+ visibility = ["//visibility:public"],
+ deps = ["//pkg/aspecterrors"],
+)
diff --git a/pkg/hooks/hooks.go b/pkg/hooks/hooks.go
new file mode 100644
index 0000000..dc7215d
--- /dev/null
+++ b/pkg/hooks/hooks.go
@@ -0,0 +1,61 @@
+/*
+Copyright © 2021 Aspect Build Systems Inc
+
+Not licensed for re-use.
+*/
+
+package hooks
+
+import (
+ "context"
+
+ "aspect.build/cli/pkg/aspecterrors"
+)
+
+type Hooks struct {
+ postBuild *hookList
+}
+
+func New() *Hooks {
+ return &Hooks{
+ postBuild: &hookList{},
+ }
+}
+
+func (hooks *Hooks) RegisterPostBuild(fn PostBuildFn) {
+ hooks.postBuild.insert(fn)
+}
+
+func (hooks *Hooks) ExecutePostBuild(ctx context.Context) *aspecterrors.ErrorList {
+ errors := &aspecterrors.ErrorList{}
+ node := hooks.postBuild.head
+ for node != nil {
+ if err := node.fn.(PostBuildFn)(ctx); err != nil {
+ errors.Insert(err)
+ }
+ node = node.next
+ }
+ return errors
+}
+
+type PostBuildFn func(ctx context.Context) error
+
+type hookList struct {
+ head *hookNode
+ tail *hookNode
+}
+
+func (l *hookList) insert(fn interface{}) {
+ node := &hookNode{fn: fn}
+ if l.head == nil {
+ l.head = node
+ } else {
+ l.tail.next = node
+ }
+ l.tail = node
+}
+
+type hookNode struct {
+ next *hookNode
+ fn interface{}
+}
diff --git a/pkg/plugins/fix_visibility/BUILD.bazel b/pkg/plugins/fix_visibility/BUILD.bazel
new file mode 100644
index 0000000..61618ef
--- /dev/null
+++ b/pkg/plugins/fix_visibility/BUILD.bazel
@@ -0,0 +1,14 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "fix_visibility",
+ srcs = ["plugin.go"],
+ importpath = "aspect.build/cli/pkg/plugins/fix_visibility",
+ visibility = ["//cmd/aspect/build:__pkg__"],
+ deps = [
+ "@bazel_gazelle//label:go_default_library",
+ "@com_github_manifoldco_promptui//:promptui",
+ "@com_github_mattn_go_isatty//:go-isatty",
+ "@go_googleapis//google/devtools/build/v1:build_go_proto",
+ ],
+)
diff --git a/pkg/plugins/fix_visibility/plugin.go b/pkg/plugins/fix_visibility/plugin.go
new file mode 100644
index 0000000..f9bcc35
--- /dev/null
+++ b/pkg/plugins/fix_visibility/plugin.go
@@ -0,0 +1,180 @@
+/*
+Copyright © 2021 Aspect Build Systems Inc
+
+Not licensed for re-use.
+*/
+
+package fix_visibility
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "io"
+ "os"
+ "os/exec"
+ "regexp"
+ "time"
+
+ "github.com/bazelbuild/bazel-gazelle/label"
+ "github.com/manifoldco/promptui"
+ isatty "github.com/mattn/go-isatty"
+ buildv1 "google.golang.org/genproto/googleapis/devtools/build/v1"
+)
+
+type FixVisibilityPlugin struct {
+ stdout io.Writer
+ buildozer Runner
+ isInteractiveMode bool
+ applyFixPrompt promptui.Prompt
+ targetsToFix *fixOrderedSet
+}
+
+func NewDefaultPlugin() *FixVisibilityPlugin {
+ isInteractiveMode := isatty.IsTerminal(os.Stdout.Fd()) || isatty.IsCygwinTerminal(os.Stdout.Fd())
+ applyFixPrompt := promptui.Prompt{
+ Label: "Would you like to apply the visibility fixes",
+ IsConfirm: true,
+ }
+ return NewPlugin(os.Stdout, &buildozer{}, isInteractiveMode, applyFixPrompt)
+}
+
+func NewPlugin(
+ stdout io.Writer,
+ buildozer Runner,
+ isInteractiveMode bool,
+ applyFixPrompt promptui.Prompt,
+) *FixVisibilityPlugin {
+ return &FixVisibilityPlugin{
+ stdout: stdout,
+ buildozer: buildozer,
+ isInteractiveMode: isInteractiveMode,
+ targetsToFix: &fixOrderedSet{nodes: make(map[fixNode]struct{})},
+ applyFixPrompt: applyFixPrompt,
+ }
+}
+
+var visibilityIssueRegex = regexp.MustCompile(`.*target '(.*)' is not visible from target '(.*)'.*`)
+var visibilityIssueSubstring = []byte("is not visible from target")
+
+func (plugin *FixVisibilityPlugin) BEPEventCallback(event *buildv1.BuildEvent) error {
+ bazelEvent := event.GetBazelEvent()
+ if bazelEvent != nil {
+ if !bytes.Contains(bazelEvent.Value, visibilityIssueSubstring) {
+ return nil
+ }
+ matches := visibilityIssueRegex.FindSubmatch(bazelEvent.Value)
+ if len(matches) != 3 {
+ return nil
+ }
+ plugin.targetsToFix.insert(string(matches[1]), string(matches[2]))
+ }
+ return nil
+}
+
+const removePrivateVisibilityBuildozerCommand = "remove visibility //visibility:private"
+
+func (plugin *FixVisibilityPlugin) PostBuildHook(ctx context.Context) error {
+ if plugin.targetsToFix.size == 0 {
+ return nil
+ }
+
+ // TODO(f0rmiga): make the timeout configurable via the plugin configuration
+ // file.
+ ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
+ defer cancel()
+
+ // TODO(f0rmiga): check if buildozer is installed, otherwise return an error.
+ for node := plugin.targetsToFix.head; node != nil; node = node.next {
+ fromLabel, err := label.Parse(node.from)
+ if err != nil {
+ return fmt.Errorf("failed to fix visibility: %w", err)
+ }
+ fromLabel.Name = "__pkg__"
+
+ hasPrivateVisibility, err := plugin.hasPrivateVisibility(ctx, node.toFix)
+ if err != nil {
+ return fmt.Errorf("failed to fix visibility: %w", err)
+ }
+
+ var applyFix bool
+ if plugin.isInteractiveMode {
+ _, err := plugin.applyFixPrompt.Run()
+ applyFix = err == nil
+ }
+
+ addVisibilityBuildozerCommand := fmt.Sprintf("add visibility %s", fromLabel)
+ if applyFix {
+ if _, err := plugin.buildozer.Run(ctx, addVisibilityBuildozerCommand, node.toFix); err != nil {
+ return fmt.Errorf("failed to fix visibility: %w", err)
+ }
+ if hasPrivateVisibility {
+ if _, err := plugin.buildozer.Run(ctx, removePrivateVisibilityBuildozerCommand, node.toFix); err != nil {
+ return fmt.Errorf("failed to fix visibility: %w", err)
+ }
+ }
+ } else {
+ fmt.Fprintf(plugin.stdout, "To fix the visibility errors, run:\n")
+ fmt.Fprintf(plugin.stdout, "buildozer '%s' %s\n", addVisibilityBuildozerCommand, node.toFix)
+ if hasPrivateVisibility {
+ fmt.Fprintf(plugin.stdout, "buildozer '%s' %s\n", removePrivateVisibilityBuildozerCommand, node.toFix)
+ }
+ }
+ }
+
+ return nil
+}
+
+func (plugin *FixVisibilityPlugin) hasPrivateVisibility(ctx context.Context, toFix string) (bool, error) {
+ visibility, err := plugin.buildozer.Run(ctx, "print visibility", toFix)
+ if err != nil {
+ return false, fmt.Errorf("failed to check if target has private visibility: %w", err)
+ }
+ return bytes.Contains(visibility, []byte("//visibility:private")), nil
+}
+
+type fixOrderedSet struct {
+ head *fixNode
+ tail *fixNode
+ nodes map[fixNode]struct{}
+ size int
+}
+
+func (s *fixOrderedSet) insert(toFix, from string) {
+ node := fixNode{
+ toFix: toFix,
+ from: from,
+ }
+ if _, exists := s.nodes[node]; !exists {
+ s.nodes[node] = struct{}{}
+ if s.head == nil {
+ s.head = &node
+ } else {
+ s.tail.next = &node
+ }
+ s.tail = &node
+ s.size++
+ }
+}
+
+type fixNode struct {
+ next *fixNode
+ toFix string
+ from string
+}
+
+type Runner interface {
+ Run(ctx context.Context, args ...string) ([]byte, error)
+}
+
+type buildozer struct{}
+
+func (b *buildozer) Run(ctx context.Context, args ...string) ([]byte, error) {
+ cmd := exec.CommandContext(ctx, "buildozer", args...)
+ var stdout bytes.Buffer
+ cmd.Stdout = &stdout
+ if err := cmd.Run(); err != nil {
+ return stdout.Bytes(), fmt.Errorf("failed to run buildozer: %w", err)
+ }
+ return stdout.Bytes(), nil
+}