/*******************************************************************************
* Copyright 2014 See AUTHORS file.
*
* 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 com.badlogicgames.packr;
import com.eclipsesource.json.*;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.TrueFileFilter;
import org.zeroturnaround.zip.ZipUtil;
import java.io.*;
import java.util.HashSet;
import java.util.Set;
/**
* Functions to reduce package size for both classpath JARs, and the bundled JRE.
*/
class PackrReduce {
static void minimizeJre(PackrOutput output, PackrConfig config) throws IOException {
if (config.minimizeJre == null) {
return;
}
System.out.println("Minimizing JRE ...");
JsonObject minimizeJson = readMinimizeProfile(config);
if (minimizeJson != null) {
if (config.verbose) {
System.out.println(" # Removing files and directories in profile '" + config.minimizeJre + "' ...");
}
JsonArray reduceArray = minimizeJson.get("reduce").asArray();
for (JsonValue reduce : reduceArray) {
String path = reduce.asObject().get("archive").asString();
File file = new File(output.resourcesFolder, path);
if (!file.exists()) {
if (config.verbose) {
System.out.println(" # No file or directory '" + file.getPath() + "' found, skipping");
}
continue;
}
boolean needsUnpack = !file.isDirectory();
File fileNoExt = needsUnpack
? new File(output.resourcesFolder, path.contains(".") ? path.substring(0, path.lastIndexOf('.')) : path)
: file;
if (needsUnpack) {
if (config.verbose) {
System.out.println(" # Unpacking '" + file.getPath() + "' ...");
}
ZipUtil.unpack(file, fileNoExt);
}
JsonArray removeArray = reduce.asObject().get("paths").asArray();
for (JsonValue remove : removeArray) {
File removeFile = new File(fileNoExt, remove.asString());
if (removeFile.exists()) {
if (removeFile.isDirectory()) {
FileUtils.deleteDirectory(removeFile);
} else {
PackrFileUtils.delete(removeFile);
}
} else {
if (config.verbose) {
System.out.println(" # No file or directory '" + removeFile.getPath() + "' found");
}
}
}
if (needsUnpack) {
if (config.verbose) {
System.out.println(" # Repacking '" + file.getPath() + "' ...");
}
long beforeLen = file.length();
PackrFileUtils.delete(file);
ZipUtil.pack(fileNoExt, file);
FileUtils.deleteDirectory(fileNoExt);
long afterLen = file.length();
if (config.verbose) {
System.out.println(" # " + beforeLen / 1024 + " kb -> " + afterLen / 1024 + " kb");
}
}
}
JsonArray removeArray = minimizeJson.get("remove").asArray();
for (JsonValue remove : removeArray) {
String platform = remove.asObject().get("platform").asString();
if (!matchPlatformString(platform, config)) {
continue;
}
JsonArray removeFilesArray = remove.asObject().get("paths").asArray();
for (JsonValue removeFile : removeFilesArray) {
removeFileWildcard(output.resourcesFolder, removeFile.asString(), config);
}
}
}
}
private static boolean matchPlatformString(String platform, PackrConfig config) {
return "*".equals(platform) || config.platform.desc.contains(platform);
}
private static void removeFileWildcard(File output, String removeFileWildcard, PackrConfig config) throws IOException {
if (removeFileWildcard.contains("*")) {
String removePath = removeFileWildcard.substring(0, removeFileWildcard.indexOf('*') - 1);
String removeSuffix = removeFileWildcard.substring(removeFileWildcard.indexOf('*') + 1);
File[] files = new File(output, removePath).listFiles();
if (files != null) {
for (File file : files) {
if (removeSuffix.isEmpty() || file.getName().endsWith(removeSuffix)) {
removeFile(file, config);
}
}
} else {
if (config.verbose) {
System.out.println(" # No matching files found in '" + removeFileWildcard + "'");
}
}
} else {
removeFile(new File(output, removeFileWildcard), config);
}
}
private static void removeFile(File file, PackrConfig config) throws IOException {
if (!file.exists()) {
if (config.verbose) {
System.out.println(" # No file or directory '" + file.getPath() + "' found");
}
return;
}
if (config.verbose) {
System.out.println(" # Removing '" + file.getPath() + "'");
}
if (file.isDirectory()) {
FileUtils.deleteDirectory(file);
} else {
PackrFileUtils.delete(file);
}
}
private static JsonObject readMinimizeProfile(PackrConfig config) throws IOException {
JsonObject json = null;
if (new File(config.minimizeJre).exists()) {
json = JsonObject.readFrom(FileUtils.readFileToString(new File(config.minimizeJre)));
} else {
InputStream in = Packr.class.getResourceAsStream("/minimize/" + config.minimizeJre);
if (in != null) {
json = JsonObject.readFrom(new InputStreamReader(in));
}
}
if (json == null && config.verbose) {
System.out.println(" # No minimize profile '" + config.minimizeJre + "' found");
}
return json;
}
static void removePlatformLibs(PackrOutput output, PackrConfig config) throws IOException {
System.out.println("Removing foreign platform libs ...");
// let's remove any shared libs not used on the platform, e.g. libGDX/LWJGL natives
for (String classpath : config.classpath) {
File jar = new File(output.resourcesFolder, new File(classpath).getName());
File jarDir = new File(output.resourcesFolder, jar.getName() + ".tmp");
if (config.verbose) {
if (jar.isDirectory()) {
System.out.println(" # Classpath '" + classpath + "' is a directory");
} else {
System.out.println(" # Unpacking '" + classpath + "' ...");
}
}
if (!jar.isDirectory()) {
ZipUtil.unpack(jar, jarDir);
}
Set<String> extensions = new HashSet<String>();
switch (config.platform) {
case Windows32:
case Windows64:
extensions.add(".dylib");
extensions.add(".so");
break;
case Linux32:
case Linux64:
extensions.add(".dylib");
extensions.add(".dll");
break;
case MacOS:
extensions.add(".dll");
extensions.add(".so");
break;
}
for (Object obj : FileUtils.listFiles(jarDir, TrueFileFilter.INSTANCE , TrueFileFilter.INSTANCE)) {
File file = new File(obj.toString());
for (String extension: extensions) {
if (file.getName().endsWith(extension)) {
if (config.verbose) {
System.out.println(" # Removing '" + file.getPath() + "'");
}
PackrFileUtils.delete(file);
}
}
}
if (!jar.isDirectory()) {
if (config.verbose) {
System.out.println(" # Repacking '" + classpath + "' ...");
}
long beforeLen = jar.length();
PackrFileUtils.delete(jar);
ZipUtil.pack(jarDir, jar);
FileUtils.deleteDirectory(jarDir);
long afterLen = jar.length();
if (config.verbose) {
System.out.println(" # " + beforeLen / 1024 + " kb -> " + afterLen / 1024 + " kb");
}
}
}
}
}