/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2007 Sun Microsystems, Inc. */ package org.opends.build.tools; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.GregorianCalendar; import java.util.LinkedList; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Task; import org.apache.tools.ant.types.FileSet; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.wc.SVNStatus; import org.tmatesoft.svn.core.wc.SVNStatusClient; import org.tmatesoft.svn.core.wc.SVNStatusType; /** * This class provides an implementation of an Ant task that may be used to * verify that the copyright dates of all modified files in the workspace have * been updated to include the current year. In particular, for all files in * one of the specified filesets that have been created or modified in the * local workspace, it will parse the file for any line which appears to be * a comment and contains the word "copyright". If the line does not also * contain the current year, then it will be flagged as a potential violation to * be addressed. */ public class CheckCopyrightDates extends Task { /** * The name of the system property that may be used to prevent copyright date * problems from failing the build. */ public static final String IGNORE_ERRORS_PROPERTY = "org.opends.server.IgnoreCopyrightDateErrors"; // A list of all the filesets to be checked. private LinkedList filesetList = new LinkedList(); // The path to the root of the Subversion workspace to check. private String workspace = null; /** * Adds the provided fileset to the list of filesets that should be checked. * * @param fileset A fileset containing a list of files that should be * checked. */ public void addFileset(FileSet fileset) { filesetList.add(fileset); } /** * Specifies the path to the root of the Subversion workspace for which to * retrieve the revision number. * * @param workspace The path to the root of the Subversion workspace for * which to retrieve the revision number. */ public void setWorkspace(String workspace) { this.workspace = workspace; } /** * Performs the appropriate processing needed for this task. In this case, * it uses SVNKit to identify all modified files in the current workspace. * For all source files, look for comment lines containing the word * "copyright" and make sure at least one of them contains the current year. */ @Override() public void execute() { // Make sure that at least one fileset was provided. if (filesetList.isEmpty()) { throw new BuildException("ERROR: No filesets were specified to " + "indicate which files should be checked."); } File workspacePath; if ((workspace == null) || (workspace.length() == 0)) { workspacePath = getProject().getBaseDir(); } else { workspacePath = new File(workspace); } String workspacePathString = workspacePath.getAbsolutePath() + File.separator; // Get the year to use in the determination. GregorianCalendar calendar = new GregorianCalendar(); int year = calendar.get(GregorianCalendar.YEAR); String yearString = String.valueOf(year); // Get the current status for all files in the fileset. For any files with // local changes, see if there are any files that potentially have the wrong // copyright year. SVNStatusClient svnClient = new SVNStatusClient(null, null); LinkedList problemFiles = new LinkedList(); for (FileSet fileSet : filesetList) { DirectoryScanner scanner = fileSet.getDirectoryScanner(getProject()); for (String relativePath : scanner.getIncludedFiles()) { String filePath = scanner.getBasedir() + File.separator + relativePath; try { SVNStatus svnStatus = svnClient.doStatus(new File(filePath), false); if (svnStatus == null) { System.err.println("WARNING: Could not determine Subversion " + "status for file " + filePath); System.err.println("No further copyright date checking will be " + "performed."); return; } SVNStatusType statusType = svnStatus.getContentsStatus(); if ((statusType == SVNStatusType.STATUS_ADDED) || (statusType == SVNStatusType.STATUS_MODIFIED) || (statusType == SVNStatusType.STATUS_UNVERSIONED)) { BufferedReader reader = null; try { boolean copyrightFound = false; boolean correctYearFound = false; reader = new BufferedReader(new FileReader(filePath)); String line = reader.readLine(); while (line != null) { String lowerLine = line.toLowerCase().trim(); if (isCommentLine(lowerLine)) { int copyrightPos = lowerLine.indexOf("copyright"); if (copyrightPos > 0) { copyrightFound = true; if (lowerLine.indexOf(yearString) > 0) { correctYearFound = true; break; } } } line = reader.readLine(); } if (copyrightFound && (! correctYearFound)) { if (filePath.startsWith(workspacePathString)) { problemFiles.add(filePath.substring( workspacePathString.length())); } else { problemFiles.add(filePath); } } } catch (IOException ioe) { System.err.println("ERROR: Could not read file " + filePath + " to check copyright date."); System.err.println("No further copyright date checking will be " + "performed."); return; } finally { try { if (reader != null) { reader.close(); } } catch (Exception e) {} } } } catch (SVNException svnException) { System.err.println("WARNING: Could not determine Subversion " + "status for file " + filePath + ": " + svnException); System.err.println("No further copyright date checking will be " + "performed."); return; } } } if (! problemFiles.isEmpty()) { System.err.println("WARNING: Potential copyright year updates needed " + "for the following files:"); for (String filename : problemFiles) { System.err.println(" " + filename); } String ignoreStr = getProject().getProperty(IGNORE_ERRORS_PROPERTY); if ((ignoreStr == null) || (! ignoreStr.equalsIgnoreCase("true"))) { throw new BuildException("Fix copyright date problems before " + "proceeding, or use '-D" + IGNORE_ERRORS_PROPERTY + "=true' to " + "ignore copyright warnings."); } } } /** * Indicates whether the provided line appears to be a comment line. It will * check for a number of common comment indicators in Java source files, * shell scripts, XML files, and LDIF files. * * @param lowerLine The line to be checked. It should have been coverted to * all lowercase characters and any leading spaces * removed. * * @return {@code true} if it appears that the line is a comment line, or * {@code false} if not. */ private static boolean isCommentLine(String lowerLine) { if (lowerLine.startsWith("/*") || lowerLine.startsWith("*") || lowerLine.startsWith("//") || lowerLine.startsWith("#") || lowerLine.startsWith("rem") || lowerLine.startsWith("