diff options
Diffstat (limited to 'build/src/main/java./aspectj/internal/tools/ant/taskdefs/Checklics.java')
-rw-r--r-- | build/src/main/java./aspectj/internal/tools/ant/taskdefs/Checklics.java | 676 |
1 files changed, 676 insertions, 0 deletions
diff --git a/build/src/main/java./aspectj/internal/tools/ant/taskdefs/Checklics.java b/build/src/main/java./aspectj/internal/tools/ant/taskdefs/Checklics.java new file mode 100644 index 000000000..904ba4656 --- /dev/null +++ b/build/src/main/java./aspectj/internal/tools/ant/taskdefs/Checklics.java @@ -0,0 +1,676 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + +package org.aspectj.internal.tools.ant.taskdefs; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.taskdefs.MatchingTask; +import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.types.Reference; + +/** + * Check that included .java files contain license and copyright strings for MPL 1.0 (default), Apache, or CPL. Use list="true" to + * get a list of known license variants {license}-{copyrightHolder} todo reimplement with regexp and jdiff FileLine utilities + */ +public class Checklics extends MatchingTask { + /* + * This does not enforce that copyrights are correct/current, only that they exist. E.g., the default behavior requires MPL but + * permits either Xerox or PARC copyright holders and any valid year. + */ + public static final String MPL_TAG = "mpl"; + public static final String APACHE_TAG = "apache"; + public static final String CPL_IBM_PARC_TAG = "cpl-ibm|parc"; + public static final String CPL_IBM_TAG = "cpl-ibm"; + public static final String MPL_XEROX_PARC_TAG = "mpl-parc|xerox"; + public static final String MPL_ONLY_TAG = "mpl-only"; + public static final String MPL_PARC_TAG = "mpl-parc"; + public static final String PARC_COPYRIGHT_TAG = "parc-copy"; + public static final String CPL_IBM_PARC_XEROX_TAG = "cpl-ibm|parc|xerox"; + public static final String CPL_IBM_PARC_XEROX_OTHERS_TAG = "cpl-ibm|parc|xerox|others"; + public static final String EPL_CPL_IBM_PARC_XEROX_OTHERS_TAG = "epl-cpl-ibm|parc|xerox|vmware|others"; + public static final String DEFAULT = EPL_CPL_IBM_PARC_XEROX_OTHERS_TAG; + + static final Map<String,License> LICENSES; // unmodifiable Map + + static { + final String CONTRIBUTORS = "Contributors"; + final String XEROX = "Xerox"; + final String PARC = "Palo Alto Research Center"; + final String APACHE = "The Apache Software Foundation"; + final String IBM = "IBM"; + final String VMWARE = "VMware"; + final String IBM_LONG = "International Business Machines"; + final String LIC_APL = "Apache Software Foundation (http://www.apache.org/)"; + final String LIC_MPL = "http://aspectj.org/MPL/"; + final String LIC_CPL = "Eclipse Public License"; + final String LIC_ECPL = " Public License"; + License APL = new License(APACHE_TAG, LIC_APL, APACHE); + License MPL = new License(MPL_TAG, LIC_MPL, XEROX); + License MPL_XEROX_PARC = new License(DEFAULT, LIC_MPL, XEROX, PARC); + License CPL_IBM_PARC = new License(CPL_IBM_PARC_TAG, LIC_CPL, new String[] { IBM_LONG, IBM, PARC }); + License CPL_IBM_PARC_XEROX = new License(CPL_IBM_PARC_XEROX_TAG, LIC_CPL, new String[] { IBM_LONG, IBM, PARC, XEROX }); + + License CPL_IBM_PARC_XEROX_OTHERS = new License(CPL_IBM_PARC_XEROX_OTHERS_TAG, LIC_CPL, new String[] { IBM_LONG, IBM, PARC, + XEROX, CONTRIBUTORS }); + License EPL_CPL_IBM_PARC_XEROX_OTHERS = new License(EPL_CPL_IBM_PARC_XEROX_OTHERS_TAG, LIC_ECPL, new String[] { IBM_LONG, + IBM, PARC, XEROX, VMWARE, CONTRIBUTORS }); + License CPL_IBM = new License(CPL_IBM_TAG, LIC_CPL, IBM, IBM_LONG); + License MPL_ONLY = new License(MPL_ONLY_TAG, LIC_MPL); + License MPL_PARC = new License(MPL_PARC_TAG, LIC_MPL, PARC); + License PARC_COPYRIGHT = new License(PARC_COPYRIGHT_TAG, null, PARC); + LICENSES = new Hashtable<String,License>(); + LICENSES.put(APL.tag, APL); + LICENSES.put(MPL.tag, MPL); + LICENSES.put(MPL_PARC.tag, MPL_PARC); + LICENSES.put(MPL_XEROX_PARC.tag, MPL_XEROX_PARC); + LICENSES.put(CPL_IBM_PARC.tag, CPL_IBM_PARC); + LICENSES.put(MPL_ONLY.tag, MPL_ONLY); + LICENSES.put(CPL_IBM.tag, CPL_IBM); + LICENSES.put(PARC_COPYRIGHT.tag, PARC_COPYRIGHT); + LICENSES.put(CPL_IBM_PARC_XEROX.tag, CPL_IBM_PARC_XEROX); + LICENSES.put(CPL_IBM_PARC_XEROX_OTHERS.tag, CPL_IBM_PARC_XEROX_OTHERS); + LICENSES.put(EPL_CPL_IBM_PARC_XEROX_OTHERS.tag, EPL_CPL_IBM_PARC_XEROX_OTHERS); + } + + /** @param args String[] { < sourcepath > {, < licenseTag > } } */ + public static void main(String[] args) { + switch (args.length) { + case 1: + runDirect(args[0], null, false); + break; + case 2: + runDirect(args[0], args[1], false); + break; + default: + String options = "{replace-headers|get-years|list|{licenseTag}}"; + System.err.println("java {me} sourcepath " + options); + break; + } + } + + /** + * Run the license check directly + * + * @param sourcepaths String[] of paths to source directories + * @param license the String tag for the license, if any + * @param failonerror boolean flag to pass to Checklics + * @throws IllegalArgumentException if sourcepaths is empty + * @return total number of failed licenses + */ + public static int runDirect(String sourcepath, String license, boolean failonerror) { + if ((null == sourcepath) || (1 > sourcepath.length())) { + throw new IllegalArgumentException("bad sourcepath: " + sourcepath); + } + Checklics me = new Checklics(); + Project p = new Project(); + p.setName("direct interface to Checklics"); + p.setBasedir("."); + me.setProject(p); + me.setFailOnError(failonerror); + me.setSourcepath(new Path(p, sourcepath)); + if (null != license) { + if ("replace-headers".equals(license)) { + me.setReplaceheaders(true); + } else if ("get-years".equals(license)) { + me.setGetYears(true); + } else if ("list".equals(license)) { + me.setList(true); + } else { + me.setLicense(license); + } + } + me.execute(); + return me.failed; + } + + private Path sourcepath; + private License license; + private boolean list; + private String streamTag; + private boolean failOnError; + private boolean getYears; + private boolean replaceHeaders; + private int failed; + private int passed; + + private boolean printDirectories; + + /** @param list if true, don't run but list known license tags */ + public void setList(boolean list) { + this.list = list; + } + + public void setPrintDirectories(boolean print) { + printDirectories = print; + } + + /** + * When failOnError is true, if any file failed, throw BuildException listing number of files that file failed to pass license + * check + * + * @param fail if true, report errors by throwing BuildException + */ + public void setFailOnError(boolean fail) { + this.failOnError = fail; + } + + /** @param tl mpl | apache | cpl */ + public void setLicense(String tl) { + License input = LICENSES.get(tl); + if (null == input) { + throw new BuildException("no license known for " + tl); + } + license = input; + } + + public void setSourcepath(Path path) { + if (sourcepath == null) { + sourcepath = path; + } else { + sourcepath.append(path); + } + } + + public Path createSourcepath() { + return sourcepath == null ? (sourcepath = new Path(project)) : sourcepath.createPath(); + } + + public void setSourcepathRef(Reference id) { + createSourcepath().setRefid(id); + } + + /** @param out "out" or "err" */ + public void setOutputStream(String out) { + this.streamTag = out; + } + + public void setReplaceheaders(boolean replaceHeaders) { + this.replaceHeaders = replaceHeaders; + } + + public void setGetYears(boolean getYears) { + this.getYears = getYears; + } + + /** list known licenses or check source tree */ + @Override + public void execute() throws BuildException { + if (list) { + list(); + } else if (replaceHeaders) { + replaceHeaders(); + } else if (getYears) { + getYears(); + } else { + checkLicenses(); + } + } + + private PrintStream getOut() { + return ("err".equals(streamTag) ? System.err : System.out); + } + + interface FileVisitor { + void visit(File file); + } + + /** visit all .java files in all directories... */ + private void visitAll(FileVisitor visitor) { + // List filelist = new ArrayList(); + String[] dirs = sourcepath.list(); + for (int i = 0; i < dirs.length; i++) { + File dir = project.resolveFile(dirs[i]); + String[] files = getDirectoryScanner(dir).getIncludedFiles(); + for (int j = 0; j < files.length; j++) { + File file = new File(dir, files[j]); + String path = file.getPath(); + if (path.endsWith(".java")) { + visitor.visit(file); + } + } + } + } + + private void replaceHeaders() { + class YearVisitor implements FileVisitor { + @Override + public void visit(File file) { + HeaderInfo info = Header.checkFile(file); + if (!Header.replaceHeader(file, info)) { + throw new BuildException("failed to replace header for " + file + " using " + info); + } + } + } + visitAll(new YearVisitor()); + } + + private void getYears() { + final PrintStream out = getOut(); + class YearVisitor implements FileVisitor { + @Override + public void visit(File file) { + HeaderInfo info = Header.checkFile(file); + out.println(info.toString()); + } + } + visitAll(new YearVisitor()); + } + + private void checkLicenses() throws BuildException { + if (null == license) { + setLicense(DEFAULT); + } + final License license = this.license; // being paranoid... + if (null == license) { + throw new BuildException("no license"); + } + final PrintStream out = getOut(); + + class Visitor implements FileVisitor { + int failed = 0; + int passed = 0; + + @Override + public void visit(File file) { + if (license.checkFile(file)) { + passed++; + } else { + failed++; + String path = file.getPath(); + if (!license.foundLicense()) { + out.println(license.tag + " LICENSE FAIL: " + path); + } + if (!license.foundCopyright()) { + out.println(license.tag + " COPYRIGHT FAIL: " + path); + } + } + } + } + Visitor visitor = new Visitor(); + visitAll(visitor); + this.failed = visitor.failed; + this.passed = visitor.passed; + if (0 < visitor.failed) { + getOut().println("Total passed: " + visitor.passed + (visitor.failed == 0 ? "" : " failed: " + visitor.failed)); + if (failOnError) { + throw new BuildException(failed + " files failed license check"); + } + } + } + + private void list() { + Iterator enu = LICENSES.keySet().iterator(); + StringBuffer sb = new StringBuffer(); + sb.append("known license keys:"); + boolean first = true; + while (enu.hasNext()) { + sb.append((first ? " " : ", ") + enu.next()); + if (first) { + first = false; + } + } + getOut().println(sb.toString()); + } + + /** + * Encapsulate license and copyright specifications to check files use hokey string matching. + */ + public static class License { + /** acceptable years for copyright prefix to company - append " " */ + static final String[] YEARS = // remove older after license xfer? + new String[] { "2002 ", "2003 ", "2004 ", "2005", "2006", "2007", "2008", + "2009", "2010", "2011", "2012", "2013", "2014", "2015", "2016", "2017", "2018", "2019", "2001 ", "2000 ", + "1999 " }; + public final String tag; + public final String license; + private final String[] copyright; + private boolean gotLicense; + private boolean gotCopyright; + + License(String tag, String license) { + this(tag, license, (String[]) null); + } + + License(String tag, String license, String copyright) { + this(tag, license, new String[] { copyright }); + } + + License(String tag, String license, String copyright, String altCopyright) { + this(tag, license, new String[] { copyright, altCopyright }); + } + + License(String tag, String license, String[] copyright) { + this.tag = tag; + if ((null == tag) || (0 == tag.length())) { + throw new IllegalArgumentException("null tag"); + } + this.license = license; + this.copyright = copyright; + } + + public final boolean gotValidFile() { + return foundLicense() && foundCopyright(); + } + + /** @return true if no license sought or if some license found */ + public final boolean foundLicense() { + return ((null == license) || gotLicense); + } + + /** @return true if no copyright sought or if some copyright found */ + public final boolean foundCopyright() { + return ((null == copyright) || gotCopyright); + } + + public boolean checkFile(final File file) { + clear(); + // boolean result = false; + BufferedReader input = null; + int lineNum = 0; + try { + input = new BufferedReader(new FileReader(file)); + String line; + while (!gotValidFile() && (line = input.readLine()) != null) { + lineNum++; + checkLine(line); + } + } catch (IOException e) { + System.err.println("reading line " + lineNum + " of " + file); + e.printStackTrace(System.err); + } finally { + if (null != input) { + try { + input.close(); + } catch (IOException e) { + } // ignore + } + } + return gotValidFile(); + } + + @Override + public String toString() { + return tag; + } + + private void checkLine(String line) { + if ((null == line) || (0 == line.length())) { + return; + } + if (!gotLicense && (null != license) && (-1 != line.indexOf(license))) { + gotLicense = true; + } + if (!gotCopyright && (null != copyright)) { + int loc; + for (int j = 0; !gotCopyright && (j < YEARS.length); j++) { + if (-1 != (loc = line.indexOf(YEARS[j]))) { + loc += YEARS[j].length(); + String afterLoc = line.substring(loc).trim(); + for (int i = 0; !gotCopyright && (i < copyright.length); i++) { + if (0 == afterLoc.indexOf(copyright[i])) { + gotCopyright = true; + } + } + } + } + } + } + + private void clear() { + if (gotLicense) { + gotLicense = false; + } + if (gotCopyright) { + gotCopyright = false; + } + } + } // class License +} + +class HeaderInfo { + /** File for which this is the info */ + public final File file; + + /** unmodifiable List of String years */ + public final List years; + + /** last line of license */ + public final int lastLine; + + /** last line of license */ + public final boolean hasLicense; + + public HeaderInfo(File file, int lastLine, List<String> years, boolean hasLicense) { + this.lastLine = lastLine; + this.file = file; + this.hasLicense = hasLicense; + List<String> newYears = new ArrayList<String>(); + newYears.addAll(years); + Collections.sort(newYears); + this.years = Collections.unmodifiableList(newYears); + if ((null == file) || !file.canWrite()) { + throw new IllegalArgumentException("bad file: " + this); + } + if (!hasLicense) { + if ((0 > lastLine) || (65 < lastLine)) { + throw new IllegalArgumentException("bad last line: " + this); + } + } else { + if ((null == years) || (1 > years.size())) { + throw new IllegalArgumentException("no years: " + this); + } + if ((20 > lastLine) || (65 < lastLine)) { + throw new IllegalArgumentException("bad last line: " + this); + } + } + } + + @Override + public String toString() { + return file.getPath() + ":" + lastLine + " " + years; + } + + public void writeHeader(PrintWriter writer) { + if (!hasLicense) { + writer.println(TOP); + writer.println(PARC_ONLY); + writeRest(writer); + } else { + final int size = years.size(); + if (1 > size) { + throw new Error("no years found in " + toString()); + } + String first = (String) years.get(0); + String last = (String) years.get(size - 1); + boolean lastIs2002 = "2002".equals(last); + String xlast = last; + if (lastIs2002) { // 2002 was PARC + xlast = (String) (size > 1 ? years.get(size - 2) : null); + // 1999-2002 Xerox implies 1999-2001 Xerox + if (first.equals(xlast) && !"2001".equals(xlast)) { + xlast = "2001"; + } + } + String xyears = first + "-" + xlast; + if (first.equals(last)) { + xyears = first; + } + + writer.println(TOP); + if (!lastIs2002) { // Xerox only + writer.println(XEROX_PREFIX + xyears + XEROX_SUFFIX + ". "); + } else if (size == 1) { // PARC only + writer.println(PARC_ONLY); + } else { // XEROX plus PARC + writer.println(XEROX_PREFIX + xyears + XEROX_SUFFIX + ", "); + writer.println(PARC); + } + writeRest(writer); + } + } + + void writeRest(PrintWriter writer) { + writer.println(" * All rights reserved. "); + writer.println(" * This program and the accompanying materials are made available "); + writer.println(" * under the terms of the Eclipse Public License v1.0 "); + writer.println(" * which accompanies this distribution and is available at "); + writer.println(" * http://www.eclipse.org/legal/epl-v10.html "); + writer.println(" * "); + writer.println(" * Contributors: "); + writer.println(" * Xerox/PARC initial implementation "); + writer.println(" * ******************************************************************/"); + writer.println(""); + } + + public static final String TOP = "/* *******************************************************************"; + public static final String PARC = " * 2002 Palo Alto Research Center, Incorporated (PARC)."; + public static final String PARC_ONLY = " * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC)."; + public static final String XEROX_PREFIX = " * Copyright (c) "; + public static final String XEROX_SUFFIX = " Xerox Corporation"; + /* + * /* ******************************************************************* Copyright (c) 1998-2001 Xerox Corporation, 2002 Palo + * Alto Research Center, Incorporated (PARC). All rights reserved. This program and the accompanying materials are made + * available under the terms of the Eclipse Public License v1.0 which accompanies this distribution and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: Xerox/PARC initial implementation ****************************************************************** + */ +} + +/** + * header search/replace using hokey string matching + */ +class Header { + + /** replace the header in file */ + public static boolean replaceHeader(File file, HeaderInfo info) { + // ArrayList years = new ArrayList(); + // int endLine = 0; + BufferedReader input = null; + PrintWriter output = null; + FileWriter outWriter = null; + int lineNum = 0; + boolean result = false; + final File inFile = new File(file.getPath() + ".tmp"); + try { + File outFile = new File(file.getPath()); + if (!file.renameTo(inFile) || !inFile.canRead()) { + throw new Error("unable to rename " + file + " to " + inFile); + } + outWriter = new FileWriter(outFile); + input = new BufferedReader(new FileReader(inFile)); + output = new PrintWriter(outWriter, true); + info.writeHeader(output); + String line; + while (null != (line = input.readLine())) { + lineNum++; + if (lineNum > info.lastLine) { + output.println(line); + } + } + } catch (IOException e) { + System.err.println("writing line " + lineNum + " of " + file); + e.printStackTrace(System.err); + result = false; + } finally { + if (null != input) { + try { + input.close(); + } catch (IOException e) { + result = false; + } + } + if (null != outWriter) { + try { + outWriter.close(); + } catch (IOException e) { + result = false; + } + } + result = inFile.delete(); + } + return result; + } + + public static HeaderInfo checkFile(final File file) { + ArrayList<String> years = new ArrayList<String>(); + int endLine = 0; + BufferedReader input = null; + int lineNum = 0; + try { + input = new BufferedReader(new FileReader(file)); + String line; + while (null != (line = input.readLine())) { + lineNum++; + String ll = line.trim(); + if (ll.startsWith("package ") || ll.startsWith("import ")) { + break; // ignore default package w/o imports + } + if (checkLine(line, years)) { + endLine = lineNum; + break; + } + } + } catch (IOException e) { + System.err.println("reading line " + lineNum + " of " + file); + e.printStackTrace(System.err); + } finally { + if (null != input) { + try { + input.close(); + } catch (IOException e) { + } // ignore + } + } + return new HeaderInfo(file, endLine, years, endLine > 0); + } + + /** + * Add any years found (as String) to years, and return true at the first end-of-comment + * + * @return true if this line has end-of-comment + */ + private static boolean checkLine(String line, ArrayList<String> years) { + if ((null == line) || (0 == line.length())) { + return false; + } + int loc; + int start = 0; + + while ((-1 != (loc = line.indexOf("199", start)) || (-1 != (loc = line.indexOf("200", start))))) { + char c = line.charAt(loc + 3); + if ((c <= '9') && (c >= '0')) { + years.add(line.substring(loc, loc + 4)); + } + start = loc + 4; + } + + return (-1 != line.indexOf("*/")); + } + +} // class Header + |