Skip to content
This repository has been archived by the owner on Dec 10, 2020. It is now read-only.

Commit

Permalink
Add the -no-header argument to jaxb generator to give deterministic o…
Browse files Browse the repository at this point in the history
…utput

Makes the jaxb output deterministic to make it compatible with caching.
Also removed some logic for global codegen strategy that is no longer needed.

The jaxb generator adds a timestamp to each java file it generates by default.

```
  // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2
  // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
  // Any modifications to this file will be lost upon recompilation of the source schema.
  // Generated on: 2015.07.09 at 03:50:50 PM PDT
```

Fortuantely, you can easiliy turn this off

```
$ xjc -h | grep header
  -no-header         :  suppress generation of a file header with timestamp
```

Testing Done:
CI is running at https://travis-ci.org/pantsbuild/pants/builds/93226958
Updated unit tests.

Bugs closed: 1768, 2627

Reviewed at https://rbcommons.com/s/twitter/r/3179/
  • Loading branch information
ericzundel committed Nov 25, 2015
1 parent 656348a commit 3e0da3f
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 79 deletions.
4 changes: 0 additions & 4 deletions src/python/pants/backend/codegen/tasks/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,8 @@ python_library(
'src/python/pants/backend/codegen/targets:java',
'src/python/pants/backend/jvm/targets:java',
'src/python/pants/backend/jvm/tasks:nailgun_task',
'src/python/pants/base:build_environment',
'src/python/pants/base:exceptions',
'src/python/pants/base:source_root',
'src/python/pants/build_graph',
'src/python/pants/java/distribution:distribution',
'src/python/pants/util:dirutil',
],
)

Expand Down
37 changes: 3 additions & 34 deletions src/python/pants/backend/codegen/tasks/jaxb_gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,13 @@

import os
import re
# just running it on code in our repositories, not on externally acquired data.
from xml.dom.minidom import parse

from pants.backend.codegen.targets.jaxb_library import JaxbLibrary
from pants.backend.codegen.tasks.simple_codegen_task import SimpleCodegenTask
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.java.distribution.distribution import DistributionLocator
from pants.util.dirutil import safe_mkdir


class JaxbGen(SimpleCodegenTask, NailgunTask):
Expand Down Expand Up @@ -49,7 +46,6 @@ def execute_codegen(self, target, target_workdir):
raise TaskError('Invalid target type "{class_type}" (expected JaxbLibrary)'
.format(class_type=type(target).__name__))

target_files = []
for source in target.sources_relative_to_buildroot():
path_to_xsd = source
output_package = target.package
Expand All @@ -58,12 +54,13 @@ def execute_codegen(self, target, target_workdir):
output_package = self._guess_package(source)
output_package = self._correct_package(output_package)

args = ['-p', output_package, '-d', target_workdir, path_to_xsd]
# 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._compile_schema(args)

if result != 0:
raise TaskError('xjc ... exited non-zero ({code})'.format(code=result))
target_files.append(self._sources_to_be_generated(target.package, path_to_xsd))

@classmethod
def _guess_package(self, path):
Expand Down Expand Up @@ -91,31 +88,3 @@ def _correct_package(self, package):
if re.search(r'\.{2,}', package) is not None:
raise ValueError('Package name cannot have consecutive periods! ({})'.format(package))
return package

@classmethod
def _sources_to_be_generated(self, package, path):
"""Predicts what java sources will be generated by an individual schema file.
:param str package: the package for the generated java files.
:param str path: the path to the .xsd schema file.
:return: a list of relative filepaths.
"""
doc = parse(path)
if package is None:
package = self._guess_package(path)
package = self._correct_package(package)

names = []
for root in doc.childNodes:
if re.match('.*?:schema$', root.nodeName, re.I) is not None:
for element in root.childNodes:
if element.nodeName != '#text' and element.attributes.has_key('name'):
name = element.attributes['name'].nodeValue
if len(name) == 0: continue
# enforce pascal-case class names
name = name[0:1].upper() + name[1:]
names.append(name)

names.append('ObjectFactory')
outdir = package.replace('.', '/')
return [os.path.join(outdir, '{}.java'.format(name)) for name in names]
3 changes: 2 additions & 1 deletion tests/python/pants_test/backend/codegen/tasks/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,9 @@ python_tests(
name = 'jaxb_gen',
sources = ['test_jaxb_gen.py'],
dependencies = [
'src/python/pants/backend/codegen/tasks:jaxb_gen',
'src/python/pants/backend/codegen:plugin',
'src/python/pants/backend/codegen/targets:java',
'src/python/pants/backend/codegen/tasks:jaxb_gen',
'src/python/pants/backend/core:plugin',
'src/python/pants/util:contextutil',
'tests/python/pants_test/tasks:task_test_base',
Expand Down
64 changes: 24 additions & 40 deletions tests/python/pants_test/backend/codegen/tasks/test_jaxb_gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
from __future__ import (absolute_import, division, generators, nested_scopes, print_function,
unicode_literals, with_statement)

import os

from pants.backend.codegen.register import build_file_aliases as register_codegen
from pants.backend.codegen.targets.jaxb_library import JaxbLibrary
from pants.backend.codegen.tasks.jaxb_gen import JaxbGen
from pants.backend.core.register import build_file_aliases as register_core
from pants.util.contextutil import temporary_file
from pants_test.tasks.task_test_base import TaskTestBase


Expand All @@ -21,12 +23,6 @@ def task_type(cls):
def alias_groups(self):
return register_core().merge(register_codegen())

def assert_files(self, package, contents, *expected_files):
with temporary_file() as fp:
fp.write(contents)
fp.close()
self.assertEqual(set(expected_files), set(JaxbGen._sources_to_be_generated(package, fp.name)))

def create_schema(self, *component_names):
return ('<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">\n'
+ '\n'.join(self.create_complex_type(c) for c in component_names)
Expand All @@ -44,39 +40,6 @@ def create_complex_type(self, name):
</xsd:complexType>'''.format(name=name)
)

def test_plain(self):
self.assert_files(
'com.actual.package',
self.create_schema('ComplicatedVegetable', 'Orange', 'Apple', 'Aardvark'),
'com/actual/package/ObjectFactory.java',
'com/actual/package/ComplicatedVegetable.java',
'com/actual/package/Orange.java',
'com/actual/package/Aardvark.java',
'com/actual/package/Apple.java'
)

def test_slashes(self):
self.assert_files(
'com/actual/package',
self.create_schema('ComplicatedVegetable', 'Orange', 'Apple', 'Aardvark'),
'com/actual/package/ObjectFactory.java',
'com/actual/package/ComplicatedVegetable.java',
'com/actual/package/Orange.java',
'com/actual/package/Aardvark.java',
'com/actual/package/Apple.java'
)

def test_leadtail(self):
self.assert_files(
'/com/actual/package/',
self.create_schema('ComplicatedVegetable', 'Orange', 'Apple', 'Aardvark'),
'com/actual/package/ObjectFactory.java',
'com/actual/package/ComplicatedVegetable.java',
'com/actual/package/Orange.java',
'com/actual/package/Aardvark.java',
'com/actual/package/Apple.java'
)

def test_correct_package(self):
fix = JaxbGen._correct_package
self.assertEqual(fix('com.foo.bar'), 'com.foo.bar', 'Expected no change.')
Expand Down Expand Up @@ -114,3 +77,24 @@ def guess(path):
self.assertEqual(guess('pantsbuild/potato/Potato.java'),
'pantsbuild.potato',
'Failed with no prefix: {0}'.format(guess_history[-1]))

def test_simple(self):
self.set_options(use_nailgun=False)
self.create_file('foo/vegetable.xml', self.create_schema('Vegetable'))
jaxblib = self.make_target('foo:jaxblib', JaxbLibrary, sources=['vegetable.xml'])
context = self.context(target_roots=[jaxblib])
task = self.create_task(context)
task.execute()
files = []
for (dirpath, dirnames, filenames) in os.walk(task.workdir):
for filename in filenames:
if filename.endswith('.java'):
files.append(os.path.join(dirpath, filename))
self.assertEquals(sorted(['ObjectFactory.java', 'Vegetable.java']),
sorted([os.path.basename(f) for f in files]))

# Make sure there is no header with a timestamp in the generated file
for f in files:
with open(f) as jaxb_file:
contents = jaxb_file.read()
self.assertNotIn('// Generated on:', contents)

0 comments on commit 3e0da3f

Please sign in to comment.