xref: /aosp_15_r20/external/bazelbuild-rules_python/gazelle/pythonconfig/pythonconfig.go (revision 60517a1edbc8ecf509223e9af94a7adec7d736b8)
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