1*60517a1eSAndroid Build Coastguard Worker// Copyright 2023 The Bazel Authors. All rights reserved. 2*60517a1eSAndroid Build Coastguard Worker// 3*60517a1eSAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*60517a1eSAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*60517a1eSAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*60517a1eSAndroid Build Coastguard Worker// 7*60517a1eSAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*60517a1eSAndroid Build Coastguard Worker// 9*60517a1eSAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*60517a1eSAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*60517a1eSAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*60517a1eSAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*60517a1eSAndroid Build Coastguard Worker// limitations under the License. 14*60517a1eSAndroid Build Coastguard Worker 15*60517a1eSAndroid Build Coastguard Workerpackage pythonconfig 16*60517a1eSAndroid Build Coastguard Worker 17*60517a1eSAndroid Build Coastguard Workerimport ( 18*60517a1eSAndroid Build Coastguard Worker "fmt" 19*60517a1eSAndroid Build Coastguard Worker "path" 20*60517a1eSAndroid Build Coastguard Worker "regexp" 21*60517a1eSAndroid Build Coastguard Worker "strings" 22*60517a1eSAndroid Build Coastguard Worker 23*60517a1eSAndroid Build Coastguard Worker "github.com/emirpasic/gods/lists/singlylinkedlist" 24*60517a1eSAndroid Build Coastguard Worker 25*60517a1eSAndroid Build Coastguard Worker "github.com/bazelbuild/bazel-gazelle/label" 26*60517a1eSAndroid Build Coastguard Worker "github.com/bazelbuild/rules_python/gazelle/manifest" 27*60517a1eSAndroid Build Coastguard Worker) 28*60517a1eSAndroid Build Coastguard Worker 29*60517a1eSAndroid Build Coastguard Worker// Directives 30*60517a1eSAndroid Build Coastguard Workerconst ( 31*60517a1eSAndroid Build Coastguard Worker // PythonExtensionDirective represents the directive that controls whether 32*60517a1eSAndroid Build Coastguard Worker // this Python extension is enabled or not. Sub-packages inherit this value. 33*60517a1eSAndroid Build Coastguard Worker // Can be either "enabled" or "disabled". Defaults to "enabled". 34*60517a1eSAndroid Build Coastguard Worker PythonExtensionDirective = "python_extension" 35*60517a1eSAndroid Build Coastguard Worker // PythonRootDirective represents the directive that sets a Bazel package as 36*60517a1eSAndroid Build Coastguard Worker // a Python root. This is used on monorepos with multiple Python projects 37*60517a1eSAndroid Build Coastguard Worker // that don't share the top-level of the workspace as the root. 38*60517a1eSAndroid Build Coastguard Worker PythonRootDirective = "python_root" 39*60517a1eSAndroid Build Coastguard Worker // PythonManifestFileNameDirective represents the directive that overrides 40*60517a1eSAndroid Build Coastguard Worker // the default gazelle_python.yaml manifest file name. 41*60517a1eSAndroid Build Coastguard Worker PythonManifestFileNameDirective = "python_manifest_file_name" 42*60517a1eSAndroid Build Coastguard Worker // IgnoreFilesDirective represents the directive that controls the ignored 43*60517a1eSAndroid Build Coastguard Worker // files from the generated targets. 44*60517a1eSAndroid Build Coastguard Worker IgnoreFilesDirective = "python_ignore_files" 45*60517a1eSAndroid Build Coastguard Worker // IgnoreDependenciesDirective represents the directive that controls the 46*60517a1eSAndroid Build Coastguard Worker // ignored dependencies from the generated targets. 47*60517a1eSAndroid Build Coastguard Worker IgnoreDependenciesDirective = "python_ignore_dependencies" 48*60517a1eSAndroid Build Coastguard Worker // ValidateImportStatementsDirective represents the directive that controls 49*60517a1eSAndroid Build Coastguard Worker // whether the Python import statements should be validated. 50*60517a1eSAndroid Build Coastguard Worker ValidateImportStatementsDirective = "python_validate_import_statements" 51*60517a1eSAndroid Build Coastguard Worker // GenerationMode represents the directive that controls the target generation 52*60517a1eSAndroid Build Coastguard Worker // mode. See below for the GenerationModeType constants. 53*60517a1eSAndroid Build Coastguard Worker GenerationMode = "python_generation_mode" 54*60517a1eSAndroid Build Coastguard Worker // GenerationModePerFileIncludeInit represents the directive that augments 55*60517a1eSAndroid Build Coastguard Worker // the "per_file" GenerationMode by including the package's __init__.py file. 56*60517a1eSAndroid Build Coastguard Worker // This is a boolean directive. 57*60517a1eSAndroid Build Coastguard Worker GenerationModePerFileIncludeInit = "python_generation_mode_per_file_include_init" 58*60517a1eSAndroid Build Coastguard Worker // GenerationModePerPackageRequireTestEntryPoint represents the directive that 59*60517a1eSAndroid Build Coastguard Worker // requires a test entry point to generate test targets in "package" GenerationMode. 60*60517a1eSAndroid Build Coastguard Worker // This is a boolean directive. 61*60517a1eSAndroid Build Coastguard Worker GenerationModePerPackageRequireTestEntryPoint = "python_generation_mode_per_package_require_test_entry_point" 62*60517a1eSAndroid Build Coastguard Worker // LibraryNamingConvention represents the directive that controls the 63*60517a1eSAndroid Build Coastguard Worker // py_library naming convention. It interpolates $package_name$ with the 64*60517a1eSAndroid Build Coastguard Worker // Bazel package name. E.g. if the Bazel package name is `foo`, setting this 65*60517a1eSAndroid Build Coastguard Worker // to `$package_name$_my_lib` would render to `foo_my_lib`. 66*60517a1eSAndroid Build Coastguard Worker LibraryNamingConvention = "python_library_naming_convention" 67*60517a1eSAndroid Build Coastguard Worker // BinaryNamingConvention represents the directive that controls the 68*60517a1eSAndroid Build Coastguard Worker // py_binary naming convention. See python_library_naming_convention for 69*60517a1eSAndroid Build Coastguard Worker // more info on the package name interpolation. 70*60517a1eSAndroid Build Coastguard Worker BinaryNamingConvention = "python_binary_naming_convention" 71*60517a1eSAndroid Build Coastguard Worker // TestNamingConvention represents the directive that controls the py_test 72*60517a1eSAndroid Build Coastguard Worker // naming convention. See python_library_naming_convention for more info on 73*60517a1eSAndroid Build Coastguard Worker // the package name interpolation. 74*60517a1eSAndroid Build Coastguard Worker TestNamingConvention = "python_test_naming_convention" 75*60517a1eSAndroid Build Coastguard Worker // DefaultVisibilty represents the directive that controls what visibility 76*60517a1eSAndroid Build Coastguard Worker // labels are added to generated python targets. 77*60517a1eSAndroid Build Coastguard Worker DefaultVisibilty = "python_default_visibility" 78*60517a1eSAndroid Build Coastguard Worker // Visibility represents the directive that controls what additional 79*60517a1eSAndroid Build Coastguard Worker // visibility labels are added to generated targets. It mimics the behavior 80*60517a1eSAndroid Build Coastguard Worker // of the `go_visibility` directive. 81*60517a1eSAndroid Build Coastguard Worker Visibility = "python_visibility" 82*60517a1eSAndroid Build Coastguard Worker // TestFilePattern represents the directive that controls which python 83*60517a1eSAndroid Build Coastguard Worker // files are mapped to `py_test` targets. 84*60517a1eSAndroid Build Coastguard Worker TestFilePattern = "python_test_file_pattern" 85*60517a1eSAndroid Build Coastguard Worker // LabelConvention represents the directive that defines the format of the 86*60517a1eSAndroid Build Coastguard Worker // labels to third-party dependencies. 87*60517a1eSAndroid Build Coastguard Worker LabelConvention = "python_label_convention" 88*60517a1eSAndroid Build Coastguard Worker // LabelNormalization represents the directive that controls how distribution 89*60517a1eSAndroid Build Coastguard Worker // names of labels to third-party dependencies are normalized. Supported values 90*60517a1eSAndroid Build Coastguard Worker // are 'none', 'pep503' and 'snake_case' (default). See LabelNormalizationType. 91*60517a1eSAndroid Build Coastguard Worker LabelNormalization = "python_label_normalization" 92*60517a1eSAndroid Build Coastguard Worker) 93*60517a1eSAndroid Build Coastguard Worker 94*60517a1eSAndroid Build Coastguard Worker// GenerationModeType represents one of the generation modes for the Python 95*60517a1eSAndroid Build Coastguard Worker// extension. 96*60517a1eSAndroid Build Coastguard Workertype GenerationModeType string 97*60517a1eSAndroid Build Coastguard Worker 98*60517a1eSAndroid Build Coastguard Worker// Generation modes 99*60517a1eSAndroid Build Coastguard Workerconst ( 100*60517a1eSAndroid Build Coastguard Worker // GenerationModePackage defines the mode in which targets will be generated 101*60517a1eSAndroid Build Coastguard Worker // for each __init__.py, or when an existing BUILD or BUILD.bazel file already 102*60517a1eSAndroid Build Coastguard Worker // determines a Bazel package. 103*60517a1eSAndroid Build Coastguard Worker GenerationModePackage GenerationModeType = "package" 104*60517a1eSAndroid Build Coastguard Worker // GenerationModeProject defines the mode in which a coarse-grained target will 105*60517a1eSAndroid Build Coastguard Worker // be generated englobing sub-directories containing Python files. 106*60517a1eSAndroid Build Coastguard Worker GenerationModeProject GenerationModeType = "project" 107*60517a1eSAndroid Build Coastguard Worker GenerationModeFile GenerationModeType = "file" 108*60517a1eSAndroid Build Coastguard Worker) 109*60517a1eSAndroid Build Coastguard Worker 110*60517a1eSAndroid Build Coastguard Workerconst ( 111*60517a1eSAndroid Build Coastguard Worker packageNameNamingConventionSubstitution = "$package_name$" 112*60517a1eSAndroid Build Coastguard Worker distributionNameLabelConventionSubstitution = "$distribution_name$" 113*60517a1eSAndroid Build Coastguard Worker) 114*60517a1eSAndroid Build Coastguard Worker 115*60517a1eSAndroid Build Coastguard Workerconst ( 116*60517a1eSAndroid Build Coastguard Worker // The default visibility label, including a format placeholder for `python_root`. 117*60517a1eSAndroid Build Coastguard Worker DefaultVisibilityFmtString = "//%s:__subpackages__" 118*60517a1eSAndroid Build Coastguard Worker // The default globs used to determine pt_test targets. 119*60517a1eSAndroid Build Coastguard Worker DefaultTestFilePatternString = "*_test.py,test_*.py" 120*60517a1eSAndroid Build Coastguard Worker // The default convention of label of third-party dependencies. 121*60517a1eSAndroid Build Coastguard Worker DefaultLabelConvention = "$distribution_name$" 122*60517a1eSAndroid Build Coastguard Worker // The default normalization applied to distribution names of third-party dependency labels. 123*60517a1eSAndroid Build Coastguard Worker DefaultLabelNormalizationType = SnakeCaseLabelNormalizationType 124*60517a1eSAndroid Build Coastguard Worker) 125*60517a1eSAndroid Build Coastguard Worker 126*60517a1eSAndroid Build Coastguard Worker// defaultIgnoreFiles is the list of default values used in the 127*60517a1eSAndroid Build Coastguard Worker// python_ignore_files option. 128*60517a1eSAndroid Build Coastguard Workervar defaultIgnoreFiles = map[string]struct{}{ 129*60517a1eSAndroid Build Coastguard Worker "setup.py": {}, 130*60517a1eSAndroid Build Coastguard Worker} 131*60517a1eSAndroid Build Coastguard Worker 132*60517a1eSAndroid Build Coastguard Worker// Configs is an extension of map[string]*Config. It provides finding methods 133*60517a1eSAndroid Build Coastguard Worker// on top of the mapping. 134*60517a1eSAndroid Build Coastguard Workertype Configs map[string]*Config 135*60517a1eSAndroid Build Coastguard Worker 136*60517a1eSAndroid Build Coastguard Worker// ParentForPackage returns the parent Config for the given Bazel package. 137*60517a1eSAndroid Build Coastguard Workerfunc (c *Configs) ParentForPackage(pkg string) *Config { 138*60517a1eSAndroid Build Coastguard Worker dir := path.Dir(pkg) 139*60517a1eSAndroid Build Coastguard Worker if dir == "." { 140*60517a1eSAndroid Build Coastguard Worker dir = "" 141*60517a1eSAndroid Build Coastguard Worker } 142*60517a1eSAndroid Build Coastguard Worker parent := (map[string]*Config)(*c)[dir] 143*60517a1eSAndroid Build Coastguard Worker return parent 144*60517a1eSAndroid Build Coastguard Worker} 145*60517a1eSAndroid Build Coastguard Worker 146*60517a1eSAndroid Build Coastguard Worker// Config represents a config extension for a specific Bazel package. 147*60517a1eSAndroid Build Coastguard Workertype Config struct { 148*60517a1eSAndroid Build Coastguard Worker parent *Config 149*60517a1eSAndroid Build Coastguard Worker 150*60517a1eSAndroid Build Coastguard Worker extensionEnabled bool 151*60517a1eSAndroid Build Coastguard Worker repoRoot string 152*60517a1eSAndroid Build Coastguard Worker pythonProjectRoot string 153*60517a1eSAndroid Build Coastguard Worker gazelleManifest *manifest.Manifest 154*60517a1eSAndroid Build Coastguard Worker 155*60517a1eSAndroid Build Coastguard Worker excludedPatterns *singlylinkedlist.List 156*60517a1eSAndroid Build Coastguard Worker ignoreFiles map[string]struct{} 157*60517a1eSAndroid Build Coastguard Worker ignoreDependencies map[string]struct{} 158*60517a1eSAndroid Build Coastguard Worker validateImportStatements bool 159*60517a1eSAndroid Build Coastguard Worker coarseGrainedGeneration bool 160*60517a1eSAndroid Build Coastguard Worker perFileGeneration bool 161*60517a1eSAndroid Build Coastguard Worker perFileGenerationIncludeInit bool 162*60517a1eSAndroid Build Coastguard Worker perPackageGenerationRequireTestEntryPoint bool 163*60517a1eSAndroid Build Coastguard Worker libraryNamingConvention string 164*60517a1eSAndroid Build Coastguard Worker binaryNamingConvention string 165*60517a1eSAndroid Build Coastguard Worker testNamingConvention string 166*60517a1eSAndroid Build Coastguard Worker defaultVisibility []string 167*60517a1eSAndroid Build Coastguard Worker visibility []string 168*60517a1eSAndroid Build Coastguard Worker testFilePattern []string 169*60517a1eSAndroid Build Coastguard Worker labelConvention string 170*60517a1eSAndroid Build Coastguard Worker labelNormalization LabelNormalizationType 171*60517a1eSAndroid Build Coastguard Worker} 172*60517a1eSAndroid Build Coastguard Worker 173*60517a1eSAndroid Build Coastguard Workertype LabelNormalizationType int 174*60517a1eSAndroid Build Coastguard Worker 175*60517a1eSAndroid Build Coastguard Workerconst ( 176*60517a1eSAndroid Build Coastguard Worker NoLabelNormalizationType LabelNormalizationType = iota 177*60517a1eSAndroid Build Coastguard Worker Pep503LabelNormalizationType 178*60517a1eSAndroid Build Coastguard Worker SnakeCaseLabelNormalizationType 179*60517a1eSAndroid Build Coastguard Worker) 180*60517a1eSAndroid Build Coastguard Worker 181*60517a1eSAndroid Build Coastguard Worker// New creates a new Config. 182*60517a1eSAndroid Build Coastguard Workerfunc New( 183*60517a1eSAndroid Build Coastguard Worker repoRoot string, 184*60517a1eSAndroid Build Coastguard Worker pythonProjectRoot string, 185*60517a1eSAndroid Build Coastguard Worker) *Config { 186*60517a1eSAndroid Build Coastguard Worker return &Config{ 187*60517a1eSAndroid Build Coastguard Worker extensionEnabled: true, 188*60517a1eSAndroid Build Coastguard Worker repoRoot: repoRoot, 189*60517a1eSAndroid Build Coastguard Worker pythonProjectRoot: pythonProjectRoot, 190*60517a1eSAndroid Build Coastguard Worker excludedPatterns: singlylinkedlist.New(), 191*60517a1eSAndroid Build Coastguard Worker ignoreFiles: make(map[string]struct{}), 192*60517a1eSAndroid Build Coastguard Worker ignoreDependencies: make(map[string]struct{}), 193*60517a1eSAndroid Build Coastguard Worker validateImportStatements: true, 194*60517a1eSAndroid Build Coastguard Worker coarseGrainedGeneration: false, 195*60517a1eSAndroid Build Coastguard Worker perFileGeneration: false, 196*60517a1eSAndroid Build Coastguard Worker perFileGenerationIncludeInit: false, 197*60517a1eSAndroid Build Coastguard Worker perPackageGenerationRequireTestEntryPoint: true, 198*60517a1eSAndroid Build Coastguard Worker libraryNamingConvention: packageNameNamingConventionSubstitution, 199*60517a1eSAndroid Build Coastguard Worker binaryNamingConvention: fmt.Sprintf("%s_bin", packageNameNamingConventionSubstitution), 200*60517a1eSAndroid Build Coastguard Worker testNamingConvention: fmt.Sprintf("%s_test", packageNameNamingConventionSubstitution), 201*60517a1eSAndroid Build Coastguard Worker defaultVisibility: []string{fmt.Sprintf(DefaultVisibilityFmtString, "")}, 202*60517a1eSAndroid Build Coastguard Worker visibility: []string{}, 203*60517a1eSAndroid Build Coastguard Worker testFilePattern: strings.Split(DefaultTestFilePatternString, ","), 204*60517a1eSAndroid Build Coastguard Worker labelConvention: DefaultLabelConvention, 205*60517a1eSAndroid Build Coastguard Worker labelNormalization: DefaultLabelNormalizationType, 206*60517a1eSAndroid Build Coastguard Worker } 207*60517a1eSAndroid Build Coastguard Worker} 208*60517a1eSAndroid Build Coastguard Worker 209*60517a1eSAndroid Build Coastguard Worker// Parent returns the parent config. 210*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) Parent() *Config { 211*60517a1eSAndroid Build Coastguard Worker return c.parent 212*60517a1eSAndroid Build Coastguard Worker} 213*60517a1eSAndroid Build Coastguard Worker 214*60517a1eSAndroid Build Coastguard Worker// NewChild creates a new child Config. It inherits desired values from the 215*60517a1eSAndroid Build Coastguard Worker// current Config and sets itself as the parent to the child. 216*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) NewChild() *Config { 217*60517a1eSAndroid Build Coastguard Worker return &Config{ 218*60517a1eSAndroid Build Coastguard Worker parent: c, 219*60517a1eSAndroid Build Coastguard Worker extensionEnabled: c.extensionEnabled, 220*60517a1eSAndroid Build Coastguard Worker repoRoot: c.repoRoot, 221*60517a1eSAndroid Build Coastguard Worker pythonProjectRoot: c.pythonProjectRoot, 222*60517a1eSAndroid Build Coastguard Worker excludedPatterns: c.excludedPatterns, 223*60517a1eSAndroid Build Coastguard Worker ignoreFiles: make(map[string]struct{}), 224*60517a1eSAndroid Build Coastguard Worker ignoreDependencies: make(map[string]struct{}), 225*60517a1eSAndroid Build Coastguard Worker validateImportStatements: c.validateImportStatements, 226*60517a1eSAndroid Build Coastguard Worker coarseGrainedGeneration: c.coarseGrainedGeneration, 227*60517a1eSAndroid Build Coastguard Worker perFileGeneration: c.perFileGeneration, 228*60517a1eSAndroid Build Coastguard Worker perFileGenerationIncludeInit: c.perFileGenerationIncludeInit, 229*60517a1eSAndroid Build Coastguard Worker perPackageGenerationRequireTestEntryPoint: c.perPackageGenerationRequireTestEntryPoint, 230*60517a1eSAndroid Build Coastguard Worker libraryNamingConvention: c.libraryNamingConvention, 231*60517a1eSAndroid Build Coastguard Worker binaryNamingConvention: c.binaryNamingConvention, 232*60517a1eSAndroid Build Coastguard Worker testNamingConvention: c.testNamingConvention, 233*60517a1eSAndroid Build Coastguard Worker defaultVisibility: c.defaultVisibility, 234*60517a1eSAndroid Build Coastguard Worker visibility: c.visibility, 235*60517a1eSAndroid Build Coastguard Worker testFilePattern: c.testFilePattern, 236*60517a1eSAndroid Build Coastguard Worker labelConvention: c.labelConvention, 237*60517a1eSAndroid Build Coastguard Worker labelNormalization: c.labelNormalization, 238*60517a1eSAndroid Build Coastguard Worker } 239*60517a1eSAndroid Build Coastguard Worker} 240*60517a1eSAndroid Build Coastguard Worker 241*60517a1eSAndroid Build Coastguard Worker// AddExcludedPattern adds a glob pattern parsed from the standard 242*60517a1eSAndroid Build Coastguard Worker// gazelle:exclude directive. 243*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) AddExcludedPattern(pattern string) { 244*60517a1eSAndroid Build Coastguard Worker c.excludedPatterns.Add(pattern) 245*60517a1eSAndroid Build Coastguard Worker} 246*60517a1eSAndroid Build Coastguard Worker 247*60517a1eSAndroid Build Coastguard Worker// ExcludedPatterns returns the excluded patterns list. 248*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) ExcludedPatterns() *singlylinkedlist.List { 249*60517a1eSAndroid Build Coastguard Worker return c.excludedPatterns 250*60517a1eSAndroid Build Coastguard Worker} 251*60517a1eSAndroid Build Coastguard Worker 252*60517a1eSAndroid Build Coastguard Worker// SetExtensionEnabled sets whether the extension is enabled or not. 253*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) SetExtensionEnabled(enabled bool) { 254*60517a1eSAndroid Build Coastguard Worker c.extensionEnabled = enabled 255*60517a1eSAndroid Build Coastguard Worker} 256*60517a1eSAndroid Build Coastguard Worker 257*60517a1eSAndroid Build Coastguard Worker// ExtensionEnabled returns whether the extension is enabled or not. 258*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) ExtensionEnabled() bool { 259*60517a1eSAndroid Build Coastguard Worker return c.extensionEnabled 260*60517a1eSAndroid Build Coastguard Worker} 261*60517a1eSAndroid Build Coastguard Worker 262*60517a1eSAndroid Build Coastguard Worker// SetPythonProjectRoot sets the Python project root. 263*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) SetPythonProjectRoot(pythonProjectRoot string) { 264*60517a1eSAndroid Build Coastguard Worker c.pythonProjectRoot = pythonProjectRoot 265*60517a1eSAndroid Build Coastguard Worker} 266*60517a1eSAndroid Build Coastguard Worker 267*60517a1eSAndroid Build Coastguard Worker// PythonProjectRoot returns the Python project root. 268*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) PythonProjectRoot() string { 269*60517a1eSAndroid Build Coastguard Worker return c.pythonProjectRoot 270*60517a1eSAndroid Build Coastguard Worker} 271*60517a1eSAndroid Build Coastguard Worker 272*60517a1eSAndroid Build Coastguard Worker// SetGazelleManifest sets the Gazelle manifest parsed from the 273*60517a1eSAndroid Build Coastguard Worker// gazelle_python.yaml file. 274*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) SetGazelleManifest(gazelleManifest *manifest.Manifest) { 275*60517a1eSAndroid Build Coastguard Worker c.gazelleManifest = gazelleManifest 276*60517a1eSAndroid Build Coastguard Worker} 277*60517a1eSAndroid Build Coastguard Worker 278*60517a1eSAndroid Build Coastguard Worker// FindThirdPartyDependency scans the gazelle manifests for the current config 279*60517a1eSAndroid Build Coastguard Worker// and the parent configs up to the root finding if it can resolve the module 280*60517a1eSAndroid Build Coastguard Worker// name. 281*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) FindThirdPartyDependency(modName string) (string, bool) { 282*60517a1eSAndroid Build Coastguard Worker for currentCfg := c; currentCfg != nil; currentCfg = currentCfg.parent { 283*60517a1eSAndroid Build Coastguard Worker if currentCfg.gazelleManifest != nil { 284*60517a1eSAndroid Build Coastguard Worker gazelleManifest := currentCfg.gazelleManifest 285*60517a1eSAndroid Build Coastguard Worker if distributionName, ok := gazelleManifest.ModulesMapping[modName]; ok { 286*60517a1eSAndroid Build Coastguard Worker var distributionRepositoryName string 287*60517a1eSAndroid Build Coastguard Worker if gazelleManifest.PipDepsRepositoryName != "" { 288*60517a1eSAndroid Build Coastguard Worker distributionRepositoryName = gazelleManifest.PipDepsRepositoryName 289*60517a1eSAndroid Build Coastguard Worker } else if gazelleManifest.PipRepository != nil { 290*60517a1eSAndroid Build Coastguard Worker distributionRepositoryName = gazelleManifest.PipRepository.Name 291*60517a1eSAndroid Build Coastguard Worker } 292*60517a1eSAndroid Build Coastguard Worker 293*60517a1eSAndroid Build Coastguard Worker lbl := currentCfg.FormatThirdPartyDependency(distributionRepositoryName, distributionName) 294*60517a1eSAndroid Build Coastguard Worker return lbl.String(), true 295*60517a1eSAndroid Build Coastguard Worker } 296*60517a1eSAndroid Build Coastguard Worker } 297*60517a1eSAndroid Build Coastguard Worker } 298*60517a1eSAndroid Build Coastguard Worker return "", false 299*60517a1eSAndroid Build Coastguard Worker} 300*60517a1eSAndroid Build Coastguard Worker 301*60517a1eSAndroid Build Coastguard Worker// AddIgnoreFile adds a file to the list of ignored files for a given package. 302*60517a1eSAndroid Build Coastguard Worker// Adding an ignored file to a package also makes it ignored on a subpackage. 303*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) AddIgnoreFile(file string) { 304*60517a1eSAndroid Build Coastguard Worker c.ignoreFiles[strings.TrimSpace(file)] = struct{}{} 305*60517a1eSAndroid Build Coastguard Worker} 306*60517a1eSAndroid Build Coastguard Worker 307*60517a1eSAndroid Build Coastguard Worker// IgnoresFile checks if a file is ignored in the given package or in one of the 308*60517a1eSAndroid Build Coastguard Worker// parent packages up to the workspace root. 309*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) IgnoresFile(file string) bool { 310*60517a1eSAndroid Build Coastguard Worker trimmedFile := strings.TrimSpace(file) 311*60517a1eSAndroid Build Coastguard Worker 312*60517a1eSAndroid Build Coastguard Worker if _, ignores := defaultIgnoreFiles[trimmedFile]; ignores { 313*60517a1eSAndroid Build Coastguard Worker return true 314*60517a1eSAndroid Build Coastguard Worker } 315*60517a1eSAndroid Build Coastguard Worker 316*60517a1eSAndroid Build Coastguard Worker if _, ignores := c.ignoreFiles[trimmedFile]; ignores { 317*60517a1eSAndroid Build Coastguard Worker return true 318*60517a1eSAndroid Build Coastguard Worker } 319*60517a1eSAndroid Build Coastguard Worker 320*60517a1eSAndroid Build Coastguard Worker parent := c.parent 321*60517a1eSAndroid Build Coastguard Worker for parent != nil { 322*60517a1eSAndroid Build Coastguard Worker if _, ignores := parent.ignoreFiles[trimmedFile]; ignores { 323*60517a1eSAndroid Build Coastguard Worker return true 324*60517a1eSAndroid Build Coastguard Worker } 325*60517a1eSAndroid Build Coastguard Worker parent = parent.parent 326*60517a1eSAndroid Build Coastguard Worker } 327*60517a1eSAndroid Build Coastguard Worker 328*60517a1eSAndroid Build Coastguard Worker return false 329*60517a1eSAndroid Build Coastguard Worker} 330*60517a1eSAndroid Build Coastguard Worker 331*60517a1eSAndroid Build Coastguard Worker// AddIgnoreDependency adds a dependency to the list of ignored dependencies for 332*60517a1eSAndroid Build Coastguard Worker// a given package. Adding an ignored dependency to a package also makes it 333*60517a1eSAndroid Build Coastguard Worker// ignored on a subpackage. 334*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) AddIgnoreDependency(dep string) { 335*60517a1eSAndroid Build Coastguard Worker c.ignoreDependencies[strings.TrimSpace(dep)] = struct{}{} 336*60517a1eSAndroid Build Coastguard Worker} 337*60517a1eSAndroid Build Coastguard Worker 338*60517a1eSAndroid Build Coastguard Worker// IgnoresDependency checks if a dependency is ignored in the given package or 339*60517a1eSAndroid Build Coastguard Worker// in one of the parent packages up to the workspace root. 340*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) IgnoresDependency(dep string) bool { 341*60517a1eSAndroid Build Coastguard Worker trimmedDep := strings.TrimSpace(dep) 342*60517a1eSAndroid Build Coastguard Worker 343*60517a1eSAndroid Build Coastguard Worker if _, ignores := c.ignoreDependencies[trimmedDep]; ignores { 344*60517a1eSAndroid Build Coastguard Worker return true 345*60517a1eSAndroid Build Coastguard Worker } 346*60517a1eSAndroid Build Coastguard Worker 347*60517a1eSAndroid Build Coastguard Worker parent := c.parent 348*60517a1eSAndroid Build Coastguard Worker for parent != nil { 349*60517a1eSAndroid Build Coastguard Worker if _, ignores := parent.ignoreDependencies[trimmedDep]; ignores { 350*60517a1eSAndroid Build Coastguard Worker return true 351*60517a1eSAndroid Build Coastguard Worker } 352*60517a1eSAndroid Build Coastguard Worker parent = parent.parent 353*60517a1eSAndroid Build Coastguard Worker } 354*60517a1eSAndroid Build Coastguard Worker 355*60517a1eSAndroid Build Coastguard Worker return false 356*60517a1eSAndroid Build Coastguard Worker} 357*60517a1eSAndroid Build Coastguard Worker 358*60517a1eSAndroid Build Coastguard Worker// SetValidateImportStatements sets whether Python import statements should be 359*60517a1eSAndroid Build Coastguard Worker// validated or not. It throws an error if this is set multiple times, i.e. if 360*60517a1eSAndroid Build Coastguard Worker// the directive is specified multiple times in the Bazel workspace. 361*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) SetValidateImportStatements(validate bool) { 362*60517a1eSAndroid Build Coastguard Worker c.validateImportStatements = validate 363*60517a1eSAndroid Build Coastguard Worker} 364*60517a1eSAndroid Build Coastguard Worker 365*60517a1eSAndroid Build Coastguard Worker// ValidateImportStatements returns whether the Python import statements should 366*60517a1eSAndroid Build Coastguard Worker// be validated or not. If this option was not explicitly specified by the user, 367*60517a1eSAndroid Build Coastguard Worker// it defaults to true. 368*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) ValidateImportStatements() bool { 369*60517a1eSAndroid Build Coastguard Worker return c.validateImportStatements 370*60517a1eSAndroid Build Coastguard Worker} 371*60517a1eSAndroid Build Coastguard Worker 372*60517a1eSAndroid Build Coastguard Worker// SetCoarseGrainedGeneration sets whether coarse-grained targets should be 373*60517a1eSAndroid Build Coastguard Worker// generated or not. 374*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) SetCoarseGrainedGeneration(coarseGrained bool) { 375*60517a1eSAndroid Build Coastguard Worker c.coarseGrainedGeneration = coarseGrained 376*60517a1eSAndroid Build Coastguard Worker} 377*60517a1eSAndroid Build Coastguard Worker 378*60517a1eSAndroid Build Coastguard Worker// CoarseGrainedGeneration returns whether coarse-grained targets should be 379*60517a1eSAndroid Build Coastguard Worker// generated or not. 380*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) CoarseGrainedGeneration() bool { 381*60517a1eSAndroid Build Coastguard Worker return c.coarseGrainedGeneration 382*60517a1eSAndroid Build Coastguard Worker} 383*60517a1eSAndroid Build Coastguard Worker 384*60517a1eSAndroid Build Coastguard Worker// SetPerFileGneration sets whether a separate py_library target should be 385*60517a1eSAndroid Build Coastguard Worker// generated for each file. 386*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) SetPerFileGeneration(perFile bool) { 387*60517a1eSAndroid Build Coastguard Worker c.perFileGeneration = perFile 388*60517a1eSAndroid Build Coastguard Worker} 389*60517a1eSAndroid Build Coastguard Worker 390*60517a1eSAndroid Build Coastguard Worker// PerFileGeneration returns whether a separate py_library target should be 391*60517a1eSAndroid Build Coastguard Worker// generated for each file. 392*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) PerFileGeneration() bool { 393*60517a1eSAndroid Build Coastguard Worker return c.perFileGeneration 394*60517a1eSAndroid Build Coastguard Worker} 395*60517a1eSAndroid Build Coastguard Worker 396*60517a1eSAndroid Build Coastguard Worker// SetPerFileGenerationIncludeInit sets whether py_library targets should 397*60517a1eSAndroid Build Coastguard Worker// include __init__.py files when PerFileGeneration() is true. 398*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) SetPerFileGenerationIncludeInit(includeInit bool) { 399*60517a1eSAndroid Build Coastguard Worker c.perFileGenerationIncludeInit = includeInit 400*60517a1eSAndroid Build Coastguard Worker} 401*60517a1eSAndroid Build Coastguard Worker 402*60517a1eSAndroid Build Coastguard Worker// PerFileGenerationIncludeInit returns whether py_library targets should 403*60517a1eSAndroid Build Coastguard Worker// include __init__.py files when PerFileGeneration() is true. 404*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) PerFileGenerationIncludeInit() bool { 405*60517a1eSAndroid Build Coastguard Worker return c.perFileGenerationIncludeInit 406*60517a1eSAndroid Build Coastguard Worker} 407*60517a1eSAndroid Build Coastguard Worker 408*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) SetPerPackageGenerationRequireTestEntryPoint(perPackageGenerationRequireTestEntryPoint bool) { 409*60517a1eSAndroid Build Coastguard Worker c.perPackageGenerationRequireTestEntryPoint = perPackageGenerationRequireTestEntryPoint 410*60517a1eSAndroid Build Coastguard Worker} 411*60517a1eSAndroid Build Coastguard Worker 412*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) PerPackageGenerationRequireTestEntryPoint() bool { 413*60517a1eSAndroid Build Coastguard Worker return c.perPackageGenerationRequireTestEntryPoint 414*60517a1eSAndroid Build Coastguard Worker} 415*60517a1eSAndroid Build Coastguard Worker 416*60517a1eSAndroid Build Coastguard Worker// SetLibraryNamingConvention sets the py_library target naming convention. 417*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) SetLibraryNamingConvention(libraryNamingConvention string) { 418*60517a1eSAndroid Build Coastguard Worker c.libraryNamingConvention = libraryNamingConvention 419*60517a1eSAndroid Build Coastguard Worker} 420*60517a1eSAndroid Build Coastguard Worker 421*60517a1eSAndroid Build Coastguard Worker// RenderLibraryName returns the py_library target name by performing all 422*60517a1eSAndroid Build Coastguard Worker// substitutions. 423*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) RenderLibraryName(packageName string) string { 424*60517a1eSAndroid Build Coastguard Worker return strings.ReplaceAll(c.libraryNamingConvention, packageNameNamingConventionSubstitution, packageName) 425*60517a1eSAndroid Build Coastguard Worker} 426*60517a1eSAndroid Build Coastguard Worker 427*60517a1eSAndroid Build Coastguard Worker// SetBinaryNamingConvention sets the py_binary target naming convention. 428*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) SetBinaryNamingConvention(binaryNamingConvention string) { 429*60517a1eSAndroid Build Coastguard Worker c.binaryNamingConvention = binaryNamingConvention 430*60517a1eSAndroid Build Coastguard Worker} 431*60517a1eSAndroid Build Coastguard Worker 432*60517a1eSAndroid Build Coastguard Worker// RenderBinaryName returns the py_binary target name by performing all 433*60517a1eSAndroid Build Coastguard Worker// substitutions. 434*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) RenderBinaryName(packageName string) string { 435*60517a1eSAndroid Build Coastguard Worker return strings.ReplaceAll(c.binaryNamingConvention, packageNameNamingConventionSubstitution, packageName) 436*60517a1eSAndroid Build Coastguard Worker} 437*60517a1eSAndroid Build Coastguard Worker 438*60517a1eSAndroid Build Coastguard Worker// SetTestNamingConvention sets the py_test target naming convention. 439*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) SetTestNamingConvention(testNamingConvention string) { 440*60517a1eSAndroid Build Coastguard Worker c.testNamingConvention = testNamingConvention 441*60517a1eSAndroid Build Coastguard Worker} 442*60517a1eSAndroid Build Coastguard Worker 443*60517a1eSAndroid Build Coastguard Worker// RenderTestName returns the py_test target name by performing all 444*60517a1eSAndroid Build Coastguard Worker// substitutions. 445*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) RenderTestName(packageName string) string { 446*60517a1eSAndroid Build Coastguard Worker return strings.ReplaceAll(c.testNamingConvention, packageNameNamingConventionSubstitution, packageName) 447*60517a1eSAndroid Build Coastguard Worker} 448*60517a1eSAndroid Build Coastguard Worker 449*60517a1eSAndroid Build Coastguard Worker// AppendVisibility adds additional items to the target's visibility. 450*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) AppendVisibility(visibility string) { 451*60517a1eSAndroid Build Coastguard Worker c.visibility = append(c.visibility, visibility) 452*60517a1eSAndroid Build Coastguard Worker} 453*60517a1eSAndroid Build Coastguard Worker 454*60517a1eSAndroid Build Coastguard Worker// Visibility returns the target's visibility. 455*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) Visibility() []string { 456*60517a1eSAndroid Build Coastguard Worker return append(c.defaultVisibility, c.visibility...) 457*60517a1eSAndroid Build Coastguard Worker} 458*60517a1eSAndroid Build Coastguard Worker 459*60517a1eSAndroid Build Coastguard Worker// SetDefaultVisibility sets the default visibility of the target. 460*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) SetDefaultVisibility(visibility []string) { 461*60517a1eSAndroid Build Coastguard Worker c.defaultVisibility = visibility 462*60517a1eSAndroid Build Coastguard Worker} 463*60517a1eSAndroid Build Coastguard Worker 464*60517a1eSAndroid Build Coastguard Worker// DefaultVisibilty returns the target's default visibility. 465*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) DefaultVisibilty() []string { 466*60517a1eSAndroid Build Coastguard Worker return c.defaultVisibility 467*60517a1eSAndroid Build Coastguard Worker} 468*60517a1eSAndroid Build Coastguard Worker 469*60517a1eSAndroid Build Coastguard Worker// SetTestFilePattern sets the file patterns that should be mapped to 'py_test' rules. 470*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) SetTestFilePattern(patterns []string) { 471*60517a1eSAndroid Build Coastguard Worker c.testFilePattern = patterns 472*60517a1eSAndroid Build Coastguard Worker} 473*60517a1eSAndroid Build Coastguard Worker 474*60517a1eSAndroid Build Coastguard Worker// TestFilePattern returns the patterns that should be mapped to 'py_test' rules. 475*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) TestFilePattern() []string { 476*60517a1eSAndroid Build Coastguard Worker return c.testFilePattern 477*60517a1eSAndroid Build Coastguard Worker} 478*60517a1eSAndroid Build Coastguard Worker 479*60517a1eSAndroid Build Coastguard Worker// SetLabelConvention sets the label convention used for third-party dependencies. 480*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) SetLabelConvention(convention string) { 481*60517a1eSAndroid Build Coastguard Worker c.labelConvention = convention 482*60517a1eSAndroid Build Coastguard Worker} 483*60517a1eSAndroid Build Coastguard Worker 484*60517a1eSAndroid Build Coastguard Worker// LabelConvention returns the label convention used for third-party dependencies. 485*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) LabelConvention() string { 486*60517a1eSAndroid Build Coastguard Worker return c.labelConvention 487*60517a1eSAndroid Build Coastguard Worker} 488*60517a1eSAndroid Build Coastguard Worker 489*60517a1eSAndroid Build Coastguard Worker// SetLabelConvention sets the label normalization applied to distribution names of third-party dependencies. 490*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) SetLabelNormalization(normalizationType LabelNormalizationType) { 491*60517a1eSAndroid Build Coastguard Worker c.labelNormalization = normalizationType 492*60517a1eSAndroid Build Coastguard Worker} 493*60517a1eSAndroid Build Coastguard Worker 494*60517a1eSAndroid Build Coastguard Worker// LabelConvention returns the label normalization applied to distribution names of third-party dependencies. 495*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) LabelNormalization() LabelNormalizationType { 496*60517a1eSAndroid Build Coastguard Worker return c.labelNormalization 497*60517a1eSAndroid Build Coastguard Worker} 498*60517a1eSAndroid Build Coastguard Worker 499*60517a1eSAndroid Build Coastguard Worker// FormatThirdPartyDependency returns a label to a third-party dependency performing all formating and normalization. 500*60517a1eSAndroid Build Coastguard Workerfunc (c *Config) FormatThirdPartyDependency(repositoryName string, distributionName string) label.Label { 501*60517a1eSAndroid Build Coastguard Worker conventionalDistributionName := strings.ReplaceAll(c.labelConvention, distributionNameLabelConventionSubstitution, distributionName) 502*60517a1eSAndroid Build Coastguard Worker 503*60517a1eSAndroid Build Coastguard Worker var normConventionalDistributionName string 504*60517a1eSAndroid Build Coastguard Worker switch norm := c.LabelNormalization(); norm { 505*60517a1eSAndroid Build Coastguard Worker case SnakeCaseLabelNormalizationType: 506*60517a1eSAndroid Build Coastguard Worker // See /python/private/normalize_name.bzl 507*60517a1eSAndroid Build Coastguard Worker normConventionalDistributionName = strings.ToLower(conventionalDistributionName) 508*60517a1eSAndroid Build Coastguard Worker normConventionalDistributionName = regexp.MustCompile(`[-_.]+`).ReplaceAllString(normConventionalDistributionName, "_") 509*60517a1eSAndroid Build Coastguard Worker normConventionalDistributionName = strings.Trim(normConventionalDistributionName, "_") 510*60517a1eSAndroid Build Coastguard Worker case Pep503LabelNormalizationType: 511*60517a1eSAndroid Build Coastguard Worker // See https://packaging.python.org/en/latest/specifications/name-normalization/#name-format 512*60517a1eSAndroid Build Coastguard Worker normConventionalDistributionName = strings.ToLower(conventionalDistributionName) // ... "should be lowercased" 513*60517a1eSAndroid Build Coastguard Worker normConventionalDistributionName = regexp.MustCompile(`[-_.]+`).ReplaceAllString(normConventionalDistributionName, "-") // ... "all runs of the characters ., -, or _ replaced with a single -" 514*60517a1eSAndroid Build Coastguard Worker normConventionalDistributionName = strings.Trim(normConventionalDistributionName, "-") // ... "must start and end with a letter or number" 515*60517a1eSAndroid Build Coastguard Worker default: 516*60517a1eSAndroid Build Coastguard Worker fallthrough 517*60517a1eSAndroid Build Coastguard Worker case NoLabelNormalizationType: 518*60517a1eSAndroid Build Coastguard Worker normConventionalDistributionName = conventionalDistributionName 519*60517a1eSAndroid Build Coastguard Worker } 520*60517a1eSAndroid Build Coastguard Worker 521*60517a1eSAndroid Build Coastguard Worker return label.New(repositoryName, normConventionalDistributionName, normConventionalDistributionName) 522*60517a1eSAndroid Build Coastguard Worker} 523