77This module has abstractions for Bazel labels.
88"""
99
10-
1110import os
1211
1312
14- _BUILD_FILE_NAMES = ("BUILD" , "BUILD.bazel" )
15-
16-
17- def for_package (root_dir , package_path ):
18- """
19- Returns a label instance for the Bazel package at the given relative path,
20- rooted at the given root_dir. Returns None if no build file exists at that
21- location.
22- """
23- for fname in _BUILD_FILE_NAMES :
24- rel_path = os .path .join (package_path , fname )
25- abs_path = os .path .join (root_dir , rel_path )
26- if os .path .isfile (abs_path ):
27- return Label (rel_path )
28- return None
29-
30-
31- def find_packages (root_dir , package_path = "" ):
32- """
33- Walks the directory tree, starting at root dir, and returns a list of
34- Label instances for all Bazel packages that exist under the given root_dir.
35-
36- If package_path is specified, the search starts at that location.
37- """
38- labels = []
39- for path , dirs , files in os .walk (os .path .join (root_dir , package_path )):
40- for fname in files :
41- if fname in _BUILD_FILE_NAMES :
42- rel_path = os .path .join (os .path .relpath (path , root_dir ), fname )
43- if rel_path .startswith ("./" ):
44- # build file at root dir, remove "./" so that the package
45- # of the Label is empty
46- rel_path = rel_path [2 :]
47- labels .append (Label (rel_path ))
48- return labels
49-
50-
5113class Label (object ):
5214 """
53- Represents a Bazel Label.
15+ Represents a bazel Label.
5416 """
5517
5618 def __init__ (self , name ):
5719 """
58- Initializes a Label with the given name, a string. name represents
59- a path-like structure with an optional target [path:target].
60-
61- If the last path segment is a build file (/BUILD or /BUILD.bazel),
62- it is removed from the path.
63-
20+ Initializes a Label with the given string label representation.
6421 """
6522 assert name is not None
6623 name = name .strip ()
6724 if name .endswith ("/" ):
6825 name = name [:- 1 ]
69- fname = os .path .basename (name )
70- if fname in ("BUILD" , "BUILD.bazel" ):
71- name = os .path .dirname (name )
72- self ._build_file_name = fname
73- else :
74- self ._build_file_name = None
7526 self ._name = name
7627
77- @property
78- def name (self ):
79- """
80- The name this instance was initialized with.
81- """
82- return self ._name
83-
84- @property
85- def package (self ):
86- """
87- The Bazel Package of this label.
88- For example, for "//a/b/c:foo", return "//a/b/c"
89- """
90- i = self ._name .find (":" )
91- if i == - 1 :
92- if self ._name .endswith ("..." ):
93- return self ._name [:- 3 ]
94- return self ._name
95- return self ._name [0 :i ]
96-
9728 @property
9829 def package_path (self ):
9930 """
100- Returns the Package of this label as a valid relative path.
31+ Returns the package of this label as a relative path.
10132 """
102- p = self .package
103- if p .startswith ("//" ):
104- p = p [2 :]
105- if p .endswith ("/" ):
106- p = p [:- 1 ]
107- return p
33+ start_index = self ._name .find ("//" )
34+ if start_index == - 1 :
35+ start_index = 0
36+ else :
37+ start_index += 2
38+ target_index = self ._name .rfind (":" )
39+ if target_index == - 1 :
40+ target_index = len (self ._name )
41+ path = self ._name [start_index :target_index ]
42+ if path .endswith ("..." ):
43+ path = path [:- 3 ]
44+ if path .endswith ("/" ):
45+ path = path [:- 1 ]
46+ return path
10847
10948 @property
11049 def target (self ):
11150 """
112- The Bazel Target of this label.
113- For example, for "//a/b/c:foo", return "foo"
51+ The bazel target of this label.
52+ For example, for "//a/b/c:foo", returns "foo".
11453 """
115- i = self ._name .find (":" )
54+ i = self ._name .rfind (":" )
11655 if i == - 1 :
11756 return os .path .basename (self ._name )
11857 return self ._name [i + 1 :]
11958
120- @property
121- def target_name (self ):
122- """
123- An alias for the "target" property.
124- """
125- return self .target
126-
12759 @property
12860 def is_default_target (self ):
12961 """
13062 Returns True if this label refers to the default target in the package,
13163 ie the target that has the same name as the directory the BUILD file
13264 lives in.
13365 """
134- package = self .package
135- target = self .target
136- if package is None :
137- return False
138- if target is None :
139- return True
140- return os .path .basename (package ) == target
66+ return os .path .basename (self .package_path ) == self .target
14167
14268 @property
14369 def is_root_target (self ):
@@ -148,66 +74,26 @@ def is_root_target(self):
14874 return "//:" in self ._name
14975
15076 @property
151- def fqname (self ):
152- """
153- The name of this label with a default repo prefix, iff the
154- initial name did not specify such a prefix and this is not a src ref.
155- """
156- if self .is_source_ref :
157- return self ._name
158- if self .has_repo_prefix :
159- return self ._name
160- else :
161- # the default prefix we use for names without repo prefix:
162- # if name is foo, fqname will be @maven//:foo
163- # "maven" doesn't really make sense to use anymore, but it isn't
164- # clear what to use instead - probably defaulting the repo doesn't
165- # make sense
166- default_repo = "maven"
167- return self .prefix_with (default_repo ).name
168-
169- @property
170- def simple_name (self ):
171- """
172- The name of this label without the remote repo prefix.
173- If this label does not have a remote repo prefix, returns just
174- its name.
175- """
176- if self .is_source_ref :
177- return self ._name
178- if self .has_repo_prefix :
179- prefix = self .repo_prefix
180- return self ._name [len (prefix )+ 4 :] # 4 = additional chars @//:
181- else :
182- return self ._name
183-
184- @property
185- def is_private (self ):
186- """
187- Returns True if this label refers to a private target (starts with ":")
188- """
189- return self ._name .startswith (":" )
190-
191- @property
192- def has_repo_prefix (self ):
77+ def has_repository_prefix (self ):
19378 """
194- Whether this label name has a remote repo prefix.
79+ Whether this label name has a remote repository prefix.
19580 """
196- return self .repo_prefix is not None
81+ return self .repository_prefix != ""
19782
19883 @property
199- def repo_prefix (self ):
84+ def repository_prefix (self ):
20085 """
201- The remote repo prefix, or workspace name of this label; None if this
202- label name doesn't have one.
86+ The repository prefix, or workspace name of this label; empty string if
87+ this label name doesn't have one.
20388
204- For example, for a label like "@pomgen//maven", returns "pomgen".
89+ For example, for a label like "@pomgen//maven", this method returns
90+ "@pomgen", for "//foo/path" it returns "".
20591 """
20692 if self ._name .startswith ("@" ):
20793 i = self ._name .find ("//" )
20894 if i != - 1 :
209- return self ._name [1 :i ]
210- return None
95+ return self ._name [0 :i ]
96+ return ""
21197
21298 @property
21399 def is_source_ref (self ):
@@ -217,81 +103,41 @@ def is_source_ref(self):
217103 return self ._name .startswith ("//" )
218104
219105 @property
220- def has_file_extension (self ):
221- ext = os .path .splitext (self ._name )[1 ]
222- return ext in (".jar" , ".proto" , ".h" , ".c" , ".cc" , ".cpp" , ".m" , ".py" , ".pyc" , ".java" , ".go" )
223-
224- @property
225- def has_extension_suffix (self ):
226- return self ._name .endswith ("_extension" )
227-
228- @property
229- def is_sources_artifact (self ):
230- return "_jar_sources" in self ._name
231-
232- @property
233- def build_file_path (self ):
106+ def canonical_form (self ):
234107 """
235- The path to the build file of this package, if this Label instance was
236- created with a path that pointed to a build file.
237- None if this Label instance does not know about the build file it was
238- created for.
239- """
240- if self ._build_file_name is None :
241- return None
242- return os .path .join (self .package_path , self ._build_file_name )
108+ Returns the label as a string in its canonical form:
243109
244- def prefix_with (self , repo_prefix ):
245- """
246- Returns a new Label instance that is qualified with the
247- specified repo_prefix. This method asserts that this instance is not
248- already fully qualified.
249- """
250- assert not self .has_repo_prefix , "This label already has a repo prefix: %s" % self ._name
251- return Label ("@%s//:%s" % (repo_prefix , self ._name ))
110+ [@repository]//<package-path>:<target>.
252111
253- def with_target (self , target ):
254- """
255- Returns a new Label instance that has the specified target.
112+ References to the default target are omitted.
256113 """
257- return Label ("%s:%s" % (self .package , target ))
114+ target = "" if self .is_default_target else ":%s" % self .target
115+ return "%s//%s%s" % (self .repository_prefix , self .package_path , target )
258116
259- def as_wildcard_label (self , wildcard ):
260- if wildcard == "..." :
261- return Label ("%s/%s" % (self .package , wildcard ))
262- else :
263- return Label ("%s:%s" % (self .package , wildcard ))
264-
265- def as_alternate_default_target_syntax (self ):
117+ def with_target (self , new_target_name ):
266118 """
267- Labels may omit the target if they refer to the default target, or they
268- may not omit it. If this Label instance refers to the default target,
269- this method returns the other syntax.
270- So:
271- Given this Label instance is: //a/b/c, returns //a/b/c:c
272- Or, given this Label instance is //a/b/c:c, returns //a/b/c
119+ Returns a new Label instance with the specified new target name.
273120 """
274- assert self .is_default_target , "label must refer to the default target"
275- if ":" in self .name :
276- return Label (self .package )
121+ if self .is_default_target :
122+ label = self .canonical_form
277123 else :
278- return Label ("%s:%s" % (self .package , self .target ))
124+ label = self .canonical_form [:- (len (self .target )+ 1 )]
125+ return Label ("%s:%s" % (label , new_target_name ))
279126
280127 def __hash__ (self ):
281- return hash ((self .package_path , self .target ))
128+ return hash ((self .repository_prefix , self . package_path , self .target ))
282129
283130 def __eq__ (self , other ):
284131 if other is None :
285132 return False
286- return self .package_path == other .package_path and self .target == other .target
133+ return (self .repository_prefix == other .repository_prefix and
134+ self .package_path == other .package_path and
135+ self .target == other .target )
287136
288137 def __ne__ (self , other ):
289138 return not self == other
290139
291- def __len__ (self ):
292- return len (self ._name )
293-
294140 def __repr__ (self ):
295- return self ._name
141+ return self .canonical_form
296142
297143 __str__ = __repr__
0 commit comments