blob: 8c1c1c5c556015dadc25c2756fc0b7fdd1ff1591 [file] [log] [blame]
/* Copyright 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.
*/
package org.apache.xmlbeans.impl.repackage;
import java.io.*;
import java.util.*;
import java.util.regex.*;
public class Repackage
{
public static void main ( String[] args ) throws Exception
{
new Repackage(args).repackage();
}
private Repackage(String[] args)
{
String sourceDir = null;
String targetDir = null;
String repackageSpec = null;
boolean failure = false;
for (int i = 0; i < args.length; i++)
{
if (args[i].equals("-repackage") && i + 1 < args.length)
repackageSpec = args[++i];
else if (args[i].equals("-f") && i + 1 < args.length)
sourceDir = args[++i];
else if (args[i].equals("-t") && i + 1 < args.length)
targetDir = args[++i];
else
failure = true;
}
if (failure || repackageSpec == null || (sourceDir == null ^ targetDir == null))
throw new RuntimeException("Usage: repackage -repackage [spec] [ -f [sourcedir] -t [targetdir] ]");
_repackager = new Repackager(repackageSpec);
if (sourceDir==null || targetDir==null)
return;
_sourceBase = new File(sourceDir);
_targetBase = new File(targetDir);
}
public void repackage () throws Exception
{
if (_sourceBase==null || _targetBase==null)
{ // read from system.in, write on system.out
System.out.println( _repackager.repackage(readInputStream(System.in)).toString() );
return;
}
_fromPackages = _repackager.getFromPackages();
_toPackages = _repackager.getToPackages();
_packagePattern =
Pattern.compile( "^\\s*package\\s+((?:\\w|\\.)*)\\s*;", Pattern.MULTILINE );
_moveAlongFiles = new ArrayList();
_movedDirs = new HashMap();
// System.out.println( "Deleting repackage dir ..." );
// recursiveDelete( _targetBase );
_targetBase.mkdirs();
ArrayList files = new ArrayList();
fillFiles( files, _sourceBase );
System.out.println( "Repackaging " + files.size() + " files ..." );
int prefixLength = _sourceBase.getCanonicalPath().length();
for ( int i = 0 ; i < files.size() ; i++ )
{
File from = (File) files.get( i );
String name = from.getCanonicalPath().substring( prefixLength + 1 );
repackageFile( name );
}
finishMovingFiles();
if (_skippedFiles > 0)
System.out.println("Skipped " + _skippedFiles + " unmodified files.");
}
private boolean fileIsUnchanged(String name)
{
File sourceFile = new File( _sourceBase, name );
File targetFile = new File( _targetBase, name );
return (sourceFile.lastModified() < targetFile.lastModified());
}
public void repackageFile ( String name )
throws IOException
{
if (name.endsWith( ".java" ))
repackageJavaFile( name );
else if (name.endsWith( ".xsdconfig" ) ||
name.endsWith( ".xml" ) ||
name.endsWith( ".g" ) )
repackageNonJavaFile( name );
else if (name.startsWith( "bin" + File.separatorChar ))
repackageNonJavaFile( name );
else
moveAlongWithJavaFiles( name );
}
public void moveAlongWithJavaFiles( String name )
{
_moveAlongFiles.add(name);
}
public void finishMovingFiles ( )
throws IOException
{
for ( Iterator i = _moveAlongFiles.iterator(); i.hasNext(); )
{
String name = (String) i.next();
String toName = name;
String srcDir = Repackager.dirForPath( name );
String toDir = (String) _movedDirs.get( srcDir );
if (toDir != null)
toName = new File( toDir, new File( name ).getName() ).toString();
if (name.endsWith( ".html" ))
repackageNonJavaFile(name, toName);
else
justMoveNonJavaFile(name, toName);
}
}
public void repackageNonJavaFile(String name)
throws IOException
{
File sourceFile = new File( _sourceBase, name );
File targetFile = new File( _targetBase, name );
if (sourceFile.lastModified() < targetFile.lastModified())
_skippedFiles += 1;
else
writeFile( targetFile, _repackager.repackage( readFile( sourceFile ) ) );
}
public void repackageNonJavaFile ( String sourceName, String targetName )
throws IOException
{
File sourceFile = new File( _sourceBase, sourceName );
File targetFile = new File( _targetBase, targetName );
if (sourceFile.lastModified() < targetFile.lastModified())
_skippedFiles += 1;
else
writeFile( targetFile, _repackager.repackage( readFile( sourceFile ) ) );
}
public void justMoveNonJavaFile ( String sourceName, String targetName )
throws IOException
{
File sourceFile = new File( _sourceBase, sourceName );
File targetFile = new File( _targetBase, targetName );
if (sourceFile.lastModified() < targetFile.lastModified())
_skippedFiles += 1;
else
copyFile( sourceFile, targetFile );
}
public void repackageJavaFile ( String name )
throws IOException
{
File sourceFile = new File(_sourceBase, name);
StringBuffer sb = readFile(sourceFile);
Matcher packageMatcher = _packagePattern.matcher( sb );
if (packageMatcher.find())
{
String pkg = packageMatcher.group( 1 );
int pkgStart = packageMatcher.start( 1 );
int pkgEnd = packageMatcher.end( 1 );
if (packageMatcher.find())
throw new RuntimeException( "Two package specifications found: " + name );
List filePath = Repackager.splitPath( name, File.separatorChar );
String srcDir = Repackager.dirForPath( name );
// Sort the repackage spec so that longer from's are first to match
// longest package first
for ( ; ; )
{
boolean swapped = false;
for ( int i = 1 ; i < filePath.size() ; i++ )
{
String spec1 = (String) filePath.get( i - 1 );
String spec2 = (String) filePath.get( i );
if (spec1.indexOf( ':' ) < spec2.indexOf( ':' ))
{
filePath.set( i - 1, spec2 );
filePath.set( i, spec1 );
swapped = true;
}
}
if (!swapped)
break;
}
List pkgPath = Repackager.splitPath( pkg, '.' );
int f = filePath.size() - 2;
if (f<0 || (filePath.size()-1)< pkgPath.size())
throw new RuntimeException("Package spec differs from file path: " + name);
for ( int i = pkgPath.size() - 1 ; i >= 0 ; i-- )
{
if (!pkgPath.get( i ).equals( filePath.get( f ) ))
throw new RuntimeException( "Package spec differs from file path: " + name );
f--;
}
List changeTo = null;
List changeFrom = null;
from:
for ( int i = 0 ; i < _fromPackages.size() ; i ++ )
{
List from = (List) _fromPackages.get( i );
if (from.size() <= pkgPath.size())
{
for ( int j = 0 ; j < from.size() ; j++ )
if (!from.get( j ).equals( pkgPath.get( j )))
continue from;
changeFrom = from;
changeTo = (List) _toPackages.get( i );
break;
}
}
if (changeTo != null)
{
String newPkg = "";
String newName = "";
for ( int i = 0 ; i < changeTo.size() ; i++ )
{
if (i > 0)
{
newPkg += ".";
newName += File.separatorChar;
}
newPkg += changeTo.get( i );
newName += changeTo.get( i );
}
for ( int i = filePath.size() - pkgPath.size() - 2 ; i >= 0 ; i-- )
newName = (String) filePath.get( i ) + File.separatorChar + newName;
for ( int i = changeFrom.size() ; i < pkgPath.size() ; i++ )
{
newName += File.separatorChar + (String) pkgPath.get( i );
newPkg += '.' + (String) pkgPath.get( i );
}
newName += File.separatorChar + (String) filePath.get( filePath.size() - 1 );
sb.replace( pkgStart, pkgEnd, newPkg );
name = newName;
String newDir = Repackager.dirForPath( name );
if (!srcDir.equals(newDir))
{
_movedDirs.put(srcDir, newDir);
}
}
}
File targetFile = new File(_targetBase, name); // new name
if (sourceFile.lastModified() < targetFile.lastModified())
{
_skippedFiles += 1;
return;
}
writeFile( new File( _targetBase, name ), _repackager.repackage( sb ) );
}
void writeFile ( File f, StringBuffer chars )
throws IOException
{
f.getParentFile().mkdirs();
OutputStream out = new FileOutputStream( f );
Writer w = new OutputStreamWriter( out );
Reader r = new StringReader( chars.toString() );
copy( r, w );
r.close();
w.close();
out.close();
}
StringBuffer readFile ( File f )
throws IOException
{
InputStream in = new FileInputStream( f );
Reader r = new InputStreamReader( in );
StringWriter w = new StringWriter();
copy( r, w );
w.close();
r.close();
in.close();
return w.getBuffer();
}
StringBuffer readInputStream ( InputStream is )
throws IOException
{
Reader r = new InputStreamReader( is );
StringWriter w = new StringWriter();
copy( r, w );
w.close();
r.close();
return w.getBuffer();
}
public static void copyFile ( File from, File to ) throws IOException
{
to.getParentFile().mkdirs();
FileInputStream in = new FileInputStream( from );
FileOutputStream out = new FileOutputStream( to );
copy( in, out );
out.close();
in.close();
}
public static void copy ( InputStream in, OutputStream out ) throws IOException
{
byte[] buffer = new byte [ 1024 * 16 ];
for ( ; ; )
{
int n = in.read( buffer, 0, buffer.length );
if (n < 0)
break;
out.write( buffer, 0, n );
}
}
public static void copy ( Reader r, Writer w ) throws IOException
{
char[] buffer = new char [ 1024 * 16 ];
for ( ; ; )
{
int n = r.read( buffer, 0, buffer.length );
if (n < 0)
break;
w.write( buffer, 0, n );
}
}
public void fillFiles ( ArrayList files, File file ) throws IOException
{
if (!file.isDirectory())
{
files.add( file );
return;
}
// Exclude the build directory
if (file.getName().equals( "build" ))
return;
// Exclude CVS directories
if (file.getName().equals( "CVS" ))
return;
String[] entries = file.list();
for ( int i = 0 ; i < entries.length ; i++ )
fillFiles( files, new File( file, entries[ i ] ) );
}
public void recursiveDelete ( File file ) throws IOException
{
if (!file.exists())
return;
if (file.isDirectory())
{
String[] entries = file.list();
for ( int i = 0 ; i < entries.length ; i++ )
recursiveDelete( new File( file, entries[ i ] ) );
}
file.delete();
}
private File _sourceBase;
private File _targetBase;
private List _fromPackages;
private List _toPackages;
private Pattern _packagePattern;
private Repackager _repackager;
private Map _movedDirs;
private List _moveAlongFiles;
private int _skippedFiles;
}