mirror of https://github.com/apache/lucene.git
LUCENE-5257: Lock down centralized versioning of ivy dependencies
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1529243 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
ce83d40c67
commit
fa90270c4d
|
@ -68,6 +68,7 @@
|
|||
<fileset dir="lucene" includes="build.xml" />
|
||||
<fileset dir="solr" includes="build.xml" />
|
||||
</subant>
|
||||
<subant target="check-lib-versions" antfile="lucene/build.xml" inheritall="false" failonerror="true"/>
|
||||
</target>
|
||||
|
||||
<target name="-validate-source-patterns" unless="disable.source-patterns">
|
||||
|
|
|
@ -138,6 +138,9 @@ Build
|
|||
* LUCENE-5249: All Lucene/Solr modules should use the same dependency versions
|
||||
(Steve Rowe)
|
||||
|
||||
* LUCENE-5257: Lock down centralized versioning of ivy dependencies
|
||||
(Steve Rowe)
|
||||
|
||||
======================= Lucene 4.5.0 =======================
|
||||
|
||||
New features
|
||||
|
|
|
@ -169,6 +169,11 @@
|
|||
</license-check-macro>
|
||||
</target>
|
||||
|
||||
<target name="check-lib-versions" depends="compile-tools,resolve,load-custom-tasks"
|
||||
description="Verify that the '/org/name' keys in ivy-versions.properties are sorted lexically and are neither duplicates nor orphans, and that all dependencies in all ivy.xml files use rev="$${/org/name}" format.">
|
||||
<lib-versions-check-macro dir="${common.dir}/.." centralized.versions.file="${common.dir}/ivy-versions.properties"/>
|
||||
</target>
|
||||
|
||||
<target name="check-forbidden-apis" depends="compile-tools,compile-test,install-forbidden-apis,-forbidden-apis-classpath,-check-forbidden-jdk-apis,-check-forbidden-test-apis,-check-system-out" description="Check forbidden API calls in compiled class files"/>
|
||||
|
||||
<!-- TODO: Make the forbidden API checks per module! -->
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
# The /org/name keys in this file must be kept lexically sorted.
|
||||
# Blank lines, comment lines, and keys that aren't in /org/name format are ignored
|
||||
# when the lexical sort check is performed by the ant check-lib-versions target.
|
||||
|
||||
/cglib/cglib-nodep = 2.2
|
||||
/com.carrotsearch.randomizedtesting/junit4-ant = 2.0.10
|
||||
/com.carrotsearch.randomizedtesting/randomizedtesting-runner = 2.0.10
|
||||
|
||||
com.carrotsearch.randomizedtesting.version = 2.0.10
|
||||
/com.carrotsearch.randomizedtesting/junit4-ant = ${com.carrotsearch.randomizedtesting.version}
|
||||
/com.carrotsearch.randomizedtesting/randomizedtesting-runner = ${com.carrotsearch.randomizedtesting.version}
|
||||
|
||||
/com.carrotsearch/hppc = 0.5.2
|
||||
/com.cybozu.labs/langdetect = 1.1-20120112
|
||||
/com.drewnoakes/metadata-extractor = 2.6.2
|
||||
|
@ -43,80 +50,116 @@
|
|||
/org.apache.ant/ant = 1.8.2
|
||||
/org.apache.commons/commons-compress = 1.4.1
|
||||
/org.apache.derby/derby = 10.9.1.0
|
||||
hadoop.version = 2.0.5-alpha
|
||||
/org.apache.hadoop/hadoop-annotations = ${hadoop.version}
|
||||
/org.apache.hadoop/hadoop-auth = ${hadoop.version}
|
||||
/org.apache.hadoop/hadoop-common = ${hadoop.version}
|
||||
/org.apache.hadoop/hadoop-hdfs = ${hadoop.version}
|
||||
/org.apache.httpcomponents/httpclient = 4.2.3
|
||||
|
||||
org.apache.hadoop.version = 2.0.5-alpha
|
||||
/org.apache.hadoop/hadoop-annotations = ${org.apache.hadoop.version}
|
||||
/org.apache.hadoop/hadoop-auth = ${org.apache.hadoop.version}
|
||||
/org.apache.hadoop/hadoop-common = ${org.apache.hadoop.version}
|
||||
/org.apache.hadoop/hadoop-hdfs = ${org.apache.hadoop.version}
|
||||
|
||||
# The httpcore version is often different from the httpclient and httpmime versions,
|
||||
# so the httpcore version value should not share the same symbolic name with them.
|
||||
/org.apache.httpcomponents/httpclient = 4.2.6
|
||||
/org.apache.httpcomponents/httpcore = 4.2.2
|
||||
/org.apache.httpcomponents/httpcore = 4.2.5
|
||||
/org.apache.httpcomponents/httpmime = 4.2.6
|
||||
/org.apache.james/apache-mime4j-core = 0.7.2
|
||||
/org.apache.james/apache-mime4j-dom = 0.7.2
|
||||
|
||||
org.apache.james.apache.mime4j = 0.7.2
|
||||
/org.apache.james/apache-mime4j-core = ${org.apache.james.apache.mime4j}
|
||||
/org.apache.james/apache-mime4j-dom = ${org.apache.james.apache.mime4j}
|
||||
|
||||
/org.apache.mahout/mahout-collections = 1.0
|
||||
/org.apache.mahout/mahout-math = 0.6
|
||||
/org.apache.pdfbox/fontbox = 1.8.1
|
||||
/org.apache.pdfbox/jempbox = 1.8.1
|
||||
/org.apache.pdfbox/pdfbox = 1.8.1
|
||||
/org.apache.poi/poi = 3.9
|
||||
/org.apache.poi/poi-ooxml = 3.9
|
||||
/org.apache.poi/poi-ooxml-schemas = 3.9
|
||||
/org.apache.poi/poi-scratchpad = 3.9
|
||||
/org.apache.tika/tika-core = 1.4
|
||||
/org.apache.tika/tika-parsers = 1.4
|
||||
/org.apache.uima/AlchemyAPIAnnotator = 2.3.1
|
||||
/org.apache.uima/OpenCalaisAnnotator = 2.3.1
|
||||
/org.apache.uima/Tagger = 2.3.1
|
||||
/org.apache.uima/WhitespaceTokenizer = 2.3.1
|
||||
/org.apache.uima/uimaj-core = 2.3.1
|
||||
|
||||
org.apache.pdfbox.version = 1.8.1
|
||||
/org.apache.pdfbox/fontbox = ${org.apache.pdfbox.version}
|
||||
/org.apache.pdfbox/jempbox = ${org.apache.pdfbox.version}
|
||||
/org.apache.pdfbox/pdfbox = ${org.apache.pdfbox.version}
|
||||
|
||||
org.apache.poi.version = 3.9
|
||||
/org.apache.poi/poi = ${org.apache.poi.version}
|
||||
/org.apache.poi/poi-ooxml = ${org.apache.poi.version}
|
||||
/org.apache.poi/poi-ooxml-schemas = ${org.apache.poi.version}
|
||||
/org.apache.poi/poi-scratchpad = ${org.apache.poi.version}
|
||||
|
||||
org.apache.tika.version = 1.4
|
||||
/org.apache.tika/tika-core = ${org.apache.tika.version}
|
||||
/org.apache.tika/tika-parsers = ${org.apache.tika.version}
|
||||
|
||||
org.apache.uima.version = 2.3.1
|
||||
/org.apache.uima/AlchemyAPIAnnotator = ${org.apache.uima.version}
|
||||
/org.apache.uima/OpenCalaisAnnotator = ${org.apache.uima.version}
|
||||
/org.apache.uima/Tagger = ${org.apache.uima.version}
|
||||
/org.apache.uima/WhitespaceTokenizer = ${org.apache.uima.version}
|
||||
/org.apache.uima/uimaj-core = ${org.apache.uima.version}
|
||||
|
||||
/org.apache.velocity/velocity = 1.7
|
||||
/org.apache.velocity/velocity-tools = 2.0
|
||||
/org.apache.xmlbeans/xmlbeans = 2.3.0
|
||||
/org.apache.zookeeper/zookeeper = 3.4.5
|
||||
/org.bouncycastle/bcmail-jdk15 = 1.45
|
||||
/org.bouncycastle/bcprov-jdk15 = 1.45
|
||||
|
||||
org.bouncycastle.version = 1.45
|
||||
/org.bouncycastle/bcmail-jdk15 = ${org.bouncycastle.version}
|
||||
/org.bouncycastle/bcprov-jdk15 = ${org.bouncycastle.version}
|
||||
|
||||
/org.carrot2.attributes/attributes-binder = 1.2.0
|
||||
/org.carrot2/carrot2-mini = 3.8.0
|
||||
/org.carrot2/morfologik-fsa = 1.7.1
|
||||
/org.carrot2/morfologik-polish = 1.7.1
|
||||
/org.carrot2/morfologik-stemming = 1.7.1
|
||||
|
||||
org.carrot2.morfologik.version = 1.7.1
|
||||
/org.carrot2/morfologik-fsa = ${org.carrot2.morfologik.version}
|
||||
/org.carrot2/morfologik-polish = ${org.carrot2.morfologik.version}
|
||||
/org.carrot2/morfologik-stemming = ${org.carrot2.morfologik.version}
|
||||
|
||||
/org.ccil.cowan.tagsoup/tagsoup = 1.2.1
|
||||
/org.codehaus.jackson/jackson-core-asl = 1.7.4
|
||||
/org.codehaus.jackson/jackson-mapper-asl = 1.7.4
|
||||
|
||||
org.codehaus.jackson.version = 1.7.4
|
||||
/org.codehaus.jackson/jackson-core-asl = ${org.codehaus.jackson.version}
|
||||
/org.codehaus.jackson/jackson-mapper-asl = ${org.codehaus.jackson.version}
|
||||
|
||||
/org.codehaus.woodstox/wstx-asl = 3.2.7
|
||||
/org.easymock/easymock = 3.0
|
||||
/org.eclipse.jetty.orbit/javax.servlet = 3.0.0.v201112011016
|
||||
jetty.version = 8.1.10.v20130312
|
||||
/org.eclipse.jetty/jetty-continuation = ${jetty.version}
|
||||
/org.eclipse.jetty/jetty-deploy = ${jetty.version}
|
||||
/org.eclipse.jetty/jetty-http = ${jetty.version}
|
||||
/org.eclipse.jetty/jetty-io = ${jetty.version}
|
||||
/org.eclipse.jetty/jetty-jmx = ${jetty.version}
|
||||
/org.eclipse.jetty/jetty-security = ${jetty.version}
|
||||
/org.eclipse.jetty/jetty-server = ${jetty.version}
|
||||
/org.eclipse.jetty/jetty-servlet = ${jetty.version}
|
||||
/org.eclipse.jetty/jetty-start = ${jetty.version}
|
||||
/org.eclipse.jetty/jetty-util = ${jetty.version}
|
||||
/org.eclipse.jetty/jetty-webapp = ${jetty.version}
|
||||
/org.eclipse.jetty/jetty-xml = ${jetty.version}
|
||||
/org.gagravarr/vorbis-java-core = 0.1
|
||||
/org.gagravarr/vorbis-java-tika = 0.1
|
||||
/org.mortbay.jetty/jetty = 6.1.26
|
||||
/org.mortbay.jetty/jetty-util = 6.1.26
|
||||
|
||||
org.eclipse.jetty.version = 8.1.10.v20130312
|
||||
/org.eclipse.jetty/jetty-continuation = ${org.eclipse.jetty.version}
|
||||
/org.eclipse.jetty/jetty-deploy = ${org.eclipse.jetty.version}
|
||||
/org.eclipse.jetty/jetty-http = ${org.eclipse.jetty.version}
|
||||
/org.eclipse.jetty/jetty-io = ${org.eclipse.jetty.version}
|
||||
/org.eclipse.jetty/jetty-jmx = ${org.eclipse.jetty.version}
|
||||
/org.eclipse.jetty/jetty-security = ${org.eclipse.jetty.version}
|
||||
/org.eclipse.jetty/jetty-server = ${org.eclipse.jetty.version}
|
||||
/org.eclipse.jetty/jetty-servlet = ${org.eclipse.jetty.version}
|
||||
/org.eclipse.jetty/jetty-start = ${org.eclipse.jetty.version}
|
||||
/org.eclipse.jetty/jetty-util = ${org.eclipse.jetty.version}
|
||||
/org.eclipse.jetty/jetty-webapp = ${org.eclipse.jetty.version}
|
||||
/org.eclipse.jetty/jetty-xml = ${org.eclipse.jetty.version}
|
||||
|
||||
org.gagravarr.vorbis.java.version = 0.1
|
||||
/org.gagravarr/vorbis-java-core = ${org.gagravarr.vorbis.java.version}
|
||||
/org.gagravarr/vorbis-java-tika = ${org.gagravarr.vorbis.java.version}
|
||||
|
||||
org.mortbay.jetty.version = 6.1.26
|
||||
/org.mortbay.jetty/jetty = ${org.mortbay.jetty.version}
|
||||
/org.mortbay.jetty/jetty-util = ${org.mortbay.jetty.version}
|
||||
|
||||
/org.noggit/noggit = 0.5
|
||||
/org.objenesis/objenesis = 1.2
|
||||
/org.ow2.asm/asm = 4.1
|
||||
/org.ow2.asm/asm-commons = 4.1
|
||||
/org.restlet.jee/org.restlet = 2.1.1
|
||||
/org.restlet.jee/org.restlet.ext.servlet = 2.1.1
|
||||
|
||||
org.ow2.asm.version = 4.1
|
||||
/org.ow2.asm/asm = ${org.ow2.asm.version}
|
||||
/org.ow2.asm/asm-commons = ${org.ow2.asm.version}
|
||||
|
||||
org.restlet.jee.version = 2.1.1
|
||||
/org.restlet.jee/org.restlet = ${org.restlet.jee.version}
|
||||
/org.restlet.jee/org.restlet.ext.servlet = ${org.restlet.jee.version}
|
||||
|
||||
/org.simpleframework/simple-xml = 2.7
|
||||
/org.slf4j/jcl-over-slf4j = 1.6.6
|
||||
/org.slf4j/jul-to-slf4j = 1.6.6
|
||||
/org.slf4j/slf4j-api = 1.6.6
|
||||
/org.slf4j/slf4j-log4j12 = 1.6.6
|
||||
|
||||
org.slf4j.version = 1.6.6
|
||||
/org.slf4j/jcl-over-slf4j = ${org.slf4j.version}
|
||||
/org.slf4j/jul-to-slf4j = ${org.slf4j.version}
|
||||
/org.slf4j/slf4j-api = ${org.slf4j.version}
|
||||
/org.slf4j/slf4j-log4j12 = ${org.slf4j.version}
|
||||
|
||||
/org.tukaani/xz = 1.0
|
||||
/rome/rome = 0.9
|
||||
/xerces/xercesImpl = 2.9.1
|
||||
|
||||
|
|
|
@ -84,4 +84,29 @@
|
|||
</licenses>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
|
||||
<macrodef name="lib-versions-check-macro">
|
||||
<attribute name="dir"/>
|
||||
<attribute name="centralized.versions.file"/>
|
||||
<sequential>
|
||||
<!--
|
||||
Verify that the '/org/name' keys in ivy-versions.properties are sorted
|
||||
lexically and are neither duplicates nor orphans, and that all
|
||||
dependencies in all ivy.xml files use rev="${/org/name}" format.
|
||||
-->
|
||||
<echo>Lib versions check under: @{dir}</echo>
|
||||
<libversions centralizedVersionsFile="@{centralized.versions.file}">
|
||||
<fileset dir="@{dir}">
|
||||
<include name="**/ivy.xml" />
|
||||
<!-- Speed up scanning a bit. -->
|
||||
<exclude name="**/.git/**" />
|
||||
<exclude name="**/.svn/**" />
|
||||
<exclude name="**/bin/**" />
|
||||
<exclude name="**/build/**" />
|
||||
<exclude name="**/dist/**" />
|
||||
<exclude name="**/src/**" />
|
||||
</fileset>
|
||||
</libversions>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
</project>
|
||||
|
|
|
@ -18,4 +18,7 @@
|
|||
<taskdef
|
||||
name="licenses"
|
||||
classname="org.apache.lucene.validation.LicenseCheckTask" />
|
||||
<taskdef
|
||||
name="libversions"
|
||||
classname="org.apache.lucene.validation.LibVersionsCheckTask" />
|
||||
</antlib>
|
||||
|
|
|
@ -0,0 +1,385 @@
|
|||
package org.apache.lucene.validation;
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import org.apache.tools.ant.BuildException;
|
||||
import org.apache.tools.ant.Project;
|
||||
import org.apache.tools.ant.Task;
|
||||
import org.apache.tools.ant.types.Resource;
|
||||
import org.apache.tools.ant.types.ResourceCollection;
|
||||
import org.apache.tools.ant.types.resources.FileResource;
|
||||
import org.apache.tools.ant.types.resources.Resources;
|
||||
import org.apache.tools.ant.util.FileNameMapper;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
import org.xml.sax.helpers.XMLReaderFactory;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CodingErrorAction;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* An Ant task to verify that the '/org/name' keys in ivy-versions.properties
|
||||
* are sorted lexically and are neither duplicates nor orphans, and that all
|
||||
* dependencies in all ivy.xml files use rev="${/org/name}" format.
|
||||
*/
|
||||
public class LibVersionsCheckTask extends Task {
|
||||
|
||||
private static final String IVY_XML_FILENAME = "ivy.xml";
|
||||
private static final Pattern COORDINATE_KEY_PATTERN = Pattern.compile("(/[^/ \t\f]+/[^=:/ \t\f]+).*");
|
||||
private static final Pattern BLANK_OR_COMMENT_LINE_PATTERN = Pattern.compile("[ \t\f]*(?:[#!].*)?");
|
||||
private static final Pattern TRAILING_BACKSLASH_PATTERN = Pattern.compile("[^\\\\]*(\\\\+)$");
|
||||
private static final Pattern LEADING_WHITESPACE_PATTERN = Pattern.compile("[ \t\f]+(.*)");
|
||||
private static final Pattern WHITESPACE_GOODSTUFF_WHITESPACE_BACKSLASH_PATTERN
|
||||
= Pattern.compile("[ \t\f]*(.*?)(?:(?<!\\\\)[ \t\f]*)?\\\\");
|
||||
private static final Pattern TRAILING_WHITESPACE_BACKSLASH_PATTERN
|
||||
= Pattern.compile("(.*?)(?:(?<!\\\\)[ \t\f]*)?\\\\");
|
||||
|
||||
/**
|
||||
* All ivy.xml files to check.
|
||||
*/
|
||||
private Resources ivyXmlResources = new Resources();
|
||||
|
||||
/**
|
||||
* Centralized Ivy versions properties file
|
||||
*/
|
||||
private File centralizedVersionsFile;
|
||||
|
||||
/**
|
||||
* License file mapper.
|
||||
*/
|
||||
private FileNameMapper licenseMapper;
|
||||
|
||||
/**
|
||||
* A logging level associated with verbose logging.
|
||||
*/
|
||||
private int verboseLevel = Project.MSG_VERBOSE;
|
||||
|
||||
/**
|
||||
* Failure flag.
|
||||
*/
|
||||
private boolean failures;
|
||||
|
||||
/**
|
||||
* All /org/name version keys found in ivy-versions.properties, and whether they
|
||||
* are referenced in any ivy.xml file.
|
||||
*/
|
||||
private Map<String,Boolean> referencedCoordinateKeys = new LinkedHashMap<String,Boolean>();
|
||||
|
||||
/**
|
||||
* Adds a set of ivy.xml resources to check.
|
||||
*/
|
||||
public void add(ResourceCollection rc) {
|
||||
ivyXmlResources.add(rc);
|
||||
}
|
||||
|
||||
public void setVerbose(boolean verbose) {
|
||||
verboseLevel = (verbose ? Project.MSG_INFO : Project.MSG_VERBOSE);
|
||||
}
|
||||
|
||||
public void setCentralizedVersionsFile(File file) {
|
||||
centralizedVersionsFile = file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the task.
|
||||
*/
|
||||
@Override
|
||||
public void execute() throws BuildException {
|
||||
log("Starting scan.", verboseLevel);
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
int errors = verifySortedCentralizedVersionsFile() ? 0 : 1;
|
||||
int checked = 0;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Iterator<Resource> iter = (Iterator<Resource>)ivyXmlResources.iterator();
|
||||
while (iter.hasNext()) {
|
||||
final Resource resource = iter.next();
|
||||
if ( ! resource.isExists()) {
|
||||
throw new BuildException("Resource does not exist: " + resource.getName());
|
||||
}
|
||||
if ( ! (resource instanceof FileResource)) {
|
||||
throw new BuildException("Only filesystem resources are supported: "
|
||||
+ resource.getName() + ", was: " + resource.getClass().getName());
|
||||
}
|
||||
|
||||
File ivyXmlFile = ((FileResource)resource).getFile();
|
||||
try {
|
||||
if ( ! checkIvyXmlFile(ivyXmlFile) ) {
|
||||
failures = true;
|
||||
errors++;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new BuildException("Exception reading file " + ivyXmlFile.getPath(), e);
|
||||
}
|
||||
checked++;
|
||||
}
|
||||
log("Checking for orphans in " + centralizedVersionsFile.getName(), verboseLevel);
|
||||
for (Map.Entry<String,Boolean> entry : referencedCoordinateKeys.entrySet()) {
|
||||
String coordinateKey = entry.getKey();
|
||||
boolean isReferenced = entry.getValue();
|
||||
if ( ! isReferenced) {
|
||||
log("ORPHAN coordinate key '" + coordinateKey + "' in " + centralizedVersionsFile.getName()
|
||||
+ " is not found in any " + IVY_XML_FILENAME + " file.",
|
||||
Project.MSG_ERR);
|
||||
failures = true;
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
|
||||
log(String.format(Locale.ROOT, "Checked that %s has lexically sorted "
|
||||
+ "'/org/name' keys and no duplicates or orphans, and scanned %d %s "
|
||||
+ "file(s) for rev=\"${/org/name}\" format (in %.2fs.), %d error(s).",
|
||||
centralizedVersionsFile.getName(), checked, IVY_XML_FILENAME,
|
||||
(System.currentTimeMillis() - start) / 1000.0, errors),
|
||||
errors > 0 ? Project.MSG_ERR : Project.MSG_INFO);
|
||||
|
||||
if (failures) {
|
||||
throw new BuildException("Lib versions check failed. Check the logs.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the "/org/name" coordinate keys in ivy-versions.properties
|
||||
* are lexically sorted and are not duplicates.
|
||||
*/
|
||||
private boolean verifySortedCentralizedVersionsFile() {
|
||||
log("Checking for lexically sorted non-duplicated '/org/name' keys in: " + centralizedVersionsFile, verboseLevel);
|
||||
final InputStream stream;
|
||||
try {
|
||||
stream = new FileInputStream(centralizedVersionsFile);
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new BuildException("Centralized versions file does not exist: "
|
||||
+ centralizedVersionsFile.getPath());
|
||||
}
|
||||
// Properties files are encoded as Latin-1
|
||||
final Reader reader = new InputStreamReader(stream, Charset.forName("ISO-8859-1"));
|
||||
final BufferedReader bufferedReader = new BufferedReader(reader);
|
||||
|
||||
String line = null;
|
||||
String currentKey = null;
|
||||
String previousKey = null;
|
||||
try {
|
||||
while (null != (line = readLogicalPropertiesLine(bufferedReader))) {
|
||||
final Matcher keyMatcher = COORDINATE_KEY_PATTERN.matcher(line);
|
||||
if ( ! keyMatcher.matches()) {
|
||||
continue; // Ignore keys that don't look like "/org/name"
|
||||
}
|
||||
currentKey = keyMatcher.group(1);
|
||||
if (null != previousKey) {
|
||||
int comparison = currentKey.compareTo(previousKey);
|
||||
if (0 == comparison) {
|
||||
log("DUPLICATE coordinate key '" + currentKey + "' in " + centralizedVersionsFile.getName(),
|
||||
Project.MSG_ERR);
|
||||
failures = true;
|
||||
} else if (comparison < 0) {
|
||||
log("OUT-OF-ORDER coordinate key '" + currentKey + "' in " + centralizedVersionsFile.getName(),
|
||||
Project.MSG_ERR);
|
||||
failures = true;
|
||||
}
|
||||
}
|
||||
referencedCoordinateKeys.put(currentKey, false);
|
||||
previousKey = currentKey;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new BuildException("Exception reading centralized versions file: "
|
||||
+ centralizedVersionsFile.getPath(), e);
|
||||
} finally {
|
||||
try { reader.close(); } catch (IOException e) { }
|
||||
}
|
||||
return ! failures;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds up logical {@link java.util.Properties} lines, composed of one non-blank,
|
||||
* non-comment initial line, either:
|
||||
*
|
||||
* 1. without a non-escaped trailing slash; or
|
||||
* 2. with a non-escaped trailing slash, followed by
|
||||
* zero or more lines with a non-escaped trailing slash, followed by
|
||||
* one or more lines without a non-escaped trailing slash
|
||||
*
|
||||
* All leading non-escaped whitespace and trailing non-escaped whitespace +
|
||||
* non-escaped slash are trimmed from each line before concatenating.
|
||||
*
|
||||
* After composing the logical line, escaped characters are un-escaped.
|
||||
*
|
||||
* null is returned if there are no lines left to read.
|
||||
*/
|
||||
private String readLogicalPropertiesLine(BufferedReader reader) throws IOException {
|
||||
final StringBuilder logicalLine = new StringBuilder();
|
||||
String line;
|
||||
do {
|
||||
line = reader.readLine();
|
||||
if (null == line) {
|
||||
return null;
|
||||
}
|
||||
} while (BLANK_OR_COMMENT_LINE_PATTERN.matcher(line).matches());
|
||||
|
||||
Matcher backslashMatcher = TRAILING_BACKSLASH_PATTERN.matcher(line);
|
||||
// Check for a non-escaped backslash
|
||||
if (backslashMatcher.find() && 1 == (backslashMatcher.group(1).length() % 2)) {
|
||||
final Matcher firstLineMatcher = TRAILING_WHITESPACE_BACKSLASH_PATTERN.matcher(line);
|
||||
if (firstLineMatcher.matches()) {
|
||||
logicalLine.append(firstLineMatcher.group(1)); // trim trailing backslash and any preceding whitespace
|
||||
}
|
||||
line = reader.readLine();
|
||||
while (null != line
|
||||
&& (backslashMatcher = TRAILING_BACKSLASH_PATTERN.matcher(line)).find()
|
||||
&& 1 == (backslashMatcher.group(1).length() % 2)) {
|
||||
// Trim leading whitespace, the trailing backslash and any preceding whitespace
|
||||
final Matcher goodStuffMatcher = WHITESPACE_GOODSTUFF_WHITESPACE_BACKSLASH_PATTERN.matcher(line);
|
||||
if (goodStuffMatcher.matches()) {
|
||||
logicalLine.append(goodStuffMatcher.group(1));
|
||||
}
|
||||
line = reader.readLine();
|
||||
}
|
||||
if (null != line) {
|
||||
// line can't have a non-escaped trailing backslash
|
||||
final Matcher leadingWhitespaceMatcher = LEADING_WHITESPACE_PATTERN.matcher(line);
|
||||
if (leadingWhitespaceMatcher.matches()) {
|
||||
line = leadingWhitespaceMatcher.group(1); // trim leading whitespace
|
||||
}
|
||||
logicalLine.append(line);
|
||||
}
|
||||
} else {
|
||||
logicalLine.append(line);
|
||||
}
|
||||
// trim non-escaped leading whitespace
|
||||
final Matcher leadingWhitespaceMatcher = LEADING_WHITESPACE_PATTERN.matcher(logicalLine);
|
||||
final CharSequence leadingWhitespaceStripped = leadingWhitespaceMatcher.matches()
|
||||
? leadingWhitespaceMatcher.group(1)
|
||||
: logicalLine;
|
||||
|
||||
// unescape all chars in the logical line
|
||||
StringBuilder output = new StringBuilder();
|
||||
final int numChars = leadingWhitespaceStripped.length();
|
||||
for (int pos = 0 ; pos < numChars - 1 ; ++pos) {
|
||||
char ch = leadingWhitespaceStripped.charAt(pos);
|
||||
if (ch == '\\') {
|
||||
ch = leadingWhitespaceStripped.charAt(++pos);
|
||||
}
|
||||
output.append(ch);
|
||||
}
|
||||
if (numChars > 0) {
|
||||
output.append(leadingWhitespaceStripped.charAt(numChars - 1));
|
||||
}
|
||||
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a single ivy.xml file for dependencies' versions in rev="${/org/name}"
|
||||
* format. Returns false if problems are found, true otherwise.
|
||||
*/
|
||||
private boolean checkIvyXmlFile(File ivyXmlFile)
|
||||
throws ParserConfigurationException, SAXException, IOException {
|
||||
log("Scanning: " + ivyXmlFile.getPath(), verboseLevel);
|
||||
XMLReader xmlReader = XMLReaderFactory.createXMLReader();
|
||||
DependencyRevChecker revChecker = new DependencyRevChecker(ivyXmlFile);
|
||||
xmlReader.setContentHandler(revChecker);
|
||||
xmlReader.setErrorHandler(revChecker);
|
||||
// To work around a bug in XERCES (XERCESJ-1257), we assume the XML is always UTF8, so we simply provide reader.
|
||||
CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder()
|
||||
.onMalformedInput(CodingErrorAction.REPORT)
|
||||
.onUnmappableCharacter(CodingErrorAction.REPORT);
|
||||
InputStream stream = new FileInputStream(ivyXmlFile);
|
||||
xmlReader.parse(new InputSource(new BufferedReader(new InputStreamReader(stream, decoder))));
|
||||
return ! revChecker.fail;
|
||||
}
|
||||
|
||||
private class DependencyRevChecker extends DefaultHandler {
|
||||
private final File ivyXmlFile;
|
||||
private final Stack<String> tags = new Stack<String>();
|
||||
|
||||
public boolean fail = false;
|
||||
|
||||
public DependencyRevChecker(File ivyXmlFile) {
|
||||
this.ivyXmlFile = ivyXmlFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
||||
if (localName.equals("dependency") && insideDependenciesTag()) {
|
||||
String org = attributes.getValue("org");
|
||||
boolean foundAllAttributes = true;
|
||||
if (null == org) {
|
||||
log("MISSING 'org' attribute on <dependency> in " + ivyXmlFile.getPath(), Project.MSG_ERR);
|
||||
fail = true;
|
||||
foundAllAttributes = false;
|
||||
}
|
||||
String name = attributes.getValue("name");
|
||||
if (null == name) {
|
||||
log("MISSING 'name' attribute on <dependency> in " + ivyXmlFile.getPath(), Project.MSG_ERR);
|
||||
fail = true;
|
||||
foundAllAttributes = false;
|
||||
}
|
||||
String rev = attributes.getValue("rev");
|
||||
if (null == rev) {
|
||||
log("MISSING 'rev' attribute on <dependency> in " + ivyXmlFile.getPath(), Project.MSG_ERR);
|
||||
fail = true;
|
||||
foundAllAttributes = false;
|
||||
}
|
||||
if (foundAllAttributes) {
|
||||
String coordinateKey = "/" + org + '/' + name;
|
||||
String expectedRev = "${" + coordinateKey + '}';
|
||||
if ( ! rev.equals(expectedRev)) {
|
||||
log("BAD <dependency> 'rev' attribute value '" + rev + "' - expected '" + expectedRev + "'"
|
||||
+ " in " + ivyXmlFile.getPath(), Project.MSG_ERR);
|
||||
fail = true;
|
||||
}
|
||||
if ( ! referencedCoordinateKeys.containsKey(coordinateKey)) {
|
||||
log("MISSING key '" + coordinateKey + "' in " + centralizedVersionsFile.getPath(), Project.MSG_ERR);
|
||||
fail = true;
|
||||
}
|
||||
referencedCoordinateKeys.put(coordinateKey, true);
|
||||
}
|
||||
}
|
||||
tags.push(localName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endElement (String uri, String localName, String qName) throws SAXException {
|
||||
tags.pop();
|
||||
}
|
||||
|
||||
private boolean insideDependenciesTag() {
|
||||
return tags.size() == 2 && tags.get(0).equals("ivy-module") && tags.get(1).equals("dependencies");
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue