diff --git a/maven-mboot/README.txt b/maven-mboot/README.txt new file mode 100644 index 0000000000..f797871b72 --- /dev/null +++ b/maven-mboot/README.txt @@ -0,0 +1,13 @@ +How to use mboot +---------------- + +o export MBOOT_HOME= +o export PATH=$PATH:$MBOOT_HOME +o ./build +o cd target +o ./mboot-install.sh +o mboot + +mboot will build Maven projects that are relatively simple. It will build +a JAR and package any resources into the JAR. Good enough for Maven itself +and the plugins but appears to be useful for other things. diff --git a/maven-mboot/build b/maven-mboot/build new file mode 100755 index 0000000000..4b9c784b0e --- /dev/null +++ b/maven-mboot/build @@ -0,0 +1,28 @@ +#!/bin/sh + +. src/bash/maven.functions + +compile . target/classes src/main + +isCommandSuccessful $? "Failed compiling Maven bootstrapper classes!" + +DIST=target/mboot + +rm -rf $DIST > /dev/null 2>&1 + +mkdir -p $DIST + +cp -r target/classes $DIST + +cp src/bash/* $DIST + +( + cd target/mboot + + tar cvzf ../mboot.tar.gz * +) + +cat src/sea/sea-header target/mboot.tar.gz > target/mboot-install.sh + +chmod +x target/mboot-install.sh + diff --git a/maven-mboot/src/bash/maven.functions b/maven-mboot/src/bash/maven.functions new file mode 100755 index 0000000000..89ce1dcb5b --- /dev/null +++ b/maven-mboot/src/bash/maven.functions @@ -0,0 +1,271 @@ +# ----------------------------------------------------------------------------- +# Maven functions +# +# @author Jason van Zyl +# ----------------------------------------------------------------------------- + +isCommandSuccessful() +{ + # $1 == $? + # $2 == Error message on failure + + ret=$1 + if [ $ret != 0 ]; then + echo $2 + exit $ret + fi +} + +runJava() +{ + # $1 == classpath + # $2 == Main class + # $3 == Mail args + + "${JAVACMD}" -classpath $1 $2 "$3" +} + +compile() +{ + # $1 == classpath + # $2 == destination for compiled classes + # $3 == source directory + # $4 == any extra sources + + if [ -d $3 ] + then + + if [ ! -d $2 ] + then + mkdir -p $2 + fi + + SOURCES=`find $3 -name '*.java'` + + "${JAVAC}" -classpath $1 -d $2 ${SOURCES} $4 + + fi +} + +buildJar() +{ + # $1 == directory to JAR + # $2 == JAR path relative to the cwd + + ( + dir=`pwd` + cd $1 + ${JAVA_HOME}/bin/jar -cf ${dir}/$2 * + ) +} + +buildMavenProject() +{ + # 1. Parse the model + # 2. Download any required dependencies + # 3. Compile the sources + # 4. Move required resources into location + # 5. Create JAR. + + # I can use maven-model and I can detach maven-model-tools from + # Plexus so that I can use it for this tool. I can just use the + # command line compiler for now. + + # $1 == directory where project lives + # $4 == jar name + # $5 == flag to leave mboot files + + ( + home=`pwd` + + cd $1 + + # Look for source directory in project.xml + sourceDirectory=`grep sourceDirectory project.xml | sed -e 's/^*//;s///;s/<\/sourceDirectory>//'` + + [ -z $sourceDirectory ] && sourceDirectory=src/main + + buildDir=target + buildDest=target/classes + + [ -d $buildDir ] && rm -rf $buildDir + + echo "Building project in `pwd`" + echo "sourceDirectory = $sourceDirectory" + echo "buildDest = ${buildDest}" + + runJava ${MBOOT_HOME}/classes Bootstrapper ${home} + + isCommandSuccessful $? "Failed running project parser!" + + projectDependencyClassPath=`cat bootstrap.classpath`:. + + if [ ! -z $sourceDirectory ] && [ -d $sourceDirectory ] + then + + compile $projectDependencyClassPath $buildDest $sourceDirectory + + isCommandSuccessful $? "Failed compiling classes!" + + fi + + copyResources + + if [ -z $2 ] + then + jarName=`getJarName project.xml` + else + jarName=$2 + fi + + buildJar $buildDest target/${jarName} + + if [ -z $3 ] + then + rm -f bootstrap.classpath > /dev/null 2>&1 + rm -f bootstrap.libs > /dev/null 2>&1 + rm -f bootstrap.resources > /dev/null 2>&1 + fi + ) +} + +getJarName() +{ + # $1 == project.xml + + version=`grep currentVersion $1 | sed -e 's/^ *//;s///;s/<\/currentVersion>//'` + + artifactId=`grep artifactId $1 | sed -e 's/^ *//;s///;s/<\/artifactId>//' | awk 'BEGIN { FS = "\n"; RS="" } { print $1 }'` + + if [ -z $artifactId ] + then + + artifactId=`grep id $1 | sed -e 's/^ *//;s///;s/<\/id>//' | awk 'BEGIN { FS = "\n"; RS="" } { print $1 }'` + + fi + + jarName="${artifactId}-${version}.jar" + + echo $jarName +} + +copyResources() +{ + resources=`cat bootstrap.resources` + + for i in $resources + do + directory=`echo $i | awk 'BEGIN { FS = "@" } { print $1 }' | awk 'BEGIN { FS = "," } { print $1 }'` + targetPath=`echo $i | awk 'BEGIN { FS = "@" } { print $1 }' | awk 'BEGIN { FS = "," } { print $2 }'` + includes=`echo $i | awk 'BEGIN { FS = "@" } { print $2 }' | awk 'BEGIN { FS = "," } { for ( j = 1; j <= NF; j++ ) { printf( "%s ", $j ) } }'` + + for include in $includes + do + files=`eval "find $directory -name $include"` + + for file in $files + do + # Replace the "/" with "@" to prevent shell expansion of *.properties + # to *.properties in the CWD. + tmpDirectory=`echo $directory | sed "s/\//@/g"` + tmpFile=`echo $file | sed "s/\//@/g"` + + # Now grab the path excluding the original directory so we can translate that + # path into the target directory. + path=`echo $tmpFile | sed "s/$tmpDirectory//;s/\@/\//g;s/^\///"` + + translatedPath=`dirname $path` + + targetDirectory="target/classes" + + if [ ! -z $targetPath ] + then + targetDirectory="${targetDirectory}/${targetPath}" + else + targetDirectory="${targetDirectory}/${translatedPath}" + fi + + [ ! -d $targetDirectory ] && mkdir -p $targetDirectory + + cp $file $targetDirectory + + done + done + done +} + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +case "`uname`" in + CYGWIN*) cygwin=true ;; + Darwin*) darwin=true + if [ -z "$JAVA_HOME" ] ; then + JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Home + fi + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# You will need to specify JAVA_HOME if compiling with 1.2 or later. + +if [ -n "$JAVA_HOME" ] ; then + if [ -f "$JAVA_HOME/lib/tools.jar" ] ; then + CLASSPATH=$CLASSPATH:$JAVA_HOME/lib/tools.jar + fi + + if [ -f "$JAVA_HOME/lib/classes.zip" ] ; then + CLASSPATH=$CLASSPATH:$JAVA_HOME/lib/classes.zip + fi +else + echo "Warning: JAVA_HOME environment variable not set." + echo " If build fails because sun.* classes could not be found" + echo " you will need to set the JAVA_HOME environment variable" + echo " to the installation directory of java." +fi + +# IBM's JDK on AIX uses strange locations for the executables: +# JAVA_HOME/jre/sh for java and rmid +# JAVA_HOME/sh for javac and rmic +if [ -z "$JAVAC" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/sh/javac" ] ; then + JAVAC=${JAVA_HOME}/sh/javac; + else + JAVAC=${JAVA_HOME}/bin/javac; + fi + else + JAVAC=javac + fi +fi +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + else + JAVACMD=java + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." + echo " We cannot execute $JAVACMD" + exit +fi + +# For Cygwin, switch to Windows format before running java +if $cygwin; then + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` +fi + +export CLASSPATH diff --git a/maven-mboot/src/bash/mboot b/maven-mboot/src/bash/mboot new file mode 100755 index 0000000000..ba23fab7b2 --- /dev/null +++ b/maven-mboot/src/bash/mboot @@ -0,0 +1,50 @@ +#!/bin/sh + +[ -z $MBOOT_HOME ] && echo && echo "You must set MBOOT_HOME to use mboot!" && echo && exit + +. ${MBOOT_HOME}/maven.functions + +VERSION=1.0 + +dir="." +jar="" +leaveBootFiles="" + +while [ $# -gt 0 ]; do + case $1 in + --version) + echo "mboot: version $VERSION" + exit 0 + ;; + -v) + verbose=-v + ;; + --dir*) + if echo $1 | grep -q '=' ; then + dir=`echo $1 | sed 's/^--dir=//'` + else + dir=$2 + shift + fi + ;; + --jar*) + if echo $1 | grep -q '=' ; then + jar=`echo $1 | sed 's/^--jar=//'` + else + jar=$2 + shift + fi + ;; + --leave-boot-files) + leaveBootFiles=1; + ;; + esac + + shift +done + +[ ! -d $dir ] && echo "Specified directory doesn't exist!" && exit + +[ ! -f $dir/project.xml ] && echo "No project.xml in specified directory!" && exit + +buildMavenProject $dir $jar $leaveBootFiles diff --git a/maven-mboot/src/main/Bootstrapper.java b/maven-mboot/src/main/Bootstrapper.java new file mode 100644 index 0000000000..fcfbd3b23a --- /dev/null +++ b/maven-mboot/src/main/Bootstrapper.java @@ -0,0 +1,718 @@ +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.SAXParseException; +import org.xml.sax.helpers.DefaultHandler; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Properties; + +public class Bootstrapper +{ + private BootstrapPomParser bootstrapPomParser; + + private List dependencies; + + private List resources; + + private File mavenRepoLocal; + + private boolean useTimestamp = true; + + private boolean ignoreErrors = true; + + private String baseUrl; + + private String proxyHost; + + private String proxyPort; + + private String proxyUserName; + + private String proxyPassword; + + public static void main( String[] args ) + throws Exception + { + Bootstrapper bootstrapper = new Bootstrapper(); + + bootstrapper.execute( args ); + } + + public void execute( String[] args ) + throws Exception + { + String basedir = args[0]; + + Properties properties = loadProperties( new File( System.getProperty( "user.home" ), "build.properties" ) ); + + baseUrl = properties.getProperty( "maven.repo.remote" ); + + if ( baseUrl == null ) + { + baseUrl = "http://www.ibiblio.org/maven/"; + } + + 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 ); + } + + System.out.println( "Using the following for your maven.repo.local: " + mavenRepoLocal ); + + bootstrapPomParser = new BootstrapPomParser(); + + bootstrapPomParser.parse( new File( "project.xml" ) ); + + dependencies = bootstrapPomParser.getDependencies(); + + List list = new ArrayList(); + + for ( Iterator i = dependencies.iterator(); i.hasNext(); ) + { + Dependency d = (Dependency) i.next(); + + list.add( getArtifactPath( d, "/" ) ); + } + + downloadDependencies( list ); + + StringBuffer classPath = new StringBuffer(); + + StringBuffer libs = new StringBuffer(); + + for ( Iterator i = dependencies.iterator(); i.hasNext(); ) + { + Dependency d = (Dependency) i.next(); + + classPath.append( mavenRepoLocal + "/" + getArtifactPath( d, "/" ) + ":" ); + + libs.append( mavenRepoLocal + "/" + getArtifactPath( d, "/" ) + "\n" ); + + } + + FileWriter writer = new FileWriter( "bootstrap.classpath" ); + + writer.write( classPath.toString() ); + + writer.close(); + + writer = new FileWriter( "bootstrap.libs" ); + + writer.write( libs.toString() ); + + writer.close(); + + resources = bootstrapPomParser.getResources(); + + StringBuffer res = new StringBuffer(); + + for ( Iterator i = resources.iterator(); i.hasNext(); ) + { + Resource r = (Resource) i.next(); + + // Not sure why r would be null. Happening in drools-core. + if ( r == null ) + { + continue; + } + + res.append( r.getDirectory() ); + + if ( r.getTargetPath() != null ) + { + res.append( "," ).append( r.getTargetPath() ); + } + + res.append( "@" ); + + int size = r.getIncludes().size(); + + for ( int j = 0; j < size; j++ ) + { + String include = (String) r.getIncludes().get( j ); + + if ( include.startsWith( "**/" ) ) + { + include = include.substring( 3 ); + } + + res.append("'").append( include ).append("'"); + + if ( j != size - 1 ) + { + res.append( "," ); + } + } + + res.append( "\n" ); + } + + writer = new FileWriter( "bootstrap.resources" ); + + writer.write( res.toString() ); + + writer.close(); + } + + private String getArtifactPath( Dependency d, String pathSeparator ) + { + return d.getArtifactDirectory() + pathSeparator + "jars" + pathSeparator + d.getArtifact(); + } + + private 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() ) + { + continue; + } + + log( "Downloading dependency: " + baseUrl + file ); + + int numRetries = 3; + + while ( numRetries >= 0 ) + { + try + { + HttpUtils.getFile( baseUrl + file, + destinationFile, + ignoreErrors, + useTimestamp, + proxyHost, + proxyPort, + proxyUserName, + proxyPassword ); + break; + } + catch ( Exception e ) + { + numRetries--; + + continue; + } + } + if ( !destinationFile.exists() ) + { + throw new Exception( "Failed to download " + baseUrl + file ); + } + } + catch ( Exception e ) + { + throw new Exception( e ); + } + } + } + + private void log( String message ) + { + System.out.println( message ); + } + + private Properties loadProperties( File file ) + { + try + { + return loadProperties( new FileInputStream( file ) ); + } + catch ( Exception e ) + { + // ignore + } + + return null; + } + + private static Properties loadProperties( InputStream is ) + { + try + { + Properties properties = new Properties(); + + if ( is != null ) + { + properties.load( is ); + } + + return properties; + } + catch ( IOException e ) + { + // ignore + } + finally + { + try + { + if ( is != null ) + { + is.close(); + } + } + catch ( IOException e ) + { + // ignore + } + } + + return null; + } + + static class BootstrapPomParser + extends DefaultHandler + { + private List dependencies = new ArrayList(); + + private List resources = new ArrayList(); + + private Dependency currentDependency; + + private Resource currentResource; + + private static SAXParserFactory saxFactory; + + private boolean insideDependency = false; + + private boolean insideUnitTest = false; + + private boolean insideResource = false; + + private StringBuffer bodyText = new StringBuffer(); + + private File file; + + public List getDependencies() + { + return dependencies; + } + + public List getResources() + { + return resources; + } + + public void parse( File file ) + { + this.file = file; + + try + { + saxFactory = SAXParserFactory.newInstance(); + + SAXParser parser = saxFactory.newSAXParser(); + + InputSource is = new InputSource( new FileInputStream( file ) ); + + parser.parse( is, this ); + } + catch ( Exception e ) + { + e.printStackTrace(); + } + } + + public void startElement( String uri, String localName, String rawName, Attributes attributes ) + { + if ( insideUnitTest ) + { + return; + } + else if( rawName.equals( "unitTest" ) ) + { + insideUnitTest = true; + } + else if ( rawName.equals( "dependency" ) ) + { + currentDependency = new Dependency(); + + insideDependency = true; + } + else if ( rawName.equals( "resource" ) ) + { + currentResource = new Resource(); + + insideResource = true; + } + } + + public void characters( char buffer[], int start, int length ) + { + bodyText.append( buffer, start, length ); + } + + private String getBodyText() + { + return bodyText.toString().trim(); + } + + public void endElement( String uri, String localName, String rawName ) + { + if ( rawName.equals( "extend" ) ) + { + String extend = getBodyText(); + + File f = new File( file.getParentFile(), extend ); + + BootstrapPomParser p = new BootstrapPomParser(); + + p.parse( f ); + + dependencies.addAll( p.getDependencies() ); + + resources.addAll( p.getResources() ); + } + else if ( rawName.equals( "unitTest" ) ) + { + insideUnitTest = false; + } + else if ( rawName.equals( "dependency" ) ) + { + dependencies.add( currentDependency ); + + insideDependency = false; + } + else if ( rawName.equals( "resource" ) ) + { + resources.add( currentResource ); + + insideResource = false; + } + else if ( insideDependency ) + { + if ( rawName.equals( "id" ) ) + { + currentDependency.setId( getBodyText() ); + } + else if ( rawName.equals( "version" ) ) + { + currentDependency.setVersion( getBodyText() ); + } + else if ( rawName.equals( "jar" ) ) + { + currentDependency.setJar( getBodyText() ); + } + else if ( rawName.equals( "type" ) ) + { + currentDependency.setType( getBodyText() ); + } + else if ( rawName.equals( "groupId" ) ) + { + currentDependency.setGroupId( getBodyText() ); + } + else if ( rawName.equals( "artifactId" ) ) + { + currentDependency.setArtifactId( getBodyText() ); + } + + } + else if ( insideResource ) + { + if ( rawName.equals( "directory" ) ) + { + currentResource.setDirectory( getBodyText() ); + } + else if ( rawName.equals( "targetPath" ) ) + { + currentResource.setTargetPath( getBodyText() ); + } + else if ( rawName.equals( "include" ) ) + { + currentResource.addInclude( getBodyText() ); + } + else if ( rawName.equals( "exclude" ) ) + { + currentResource.addExclude( getBodyText() ); + } + } + + bodyText = new StringBuffer(); + } + + public void warning( SAXParseException spe ) + { + printParseError( "Warning", spe ); + } + + public void error( SAXParseException spe ) + { + printParseError( "Error", spe ); + } + + public void fatalError( SAXParseException spe ) + { + printParseError( "Fatal Error", spe ); + } + + private final void printParseError( String type, SAXParseException spe ) + { + System.err.println( type + " [line " + spe.getLineNumber() + + ", row " + spe.getColumnNumber() + "]: " + + spe.getMessage() ); + } + } + + public static class Dependency + { + private String id; + + private String version; + + private String url; + + private String jar; + + private String artifactId; + + private String groupId; + + private String type = "jar"; + + public Dependency() + { + } + + public void setId( String id ) + { + this.id = id; + } + + public String getId() + { + if ( isValid( getGroupId() ) + && isValid( getArtifactId() ) ) + { + // We have something like: + // + // + // commons-jelly + // commons-jelly-tags-velocity + // SNAPSHOT + // + + return getGroupId() + ":" + getArtifactId(); + } + + return id; + } + + public void setGroupId( String groupId ) + { + this.groupId = groupId; + } + + public String getGroupId() + { + return groupId; + } + + public String getArtifactDirectory() + { + if ( isValid( getGroupId() ) ) + { + return getGroupId(); + } + + return getId(); + } + + public String getArtifactId() + { + return artifactId; + } + + public void setArtifactId( String artifactId ) + { + this.artifactId = artifactId; + } + + public String getArtifact() + { + // If the jar name has been explicty set then use that. This + // is when the element is explicity used in the POM. + if ( jar != null) + { + return jar; + } + + if ( isValid( getArtifactId() ) ) + { + return getArtifactId() + "-" + getVersion() + "." + getType(); + } + else + { + return getId() + "-" + getVersion() + "." + getType(); + } + } + + public void setVersion( String version ) + { + this.version = version; + } + + public String getVersion() + { + return version; + } + + public void setJar( String jar ) + { + // This is a check we need because of the jelly interpolation + // process. If we don't check an empty string will be set and + // screw up getArtifact() above. + if ( jar.trim().length() == 0 ) + { + return; + } + + this.jar = jar; + } + + public String getJar() + { + return jar; + } + + public void setUrl( String url ) + { + this.url = url; + } + + public String getUrl() + { + return url; + } + + public String getType() + { + return type; + } + + public void setType( String type ) + { + this.type = type; + } + + private boolean isValid( String value ) + { + if ( value != null + && value.trim().equals("") == false ) + { + return true; + } + + return false; + } + } + + public static class Resource + implements Serializable + { + private String directory; + + private String targetPath; + + private List includes = new ArrayList(); + + private List excludes = new ArrayList(); + + private boolean filtering; + + public void addInclude( String pattern ) + { + this.includes.add( pattern ); + } + + public void addExclude( String pattern ) + { + this.excludes.add( pattern ); + } + + public List getIncludes() + { + return this.includes; + } + + public List getExcludes() + { + return this.excludes; + } + + public void setDirectory( String directory ) + { + this.directory = directory; + } + + public String getDirectory() + { + return this.directory; + } + + public void setTargetPath( String targetPath ) + { + this.targetPath = targetPath; + } + + public String getTargetPath() + { + return targetPath; + } + + public boolean getFiltering() + { + return filtering; + } + + public void setFiltering( boolean filtering ) + { + this.filtering = filtering; + } + } +} diff --git a/maven-mboot/src/main/HttpUtils.java b/maven-mboot/src/main/HttpUtils.java new file mode 100644 index 0000000000..0e021be0bf --- /dev/null +++ b/maven-mboot/src/main/HttpUtils.java @@ -0,0 +1,336 @@ +import java.io.File; +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 Jason van Zyl + * + * @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 + */ + 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. Returns true if the file was successfully + * retrieved or if it is up to date (when the useTimestamp flag is set). + * + * @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 + * destinationFile against the remote source + * @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. + */ + public static void getFile( String url, + File destinationFile, + boolean ignoreErrors, + boolean useTimestamp, + String proxyHost, + String proxyPort, + String proxyUserName, + String proxyPassword, + boolean useChecksum ) + throws Exception + { + // 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. Returns true if the file was successfully + * retrieved or if it is up to date (when the useTimestamp flag is set). + * + * @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 + * destinationFile against the remote source + * @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 + */ + public static void getFile( String url, + File destinationFile, + boolean ignoreErrors, + boolean useTimestamp, + String proxyHost, + String proxyPort, + String proxyUserName, + String proxyPassword ) + throws Exception + { + String[] s = parseUrl( url ); + String username = s[0]; + String password = s[1]; + String parsedUrl = s[2]; + + URL source = new URL( parsedUrl ); + + //set the timestamp to the file date. + long timestamp = 0; + boolean hasTimestamp = false; + if ( useTimestamp && destinationFile.exists() ) + { + timestamp = destinationFile.lastModified(); + hasTimestamp = true; + } + + //set proxy connection + useProxyUser( proxyHost, proxyPort, proxyUserName, proxyPassword ); + + //set up the URL connection + URLConnection connection = source.openConnection(); + //modify the headers + //NB: things like user authentication could go in here too. + if ( useTimestamp && hasTimestamp ) + { + connection.setIfModifiedSince( timestamp ); + } + // prepare Java 1.1 style credentials + if ( username != null || password != null ) + { + String up = username + ":" + password; + String encoding = null; + // check to see if sun's Base64 encoder is available. + try + { + sun.misc.BASE64Encoder encoder = + (sun.misc.BASE64Encoder) Class.forName( + "sun.misc.BASE64Encoder" ).newInstance(); + + encoding = encoder.encode( up.getBytes() ); + } + catch ( Exception ex ) + { + // Do nothing, as for MavenSession we will never use + // auth and we will eventually move over httpclient + // in the commons. + } + 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; + if ( httpConnection.getResponseCode() == HttpURLConnection.HTTP_NOT_MODIFIED ) + { + return; + } + // test for 401 result (HTTP only) + if ( httpConnection.getResponseCode() == HttpURLConnection.HTTP_UNAUTHORIZED ) + { + throw new Exception( "Not authorized." ); + } + } + + // 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; + for ( int i = 0; i < 3; i++ ) + { + try + { + is = connection.getInputStream(); + break; + } + catch ( IOException ex ) + { + // do nothing + } + } + if ( is == null ) + { + if ( ignoreErrors ) + { + return; + } + + // This will never happen with maven's use of this class. + throw new Exception( "Can't get " + destinationFile.getName() + " to " + destinationFile ); + } + + 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 ( useTimestamp ) + { + 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. + */ + 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 s = url.substring( 7, i ); + int j = s.indexOf( ":" ); + parsedUrl[0] = s.substring( 0, j ); + parsedUrl[1] = s.substring( j + 1 ); + parsedUrl[2] = "http://" + 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 + * @exception Exception Thrown in unrecoverable error. Likely this + * comes from file access failures. + */ + private static boolean touchFile( File file, long timemillis ) + throws Exception + { + long modifiedTime; + + if ( timemillis < 0 ) + { + modifiedTime = System.currentTimeMillis(); + } + else + { + modifiedTime = timemillis; + } + + file.setLastModified( modifiedTime ); + return true; + } +} diff --git a/maven-mboot/src/sea/sea-header b/maven-mboot/src/sea/sea-header new file mode 100644 index 0000000000..461d53b50b --- /dev/null +++ b/maven-mboot/src/sea/sea-header @@ -0,0 +1,39 @@ +#!/bin/sh +echo "" +echo Maven MBoot +echo "" + +echo +echo "Where would you like to install mboot? [ ~/mboot ] " +echo + +read $DIR + +[ -z $DIR ] && DIR=~/mboot + +echo "Installing mboot in $DIR ..." + +export DIR + +[ -d $DIR ] && rm -rf $DIR + +mkdir $DIR + +SKIP=`awk '/^__ARCHIVE_FOLLOWS__/ { print NR + 1; exit 0; }' $0` + +# Take the TGZ portion of this file and pipe it to tar. +tail +$SKIP $0 | tar xz -C $DIR + +# execute the installation script + +#PREV=`pwd` +#cd $WORK_DIR +#./install.sh + +# delete the temp files +#cd $PREV +#rm -rf $WORK_DIR + +exit 0 + +__ARCHIVE_FOLLOWS__