1*bcb5dc79SHONG Yifan/* Copyright 2020 The Bazel Authors. All rights reserved. 2*bcb5dc79SHONG Yifan 3*bcb5dc79SHONG YifanLicensed under the Apache License, Version 2.0 (the "License"); 4*bcb5dc79SHONG Yifanyou may not use this file except in compliance with the License. 5*bcb5dc79SHONG YifanYou may obtain a copy of the License at 6*bcb5dc79SHONG Yifan 7*bcb5dc79SHONG Yifan http://www.apache.org/licenses/LICENSE-2.0 8*bcb5dc79SHONG Yifan 9*bcb5dc79SHONG YifanUnless required by applicable law or agreed to in writing, software 10*bcb5dc79SHONG Yifandistributed under the License is distributed on an "AS IS" BASIS, 11*bcb5dc79SHONG YifanWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*bcb5dc79SHONG YifanSee the License for the specific language governing permissions and 13*bcb5dc79SHONG Yifanlimitations under the License. 14*bcb5dc79SHONG Yifan*/ 15*bcb5dc79SHONG Yifan 16*bcb5dc79SHONG Yifan// Package bzl generates a `bzl_library` target for every `.bzl` file in 17*bcb5dc79SHONG Yifan// each package. 18*bcb5dc79SHONG Yifan// 19*bcb5dc79SHONG Yifan// The `bzl_library` rule is provided by 20*bcb5dc79SHONG Yifan// https://github.com/bazelbuild/bazel-skylib. 21*bcb5dc79SHONG Yifan// 22*bcb5dc79SHONG Yifan// This extension is experimental and subject to change. It is not included 23*bcb5dc79SHONG Yifan// in the default Gazelle binary. 24*bcb5dc79SHONG Yifanpackage bzl 25*bcb5dc79SHONG Yifan 26*bcb5dc79SHONG Yifanimport ( 27*bcb5dc79SHONG Yifan "flag" 28*bcb5dc79SHONG Yifan "fmt" 29*bcb5dc79SHONG Yifan "io/ioutil" 30*bcb5dc79SHONG Yifan "log" 31*bcb5dc79SHONG Yifan "path/filepath" 32*bcb5dc79SHONG Yifan "sort" 33*bcb5dc79SHONG Yifan "strings" 34*bcb5dc79SHONG Yifan 35*bcb5dc79SHONG Yifan "github.com/bazelbuild/bazel-gazelle/config" 36*bcb5dc79SHONG Yifan "github.com/bazelbuild/bazel-gazelle/label" 37*bcb5dc79SHONG Yifan "github.com/bazelbuild/bazel-gazelle/language" 38*bcb5dc79SHONG Yifan "github.com/bazelbuild/bazel-gazelle/pathtools" 39*bcb5dc79SHONG Yifan "github.com/bazelbuild/bazel-gazelle/repo" 40*bcb5dc79SHONG Yifan "github.com/bazelbuild/bazel-gazelle/resolve" 41*bcb5dc79SHONG Yifan "github.com/bazelbuild/bazel-gazelle/rule" 42*bcb5dc79SHONG Yifan 43*bcb5dc79SHONG Yifan "github.com/bazelbuild/buildtools/build" 44*bcb5dc79SHONG Yifan) 45*bcb5dc79SHONG Yifan 46*bcb5dc79SHONG Yifanconst languageName = "starlark" 47*bcb5dc79SHONG Yifanconst fileType = ".bzl" 48*bcb5dc79SHONG Yifan 49*bcb5dc79SHONG Yifanvar ignoreSuffix = suffixes{ 50*bcb5dc79SHONG Yifan "_tests.bzl", 51*bcb5dc79SHONG Yifan "_test.bzl", 52*bcb5dc79SHONG Yifan} 53*bcb5dc79SHONG Yifan 54*bcb5dc79SHONG Yifantype suffixes []string 55*bcb5dc79SHONG Yifan 56*bcb5dc79SHONG Yifanfunc (s suffixes) Matches(test string) bool { 57*bcb5dc79SHONG Yifan for _, v := range s { 58*bcb5dc79SHONG Yifan if strings.HasSuffix(test, v) { 59*bcb5dc79SHONG Yifan return true 60*bcb5dc79SHONG Yifan } 61*bcb5dc79SHONG Yifan } 62*bcb5dc79SHONG Yifan return false 63*bcb5dc79SHONG Yifan} 64*bcb5dc79SHONG Yifan 65*bcb5dc79SHONG Yifantype bzlLibraryLang struct{} 66*bcb5dc79SHONG Yifan 67*bcb5dc79SHONG Yifan// NewLanguage is called by Gazelle to install this language extension in a binary. 68*bcb5dc79SHONG Yifanfunc NewLanguage() language.Language { 69*bcb5dc79SHONG Yifan return &bzlLibraryLang{} 70*bcb5dc79SHONG Yifan} 71*bcb5dc79SHONG Yifan 72*bcb5dc79SHONG Yifan// Name returns the name of the language. This should be a prefix of the 73*bcb5dc79SHONG Yifan// kinds of rules generated by the language, e.g., "go" for the Go extension 74*bcb5dc79SHONG Yifan// since it generates "go_library" rules. 75*bcb5dc79SHONG Yifanfunc (*bzlLibraryLang) Name() string { return languageName } 76*bcb5dc79SHONG Yifan 77*bcb5dc79SHONG Yifan// The following methods are implemented to satisfy the 78*bcb5dc79SHONG Yifan// https://pkg.go.dev/github.com/bazelbuild/bazel-gazelle/resolve?tab=doc#Resolver 79*bcb5dc79SHONG Yifan// interface, but are otherwise unused. 80*bcb5dc79SHONG Yifanfunc (*bzlLibraryLang) RegisterFlags(fs *flag.FlagSet, cmd string, c *config.Config) {} 81*bcb5dc79SHONG Yifanfunc (*bzlLibraryLang) CheckFlags(fs *flag.FlagSet, c *config.Config) error { return nil } 82*bcb5dc79SHONG Yifanfunc (*bzlLibraryLang) KnownDirectives() []string { return nil } 83*bcb5dc79SHONG Yifanfunc (*bzlLibraryLang) Configure(c *config.Config, rel string, f *rule.File) {} 84*bcb5dc79SHONG Yifan 85*bcb5dc79SHONG Yifan// Kinds returns a map of maps rule names (kinds) and information on how to 86*bcb5dc79SHONG Yifan// match and merge attributes that may be found in rules of those kinds. All 87*bcb5dc79SHONG Yifan// kinds of rules generated for this language may be found here. 88*bcb5dc79SHONG Yifanfunc (*bzlLibraryLang) Kinds() map[string]rule.KindInfo { 89*bcb5dc79SHONG Yifan return kinds 90*bcb5dc79SHONG Yifan} 91*bcb5dc79SHONG Yifan 92*bcb5dc79SHONG Yifan// Loads returns .bzl files and symbols they define. Every rule generated by 93*bcb5dc79SHONG Yifan// GenerateRules, now or in the past, should be loadable from one of these 94*bcb5dc79SHONG Yifan// files. 95*bcb5dc79SHONG Yifanfunc (*bzlLibraryLang) Loads() []rule.LoadInfo { 96*bcb5dc79SHONG Yifan return []rule.LoadInfo{{ 97*bcb5dc79SHONG Yifan Name: "@bazel_skylib//:bzl_library.bzl", 98*bcb5dc79SHONG Yifan Symbols: []string{"bzl_library"}, 99*bcb5dc79SHONG Yifan }} 100*bcb5dc79SHONG Yifan} 101*bcb5dc79SHONG Yifan 102*bcb5dc79SHONG Yifan// Fix repairs deprecated usage of language-specific rules in f. This is 103*bcb5dc79SHONG Yifan// called before the file is indexed. Unless c.ShouldFix is true, fixes 104*bcb5dc79SHONG Yifan// that delete or rename rules should not be performed. 105*bcb5dc79SHONG Yifanfunc (*bzlLibraryLang) Fix(c *config.Config, f *rule.File) {} 106*bcb5dc79SHONG Yifan 107*bcb5dc79SHONG Yifan// Imports returns a list of ImportSpecs that can be used to import the rule 108*bcb5dc79SHONG Yifan// r. This is used to populate RuleIndex. 109*bcb5dc79SHONG Yifan// 110*bcb5dc79SHONG Yifan// If nil is returned, the rule will not be indexed. If any non-nil slice is 111*bcb5dc79SHONG Yifan// returned, including an empty slice, the rule will be indexed. 112*bcb5dc79SHONG Yifanfunc (b *bzlLibraryLang) Imports(c *config.Config, r *rule.Rule, f *rule.File) []resolve.ImportSpec { 113*bcb5dc79SHONG Yifan srcs := r.AttrStrings("srcs") 114*bcb5dc79SHONG Yifan imports := make([]resolve.ImportSpec, 0, len(srcs)) 115*bcb5dc79SHONG Yifan 116*bcb5dc79SHONG Yifan for _, src := range srcs { 117*bcb5dc79SHONG Yifan spec := resolve.ImportSpec{ 118*bcb5dc79SHONG Yifan // Lang is the language in which the import string appears (this should 119*bcb5dc79SHONG Yifan // match Resolver.Name). 120*bcb5dc79SHONG Yifan Lang: languageName, 121*bcb5dc79SHONG Yifan // Imp is an import string for the library. 122*bcb5dc79SHONG Yifan Imp: fmt.Sprintf("//%s:%s", f.Pkg, src), 123*bcb5dc79SHONG Yifan } 124*bcb5dc79SHONG Yifan 125*bcb5dc79SHONG Yifan imports = append(imports, spec) 126*bcb5dc79SHONG Yifan } 127*bcb5dc79SHONG Yifan 128*bcb5dc79SHONG Yifan return imports 129*bcb5dc79SHONG Yifan} 130*bcb5dc79SHONG Yifan 131*bcb5dc79SHONG Yifan// Embeds returns a list of labels of rules that the given rule embeds. If 132*bcb5dc79SHONG Yifan// a rule is embedded by another importable rule of the same language, only 133*bcb5dc79SHONG Yifan// the embedding rule will be indexed. The embedding rule will inherit 134*bcb5dc79SHONG Yifan// the imports of the embedded rule. 135*bcb5dc79SHONG Yifan// Since SkyLark doesn't support embedding this should always return nil. 136*bcb5dc79SHONG Yifanfunc (*bzlLibraryLang) Embeds(r *rule.Rule, from label.Label) []label.Label { return nil } 137*bcb5dc79SHONG Yifan 138*bcb5dc79SHONG Yifan// Resolve translates imported libraries for a given rule into Bazel 139*bcb5dc79SHONG Yifan// dependencies. Information about imported libraries is returned for each 140*bcb5dc79SHONG Yifan// rule generated by language.GenerateRules in 141*bcb5dc79SHONG Yifan// language.GenerateResult.Imports. Resolve generates a "deps" attribute (or 142*bcb5dc79SHONG Yifan// the appropriate language-specific equivalent) for each import according to 143*bcb5dc79SHONG Yifan// language-specific rules and heuristics. 144*bcb5dc79SHONG Yifanfunc (*bzlLibraryLang) Resolve(c *config.Config, ix *resolve.RuleIndex, rc *repo.RemoteCache, r *rule.Rule, importsRaw interface{}, from label.Label) { 145*bcb5dc79SHONG Yifan imports := importsRaw.([]string) 146*bcb5dc79SHONG Yifan 147*bcb5dc79SHONG Yifan r.DelAttr("deps") 148*bcb5dc79SHONG Yifan 149*bcb5dc79SHONG Yifan if len(imports) == 0 { 150*bcb5dc79SHONG Yifan return 151*bcb5dc79SHONG Yifan } 152*bcb5dc79SHONG Yifan 153*bcb5dc79SHONG Yifan deps := make([]string, 0, len(imports)) 154*bcb5dc79SHONG Yifan for _, imp := range imports { 155*bcb5dc79SHONG Yifan impLabel, err := label.Parse(imp) 156*bcb5dc79SHONG Yifan if err != nil { 157*bcb5dc79SHONG Yifan log.Printf("%s: import of %q is invalid: %v", from.String(), imp, err) 158*bcb5dc79SHONG Yifan continue 159*bcb5dc79SHONG Yifan } 160*bcb5dc79SHONG Yifan 161*bcb5dc79SHONG Yifan // the index only contains absolute labels, not relative 162*bcb5dc79SHONG Yifan impLabel = impLabel.Abs(from.Repo, from.Pkg) 163*bcb5dc79SHONG Yifan 164*bcb5dc79SHONG Yifan if impLabel.Repo == "bazel_tools" { 165*bcb5dc79SHONG Yifan // The @bazel_tools repo is tricky because it is a part of the "shipped 166*bcb5dc79SHONG Yifan // with bazel" core library for interacting with the outside world. 167*bcb5dc79SHONG Yifan // This means that it can not depend on skylib. Fortunately there is a 168*bcb5dc79SHONG Yifan // fairly simple workaround for this, which is that you can add those 169*bcb5dc79SHONG Yifan // bzl files as `deps` entries. 170*bcb5dc79SHONG Yifan deps = append(deps, imp) 171*bcb5dc79SHONG Yifan continue 172*bcb5dc79SHONG Yifan } 173*bcb5dc79SHONG Yifan 174*bcb5dc79SHONG Yifan if impLabel.Repo != "" || !c.IndexLibraries { 175*bcb5dc79SHONG Yifan // This is a dependency that is external to the current repo, or indexing 176*bcb5dc79SHONG Yifan // is disabled so take a guess at what the target name should be. 177*bcb5dc79SHONG Yifan deps = append(deps, strings.TrimSuffix(imp, fileType)) 178*bcb5dc79SHONG Yifan continue 179*bcb5dc79SHONG Yifan } 180*bcb5dc79SHONG Yifan 181*bcb5dc79SHONG Yifan res := resolve.ImportSpec{ 182*bcb5dc79SHONG Yifan Lang: languageName, 183*bcb5dc79SHONG Yifan Imp: impLabel.String(), 184*bcb5dc79SHONG Yifan } 185*bcb5dc79SHONG Yifan matches := ix.FindRulesByImport(res, languageName) 186*bcb5dc79SHONG Yifan 187*bcb5dc79SHONG Yifan if len(matches) == 0 { 188*bcb5dc79SHONG Yifan log.Printf("%s: %q (%s) was not found in dependency index. Skipping. This may result in an incomplete deps section and require manual BUILD file intervention.\n", from.String(), imp, impLabel.String()) 189*bcb5dc79SHONG Yifan } 190*bcb5dc79SHONG Yifan 191*bcb5dc79SHONG Yifan for _, m := range matches { 192*bcb5dc79SHONG Yifan depLabel := m.Label 193*bcb5dc79SHONG Yifan depLabel = depLabel.Rel(from.Repo, from.Pkg) 194*bcb5dc79SHONG Yifan deps = append(deps, depLabel.String()) 195*bcb5dc79SHONG Yifan } 196*bcb5dc79SHONG Yifan } 197*bcb5dc79SHONG Yifan 198*bcb5dc79SHONG Yifan sort.Strings(deps) 199*bcb5dc79SHONG Yifan if len(deps) > 0 { 200*bcb5dc79SHONG Yifan r.SetAttr("deps", deps) 201*bcb5dc79SHONG Yifan } 202*bcb5dc79SHONG Yifan} 203*bcb5dc79SHONG Yifan 204*bcb5dc79SHONG Yifanvar kinds = map[string]rule.KindInfo{ 205*bcb5dc79SHONG Yifan "bzl_library": { 206*bcb5dc79SHONG Yifan NonEmptyAttrs: map[string]bool{"srcs": true, "deps": true}, 207*bcb5dc79SHONG Yifan MergeableAttrs: map[string]bool{"srcs": true}, 208*bcb5dc79SHONG Yifan }, 209*bcb5dc79SHONG Yifan} 210*bcb5dc79SHONG Yifan 211*bcb5dc79SHONG Yifan// GenerateRules extracts build metadata from source files in a directory. 212*bcb5dc79SHONG Yifan// GenerateRules is called in each directory where an update is requested 213*bcb5dc79SHONG Yifan// in depth-first post-order. 214*bcb5dc79SHONG Yifan// 215*bcb5dc79SHONG Yifan// args contains the arguments for GenerateRules. This is passed as a 216*bcb5dc79SHONG Yifan// struct to avoid breaking implementations in the future when new 217*bcb5dc79SHONG Yifan// fields are added. 218*bcb5dc79SHONG Yifan// 219*bcb5dc79SHONG Yifan// A GenerateResult struct is returned. Optional fields may be added to this 220*bcb5dc79SHONG Yifan// type in the future. 221*bcb5dc79SHONG Yifan// 222*bcb5dc79SHONG Yifan// Any non-fatal errors this function encounters should be logged using 223*bcb5dc79SHONG Yifan// log.Print. 224*bcb5dc79SHONG Yifanfunc (*bzlLibraryLang) GenerateRules(args language.GenerateArgs) language.GenerateResult { 225*bcb5dc79SHONG Yifan var rules []*rule.Rule 226*bcb5dc79SHONG Yifan var imports []interface{} 227*bcb5dc79SHONG Yifan for _, f := range append(args.RegularFiles, args.GenFiles...) { 228*bcb5dc79SHONG Yifan if !isBzlSourceFile(f) { 229*bcb5dc79SHONG Yifan continue 230*bcb5dc79SHONG Yifan } 231*bcb5dc79SHONG Yifan name := strings.TrimSuffix(f, fileType) 232*bcb5dc79SHONG Yifan r := rule.NewRule("bzl_library", name) 233*bcb5dc79SHONG Yifan 234*bcb5dc79SHONG Yifan r.SetAttr("srcs", []string{f}) 235*bcb5dc79SHONG Yifan 236*bcb5dc79SHONG Yifan shouldSetVisibility := args.File == nil || !args.File.HasDefaultVisibility() 237*bcb5dc79SHONG Yifan if shouldSetVisibility { 238*bcb5dc79SHONG Yifan vis := checkInternalVisibility(args.Rel, "//visibility:public") 239*bcb5dc79SHONG Yifan r.SetAttr("visibility", []string{vis}) 240*bcb5dc79SHONG Yifan } 241*bcb5dc79SHONG Yifan 242*bcb5dc79SHONG Yifan fullPath := filepath.Join(args.Dir, f) 243*bcb5dc79SHONG Yifan loads, err := getBzlFileLoads(fullPath) 244*bcb5dc79SHONG Yifan if err != nil { 245*bcb5dc79SHONG Yifan log.Printf("%s: contains syntax errors: %v", fullPath, err) 246*bcb5dc79SHONG Yifan // Don't `continue` since it is reasonable to create a target even 247*bcb5dc79SHONG Yifan // without deps. 248*bcb5dc79SHONG Yifan } 249*bcb5dc79SHONG Yifan 250*bcb5dc79SHONG Yifan rules = append(rules, r) 251*bcb5dc79SHONG Yifan imports = append(imports, loads) 252*bcb5dc79SHONG Yifan } 253*bcb5dc79SHONG Yifan 254*bcb5dc79SHONG Yifan return language.GenerateResult{ 255*bcb5dc79SHONG Yifan Gen: rules, 256*bcb5dc79SHONG Yifan Imports: imports, 257*bcb5dc79SHONG Yifan Empty: generateEmpty(args), 258*bcb5dc79SHONG Yifan } 259*bcb5dc79SHONG Yifan} 260*bcb5dc79SHONG Yifan 261*bcb5dc79SHONG Yifanfunc getBzlFileLoads(path string) ([]string, error) { 262*bcb5dc79SHONG Yifan f, err := ioutil.ReadFile(path) 263*bcb5dc79SHONG Yifan if err != nil { 264*bcb5dc79SHONG Yifan return nil, fmt.Errorf("ioutil.ReadFile(%q) error: %v", path, err) 265*bcb5dc79SHONG Yifan } 266*bcb5dc79SHONG Yifan ast, err := build.ParseBuild(path, f) 267*bcb5dc79SHONG Yifan if err != nil { 268*bcb5dc79SHONG Yifan return nil, fmt.Errorf("build.Parse(%q) error: %v", f, err) 269*bcb5dc79SHONG Yifan } 270*bcb5dc79SHONG Yifan 271*bcb5dc79SHONG Yifan var loads []string 272*bcb5dc79SHONG Yifan build.WalkOnce(ast, func(expr *build.Expr) { 273*bcb5dc79SHONG Yifan n := *expr 274*bcb5dc79SHONG Yifan if l, ok := n.(*build.LoadStmt); ok { 275*bcb5dc79SHONG Yifan loads = append(loads, l.Module.Value) 276*bcb5dc79SHONG Yifan } 277*bcb5dc79SHONG Yifan }) 278*bcb5dc79SHONG Yifan sort.Strings(loads) 279*bcb5dc79SHONG Yifan 280*bcb5dc79SHONG Yifan return loads, nil 281*bcb5dc79SHONG Yifan} 282*bcb5dc79SHONG Yifan 283*bcb5dc79SHONG Yifanfunc isBzlSourceFile(f string) bool { 284*bcb5dc79SHONG Yifan return strings.HasSuffix(f, fileType) && !ignoreSuffix.Matches(f) 285*bcb5dc79SHONG Yifan} 286*bcb5dc79SHONG Yifan 287*bcb5dc79SHONG Yifan// generateEmpty generates the list of rules that don't need to exist in the 288*bcb5dc79SHONG Yifan// BUILD file any more. 289*bcb5dc79SHONG Yifan// For each bzl_library rule in args.File that only has srcs that aren't in 290*bcb5dc79SHONG Yifan// args.RegularFiles or args.GenFiles, add a bzl_library with no srcs or deps. 291*bcb5dc79SHONG Yifan// That will let Gazelle delete bzl_library rules after the corresponding .bzl 292*bcb5dc79SHONG Yifan// files are deleted. 293*bcb5dc79SHONG Yifanfunc generateEmpty(args language.GenerateArgs) []*rule.Rule { 294*bcb5dc79SHONG Yifan var ret []*rule.Rule 295*bcb5dc79SHONG Yifan if args.File == nil { 296*bcb5dc79SHONG Yifan return ret 297*bcb5dc79SHONG Yifan } 298*bcb5dc79SHONG Yifan for _, r := range args.File.Rules { 299*bcb5dc79SHONG Yifan if r.Kind() != "bzl_library" { 300*bcb5dc79SHONG Yifan continue 301*bcb5dc79SHONG Yifan } 302*bcb5dc79SHONG Yifan name := r.AttrString("name") 303*bcb5dc79SHONG Yifan 304*bcb5dc79SHONG Yifan exists := make(map[string]bool) 305*bcb5dc79SHONG Yifan for _, f := range args.RegularFiles { 306*bcb5dc79SHONG Yifan exists[f] = true 307*bcb5dc79SHONG Yifan } 308*bcb5dc79SHONG Yifan for _, f := range args.GenFiles { 309*bcb5dc79SHONG Yifan exists[f] = true 310*bcb5dc79SHONG Yifan } 311*bcb5dc79SHONG Yifan for _, r := range args.File.Rules { 312*bcb5dc79SHONG Yifan srcsExist := false 313*bcb5dc79SHONG Yifan for _, f := range r.AttrStrings("srcs") { 314*bcb5dc79SHONG Yifan if exists[f] { 315*bcb5dc79SHONG Yifan srcsExist = true 316*bcb5dc79SHONG Yifan break 317*bcb5dc79SHONG Yifan } 318*bcb5dc79SHONG Yifan } 319*bcb5dc79SHONG Yifan if !srcsExist { 320*bcb5dc79SHONG Yifan ret = append(ret, rule.NewRule("bzl_library", name)) 321*bcb5dc79SHONG Yifan } 322*bcb5dc79SHONG Yifan } 323*bcb5dc79SHONG Yifan } 324*bcb5dc79SHONG Yifan return ret 325*bcb5dc79SHONG Yifan} 326*bcb5dc79SHONG Yifan 327*bcb5dc79SHONG Yifantype srcsList []string 328*bcb5dc79SHONG Yifan 329*bcb5dc79SHONG Yifanfunc (s srcsList) Contains(m string) bool { 330*bcb5dc79SHONG Yifan for _, e := range s { 331*bcb5dc79SHONG Yifan if e == m { 332*bcb5dc79SHONG Yifan return true 333*bcb5dc79SHONG Yifan } 334*bcb5dc79SHONG Yifan } 335*bcb5dc79SHONG Yifan return false 336*bcb5dc79SHONG Yifan} 337*bcb5dc79SHONG Yifan 338*bcb5dc79SHONG Yifan// checkInternalVisibility overrides the given visibility if the package is 339*bcb5dc79SHONG Yifan// internal. 340*bcb5dc79SHONG Yifanfunc checkInternalVisibility(rel, visibility string) string { 341*bcb5dc79SHONG Yifan if i := pathtools.Index(rel, "internal"); i > 0 { 342*bcb5dc79SHONG Yifan visibility = fmt.Sprintf("//%s:__subpackages__", rel[:i-1]) 343*bcb5dc79SHONG Yifan } else if i := pathtools.Index(rel, "private"); i > 0 { 344*bcb5dc79SHONG Yifan visibility = fmt.Sprintf("//%s:__subpackages__", rel[:i-1]) 345*bcb5dc79SHONG Yifan } else if pathtools.HasPrefix(rel, "internal") || pathtools.HasPrefix(rel, "private") { 346*bcb5dc79SHONG Yifan visibility = "//:__subpackages__" 347*bcb5dc79SHONG Yifan } 348*bcb5dc79SHONG Yifan return visibility 349*bcb5dc79SHONG Yifan} 350