Browse Source

checksum task and condition.

I promise to add testcases later 8-)

Submitted by:	Magesh Umasankar <umagesh@rediffmail.com>


git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@269929 13f79535-47bb-0310-9956-ffa450edef68
master
Stefan Bodewig 23 years ago
parent
commit
9ded403f70
7 changed files with 585 additions and 3 deletions
  1. +1
    -3
      WHATSNEW
  2. +151
    -0
      docs/manual/CoreTasks/checksum.html
  3. +7
    -0
      docs/manual/CoreTasks/condition.html
  4. +1
    -0
      docs/manual/coretasklist.html
  5. +416
    -0
      src/main/org/apache/tools/ant/taskdefs/Checksum.java
  6. +8
    -0
      src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java
  7. +1
    -0
      src/main/org/apache/tools/ant/taskdefs/defaults.properties

+ 1
- 3
WHATSNEW View File

@@ -41,9 +41,7 @@ Other changes:
--------------

* New tasks bzip2 and bunzip2 to pack and unpack files using the
BZip2 alogrythm

* New task replaceregexp
BZip2 alogrithm, replaceregexp, checksum

* The attributes zipfile, jarfile, warfile and earfile (from the Zip,
Jar, War and Ear tasks) have been deprecated and superseded by a


+ 151
- 0
docs/manual/CoreTasks/checksum.html View File

@@ -0,0 +1,151 @@
<html>

<head>
<meta http-equiv="Content-Language" content="en-us">
<title>Apache Ant User Manual</title>
</head>

<body>

<h2><a name="checksum">Checksum</a></h2>
<h3>Description</h3>
<p>
Generates checksum for files. This task can also be used to
perform checksum verifications.
</p>
<h3>Parameters</h3>
<table border="1" cellpadding="2" cellspacing="0">
<tr>
<td valign="top"><b>Attribute</b></td>
<td valign="top"><b>Description</b></td>
<td align="center" valign="top"><b>Required</b></td>
</tr>
<tr>
<td valign="top">file</td>
<td valign="top">The file to generate checksum for.</td>
<td valign="top" align="center">One of either <var>file</var> or
at least one nested fileset element.</td>
</tr>
<tr>
<td valign="top">algorithm</td>
<td valign="top">Specifies the algorithm to be used to
compute the checksum. Defaults to &quot;MD5&quot;.
Other popular algorithms like &quot;SHA&quot; may be used
as well.
</td>
<td valign="top" align="center">No</td>
</tr>
<tr>
<td valign="top">provider</td>
<td valign="top">Specifies the provider of the algorithm.</td>
<td valign="top" align="center">No</td>
</tr>
<tr>
<td valign="top">fileext</td>
<td valign="top">The generated checksum file's name will be the
original filename with &quot;.&quot; and fileext added to it.
Defaults to the algorithm name being used.
</td>
<td valign="top" align="center">No</td>
</tr>
<tr>
<td valign="top">property</td>
<td valign="top">Specifies the name of the property to be set
with the generated checksum value. This cannot be specified
when fileext is being used or when the number of files
for which checksums is to be generated is greater than 1.
</td>
<td valign="top" align="center">No</td>
</tr>
<tr>
<td valign="top">overwrite</td>
<td valign="top">Overwrite existing files even if the destination
files are newer. Defaults to &quot;no&quot;.</td>
<td valign="top" align="center">No</td>
</tr>
<tr>
<td valign="top">verifyproperty</td>
<td valign="top">Specifies the name of the property to be set
with &quot;true&quot; or &quot;false&quot; depending upon whether
the generated checksum matches the existing checksum. When
this is set, the generated checksum is not written to a file or
property, but rather, the content of the file or property is used to
check against the generated checksum.
<td valign="top" align="center">No</td>
</tr>
</table>
<h3>Parameters specified as nested elements</h3>

<h4>fileset</h4>
<p>
<a href="../CoreTypes/fileset.html">FileSets</a> are used to select files to
generate checksums for.
</p>

<h3>Examples</h3>
<p><b>Example 1</b></p>
<pre>&lt;checksum file=&quot;foo.bar&quot;/&gt;</pre>
Generates a MD5 checksum for foo.bar and stores the checksum in the destination file
foo.bar.MD5. foo.bar.MD5 is overwritten only if foo.bar is newer than itself.

<p><b>Example 2</b></p>
<pre>&lt;checksum file=&quot;foo.bar&quot; forceOverwrite=&quot;yes&quot;/&gt;</pre>
Generates a MD5 checksum for foo.bar and stores the checksum in foo.bar.MD5.
If foo.bar.MD5 already exists, it is overwritten.

<p><b>Example 3</b></p>
<pre>&lt;checksum file=&quot;foo.bar&quot; property=&quot;foobarMD5&quot;/&gt;</pre>
Generates a MD5 checksum for foo.bar and stores it in the Project Property foobarMD5.

<p><b>Example 4</b></p>
<pre>&lt;checksum file=&quot;foo.bar&quot; verifyProperty=&quot;isMD5ok&quot;/&gt;</pre>
Generates a MD5 checksum for foo.bar, compares it against foo.bar.MD5 and sets
isMD5ok to either true or false, depending upon the result.

<p><b>Example 5</b></p>
<pre>&lt;checksum file=&quot;foo.bar&quot; algorithm=&quot;SHA&quot; fileext=&quot;asc&quot;/&gt;</pre>
Generates a SHA checksum for foo.bar and stores the checksum in the destination file
foo.bar.asc. foo.bar.asc is overwritten only if foo.bar is newer than itself.

<p><b>Example 6</b></p>
<pre>
&lt;checksum file=&quot;foo.bar&quot; property=&quot;${md5}&quot; verifyProperty=&quot;isEqual&quot;/&gt;
</pre>
Generates a MD5 checksum for foo.bar, compares it against the value of the property
md5, and sets isEqual to either true or false, depending upon the result.

<p><b>Example 7</b></p>
<pre>
&lt;checksum&gt;
&lt;fileset dir=&quot;.&quot;&gt;
&lt;include name=&quot;foo*&quot;/&gt;
&lt;/fileset&gt;
&lt;/checksum&gt;
</pre>
Works just like Example 1, but generates a .MD5 file for every file that begins with the name foo.

<p><b>Example 8</b></p>
<pre>
&lt;condition property=&quot;isChecksumEqual&quot;&gt;
&lt;checksum&gt;
&lt;fileset dir=&quot;.&quot;&gt;
&lt;include name=&quot;foo.bar&quot;/&gt;
&lt;/fileset&gt;
&lt;/checksum&gt;
&lt;/condition&gt;
</pre>
Works like Example 4, but sets isChecksumEqual to either true or false.
This example demonstrates use with the Condition task.


<h3>Note:</h3>
When working with more than one file, if condition and/or verifyproperty is used,
the result will be true only if the checksums matched correctly for all files being
considered.

<hr><p align="center">Copyright &copy; 2000,2001 Apache Software Foundation. All rights
Reserved.</p>

</body>
</html>


+ 7
- 0
docs/manual/CoreTasks/condition.html View File

@@ -138,6 +138,13 @@ are redundant and will be ignored.</p>
</tr>
</table>

<h4>checksum</h4>

<p>This condition is identical to the <a
href="checksum.html">Checksum</a> task, all attributes and nested
elements of that task are supported, the property and overwrite
attributes are redundant and will be ignored.</p>

<h3>Examples</h3>
<pre>
&lt;condition property=&quot;javamail.complete&quot;&gt;


+ 1
- 0
docs/manual/coretasklist.html View File

@@ -30,6 +30,7 @@
<a href="CoreTasks/available.html">Available</a><br>
<a href="CoreTasks/unpack.html">BUnzip2</a><br>
<a href="CoreTasks/pack.html">BZip2</a><br>
<a href="CoreTasks/checksum.html">Checksum</a><br>
<a href="CoreTasks/chmod.html">Chmod</a><br>
<a href="CoreTasks/condition.html">Condition</a><br>
<a href="CoreTasks/copy.html">Copy</a><br>


+ 416
- 0
src/main/org/apache/tools/ant/taskdefs/Checksum.java View File

@@ -0,0 +1,416 @@
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2001 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Ant", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.tools.ant.taskdefs;

import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.Enumeration;
import java.util.Hashtable;
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.condition.Condition;
import org.apache.tools.ant.taskdefs.MatchingTask;
import org.apache.tools.ant.types.FileSet;

/**
* This task can be used to create checksums for files.
* It can also be used to verify checksums.
*
* @author <a href="mailto:umagesh@rediffmail.com">Magesh Umasankar</a>
*/
public class Checksum extends MatchingTask implements Condition {
/**
* File for which checksum is to be calculated.
*/
private File file = null;
/**
* MessageDigest algorithm to be used.
*/
private String algorithm = "MD5";
/**
* MessageDigest Algorithm provider
*/
private String provider = null;
/**
* File Extension that is be to used to create or identify
* destination file
*/
private String fileext;
/**
* Holds generated checksum and gets set as a Project Property.
*/
private String property;
/**
* Create new destination file? Defaults to false.
*/
private boolean forceOverwrite;
/**
* Contains the result of a checksum verification. ("true" or "false")
*/
private String verifyProperty;
/**
* Vector to hold source file sets.
*/
private Vector filesets = new Vector();
/**
* Stores SourceFile, DestFile pairs and SourceFile, Property String pairs.
*/
private Hashtable includeFileMap = new Hashtable();
/**
* Message Digest instance
*/
private MessageDigest messageDigest;
/**
* is this task being used as a nested condition element?
*/
private boolean isCondition;

/**
* Sets the file for which the checksum is to be calculated.
*/
public void setFile(File file) {
this.file = file;
}

/**
* Sets the MessageDigest algorithm to be used
* to calculate the checksum.
*/
public void setAlgorithm(String algorithm) {
this.algorithm = algorithm;
}

/**
* Sets the MessageDigest algorithm provider to be used
* to calculate the checksum.
*/
public void setProvider(String provider) {
this.provider = provider;
}

/**
* Sets the File Extension that is be to used to
* create or identify destination file
*/
public void setFileext(String fileext) {
this.fileext = fileext;
}

/**
* Sets the property to hold the generated checksum
*/
public void setProperty(String property) {
this.property = property;
}

/**
* Sets verify property. This project property holds
* the result of a checksum verification - "true" or "false"
*/
public void setVerifyproperty(String verifyProperty) {
this.verifyProperty = verifyProperty;
}

/**
* Overwrite existing file irrespective of whether it is newer than
* the source file? Defaults to false.
*/
public void setForceOverwrite(boolean forceOverwrite) {
this.forceOverwrite = forceOverwrite;
}

/**
* Adds a set of files (nested fileset attribute).
*/
public void addFileset(FileSet set) {
filesets.addElement(set);
}

/**
* Calculate the checksum(s).
*/
public void execute() throws BuildException {
boolean value = validateAndExecute();
if (verifyProperty != null) {
project.setProperty(verifyProperty,
new Boolean(value).toString());
}
}

/**
* Calculate the checksum(s)
*
* @return Returns true if the checksum verification test passed,
* false otherwise.
*/
public boolean eval() throws BuildException {
isCondition = true;
return validateAndExecute();
}

/**
* Validate attributes and get down to business.
*/
private boolean validateAndExecute() throws BuildException {

if (file == null && filesets.size() == 0) {
throw new BuildException(
"Specify at least one source - a file or a fileset.");
}

if (file != null && file.exists() && file.isDirectory()) {
throw new BuildException(
"Checksum cannot be generated for directories");
}

if (property != null && fileext != null) {
throw new BuildException(
"Property and FileExt cannot co-exist.");
}

if (property != null) {
if (forceOverwrite) {
throw new BuildException(
"ForceOverwrite cannot be used when Property is specified");
}

if (file != null) {
if (filesets.size() > 0) {
throw new BuildException(
"Multiple files cannot be used when Property is specified");
}
} else {
if (filesets.size() > 1) {
throw new BuildException(
"Multiple files cannot be used when Property is specified");
}
}
}

if (verifyProperty != null) {
isCondition = true;
}

if (verifyProperty != null && forceOverwrite) {
throw new BuildException(
"VerifyProperty and ForceOverwrite cannot co-exist.");
}

if (isCondition && forceOverwrite) {
throw new BuildException(
"ForceOverwrite cannot be used when conditions are being used.");
}

if (fileext == null) {
fileext = "." + algorithm;
} else if (fileext.trim().length() == 0) {
throw new BuildException(
"File extension when specified must not be an empty string");
}

messageDigest = null;
if (provider != null) {
try {
messageDigest = MessageDigest.getInstance(algorithm, provider);
} catch (NoSuchAlgorithmException noalgo) {
throw new BuildException(noalgo, location);
} catch (NoSuchProviderException noprovider) {
throw new BuildException(noprovider, location);
}
} else {
try {
messageDigest = MessageDigest.getInstance(algorithm);
} catch (NoSuchAlgorithmException noalgo) {
throw new BuildException(noalgo, location);
}
}

if (messageDigest == null) {
throw new BuildException("Unable to create Message Digest",
location);
}

addToIncludeFileMap(file);

int sizeofFileSet = filesets.size();
for (int i = 0; i < sizeofFileSet; i++) {
FileSet fs = (FileSet) filesets.elementAt(i);
DirectoryScanner ds = fs.getDirectoryScanner(project);
String[] srcFiles = ds.getIncludedFiles();
for (int j = 0; j < srcFiles.length; j++) {
File src = new File(srcFiles[j]);
addToIncludeFileMap(src);
}
}

return generateChecksums();
}

/**
* Add key-value pair to the hashtable upon which
* to later operate upon.
*/
private void addToIncludeFileMap(File file) throws BuildException {
if (file != null) {
if (file.exists()) {
if (property == null) {
File dest = new File(file.getParent(), file.getName() + fileext);
if (forceOverwrite || isCondition ||
(file.lastModified() > dest.lastModified())) {
includeFileMap.put(file, dest);
} else {
log(file + " omitted as " + dest + " is up to date.",
Project.MSG_VERBOSE);
}
} else {
includeFileMap.put(file, property);
}
} else {
String message = "Could not find file "
+ file.getAbsolutePath()
+ " to generate checksum for.";
log(message);
throw new BuildException(message, location);
}
}
}

/**
* Generate checksum(s) using the message digest created earlier.
*/
private boolean generateChecksums() throws BuildException {
boolean checksumMatches = true;
FileInputStream fis = null;
FileOutputStream fos = null;
try {
for (Enumeration e = includeFileMap.keys(); e.hasMoreElements();) {
messageDigest.reset();
File src = (File) e.nextElement();
fis = new FileInputStream(src);
DigestInputStream dis = new DigestInputStream(fis,
messageDigest);
while (dis.read() != -1);
dis.close();
fis.close();
fis = null;
byte[] fileDigest = messageDigest.digest ();
String checksum = "";
for (int i = 0; i < fileDigest.length; i++) {
String hexStr = Integer.toHexString(0x00ff & fileDigest[i]);
if (hexStr.length() < 2) {
checksum += "0";
}
checksum += hexStr;
}
//can either be a property name string or a file
Object destination = includeFileMap.get(src);
if (destination instanceof java.lang.String) {
String prop = (String) destination;
if (isCondition) {
checksumMatches = checksum.equals(property);
} else {
project.setProperty(prop, checksum);
}
} else if (destination instanceof java.io.File) {
if (isCondition) {
File existingFile = (File) destination;
if (existingFile.exists() &&
existingFile.length() == checksum.length()) {
fis = new FileInputStream(existingFile);
DataInputStream edis = new DataInputStream(fis);
String suppliedChecksum = "";
if (edis.available() > 0) {
suppliedChecksum = edis.readLine();
}
fis.close();
fis = null;
edis.close();
checksumMatches =
checksum.equals(suppliedChecksum);
} else {
checksumMatches = false;
}
} else {
File dest = (File) destination;
fos = new FileOutputStream(dest);
fos.write(checksum.getBytes());
}
}
}
} catch (Exception e) {
throw new BuildException(e, location);
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {}
}
}
return checksumMatches;
}
}

+ 8
- 0
src/main/org/apache/tools/ant/taskdefs/condition/ConditionBase.java View File

@@ -61,6 +61,7 @@ import java.util.Vector;

import org.apache.tools.ant.ProjectComponent;
import org.apache.tools.ant.taskdefs.Available;
import org.apache.tools.ant.taskdefs.Checksum;
import org.apache.tools.ant.taskdefs.UpToDate;

/**
@@ -97,6 +98,13 @@ public abstract class ConditionBase extends ProjectComponent {
*/
public void addAvailable(Available a) {conditions.addElement(a);}

/**
* Add an &lt;checksum&gt; condition.
*
* @since 1.4
*/
public void addAvailable(Checksum c) {conditions.addElement(c);}

/**
* Add an &lt;uptodate&gt; condition.
*


+ 1
- 0
src/main/org/apache/tools/ant/taskdefs/defaults.properties View File

@@ -55,6 +55,7 @@ condition=org.apache.tools.ant.taskdefs.ConditionTask
dependset=org.apache.tools.ant.taskdefs.DependSet
bzip2=org.apache.tools.ant.taskdefs.BZip2
bunzip2=org.apache.tools.ant.taskdefs.BUnzip2
checksum=org.apache.tools.ant.taskdefs.Checksum

# optional tasks
script=org.apache.tools.ant.taskdefs.optional.Script


Loading…
Cancel
Save