forked from pantsbuild/pants
-
Notifications
You must be signed in to change notification settings - Fork 37
/
jaxb_gen.py
126 lines (108 loc) · 4.92 KB
/
jaxb_gen.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
# coding=utf-8
# Copyright 2014 Pants project contributors (see CONTRIBUTORS.md).
# Licensed under the Apache License, Version 2.0 (see LICENSE).
from __future__ import (absolute_import, division, generators, nested_scopes, print_function,
unicode_literals, with_statement)
import os
import re
from pants.backend.codegen.jaxb.jaxb_library import JaxbLibrary
from pants.backend.jvm.targets.java_library import JavaLibrary
from pants.backend.jvm.tasks.nailgun_task import NailgunTask
from pants.base.exceptions import TaskError
from pants.base.workunit import WorkUnitLabel
from pants.java.jar.jar_dependency import JarDependency
from pants.task.simple_codegen_task import SimpleCodegenTask
class JaxbGen(SimpleCodegenTask, NailgunTask):
"""Generates java source files from jaxb schema (.xsd)."""
_XJC_MAIN = 'com.sun.tools.xjc.Driver'
_XML_BIND_VERSION = '2.3.0'
sources_globs = ('**/*',)
@classmethod
def register_options(cls, register):
super(JaxbGen, cls).register_options(register)
cls.register_jvm_tool(register,
'xjc',
classpath=[
JarDependency(org='com.sun.xml.bind',
name='jaxb-core',
rev=cls._XML_BIND_VERSION),
JarDependency(org='com.sun.xml.bind',
name='jaxb-impl',
rev=cls._XML_BIND_VERSION),
JarDependency(org='com.sun.xml.bind',
name='jaxb-xjc',
rev=cls._XML_BIND_VERSION),
JarDependency(org='com.sun.activation',
name='javax.activation',
rev='1.2.0'),
JarDependency(org='javax.xml.bind',
name='jaxb-api',
rev=cls._XML_BIND_VERSION),
],
main=cls._XJC_MAIN,
)
def __init__(self, *args, **kwargs):
"""
:param context: inherited parameter from Task
:param workdir: inherited parameter from Task
"""
super(JaxbGen, self).__init__(*args, **kwargs)
self.set_distribution(jdk=True)
self.gen_langs = set()
lang = 'java'
if self.context.products.isrequired(lang):
self.gen_langs.add(lang)
def synthetic_target_type(self, target):
return JavaLibrary
def is_gentarget(self, target):
return isinstance(target, JaxbLibrary)
def execute_codegen(self, target, target_workdir):
if not isinstance(target, JaxbLibrary):
raise TaskError('Invalid target type "{class_type}" (expected JaxbLibrary)'
.format(class_type=type(target).__name__))
for source in target.sources_relative_to_buildroot():
path_to_xsd = source
output_package = target.package
if output_package is None:
output_package = self._guess_package(source)
output_package = self._correct_package(output_package)
# NB(zundel): The -no-header option keeps it from writing a timestamp, making the
# output non-deterministic. See https://github.com/pantsbuild/pants/issues/1786
args = [
'-p', output_package,
'-d', target_workdir,
'-no-header', path_to_xsd
]
result = self.runjava(classpath=self.tool_classpath('xjc'),
main=self._XJC_MAIN,
jvm_options=self.get_options().jvm_options,
args=args,
workunit_name='xjc',
workunit_labels=[WorkUnitLabel.TOOL])
if result != 0:
raise TaskError('xjc ... exited non-zero ({code})'.format(code=result))
@classmethod
def _guess_package(self, path):
"""Used in execute_codegen to actually invoke the compiler with the proper arguments, and in
_sources_to_be_generated to declare what the generated files will be.
"""
supported_prefixes = ('com', 'org', 'net',)
package = ''
slash = path.rfind(os.path.sep)
prefix_with_slash = max(path.rfind(os.path.join('', prefix, ''))
for prefix in supported_prefixes)
if prefix_with_slash < 0:
package = path[:slash]
elif prefix_with_slash >= 0:
package = path[prefix_with_slash:slash]
package = package.replace(os.path.sep, ' ')
package = package.strip().replace(' ', '.')
return package
@classmethod
def _correct_package(self, package):
package = package.replace('/', '.')
package = re.sub(r'^\.+', '', package)
package = re.sub(r'\.+$', '', package)
if re.search(r'\.{2,}', package) is not None:
raise ValueError('Package name cannot have consecutive periods! ({})'.format(package))
return package