Package files utility
/* 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.
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
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;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
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;
}
/*
* 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.
*/
class Repackager {
public Repackager(String repackageSpecs) {
_fromPackages = new ArrayList();
_toPackages = new ArrayList();
List repackages = splitPath(repackageSpecs, ';');
// 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 < repackages.size(); i++) {
String spec1 = (String) repackages.get(i - 1);
String spec2 = (String) repackages.get(i);
if (spec1.indexOf(':') < spec2.indexOf(':')) {
repackages.set(i - 1, spec2);
repackages.set(i, spec1);
swapped = true;
}
}
if (!swapped)
break;
}
for (int i = 0; i < repackages.size(); i++) {
String spec = (String) repackages.get(i);
int j = spec.indexOf(':');
if (j < 0 || spec.indexOf(':', j + 1) >= 0)
throw new RuntimeException("Illegal repackage specification: " + spec);
String from = spec.substring(0, j);
String to = spec.substring(j + 1);
_fromPackages.add(Repackager.splitPath(from, '.'));
_toPackages.add(Repackager.splitPath(to, '.'));
}
_fromMatchers = new Matcher[_fromPackages.size() * 2];
_toPackageNames = new String[_fromPackages.size() * 2];
addPatterns('.', 0);
addPatterns('/', _fromPackages.size());
}
void addPatterns(char sep, int off) {
for (int i = 0; i < _fromPackages.size(); i++) {
List from = (List) _fromPackages.get(i);
List to = (List) _toPackages.get(i);
String pattern = "";
for (int j = 0; j < from.size(); j++) {
if (j > 0)
pattern += "\\" + sep;
pattern += from.get(j);
}
String toPackage = "";
for (int j = 0; j < to.size(); j++) {
if (j > 0)
toPackage += sep;
toPackage += to.get(j);
}
_fromMatchers[off + i] = Pattern.compile(pattern).matcher("");
_toPackageNames[off + i] = toPackage;
}
}
public StringBuffer repackage(StringBuffer sb) {
StringBuffer result = null;
for (int i = 0; i < _fromMatchers.length; i++) {
Matcher m = (Matcher) _fromMatchers[i];
m.reset(sb);
for (boolean found = m.find(); found; found = m.find()) {
if (result == null)
result = new StringBuffer();
m.appendReplacement(result, _toPackageNames[i]);
}
if (result != null) {
m.appendTail(result);
sb = result;
result = null;
}
}
return sb;
}
public List getFromPackages() {
return _fromPackages;
}
public List getToPackages() {
return _toPackages;
}
public static ArrayList splitPath(String path, char separator) {
ArrayList components = new ArrayList();
for (;;) {
int i = path.indexOf(separator);
if (i < 0)
break;
components.add(path.substring(0, i));
path = path.substring(i + 1);
}
if (path.length() > 0)
components.add(path);
return components;
}
public static String dirForPath(String path) {
return new File(path).getParent();
}
private List _fromPackages;
private List _toPackages;
private Matcher[] _fromMatchers;
private String[] _toPackageNames;
}
Related examples in the same category