mirror of https://github.com/apache/maven.git
Initial revision
git-svn-id: https://svn.apache.org/repos/asf/maven/components/trunk@162868 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
e9dcf04570
commit
65a5fee935
|
@ -0,0 +1,11 @@
|
|||
*~
|
||||
*.log
|
||||
target
|
||||
dist
|
||||
*.ipr
|
||||
*.iws
|
||||
*.iml
|
||||
dist
|
||||
target
|
||||
.classpath
|
||||
.project
|
|
@ -0,0 +1,13 @@
|
|||
#!/bin/sh
|
||||
|
||||
buildDir=target
|
||||
|
||||
rm -rf ${buildDir} > /dev/null 2>&1
|
||||
|
||||
mkdir ${buildDir}
|
||||
|
||||
javac -d ${buildDir} @sources.txt
|
||||
|
||||
cp src/main/resources/mboot.deps ${buildDir}/mboot.deps
|
||||
|
||||
( cd ${buildDir} ; jar -cf ../mboot.jar -m ../manifest.txt * )
|
|
@ -0,0 +1,3 @@
|
|||
Manifest-Version: 1.0
|
||||
Created-By: 0.92-gcc
|
||||
Main-Class: MBoot
|
Binary file not shown.
|
@ -0,0 +1,19 @@
|
|||
src/main/java/ArtifactDownloader.java
|
||||
src/main/java/Base64.java
|
||||
src/main/java/FileUtils.java
|
||||
src/main/java/HttpUtils.java
|
||||
src/main/java/IsolatedClassLoader.java
|
||||
src/main/java/JavacCompiler.java
|
||||
src/main/java/AbstractCompiler.java
|
||||
src/main/java/CompilerError.java
|
||||
src/main/java/StreamPumper.java
|
||||
src/main/java/DirectoryScanner.java
|
||||
src/main/java/SelectorUtils.java
|
||||
src/main/java/MBoot.java
|
||||
src/main/java/SurefirePlugin.java
|
||||
src/main/java/JarMojo.java
|
||||
src/main/java/StringUtils.java
|
||||
src/main/java/IOUtil.java
|
||||
src/main/java/Commandline.java
|
||||
src/main/java/SurefireBooter.java
|
||||
src/main/java/Os.java
|
|
@ -0,0 +1,124 @@
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
|
||||
* @author <a href="mailto:michal.maczka@dimatics.com">Michal Maczka</a>
|
||||
* @version $Id$
|
||||
*/
|
||||
public abstract class AbstractCompiler
|
||||
{
|
||||
private static String PS = System.getProperty( "path.separator" );
|
||||
|
||||
public String getClasspathString( String[] classpathElements )
|
||||
throws Exception
|
||||
{
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
for ( int i = 0; i < classpathElements.length; i++ )
|
||||
{
|
||||
sb.append( classpathElements[i] ).append( PS );
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
protected String[] getSourceFiles( String[] sourceDirectories )
|
||||
{
|
||||
List sources = new ArrayList();
|
||||
|
||||
for ( int i = 0; i < sourceDirectories.length; i++ )
|
||||
{
|
||||
DirectoryScanner scanner = new DirectoryScanner();
|
||||
|
||||
scanner.setBasedir( sourceDirectories[i] );
|
||||
|
||||
scanner.setIncludes( new String[]{"**/*.java"} );
|
||||
|
||||
scanner.scan();
|
||||
|
||||
String[] sourceDirectorySources = scanner.getIncludedFiles();
|
||||
|
||||
for ( int j = 0; j < sourceDirectorySources.length; j++ )
|
||||
{
|
||||
File f = new File( sourceDirectories[i], sourceDirectorySources[j] );
|
||||
|
||||
sources.add( f.getPath() );
|
||||
}
|
||||
}
|
||||
|
||||
String[] sourceArray = new String[sources.size()];
|
||||
|
||||
return (String[]) sources.toArray( sourceArray );
|
||||
}
|
||||
|
||||
protected String makeClassName( String fileName, String sourceDir )
|
||||
throws IOException
|
||||
{
|
||||
File origFile = new File( fileName );
|
||||
String canonical = null;
|
||||
|
||||
if ( origFile.exists() )
|
||||
{
|
||||
canonical = origFile.getCanonicalPath().replace( '\\', '/' );
|
||||
}
|
||||
|
||||
String str = fileName;
|
||||
str = str.replace( '\\', '/' );
|
||||
|
||||
if ( sourceDir != null )
|
||||
{
|
||||
String prefix =
|
||||
new File( sourceDir ).getCanonicalPath().replace( '\\', '/' );
|
||||
|
||||
if ( canonical != null )
|
||||
{
|
||||
if ( canonical.startsWith( prefix ) )
|
||||
{
|
||||
String result = canonical.substring( prefix.length() + 1, canonical.length() - 5 );
|
||||
|
||||
result = result.replace( '/', '.' );
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
File t = new File( sourceDir, fileName );
|
||||
|
||||
if ( t.exists() )
|
||||
{
|
||||
str = t.getCanonicalPath().replace( '\\', '/' );
|
||||
|
||||
String result = str.substring( prefix.length() + 1, str.length() - 5 ).replace( '/', '.' );
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( fileName.endsWith( ".java" ) )
|
||||
{
|
||||
fileName = fileName.substring( 0, fileName.length() - 5 );
|
||||
}
|
||||
|
||||
fileName = fileName.replace( '\\', '.' );
|
||||
|
||||
return fileName.replace( '/', '.' );
|
||||
}
|
||||
|
||||
protected String[] toStringArray( List arguments )
|
||||
{
|
||||
String[] args = new String[arguments.size()];
|
||||
|
||||
for ( int i = 0; i < arguments.size(); i++ )
|
||||
{
|
||||
args[i] = (String) arguments.get( i );
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,235 @@
|
|||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
public class ArtifactDownloader
|
||||
{
|
||||
public static final String SNAPSHOT_SIGNATURE = "-SNAPSHOT";
|
||||
|
||||
private File mavenRepoLocal;
|
||||
|
||||
private List remoteRepos;
|
||||
|
||||
private boolean useTimestamp = true;
|
||||
|
||||
private boolean ignoreErrors = true;
|
||||
|
||||
private String proxyHost;
|
||||
|
||||
private String proxyPort;
|
||||
|
||||
private String proxyUserName;
|
||||
|
||||
private String proxyPassword;
|
||||
|
||||
public ArtifactDownloader( Properties properties ) throws Exception
|
||||
{
|
||||
setRemoteRepo( properties.getProperty( "maven.repo.remote" ) );
|
||||
|
||||
String mavenRepoLocalProperty = properties.getProperty( "maven.repo.local" );
|
||||
|
||||
if ( mavenRepoLocalProperty == null )
|
||||
{
|
||||
mavenRepoLocalProperty = System.getProperty( "user.home" ) + "/.maven/repository";
|
||||
}
|
||||
|
||||
mavenRepoLocal = new File( mavenRepoLocalProperty );
|
||||
|
||||
if ( !mavenRepoLocal.exists() )
|
||||
{
|
||||
if ( !mavenRepoLocal.mkdirs() )
|
||||
{
|
||||
System.err.println( "Cannot create the specified maven.repo.local: " + mavenRepoLocal );
|
||||
|
||||
System.exit( 1 );
|
||||
}
|
||||
}
|
||||
|
||||
if ( !mavenRepoLocal.canWrite() )
|
||||
{
|
||||
System.err.println( "Can't write to " + mavenRepoLocal.getAbsolutePath() );
|
||||
|
||||
System.exit( 1 );
|
||||
}
|
||||
|
||||
writeFile( "bootstrap.repo", mavenRepoLocal.getPath() );
|
||||
|
||||
System.out.println( "Using the following for your maven.repo.local: " + mavenRepoLocal );
|
||||
}
|
||||
|
||||
private void writeFile( String name, String contents )
|
||||
throws Exception
|
||||
{
|
||||
Writer writer = new FileWriter( name );
|
||||
|
||||
writer.write( contents );
|
||||
|
||||
writer.close();
|
||||
}
|
||||
|
||||
public File getMavenRepoLocal()
|
||||
{
|
||||
return mavenRepoLocal;
|
||||
}
|
||||
|
||||
public void downloadDependencies( List files )
|
||||
throws Exception
|
||||
{
|
||||
for ( Iterator j = files.iterator(); j.hasNext(); )
|
||||
{
|
||||
try
|
||||
{
|
||||
String file = (String) j.next();
|
||||
|
||||
File destinationFile = new File( mavenRepoLocal, file );
|
||||
|
||||
// The directory structure for this project may
|
||||
// not exists so create it if missing.
|
||||
File directory = destinationFile.getParentFile();
|
||||
|
||||
if ( directory.exists() == false )
|
||||
{
|
||||
directory.mkdirs();
|
||||
}
|
||||
|
||||
if ( destinationFile.exists() && file.indexOf( SNAPSHOT_SIGNATURE ) < 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//log( "Downloading dependency: " + file );
|
||||
|
||||
getRemoteArtifact( file, destinationFile );
|
||||
|
||||
if ( !destinationFile.exists() )
|
||||
{
|
||||
throw new Exception( "Failed to download " + file );
|
||||
}
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
throw new Exception( e );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setRemoteRepo( String repos )
|
||||
{
|
||||
remoteRepos = new ArrayList();
|
||||
|
||||
if ( repos == null )
|
||||
{
|
||||
remoteRepos.add( "http://www.ibiblio.org/maven/" );
|
||||
return;
|
||||
}
|
||||
|
||||
StringTokenizer st = new StringTokenizer( repos, "," );
|
||||
while ( st.hasMoreTokens() )
|
||||
{
|
||||
remoteRepos.add( st.nextToken().trim() );
|
||||
}
|
||||
}
|
||||
|
||||
private List getRemoteRepo()
|
||||
{
|
||||
return remoteRepos;
|
||||
}
|
||||
|
||||
private boolean getRemoteArtifact( String file, File destinationFile )
|
||||
{
|
||||
boolean fileFound = false;
|
||||
|
||||
for ( Iterator i = getRemoteRepo().iterator(); i.hasNext(); )
|
||||
{
|
||||
String remoteRepo = (String) i.next();
|
||||
|
||||
// The username and password parameters are not being
|
||||
// used here. Those are the "" parameters you see below.
|
||||
String url = remoteRepo + "/" + file;
|
||||
|
||||
if ( !url.startsWith( "file" ) )
|
||||
{
|
||||
url = replace( url, "//", "/" );
|
||||
if ( url.startsWith( "https" ) )
|
||||
{
|
||||
url = replace( url, "https:/", "https://" );
|
||||
}
|
||||
else
|
||||
{
|
||||
url = replace( url, "http:/", "http://" );
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to retrieve the artifact and set the checksum if retrieval
|
||||
// of the checksum file was successful.
|
||||
try
|
||||
{
|
||||
HttpUtils.getFile( url,
|
||||
destinationFile,
|
||||
ignoreErrors,
|
||||
useTimestamp,
|
||||
proxyHost,
|
||||
proxyPort,
|
||||
proxyUserName,
|
||||
proxyPassword,
|
||||
true );
|
||||
|
||||
// Artifact was found, continue checking additional remote repos (if any)
|
||||
// in case there is a newer version (i.e. snapshots) in another repo
|
||||
fileFound = true;
|
||||
}
|
||||
catch ( FileNotFoundException e )
|
||||
{
|
||||
// Ignore
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
// If there are additional remote repos, then ignore exception
|
||||
// as artifact may be found in another remote repo. If there
|
||||
// are no more remote repos to check and the artifact wasn't found in
|
||||
// a previous remote repo, then artifactFound is false indicating
|
||||
// that the artifact could not be found in any of the remote repos
|
||||
//
|
||||
// arguably, we need to give the user better control (another command-
|
||||
// line switch perhaps) of what to do in this case? Maven already has
|
||||
// a command-line switch to work in offline mode, but what about when
|
||||
// one of two or more remote repos is unavailable? There may be multiple
|
||||
// remote repos for redundancy, in which case you probably want the build
|
||||
// to continue. There may however be multiple remote repos because some
|
||||
// artifacts are on one, and some are on another. In this case, you may
|
||||
// want the build to break.
|
||||
//
|
||||
// print a warning, in any case, so user catches on to mistyped
|
||||
// hostnames, or other snafus
|
||||
log( "Error retrieving artifact from [" + url + "]: " );
|
||||
}
|
||||
}
|
||||
|
||||
return fileFound;
|
||||
}
|
||||
|
||||
private String replace( String text, String repl, String with )
|
||||
{
|
||||
StringBuffer buf = new StringBuffer( text.length() );
|
||||
int start = 0, end = 0;
|
||||
while ( ( end = text.indexOf( repl, start ) ) != -1 )
|
||||
{
|
||||
buf.append( text.substring( start, end ) ).append( with );
|
||||
start = end + repl.length();
|
||||
}
|
||||
buf.append( text.substring( start ) );
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private void log( String message )
|
||||
{
|
||||
System.out.println( message );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,386 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
* Copyright 2001-2004 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.
|
||||
* ====================================================================
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
// import org.apache.commons.logging.Log;
|
||||
// import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Encode/Decode Base-64.
|
||||
*
|
||||
* @author John Casey
|
||||
*/
|
||||
public final class Base64
|
||||
{
|
||||
|
||||
// private static final Log LOG = LogFactory.getLog( Base64.class );
|
||||
|
||||
private static final String CRLF = System.getProperty( "line.separator" );
|
||||
|
||||
private static final int LINE_END = 64;
|
||||
|
||||
public static String encode( byte[] data )
|
||||
{
|
||||
return Base64.encode( data, true );
|
||||
}
|
||||
|
||||
public static String encode( byte[] data, boolean useLineDelimiter )
|
||||
{
|
||||
if ( data == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else if ( data.length == 0 )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
int padding = 3 - ( data.length % 3 );
|
||||
|
||||
// if ( LOG.isDebugEnabled() )
|
||||
// {
|
||||
// LOG.debug( "padding = " + padding + "characters." );
|
||||
// }
|
||||
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
|
||||
for ( int i = 0; i < data.length; i += 3 )
|
||||
{
|
||||
// if ( LOG.isDebugEnabled() )
|
||||
// {
|
||||
// LOG.debug( "iteration base offset = " + i );
|
||||
// }
|
||||
|
||||
int neutral = ( data[i] < 0 ? data[i] + 256 : data[i] );
|
||||
|
||||
int block = ( neutral & 0xff );
|
||||
// if ( LOG.isDebugEnabled() )
|
||||
// {
|
||||
// LOG.debug( "after first byte, block = " + Integer.toBinaryString( block ) );
|
||||
// }
|
||||
|
||||
boolean inLastSegment = false;
|
||||
|
||||
block <<= 8;
|
||||
if ( i + 1 < data.length )
|
||||
{
|
||||
neutral = ( data[i + 1] < 0 ? data[i + 1] + 256 : data[i + 1] );
|
||||
block |= ( neutral & 0xff );
|
||||
}
|
||||
else
|
||||
{
|
||||
inLastSegment = true;
|
||||
}
|
||||
// if ( LOG.isDebugEnabled() )
|
||||
// {
|
||||
// LOG.debug( "after second byte, block = " + Integer.toBinaryString( block ) + "; inLastSegment = "
|
||||
// + inLastSegment );
|
||||
// }
|
||||
|
||||
block <<= 8;
|
||||
if ( i + 2 < data.length )
|
||||
{
|
||||
neutral = ( data[i + 2] < 0 ? data[i + 2] + 256 : data[i + 2] );
|
||||
block |= ( neutral & 0xff );
|
||||
}
|
||||
else
|
||||
{
|
||||
inLastSegment = true;
|
||||
}
|
||||
// if ( LOG.isDebugEnabled() )
|
||||
// {
|
||||
// LOG.debug( "after third byte, block = " + Integer.toBinaryString( block ) + "; inLastSegment = "
|
||||
// + inLastSegment );
|
||||
// }
|
||||
|
||||
char[] encoded = new char[4];
|
||||
int encIdx = 0;
|
||||
encoded[0] = toBase64Char( ( block >>> 18 ) & 0x3f );
|
||||
// if ( LOG.isDebugEnabled() )
|
||||
// {
|
||||
// LOG.debug( "first character = " + encoded[0] );
|
||||
// }
|
||||
|
||||
encoded[1] = toBase64Char( ( block >>> 12 ) & 0x3f );
|
||||
// if ( LOG.isDebugEnabled() )
|
||||
// {
|
||||
// LOG.debug( "second character = " + encoded[1] );
|
||||
// }
|
||||
|
||||
if ( inLastSegment && padding > 1 )
|
||||
{
|
||||
encoded[2] = '=';
|
||||
}
|
||||
else
|
||||
{
|
||||
encoded[2] = toBase64Char( ( block >>> 6 ) & 0x3f );
|
||||
}
|
||||
// if ( LOG.isDebugEnabled() )
|
||||
// {
|
||||
// LOG.debug( "third character = " + encoded[2] );
|
||||
// }
|
||||
|
||||
if ( inLastSegment && padding > 0 )
|
||||
{
|
||||
encoded[3] = '=';
|
||||
}
|
||||
else
|
||||
{
|
||||
encoded[3] = toBase64Char( block & 0x3f );
|
||||
}
|
||||
// if ( LOG.isDebugEnabled() )
|
||||
// {
|
||||
// LOG.debug( "fourth character = " + encoded[3] );
|
||||
// }
|
||||
|
||||
buffer.append( encoded );
|
||||
}
|
||||
|
||||
if ( useLineDelimiter )
|
||||
{
|
||||
return canonicalize( buffer.toString() );
|
||||
}
|
||||
else
|
||||
{
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] decode( String src )
|
||||
{
|
||||
return Base64.decode( src, true );
|
||||
}
|
||||
|
||||
public static byte[] decode( String src, boolean useLineDelimiter )
|
||||
{
|
||||
if ( src == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else if ( src.length() < 1 )
|
||||
{
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
// if ( LOG.isDebugEnabled() )
|
||||
// {
|
||||
// LOG.debug( "pre-canonicalization = \n" + src );
|
||||
// }
|
||||
String data = src;
|
||||
|
||||
if ( useLineDelimiter )
|
||||
{
|
||||
data = deCanonicalize( src );
|
||||
}
|
||||
// if ( LOG.isDebugEnabled() )
|
||||
// {
|
||||
// LOG.debug( "post-canonicalization = \n" + data );
|
||||
// }
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
|
||||
char[] input = data.toCharArray();
|
||||
|
||||
int index = 0;
|
||||
for ( int i = 0; i < input.length; i += 4 )
|
||||
{
|
||||
// if ( LOG.isDebugEnabled() )
|
||||
// {
|
||||
// LOG.debug( "iteration base offset = " + i );
|
||||
// }
|
||||
|
||||
int block = ( toBase64Int( input[i] ) & 0x3f );
|
||||
// if ( LOG.isDebugEnabled() )
|
||||
// {
|
||||
// LOG.debug( "block after first char [" + input[i] + "] = " + Integer.toBinaryString( block ) );
|
||||
// }
|
||||
|
||||
block <<= 6;
|
||||
block |= ( toBase64Int( input[i + 1] ) & 0x3f );
|
||||
// if ( LOG.isDebugEnabled() )
|
||||
// {
|
||||
// LOG.debug( "block after second char [" + input[i + 1] + "] = " + Integer.toBinaryString( block ) );
|
||||
// }
|
||||
|
||||
boolean inPadding = false;
|
||||
boolean twoCharPadding = false;
|
||||
block <<= 6;
|
||||
if ( input[i + 2] != '=' )
|
||||
{
|
||||
block |= ( toBase64Int( input[i + 2] ) & 0x3f );
|
||||
}
|
||||
else
|
||||
{
|
||||
twoCharPadding = true;
|
||||
inPadding = true;
|
||||
}
|
||||
|
||||
// if ( LOG.isDebugEnabled() )
|
||||
// {
|
||||
// LOG.debug( "block after third char [" + input[i + 2] + "] = " + Integer.toBinaryString( block ) );
|
||||
// }
|
||||
|
||||
block <<= 6;
|
||||
if ( input[i + 3] != '=' )
|
||||
{
|
||||
block |= ( toBase64Int( input[i + 3] ) & 0x3f );
|
||||
}
|
||||
else
|
||||
{
|
||||
inPadding = true;
|
||||
}
|
||||
|
||||
// if ( LOG.isDebugEnabled() )
|
||||
// {
|
||||
// LOG.debug( "block after fourth char [" + input[i + 3] + "] = " + Integer.toBinaryString( block ) );
|
||||
// }
|
||||
|
||||
baos.write( ( block >>> 16 ) & 0xff );
|
||||
// if ( LOG.isDebugEnabled() )
|
||||
// {
|
||||
// LOG.debug( "byte[" + ( index++ ) + "] = " + ( ( block >>> 16 ) & 0xff ) );
|
||||
// }
|
||||
|
||||
if ( !inPadding || !twoCharPadding )
|
||||
{
|
||||
baos.write( ( block >>> 8 ) & 0xff );
|
||||
// if ( LOG.isDebugEnabled() )
|
||||
// {
|
||||
// LOG.debug( "byte[" + ( index++ ) + "] = " + ( ( block >>> 8 ) & 0xff ) );
|
||||
// }
|
||||
}
|
||||
|
||||
if ( !inPadding )
|
||||
{
|
||||
baos.write( block & 0xff );
|
||||
// if ( LOG.isDebugEnabled() )
|
||||
// {
|
||||
// LOG.debug( "byte[" + ( index++ ) + "] = " + ( block & 0xff ) );
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
byte[] result = baos.toByteArray();
|
||||
// if ( LOG.isDebugEnabled() )
|
||||
// {
|
||||
// LOG.debug( "byte array is " + result.length + " bytes long." );
|
||||
// }
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static char toBase64Char( int input )
|
||||
{
|
||||
if ( input > -1 && input < 26 )
|
||||
{
|
||||
return (char) ( 'A' + input );
|
||||
}
|
||||
else if ( input > 25 && input < 52 )
|
||||
{
|
||||
return (char) ( 'a' + input - 26 );
|
||||
}
|
||||
else if ( input > 51 && input < 62 )
|
||||
{
|
||||
return (char) ( '0' + input - 52 );
|
||||
}
|
||||
else if ( input == 62 )
|
||||
{
|
||||
return '+';
|
||||
}
|
||||
else if ( input == 63 )
|
||||
{
|
||||
return '/';
|
||||
}
|
||||
else
|
||||
{
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
|
||||
private static int toBase64Int( char input )
|
||||
{
|
||||
if ( input >= 'A' && input <= 'Z' )
|
||||
{
|
||||
return input - 'A';
|
||||
}
|
||||
else if ( input >= 'a' && input <= 'z' )
|
||||
{
|
||||
return input + 26 - 'a';
|
||||
}
|
||||
else if ( input >= '0' && input <= '9' )
|
||||
{
|
||||
return input + 52 - '0';
|
||||
}
|
||||
else if ( input == '+' )
|
||||
{
|
||||
return 62;
|
||||
}
|
||||
else if ( input == '/' )
|
||||
{
|
||||
return 63;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static String deCanonicalize( String data )
|
||||
{
|
||||
if ( data == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
StringBuffer buffer = new StringBuffer( data.length() );
|
||||
for ( int i = 0; i < data.length(); i++ )
|
||||
{
|
||||
char c = data.charAt( i );
|
||||
if ( c != '\r' && c != '\n' )
|
||||
{
|
||||
buffer.append( c );
|
||||
}
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
private static String canonicalize( String data )
|
||||
{
|
||||
StringBuffer buffer = new StringBuffer( (int) ( data.length() * 1.1 ) );
|
||||
|
||||
int col = 0;
|
||||
for ( int i = 0; i < data.length(); i++ )
|
||||
{
|
||||
if ( col == LINE_END )
|
||||
{
|
||||
buffer.append( CRLF );
|
||||
col = 0;
|
||||
}
|
||||
|
||||
buffer.append( data.charAt( i ) );
|
||||
col++;
|
||||
}
|
||||
|
||||
buffer.append( CRLF );
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,606 @@
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* Commandline objects help handling command lines specifying processes to
|
||||
* execute.
|
||||
*
|
||||
* The class can be used to define a command line as nested elements or as a
|
||||
* helper to define a command line by an application.
|
||||
* <p>
|
||||
* <code>
|
||||
* <someelement><br>
|
||||
* <acommandline executable="/executable/to/run"><br>
|
||||
* <argument value="argument 1" /><br>
|
||||
* <argument line="argument_1 argument_2 argument_3" /><br>
|
||||
* <argument value="argument 4" /><br>
|
||||
* </acommandline><br>
|
||||
* </someelement><br>
|
||||
* </code>
|
||||
* The element <code>someelement</code> must provide a method
|
||||
* <code>createAcommandline</code> which returns an instance of this class.
|
||||
*
|
||||
* @author thomas.haas@softwired-inc.com
|
||||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
|
||||
*/
|
||||
public class Commandline implements Cloneable
|
||||
{
|
||||
|
||||
protected static final String OS_NAME = "os.name";
|
||||
protected static final String WINDOWS = "Windows";
|
||||
|
||||
private String shell = null;
|
||||
private Vector shellArgs = new Vector();
|
||||
private String executable = null;
|
||||
private Vector arguments = new Vector();
|
||||
private File workingDir = null;
|
||||
|
||||
public Commandline( String toProcess )
|
||||
{
|
||||
super();
|
||||
setDefaultShell();
|
||||
String[] tmp = new String[0];
|
||||
try
|
||||
{
|
||||
tmp = translateCommandline( toProcess );
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
System.err.println( "Error translating Commandline." );
|
||||
}
|
||||
if ( tmp != null && tmp.length > 0 )
|
||||
{
|
||||
setExecutable( tmp[0] );
|
||||
for ( int i = 1; i < tmp.length; i++ )
|
||||
{
|
||||
createArgument().setValue( tmp[i] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Commandline()
|
||||
{
|
||||
super();
|
||||
setDefaultShell();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for nested xml command line definitions.
|
||||
*/
|
||||
public static class Argument
|
||||
{
|
||||
|
||||
private String[] parts;
|
||||
|
||||
/**
|
||||
* Sets a single commandline argument.
|
||||
*
|
||||
* @param value a single commandline argument.
|
||||
*/
|
||||
public void setValue( String value )
|
||||
{
|
||||
parts = new String[]{value};
|
||||
}
|
||||
|
||||
/**
|
||||
* Line to split into several commandline arguments.
|
||||
*
|
||||
* @param line line to split into several commandline arguments
|
||||
*/
|
||||
public void setLine( String line )
|
||||
{
|
||||
if ( line == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
parts = translateCommandline( line );
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
System.err.println( "Error translating Commandline." );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a single commandline argument to the absolute filename
|
||||
* of the given file.
|
||||
*
|
||||
* @param value a single commandline argument.
|
||||
*/
|
||||
public void setFile( File value )
|
||||
{
|
||||
parts = new String[]{value.getAbsolutePath()};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parts this Argument consists of.
|
||||
*/
|
||||
public String[] getParts()
|
||||
{
|
||||
return parts;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class to keep track of the position of an Argument.
|
||||
*/
|
||||
// <p>This class is there to support the srcfile and targetfile
|
||||
// elements of <execon> and <transform> - don't know
|
||||
// whether there might be additional use cases.</p> --SB
|
||||
public class Marker
|
||||
{
|
||||
|
||||
private int position;
|
||||
private int realPos = -1;
|
||||
|
||||
Marker( int position )
|
||||
{
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of arguments that preceeded this marker.
|
||||
*
|
||||
* <p>The name of the executable - if set - is counted as the
|
||||
* very first argument.</p>
|
||||
*/
|
||||
public int getPosition()
|
||||
{
|
||||
if ( realPos == -1 )
|
||||
{
|
||||
realPos = ( executable == null ? 0 : 1 );
|
||||
for ( int i = 0; i < position; i++ )
|
||||
{
|
||||
Argument arg = (Argument) arguments.elementAt( i );
|
||||
realPos += arg.getParts().length;
|
||||
}
|
||||
}
|
||||
return realPos;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>Sets the shell or command-line interpretor for the detected operating system,
|
||||
* and the shell arguments.</p>
|
||||
*/
|
||||
private void setDefaultShell() {
|
||||
String os = System.getProperty(OS_NAME);
|
||||
|
||||
//If this is windows set the shell to command.com or cmd.exe with correct arguments.
|
||||
if ( os.indexOf(WINDOWS) != -1 )
|
||||
{
|
||||
if (os.indexOf("95") != -1 || os.indexOf("98") != -1 || os.indexOf("Me") != -1)
|
||||
{
|
||||
shell = "COMMAND.COM";
|
||||
shellArgs.add("/C");
|
||||
}
|
||||
else
|
||||
{
|
||||
shell = "CMD.EXE";
|
||||
shellArgs.add("/X");
|
||||
shellArgs.add("/C");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Gets the shell or command-line interpretor for the detected operating system,
|
||||
* and the shell arguments.</p>
|
||||
*/
|
||||
private String getDefaultShell()
|
||||
{
|
||||
if ( shell != null )
|
||||
{
|
||||
String args = "";
|
||||
for (Enumeration enums = shellArgs.elements(); enums.hasMoreElements(); )
|
||||
{
|
||||
args += (String)enums.nextElement();
|
||||
if (enums.hasMoreElements())
|
||||
{
|
||||
args += " ";
|
||||
}
|
||||
}
|
||||
|
||||
if (args.length() > 0)
|
||||
{
|
||||
return shell + " " + args;
|
||||
}
|
||||
else
|
||||
{
|
||||
return shell;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an argument object.
|
||||
*
|
||||
* <p>Each commandline object has at most one instance of the
|
||||
* argument class. This method calls
|
||||
* <code>this.createArgument(false)</code>.</p>
|
||||
*
|
||||
* @see #createArgument(boolean)
|
||||
* @return the argument object.
|
||||
*/
|
||||
public Argument createArgument()
|
||||
{
|
||||
return this.createArgument( false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an argument object and adds it to our list of args.
|
||||
*
|
||||
* <p>Each commandline object has at most one instance of the
|
||||
* argument class.</p>
|
||||
*
|
||||
* @param insertAtStart if true, the argument is inserted at the
|
||||
* beginning of the list of args, otherwise it is appended.
|
||||
*/
|
||||
public Argument createArgument( boolean insertAtStart )
|
||||
{
|
||||
Argument argument = new Argument();
|
||||
if ( insertAtStart )
|
||||
{
|
||||
arguments.insertElementAt( argument, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
arguments.addElement( argument );
|
||||
}
|
||||
return argument;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the executable to run.
|
||||
*/
|
||||
public void setExecutable( String executable )
|
||||
{
|
||||
if ( executable == null || executable.length() == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
this.executable =
|
||||
executable.replace( '/', File.separatorChar ).replace( '\\', File.separatorChar );
|
||||
}
|
||||
|
||||
public String getExecutable()
|
||||
{
|
||||
return executable;
|
||||
}
|
||||
|
||||
public void addArguments( String[] line )
|
||||
{
|
||||
for ( int i = 0; i < line.length; i++ )
|
||||
{
|
||||
createArgument().setValue( line[i] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the executable and all defined arguments.
|
||||
*/
|
||||
public String[] getCommandline()
|
||||
{
|
||||
final String[] args = getArguments();
|
||||
if ( executable == null )
|
||||
{
|
||||
return args;
|
||||
}
|
||||
final String[] result = new String[args.length + 1];
|
||||
result[0] = executable;
|
||||
System.arraycopy( args, 0, result, 1, args.length );
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shell, executable and all defined arguments.
|
||||
*/
|
||||
public String[] getShellCommandline()
|
||||
{
|
||||
int shellCount = 0;
|
||||
int arrayPos = 0;
|
||||
if ( shell != null )
|
||||
{
|
||||
shellCount = 1;
|
||||
}
|
||||
shellCount += shellArgs.size();
|
||||
final String[] args = getArguments();
|
||||
|
||||
String[] result = new String[shellCount + args.length + (( executable == null )? 0:1)];
|
||||
//Build shell and arguments into result
|
||||
if ( shell != null )
|
||||
{
|
||||
result[0] = shell;
|
||||
arrayPos++;
|
||||
}
|
||||
System.arraycopy( shellArgs.toArray(), 0, result, arrayPos, shellArgs.size() );
|
||||
arrayPos += shellArgs.size();
|
||||
//Build excutable and arguments into result
|
||||
if ( executable != null )
|
||||
{
|
||||
result[arrayPos] = executable;
|
||||
arrayPos++;
|
||||
}
|
||||
System.arraycopy( args, 0, result, arrayPos, args.length );
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all arguments defined by <code>addLine</code>,
|
||||
* <code>addValue</code> or the argument object.
|
||||
*/
|
||||
public String[] getArguments()
|
||||
{
|
||||
Vector result = new Vector( arguments.size() * 2 );
|
||||
for ( int i = 0; i < arguments.size(); i++ )
|
||||
{
|
||||
Argument arg = (Argument) arguments.elementAt( i );
|
||||
String[] s = arg.getParts();
|
||||
if ( s != null )
|
||||
{
|
||||
for ( int j = 0; j < s.length; j++ )
|
||||
{
|
||||
result.addElement( s[j] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String[] res = new String[result.size()];
|
||||
result.copyInto( res );
|
||||
return res;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return toString( getCommandline() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Put quotes around the given String if necessary.
|
||||
*
|
||||
* <p>If the argument doesn't include spaces or quotes, return it
|
||||
* as is. If it contains double quotes, use single quotes - else
|
||||
* surround the argument by double quotes.</p>
|
||||
*
|
||||
* @exception Exception if the argument contains both, single
|
||||
* and double quotes.
|
||||
*/
|
||||
public static String quoteArgument( String argument ) throws Exception
|
||||
{
|
||||
if ( argument.indexOf( "\"" ) > -1 )
|
||||
{
|
||||
if ( argument.indexOf( "\'" ) > -1 )
|
||||
{
|
||||
throw new Exception( "Can't handle single and double quotes in same argument" );
|
||||
}
|
||||
else
|
||||
{
|
||||
return '\'' + argument + '\'';
|
||||
}
|
||||
}
|
||||
else if ( argument.indexOf( "\'" ) > -1 || argument.indexOf( " " ) > -1 )
|
||||
{
|
||||
return '\"' + argument + '\"';
|
||||
}
|
||||
else
|
||||
{
|
||||
return argument;
|
||||
}
|
||||
}
|
||||
|
||||
public static String toString( String[] line )
|
||||
{
|
||||
// empty path return empty string
|
||||
if ( line == null || line.length == 0 )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
// path containing one or more elements
|
||||
final StringBuffer result = new StringBuffer();
|
||||
for ( int i = 0; i < line.length; i++ )
|
||||
{
|
||||
if ( i > 0 )
|
||||
{
|
||||
result.append( ' ' );
|
||||
}
|
||||
try
|
||||
{
|
||||
result.append( quoteArgument( line[i] ) );
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
System.err.println( "Error quoting argument." );
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public static String[] translateCommandline( String toProcess ) throws Exception
|
||||
{
|
||||
if ( toProcess == null || toProcess.length() == 0 )
|
||||
{
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
// parse with a simple finite state machine
|
||||
|
||||
final int normal = 0;
|
||||
final int inQuote = 1;
|
||||
final int inDoubleQuote = 2;
|
||||
int state = normal;
|
||||
StringTokenizer tok = new StringTokenizer( toProcess, "\"\' ", true );
|
||||
Vector v = new Vector();
|
||||
StringBuffer current = new StringBuffer();
|
||||
|
||||
while ( tok.hasMoreTokens() )
|
||||
{
|
||||
String nextTok = tok.nextToken();
|
||||
switch ( state )
|
||||
{
|
||||
case inQuote:
|
||||
if ( "\'".equals( nextTok ) )
|
||||
{
|
||||
state = normal;
|
||||
}
|
||||
else
|
||||
{
|
||||
current.append( nextTok );
|
||||
}
|
||||
break;
|
||||
case inDoubleQuote:
|
||||
if ( "\"".equals( nextTok ) )
|
||||
{
|
||||
state = normal;
|
||||
}
|
||||
else
|
||||
{
|
||||
current.append( nextTok );
|
||||
}
|
||||
break;
|
||||
default :
|
||||
if ( "\'".equals( nextTok ) )
|
||||
{
|
||||
state = inQuote;
|
||||
}
|
||||
else if ( "\"".equals( nextTok ) )
|
||||
{
|
||||
state = inDoubleQuote;
|
||||
}
|
||||
else if ( " ".equals( nextTok ) )
|
||||
{
|
||||
if ( current.length() != 0 )
|
||||
{
|
||||
v.addElement( current.toString() );
|
||||
current.setLength( 0 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
current.append( nextTok );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( current.length() != 0 )
|
||||
{
|
||||
v.addElement( current.toString() );
|
||||
}
|
||||
|
||||
if ( state == inQuote || state == inDoubleQuote )
|
||||
{
|
||||
throw new Exception( "unbalanced quotes in " + toProcess );
|
||||
}
|
||||
|
||||
String[] args = new String[v.size()];
|
||||
v.copyInto( args );
|
||||
return args;
|
||||
}
|
||||
|
||||
public int size()
|
||||
{
|
||||
return getCommandline().length;
|
||||
}
|
||||
|
||||
public Object clone()
|
||||
{
|
||||
Commandline c = new Commandline();
|
||||
c.setExecutable( executable );
|
||||
c.addArguments( getArguments() );
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear out the whole command line. */
|
||||
public void clear()
|
||||
{
|
||||
executable = null;
|
||||
arguments.removeAllElements();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear out the arguments but leave the executable in place for another operation.
|
||||
*/
|
||||
public void clearArgs()
|
||||
{
|
||||
arguments.removeAllElements();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a marker.
|
||||
*
|
||||
* <p>This marker can be used to locate a position on the
|
||||
* commandline - to insert something for example - when all
|
||||
* parameters have been set.</p>
|
||||
*/
|
||||
public Marker createMarker()
|
||||
{
|
||||
return new Marker( arguments.size() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets execution directory.
|
||||
*/
|
||||
public void setWorkingDirectory( String path )
|
||||
{
|
||||
if ( path != null )
|
||||
{
|
||||
workingDir = new File( path );
|
||||
}
|
||||
}
|
||||
|
||||
public File getWorkingDirectory()
|
||||
{
|
||||
return workingDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the command.
|
||||
*/
|
||||
public Process execute()
|
||||
throws IOException
|
||||
{
|
||||
Process process = null;
|
||||
|
||||
if ( workingDir == null )
|
||||
{
|
||||
System.err.println( "Executing \"" + this + "\"" );
|
||||
process = Runtime.getRuntime().exec( getShellCommandline() );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !workingDir.exists() )
|
||||
{
|
||||
throw new IOException(
|
||||
"Working directory \"" + workingDir.getPath() + "\" does not exist!" );
|
||||
}
|
||||
else if ( !workingDir.isDirectory() )
|
||||
{
|
||||
throw new IOException(
|
||||
"Path \"" + workingDir.getPath() + "\" does not specify a directory." );
|
||||
}
|
||||
|
||||
System.err.println(
|
||||
"Executing \""
|
||||
+ this
|
||||
+ "\" in directory "
|
||||
+ ( workingDir != null ? workingDir.getAbsolutePath() : null ) );
|
||||
process = Runtime.getRuntime().exec( getShellCommandline(), null, workingDir );
|
||||
}
|
||||
|
||||
return process;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
|
||||
/**
|
||||
* This class encapsulates an error message produced by a programming language
|
||||
* processor (whether interpreted or compiled)
|
||||
*
|
||||
* @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
|
||||
* @version CVS $Id$
|
||||
* @since 2.0
|
||||
*/
|
||||
|
||||
public class CompilerError
|
||||
{
|
||||
/**
|
||||
* Is this a severe error or a warning?
|
||||
*/
|
||||
private boolean error;
|
||||
/**
|
||||
* The start line number of the offending program text
|
||||
*/
|
||||
private int startline;
|
||||
/**
|
||||
* The start column number of the offending program text
|
||||
*/
|
||||
private int startcolumn;
|
||||
/**
|
||||
* The end line number of the offending program text
|
||||
*/
|
||||
private int endline;
|
||||
/**
|
||||
* The end column number of the offending program text
|
||||
*/
|
||||
private int endcolumn;
|
||||
/**
|
||||
* The name of the file containing the offending program text
|
||||
*/
|
||||
private String file;
|
||||
/**
|
||||
* The actual error text produced by the language processor
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* The error message constructor.
|
||||
*
|
||||
* @param file The name of the file containing the offending program text
|
||||
* @param error The actual error text produced by the language processor
|
||||
* @param startline The start line number of the offending program text
|
||||
* @param startcolumn The start column number of the offending program text
|
||||
* @param endline The end line number of the offending program text
|
||||
* @param endcolumn The end column number of the offending program text
|
||||
* @param message The actual error text produced by the language processor
|
||||
*/
|
||||
public CompilerError( String file,
|
||||
boolean error,
|
||||
int startline,
|
||||
int startcolumn,
|
||||
int endline,
|
||||
int endcolumn,
|
||||
String message )
|
||||
{
|
||||
this.file = file;
|
||||
this.error = error;
|
||||
this.startline = startline;
|
||||
this.startcolumn = startcolumn;
|
||||
this.endline = endline;
|
||||
this.endcolumn = endcolumn;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
/**
|
||||
* The error message constructor.
|
||||
*
|
||||
* @param message The actual error text produced by the language processor
|
||||
*/
|
||||
public CompilerError( String message )
|
||||
{
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the filename associated with this compiler error.
|
||||
*
|
||||
* @return The filename associated with this compiler error
|
||||
*/
|
||||
public String getFile()
|
||||
{
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert whether this is a severe error or a warning
|
||||
*
|
||||
* @return Whether the error is severe
|
||||
*/
|
||||
public boolean isError()
|
||||
{
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the starting line number of the program text originating this error
|
||||
*
|
||||
* @return The starting line number of the program text originating this error
|
||||
*/
|
||||
public int getStartLine()
|
||||
{
|
||||
return startline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the starting column number of the program text originating this
|
||||
* error
|
||||
*
|
||||
* @return The starting column number of the program text originating this
|
||||
* error
|
||||
*/
|
||||
public int getStartColumn()
|
||||
{
|
||||
return startcolumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ending line number of the program text originating this error
|
||||
*
|
||||
* @return The ending line number of the program text originating this error
|
||||
*/
|
||||
public int getEndLine()
|
||||
{
|
||||
return endline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ending column number of the program text originating this
|
||||
* error
|
||||
*
|
||||
* @return The ending column number of the program text originating this
|
||||
* error
|
||||
*/
|
||||
public int getEndColumn()
|
||||
{
|
||||
return endcolumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the message produced by the language processor
|
||||
*
|
||||
* @return The message produced by the language processor
|
||||
*/
|
||||
public String getMessage()
|
||||
{
|
||||
return message;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return file + ":" + "[" + startline + "," + startcolumn + "] " + message;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,993 @@
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* Class for scanning a directory for files/directories which match certain
|
||||
* criteria.
|
||||
* <p/>
|
||||
* These criteria consist of selectors and patterns which have been specified.
|
||||
* With the selectors you can select which files you want to have included.
|
||||
* Files which are not selected are excluded. With patterns you can include
|
||||
* or exclude files based on their filename.
|
||||
* <p/>
|
||||
* The idea is simple. A given directory is recursively scanned for all files
|
||||
* and directories. Each file/directory is matched against a set of selectors,
|
||||
* including special support for matching against filenames with include and
|
||||
* and exclude patterns. Only files/directories which match at least one
|
||||
* pattern of the include pattern list or other file selector, and don't match
|
||||
* any pattern of the exclude pattern list or fail to match against a required
|
||||
* selector will be placed in the list of files/directories found.
|
||||
* <p/>
|
||||
* When no list of include patterns is supplied, "**" will be used, which
|
||||
* means that everything will be matched. When no list of exclude patterns is
|
||||
* supplied, an empty list is used, such that nothing will be excluded. When
|
||||
* no selectors are supplied, none are applied.
|
||||
* <p/>
|
||||
* The filename pattern matching is done as follows:
|
||||
* The name to be matched is split up in path segments. A path segment is the
|
||||
* name of a directory or file, which is bounded by
|
||||
* <code>File.separator</code> ('/' under UNIX, '\' under Windows).
|
||||
* For example, "abc/def/ghi/xyz.java" is split up in the segments "abc",
|
||||
* "def","ghi" and "xyz.java".
|
||||
* The same is done for the pattern against which should be matched.
|
||||
* <p/>
|
||||
* The segments of the name and the pattern are then matched against each
|
||||
* other. When '**' is used for a path segment in the pattern, it matches
|
||||
* zero or more path segments of the name.
|
||||
* <p/>
|
||||
* There is a special case regarding the use of <code>File.separator</code>s
|
||||
* at the beginning of the pattern and the string to match:<br>
|
||||
* When a pattern starts with a <code>File.separator</code>, the string
|
||||
* to match must also start with a <code>File.separator</code>.
|
||||
* When a pattern does not start with a <code>File.separator</code>, the
|
||||
* string to match may not start with a <code>File.separator</code>.
|
||||
* When one of these rules is not obeyed, the string will not
|
||||
* match.
|
||||
* <p/>
|
||||
* When a name path segment is matched against a pattern path segment, the
|
||||
* following special characters can be used:<br>
|
||||
* '*' matches zero or more characters<br>
|
||||
* '?' matches one character.
|
||||
* <p/>
|
||||
* Examples:
|
||||
* <p/>
|
||||
* "**\*.class" matches all .class files/dirs in a directory tree.
|
||||
* <p/>
|
||||
* "test\a??.java" matches all files/dirs which start with an 'a', then two
|
||||
* more characters and then ".java", in a directory called test.
|
||||
* <p/>
|
||||
* "**" matches everything in a directory tree.
|
||||
* <p/>
|
||||
* "**\test\**\XYZ*" matches all files/dirs which start with "XYZ" and where
|
||||
* there is a parent directory called test (e.g. "abc\test\def\ghi\XYZ123").
|
||||
* <p/>
|
||||
* Case sensitivity may be turned off if necessary. By default, it is
|
||||
* turned on.
|
||||
* <p/>
|
||||
* Example of usage:
|
||||
* <pre>
|
||||
* String[] includes = {"**\\*.class"};
|
||||
* String[] excludes = {"modules\\*\\**"};
|
||||
* ds.setIncludes(includes);
|
||||
* ds.setExcludes(excludes);
|
||||
* ds.setBasedir(new File("test"));
|
||||
* ds.setCaseSensitive(true);
|
||||
* ds.scan();
|
||||
* <p/>
|
||||
* System.out.println("FILES:");
|
||||
* String[] files = ds.getIncludedFiles();
|
||||
* for (int i = 0; i < files.length; i++) {
|
||||
* System.out.println(files[i]);
|
||||
* }
|
||||
* </pre>
|
||||
* This will scan a directory called test for .class files, but excludes all
|
||||
* files in all proper subdirectories of a directory called "modules"
|
||||
*
|
||||
* @author Arnout J. Kuiper
|
||||
* <a href="mailto:ajkuiper@wxs.nl">ajkuiper@wxs.nl</a>
|
||||
* @author Magesh Umasankar
|
||||
* @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a>
|
||||
* @author <a href="mailto:levylambert@tiscali-dsl.de">Antoine Levy-Lambert</a>
|
||||
*/
|
||||
public class DirectoryScanner
|
||||
{
|
||||
/**
|
||||
* Patterns which should be excluded by default.
|
||||
*
|
||||
* @see #addDefaultExcludes()
|
||||
*/
|
||||
protected static final String[] DEFAULTEXCLUDES = {
|
||||
// Miscellaneous typical temporary files
|
||||
"**/*~",
|
||||
"**/#*#",
|
||||
"**/.#*",
|
||||
"**/%*%",
|
||||
"**/._*",
|
||||
|
||||
// CVS
|
||||
"**/CVS",
|
||||
"**/CVS/**",
|
||||
"**/.cvsignore",
|
||||
|
||||
// SCCS
|
||||
"**/SCCS",
|
||||
"**/SCCS/**",
|
||||
|
||||
// Visual SourceSafe
|
||||
"**/vssver.scc",
|
||||
|
||||
// Subversion
|
||||
"**/.svn",
|
||||
"**/.svn/**",
|
||||
|
||||
// Mac
|
||||
"**/.DS_Store"
|
||||
};
|
||||
|
||||
/**
|
||||
* The base directory to be scanned.
|
||||
*/
|
||||
protected File basedir;
|
||||
|
||||
/**
|
||||
* The patterns for the files to be included.
|
||||
*/
|
||||
protected String[] includes;
|
||||
|
||||
/**
|
||||
* The patterns for the files to be excluded.
|
||||
*/
|
||||
protected String[] excludes;
|
||||
|
||||
/**
|
||||
* The files which matched at least one include and no excludes
|
||||
* and were selected.
|
||||
*/
|
||||
protected Vector filesIncluded;
|
||||
|
||||
/**
|
||||
* The files which did not match any includes or selectors.
|
||||
*/
|
||||
protected Vector filesNotIncluded;
|
||||
|
||||
/**
|
||||
* The files which matched at least one include and at least
|
||||
* one exclude.
|
||||
*/
|
||||
protected Vector filesExcluded;
|
||||
|
||||
/**
|
||||
* The directories which matched at least one include and no excludes
|
||||
* and were selected.
|
||||
*/
|
||||
protected Vector dirsIncluded;
|
||||
|
||||
/**
|
||||
* The directories which were found and did not match any includes.
|
||||
*/
|
||||
protected Vector dirsNotIncluded;
|
||||
|
||||
/**
|
||||
* The directories which matched at least one include and at least one
|
||||
* exclude.
|
||||
*/
|
||||
protected Vector dirsExcluded;
|
||||
|
||||
/**
|
||||
* The files which matched at least one include and no excludes and
|
||||
* which a selector discarded.
|
||||
*/
|
||||
protected Vector filesDeselected;
|
||||
|
||||
/**
|
||||
* The directories which matched at least one include and no excludes
|
||||
* but which a selector discarded.
|
||||
*/
|
||||
protected Vector dirsDeselected;
|
||||
|
||||
/**
|
||||
* Whether or not our results were built by a slow scan.
|
||||
*/
|
||||
protected boolean haveSlowResults = false;
|
||||
|
||||
/**
|
||||
* Whether or not the file system should be treated as a case sensitive
|
||||
* one.
|
||||
*/
|
||||
protected boolean isCaseSensitive = true;
|
||||
|
||||
/**
|
||||
* Whether or not symbolic links should be followed.
|
||||
*
|
||||
* @since Ant 1.5
|
||||
*/
|
||||
private boolean followSymlinks = true;
|
||||
|
||||
/**
|
||||
* Whether or not everything tested so far has been included.
|
||||
*/
|
||||
protected boolean everythingIncluded = true;
|
||||
|
||||
/**
|
||||
* Sole constructor.
|
||||
*/
|
||||
public DirectoryScanner()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether or not a given path matches the start of a given
|
||||
* pattern up to the first "**".
|
||||
* <p/>
|
||||
* This is not a general purpose test and should only be used if you
|
||||
* can live with false positives. For example, <code>pattern=**\a</code>
|
||||
* and <code>str=b</code> will yield <code>true</code>.
|
||||
*
|
||||
* @param pattern The pattern to match against. Must not be
|
||||
* <code>null</code>.
|
||||
* @param str The path to match, as a String. Must not be
|
||||
* <code>null</code>.
|
||||
* @return whether or not a given path matches the start of a given
|
||||
* pattern up to the first "**".
|
||||
*/
|
||||
protected static boolean matchPatternStart( String pattern, String str )
|
||||
{
|
||||
return SelectorUtils.matchPatternStart( pattern, str );
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether or not a given path matches the start of a given
|
||||
* pattern up to the first "**".
|
||||
* <p/>
|
||||
* This is not a general purpose test and should only be used if you
|
||||
* can live with false positives. For example, <code>pattern=**\a</code>
|
||||
* and <code>str=b</code> will yield <code>true</code>.
|
||||
*
|
||||
* @param pattern The pattern to match against. Must not be
|
||||
* <code>null</code>.
|
||||
* @param str The path to match, as a String. Must not be
|
||||
* <code>null</code>.
|
||||
* @param isCaseSensitive Whether or not matching should be performed
|
||||
* case sensitively.
|
||||
* @return whether or not a given path matches the start of a given
|
||||
* pattern up to the first "**".
|
||||
*/
|
||||
protected static boolean matchPatternStart( String pattern, String str,
|
||||
boolean isCaseSensitive )
|
||||
{
|
||||
return SelectorUtils.matchPatternStart( pattern, str, isCaseSensitive );
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether or not a given path matches a given pattern.
|
||||
*
|
||||
* @param pattern The pattern to match against. Must not be
|
||||
* <code>null</code>.
|
||||
* @param str The path to match, as a String. Must not be
|
||||
* <code>null</code>.
|
||||
* @return <code>true</code> if the pattern matches against the string,
|
||||
* or <code>false</code> otherwise.
|
||||
*/
|
||||
protected static boolean matchPath( String pattern, String str )
|
||||
{
|
||||
return SelectorUtils.matchPath( pattern, str );
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether or not a given path matches a given pattern.
|
||||
*
|
||||
* @param pattern The pattern to match against. Must not be
|
||||
* <code>null</code>.
|
||||
* @param str The path to match, as a String. Must not be
|
||||
* <code>null</code>.
|
||||
* @param isCaseSensitive Whether or not matching should be performed
|
||||
* case sensitively.
|
||||
* @return <code>true</code> if the pattern matches against the string,
|
||||
* or <code>false</code> otherwise.
|
||||
*/
|
||||
protected static boolean matchPath( String pattern, String str,
|
||||
boolean isCaseSensitive )
|
||||
{
|
||||
return SelectorUtils.matchPath( pattern, str, isCaseSensitive );
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether or not a string matches against a pattern.
|
||||
* The pattern may contain two special characters:<br>
|
||||
* '*' means zero or more characters<br>
|
||||
* '?' means one and only one character
|
||||
*
|
||||
* @param pattern The pattern to match against.
|
||||
* Must not be <code>null</code>.
|
||||
* @param str The string which must be matched against the pattern.
|
||||
* Must not be <code>null</code>.
|
||||
* @return <code>true</code> if the string matches against the pattern,
|
||||
* or <code>false</code> otherwise.
|
||||
*/
|
||||
public static boolean match( String pattern, String str )
|
||||
{
|
||||
return SelectorUtils.match( pattern, str );
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether or not a string matches against a pattern.
|
||||
* The pattern may contain two special characters:<br>
|
||||
* '*' means zero or more characters<br>
|
||||
* '?' means one and only one character
|
||||
*
|
||||
* @param pattern The pattern to match against.
|
||||
* Must not be <code>null</code>.
|
||||
* @param str The string which must be matched against the pattern.
|
||||
* Must not be <code>null</code>.
|
||||
* @param isCaseSensitive Whether or not matching should be performed
|
||||
* case sensitively.
|
||||
* @return <code>true</code> if the string matches against the pattern,
|
||||
* or <code>false</code> otherwise.
|
||||
*/
|
||||
protected static boolean match( String pattern, String str,
|
||||
boolean isCaseSensitive )
|
||||
{
|
||||
return SelectorUtils.match( pattern, str, isCaseSensitive );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the base directory to be scanned. This is the directory which is
|
||||
* scanned recursively. All '/' and '\' characters are replaced by
|
||||
* <code>File.separatorChar</code>, so the separator used need not match
|
||||
* <code>File.separatorChar</code>.
|
||||
*
|
||||
* @param basedir The base directory to scan.
|
||||
* Must not be <code>null</code>.
|
||||
*/
|
||||
public void setBasedir( String basedir )
|
||||
{
|
||||
setBasedir( new File( basedir.replace( '/', File.separatorChar ).replace( '\\', File.separatorChar ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the base directory to be scanned. This is the directory which is
|
||||
* scanned recursively.
|
||||
*
|
||||
* @param basedir The base directory for scanning.
|
||||
* Should not be <code>null</code>.
|
||||
*/
|
||||
public void setBasedir( File basedir )
|
||||
{
|
||||
this.basedir = basedir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the base directory to be scanned.
|
||||
* This is the directory which is scanned recursively.
|
||||
*
|
||||
* @return the base directory to be scanned
|
||||
*/
|
||||
public File getBasedir()
|
||||
{
|
||||
return basedir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether or not the file system should be regarded as case sensitive.
|
||||
*
|
||||
* @param isCaseSensitive whether or not the file system should be
|
||||
* regarded as a case sensitive one
|
||||
*/
|
||||
public void setCaseSensitive( boolean isCaseSensitive )
|
||||
{
|
||||
this.isCaseSensitive = isCaseSensitive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether or not symbolic links should be followed.
|
||||
*
|
||||
* @param followSymlinks whether or not symbolic links should be followed
|
||||
*/
|
||||
public void setFollowSymlinks( boolean followSymlinks )
|
||||
{
|
||||
this.followSymlinks = followSymlinks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the list of include patterns to use. All '/' and '\' characters
|
||||
* are replaced by <code>File.separatorChar</code>, so the separator used
|
||||
* need not match <code>File.separatorChar</code>.
|
||||
* <p/>
|
||||
* When a pattern ends with a '/' or '\', "**" is appended.
|
||||
*
|
||||
* @param includes A list of include patterns.
|
||||
* May be <code>null</code>, indicating that all files
|
||||
* should be included. If a non-<code>null</code>
|
||||
* list is given, all elements must be
|
||||
* non-<code>null</code>.
|
||||
*/
|
||||
public void setIncludes( String[] includes )
|
||||
{
|
||||
if ( includes == null )
|
||||
{
|
||||
this.includes = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.includes = new String[includes.length];
|
||||
for ( int i = 0; i < includes.length; i++ )
|
||||
{
|
||||
String pattern;
|
||||
pattern = includes[i].replace( '/', File.separatorChar ).replace( '\\', File.separatorChar );
|
||||
if ( pattern.endsWith( File.separator ) )
|
||||
{
|
||||
pattern += "**";
|
||||
}
|
||||
this.includes[i] = pattern;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the list of exclude patterns to use. All '/' and '\' characters
|
||||
* are replaced by <code>File.separatorChar</code>, so the separator used
|
||||
* need not match <code>File.separatorChar</code>.
|
||||
* <p/>
|
||||
* When a pattern ends with a '/' or '\', "**" is appended.
|
||||
*
|
||||
* @param excludes A list of exclude patterns.
|
||||
* May be <code>null</code>, indicating that no files
|
||||
* should be excluded. If a non-<code>null</code> list is
|
||||
* given, all elements must be non-<code>null</code>.
|
||||
*/
|
||||
public void setExcludes( String[] excludes )
|
||||
{
|
||||
if ( excludes == null )
|
||||
{
|
||||
this.excludes = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.excludes = new String[excludes.length];
|
||||
for ( int i = 0; i < excludes.length; i++ )
|
||||
{
|
||||
String pattern;
|
||||
pattern = excludes[i].replace( '/', File.separatorChar ).replace( '\\', File.separatorChar );
|
||||
if ( pattern.endsWith( File.separator ) )
|
||||
{
|
||||
pattern += "**";
|
||||
}
|
||||
this.excludes[i] = pattern;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the scanner has included all the files or
|
||||
* directories it has come across so far.
|
||||
*
|
||||
* @return <code>true</code> if all files and directories which have
|
||||
* been found so far have been included.
|
||||
*/
|
||||
public boolean isEverythingIncluded()
|
||||
{
|
||||
return everythingIncluded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the base directory for files which match at least one include
|
||||
* pattern and don't match any exclude patterns. If there are selectors
|
||||
* then the files must pass muster there, as well.
|
||||
*
|
||||
* @throws IllegalStateException if the base directory was set
|
||||
* incorrectly (i.e. if it is <code>null</code>, doesn't exist,
|
||||
* or isn't a directory).
|
||||
*/
|
||||
public void scan() throws IllegalStateException
|
||||
{
|
||||
if ( basedir == null )
|
||||
{
|
||||
throw new IllegalStateException( "No basedir set" );
|
||||
}
|
||||
if ( !basedir.exists() )
|
||||
{
|
||||
throw new IllegalStateException( "basedir " + basedir
|
||||
+ " does not exist" );
|
||||
}
|
||||
if ( !basedir.isDirectory() )
|
||||
{
|
||||
throw new IllegalStateException( "basedir " + basedir
|
||||
+ " is not a directory" );
|
||||
}
|
||||
|
||||
if ( includes == null )
|
||||
{
|
||||
// No includes supplied, so set it to 'matches all'
|
||||
includes = new String[1];
|
||||
includes[0] = "**";
|
||||
}
|
||||
if ( excludes == null )
|
||||
{
|
||||
excludes = new String[0];
|
||||
}
|
||||
|
||||
filesIncluded = new Vector();
|
||||
filesNotIncluded = new Vector();
|
||||
filesExcluded = new Vector();
|
||||
filesDeselected = new Vector();
|
||||
dirsIncluded = new Vector();
|
||||
dirsNotIncluded = new Vector();
|
||||
dirsExcluded = new Vector();
|
||||
dirsDeselected = new Vector();
|
||||
|
||||
if ( isIncluded( "" ) )
|
||||
{
|
||||
if ( !isExcluded( "" ) )
|
||||
{
|
||||
if ( isSelected( "", basedir ) )
|
||||
{
|
||||
dirsIncluded.addElement( "" );
|
||||
}
|
||||
else
|
||||
{
|
||||
dirsDeselected.addElement( "" );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dirsExcluded.addElement( "" );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dirsNotIncluded.addElement( "" );
|
||||
}
|
||||
scandir( basedir, "", true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Top level invocation for a slow scan. A slow scan builds up a full
|
||||
* list of excluded/included files/directories, whereas a fast scan
|
||||
* will only have full results for included files, as it ignores
|
||||
* directories which can't possibly hold any included files/directories.
|
||||
* <p/>
|
||||
* Returns immediately if a slow scan has already been completed.
|
||||
*/
|
||||
protected void slowScan()
|
||||
{
|
||||
if ( haveSlowResults )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
String[] excl = new String[dirsExcluded.size()];
|
||||
dirsExcluded.copyInto( excl );
|
||||
|
||||
String[] notIncl = new String[dirsNotIncluded.size()];
|
||||
dirsNotIncluded.copyInto( notIncl );
|
||||
|
||||
for ( int i = 0; i < excl.length; i++ )
|
||||
{
|
||||
if ( !couldHoldIncluded( excl[i] ) )
|
||||
{
|
||||
scandir( new File( basedir, excl[i] ),
|
||||
excl[i] + File.separator, false );
|
||||
}
|
||||
}
|
||||
|
||||
for ( int i = 0; i < notIncl.length; i++ )
|
||||
{
|
||||
if ( !couldHoldIncluded( notIncl[i] ) )
|
||||
{
|
||||
scandir( new File( basedir, notIncl[i] ),
|
||||
notIncl[i] + File.separator, false );
|
||||
}
|
||||
}
|
||||
|
||||
haveSlowResults = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the given directory for files and directories. Found files and
|
||||
* directories are placed in their respective collections, based on the
|
||||
* matching of includes, excludes, and the selectors. When a directory
|
||||
* is found, it is scanned recursively.
|
||||
*
|
||||
* @param dir The directory to scan. Must not be <code>null</code>.
|
||||
* @param vpath The path relative to the base directory (needed to
|
||||
* prevent problems with an absolute path when using
|
||||
* dir). Must not be <code>null</code>.
|
||||
* @param fast Whether or not this call is part of a fast scan.
|
||||
* @see #filesIncluded
|
||||
* @see #filesNotIncluded
|
||||
* @see #filesExcluded
|
||||
* @see #dirsIncluded
|
||||
* @see #dirsNotIncluded
|
||||
* @see #dirsExcluded
|
||||
* @see #slowScan
|
||||
*/
|
||||
protected void scandir( File dir, String vpath, boolean fast )
|
||||
{
|
||||
String[] newfiles = dir.list();
|
||||
|
||||
if ( newfiles == null )
|
||||
{
|
||||
/*
|
||||
* two reasons are mentioned in the API docs for File.list
|
||||
* (1) dir is not a directory. This is impossible as
|
||||
* we wouldn't get here in this case.
|
||||
* (2) an IO error occurred (why doesn't it throw an exception
|
||||
* then???)
|
||||
*/
|
||||
//throw new Exception( "IO error scanning directory " + dir.getAbsolutePath() );
|
||||
}
|
||||
|
||||
if ( !followSymlinks )
|
||||
{
|
||||
Vector noLinks = new Vector();
|
||||
for ( int i = 0; i < newfiles.length; i++ )
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( isSymbolicLink( dir, newfiles[i] ) )
|
||||
{
|
||||
String name = vpath + newfiles[i];
|
||||
File file = new File( dir, newfiles[i] );
|
||||
if ( file.isDirectory() )
|
||||
{
|
||||
dirsExcluded.addElement( name );
|
||||
}
|
||||
else
|
||||
{
|
||||
filesExcluded.addElement( name );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
noLinks.addElement( newfiles[i] );
|
||||
}
|
||||
}
|
||||
catch ( IOException ioe )
|
||||
{
|
||||
String msg = "IOException caught while checking "
|
||||
+ "for links, couldn't get cannonical path!";
|
||||
// will be caught and redirected to Ant's logging system
|
||||
System.err.println( msg );
|
||||
noLinks.addElement( newfiles[i] );
|
||||
}
|
||||
}
|
||||
newfiles = new String[noLinks.size()];
|
||||
noLinks.copyInto( newfiles );
|
||||
}
|
||||
|
||||
for ( int i = 0; i < newfiles.length; i++ )
|
||||
{
|
||||
String name = vpath + newfiles[i];
|
||||
File file = new File( dir, newfiles[i] );
|
||||
if ( file.isDirectory() )
|
||||
{
|
||||
if ( isIncluded( name ) )
|
||||
{
|
||||
if ( !isExcluded( name ) )
|
||||
{
|
||||
if ( isSelected( name, file ) )
|
||||
{
|
||||
dirsIncluded.addElement( name );
|
||||
if ( fast )
|
||||
{
|
||||
scandir( file, name + File.separator, fast );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
everythingIncluded = false;
|
||||
dirsDeselected.addElement( name );
|
||||
if ( fast && couldHoldIncluded( name ) )
|
||||
{
|
||||
scandir( file, name + File.separator, fast );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
everythingIncluded = false;
|
||||
dirsExcluded.addElement( name );
|
||||
if ( fast && couldHoldIncluded( name ) )
|
||||
{
|
||||
scandir( file, name + File.separator, fast );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
everythingIncluded = false;
|
||||
dirsNotIncluded.addElement( name );
|
||||
if ( fast && couldHoldIncluded( name ) )
|
||||
{
|
||||
scandir( file, name + File.separator, fast );
|
||||
}
|
||||
}
|
||||
if ( !fast )
|
||||
{
|
||||
scandir( file, name + File.separator, fast );
|
||||
}
|
||||
}
|
||||
else if ( file.isFile() )
|
||||
{
|
||||
if ( isIncluded( name ) )
|
||||
{
|
||||
if ( !isExcluded( name ) )
|
||||
{
|
||||
if ( isSelected( name, file ) )
|
||||
{
|
||||
filesIncluded.addElement( name );
|
||||
}
|
||||
else
|
||||
{
|
||||
everythingIncluded = false;
|
||||
filesDeselected.addElement( name );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
everythingIncluded = false;
|
||||
filesExcluded.addElement( name );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
everythingIncluded = false;
|
||||
filesNotIncluded.addElement( name );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether or not a name matches against at least one include
|
||||
* pattern.
|
||||
*
|
||||
* @param name The name to match. Must not be <code>null</code>.
|
||||
* @return <code>true</code> when the name matches against at least one
|
||||
* include pattern, or <code>false</code> otherwise.
|
||||
*/
|
||||
protected boolean isIncluded( String name )
|
||||
{
|
||||
for ( int i = 0; i < includes.length; i++ )
|
||||
{
|
||||
if ( matchPath( includes[i], name, isCaseSensitive ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether or not a name matches the start of at least one include
|
||||
* pattern.
|
||||
*
|
||||
* @param name The name to match. Must not be <code>null</code>.
|
||||
* @return <code>true</code> when the name matches against the start of at
|
||||
* least one include pattern, or <code>false</code> otherwise.
|
||||
*/
|
||||
protected boolean couldHoldIncluded( String name )
|
||||
{
|
||||
for ( int i = 0; i < includes.length; i++ )
|
||||
{
|
||||
if ( matchPatternStart( includes[i], name, isCaseSensitive ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether or not a name matches against at least one exclude
|
||||
* pattern.
|
||||
*
|
||||
* @param name The name to match. Must not be <code>null</code>.
|
||||
* @return <code>true</code> when the name matches against at least one
|
||||
* exclude pattern, or <code>false</code> otherwise.
|
||||
*/
|
||||
protected boolean isExcluded( String name )
|
||||
{
|
||||
for ( int i = 0; i < excludes.length; i++ )
|
||||
{
|
||||
if ( matchPath( excludes[i], name, isCaseSensitive ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether a name should be selected.
|
||||
*
|
||||
* @param name the filename to check for selecting
|
||||
* @param file the java.io.File object for this filename
|
||||
* @return <code>false</code> when the selectors says that the file
|
||||
* should not be selected, <code>true</code> otherwise.
|
||||
*/
|
||||
protected boolean isSelected( String name, File file )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the names of the files which matched at least one of the
|
||||
* include patterns and none of the exclude patterns.
|
||||
* The names are relative to the base directory.
|
||||
*
|
||||
* @return the names of the files which matched at least one of the
|
||||
* include patterns and none of the exclude patterns.
|
||||
*/
|
||||
public String[] getIncludedFiles()
|
||||
{
|
||||
String[] files = new String[filesIncluded.size()];
|
||||
filesIncluded.copyInto( files );
|
||||
return files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the names of the files which matched none of the include
|
||||
* patterns. The names are relative to the base directory. This involves
|
||||
* performing a slow scan if one has not already been completed.
|
||||
*
|
||||
* @return the names of the files which matched none of the include
|
||||
* patterns.
|
||||
* @see #slowScan
|
||||
*/
|
||||
public String[] getNotIncludedFiles()
|
||||
{
|
||||
slowScan();
|
||||
String[] files = new String[filesNotIncluded.size()];
|
||||
filesNotIncluded.copyInto( files );
|
||||
return files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the names of the files which matched at least one of the
|
||||
* include patterns and at least one of the exclude patterns.
|
||||
* The names are relative to the base directory. This involves
|
||||
* performing a slow scan if one has not already been completed.
|
||||
*
|
||||
* @return the names of the files which matched at least one of the
|
||||
* include patterns and at at least one of the exclude patterns.
|
||||
* @see #slowScan
|
||||
*/
|
||||
public String[] getExcludedFiles()
|
||||
{
|
||||
slowScan();
|
||||
String[] files = new String[filesExcluded.size()];
|
||||
filesExcluded.copyInto( files );
|
||||
return files;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the names of the files which were selected out and
|
||||
* therefore not ultimately included.</p>
|
||||
* <p/>
|
||||
* <p>The names are relative to the base directory. This involves
|
||||
* performing a slow scan if one has not already been completed.</p>
|
||||
*
|
||||
* @return the names of the files which were deselected.
|
||||
* @see #slowScan
|
||||
*/
|
||||
public String[] getDeselectedFiles()
|
||||
{
|
||||
slowScan();
|
||||
String[] files = new String[filesDeselected.size()];
|
||||
filesDeselected.copyInto( files );
|
||||
return files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the names of the directories which matched at least one of the
|
||||
* include patterns and none of the exclude patterns.
|
||||
* The names are relative to the base directory.
|
||||
*
|
||||
* @return the names of the directories which matched at least one of the
|
||||
* include patterns and none of the exclude patterns.
|
||||
*/
|
||||
public String[] getIncludedDirectories()
|
||||
{
|
||||
String[] directories = new String[dirsIncluded.size()];
|
||||
dirsIncluded.copyInto( directories );
|
||||
return directories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the names of the directories which matched none of the include
|
||||
* patterns. The names are relative to the base directory. This involves
|
||||
* performing a slow scan if one has not already been completed.
|
||||
*
|
||||
* @return the names of the directories which matched none of the include
|
||||
* patterns.
|
||||
* @see #slowScan
|
||||
*/
|
||||
public String[] getNotIncludedDirectories()
|
||||
{
|
||||
slowScan();
|
||||
String[] directories = new String[dirsNotIncluded.size()];
|
||||
dirsNotIncluded.copyInto( directories );
|
||||
return directories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the names of the directories which matched at least one of the
|
||||
* include patterns and at least one of the exclude patterns.
|
||||
* The names are relative to the base directory. This involves
|
||||
* performing a slow scan if one has not already been completed.
|
||||
*
|
||||
* @return the names of the directories which matched at least one of the
|
||||
* include patterns and at least one of the exclude patterns.
|
||||
* @see #slowScan
|
||||
*/
|
||||
public String[] getExcludedDirectories()
|
||||
{
|
||||
slowScan();
|
||||
String[] directories = new String[dirsExcluded.size()];
|
||||
dirsExcluded.copyInto( directories );
|
||||
return directories;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the names of the directories which were selected out and
|
||||
* therefore not ultimately included.</p>
|
||||
* <p/>
|
||||
* <p>The names are relative to the base directory. This involves
|
||||
* performing a slow scan if one has not already been completed.</p>
|
||||
*
|
||||
* @return the names of the directories which were deselected.
|
||||
* @see #slowScan
|
||||
*/
|
||||
public String[] getDeselectedDirectories()
|
||||
{
|
||||
slowScan();
|
||||
String[] directories = new String[dirsDeselected.size()];
|
||||
dirsDeselected.copyInto( directories );
|
||||
return directories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds default exclusions to the current exclusions set.
|
||||
*/
|
||||
public void addDefaultExcludes()
|
||||
{
|
||||
int excludesLength = excludes == null ? 0 : excludes.length;
|
||||
String[] newExcludes;
|
||||
newExcludes = new String[excludesLength + DEFAULTEXCLUDES.length];
|
||||
if ( excludesLength > 0 )
|
||||
{
|
||||
System.arraycopy( excludes, 0, newExcludes, 0, excludesLength );
|
||||
}
|
||||
for ( int i = 0; i < DEFAULTEXCLUDES.length; i++ )
|
||||
{
|
||||
newExcludes[i + excludesLength] = DEFAULTEXCLUDES[i].replace( '/',
|
||||
File.separatorChar ).replace( '\\', File.separatorChar );
|
||||
}
|
||||
excludes = newExcludes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a given file is a symbolic link.
|
||||
* <p/>
|
||||
* <p>It doesn't really test for symbolic links but whether the
|
||||
* canonical and absolute paths of the file are identical - this
|
||||
* may lead to false positives on some platforms.</p>
|
||||
*
|
||||
* @param parent the parent directory of the file to test
|
||||
* @param name the name of the file to test.
|
||||
* @since Ant 1.5
|
||||
*/
|
||||
public boolean isSymbolicLink( File parent, String name )
|
||||
throws IOException
|
||||
{
|
||||
File resolvedParent = new File( parent.getCanonicalPath() );
|
||||
File toTest = new File( resolvedParent, name );
|
||||
return !toTest.getAbsolutePath().equals( toTest.getCanonicalPath() );
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,398 @@
|
|||
/* ====================================================================
|
||||
* Copyright 2001-2004 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.
|
||||
* ====================================================================
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.Authenticator;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.PasswordAuthentication;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
|
||||
/**
|
||||
* Http utils for retrieving files.
|
||||
*
|
||||
* @author costin@dnt.ro
|
||||
* @author gg@grtmail.com (Added Java 1.1 style HTTP basic auth)
|
||||
* @author <a href="mailto:jason@zenplex.com">Jason van Zyl</a>
|
||||
* @todo Need to add a timeout so we can flip to a backup repository.
|
||||
* @todo Download everything in a single session.
|
||||
* @todo Throw meaningful exception when authentication fails.
|
||||
*/
|
||||
public class HttpUtils
|
||||
{
|
||||
/**
|
||||
* Use a proxy to bypass the firewall with or without authentication
|
||||
*
|
||||
* @param proxyHost Proxy Host (if proxy is required), or null
|
||||
* @param proxyPort Proxy Port (if proxy is required), or null
|
||||
* @param proxyUserName Proxy Username (if authentification is required),
|
||||
* or null
|
||||
* @param proxyPassword Proxy Password (if authentification is required),
|
||||
* or null
|
||||
* @throws SecurityException if an operation is not authorized by the
|
||||
* SecurityManager
|
||||
*/
|
||||
public static void useProxyUser( final String proxyHost,
|
||||
final String proxyPort,
|
||||
final String proxyUserName,
|
||||
final String proxyPassword )
|
||||
{
|
||||
if ( proxyHost != null && proxyPort != null )
|
||||
{
|
||||
System.getProperties().put( "proxySet", "true" );
|
||||
System.getProperties().put( "proxyHost", proxyHost );
|
||||
System.getProperties().put( "proxyPort", proxyPort );
|
||||
|
||||
if ( proxyUserName != null )
|
||||
{
|
||||
Authenticator.setDefault( new Authenticator()
|
||||
{
|
||||
protected PasswordAuthentication getPasswordAuthentication()
|
||||
{
|
||||
return new PasswordAuthentication( proxyUserName,
|
||||
proxyPassword == null ? new char[0] : proxyPassword.toCharArray() );
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a remote file. Throws an Exception on errors unless the
|
||||
* ifnoreErrors flag is set to True
|
||||
*
|
||||
* @param url the of the file to retrieve
|
||||
* @param destinationFile where to store it
|
||||
* @param ignoreErrors whether to ignore errors during I/O or throw an
|
||||
* exception when they happen
|
||||
* @param useTimestamp whether to check the modified timestamp on the
|
||||
* <code>destinationFile</code> against the remote <code>source</code>
|
||||
* @param proxyHost Proxy Host (if proxy is required), or null
|
||||
* @param proxyPort Proxy Port (if proxy is required), or null
|
||||
* @param proxyUserName Proxy Username (if authentification is required),
|
||||
* or null.
|
||||
* @param proxyPassword Proxy Password (if authentification is required),
|
||||
* or null.
|
||||
* @param useChecksum Flag to indicate the use of the checksum for the retrieved
|
||||
* artifact if it is available.
|
||||
* @throws IOException If an I/O exception occurs.
|
||||
*/
|
||||
public static void getFile( String url,
|
||||
File destinationFile,
|
||||
boolean ignoreErrors,
|
||||
boolean useTimestamp,
|
||||
String proxyHost,
|
||||
String proxyPort,
|
||||
String proxyUserName,
|
||||
String proxyPassword,
|
||||
boolean useChecksum )
|
||||
throws IOException
|
||||
{
|
||||
// Get the requested file.
|
||||
getFile( url,
|
||||
destinationFile,
|
||||
ignoreErrors,
|
||||
useTimestamp,
|
||||
proxyHost,
|
||||
proxyPort,
|
||||
proxyUserName,
|
||||
proxyPassword );
|
||||
|
||||
// Get the checksum if requested.
|
||||
if ( useChecksum )
|
||||
{
|
||||
File checksumFile = new File( destinationFile + ".md5" );
|
||||
|
||||
try
|
||||
{
|
||||
getFile( url + ".md5",
|
||||
checksumFile,
|
||||
ignoreErrors,
|
||||
useTimestamp,
|
||||
proxyHost,
|
||||
proxyPort,
|
||||
proxyUserName,
|
||||
proxyPassword );
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
// do nothing we will check later in the process
|
||||
// for the checksums.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a remote file. Throws an Exception on errors unless the
|
||||
* ifnoreErrors flag is set to True
|
||||
*
|
||||
* @param url the of the file to retrieve
|
||||
* @param destinationFile where to store it
|
||||
* @param ignoreErrors whether to ignore errors during I/O or throw an
|
||||
* exception when they happen
|
||||
* @param useTimestamp whether to check the modified timestamp on the
|
||||
* <code>destinationFile</code> against the remote <code>source</code>
|
||||
* @param proxyHost Proxy Host (if proxy is required), or null
|
||||
* @param proxyPort Proxy Port (if proxy is required), or null
|
||||
* @param proxyUserName Proxy Username (if authentification is required),
|
||||
* or null
|
||||
* @param proxyPassword Proxy Password (if authentification is required),
|
||||
* or null
|
||||
* @throws IOException If an I/O exception occurs.
|
||||
*/
|
||||
public static void getFile( String url,
|
||||
File destinationFile,
|
||||
boolean ignoreErrors,
|
||||
boolean useTimestamp,
|
||||
String proxyHost,
|
||||
String proxyPort,
|
||||
String proxyUserName,
|
||||
String proxyPassword )
|
||||
throws IOException
|
||||
{
|
||||
//set the timestamp to the file date.
|
||||
long timestamp = -1;
|
||||
if ( useTimestamp && destinationFile.exists() )
|
||||
{
|
||||
timestamp = destinationFile.lastModified();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
getFile( url,
|
||||
destinationFile,
|
||||
timestamp,
|
||||
proxyHost,
|
||||
proxyPort,
|
||||
proxyUserName,
|
||||
proxyPassword );
|
||||
}
|
||||
catch ( IOException ex )
|
||||
{
|
||||
if ( !ignoreErrors )
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a remote file.
|
||||
*
|
||||
* @param url the URL of the file to retrieve
|
||||
* @param destinationFile where to store it
|
||||
* @param timestamp if provided, the remote URL is only retrieved if it was
|
||||
* modified more recently than timestamp. Otherwise, negative value indicates that
|
||||
* the remote URL should be retrieved unconditionally.
|
||||
* @param proxyHost Proxy Host (if proxy is required), or null
|
||||
* @param proxyPort Proxy Port (if proxy is required), or null
|
||||
* @param proxyUserName Proxy Username (if authentification is required),
|
||||
* or null
|
||||
* @param proxyPassword Proxy Password (if authentification is required),
|
||||
* or null
|
||||
* @throws IOException If an I/O exception occurs.
|
||||
*/
|
||||
public static void getFile( String url,
|
||||
File destinationFile,
|
||||
long timestamp,
|
||||
String proxyHost,
|
||||
String proxyPort,
|
||||
String proxyUserName,
|
||||
String proxyPassword )
|
||||
throws IOException
|
||||
{
|
||||
String[] s = parseUrl( url );
|
||||
String username = s[0];
|
||||
String password = s[1];
|
||||
String parsedUrl = s[2];
|
||||
|
||||
URL source = new URL( parsedUrl );
|
||||
|
||||
//set proxy connection
|
||||
useProxyUser( proxyHost, proxyPort, proxyUserName, proxyPassword );
|
||||
|
||||
//set up the URL connection
|
||||
URLConnection connection = source.openConnection();
|
||||
|
||||
//modify the headers
|
||||
if ( timestamp >= 0 )
|
||||
{
|
||||
connection.setIfModifiedSince( timestamp );
|
||||
}
|
||||
// prepare Java 1.1 style credentials
|
||||
if ( username != null || password != null )
|
||||
{
|
||||
String up = username + ":" + password;
|
||||
String encoding = Base64.encode( up.getBytes(), false );
|
||||
connection.setRequestProperty( "Authorization", "Basic " + encoding );
|
||||
}
|
||||
|
||||
//connect to the remote site (may take some time)
|
||||
connection.connect();
|
||||
//next test for a 304 result (HTTP only)
|
||||
if ( connection instanceof HttpURLConnection )
|
||||
{
|
||||
HttpURLConnection httpConnection = (HttpURLConnection) connection;
|
||||
// although HTTPUrlConnection javadocs says FileNotFoundException should be
|
||||
// thrown on a 404 error, that certainly does not appear to be the case, so
|
||||
// test for 404 ourselves, and throw FileNotFoundException as needed
|
||||
if ( httpConnection.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND )
|
||||
{
|
||||
throw new FileNotFoundException( url.toString() + " (HTTP Error: "
|
||||
+ httpConnection.getResponseCode() + " " + httpConnection.getResponseMessage() + ")" );
|
||||
}
|
||||
if ( httpConnection.getResponseCode() == HttpURLConnection.HTTP_NOT_MODIFIED )
|
||||
{
|
||||
return;
|
||||
}
|
||||
// test for 401 result (HTTP only)
|
||||
if ( httpConnection.getResponseCode() == HttpURLConnection.HTTP_UNAUTHORIZED )
|
||||
{
|
||||
throw new IOException( "Not authorized." );
|
||||
}
|
||||
// test for 407 result (HTTP only)
|
||||
if ( httpConnection.getResponseCode() == HttpURLConnection.HTTP_PROXY_AUTH )
|
||||
{
|
||||
throw new IOException( "Not authorized by proxy." );
|
||||
}
|
||||
}
|
||||
|
||||
// REVISIT: at this point even non HTTP connections may support the
|
||||
// if-modified-since behaviour - we just check the date of the
|
||||
// content and skip the write if it is not newer.
|
||||
// Some protocols (FTP) dont include dates, of course.
|
||||
|
||||
InputStream is = null;
|
||||
IOException isException = null;
|
||||
for ( int i = 0; i < 3; i++ )
|
||||
{
|
||||
try
|
||||
{
|
||||
is = connection.getInputStream();
|
||||
break;
|
||||
}
|
||||
catch ( IOException ex )
|
||||
{
|
||||
isException = ex;
|
||||
}
|
||||
}
|
||||
if ( is == null )
|
||||
{
|
||||
throw isException;
|
||||
}
|
||||
|
||||
if ( connection.getLastModified() <= timestamp &&
|
||||
connection.getLastModified() != 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FileOutputStream fos = new FileOutputStream( destinationFile );
|
||||
|
||||
byte[] buffer = new byte[100 * 1024];
|
||||
int length;
|
||||
|
||||
while ( ( length = is.read( buffer ) ) >= 0 )
|
||||
{
|
||||
fos.write( buffer, 0, length );
|
||||
System.out.print( "." );
|
||||
}
|
||||
|
||||
System.out.println();
|
||||
fos.close();
|
||||
is.close();
|
||||
|
||||
// if (and only if) the use file time option is set, then the
|
||||
// saved file now has its timestamp set to that of the downloaded
|
||||
// file
|
||||
if ( timestamp >= 0 )
|
||||
{
|
||||
long remoteTimestamp = connection.getLastModified();
|
||||
if ( remoteTimestamp != 0 )
|
||||
{
|
||||
touchFile( destinationFile, remoteTimestamp );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an url which might contain a username and password. If the
|
||||
* given url doesn't contain a username and password then return the
|
||||
* origin url unchanged.
|
||||
*
|
||||
* @param url The url to parse.
|
||||
* @return The username, password and url.
|
||||
* @throws RuntimeException if the url is (very) invalid
|
||||
*/
|
||||
static String[] parseUrl( String url )
|
||||
{
|
||||
String[] parsedUrl = new String[3];
|
||||
parsedUrl[0] = null;
|
||||
parsedUrl[1] = null;
|
||||
parsedUrl[2] = url;
|
||||
|
||||
// We want to be able to deal with Basic Auth where the username
|
||||
// and password are part of the URL. An example of the URL string
|
||||
// we would like to be able to parse is like the following:
|
||||
//
|
||||
// http://username:password@repository.mycompany.com
|
||||
|
||||
int i = url.indexOf( "@" );
|
||||
if ( i > 0 )
|
||||
{
|
||||
String protocol = url.substring( 0, url.indexOf( "://" ) ) + "://";
|
||||
String s = url.substring( protocol.length(), i );
|
||||
int j = s.indexOf( ":" );
|
||||
parsedUrl[0] = s.substring( 0, j );
|
||||
parsedUrl[1] = s.substring( j + 1 );
|
||||
parsedUrl[2] = protocol + url.substring( i + 1 );
|
||||
}
|
||||
|
||||
return parsedUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the timestamp of a named file to a specified time.
|
||||
*
|
||||
* @param file the file to touch
|
||||
* @param timemillis in milliseconds since the start of the era
|
||||
* @return true if it succeeded. False means that this is a java1.1 system
|
||||
* and that file times can not be set
|
||||
* @throws RuntimeException Thrown in unrecoverable error. Likely this
|
||||
* comes from file access failures.
|
||||
*/
|
||||
private static boolean touchFile( File file, long timemillis )
|
||||
{
|
||||
long modifiedTime;
|
||||
|
||||
if ( timemillis < 0 )
|
||||
{
|
||||
modifiedTime = System.currentTimeMillis();
|
||||
}
|
||||
else
|
||||
{
|
||||
modifiedTime = timemillis;
|
||||
}
|
||||
|
||||
file.setLastModified( modifiedTime );
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,759 @@
|
|||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
|
||||
/**
|
||||
* General IO Stream manipulation.
|
||||
* <p/>
|
||||
* This class provides static utility methods for input/output operations, particularly buffered
|
||||
* copying between sources (<code>InputStream</code>, <code>Reader</code>, <code>String</code> and
|
||||
* <code>byte[]</code>) and destinations (<code>OutputStream</code>, <code>Writer</code>,
|
||||
* <code>String</code> and <code>byte[]</code>).
|
||||
* </p>
|
||||
* <p/>
|
||||
* <p>Unless otherwise noted, these <code>copy</code> methods do <em>not</em> flush or close the
|
||||
* streams. Often, doing so would require making non-portable assumptions about the streams' origin
|
||||
* and further use. This means that both streams' <code>close()</code> methods must be called after
|
||||
* copying. if one omits this step, then the stream resources (sockets, file descriptors) are
|
||||
* released when the associated Stream is garbage-collected. It is not a good idea to rely on this
|
||||
* mechanism. For a good overview of the distinction between "memory management" and "resource
|
||||
* management", see <a href="http://www.unixreview.com/articles/1998/9804/9804ja/ja.htm">this
|
||||
* UnixReview article</a></p>
|
||||
* <p/>
|
||||
* <p>For each <code>copy</code> method, a variant is provided that allows the caller to specify the
|
||||
* buffer size (the default is 4k). As the buffer size can have a fairly large impact on speed, this
|
||||
* may be worth tweaking. Often "large buffer -> faster" does not hold, even for large data
|
||||
* transfers.</p>
|
||||
* <p/>
|
||||
* <p>For byte-to-char methods, a <code>copy</code> variant allows the encoding to be selected
|
||||
* (otherwise the platform default is used).</p>
|
||||
* <p/>
|
||||
* <p>The <code>copy</code> methods use an internal buffer when copying. It is therefore advisable
|
||||
* <em>not</em> to deliberately wrap the stream arguments to the <code>copy</code> methods in
|
||||
* <code>Buffered*</code> streams. For example, don't do the
|
||||
* following:</p>
|
||||
* <p/>
|
||||
* <code>copy( new BufferedInputStream( in ), new BufferedOutputStream( out ) );</code>
|
||||
* <p/>
|
||||
* <p>The rationale is as follows:</p>
|
||||
* <p/>
|
||||
* <p>Imagine that an InputStream's read() is a very expensive operation, which would usually suggest
|
||||
* wrapping in a BufferedInputStream. The BufferedInputStream works by issuing infrequent
|
||||
* {@link java.io.InputStream#read(byte[] b, int off, int len)} requests on the underlying InputStream, to
|
||||
* fill an internal buffer, from which further <code>read</code> requests can inexpensively get
|
||||
* their data (until the buffer runs out).</p>
|
||||
* <p>However, the <code>copy</code> methods do the same thing, keeping an internal buffer,
|
||||
* populated by {@link InputStream#read(byte[] b, int off, int len)} requests. Having two buffers
|
||||
* (or three if the destination stream is also buffered) is pointless, and the unnecessary buffer
|
||||
* management hurts performance slightly (about 3%, according to some simple experiments).</p>
|
||||
*
|
||||
* @author <a href="mailto:peter@codehaus.org">Peter Donald</a>
|
||||
* @author <a href="mailto:jefft@codehaus.org">Jeff Turner</a>
|
||||
* @version CVS $Revision$ $Date$
|
||||
* @since 4.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Behold, intrepid explorers; a map of this class:
|
||||
*
|
||||
* Method Input Output Dependency
|
||||
* ------ ----- ------ -------
|
||||
* 1 copy InputStream OutputStream (primitive)
|
||||
* 2 copy Reader Writer (primitive)
|
||||
*
|
||||
* 3 copy InputStream Writer 2
|
||||
* 4 toString InputStream String 3
|
||||
* 5 toByteArray InputStream byte[] 1
|
||||
*
|
||||
* 6 copy Reader OutputStream 2
|
||||
* 7 toString Reader String 2
|
||||
* 8 toByteArray Reader byte[] 6
|
||||
*
|
||||
* 9 copy String OutputStream 2
|
||||
* 10 copy String Writer (trivial)
|
||||
* 11 toByteArray String byte[] 9
|
||||
*
|
||||
* 12 copy byte[] Writer 3
|
||||
* 13 toString byte[] String 12
|
||||
* 14 copy byte[] OutputStream (trivial)
|
||||
*
|
||||
*
|
||||
* Note that only the first two methods shuffle bytes; the rest use these two, or (if possible) copy
|
||||
* using native Java copy methods. As there are method variants to specify buffer size and encoding,
|
||||
* each row may correspond to up to 4 methods.
|
||||
*
|
||||
*/
|
||||
|
||||
public final class IOUtil
|
||||
{
|
||||
private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
|
||||
|
||||
/**
|
||||
* Private constructor to prevent instantiation.
|
||||
*/
|
||||
private IOUtil()
|
||||
{
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Core copy methods
|
||||
///////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Copy bytes from an <code>InputStream</code> to an <code>OutputStream</code>.
|
||||
*/
|
||||
public static void copy( final InputStream input, final OutputStream output )
|
||||
throws IOException
|
||||
{
|
||||
copy( input, output, DEFAULT_BUFFER_SIZE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy bytes from an <code>InputStream</code> to an <code>OutputStream</code>.
|
||||
*
|
||||
* @param bufferSize Size of internal buffer to use.
|
||||
*/
|
||||
public static void copy( final InputStream input,
|
||||
final OutputStream output,
|
||||
final int bufferSize )
|
||||
throws IOException
|
||||
{
|
||||
final byte[] buffer = new byte[bufferSize];
|
||||
int n = 0;
|
||||
while ( -1 != ( n = input.read( buffer ) ) )
|
||||
{
|
||||
output.write( buffer, 0, n );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy chars from a <code>Reader</code> to a <code>Writer</code>.
|
||||
*/
|
||||
public static void copy( final Reader input, final Writer output )
|
||||
throws IOException
|
||||
{
|
||||
copy( input, output, DEFAULT_BUFFER_SIZE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy chars from a <code>Reader</code> to a <code>Writer</code>.
|
||||
*
|
||||
* @param bufferSize Size of internal buffer to use.
|
||||
*/
|
||||
public static void copy( final Reader input, final Writer output, final int bufferSize )
|
||||
throws IOException
|
||||
{
|
||||
final char[] buffer = new char[bufferSize];
|
||||
int n = 0;
|
||||
while ( -1 != ( n = input.read( buffer ) ) )
|
||||
{
|
||||
output.write( buffer, 0, n );
|
||||
}
|
||||
output.flush();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Derived copy methods
|
||||
// InputStream -> *
|
||||
///////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// InputStream -> Writer
|
||||
|
||||
/**
|
||||
* Copy and convert bytes from an <code>InputStream</code> to chars on a
|
||||
* <code>Writer</code>.
|
||||
* The platform's default encoding is used for the byte-to-char conversion.
|
||||
*/
|
||||
public static void copy( final InputStream input, final Writer output )
|
||||
throws IOException
|
||||
{
|
||||
copy( input, output, DEFAULT_BUFFER_SIZE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy and convert bytes from an <code>InputStream</code> to chars on a
|
||||
* <code>Writer</code>.
|
||||
* The platform's default encoding is used for the byte-to-char conversion.
|
||||
*
|
||||
* @param bufferSize Size of internal buffer to use.
|
||||
*/
|
||||
public static void copy( final InputStream input, final Writer output, final int bufferSize )
|
||||
throws IOException
|
||||
{
|
||||
final InputStreamReader in = new InputStreamReader( input );
|
||||
copy( in, output, bufferSize );
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy and convert bytes from an <code>InputStream</code> to chars on a
|
||||
* <code>Writer</code>, using the specified encoding.
|
||||
*
|
||||
* @param encoding The name of a supported character encoding. See the
|
||||
* <a href="http://www.iana.org/assignments/character-sets">IANA
|
||||
* Charset Registry</a> for a list of valid encoding types.
|
||||
*/
|
||||
public static void copy( final InputStream input, final Writer output, final String encoding )
|
||||
throws IOException
|
||||
{
|
||||
final InputStreamReader in = new InputStreamReader( input, encoding );
|
||||
copy( in, output );
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy and convert bytes from an <code>InputStream</code> to chars on a
|
||||
* <code>Writer</code>, using the specified encoding.
|
||||
*
|
||||
* @param encoding The name of a supported character encoding. See the
|
||||
* <a href="http://www.iana.org/assignments/character-sets">IANA
|
||||
* Charset Registry</a> for a list of valid encoding types.
|
||||
* @param bufferSize Size of internal buffer to use.
|
||||
*/
|
||||
public static void copy( final InputStream input,
|
||||
final Writer output,
|
||||
final String encoding,
|
||||
final int bufferSize )
|
||||
throws IOException
|
||||
{
|
||||
final InputStreamReader in = new InputStreamReader( input, encoding );
|
||||
copy( in, output, bufferSize );
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// InputStream -> String
|
||||
|
||||
/**
|
||||
* Get the contents of an <code>InputStream</code> as a String.
|
||||
* The platform's default encoding is used for the byte-to-char conversion.
|
||||
*/
|
||||
public static String toString( final InputStream input )
|
||||
throws IOException
|
||||
{
|
||||
return toString( input, DEFAULT_BUFFER_SIZE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the contents of an <code>InputStream</code> as a String.
|
||||
* The platform's default encoding is used for the byte-to-char conversion.
|
||||
*
|
||||
* @param bufferSize Size of internal buffer to use.
|
||||
*/
|
||||
public static String toString( final InputStream input, final int bufferSize )
|
||||
throws IOException
|
||||
{
|
||||
final StringWriter sw = new StringWriter();
|
||||
copy( input, sw, bufferSize );
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the contents of an <code>InputStream</code> as a String.
|
||||
*
|
||||
* @param encoding The name of a supported character encoding. See the
|
||||
* <a href="http://www.iana.org/assignments/character-sets">IANA
|
||||
* Charset Registry</a> for a list of valid encoding types.
|
||||
*/
|
||||
public static String toString( final InputStream input, final String encoding )
|
||||
throws IOException
|
||||
{
|
||||
return toString( input, encoding, DEFAULT_BUFFER_SIZE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the contents of an <code>InputStream</code> as a String.
|
||||
*
|
||||
* @param encoding The name of a supported character encoding. See the
|
||||
* <a href="http://www.iana.org/assignments/character-sets">IANA
|
||||
* Charset Registry</a> for a list of valid encoding types.
|
||||
* @param bufferSize Size of internal buffer to use.
|
||||
*/
|
||||
public static String toString( final InputStream input,
|
||||
final String encoding,
|
||||
final int bufferSize )
|
||||
throws IOException
|
||||
{
|
||||
final StringWriter sw = new StringWriter();
|
||||
copy( input, sw, encoding, bufferSize );
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// InputStream -> byte[]
|
||||
|
||||
/**
|
||||
* Get the contents of an <code>InputStream</code> as a <code>byte[]</code>.
|
||||
*/
|
||||
public static byte[] toByteArray( final InputStream input )
|
||||
throws IOException
|
||||
{
|
||||
return toByteArray( input, DEFAULT_BUFFER_SIZE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the contents of an <code>InputStream</code> as a <code>byte[]</code>.
|
||||
*
|
||||
* @param bufferSize Size of internal buffer to use.
|
||||
*/
|
||||
public static byte[] toByteArray( final InputStream input, final int bufferSize )
|
||||
throws IOException
|
||||
{
|
||||
final ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
copy( input, output, bufferSize );
|
||||
return output.toByteArray();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Derived copy methods
|
||||
// Reader -> *
|
||||
///////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Reader -> OutputStream
|
||||
/**
|
||||
* Serialize chars from a <code>Reader</code> to bytes on an <code>OutputStream</code>, and
|
||||
* flush the <code>OutputStream</code>.
|
||||
*/
|
||||
public static void copy( final Reader input, final OutputStream output )
|
||||
throws IOException
|
||||
{
|
||||
copy( input, output, DEFAULT_BUFFER_SIZE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize chars from a <code>Reader</code> to bytes on an <code>OutputStream</code>, and
|
||||
* flush the <code>OutputStream</code>.
|
||||
*
|
||||
* @param bufferSize Size of internal buffer to use.
|
||||
*/
|
||||
public static void copy( final Reader input, final OutputStream output, final int bufferSize )
|
||||
throws IOException
|
||||
{
|
||||
final OutputStreamWriter out = new OutputStreamWriter( output );
|
||||
copy( input, out, bufferSize );
|
||||
// NOTE: Unless anyone is planning on rewriting OutputStreamWriter, we have to flush
|
||||
// here.
|
||||
out.flush();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Reader -> String
|
||||
/**
|
||||
* Get the contents of a <code>Reader</code> as a String.
|
||||
*/
|
||||
public static String toString( final Reader input )
|
||||
throws IOException
|
||||
{
|
||||
return toString( input, DEFAULT_BUFFER_SIZE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the contents of a <code>Reader</code> as a String.
|
||||
*
|
||||
* @param bufferSize Size of internal buffer to use.
|
||||
*/
|
||||
public static String toString( final Reader input, final int bufferSize )
|
||||
throws IOException
|
||||
{
|
||||
final StringWriter sw = new StringWriter();
|
||||
copy( input, sw, bufferSize );
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Reader -> byte[]
|
||||
/**
|
||||
* Get the contents of a <code>Reader</code> as a <code>byte[]</code>.
|
||||
*/
|
||||
public static byte[] toByteArray( final Reader input )
|
||||
throws IOException
|
||||
{
|
||||
return toByteArray( input, DEFAULT_BUFFER_SIZE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the contents of a <code>Reader</code> as a <code>byte[]</code>.
|
||||
*
|
||||
* @param bufferSize Size of internal buffer to use.
|
||||
*/
|
||||
public static byte[] toByteArray( final Reader input, final int bufferSize )
|
||||
throws IOException
|
||||
{
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
copy( input, output, bufferSize );
|
||||
return output.toByteArray();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Derived copy methods
|
||||
// String -> *
|
||||
///////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// String -> OutputStream
|
||||
|
||||
/**
|
||||
* Serialize chars from a <code>String</code> to bytes on an <code>OutputStream</code>, and
|
||||
* flush the <code>OutputStream</code>.
|
||||
*/
|
||||
public static void copy( final String input, final OutputStream output )
|
||||
throws IOException
|
||||
{
|
||||
copy( input, output, DEFAULT_BUFFER_SIZE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize chars from a <code>String</code> to bytes on an <code>OutputStream</code>, and
|
||||
* flush the <code>OutputStream</code>.
|
||||
*
|
||||
* @param bufferSize Size of internal buffer to use.
|
||||
*/
|
||||
public static void copy( final String input, final OutputStream output, final int bufferSize )
|
||||
throws IOException
|
||||
{
|
||||
final StringReader in = new StringReader( input );
|
||||
final OutputStreamWriter out = new OutputStreamWriter( output );
|
||||
copy( in, out, bufferSize );
|
||||
// NOTE: Unless anyone is planning on rewriting OutputStreamWriter, we have to flush
|
||||
// here.
|
||||
out.flush();
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// String -> Writer
|
||||
|
||||
/**
|
||||
* Copy chars from a <code>String</code> to a <code>Writer</code>.
|
||||
*/
|
||||
public static void copy( final String input, final Writer output )
|
||||
throws IOException
|
||||
{
|
||||
output.write( input );
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy bytes from an <code>InputStream</code> to an
|
||||
* <code>OutputStream</code>, with buffering.
|
||||
* This is equivalent to passing a
|
||||
* {@link java.io.BufferedInputStream} and
|
||||
* {@link java.io.BufferedOutputStream} to {@link #copy(InputStream, OutputStream)},
|
||||
* and flushing the output stream afterwards. The streams are not closed
|
||||
* after the copy.
|
||||
*
|
||||
* @deprecated Buffering streams is actively harmful! See the class description as to why. Use
|
||||
* {@link #copy(InputStream, OutputStream)} instead.
|
||||
*/
|
||||
public static void bufferedCopy( final InputStream input, final OutputStream output )
|
||||
throws IOException
|
||||
{
|
||||
final BufferedInputStream in = new BufferedInputStream( input );
|
||||
final BufferedOutputStream out = new BufferedOutputStream( output );
|
||||
copy( in, out );
|
||||
out.flush();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// String -> byte[]
|
||||
/**
|
||||
* Get the contents of a <code>String</code> as a <code>byte[]</code>.
|
||||
*/
|
||||
public static byte[] toByteArray( final String input )
|
||||
throws IOException
|
||||
{
|
||||
return toByteArray( input, DEFAULT_BUFFER_SIZE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the contents of a <code>String</code> as a <code>byte[]</code>.
|
||||
*
|
||||
* @param bufferSize Size of internal buffer to use.
|
||||
*/
|
||||
public static byte[] toByteArray( final String input, final int bufferSize )
|
||||
throws IOException
|
||||
{
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
copy( input, output, bufferSize );
|
||||
return output.toByteArray();
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// Derived copy methods
|
||||
// byte[] -> *
|
||||
///////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// byte[] -> Writer
|
||||
|
||||
/**
|
||||
* Copy and convert bytes from a <code>byte[]</code> to chars on a
|
||||
* <code>Writer</code>.
|
||||
* The platform's default encoding is used for the byte-to-char conversion.
|
||||
*/
|
||||
public static void copy( final byte[] input, final Writer output )
|
||||
throws IOException
|
||||
{
|
||||
copy( input, output, DEFAULT_BUFFER_SIZE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy and convert bytes from a <code>byte[]</code> to chars on a
|
||||
* <code>Writer</code>.
|
||||
* The platform's default encoding is used for the byte-to-char conversion.
|
||||
*
|
||||
* @param bufferSize Size of internal buffer to use.
|
||||
*/
|
||||
public static void copy( final byte[] input, final Writer output, final int bufferSize )
|
||||
throws IOException
|
||||
{
|
||||
final ByteArrayInputStream in = new ByteArrayInputStream( input );
|
||||
copy( in, output, bufferSize );
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy and convert bytes from a <code>byte[]</code> to chars on a
|
||||
* <code>Writer</code>, using the specified encoding.
|
||||
*
|
||||
* @param encoding The name of a supported character encoding. See the
|
||||
* <a href="http://www.iana.org/assignments/character-sets">IANA
|
||||
* Charset Registry</a> for a list of valid encoding types.
|
||||
*/
|
||||
public static void copy( final byte[] input, final Writer output, final String encoding )
|
||||
throws IOException
|
||||
{
|
||||
final ByteArrayInputStream in = new ByteArrayInputStream( input );
|
||||
copy( in, output, encoding );
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy and convert bytes from a <code>byte[]</code> to chars on a
|
||||
* <code>Writer</code>, using the specified encoding.
|
||||
*
|
||||
* @param encoding The name of a supported character encoding. See the
|
||||
* <a href="http://www.iana.org/assignments/character-sets">IANA
|
||||
* Charset Registry</a> for a list of valid encoding types.
|
||||
* @param bufferSize Size of internal buffer to use.
|
||||
*/
|
||||
public static void copy( final byte[] input,
|
||||
final Writer output,
|
||||
final String encoding,
|
||||
final int bufferSize )
|
||||
throws IOException
|
||||
{
|
||||
final ByteArrayInputStream in = new ByteArrayInputStream( input );
|
||||
copy( in, output, encoding, bufferSize );
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// byte[] -> String
|
||||
|
||||
/**
|
||||
* Get the contents of a <code>byte[]</code> as a String.
|
||||
* The platform's default encoding is used for the byte-to-char conversion.
|
||||
*/
|
||||
public static String toString( final byte[] input )
|
||||
throws IOException
|
||||
{
|
||||
return toString( input, DEFAULT_BUFFER_SIZE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the contents of a <code>byte[]</code> as a String.
|
||||
* The platform's default encoding is used for the byte-to-char conversion.
|
||||
*
|
||||
* @param bufferSize Size of internal buffer to use.
|
||||
*/
|
||||
public static String toString( final byte[] input, final int bufferSize )
|
||||
throws IOException
|
||||
{
|
||||
final StringWriter sw = new StringWriter();
|
||||
copy( input, sw, bufferSize );
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the contents of a <code>byte[]</code> as a String.
|
||||
*
|
||||
* @param encoding The name of a supported character encoding. See the
|
||||
* <a href="http://www.iana.org/assignments/character-sets">IANA
|
||||
* Charset Registry</a> for a list of valid encoding types.
|
||||
*/
|
||||
public static String toString( final byte[] input, final String encoding )
|
||||
throws IOException
|
||||
{
|
||||
return toString( input, encoding, DEFAULT_BUFFER_SIZE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the contents of a <code>byte[]</code> as a String.
|
||||
*
|
||||
* @param encoding The name of a supported character encoding. See the
|
||||
* <a href="http://www.iana.org/assignments/character-sets">IANA
|
||||
* Charset Registry</a> for a list of valid encoding types.
|
||||
* @param bufferSize Size of internal buffer to use.
|
||||
*/
|
||||
public static String toString( final byte[] input,
|
||||
final String encoding,
|
||||
final int bufferSize )
|
||||
throws IOException
|
||||
{
|
||||
final StringWriter sw = new StringWriter();
|
||||
copy( input, sw, encoding, bufferSize );
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// byte[] -> OutputStream
|
||||
|
||||
/**
|
||||
* Copy bytes from a <code>byte[]</code> to an <code>OutputStream</code>.
|
||||
*/
|
||||
public static void copy( final byte[] input, final OutputStream output )
|
||||
throws IOException
|
||||
{
|
||||
copy( input, output, DEFAULT_BUFFER_SIZE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy bytes from a <code>byte[]</code> to an <code>OutputStream</code>.
|
||||
*
|
||||
* @param bufferSize Size of internal buffer to use.
|
||||
*/
|
||||
public static void copy( final byte[] input,
|
||||
final OutputStream output,
|
||||
final int bufferSize )
|
||||
throws IOException
|
||||
{
|
||||
output.write( input );
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the contents of two Streams to determine if they are equal or not.
|
||||
*
|
||||
* @param input1 the first stream
|
||||
* @param input2 the second stream
|
||||
* @return true if the content of the streams are equal or they both don't exist, false otherwise
|
||||
*/
|
||||
public static boolean contentEquals( final InputStream input1,
|
||||
final InputStream input2 )
|
||||
throws IOException
|
||||
{
|
||||
final InputStream bufferedInput1 = new BufferedInputStream( input1 );
|
||||
final InputStream bufferedInput2 = new BufferedInputStream( input2 );
|
||||
|
||||
int ch = bufferedInput1.read();
|
||||
while ( -1 != ch )
|
||||
{
|
||||
final int ch2 = bufferedInput2.read();
|
||||
if ( ch != ch2 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ch = bufferedInput1.read();
|
||||
}
|
||||
|
||||
final int ch2 = bufferedInput2.read();
|
||||
if ( -1 != ch2 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// close()
|
||||
|
||||
/**
|
||||
* A IOException ignoring method that simply closes the stream.
|
||||
*
|
||||
* @param inputStream The stream to close.
|
||||
*/
|
||||
public static void close( InputStream inputStream )
|
||||
{
|
||||
try
|
||||
{
|
||||
inputStream.close();
|
||||
}
|
||||
catch ( IOException ex )
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A IOException ignoring method that simply closes the stream.
|
||||
*
|
||||
* @param outputStream The stream to close.
|
||||
*/
|
||||
public static void close( OutputStream outputStream )
|
||||
{
|
||||
try
|
||||
{
|
||||
outputStream.close();
|
||||
}
|
||||
catch ( IOException ex )
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A IOException ignoring method that simply closes the reader.
|
||||
*
|
||||
* @param reader The reader to close.
|
||||
*/
|
||||
public static void close( Reader reader )
|
||||
{
|
||||
try
|
||||
{
|
||||
reader.close();
|
||||
}
|
||||
catch ( IOException ex )
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A IOException ignoring method that simply closes the stream.
|
||||
*
|
||||
* @param wrtier The writer to close.
|
||||
*/
|
||||
public static void close( Writer writer )
|
||||
{
|
||||
try
|
||||
{
|
||||
writer.close();
|
||||
}
|
||||
catch ( IOException ex )
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
|
||||
import java.net.URLClassLoader;
|
||||
import java.net.URL;
|
||||
|
||||
public class IsolatedClassLoader
|
||||
extends URLClassLoader
|
||||
{
|
||||
private ClassLoader parent = ClassLoader.getSystemClassLoader();
|
||||
|
||||
public IsolatedClassLoader()
|
||||
{
|
||||
super( new URL[0], null );
|
||||
}
|
||||
|
||||
public void addURL( URL url )
|
||||
{
|
||||
super.addURL( url );
|
||||
}
|
||||
|
||||
public synchronized Class loadClass( String className )
|
||||
throws ClassNotFoundException
|
||||
{
|
||||
Class c = findLoadedClass( className );
|
||||
|
||||
ClassNotFoundException ex = null;
|
||||
|
||||
if ( c == null )
|
||||
{
|
||||
try
|
||||
{
|
||||
c = findClass( className );
|
||||
}
|
||||
catch ( ClassNotFoundException e )
|
||||
{
|
||||
ex = e;
|
||||
|
||||
if ( parent != null )
|
||||
{
|
||||
c = parent.loadClass( className );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( c == null )
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,206 @@
|
|||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
public class JarMojo
|
||||
{
|
||||
private byte[] buffer = new byte[4096];
|
||||
|
||||
public void execute( File basedir, String outputDirectory, String jarName )
|
||||
throws Exception
|
||||
{
|
||||
File jarFile = new File( new File( outputDirectory ), jarName + ".jar" );
|
||||
|
||||
Map includes = new LinkedHashMap();
|
||||
|
||||
addDirectory( includes, "**/**", "**/package.html", "", basedir );
|
||||
|
||||
createJar( jarFile, includes );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all files in the specified directory to the archive.
|
||||
*
|
||||
* @param includes a map <String, File> of items to be include in the outpur
|
||||
* @param baseDir the directory to add
|
||||
*/
|
||||
protected void addDirectory( Map includes, File baseDir ) throws IOException
|
||||
{
|
||||
addDirectory( includes, "", baseDir );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all files in the specified directory to the archive.
|
||||
*
|
||||
* @param includes a map <String, File> of items to be include in the outpur
|
||||
* @param prefix value to be added to the front of jar entry names
|
||||
* @param baseDir the directory to add
|
||||
*/
|
||||
protected void addDirectory( Map includes, String prefix, File baseDir ) throws IOException
|
||||
{
|
||||
addDirectory( includes, null, null, prefix, baseDir );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all files in the specified directory to the archive.
|
||||
*
|
||||
* @param includes a map <String, File> of items to be include in the outpur
|
||||
* @param includesPattern Sets the list of include patterns to use
|
||||
* @param excludesPattern Sets the list of exclude patterns to use
|
||||
* @param prefix value to be added to the front of jar entry names
|
||||
* @param baseDir the directory to add
|
||||
*/
|
||||
protected void addDirectory( Map includes, String includesPattern, String excludesPattern, String prefix, File baseDir )
|
||||
throws IOException
|
||||
{
|
||||
if ( !baseDir.exists() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DirectoryScanner scanner = new DirectoryScanner();
|
||||
scanner.setBasedir( baseDir );
|
||||
if ( includesPattern != null )
|
||||
{
|
||||
scanner.setIncludes( StringUtils.split( includesPattern, "," ) );
|
||||
}
|
||||
|
||||
if ( excludesPattern != null )
|
||||
{
|
||||
scanner.setExcludes( StringUtils.split( excludesPattern, "," ) );
|
||||
}
|
||||
scanner.scan();
|
||||
String[] files = scanner.getIncludedFiles();
|
||||
for ( int i = 0; i < files.length; i++ )
|
||||
{
|
||||
String file = files[i];
|
||||
file = file.replace( '\\', '/' ); // todo shouldn't the scanner return platform independent names?
|
||||
includes.put( prefix + file, new File( baseDir, file ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the jar file specified and include the listed files.
|
||||
*
|
||||
* @param jarFile the jar file to create
|
||||
* @param includes a Map<String, File>of items to include; the key is the jar entry name
|
||||
* @throws IOException if there is a problem writing the archive or reading the sources
|
||||
*/
|
||||
protected void createJar( File jarFile, Map includes ) throws IOException
|
||||
{
|
||||
File parentJarFile = jarFile.getParentFile();
|
||||
if ( !parentJarFile.exists() )
|
||||
{
|
||||
parentJarFile.mkdirs();
|
||||
}
|
||||
JarOutputStream jos = createJar( jarFile, createManifest() );
|
||||
try
|
||||
{
|
||||
addEntries( jos, includes );
|
||||
}
|
||||
finally
|
||||
{
|
||||
jos.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a manifest for the jar file
|
||||
*
|
||||
* @return a default manifest; the Manifest-Version and Created-By attributes are initialized
|
||||
*/
|
||||
protected Manifest createManifest()
|
||||
{
|
||||
Manifest mf = new Manifest();
|
||||
Attributes attrs = mf.getMainAttributes();
|
||||
attrs.putValue( Attributes.Name.MANIFEST_VERSION.toString(), "1.0" );
|
||||
attrs.putValue( "Created-By", "2.0 (Apache Maven)" );
|
||||
return mf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the specified jar file and return a JarOutputStream to it
|
||||
*
|
||||
* @param jarFile the jar file to create
|
||||
* @param mf the manifest to use
|
||||
* @return a JarOutputStream that can be used to write to that file
|
||||
* @throws IOException if there was a problem opening the file
|
||||
*/
|
||||
protected JarOutputStream createJar( File jarFile, Manifest mf ) throws IOException
|
||||
{
|
||||
jarFile.getParentFile().mkdirs();
|
||||
FileOutputStream fos = new FileOutputStream( jarFile );
|
||||
try
|
||||
{
|
||||
return new JarOutputStream( fos, mf );
|
||||
}
|
||||
catch ( IOException e )
|
||||
{
|
||||
try
|
||||
{
|
||||
fos.close();
|
||||
jarFile.delete();
|
||||
}
|
||||
catch ( IOException e1 )
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all entries in the supplied Map to the jar
|
||||
*
|
||||
* @param jos a JarOutputStream that can be used to write to the jar
|
||||
* @param includes a Map<String, File> of entries to add
|
||||
* @throws IOException if there is a problem writing the archive or reading the sources
|
||||
*/
|
||||
protected void addEntries( JarOutputStream jos, Map includes ) throws IOException
|
||||
{
|
||||
for ( Iterator i = includes.entrySet().iterator(); i.hasNext(); )
|
||||
{
|
||||
Map.Entry entry = (Map.Entry) i.next();
|
||||
String name = (String) entry.getKey();
|
||||
File file = (File) entry.getValue();
|
||||
addEntry( jos, name, file );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a single entry to the jar
|
||||
*
|
||||
* @param jos a JarOutputStream that can be used to write to the jar
|
||||
* @param name the entry name to use; must be '/' delimited
|
||||
* @param source the file to add
|
||||
* @throws IOException if there is a problem writing the archive or reading the sources
|
||||
*/
|
||||
protected void addEntry( JarOutputStream jos, String name, File source ) throws IOException
|
||||
{
|
||||
FileInputStream fis = new FileInputStream( source );
|
||||
try
|
||||
{
|
||||
jos.putNextEntry( new JarEntry( name ) );
|
||||
int count;
|
||||
while ( ( count = fis.read( buffer ) ) > 0 )
|
||||
{
|
||||
jos.write( buffer, 0, count );
|
||||
}
|
||||
jos.closeEntry();
|
||||
}
|
||||
finally
|
||||
{
|
||||
fis.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
public class JavacCompiler
|
||||
extends AbstractCompiler
|
||||
{
|
||||
static final int OUTPUT_BUFFER_SIZE = 1024;
|
||||
|
||||
public JavacCompiler()
|
||||
{
|
||||
}
|
||||
|
||||
public List compile( String[] classpathElements, String[] sourceDirectories, String destinationDirectory )
|
||||
throws Exception
|
||||
{
|
||||
File destinationDir = new File( destinationDirectory );
|
||||
|
||||
if ( !destinationDir.exists() )
|
||||
{
|
||||
destinationDir.mkdirs();
|
||||
}
|
||||
|
||||
String[] sources = getSourceFiles( sourceDirectories );
|
||||
|
||||
int j = 5;
|
||||
|
||||
String[] args = new String[sources.length + j];
|
||||
|
||||
args[0] = "-d";
|
||||
|
||||
args[1] = destinationDir.getAbsolutePath();
|
||||
|
||||
args[2] = "-nowarn";
|
||||
|
||||
args[3] = "-classpath";
|
||||
|
||||
args[4] = getClasspathString( classpathElements );
|
||||
|
||||
for ( int i = 0; i < sources.length; i++ )
|
||||
{
|
||||
args[i + j] = sources[i];
|
||||
}
|
||||
|
||||
IsolatedClassLoader cl = new IsolatedClassLoader();
|
||||
|
||||
File toolsJar = new File( System.getProperty( "java.home" ), "../lib/tools.jar" );
|
||||
|
||||
cl.addURL( toolsJar.toURL() );
|
||||
|
||||
Class c = cl.loadClass( "sun.tools.javac.Main" );
|
||||
|
||||
Constructor cons = c.getConstructor( new Class[]{OutputStream.class, String.class} );
|
||||
|
||||
ByteArrayOutputStream err = new ByteArrayOutputStream();
|
||||
|
||||
Object compiler = cons.newInstance( new Object[]{err, "javac"} );
|
||||
|
||||
Method compile = c.getMethod( "compile", new Class[]{String[].class} );
|
||||
|
||||
Boolean ok = (Boolean) compile.invoke( compiler, new Object[]{args} );
|
||||
|
||||
List messages = parseModernStream( new BufferedReader( new InputStreamReader( new ByteArrayInputStream( err.toByteArray() ) ) ) );
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
protected List parseModernStream( BufferedReader input )
|
||||
throws IOException
|
||||
{
|
||||
List errors = new ArrayList();
|
||||
|
||||
String line = null;
|
||||
|
||||
StringBuffer buffer = null;
|
||||
|
||||
while ( true )
|
||||
{
|
||||
// cleanup the buffer
|
||||
buffer = new StringBuffer(); // this is quicker than clearing it
|
||||
|
||||
// most errors terminate with the '^' char
|
||||
do
|
||||
{
|
||||
if ( ( line = input.readLine() ) == null )
|
||||
{
|
||||
return errors;
|
||||
}
|
||||
|
||||
buffer.append( line );
|
||||
|
||||
buffer.append( '\n' );
|
||||
}
|
||||
while ( !line.endsWith( "^" ) );
|
||||
|
||||
// add the error bean
|
||||
errors.add( parseModernError( buffer.toString() ) );
|
||||
}
|
||||
}
|
||||
|
||||
private CompilerError parseModernError( String error )
|
||||
{
|
||||
StringTokenizer tokens = new StringTokenizer( error, ":" );
|
||||
|
||||
try
|
||||
{
|
||||
String file = tokens.nextToken();
|
||||
|
||||
if ( file.length() == 1 )
|
||||
{
|
||||
file = new StringBuffer( file ).append( ":" ).append( tokens.nextToken() ).toString();
|
||||
}
|
||||
|
||||
int line = Integer.parseInt( tokens.nextToken() );
|
||||
|
||||
String message = tokens.nextToken( "\n" ).substring( 1 );
|
||||
|
||||
String context = tokens.nextToken( "\n" );
|
||||
|
||||
String pointer = tokens.nextToken( "\n" );
|
||||
|
||||
int startcolumn = pointer.indexOf( "^" );
|
||||
|
||||
int endcolumn = context.indexOf( " ", startcolumn );
|
||||
|
||||
if ( endcolumn == -1 )
|
||||
{
|
||||
endcolumn = context.length();
|
||||
}
|
||||
|
||||
return new CompilerError( file, false, line, startcolumn, line, endcolumn, message );
|
||||
}
|
||||
catch ( NoSuchElementException nse )
|
||||
{
|
||||
return new CompilerError( "no more tokens - could not parse error message: " + error );
|
||||
}
|
||||
catch ( Exception nse )
|
||||
{
|
||||
return new CompilerError( "could not parse error message: " + error );
|
||||
}
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return "Sun Javac Compiler";
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,253 @@
|
|||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Condition that tests the OS type.
|
||||
*
|
||||
* @author Stefan Bodewig
|
||||
* @author Magesh Umasankar
|
||||
* @since Ant 1.4
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class Os
|
||||
{
|
||||
private static final String OS_NAME = System.getProperty( "os.name" ).toLowerCase( Locale.US );
|
||||
|
||||
private static final String OS_ARCH = System.getProperty( "os.arch" ).toLowerCase( Locale.US );
|
||||
|
||||
private static final String OS_VERSION = System.getProperty( "os.version" ).toLowerCase( Locale.US );
|
||||
|
||||
private static final String PATH_SEP = System.getProperty( "path.separator" );
|
||||
|
||||
private String family;
|
||||
private String name;
|
||||
private String version;
|
||||
private String arch;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*
|
||||
*/
|
||||
public Os()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that sets the family attribute
|
||||
*
|
||||
* @param family a String value
|
||||
*/
|
||||
public Os( String family )
|
||||
{
|
||||
setFamily( family );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the desired OS family type
|
||||
*
|
||||
* @param f The OS family type desired<br />
|
||||
* Possible values:<br />
|
||||
* <ul>
|
||||
* <li>dos</li>
|
||||
* <li>mac</li>
|
||||
* <li>netware</li>
|
||||
* <li>os/2</li>
|
||||
* <li>tandem</li>
|
||||
* <li>unix</li>
|
||||
* <li>windows</li>
|
||||
* <li>win9x</li>
|
||||
* <li>z/os</li>
|
||||
* <li>os/400</li>
|
||||
* </ul>
|
||||
*/
|
||||
public void setFamily( String f )
|
||||
{
|
||||
family = f.toLowerCase( Locale.US );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the desired OS name
|
||||
*
|
||||
* @param name The OS name
|
||||
*/
|
||||
public void setName( String name )
|
||||
{
|
||||
this.name = name.toLowerCase( Locale.US );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the desired OS architecture
|
||||
*
|
||||
* @param arch The OS architecture
|
||||
*/
|
||||
public void setArch( String arch )
|
||||
{
|
||||
this.arch = arch.toLowerCase( Locale.US );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the desired OS version
|
||||
*
|
||||
* @param version The OS version
|
||||
*/
|
||||
public void setVersion( String version )
|
||||
{
|
||||
this.version = version.toLowerCase( Locale.US );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the OS on which Ant is executing matches the type of
|
||||
* that set in setFamily.
|
||||
* @see Os#setFamily(String)
|
||||
*/
|
||||
public boolean eval() throws Exception
|
||||
{
|
||||
return isOs( family, name, arch, version );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the OS on which Ant is executing matches the
|
||||
* given OS family.
|
||||
* @param family the family to check for
|
||||
* @return true if the OS matches
|
||||
* @since 1.5
|
||||
*/
|
||||
public static boolean isFamily( String family )
|
||||
{
|
||||
return isOs( family, null, null, null );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the OS on which Ant is executing matches the
|
||||
* given OS name.
|
||||
*
|
||||
* @param name the OS name to check for
|
||||
* @return true if the OS matches
|
||||
* @since 1.7
|
||||
*/
|
||||
public static boolean isName( String name )
|
||||
{
|
||||
return isOs( null, name, null, null );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the OS on which Ant is executing matches the
|
||||
* given OS architecture.
|
||||
*
|
||||
* @param arch the OS architecture to check for
|
||||
* @return true if the OS matches
|
||||
* @since 1.7
|
||||
*/
|
||||
public static boolean isArch( String arch )
|
||||
{
|
||||
return isOs( null, null, arch, null );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the OS on which Ant is executing matches the
|
||||
* given OS version.
|
||||
*
|
||||
* @param version the OS version to check for
|
||||
* @return true if the OS matches
|
||||
* @since 1.7
|
||||
*/
|
||||
public static boolean isVersion( String version )
|
||||
{
|
||||
return isOs( null, null, null, version );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the OS on which Ant is executing matches the
|
||||
* given OS family, name, architecture and version
|
||||
*
|
||||
* @param family The OS family
|
||||
* @param name The OS name
|
||||
* @param arch The OS architecture
|
||||
* @param version The OS version
|
||||
* @return true if the OS matches
|
||||
* @since 1.7
|
||||
*/
|
||||
public static boolean isOs( String family, String name, String arch,
|
||||
String version )
|
||||
{
|
||||
boolean retValue = false;
|
||||
|
||||
if ( family != null || name != null || arch != null
|
||||
|| version != null )
|
||||
{
|
||||
|
||||
boolean isFamily = true;
|
||||
boolean isName = true;
|
||||
boolean isArch = true;
|
||||
boolean isVersion = true;
|
||||
|
||||
if ( family != null )
|
||||
{
|
||||
if ( family.equals( "windows" ) )
|
||||
{
|
||||
isFamily = OS_NAME.indexOf( "windows" ) > -1;
|
||||
}
|
||||
else if ( family.equals( "os/2" ) )
|
||||
{
|
||||
isFamily = OS_NAME.indexOf( "os/2" ) > -1;
|
||||
}
|
||||
else if ( family.equals( "netware" ) )
|
||||
{
|
||||
isFamily = OS_NAME.indexOf( "netware" ) > -1;
|
||||
}
|
||||
else if ( family.equals( "dos" ) )
|
||||
{
|
||||
isFamily = PATH_SEP.equals( ";" ) && !isFamily( "netware" );
|
||||
}
|
||||
else if ( family.equals( "mac" ) )
|
||||
{
|
||||
isFamily = OS_NAME.indexOf( "mac" ) > -1;
|
||||
}
|
||||
else if ( family.equals( "tandem" ) )
|
||||
{
|
||||
isFamily = OS_NAME.indexOf( "nonstop_kernel" ) > -1;
|
||||
}
|
||||
else if ( family.equals( "unix" ) )
|
||||
{
|
||||
isFamily = PATH_SEP.equals( ":" )
|
||||
&& !isFamily( "openvms" )
|
||||
&& ( !isFamily( "mac" ) || OS_NAME.endsWith( "x" ) );
|
||||
}
|
||||
else if ( family.equals( "win9x" ) )
|
||||
{
|
||||
isFamily = isFamily( "windows" )
|
||||
&& ( OS_NAME.indexOf( "95" ) >= 0
|
||||
|| OS_NAME.indexOf( "98" ) >= 0
|
||||
|| OS_NAME.indexOf( "me" ) >= 0
|
||||
|| OS_NAME.indexOf( "ce" ) >= 0 );
|
||||
}
|
||||
else if ( family.equals( "z/os" ) )
|
||||
{
|
||||
isFamily = OS_NAME.indexOf( "z/os" ) > -1
|
||||
|| OS_NAME.indexOf( "os/390" ) > -1;
|
||||
}
|
||||
else if ( family.equals( "os/400" ) )
|
||||
{
|
||||
isFamily = OS_NAME.indexOf( "os/400" ) > -1;
|
||||
}
|
||||
else if ( family.equals( "openvms" ) )
|
||||
{
|
||||
isFamily = OS_NAME.indexOf( "openvms" ) > -1;
|
||||
}
|
||||
}
|
||||
if ( name != null )
|
||||
{
|
||||
isName = name.equals( OS_NAME );
|
||||
}
|
||||
if ( arch != null )
|
||||
{
|
||||
isArch = arch.equals( OS_ARCH );
|
||||
}
|
||||
if ( version != null )
|
||||
{
|
||||
isVersion = version.equals( OS_VERSION );
|
||||
}
|
||||
retValue = isFamily && isName && isArch && isVersion;
|
||||
}
|
||||
return retValue;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,609 @@
|
|||
|
||||
import java.io.File;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* <p>This is a utility class used by selectors and DirectoryScanner. The
|
||||
* functionality more properly belongs just to selectors, but unfortunately
|
||||
* DirectoryScanner exposed these as protected methods. Thus we have to
|
||||
* support any subclasses of DirectoryScanner that may access these methods.
|
||||
* </p>
|
||||
* <p>This is a Singleton.</p>
|
||||
*
|
||||
* @author Arnout J. Kuiper
|
||||
* <a href="mailto:ajkuiper@wxs.nl">ajkuiper@wxs.nl</a>
|
||||
* @author Magesh Umasankar
|
||||
* @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a>
|
||||
* @since 1.5
|
||||
*/
|
||||
public final class SelectorUtils
|
||||
{
|
||||
|
||||
private static SelectorUtils instance = new SelectorUtils();
|
||||
|
||||
/**
|
||||
* Private Constructor
|
||||
*/
|
||||
private SelectorUtils()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the manager of the Singleton.
|
||||
*/
|
||||
public static SelectorUtils getInstance()
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether or not a given path matches the start of a given
|
||||
* pattern up to the first "**".
|
||||
* <p/>
|
||||
* This is not a general purpose test and should only be used if you
|
||||
* can live with false positives. For example, <code>pattern=**\a</code>
|
||||
* and <code>str=b</code> will yield <code>true</code>.
|
||||
*
|
||||
* @param pattern The pattern to match against. Must not be
|
||||
* <code>null</code>.
|
||||
* @param str The path to match, as a String. Must not be
|
||||
* <code>null</code>.
|
||||
* @return whether or not a given path matches the start of a given
|
||||
* pattern up to the first "**".
|
||||
*/
|
||||
public static boolean matchPatternStart( String pattern, String str )
|
||||
{
|
||||
return matchPatternStart( pattern, str, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether or not a given path matches the start of a given
|
||||
* pattern up to the first "**".
|
||||
* <p/>
|
||||
* This is not a general purpose test and should only be used if you
|
||||
* can live with false positives. For example, <code>pattern=**\a</code>
|
||||
* and <code>str=b</code> will yield <code>true</code>.
|
||||
*
|
||||
* @param pattern The pattern to match against. Must not be
|
||||
* <code>null</code>.
|
||||
* @param str The path to match, as a String. Must not be
|
||||
* <code>null</code>.
|
||||
* @param isCaseSensitive Whether or not matching should be performed
|
||||
* case sensitively.
|
||||
* @return whether or not a given path matches the start of a given
|
||||
* pattern up to the first "**".
|
||||
*/
|
||||
public static boolean matchPatternStart( String pattern, String str,
|
||||
boolean isCaseSensitive )
|
||||
{
|
||||
// When str starts with a File.separator, pattern has to start with a
|
||||
// File.separator.
|
||||
// When pattern starts with a File.separator, str has to start with a
|
||||
// File.separator.
|
||||
if ( str.startsWith( File.separator ) !=
|
||||
pattern.startsWith( File.separator ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector patDirs = tokenizePath( pattern );
|
||||
Vector strDirs = tokenizePath( str );
|
||||
|
||||
int patIdxStart = 0;
|
||||
int patIdxEnd = patDirs.size() - 1;
|
||||
int strIdxStart = 0;
|
||||
int strIdxEnd = strDirs.size() - 1;
|
||||
|
||||
// up to first '**'
|
||||
while ( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd )
|
||||
{
|
||||
String patDir = (String) patDirs.elementAt( patIdxStart );
|
||||
if ( patDir.equals( "**" ) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
if ( !match( patDir, (String) strDirs.elementAt( strIdxStart ),
|
||||
isCaseSensitive ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
patIdxStart++;
|
||||
strIdxStart++;
|
||||
}
|
||||
|
||||
if ( strIdxStart > strIdxEnd )
|
||||
{
|
||||
// String is exhausted
|
||||
return true;
|
||||
}
|
||||
else if ( patIdxStart > patIdxEnd )
|
||||
{
|
||||
// String not exhausted, but pattern is. Failure.
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// pattern now holds ** while string is not exhausted
|
||||
// this will generate false positives but we can live with that.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether or not a given path matches a given pattern.
|
||||
*
|
||||
* @param pattern The pattern to match against. Must not be
|
||||
* <code>null</code>.
|
||||
* @param str The path to match, as a String. Must not be
|
||||
* <code>null</code>.
|
||||
* @return <code>true</code> if the pattern matches against the string,
|
||||
* or <code>false</code> otherwise.
|
||||
*/
|
||||
public static boolean matchPath( String pattern, String str )
|
||||
{
|
||||
return matchPath( pattern, str, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether or not a given path matches a given pattern.
|
||||
*
|
||||
* @param pattern The pattern to match against. Must not be
|
||||
* <code>null</code>.
|
||||
* @param str The path to match, as a String. Must not be
|
||||
* <code>null</code>.
|
||||
* @param isCaseSensitive Whether or not matching should be performed
|
||||
* case sensitively.
|
||||
* @return <code>true</code> if the pattern matches against the string,
|
||||
* or <code>false</code> otherwise.
|
||||
*/
|
||||
public static boolean matchPath( String pattern, String str,
|
||||
boolean isCaseSensitive )
|
||||
{
|
||||
// When str starts with a File.separator, pattern has to start with a
|
||||
// File.separator.
|
||||
// When pattern starts with a File.separator, str has to start with a
|
||||
// File.separator.
|
||||
if ( str.startsWith( File.separator ) !=
|
||||
pattern.startsWith( File.separator ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector patDirs = tokenizePath( pattern );
|
||||
Vector strDirs = tokenizePath( str );
|
||||
|
||||
int patIdxStart = 0;
|
||||
int patIdxEnd = patDirs.size() - 1;
|
||||
int strIdxStart = 0;
|
||||
int strIdxEnd = strDirs.size() - 1;
|
||||
|
||||
// up to first '**'
|
||||
while ( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd )
|
||||
{
|
||||
String patDir = (String) patDirs.elementAt( patIdxStart );
|
||||
if ( patDir.equals( "**" ) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
if ( !match( patDir, (String) strDirs.elementAt( strIdxStart ),
|
||||
isCaseSensitive ) )
|
||||
{
|
||||
patDirs = null;
|
||||
strDirs = null;
|
||||
return false;
|
||||
}
|
||||
patIdxStart++;
|
||||
strIdxStart++;
|
||||
}
|
||||
if ( strIdxStart > strIdxEnd )
|
||||
{
|
||||
// String is exhausted
|
||||
for ( int i = patIdxStart; i <= patIdxEnd; i++ )
|
||||
{
|
||||
if ( !patDirs.elementAt( i ).equals( "**" ) )
|
||||
{
|
||||
patDirs = null;
|
||||
strDirs = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( patIdxStart > patIdxEnd )
|
||||
{
|
||||
// String not exhausted, but pattern is. Failure.
|
||||
patDirs = null;
|
||||
strDirs = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// up to last '**'
|
||||
while ( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd )
|
||||
{
|
||||
String patDir = (String) patDirs.elementAt( patIdxEnd );
|
||||
if ( patDir.equals( "**" ) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
if ( !match( patDir, (String) strDirs.elementAt( strIdxEnd ),
|
||||
isCaseSensitive ) )
|
||||
{
|
||||
patDirs = null;
|
||||
strDirs = null;
|
||||
return false;
|
||||
}
|
||||
patIdxEnd--;
|
||||
strIdxEnd--;
|
||||
}
|
||||
if ( strIdxStart > strIdxEnd )
|
||||
{
|
||||
// String is exhausted
|
||||
for ( int i = patIdxStart; i <= patIdxEnd; i++ )
|
||||
{
|
||||
if ( !patDirs.elementAt( i ).equals( "**" ) )
|
||||
{
|
||||
patDirs = null;
|
||||
strDirs = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
while ( patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd )
|
||||
{
|
||||
int patIdxTmp = -1;
|
||||
for ( int i = patIdxStart + 1; i <= patIdxEnd; i++ )
|
||||
{
|
||||
if ( patDirs.elementAt( i ).equals( "**" ) )
|
||||
{
|
||||
patIdxTmp = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( patIdxTmp == patIdxStart + 1 )
|
||||
{
|
||||
// '**/**' situation, so skip one
|
||||
patIdxStart++;
|
||||
continue;
|
||||
}
|
||||
// Find the pattern between padIdxStart & padIdxTmp in str between
|
||||
// strIdxStart & strIdxEnd
|
||||
int patLength = ( patIdxTmp - patIdxStart - 1 );
|
||||
int strLength = ( strIdxEnd - strIdxStart + 1 );
|
||||
int foundIdx = -1;
|
||||
strLoop:
|
||||
for ( int i = 0; i <= strLength - patLength; i++ )
|
||||
{
|
||||
for ( int j = 0; j < patLength; j++ )
|
||||
{
|
||||
String subPat = (String) patDirs.elementAt( patIdxStart + j + 1 );
|
||||
String subStr = (String) strDirs.elementAt( strIdxStart + i + j );
|
||||
if ( !match( subPat, subStr, isCaseSensitive ) )
|
||||
{
|
||||
continue strLoop;
|
||||
}
|
||||
}
|
||||
|
||||
foundIdx = strIdxStart + i;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( foundIdx == -1 )
|
||||
{
|
||||
patDirs = null;
|
||||
strDirs = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
patIdxStart = patIdxTmp;
|
||||
strIdxStart = foundIdx + patLength;
|
||||
}
|
||||
|
||||
for ( int i = patIdxStart; i <= patIdxEnd; i++ )
|
||||
{
|
||||
if ( !patDirs.elementAt( i ).equals( "**" ) )
|
||||
{
|
||||
patDirs = null;
|
||||
strDirs = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether or not a string matches against a pattern.
|
||||
* The pattern may contain two special characters:<br>
|
||||
* '*' means zero or more characters<br>
|
||||
* '?' means one and only one character
|
||||
*
|
||||
* @param pattern The pattern to match against.
|
||||
* Must not be <code>null</code>.
|
||||
* @param str The string which must be matched against the pattern.
|
||||
* Must not be <code>null</code>.
|
||||
* @return <code>true</code> if the string matches against the pattern,
|
||||
* or <code>false</code> otherwise.
|
||||
*/
|
||||
public static boolean match( String pattern, String str )
|
||||
{
|
||||
return match( pattern, str, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether or not a string matches against a pattern.
|
||||
* The pattern may contain two special characters:<br>
|
||||
* '*' means zero or more characters<br>
|
||||
* '?' means one and only one character
|
||||
*
|
||||
* @param pattern The pattern to match against.
|
||||
* Must not be <code>null</code>.
|
||||
* @param str The string which must be matched against the pattern.
|
||||
* Must not be <code>null</code>.
|
||||
* @param isCaseSensitive Whether or not matching should be performed
|
||||
* case sensitively.
|
||||
* @return <code>true</code> if the string matches against the pattern,
|
||||
* or <code>false</code> otherwise.
|
||||
*/
|
||||
public static boolean match( String pattern, String str,
|
||||
boolean isCaseSensitive )
|
||||
{
|
||||
char[] patArr = pattern.toCharArray();
|
||||
char[] strArr = str.toCharArray();
|
||||
int patIdxStart = 0;
|
||||
int patIdxEnd = patArr.length - 1;
|
||||
int strIdxStart = 0;
|
||||
int strIdxEnd = strArr.length - 1;
|
||||
char ch;
|
||||
|
||||
boolean containsStar = false;
|
||||
for ( int i = 0; i < patArr.length; i++ )
|
||||
{
|
||||
if ( patArr[i] == '*' )
|
||||
{
|
||||
containsStar = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !containsStar )
|
||||
{
|
||||
// No '*'s, so we make a shortcut
|
||||
if ( patIdxEnd != strIdxEnd )
|
||||
{
|
||||
return false; // Pattern and string do not have the same size
|
||||
}
|
||||
for ( int i = 0; i <= patIdxEnd; i++ )
|
||||
{
|
||||
ch = patArr[i];
|
||||
if ( ch != '?' )
|
||||
{
|
||||
if ( isCaseSensitive && ch != strArr[i] )
|
||||
{
|
||||
return false;// Character mismatch
|
||||
}
|
||||
if ( !isCaseSensitive && Character.toUpperCase( ch ) !=
|
||||
Character.toUpperCase( strArr[i] ) )
|
||||
{
|
||||
return false; // Character mismatch
|
||||
}
|
||||
}
|
||||
}
|
||||
return true; // String matches against pattern
|
||||
}
|
||||
|
||||
if ( patIdxEnd == 0 )
|
||||
{
|
||||
return true; // Pattern contains only '*', which matches anything
|
||||
}
|
||||
|
||||
// Process characters before first star
|
||||
while ( ( ch = patArr[patIdxStart] ) != '*' && strIdxStart <= strIdxEnd )
|
||||
{
|
||||
if ( ch != '?' )
|
||||
{
|
||||
if ( isCaseSensitive && ch != strArr[strIdxStart] )
|
||||
{
|
||||
return false;// Character mismatch
|
||||
}
|
||||
if ( !isCaseSensitive && Character.toUpperCase( ch ) !=
|
||||
Character.toUpperCase( strArr[strIdxStart] ) )
|
||||
{
|
||||
return false;// Character mismatch
|
||||
}
|
||||
}
|
||||
patIdxStart++;
|
||||
strIdxStart++;
|
||||
}
|
||||
if ( strIdxStart > strIdxEnd )
|
||||
{
|
||||
// All characters in the string are used. Check if only '*'s are
|
||||
// left in the pattern. If so, we succeeded. Otherwise failure.
|
||||
for ( int i = patIdxStart; i <= patIdxEnd; i++ )
|
||||
{
|
||||
if ( patArr[i] != '*' )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Process characters after last star
|
||||
while ( ( ch = patArr[patIdxEnd] ) != '*' && strIdxStart <= strIdxEnd )
|
||||
{
|
||||
if ( ch != '?' )
|
||||
{
|
||||
if ( isCaseSensitive && ch != strArr[strIdxEnd] )
|
||||
{
|
||||
return false;// Character mismatch
|
||||
}
|
||||
if ( !isCaseSensitive && Character.toUpperCase( ch ) !=
|
||||
Character.toUpperCase( strArr[strIdxEnd] ) )
|
||||
{
|
||||
return false;// Character mismatch
|
||||
}
|
||||
}
|
||||
patIdxEnd--;
|
||||
strIdxEnd--;
|
||||
}
|
||||
if ( strIdxStart > strIdxEnd )
|
||||
{
|
||||
// All characters in the string are used. Check if only '*'s are
|
||||
// left in the pattern. If so, we succeeded. Otherwise failure.
|
||||
for ( int i = patIdxStart; i <= patIdxEnd; i++ )
|
||||
{
|
||||
if ( patArr[i] != '*' )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// process pattern between stars. padIdxStart and patIdxEnd point
|
||||
// always to a '*'.
|
||||
while ( patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd )
|
||||
{
|
||||
int patIdxTmp = -1;
|
||||
for ( int i = patIdxStart + 1; i <= patIdxEnd; i++ )
|
||||
{
|
||||
if ( patArr[i] == '*' )
|
||||
{
|
||||
patIdxTmp = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( patIdxTmp == patIdxStart + 1 )
|
||||
{
|
||||
// Two stars next to each other, skip the first one.
|
||||
patIdxStart++;
|
||||
continue;
|
||||
}
|
||||
// Find the pattern between padIdxStart & padIdxTmp in str between
|
||||
// strIdxStart & strIdxEnd
|
||||
int patLength = ( patIdxTmp - patIdxStart - 1 );
|
||||
int strLength = ( strIdxEnd - strIdxStart + 1 );
|
||||
int foundIdx = -1;
|
||||
strLoop:
|
||||
for ( int i = 0; i <= strLength - patLength; i++ )
|
||||
{
|
||||
for ( int j = 0; j < patLength; j++ )
|
||||
{
|
||||
ch = patArr[patIdxStart + j + 1];
|
||||
if ( ch != '?' )
|
||||
{
|
||||
if ( isCaseSensitive && ch != strArr[strIdxStart + i + j] )
|
||||
{
|
||||
continue strLoop;
|
||||
}
|
||||
if ( !isCaseSensitive && Character.toUpperCase( ch ) !=
|
||||
Character.toUpperCase( strArr[strIdxStart + i + j] ) )
|
||||
{
|
||||
continue strLoop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foundIdx = strIdxStart + i;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( foundIdx == -1 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
patIdxStart = patIdxTmp;
|
||||
strIdxStart = foundIdx + patLength;
|
||||
}
|
||||
|
||||
// All characters in the string are used. Check if only '*'s are left
|
||||
// in the pattern. If so, we succeeded. Otherwise failure.
|
||||
for ( int i = patIdxStart; i <= patIdxEnd; i++ )
|
||||
{
|
||||
if ( patArr[i] != '*' )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Breaks a path up into a Vector of path elements, tokenizing on
|
||||
* <code>File.separator</code>.
|
||||
*
|
||||
* @param path Path to tokenize. Must not be <code>null</code>.
|
||||
* @return a Vector of path elements from the tokenized path
|
||||
*/
|
||||
public static Vector tokenizePath( String path )
|
||||
{
|
||||
Vector ret = new Vector();
|
||||
StringTokenizer st = new StringTokenizer( path, File.separator );
|
||||
while ( st.hasMoreTokens() )
|
||||
{
|
||||
ret.addElement( st.nextToken() );
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns dependency information on these two files. If src has been
|
||||
* modified later than target, it returns true. If target doesn't exist,
|
||||
* it likewise returns true. Otherwise, target is newer than src and
|
||||
* is not out of date, thus the method returns false. It also returns
|
||||
* false if the src file doesn't even exist, since how could the
|
||||
* target then be out of date.
|
||||
*
|
||||
* @param src the original file
|
||||
* @param target the file being compared against
|
||||
* @param granularity the amount in seconds of slack we will give in
|
||||
* determining out of dateness
|
||||
* @return whether the target is out of date
|
||||
*/
|
||||
public static boolean isOutOfDate( File src, File target, int granularity )
|
||||
{
|
||||
if ( !src.exists() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ( !target.exists() )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if ( ( src.lastModified() - granularity ) > target.lastModified() )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* "Flattens" a string by removing all whitespace (space, tab, linefeed,
|
||||
* carriage return, and formfeed). This uses StringTokenizer and the
|
||||
* default set of tokens as documented in the single arguement constructor.
|
||||
*
|
||||
* @param input a String to remove all whitespace.
|
||||
* @return a String that has had all whitespace removed.
|
||||
*/
|
||||
public static String removeWhitespace( String input )
|
||||
{
|
||||
StringBuffer result = new StringBuffer();
|
||||
if ( input != null )
|
||||
{
|
||||
StringTokenizer st = new StringTokenizer( input );
|
||||
while ( st.hasMoreTokens() )
|
||||
{
|
||||
result.append( st.nextToken() );
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
|
||||
* @version $Id$
|
||||
*/
|
||||
public class StreamPumper
|
||||
extends Thread
|
||||
{
|
||||
private static final int BUFFER_SIZE = 512;
|
||||
|
||||
private BufferedInputStream stream;
|
||||
private boolean endOfStream = false;
|
||||
private int SLEEP_TIME = 5;
|
||||
private OutputStream out;
|
||||
|
||||
public StreamPumper( BufferedInputStream is, OutputStream out )
|
||||
{
|
||||
this.stream = is;
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
public void pumpStream() throws IOException
|
||||
{
|
||||
byte[] buf = new byte[BUFFER_SIZE];
|
||||
if ( !endOfStream )
|
||||
{
|
||||
int bytesRead = stream.read( buf, 0, BUFFER_SIZE );
|
||||
|
||||
if ( bytesRead > 0 )
|
||||
{
|
||||
out.write( buf, 0, bytesRead );
|
||||
}
|
||||
else if ( bytesRead == -1 )
|
||||
{
|
||||
endOfStream = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
while ( !endOfStream )
|
||||
{
|
||||
pumpStream();
|
||||
sleep( SLEEP_TIME );
|
||||
}
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
// getLogger().warn("Jikes.run()", e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* <p>Common <code>String</code> manipulation routines.</p>
|
||||
* <p/>
|
||||
* <p>Originally from
|
||||
* <a href="http://jakarta.codehaus.org/turbine/">Turbine</a> and the
|
||||
* GenerationJavaCore library.</p>
|
||||
*
|
||||
* @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
|
||||
* @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
|
||||
* @author <a href="mailto:gcoladonato@yahoo.com">Greg Coladonato</a>
|
||||
* @author <a href="mailto:bayard@generationjava.com">Henri Yandell</a>
|
||||
* @author <a href="mailto:ed@codehaus.org">Ed Korthof</a>
|
||||
* @author <a href="mailto:rand_mcneely@yahoo.com">Rand McNeely</a>
|
||||
* @author Stephen Colebourne
|
||||
* @author <a href="mailto:fredrik@westermarck.com">Fredrik Westermarck</a>
|
||||
* @author Holger Krauth
|
||||
* @author <a href="mailto:alex@purpletech.com">Alexander Day Chaffee</a>
|
||||
* @version $Id$
|
||||
* @since 1.0
|
||||
*/
|
||||
public class StringUtils
|
||||
{
|
||||
public static String[] split( String str )
|
||||
{
|
||||
return split( str, null, -1 );
|
||||
}
|
||||
|
||||
public static String[] split( String text, String separator )
|
||||
{
|
||||
return split( text, separator, -1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Splits the provided text into a array, based on a given separator.</p>
|
||||
* <p/>
|
||||
* <p>The separator is not included in the returned String array. The
|
||||
* maximum number of splits to perfom can be controlled. A <code>null</code>
|
||||
* separator will cause parsing to be on whitespace.</p>
|
||||
* <p/>
|
||||
* <p>This is useful for quickly splitting a String directly into
|
||||
* an array of tokens, instead of an enumeration of tokens (as
|
||||
* <code>StringTokenizer</code> does).</p>
|
||||
*
|
||||
* @param str The string to parse.
|
||||
* @param separator Characters used as the delimiters. If
|
||||
* <code>null</code>, splits on whitespace.
|
||||
* @param max The maximum number of elements to include in the
|
||||
* array. A zero or negative value implies no limit.
|
||||
* @return an array of parsed Strings
|
||||
*/
|
||||
public static String[] split( String str, String separator, int max )
|
||||
{
|
||||
StringTokenizer tok = null;
|
||||
if ( separator == null )
|
||||
{
|
||||
// Null separator means we're using StringTokenizer's default
|
||||
// delimiter, which comprises all whitespace characters.
|
||||
tok = new StringTokenizer( str );
|
||||
}
|
||||
else
|
||||
{
|
||||
tok = new StringTokenizer( str, separator );
|
||||
}
|
||||
|
||||
int listSize = tok.countTokens();
|
||||
if ( max > 0 && listSize > max )
|
||||
{
|
||||
listSize = max;
|
||||
}
|
||||
|
||||
String[] list = new String[listSize];
|
||||
int i = 0;
|
||||
int lastTokenBegin = 0;
|
||||
int lastTokenEnd = 0;
|
||||
while ( tok.hasMoreTokens() )
|
||||
{
|
||||
if ( max > 0 && i == listSize - 1 )
|
||||
{
|
||||
// In the situation where we hit the max yet have
|
||||
// tokens left over in our input, the last list
|
||||
// element gets all remaining text.
|
||||
String endToken = tok.nextToken();
|
||||
lastTokenBegin = str.indexOf( endToken, lastTokenEnd );
|
||||
list[i] = str.substring( lastTokenBegin );
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
list[i] = tok.nextToken();
|
||||
lastTokenBegin = str.indexOf( list[i], lastTokenEnd );
|
||||
lastTokenEnd = lastTokenBegin + list[i].length();
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static String replaceOnce( String text, String repl, String with )
|
||||
{
|
||||
return replace( text, repl, with, 1 );
|
||||
}
|
||||
|
||||
public static String replace( String text, String repl, String with )
|
||||
{
|
||||
return replace( text, repl, with, -1 );
|
||||
}
|
||||
|
||||
public static String replace( String text, String repl, String with, int max )
|
||||
{
|
||||
if ( text == null || repl == null || with == null || repl.length() == 0 )
|
||||
{
|
||||
return text;
|
||||
}
|
||||
|
||||
StringBuffer buf = new StringBuffer( text.length() );
|
||||
int start = 0, end = 0;
|
||||
while ( ( end = text.indexOf( repl, start ) ) != -1 )
|
||||
{
|
||||
buf.append( text.substring( start, end ) ).append( with );
|
||||
start = end + repl.length();
|
||||
|
||||
if ( --max == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
buf.append( text.substring( start ) );
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static String interpolate( String text, Map namespace )
|
||||
{
|
||||
Iterator keys = namespace.keySet().iterator();
|
||||
|
||||
while ( keys.hasNext() )
|
||||
{
|
||||
String key = keys.next().toString();
|
||||
|
||||
Object obj = namespace.get( key );
|
||||
|
||||
String value = obj.toString();
|
||||
|
||||
text = StringUtils.replace( text, "${" + key + "}", value );
|
||||
|
||||
if ( key.indexOf( " " ) == -1 )
|
||||
{
|
||||
text = StringUtils.replace( text, "$" + key, value );
|
||||
}
|
||||
}
|
||||
return text;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,183 @@
|
|||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
public class SurefireBooter
|
||||
{
|
||||
private List batteries = new ArrayList();
|
||||
|
||||
private List reports = new ArrayList();
|
||||
|
||||
private List classpathUrls = new ArrayList();
|
||||
|
||||
public SurefireBooter()
|
||||
{
|
||||
}
|
||||
|
||||
public void addBattery( String battery, Object[] params )
|
||||
{
|
||||
batteries.add( new Object[]{ battery, params } );
|
||||
}
|
||||
|
||||
public void addBattery( String battery )
|
||||
{
|
||||
batteries.add( new Object[]{ battery, null } );
|
||||
}
|
||||
|
||||
public void addReport( String report )
|
||||
{
|
||||
reports.add( report );
|
||||
}
|
||||
|
||||
public void addClassPathUrl( String path )
|
||||
{
|
||||
if ( !classpathUrls.contains( path ) )
|
||||
{
|
||||
classpathUrls.add( path );
|
||||
}
|
||||
}
|
||||
|
||||
public boolean run()
|
||||
throws Exception
|
||||
{
|
||||
IsolatedClassLoader surefireClassLoader = new IsolatedClassLoader();
|
||||
|
||||
for ( Iterator i = classpathUrls.iterator(); i.hasNext(); )
|
||||
{
|
||||
String url = (String) i.next();
|
||||
|
||||
if ( url != null )
|
||||
{
|
||||
surefireClassLoader.addURL( new File( url ).toURL() );
|
||||
}
|
||||
}
|
||||
|
||||
Class batteryExecutorClass = surefireClassLoader.loadClass( "org.codehaus.surefire.Surefire" );
|
||||
|
||||
Object batteryExecutor = batteryExecutorClass.newInstance();
|
||||
|
||||
Method run = batteryExecutorClass.getMethod( "run", new Class[] { List.class, List.class, ClassLoader.class } );
|
||||
|
||||
ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
|
||||
|
||||
Thread.currentThread().setContextClassLoader( surefireClassLoader );
|
||||
|
||||
Boolean result = (Boolean) run.invoke( batteryExecutor, new Object[]{ reports, batteries, surefireClassLoader } );
|
||||
|
||||
Thread.currentThread().setContextClassLoader( oldContextClassLoader );
|
||||
|
||||
return result.booleanValue();
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
batteries.clear();
|
||||
|
||||
reports.clear();
|
||||
|
||||
classpathUrls.clear();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Main
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
public static void main( String[] args )
|
||||
throws Exception
|
||||
{
|
||||
String basedir = args[0];
|
||||
|
||||
System.setProperty( "basedir", basedir );
|
||||
|
||||
String mavenRepoLocal = args[1];
|
||||
|
||||
File dependenciesFile = new File( args[2] );
|
||||
|
||||
List dependencies = new ArrayList();
|
||||
|
||||
BufferedReader buf = new BufferedReader( new FileReader( dependenciesFile ) );
|
||||
|
||||
String line;
|
||||
|
||||
while ( ( line = buf.readLine() ) != null )
|
||||
{
|
||||
dependencies.add( line );
|
||||
}
|
||||
|
||||
buf.close();
|
||||
|
||||
File includesFile = new File( args[3] );
|
||||
|
||||
List includes = new ArrayList();
|
||||
|
||||
buf = new BufferedReader( new FileReader( includesFile ) );
|
||||
|
||||
line = buf.readLine();
|
||||
|
||||
String includesStr = line.substring( line.indexOf( "@" ) + 1 );
|
||||
|
||||
StringTokenizer st = new StringTokenizer( includesStr, "," );
|
||||
|
||||
while ( st.hasMoreTokens() )
|
||||
{
|
||||
String inc = st.nextToken().trim();
|
||||
|
||||
includes.add( inc );
|
||||
}
|
||||
|
||||
buf.close();
|
||||
|
||||
File excludesFile = new File( args[4] );
|
||||
|
||||
List excludes = new ArrayList();
|
||||
|
||||
buf = new BufferedReader( new FileReader( excludesFile ) );
|
||||
|
||||
line = buf.readLine();
|
||||
|
||||
String excludesStr = line.substring( line.indexOf( "@" ) + 1 );
|
||||
|
||||
st = new StringTokenizer( excludesStr, "," );
|
||||
|
||||
while ( st.hasMoreTokens() )
|
||||
{
|
||||
excludes.add( st.nextToken().trim() );
|
||||
}
|
||||
|
||||
buf.close();
|
||||
|
||||
SurefireBooter surefireBooter = new SurefireBooter();
|
||||
|
||||
surefireBooter.addBattery( "org.codehaus.surefire.battery.DirectoryBattery", new Object[]{ basedir, includes, excludes } );
|
||||
|
||||
surefireBooter.addClassPathUrl( new File( mavenRepoLocal, "junit/jars/junit-3.8.1.jar" ).getPath() );
|
||||
|
||||
surefireBooter.addClassPathUrl( new File( mavenRepoLocal, "surefire/jars/surefire-1.1.jar" ).getPath() );
|
||||
|
||||
surefireBooter.addClassPathUrl( new File( basedir, "target/classes/" ).getPath() );
|
||||
|
||||
surefireBooter.addClassPathUrl( new File( basedir, "target/test-classes/" ).getPath() );
|
||||
|
||||
processDependencies( dependencies, surefireBooter );
|
||||
|
||||
surefireBooter.addReport( "org.codehaus.surefire.report.ConsoleReport" );
|
||||
|
||||
surefireBooter.run();
|
||||
}
|
||||
|
||||
private static void processDependencies( List dependencies, SurefireBooter sureFire )
|
||||
throws Exception
|
||||
{
|
||||
for ( Iterator i = dependencies.iterator(); i.hasNext(); )
|
||||
{
|
||||
String dep = (String) i.next();
|
||||
|
||||
sureFire.addClassPathUrl( new File( dep ).getPath() );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
public class SurefirePlugin
|
||||
{
|
||||
public boolean execute( String mavenRepoLocal,
|
||||
String basedir,
|
||||
String classesDirectory,
|
||||
String testClassesDirectory,
|
||||
List includes,
|
||||
List excludes,
|
||||
String[] classpathElements )
|
||||
throws Exception
|
||||
{
|
||||
System.setProperty( "basedir", basedir );
|
||||
|
||||
SurefireBooter surefireBooter = new SurefireBooter();
|
||||
|
||||
surefireBooter.addBattery( "org.codehaus.surefire.battery.DirectoryBattery", new Object[]{basedir, includes, excludes} );
|
||||
|
||||
surefireBooter.addClassPathUrl( new File( mavenRepoLocal, "junit/jars/junit-3.8.1.jar" ).getPath() );
|
||||
|
||||
surefireBooter.addClassPathUrl( new File( mavenRepoLocal, "surefire/jars/surefire-1.1.jar" ).getPath() );
|
||||
|
||||
surefireBooter.addClassPathUrl( new File( classesDirectory ).getPath() );
|
||||
|
||||
surefireBooter.addClassPathUrl( new File( testClassesDirectory ).getPath() );
|
||||
|
||||
for ( int i = 0; i < classpathElements.length; i++ )
|
||||
{
|
||||
surefireBooter.addClassPathUrl( classpathElements[i] );
|
||||
}
|
||||
|
||||
surefireBooter.addReport( "org.codehaus.surefire.report.ConsoleReport" );
|
||||
|
||||
return surefireBooter.run();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
junit/jars/junit-3.8.1.jar
|
||||
surefire/jars/surefire-booter-1.1.jar
|
||||
surefire/jars/surefire-1.1.jar
|
||||
modello/jars/modello-1.0-SNAPSHOT.jar
|
||||
xpp3/jars/xpp3-1.1.3.3.jar
|
||||
xstream/jars/xstream-1.0-SNAPSHOT.jar
|
||||
qdox/jars/qdox-1.2.jar
|
||||
maven/jars/maven-plugin-2.0-SNAPSHOT.jar
|
Loading…
Reference in New Issue