All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.tools.ant.taskdefs.cvslib.ChangeLogTask Maven / Gradle / Ivy

The newest version!
/*
 *  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
 *
 *      https://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.
 *
 */
package org.apache.tools.ant.taskdefs.cvslib;

import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.Vector;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.AbstractCvsTask;
import org.apache.tools.ant.types.FileSet;

/**
 * Examines the output of cvs log and group related changes together.
 *
 * It produces an XML output representing the list of changes.
 * 
 * <!-- Root element -->
 * <!ELEMENT changelog (entry+)>
 * <!-- CVS Entry -->
 * <!ELEMENT entry (date,author,file+,msg)>
 * <!-- Date of cvs entry -->
 * <!ELEMENT date (#PCDATA)>
 * <!-- Author of change -->
 * <!ELEMENT author (#PCDATA)>
 * <!-- List of files affected -->
 * <!ELEMENT msg (#PCDATA)>
 * <!-- File changed -->
 * <!ELEMENT file (name,revision,prevrevision?)>
 * <!-- Name of the file -->
 * <!ELEMENT name (#PCDATA)>
 * <!-- Revision number -->
 * <!ELEMENT revision (#PCDATA)>
 * <!-- Previous revision number -->
 * <!ELEMENT prevrevision (#PCDATA)>
 * 
* * @since Ant 1.5 * @ant.task name="cvschangelog" category="scm" */ public class ChangeLogTask extends AbstractCvsTask { /** User list */ private File usersFile; /** User list */ private List cvsUsers = new Vector<>(); /** Input dir */ private File inputDir; /** Output file */ private File destFile; /** The earliest date at which to start processing entries. */ private Date startDate; /** The latest date at which to stop processing entries. */ private Date endDate; /** Determines whether log (false) or rlog (true) is used */ private boolean remote = false; /** Start tag when doing tag ranges. */ private String startTag; /** End tag when doing tag ranges. */ private String endTag; /** * Filesets containing list of files against which the cvs log will be * performed. If empty then all files in the working directory will * be checked. */ private final List filesets = new Vector<>(); /** * Set the base dir for cvs. * * @param inputDir The new dir value */ public void setDir(final File inputDir) { this.inputDir = inputDir; } /** * Set the output file for the log. * * @param destFile The new destfile value */ public void setDestfile(final File destFile) { this.destFile = destFile; } /** * Set a lookup list of user names & addresses * * @param usersFile The file containing the users info. */ public void setUsersfile(final File usersFile) { this.usersFile = usersFile; } /** * Add a user to list changelog knows about. * * @param user the user */ public void addUser(final CvsUser user) { cvsUsers.add(user); } /** * Set the date at which the changelog should start. * * @param start The date at which the changelog should start. */ public void setStart(final Date start) { this.startDate = start; } /** * Set the date at which the changelog should stop. * * @param endDate The date at which the changelog should stop. */ public void setEnd(final Date endDate) { this.endDate = endDate; } /** * Set the number of days worth of log entries to process. * * @param days the number of days of log to process. */ public void setDaysinpast(final int days) { // CheckStyle:MagicNumber OFF final long time = System.currentTimeMillis() - (long) days * 24 * 60 * 60 * 1000; // CheckStyle:MagicNumber ON setStart(new Date(time)); } /** * Whether to use rlog against a remote repository instead of log * in a working copy's directory. * * @param remote boolean * @since Ant 1.8.0 */ public void setRemote(final boolean remote) { this.remote = remote; } /** * Set the tag at which the changelog should start. * * @param start The date at which the changelog should start. */ public void setStartTag(final String start) { this.startTag = start; } /** * Set the tag at which the changelog should stop. * * @param end The date at which the changelog should stop. */ public void setEndTag(final String end) { this.endTag = end; } /** * Adds a set of files about which cvs logs will be generated. * * @param fileSet a set of files about which cvs logs will be generated. */ public void addFileset(final FileSet fileSet) { filesets.add(fileSet); } /** * Execute task * * @exception BuildException if something goes wrong executing the * cvs command */ @Override public void execute() throws BuildException { File savedDir = inputDir; // may be altered in validate try { validate(); final Properties userList = new Properties(); loadUserlist(userList); for (CvsUser user : cvsUsers) { user.validate(); userList.put(user.getUserID(), user.getDisplayname()); } if (!remote) { setCommand("log"); if (getTag() != null) { CvsVersion myCvsVersion = new CvsVersion(); myCvsVersion.setProject(getProject()); myCvsVersion.setTaskName("cvsversion"); myCvsVersion.setCvsRoot(getCvsRoot()); myCvsVersion.setCvsRsh(getCvsRsh()); myCvsVersion.setPassfile(getPassFile()); myCvsVersion.setDest(inputDir); myCvsVersion.execute(); if (myCvsVersion.supportsCvsLogWithSOption()) { addCommandArgument("-S"); } } } else { // supply 'rlog' as argument instead of command setCommand(""); addCommandArgument("rlog"); // Do not print name/header if no revisions // selected. This is quicker: less output to parse. addCommandArgument("-S"); // Do not list tags. This is quicker: less output to // parse. addCommandArgument("-N"); } if (null != startTag || null != endTag) { // man, do I get spoiled by C#'s ?? operator String startValue = startTag == null ? "" : startTag; String endValue = endTag == null ? "" : endTag; addCommandArgument("-r" + startValue + "::" + endValue); } else if (null != startDate) { final SimpleDateFormat outputDate = new SimpleDateFormat("yyyy-MM-dd"); // We want something of the form: -d ">=YYYY-MM-dd" final String dateRange = ">=" + outputDate.format(startDate); // Supply '-d' as a separate argument - Bug# 14397 addCommandArgument("-d"); addCommandArgument(dateRange); } // Check if list of files to check has been specified for (FileSet fileSet : filesets) { final DirectoryScanner scanner = fileSet.getDirectoryScanner(getProject()); for (String file : scanner.getIncludedFiles()) { addCommandArgument(file); } } final ChangeLogParser parser = new ChangeLogParser(remote, getPackage(), getModules()); final RedirectingStreamHandler handler = new RedirectingStreamHandler(parser); log(getCommand(), Project.MSG_VERBOSE); setDest(inputDir); setExecuteStreamHandler(handler); try { super.execute(); } finally { final String errors = handler.getErrors(); if (null != errors) { log(errors, Project.MSG_ERR); } } final CVSEntry[] entrySet = parser.getEntrySetAsArray(); final CVSEntry[] filteredEntrySet = filterEntrySet(entrySet); replaceAuthorIdWithName(userList, filteredEntrySet); writeChangeLog(filteredEntrySet); } finally { inputDir = savedDir; } } /** * Validate the parameters specified for task. * * @throws BuildException if fails validation checks */ private void validate() throws BuildException { if (null == inputDir) { inputDir = getProject().getBaseDir(); } if (null == destFile) { throw new BuildException("Destfile must be set."); } if (!inputDir.exists()) { throw new BuildException("Cannot find base dir %s", inputDir.getAbsolutePath()); } if (null != usersFile && !usersFile.exists()) { throw new BuildException("Cannot find user lookup list %s", usersFile.getAbsolutePath()); } if ((null != startTag || null != endTag) && (null != startDate || null != endDate)) { throw new BuildException( "Specify either a tag or date range, not both"); } } /** * Load the userlist from the userList file (if specified) and add to * list of users. * * @param userList the file of users * @throws BuildException if file can not be loaded for some reason */ private void loadUserlist(final Properties userList) throws BuildException { if (null != usersFile) { try { userList.load(Files.newInputStream(usersFile.toPath())); } catch (final IOException ioe) { throw new BuildException(ioe.toString(), ioe); } } } /** * Filter the specified entries according to an appropriate rule. * * @param entrySet the entry set to filter * @return the filtered entry set */ private CVSEntry[] filterEntrySet(final CVSEntry[] entrySet) { final List results = new ArrayList<>(); for (CVSEntry cvsEntry : entrySet) { final Date date = cvsEntry.getDate(); //bug#30471 //this is caused by Date.after throwing a NullPointerException //for some reason there's no date set in the CVSEntry //https://docs.oracle.com/javase/1.5.0/docs/api/java/util/Date.html#after(java.util.Date) //according to the docs as of 1.5 it does throw //for now skip entries which are missing a date if (null == date) { continue; } if (null != startDate && startDate.after(date)) { //Skip dates that are too early continue; } if (null != endDate && endDate.before(date)) { //Skip dates that are too late continue; } results.add(cvsEntry); } return results.toArray(new CVSEntry[0]); } /** * replace all known author's id's with their maven specified names */ private void replaceAuthorIdWithName(final Properties userList, final CVSEntry[] entrySet) { for (final CVSEntry entry : entrySet) { if (userList.containsKey(entry.getAuthor())) { entry.setAuthor(userList.getProperty(entry.getAuthor())); } } } /** * Print changelog to file specified in task. * * @param entrySet the entry set to write. * @throws BuildException if there is an error writing changelog. */ private void writeChangeLog(final CVSEntry[] entrySet) throws BuildException { try (final PrintWriter writer = new PrintWriter( new OutputStreamWriter(Files.newOutputStream(destFile.toPath()), StandardCharsets.UTF_8))) { new ChangeLogWriter().printChangeLog(writer, entrySet); if (writer.checkError()) { throw new IOException("Encountered an error writing changelog"); } } catch (final UnsupportedEncodingException uee) { getProject().log(uee.toString(), Project.MSG_ERR); } catch (final IOException ioe) { throw new BuildException(ioe.toString(), ioe); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy