Merge "Allow //visibility:public to override other visibility rules."
This commit is contained in:
@@ -197,8 +197,10 @@ where `//project` is the module's package. e.g. using `[":__subpackages__"]` in
|
|||||||
* `["//visibility:legacy_public"]`: The default visibility, behaves as
|
* `["//visibility:legacy_public"]`: The default visibility, behaves as
|
||||||
`//visibility:public` for now. It is an error if it is used in a module.
|
`//visibility:public` for now. It is an error if it is used in a module.
|
||||||
|
|
||||||
The visibility rules of `//visibility:public` and `//visibility:private` can
|
The visibility rules of `//visibility:public` and `//visibility:private` can not
|
||||||
not be combined with any other visibility specifications.
|
be combined with any other visibility specifications, except
|
||||||
|
`//visibility:public` is allowed to override visibility specifications imported
|
||||||
|
through the `defaults` property.
|
||||||
|
|
||||||
Packages outside `vendor/` cannot make themselves visible to specific packages
|
Packages outside `vendor/` cannot make themselves visible to specific packages
|
||||||
in `vendor/`, e.g. a module in `libcore` cannot declare that it is visible to
|
in `vendor/`, e.g. a module in `libcore` cannot declare that it is visible to
|
||||||
|
@@ -76,6 +76,7 @@ var preArch = []RegisterMutatorFunc{
|
|||||||
registerLoadHookMutator,
|
registerLoadHookMutator,
|
||||||
RegisterNamespaceMutator,
|
RegisterNamespaceMutator,
|
||||||
RegisterPrebuiltsPreArchMutators,
|
RegisterPrebuiltsPreArchMutators,
|
||||||
|
registerVisibilityRuleChecker,
|
||||||
RegisterDefaultsPreArchMutators,
|
RegisterDefaultsPreArchMutators,
|
||||||
registerVisibilityRuleGatherer,
|
registerVisibilityRuleGatherer,
|
||||||
}
|
}
|
||||||
|
@@ -71,7 +71,17 @@ type visibilityRule interface {
|
|||||||
String() string
|
String() string
|
||||||
}
|
}
|
||||||
|
|
||||||
// A compositeRule is a visibility rule composed from other visibility rules.
|
// A compositeRule is a visibility rule composed from a list of atomic visibility rules.
|
||||||
|
//
|
||||||
|
// The list corresponds to the list of strings in the visibility property after defaults expansion.
|
||||||
|
// Even though //visibility:public is not allowed together with other rules in the visibility list
|
||||||
|
// of a single module, it is allowed here to permit a module to override an inherited visibility
|
||||||
|
// spec with public visibility.
|
||||||
|
//
|
||||||
|
// //visibility:private is not allowed in the same way, since we'd need to check for it during the
|
||||||
|
// defaults expansion to make that work. No non-private visibility rules are allowed in a
|
||||||
|
// compositeRule containing a privateRule.
|
||||||
|
//
|
||||||
// This array will only be [] if all the rules are invalid and will behave as if visibility was
|
// This array will only be [] if all the rules are invalid and will behave as if visibility was
|
||||||
// ["//visibility:private"].
|
// ["//visibility:private"].
|
||||||
type compositeRule []visibilityRule
|
type compositeRule []visibilityRule
|
||||||
@@ -126,6 +136,28 @@ func (r subpackagesRule) String() string {
|
|||||||
return fmt.Sprintf("//%s:__subpackages__", r.pkgPrefix)
|
return fmt.Sprintf("//%s:__subpackages__", r.pkgPrefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// visibilityRule for //visibility:public
|
||||||
|
type publicRule struct{}
|
||||||
|
|
||||||
|
func (r publicRule) matches(_ qualifiedModuleName) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r publicRule) String() string {
|
||||||
|
return "//visibility:public"
|
||||||
|
}
|
||||||
|
|
||||||
|
// visibilityRule for //visibility:private
|
||||||
|
type privateRule struct{}
|
||||||
|
|
||||||
|
func (r privateRule) matches(_ qualifiedModuleName) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r privateRule) String() string {
|
||||||
|
return "//visibility:private"
|
||||||
|
}
|
||||||
|
|
||||||
var visibilityRuleMap = NewOnceKey("visibilityRuleMap")
|
var visibilityRuleMap = NewOnceKey("visibilityRuleMap")
|
||||||
|
|
||||||
// The map from qualifiedModuleName to visibilityRule.
|
// The map from qualifiedModuleName to visibilityRule.
|
||||||
@@ -135,8 +167,15 @@ func moduleToVisibilityRuleMap(ctx BaseModuleContext) *sync.Map {
|
|||||||
}).(*sync.Map)
|
}).(*sync.Map)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The rule checker needs to be registered before defaults expansion to correctly check that
|
||||||
|
// //visibility:xxx isn't combined with other packages in the same list in any one module.
|
||||||
|
func registerVisibilityRuleChecker(ctx RegisterMutatorsContext) {
|
||||||
|
ctx.BottomUp("visibilityRuleChecker", visibilityRuleChecker).Parallel()
|
||||||
|
}
|
||||||
|
|
||||||
// Visibility is not dependent on arch so this must be registered before the arch phase to avoid
|
// Visibility is not dependent on arch so this must be registered before the arch phase to avoid
|
||||||
// having to process multiple variants for each module.
|
// having to process multiple variants for each module. This goes after defaults expansion to gather
|
||||||
|
// the complete visibility lists from flat lists.
|
||||||
func registerVisibilityRuleGatherer(ctx RegisterMutatorsContext) {
|
func registerVisibilityRuleGatherer(ctx RegisterMutatorsContext) {
|
||||||
ctx.BottomUp("visibilityRuleGatherer", visibilityRuleGatherer).Parallel()
|
ctx.BottomUp("visibilityRuleGatherer", visibilityRuleGatherer).Parallel()
|
||||||
}
|
}
|
||||||
@@ -146,11 +185,80 @@ func registerVisibilityRuleEnforcer(ctx RegisterMutatorsContext) {
|
|||||||
ctx.TopDown("visibilityRuleEnforcer", visibilityRuleEnforcer).Parallel()
|
ctx.TopDown("visibilityRuleEnforcer", visibilityRuleEnforcer).Parallel()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gathers the visibility rules, parses the visibility properties, stores them in a map by
|
// Checks the per-module visibility rule lists before defaults expansion.
|
||||||
// qualifiedModuleName for retrieval during enforcement.
|
func visibilityRuleChecker(ctx BottomUpMutatorContext) {
|
||||||
|
qualified := createQualifiedModuleName(ctx)
|
||||||
|
if d, ok := ctx.Module().(Defaults); ok {
|
||||||
|
// Defaults modules don't store the payload properties in m.base().
|
||||||
|
for _, props := range d.properties() {
|
||||||
|
if cp, ok := props.(*commonProperties); ok {
|
||||||
|
if visibility := cp.Visibility; visibility != nil {
|
||||||
|
checkRules(ctx, qualified.pkg, visibility)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if m, ok := ctx.Module().(Module); ok {
|
||||||
|
if visibility := m.base().commonProperties.Visibility; visibility != nil {
|
||||||
|
checkRules(ctx, qualified.pkg, visibility)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkRules(ctx BottomUpMutatorContext, currentPkg string, visibility []string) {
|
||||||
|
ruleCount := len(visibility)
|
||||||
|
if ruleCount == 0 {
|
||||||
|
// This prohibits an empty list as its meaning is unclear, e.g. it could mean no visibility and
|
||||||
|
// it could mean public visibility. Requiring at least one rule makes the owner's intent
|
||||||
|
// clearer.
|
||||||
|
ctx.PropertyErrorf("visibility", "must contain at least one visibility rule")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range visibility {
|
||||||
|
ok, pkg, name := splitRule(ctx, v, currentPkg)
|
||||||
|
if !ok {
|
||||||
|
// Visibility rule is invalid so ignore it. Keep going rather than aborting straight away to
|
||||||
|
// ensure all the rules on this module are checked.
|
||||||
|
ctx.PropertyErrorf("visibility",
|
||||||
|
"invalid visibility pattern %q must match"+
|
||||||
|
" //<package>:<module>, //<package> or :<module>",
|
||||||
|
v)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if pkg == "visibility" {
|
||||||
|
switch name {
|
||||||
|
case "private", "public":
|
||||||
|
case "legacy_public":
|
||||||
|
ctx.PropertyErrorf("visibility", "//visibility:legacy_public must not be used")
|
||||||
|
continue
|
||||||
|
default:
|
||||||
|
ctx.PropertyErrorf("visibility", "unrecognized visibility rule %q", v)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ruleCount != 1 {
|
||||||
|
ctx.PropertyErrorf("visibility", "cannot mix %q with any other visibility rules", v)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the current directory is not in the vendor tree then there are some additional
|
||||||
|
// restrictions on the rules.
|
||||||
|
if !isAncestor("vendor", currentPkg) {
|
||||||
|
if !isAllowedFromOutsideVendor(pkg, name) {
|
||||||
|
ctx.PropertyErrorf("visibility",
|
||||||
|
"%q is not allowed. Packages outside //vendor cannot make themselves visible to specific"+
|
||||||
|
" targets within //vendor, they can only use //vendor:__subpackages__.", v)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gathers the flattened visibility rules after defaults expansion, parses the visibility
|
||||||
|
// properties, stores them in a map by qualifiedModuleName for retrieval during enforcement.
|
||||||
//
|
//
|
||||||
// See ../README.md#Visibility for information on the format of the visibility rules.
|
// See ../README.md#Visibility for information on the format of the visibility rules.
|
||||||
|
|
||||||
func visibilityRuleGatherer(ctx BottomUpMutatorContext) {
|
func visibilityRuleGatherer(ctx BottomUpMutatorContext) {
|
||||||
m, ok := ctx.Module().(Module)
|
m, ok := ctx.Module().(Module)
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -169,74 +277,51 @@ func visibilityRuleGatherer(ctx BottomUpMutatorContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func parseRules(ctx BottomUpMutatorContext, currentPkg string, visibility []string) compositeRule {
|
func parseRules(ctx BottomUpMutatorContext, currentPkg string, visibility []string) compositeRule {
|
||||||
ruleCount := len(visibility)
|
rules := make(compositeRule, 0, len(visibility))
|
||||||
if ruleCount == 0 {
|
hasPrivateRule := false
|
||||||
// This prohibits an empty list as its meaning is unclear, e.g. it could mean no visibility and
|
hasNonPrivateRule := false
|
||||||
// it could mean public visibility. Requiring at least one rule makes the owner's intent
|
|
||||||
// clearer.
|
|
||||||
ctx.PropertyErrorf("visibility", "must contain at least one visibility rule")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
rules := make(compositeRule, 0, ruleCount)
|
|
||||||
for _, v := range visibility {
|
for _, v := range visibility {
|
||||||
ok, pkg, name := splitRule(ctx, v, currentPkg)
|
ok, pkg, name := splitRule(ctx, v, currentPkg)
|
||||||
if !ok {
|
if !ok {
|
||||||
// Visibility rule is invalid so ignore it. Keep going rather than aborting straight away to
|
|
||||||
// ensure all the rules on this module are checked.
|
|
||||||
ctx.PropertyErrorf("visibility",
|
|
||||||
"invalid visibility pattern %q must match"+
|
|
||||||
" //<package>:<module>, //<package> or :<module>",
|
|
||||||
v)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var r visibilityRule
|
||||||
|
isPrivateRule := false
|
||||||
if pkg == "visibility" {
|
if pkg == "visibility" {
|
||||||
if ruleCount != 1 {
|
|
||||||
ctx.PropertyErrorf("visibility", "cannot mix %q with any other visibility rules", v)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
switch name {
|
switch name {
|
||||||
case "private":
|
case "private":
|
||||||
rules = append(rules, packageRule{currentPkg})
|
r = privateRule{}
|
||||||
continue
|
isPrivateRule = true
|
||||||
case "public":
|
case "public":
|
||||||
return nil
|
r = publicRule{}
|
||||||
case "legacy_public":
|
}
|
||||||
ctx.PropertyErrorf("visibility", "//visibility:legacy_public must not be used")
|
} else {
|
||||||
return nil
|
switch name {
|
||||||
|
case "__pkg__":
|
||||||
|
r = packageRule{pkg}
|
||||||
|
case "__subpackages__":
|
||||||
|
r = subpackagesRule{pkg}
|
||||||
default:
|
default:
|
||||||
ctx.PropertyErrorf("visibility", "unrecognized visibility rule %q", v)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the current directory is not in the vendor tree then there are some additional
|
if isPrivateRule {
|
||||||
// restrictions on the rules.
|
hasPrivateRule = true
|
||||||
if !isAncestor("vendor", currentPkg) {
|
} else {
|
||||||
if !isAllowedFromOutsideVendor(pkg, name) {
|
hasNonPrivateRule = true
|
||||||
ctx.PropertyErrorf("visibility",
|
|
||||||
"%q is not allowed. Packages outside //vendor cannot make themselves visible to specific"+
|
|
||||||
" targets within //vendor, they can only use //vendor:__subpackages__.", v)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the rule
|
|
||||||
var r visibilityRule
|
|
||||||
switch name {
|
|
||||||
case "__pkg__":
|
|
||||||
r = packageRule{pkg}
|
|
||||||
case "__subpackages__":
|
|
||||||
r = subpackagesRule{pkg}
|
|
||||||
default:
|
|
||||||
ctx.PropertyErrorf("visibility", "unrecognized visibility rule %q", v)
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rules = append(rules, r)
|
rules = append(rules, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if hasPrivateRule && hasNonPrivateRule {
|
||||||
|
ctx.PropertyErrorf("visibility",
|
||||||
|
"cannot mix \"//visibility:private\" with any other visibility rules")
|
||||||
|
return compositeRule{privateRule{}}
|
||||||
|
}
|
||||||
|
|
||||||
return rules
|
return rules
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,8 +359,7 @@ func splitRule(ctx BaseModuleContext, ruleExpression string, currentPkg string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func visibilityRuleEnforcer(ctx TopDownMutatorContext) {
|
func visibilityRuleEnforcer(ctx TopDownMutatorContext) {
|
||||||
_, ok := ctx.Module().(Module)
|
if _, ok := ctx.Module().(Module); !ok {
|
||||||
if !ok {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,9 +381,7 @@ func visibilityRuleEnforcer(ctx TopDownMutatorContext) {
|
|||||||
rule, ok := moduleToVisibilityRule.Load(depQualified)
|
rule, ok := moduleToVisibilityRule.Load(depQualified)
|
||||||
if ok {
|
if ok {
|
||||||
if !rule.(compositeRule).matches(qualified) {
|
if !rule.(compositeRule).matches(qualified) {
|
||||||
ctx.ModuleErrorf(
|
ctx.ModuleErrorf("depends on %s which is not visible to this module", depQualified)
|
||||||
"depends on %s which is not visible to this module; %s is only visible to %s",
|
|
||||||
depQualified, depQualified, rule)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@@ -91,7 +91,7 @@ var visibilityTests = []struct {
|
|||||||
expectedErrors: []string{`unrecognized visibility rule "//visibility:unknown"`},
|
expectedErrors: []string{`unrecognized visibility rule "//visibility:unknown"`},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "//visibility:public mixed",
|
name: "//visibility:xxx mixed",
|
||||||
fs: map[string][]byte{
|
fs: map[string][]byte{
|
||||||
"top/Blueprints": []byte(`
|
"top/Blueprints": []byte(`
|
||||||
mock_library {
|
mock_library {
|
||||||
@@ -105,10 +105,10 @@ var visibilityTests = []struct {
|
|||||||
}`),
|
}`),
|
||||||
},
|
},
|
||||||
expectedErrors: []string{
|
expectedErrors: []string{
|
||||||
`module "libother" variant "android_common": visibility: cannot mix "//visibility:private"` +
|
`module "libother": visibility: cannot mix "//visibility:private"` +
|
||||||
|
` with any other visibility rules`,
|
||||||
|
`module "libexample": visibility: cannot mix "//visibility:public"` +
|
||||||
` with any other visibility rules`,
|
` with any other visibility rules`,
|
||||||
`module "libexample" variant "android_common": visibility: cannot mix` +
|
|
||||||
` "//visibility:public" with any other visibility rules`,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -121,7 +121,7 @@ var visibilityTests = []struct {
|
|||||||
}`),
|
}`),
|
||||||
},
|
},
|
||||||
expectedErrors: []string{
|
expectedErrors: []string{
|
||||||
`module "libexample" variant "android_common": visibility: //visibility:legacy_public must` +
|
`module "libexample": visibility: //visibility:legacy_public must` +
|
||||||
` not be used`,
|
` not be used`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -152,33 +152,6 @@ var visibilityTests = []struct {
|
|||||||
}`),
|
}`),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
// Verify that //visibility:public will allow the module to be referenced from anywhere, e.g.
|
|
||||||
// the current directory, a nested directory and a directory in a separate tree.
|
|
||||||
name: "//visibility:public",
|
|
||||||
fs: map[string][]byte{
|
|
||||||
"top/Blueprints": []byte(`
|
|
||||||
mock_library {
|
|
||||||
name: "libexample",
|
|
||||||
visibility: ["//visibility:public"],
|
|
||||||
}
|
|
||||||
|
|
||||||
mock_library {
|
|
||||||
name: "libsamepackage",
|
|
||||||
deps: ["libexample"],
|
|
||||||
}`),
|
|
||||||
"top/nested/Blueprints": []byte(`
|
|
||||||
mock_library {
|
|
||||||
name: "libnested",
|
|
||||||
deps: ["libexample"],
|
|
||||||
}`),
|
|
||||||
"other/Blueprints": []byte(`
|
|
||||||
mock_library {
|
|
||||||
name: "libother",
|
|
||||||
deps: ["libexample"],
|
|
||||||
}`),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
// Verify that //visibility:private allows the module to be referenced from the current
|
// Verify that //visibility:private allows the module to be referenced from the current
|
||||||
// directory only.
|
// directory only.
|
||||||
@@ -207,9 +180,9 @@ var visibilityTests = []struct {
|
|||||||
},
|
},
|
||||||
expectedErrors: []string{
|
expectedErrors: []string{
|
||||||
`module "libnested" variant "android_common": depends on //top:libexample which is not` +
|
`module "libnested" variant "android_common": depends on //top:libexample which is not` +
|
||||||
` visible to this module; //top:libexample is only visible to \[//top:__pkg__\]`,
|
` visible to this module`,
|
||||||
`module "libother" variant "android_common": depends on //top:libexample which is not` +
|
`module "libother" variant "android_common": depends on //top:libexample which is not` +
|
||||||
` visible to this module; //top:libexample is only visible to \[//top:__pkg__\]`,
|
` visible to this module`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -239,9 +212,9 @@ var visibilityTests = []struct {
|
|||||||
},
|
},
|
||||||
expectedErrors: []string{
|
expectedErrors: []string{
|
||||||
`module "libnested" variant "android_common": depends on //top:libexample which is not` +
|
`module "libnested" variant "android_common": depends on //top:libexample which is not` +
|
||||||
` visible to this module; //top:libexample is only visible to \[//top:__pkg__\]`,
|
` visible to this module`,
|
||||||
`module "libother" variant "android_common": depends on //top:libexample which is not` +
|
`module "libother" variant "android_common": depends on //top:libexample which is not` +
|
||||||
` visible to this module; //top:libexample is only visible to \[//top:__pkg__\]`,
|
` visible to this module`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -277,9 +250,9 @@ var visibilityTests = []struct {
|
|||||||
},
|
},
|
||||||
expectedErrors: []string{
|
expectedErrors: []string{
|
||||||
`module "libother" variant "android_common": depends on //top:libexample which is not` +
|
`module "libother" variant "android_common": depends on //top:libexample which is not` +
|
||||||
` visible to this module; //top:libexample is only visible to \[//top/nested:__pkg__\]`,
|
` visible to this module`,
|
||||||
`module "libnestedagain" variant "android_common": depends on //top:libexample which is not` +
|
`module "libnestedagain" variant "android_common": depends on //top:libexample which is not` +
|
||||||
` visible to this module; //top:libexample is only visible to \[//top/nested:__pkg__\]`,
|
` visible to this module`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -310,7 +283,7 @@ var visibilityTests = []struct {
|
|||||||
},
|
},
|
||||||
expectedErrors: []string{
|
expectedErrors: []string{
|
||||||
`module "libother" variant "android_common": depends on //top:libexample which is not` +
|
`module "libother" variant "android_common": depends on //top:libexample which is not` +
|
||||||
` visible to this module; //top:libexample is only visible to \[//top:__subpackages__\]`,
|
` visible to this module`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -341,8 +314,7 @@ var visibilityTests = []struct {
|
|||||||
},
|
},
|
||||||
expectedErrors: []string{
|
expectedErrors: []string{
|
||||||
`module "libother" variant "android_common": depends on //top:libexample which is not` +
|
`module "libother" variant "android_common": depends on //top:libexample which is not` +
|
||||||
` visible to this module; //top:libexample is only visible to` +
|
` visible to this module`,
|
||||||
` \[//top/nested:__subpackages__, //other:__pkg__\]`,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -399,11 +371,295 @@ var visibilityTests = []struct {
|
|||||||
}`),
|
}`),
|
||||||
},
|
},
|
||||||
expectedErrors: []string{
|
expectedErrors: []string{
|
||||||
`module "libsamepackage" variant "android_common": visibility: "//vendor/apps/AcmeSettings"` +
|
`module "libsamepackage": visibility: "//vendor/apps/AcmeSettings"` +
|
||||||
` is not allowed. Packages outside //vendor cannot make themselves visible to specific` +
|
` is not allowed. Packages outside //vendor cannot make themselves visible to specific` +
|
||||||
` targets within //vendor, they can only use //vendor:__subpackages__.`,
|
` targets within //vendor, they can only use //vendor:__subpackages__.`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Defaults propagation tests
|
||||||
|
{
|
||||||
|
// Check that visibility is the union of the defaults modules.
|
||||||
|
name: "defaults union, basic",
|
||||||
|
fs: map[string][]byte{
|
||||||
|
"top/Blueprints": []byte(`
|
||||||
|
mock_defaults {
|
||||||
|
name: "libexample_defaults",
|
||||||
|
visibility: ["//other"],
|
||||||
|
}
|
||||||
|
mock_library {
|
||||||
|
name: "libexample",
|
||||||
|
visibility: ["//top/nested"],
|
||||||
|
defaults: ["libexample_defaults"],
|
||||||
|
}
|
||||||
|
mock_library {
|
||||||
|
name: "libsamepackage",
|
||||||
|
deps: ["libexample"],
|
||||||
|
}`),
|
||||||
|
"top/nested/Blueprints": []byte(`
|
||||||
|
mock_library {
|
||||||
|
name: "libnested",
|
||||||
|
deps: ["libexample"],
|
||||||
|
}`),
|
||||||
|
"other/Blueprints": []byte(`
|
||||||
|
mock_library {
|
||||||
|
name: "libother",
|
||||||
|
deps: ["libexample"],
|
||||||
|
}`),
|
||||||
|
"outsider/Blueprints": []byte(`
|
||||||
|
mock_library {
|
||||||
|
name: "liboutsider",
|
||||||
|
deps: ["libexample"],
|
||||||
|
}`),
|
||||||
|
},
|
||||||
|
expectedErrors: []string{
|
||||||
|
`module "liboutsider" variant "android_common": depends on //top:libexample which is not` +
|
||||||
|
` visible to this module`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "defaults union, multiple defaults",
|
||||||
|
fs: map[string][]byte{
|
||||||
|
"top/Blueprints": []byte(`
|
||||||
|
mock_defaults {
|
||||||
|
name: "libexample_defaults_1",
|
||||||
|
visibility: ["//other"],
|
||||||
|
}
|
||||||
|
mock_defaults {
|
||||||
|
name: "libexample_defaults_2",
|
||||||
|
visibility: ["//top/nested"],
|
||||||
|
}
|
||||||
|
mock_library {
|
||||||
|
name: "libexample",
|
||||||
|
defaults: ["libexample_defaults_1", "libexample_defaults_2"],
|
||||||
|
}
|
||||||
|
mock_library {
|
||||||
|
name: "libsamepackage",
|
||||||
|
deps: ["libexample"],
|
||||||
|
}`),
|
||||||
|
"top/nested/Blueprints": []byte(`
|
||||||
|
mock_library {
|
||||||
|
name: "libnested",
|
||||||
|
deps: ["libexample"],
|
||||||
|
}`),
|
||||||
|
"other/Blueprints": []byte(`
|
||||||
|
mock_library {
|
||||||
|
name: "libother",
|
||||||
|
deps: ["libexample"],
|
||||||
|
}`),
|
||||||
|
"outsider/Blueprints": []byte(`
|
||||||
|
mock_library {
|
||||||
|
name: "liboutsider",
|
||||||
|
deps: ["libexample"],
|
||||||
|
}`),
|
||||||
|
},
|
||||||
|
expectedErrors: []string{
|
||||||
|
`module "liboutsider" variant "android_common": depends on //top:libexample which is not` +
|
||||||
|
` visible to this module`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "//visibility:public mixed with other in defaults",
|
||||||
|
fs: map[string][]byte{
|
||||||
|
"top/Blueprints": []byte(`
|
||||||
|
mock_defaults {
|
||||||
|
name: "libexample_defaults",
|
||||||
|
visibility: ["//visibility:public", "//namespace"],
|
||||||
|
}
|
||||||
|
mock_library {
|
||||||
|
name: "libexample",
|
||||||
|
defaults: ["libexample_defaults"],
|
||||||
|
}`),
|
||||||
|
},
|
||||||
|
expectedErrors: []string{
|
||||||
|
`module "libexample_defaults": visibility: cannot mix "//visibility:public"` +
|
||||||
|
` with any other visibility rules`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "//visibility:public overriding defaults",
|
||||||
|
fs: map[string][]byte{
|
||||||
|
"top/Blueprints": []byte(`
|
||||||
|
mock_defaults {
|
||||||
|
name: "libexample_defaults",
|
||||||
|
visibility: ["//namespace"],
|
||||||
|
}
|
||||||
|
mock_library {
|
||||||
|
name: "libexample",
|
||||||
|
visibility: ["//visibility:public"],
|
||||||
|
defaults: ["libexample_defaults"],
|
||||||
|
}`),
|
||||||
|
"outsider/Blueprints": []byte(`
|
||||||
|
mock_library {
|
||||||
|
name: "liboutsider",
|
||||||
|
deps: ["libexample"],
|
||||||
|
}`),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "//visibility:public mixed with other from different defaults 1",
|
||||||
|
fs: map[string][]byte{
|
||||||
|
"top/Blueprints": []byte(`
|
||||||
|
mock_defaults {
|
||||||
|
name: "libexample_defaults_1",
|
||||||
|
visibility: ["//namespace"],
|
||||||
|
}
|
||||||
|
mock_defaults {
|
||||||
|
name: "libexample_defaults_2",
|
||||||
|
visibility: ["//visibility:public"],
|
||||||
|
}
|
||||||
|
mock_library {
|
||||||
|
name: "libexample",
|
||||||
|
defaults: ["libexample_defaults_1", "libexample_defaults_2"],
|
||||||
|
}`),
|
||||||
|
"outsider/Blueprints": []byte(`
|
||||||
|
mock_library {
|
||||||
|
name: "liboutsider",
|
||||||
|
deps: ["libexample"],
|
||||||
|
}`),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "//visibility:public mixed with other from different defaults 2",
|
||||||
|
fs: map[string][]byte{
|
||||||
|
"top/Blueprints": []byte(`
|
||||||
|
mock_defaults {
|
||||||
|
name: "libexample_defaults_1",
|
||||||
|
visibility: ["//visibility:public"],
|
||||||
|
}
|
||||||
|
mock_defaults {
|
||||||
|
name: "libexample_defaults_2",
|
||||||
|
visibility: ["//namespace"],
|
||||||
|
}
|
||||||
|
mock_library {
|
||||||
|
name: "libexample",
|
||||||
|
defaults: ["libexample_defaults_1", "libexample_defaults_2"],
|
||||||
|
}`),
|
||||||
|
"outsider/Blueprints": []byte(`
|
||||||
|
mock_library {
|
||||||
|
name: "liboutsider",
|
||||||
|
deps: ["libexample"],
|
||||||
|
}`),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "//visibility:private in defaults",
|
||||||
|
fs: map[string][]byte{
|
||||||
|
"top/Blueprints": []byte(`
|
||||||
|
mock_defaults {
|
||||||
|
name: "libexample_defaults",
|
||||||
|
visibility: ["//visibility:private"],
|
||||||
|
}
|
||||||
|
mock_library {
|
||||||
|
name: "libexample",
|
||||||
|
defaults: ["libexample_defaults"],
|
||||||
|
}
|
||||||
|
mock_library {
|
||||||
|
name: "libsamepackage",
|
||||||
|
deps: ["libexample"],
|
||||||
|
}`),
|
||||||
|
"top/nested/Blueprints": []byte(`
|
||||||
|
mock_library {
|
||||||
|
name: "libnested",
|
||||||
|
deps: ["libexample"],
|
||||||
|
}`),
|
||||||
|
"other/Blueprints": []byte(`
|
||||||
|
mock_library {
|
||||||
|
name: "libother",
|
||||||
|
deps: ["libexample"],
|
||||||
|
}`),
|
||||||
|
},
|
||||||
|
expectedErrors: []string{
|
||||||
|
`module "libnested" variant "android_common": depends on //top:libexample which is not` +
|
||||||
|
` visible to this module`,
|
||||||
|
`module "libother" variant "android_common": depends on //top:libexample which is not` +
|
||||||
|
` visible to this module`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "//visibility:private mixed with other in defaults",
|
||||||
|
fs: map[string][]byte{
|
||||||
|
"top/Blueprints": []byte(`
|
||||||
|
mock_defaults {
|
||||||
|
name: "libexample_defaults",
|
||||||
|
visibility: ["//visibility:private", "//namespace"],
|
||||||
|
}
|
||||||
|
mock_library {
|
||||||
|
name: "libexample",
|
||||||
|
defaults: ["libexample_defaults"],
|
||||||
|
}`),
|
||||||
|
},
|
||||||
|
expectedErrors: []string{
|
||||||
|
`module "libexample_defaults": visibility: cannot mix "//visibility:private"` +
|
||||||
|
` with any other visibility rules`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "//visibility:private overriding defaults",
|
||||||
|
fs: map[string][]byte{
|
||||||
|
"top/Blueprints": []byte(`
|
||||||
|
mock_defaults {
|
||||||
|
name: "libexample_defaults",
|
||||||
|
visibility: ["//namespace"],
|
||||||
|
}
|
||||||
|
mock_library {
|
||||||
|
name: "libexample",
|
||||||
|
visibility: ["//visibility:private"],
|
||||||
|
defaults: ["libexample_defaults"],
|
||||||
|
}`),
|
||||||
|
},
|
||||||
|
expectedErrors: []string{
|
||||||
|
`module "libexample": visibility: cannot mix "//visibility:private"` +
|
||||||
|
` with any other visibility rules`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "//visibility:private in defaults overridden",
|
||||||
|
fs: map[string][]byte{
|
||||||
|
"top/Blueprints": []byte(`
|
||||||
|
mock_defaults {
|
||||||
|
name: "libexample_defaults",
|
||||||
|
visibility: ["//visibility:private"],
|
||||||
|
}
|
||||||
|
mock_library {
|
||||||
|
name: "libexample",
|
||||||
|
visibility: ["//namespace"],
|
||||||
|
defaults: ["libexample_defaults"],
|
||||||
|
}`),
|
||||||
|
},
|
||||||
|
expectedErrors: []string{
|
||||||
|
`module "libexample": visibility: cannot mix "//visibility:private"` +
|
||||||
|
` with any other visibility rules`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "//visibility:private mixed with itself",
|
||||||
|
fs: map[string][]byte{
|
||||||
|
"top/Blueprints": []byte(`
|
||||||
|
mock_defaults {
|
||||||
|
name: "libexample_defaults_1",
|
||||||
|
visibility: ["//visibility:private"],
|
||||||
|
}
|
||||||
|
mock_defaults {
|
||||||
|
name: "libexample_defaults_2",
|
||||||
|
visibility: ["//visibility:private"],
|
||||||
|
}
|
||||||
|
mock_library {
|
||||||
|
name: "libexample",
|
||||||
|
visibility: ["//visibility:private"],
|
||||||
|
defaults: ["libexample_defaults_1", "libexample_defaults_2"],
|
||||||
|
}`),
|
||||||
|
"outsider/Blueprints": []byte(`
|
||||||
|
mock_library {
|
||||||
|
name: "liboutsider",
|
||||||
|
deps: ["libexample"],
|
||||||
|
}`),
|
||||||
|
},
|
||||||
|
expectedErrors: []string{
|
||||||
|
`module "liboutsider" variant "android_common": depends on //top:libexample which is not` +
|
||||||
|
` visible to this module`,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVisibility(t *testing.T) {
|
func TestVisibility(t *testing.T) {
|
||||||
@@ -445,7 +701,10 @@ func testVisibility(buildDir string, fs map[string][]byte) (*TestContext, []erro
|
|||||||
|
|
||||||
ctx := NewTestArchContext()
|
ctx := NewTestArchContext()
|
||||||
ctx.RegisterModuleType("mock_library", ModuleFactoryAdaptor(newMockLibraryModule))
|
ctx.RegisterModuleType("mock_library", ModuleFactoryAdaptor(newMockLibraryModule))
|
||||||
ctx.PreDepsMutators(registerVisibilityRuleGatherer)
|
ctx.RegisterModuleType("mock_defaults", ModuleFactoryAdaptor(defaultsFactory))
|
||||||
|
ctx.PreArchMutators(registerVisibilityRuleChecker)
|
||||||
|
ctx.PreArchMutators(RegisterDefaultsPreArchMutators)
|
||||||
|
ctx.PreArchMutators(registerVisibilityRuleGatherer)
|
||||||
ctx.PostDepsMutators(registerVisibilityRuleEnforcer)
|
ctx.PostDepsMutators(registerVisibilityRuleEnforcer)
|
||||||
ctx.Register()
|
ctx.Register()
|
||||||
|
|
||||||
@@ -466,6 +725,7 @@ type mockLibraryProperties struct {
|
|||||||
|
|
||||||
type mockLibraryModule struct {
|
type mockLibraryModule struct {
|
||||||
ModuleBase
|
ModuleBase
|
||||||
|
DefaultableModuleBase
|
||||||
properties mockLibraryProperties
|
properties mockLibraryProperties
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -473,6 +733,7 @@ func newMockLibraryModule() Module {
|
|||||||
m := &mockLibraryModule{}
|
m := &mockLibraryModule{}
|
||||||
m.AddProperties(&m.properties)
|
m.AddProperties(&m.properties)
|
||||||
InitAndroidArchModule(m, HostAndDeviceSupported, MultilibCommon)
|
InitAndroidArchModule(m, HostAndDeviceSupported, MultilibCommon)
|
||||||
|
InitDefaultableModule(m)
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -487,3 +748,17 @@ func (j *mockLibraryModule) DepsMutator(ctx BottomUpMutatorContext) {
|
|||||||
|
|
||||||
func (p *mockLibraryModule) GenerateAndroidBuildActions(ModuleContext) {
|
func (p *mockLibraryModule) GenerateAndroidBuildActions(ModuleContext) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type mockDefaults struct {
|
||||||
|
ModuleBase
|
||||||
|
DefaultsModuleBase
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultsFactory() Module {
|
||||||
|
m := &mockDefaults{}
|
||||||
|
InitDefaultsModule(m)
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*mockDefaults) GenerateAndroidBuildActions(ctx ModuleContext) {
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user