forked from salesforce/pomgen
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbuildpom.py
369 lines (288 loc) · 13.7 KB
/
buildpom.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
"""
Copyright (c) 2018, salesforce.com, inc.
All rights reserved.
SPDX-License-Identifier: BSD-3-Clause
For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
This module is responsible for parsing BUILD.pom and BUILD.pom.released files.
"""
from collections import namedtuple
from common import code
from common import mdfiles
from common import pomgenmode
from common import version as versionm
import os
class MavenArtifactDef(object):
"""
Represents an instance of a maven_artifact rule defined in BUILD.pom file.
Information from the BUILD.pom.released file is added, if that file exists.
==== Read out of the BUILD.pom file ====
group_id: the maven artifact groupId of the bazel package.
artifact_id: the maven artifact id (artifactId) of the bazel package.
version: the maven artifact version of the bazel package.
pom_generation_mode: the pom generation strategy, the type is
common.pomgenmode.PomGenMode
custom_pom_template: if the pom_generation_mode is "template",
this is the content of the specified pom template file
include_deps: whether pomgen should include dependencies in the generated
pom. This defaults to True, because figuring out dependencies and
including them in the generated pom is kinda the main purpose of
pomgen. However, there are some edge cases where we just want a dummy
pom to facilitate upload to Nexus only.
Setting this to False also disables crawling source dependencies
referenced by this bazel package.
change_detection: whether pomgen should mark this artifact as needing to be
released based on whether changes have been made made to the artifact
since it was last released. Defaults to True.
If set explicitly to False, then the artifact is unconditionally marked
as needing to be released.
additional_change_detected_packages: list of additional bazel packages
pomgen should check for changes when determining whether this artifact
needs to be released.
gen_dependency_management_pom: whether to generate an additional pom.xml
that only contains <dependencyManagement>. Defaults to False.
jar_path: optional and for supporting the edge-case when the jar artifact
already exists: if set, the relative path from this BUILD.pom file to
the jar artifact to use. this can be used if bazel doesn't actually
build the jar (-> java_import).
version_increment_strategy_name: specifies how this artifacts version should
be incremented.
==== Read out of the optional BUILD.pom.released file ====
released_version: the previously released version to Nexus
released_artifact_hash: the hash of the artifact at the time it was
previously released to Nexus
===== Internal attributes (never specified by the user) ====
deps: additional targets this package depends on; list of Bazel labels.
For example: deps = ["//projects/libs/servicelibs/srpc/srpc-thrift-svc-runtime"]
The deps attribute is only used by tests.
bazel_package: the bazel package the BUILD (and MVN-INF/) files live in
bazel_target: the bazel target that builds this artifact
library_path: the path to the root directory of the library this artifact
is part of
requires_release: whether this artifact should be released (to Nexus
or local Maven repository)
release_reason: the reason for releasing this artifact
released_pom_content: if the file pom.xml.released exists next to the
BUILD.pom file, the content of the pom.xml.released file
=====
Implementation notes:
- properties are kept read-only whenever possible
- the constructor provides default values for easier instantiation
in test code
"""
def __init__(self,
group_id,
artifact_id,
version,
pom_generation_mode=pomgenmode.DEFAULT,
custom_pom_template_content=None,
include_deps=True,
change_detection=True,
additional_change_detected_packages=[],
gen_dependency_management_pom=False,
jar_path=None,
deps=[],
version_increment_strategy_name=None,
released_version=None,
released_artifact_hash=None,
bazel_package=None,
bazel_target=None,
library_path=None,
requires_release=None,
released_pom_content=None):
self._group_id = group_id
self._artifact_id = artifact_id
self._version = version
self._pom_generation_mode = pom_generation_mode
self._custom_pom_template_content = custom_pom_template_content
self._include_deps = include_deps
self._change_detection = change_detection
self._additional_change_detected_packages = additional_change_detected_packages
self._gen_dependency_management_pom = gen_dependency_management_pom
self._jar_path = jar_path
self._deps = deps
self._version_increment_strategy_name = version_increment_strategy_name
self._released_version = released_version
self._released_artifact_hash = released_artifact_hash
self._bazel_package = bazel_package
self._bazel_target = bazel_target
self._library_path = library_path
self._requires_release = requires_release
self._release_reason = None
self._released_pom_content = released_pom_content
# data cleanup/verification/sanitization
# these are separate methods for better readability
self._sanitize_additional_change_detected_packages()
@property
def group_id(self):
return self._group_id
@property
def artifact_id(self):
return self._artifact_id
@property
def version(self):
return self._version
@property
def pom_generation_mode(self):
return self._pom_generation_mode
@property
def custom_pom_template_content(self):
return self._custom_pom_template_content
@custom_pom_template_content.setter
def custom_pom_template_content(self, value):
self._custom_pom_template_content = value
@property
def include_deps(self):
return self._include_deps
@property
def change_detection(self):
return self._change_detection
@property
def additional_change_detected_packages(self):
return self._additional_change_detected_packages
@property
def gen_dependency_management_pom(self):
return self._gen_dependency_management_pom
@property
def jar_path(self):
return self._jar_path
@property
def deps(self):
return self._deps
@property
def released_version(self):
return self._released_version
@property
def released_artifact_hash(self):
return self._released_artifact_hash
@released_artifact_hash.setter
def released_artifact_hash(self, value):
self._released_artifact_hash = value
@property
def bazel_package(self):
return self._bazel_package
@property
def bazel_target(self):
return self._bazel_target
@property
def library_path(self):
return self._library_path
@library_path.setter
def library_path(self, value):
self._library_path = value
@property
def requires_release(self):
if not self._pom_generation_mode.produces_artifact:
# nothing ever to release
return False
return self._requires_release
@requires_release.setter
def requires_release(self, value):
self._requires_release = value
@property
def release_reason(self):
return self._release_reason
@release_reason.setter
def release_reason(self, value):
self._release_reason = value
@property
def released_pom_content(self):
return self._released_pom_content
@property
def version_increment_strategy_name(self):
return self._version_increment_strategy_name
def __str__(self):
return "%s:%s" % (self._group_id, self._artifact_id)
def __repr__(self):
return str(self)
def _sanitize_additional_change_detected_packages(self):
# we treat these bazel package as paths relative to the repo root,
# so make sure they don't start with "//"
self._additional_change_detected_packages = [p[2:] if p.startswith("//") else p for p in self._additional_change_detected_packages]
# only used internally for parsing
ReleasedMavenArtifactDef = namedtuple("ReleasedMavenArtifactDef", "version artifact_hash")
def parse_maven_artifact_def(root_path, package):
"""
Parses the BUILD.pom file *and* BUILD.pom.released file at the specified
path and returns a MavenArtifactDef instance.
Returns None if there is no BUILD.pom file at the specified path.
"""
content, path = mdfiles.read_file(root_path, package, mdfiles.BUILD_POM_FILE_NAME)
if content is None:
return None
ma = code.get_function_block(content, "maven_artifact")
ma_attrs = code.parse_attributes(ma)
art_def = MavenArtifactDef(
group_id=ma_attrs.get("group_id", None),
artifact_id=ma_attrs.get("artifact_id", None),
version=ma_attrs.get("version", None),
pom_generation_mode=ma_attrs.get("pom_generation_mode", None),
include_deps=ma_attrs.get("include_deps", True),
change_detection=ma_attrs.get("change_detection", True),
additional_change_detected_packages=ma_attrs.get("additional_change_detected_packages", []),
gen_dependency_management_pom=ma_attrs.get("generate_dependency_management_pom", False),
jar_path=ma_attrs.get("jar_path", None),
bazel_target=ma_attrs.get("target_name", None),
deps=ma_attrs.get("deps", []))
template_path = ma_attrs.get("pom_template_file", None)
if template_path is not None:
template_content, _ = mdfiles.read_file(root_path, package, template_path)
art_def.custom_pom_template_content = template_content
pom_generation_mode = pomgenmode.from_string(art_def.pom_generation_mode)
if pom_generation_mode.produces_artifact:
rel_art_def = _parse_released_maven_artifact_def(root_path, package)
released_pom_content = _read_released_pom(root_path, package)
maup = code.get_function_block(content, "maven_artifact_update")
maup_attrs = code.parse_attributes(maup)
vers_inc_strat_name = maup_attrs.get("version_increment_strategy", None)
return _augment_art_def_values(art_def, rel_art_def, package,
released_pom_content,
vers_inc_strat_name,
pom_generation_mode)
else:
return _augment_art_def_values(art_def,
rel_art_def=None,
bazel_package=package,
released_pom_content=None,
version_increment_strategy_name=None,
pom_generation_mode=pom_generation_mode)
def _read_released_pom(root_path, package):
content, _ = mdfiles.read_file(root_path, package, mdfiles.POM_XML_RELEASED_FILE_NAME)
return content
def _parse_released_maven_artifact_def(root_path, package):
"""
Parses the BUILD.pom.released file at the specified path and returns a
ReleasedMavenArtifactDef instance.
Returns None if there is no BUILD.pom.released file at the specified path.
"""
content, _ = mdfiles.read_file(root_path, package, mdfiles.BUILD_POM_RELEASED_FILE_NAME)
if content is None:
return None
attrs = code.parse_attributes(content)
return ReleasedMavenArtifactDef(
version=attrs.get("version", None),
artifact_hash=attrs.get("artifact_hash", None))
def _augment_art_def_values(user_art_def, rel_art_def, bazel_package,
released_pom_content,
version_increment_strategy_name,
pom_generation_mode):
"""
Defaults values that have not been provided in the BUILD.pom file.
"""
return MavenArtifactDef(
group_id=user_art_def.group_id,
artifact_id=user_art_def.artifact_id,
version=user_art_def.version,
pom_generation_mode=pom_generation_mode,
custom_pom_template_content=user_art_def.custom_pom_template_content,
include_deps=True if user_art_def.include_deps is None else user_art_def.include_deps,
change_detection=True if user_art_def.change_detection is None else user_art_def.change_detection,
additional_change_detected_packages=[] if user_art_def.additional_change_detected_packages is None else user_art_def.additional_change_detected_packages,
gen_dependency_management_pom=False if user_art_def.gen_dependency_management_pom is None else user_art_def.gen_dependency_management_pom,
jar_path=None if user_art_def.jar_path is None else os.path.normpath(os.path.join(bazel_package, mdfiles.MD_DIR_NAME, user_art_def.jar_path)),
deps=user_art_def.deps,
bazel_target=user_art_def.bazel_target if user_art_def.bazel_target is not None else os.path.basename(bazel_package),
released_version=rel_art_def.version if rel_art_def is not None else None,
released_artifact_hash=rel_art_def.artifact_hash if rel_art_def is not None else None,
bazel_package=bazel_package,
released_pom_content=released_pom_content,
version_increment_strategy_name=version_increment_strategy_name)