org.apache.tools.ant.taskdefs.Touch Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of testatoo-container-jetty-full Show documentation
Show all versions of testatoo-container-jetty-full Show documentation
Testatoo Jetty Container with JSP support
/*
* Copyright 2000-2005 The Apache Software Foundation
*
* Licensed 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.
*
*/
package org.apache.tools.ant.taskdefs;
import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Locale;
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.Task;
import org.apache.tools.ant.types.Mapper;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.FileList;
import org.apache.tools.ant.util.FileUtils;
import org.apache.tools.ant.util.FileNameMapper;
/**
* Touch a file and/or fileset(s) and/or filelist(s);
* corresponds to the Unix touch command.
*
* If the file to touch doesn't exist, an empty one is created.
*
* @since Ant 1.1
*
* @ant.task category="filesystem"
*/
public class Touch extends Task {
private interface DateFormatFactory {
DateFormat getPrimaryFormat();
DateFormat getFallbackFormat();
}
private static final DateFormatFactory DEFAULT_DF_FACTORY
= new DateFormatFactory() {
/*
* The initial version used DateFormat.SHORT for the
* time format, which ignores seconds. If we want
* seconds as well, we need DateFormat.MEDIUM, which
* in turn would break all old build files.
*
* First try to parse with DateFormat.SHORT and if
* that fails with MEDIUM - throw an exception if both
* fail.
*/
public DateFormat getPrimaryFormat() {
return DateFormat.getDateTimeInstance(DateFormat.SHORT,
DateFormat.SHORT, Locale.US);
}
public DateFormat getFallbackFormat() {
return DateFormat.getDateTimeInstance(DateFormat.SHORT,
DateFormat.MEDIUM, Locale.US);
}
};
private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
private File file;
private long millis = -1;
private String dateTime;
private Vector filesets = new Vector();
private Vector filelists = new Vector();
private boolean dateTimeConfigured;
private boolean mkdirs;
private boolean verbose = true;
private FileNameMapper fileNameMapper = null;
private DateFormatFactory dfFactory = DEFAULT_DF_FACTORY;
/**
* Construct a new Touch
task.
*/
public Touch() {
}
/**
* Sets a single source file to touch. If the file does not exist
* an empty file will be created.
* @param file the File
to touch.
*/
public void setFile(File file) {
this.file = file;
}
/**
* Set the new modification time of file(s) touched
* in milliseconds since midnight Jan 1 1970. Optional, default=now.
* @param millis the long
timestamp to use.
*/
public void setMillis(long millis) {
this.millis = millis;
}
/**
* Set the new modification time of file(s) touched
* in the format "MM/DD/YYYY HH:MM AM or PM"
* or "MM/DD/YYYY HH:MM:SS AM or PM".
* Optional, default=now.
* @param dateTime the String
date in the specified format.
*/
public void setDatetime(String dateTime) {
if (this.dateTime != null) {
log("Resetting datetime attribute to " + dateTime, Project.MSG_VERBOSE);
}
this.dateTime = dateTime;
dateTimeConfigured = false;
}
/**
* Set whether nonexistent parent directories should be created
* when touching new files.
* @param mkdirs boolean
whether to create parent directories.
* @since Ant 1.6.3
*/
public void setMkdirs(boolean mkdirs) {
this.mkdirs = mkdirs;
}
/**
* Set whether the touch task will report every file it creates;
* defaults to true
.
* @param verbose boolean
flag.
* @since Ant 1.6.3
*/
public void setVerbose(boolean verbose) {
this.verbose = verbose;
}
/**
* Set the format of the datetime attribute.
* @param pattern the SimpleDateFormat
-compatible format pattern.
* @since Ant 1.6.3
*/
public void setPattern(final String pattern) {
dfFactory = new DateFormatFactory() {
public DateFormat getPrimaryFormat() {
return new SimpleDateFormat(pattern);
}
public DateFormat getFallbackFormat() {
return null;
}
};
}
/**
* Add a Mapper
.
* @param mapper the Mapper
to add.
* @since Ant 1.6.3
*/
public void addConfiguredMapper(Mapper mapper) {
add(mapper.getImplementation());
}
/**
* Add a FileNameMapper
.
* @param fileNameMapper the FileNameMapper
to add.
* @since Ant 1.6.3
* @throws BuildException if multiple mappers are added.
*/
public void add(FileNameMapper fileNameMapper) throws BuildException {
if (this.fileNameMapper != null) {
throw new BuildException("Only one mapper may be added to the "
+ getTaskName() + " task.");
}
this.fileNameMapper = fileNameMapper;
}
/**
* Add a set of files to touch.
* @param set the Fileset
to add.
*/
public void addFileset(FileSet set) {
filesets.addElement(set);
}
/**
* Add a filelist to touch.
* @param list the Filelist
to add.
*/
public void addFilelist(FileList list) {
filelists.addElement(list);
}
/**
* Check that this task has been configured properly.
* @throws BuildException if configuration errors are detected.
* @since Ant 1.6.3
*/
protected synchronized void checkConfiguration() throws BuildException {
if (file == null && filesets.size() + filelists.size() == 0) {
throw new BuildException("Specify at least one source"
+ "--a file, filelist or a fileset.");
}
if (file != null && file.exists() && file.isDirectory()) {
throw new BuildException("Use a fileset to touch directories.");
}
if (dateTime != null && !dateTimeConfigured) {
long workmillis = millis;
DateFormat df = dfFactory.getPrimaryFormat();
ParseException pe = null;
try {
workmillis = df.parse(dateTime).getTime();
} catch (ParseException peOne) {
df = dfFactory.getFallbackFormat();
if (df == null) {
pe = peOne;
} else {
try {
workmillis = df.parse(dateTime).getTime();
} catch (ParseException peTwo) {
pe = peTwo;
}
}
}
if (pe != null) {
throw new BuildException(pe.getMessage(), pe, getLocation());
}
if (workmillis < 0) {
throw new BuildException("Date of " + dateTime
+ " results in negative "
+ "milliseconds value "
+ "relative to epoch "
+ "(January 1, 1970, "
+ "00:00:00 GMT).");
}
log("Setting millis to " + workmillis + " from datetime attribute",
((millis < 0) ? Project.MSG_DEBUG : Project.MSG_VERBOSE));
setMillis(workmillis);
//only set if successful to this point:
dateTimeConfigured = true;
}
}
/**
* Execute the touch operation.
* @throws BuildException if an error occurs.
*/
public void execute() throws BuildException {
checkConfiguration();
touch();
}
/**
* Does the actual work; assumes everything has been checked by now.
* @throws BuildException if an error occurs.
*/
protected void touch() throws BuildException {
long defaultTimestamp = getTimestamp();
if (file != null) {
touch(file.getParentFile(), file.getName(), defaultTimestamp);
}
// deal with the filesets
for (int i = 0; i < filesets.size(); i++) {
FileSet fs = (FileSet) filesets.elementAt(i);
DirectoryScanner ds = fs.getDirectoryScanner(getProject());
File fromDir = fs.getDir(getProject());
String[] srcFiles = ds.getIncludedFiles();
String[] srcDirs = ds.getIncludedDirectories();
for (int j = 0; j < srcFiles.length; j++) {
touch(fromDir, srcFiles[j], defaultTimestamp);
}
for (int j = 0; j < srcDirs.length; j++) {
touch(fromDir, srcDirs[j], defaultTimestamp);
}
}
// deal with the filelists
for (int i = 0; i < filelists.size(); i++) {
FileList fl = (FileList) filelists.elementAt(i);
File fromDir = fl.getDir(getProject());
String[] srcFiles = fl.getFiles(getProject());
for (int j = 0; j < srcFiles.length; j++) {
touch(fromDir, srcFiles[j], defaultTimestamp);
}
}
}
/**
* Touch a single file with the current timestamp (this.millis). This method
* does not interact with any nested mappers and remains for reasons of
* backwards-compatibility only.
* @param file file to touch
* @throws BuildException
* @deprecated
*/
protected void touch(File file) {
touch(file, getTimestamp());
}
private long getTimestamp() {
return (millis < 0) ? System.currentTimeMillis() : millis;
}
private void touch(File fromDir, String filename, long defaultTimestamp) {
File f = FILE_UTILS.resolveFile(fromDir, filename);
if (fileNameMapper == null) {
touch(f, defaultTimestamp);
} else {
String[] mapped = fileNameMapper.mapFileName(filename);
if (mapped != null && mapped.length > 0) {
long modTime = (f.exists()) ? f.lastModified() : defaultTimestamp;
for (int i = 0; i < mapped.length; i++) {
touch(getProject().resolveFile(mapped[i]), modTime);
}
}
}
}
private void touch(File file, long modTime) {
if (!file.exists()) {
log("Creating " + file,
((verbose) ? Project.MSG_INFO : Project.MSG_VERBOSE));
try {
FILE_UTILS.createNewFile(file, mkdirs);
} catch (IOException ioe) {
throw new BuildException("Could not create " + file, ioe,
getLocation());
}
}
if (!file.canWrite()) {
throw new BuildException("Can not change modification date of "
+ "read-only file " + file);
}
FILE_UTILS.setFileLastModified(file, modTime);
}
}