Created
October 14, 2008 23:50
-
-
Save tlrobinson/16826 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var objjPath = OBJJ_LIB+'/Frameworks-Rhino/Objective-J/Objective-J.js', | |
bridgePath = OBJJ_LIB+'/bridge.js', | |
envPath = "/Users/tlrobinson/280North/git/cappuccino/Tools/press/env.js"; | |
/* | |
param context includes | |
scope: a global variable containing objj_files hash | |
processedFiles: hash containing file paths which have already been analyzed | |
dependencies: hash mapping from paths to an array of global variables defined by that file | |
[importCallback]: callback function that is called for each imported file (takes importing file path, and imported file path parameters) | |
[referencedCallback]: callback function that is called for each referenced file (takes referencing file path, referenced file path parameters, and list of tokens) | |
[importedFiles]: hash that will contain a mapping of file names to a hash of imported files | |
[referencedFiles]: hash that will contain a mapping of file names to a hash of referenced files (which contains a hash of tokens referenced) | |
param file is an objj_file object containing path, fragments, content, bundle, etc | |
*/ | |
function traverseDependencies(context, file) | |
{ | |
if (context.processedFiles[file.path]) | |
return; | |
context.processedFiles[file.path] = true; | |
var ignoreImports = false; | |
if (context.ignoreAllImports) | |
{ | |
CPLog.warn("Ignoring all import fragments. ("+file.path+")"); | |
ignoreImports = true; | |
} | |
else if (context.ignoreFrameworkImports) | |
{ | |
var matches = file.path.match(/([^\/]+)\/([^\/]+)\.j$/); // Matches "ZZZ/ZZZ.j" (e.x. AppKit/AppKit.j and Foundation/Foundation.j) | |
if (matches && matches[1] === matches[2]) | |
{ | |
CPLog.warn("Framework import file! Ignoring all import fragments. ("+file.path+")"); | |
ignoreImports = true; | |
} | |
} | |
// if fragments are missing, preprocess the contents | |
if (!file.fragments) | |
{ | |
if (file.included) | |
CPLog.warn(file.path + " is included but missing fragments"); | |
else | |
CPLog.warn("Preprocessing " + file.path); | |
file.fragments = objj_preprocess(file.contents, file.bundle, file); | |
} | |
// sprite: look for pngs in the Resources directory | |
if (!context.bundleImages) | |
context.bundleImages = {}; | |
if (!context.bundleImages[file.bundle.path]) | |
{ | |
var resourcesFile = new java.io.File(dirname(file.bundle.path) + "/Resources"); | |
if (resourcesFile.exists()) | |
{ | |
context.bundleImages[file.bundle.path] = {}; | |
var pngFiles = find(resourcesFile, (/\.png$/)); | |
for (var i = 0; i < pngFiles.length; i++) | |
{ | |
var path = pathRelativeTo(pngFiles[i].getCanonicalPath(), resourcesFile.getCanonicalPath()); | |
context.bundleImages[file.bundle.path][path] = 1; | |
} | |
} | |
} | |
var images = context.bundleImages[file.bundle.path]; | |
var referencedFiles = {}, | |
importedFiles = {}; | |
CPLog.trace("Processing " + file.path + " fragments ("+file.fragments.length+")"); | |
for (var i = 0; i < file.fragments.length; i++) | |
{ | |
var fragment = file.fragments[i]; | |
if (fragment.type & FRAGMENT_CODE) | |
{ | |
var lexer = new objj_lexer(fragment.info, NULL); | |
var token; | |
while (token = lexer.skip_whitespace()) | |
{ | |
if (context.dependencies[token]) | |
{ | |
var files = context.dependencies[token] | |
for (var j = 0; j < files.length; j++) | |
{ | |
// don't record references to self | |
if (files[j] != file.path) | |
{ | |
if (!referencedFiles[files[j]]) | |
referencedFiles[files[j]] = {}; | |
referencedFiles[files[j]][token] = true; | |
} | |
} | |
} | |
var matches = token.match(new RegExp("^['\"](.*)['\"]$")); | |
if (matches && images && images[matches[1]]) | |
images[matches[1]] = (images[matches[1]] | 2); | |
} | |
} | |
else if (fragment.type & FRAGMENT_FILE) | |
{ | |
if (ignoreImports) | |
{ | |
fragment.conditionallyIgnore = true; | |
} | |
else | |
{ | |
var importedFile = findImportInObjjFiles(context.scope, fragment); | |
if (importedFile) | |
{ | |
// should never import self, but just in case? | |
if (importedFile != file.path) | |
importedFiles[importedFile] = true; | |
else | |
CPLog.error("Ignoring self import (why are you importing yourself!?): " + file.path); | |
} | |
else | |
CPLog.error("Couldn't find file for import " + fragment.info + "("+fragment.type+")"); | |
} | |
} | |
} | |
// check each imported file | |
for (var importedFile in importedFiles) | |
{ | |
if (importedFile != file.path) | |
{ | |
if (context.importCallback) | |
context.importCallback(file.path, importedFile); | |
if (context.scope.objj_files[importedFile]) | |
traverseDependencies(context, context.scope.objj_files[importedFile]); | |
else | |
CPLog.error("Missing imported file: " + importedFile); | |
} | |
} | |
if (context.importedFiles) | |
context.importedFiles[file.path] = importedFiles; | |
// check each referenced file | |
for (var referencedFile in referencedFiles) | |
{ | |
if (referencedFile != file.path) | |
{ | |
if (context.referenceCallback) | |
context.referenceCallback(file.path, referencedFile, referencedFiles[referencedFile]); | |
if (context.scope.objj_files[referencedFile]) | |
traverseDependencies(context, context.scope.objj_files[referencedFile]); | |
else | |
CPLog.error("Missing referenced file: " + referencedFile); | |
} | |
} | |
if (context.referencedFiles) | |
context.referencedFiles[file.path] = referencedFiles; | |
} | |
function findImportInObjjFiles(scope, fragment) | |
{ | |
var importPath = null; | |
if (fragment.type & FRAGMENT_LOCAL) | |
{ | |
var searchPath = fragment.info; | |
CPLog.trace("Looking for " + searchPath); | |
//for (var i in scope.objj_files) CPLog.debug(" " + i); | |
if (scope.objj_files[searchPath]) | |
{ | |
importPath = searchPath; | |
} | |
} | |
else | |
{ | |
var count = scope.OBJJ_INCLUDE_PATHS.length; | |
while (count--) | |
{ | |
var searchPath = scope.OBJJ_INCLUDE_PATHS[count].replace(/\/$/, "") + "/" + fragment.info; | |
if (scope.objj_files[searchPath]) | |
{ | |
importPath = searchPath; | |
break; | |
} | |
} | |
} | |
return importPath; | |
} | |
// given a fresh scope and the path to a root source file, determine which files define each global variable | |
function findGlobalDefines(context, scope, rootPath, evaledFragments) | |
{ | |
addMockBrowserEnvironment(scope); | |
var ignore = cloneProperties(scope, true); | |
ignore['bundle'] = true; | |
var dependencies = {}; | |
//scope.fragment_evaluate_file_original = scope.fragment_evaluate_file; | |
//scope.fragment_evaluate_file = function(aFragment) | |
//{ | |
// //CPLog.trace("Loading "+aFragment.info); | |
// | |
// var result = scope.fragment_evaluate_file_original(aFragment); | |
// | |
// return result; | |
//} | |
var needsPatch = true, | |
patchString = "__RHINO_FIRST_SCOPE.String.prototype.isa=CPString;__RHINO_FIRST_SCOPE.Number.prototype.isa=CPNumber;__RHINO_FIRST_SCOPE.Boolean.prototype.isa=CPNumber;print('PATCHED!');"; | |
// OVERRIDE fragment_evaluate_file | |
var fragment_evaluate_file_original = scope.fragment_evaluate_file; | |
scope.fragment_evaluate_file = function(aFragment) { | |
// patch Foundation.j (HACK for Rhino bug #374918) | |
if (needsPatch && aFragment.file && (/Foundation\.j$/).test(aFragment.file.path)) | |
{ | |
CPLog.error("Patching Foundation.j"); | |
var patchFragment = new objj_fragment(); | |
patchFragment.info = patchString; | |
patchFragment.type = FRAGMENT_CODE; | |
patchFragment.file = aFragment.file; | |
patchFragment.bundle = aFragment.bundle; | |
patchFragment.context = aFragment.context; | |
for (var i = 0; i < aFragment.context.fragments.length; i++) | |
{ | |
if ((aFragment.context.fragments[i].type & FRAGMENT_FILE) && (/Foundation\//).test(aFragment.context.fragments[i].info)) | |
{ | |
CPLog.error("Inserting patch"); | |
aFragment.context.fragments.splice(i, 0, patchFragment); | |
break; | |
} | |
} | |
needsPatch = false; | |
} | |
return fragment_evaluate_file_original(aFragment); | |
} | |
// OVERRIDE fragment_evaluate_code | |
var fragment_evaluate_code_original = scope.fragment_evaluate_code; | |
scope.fragment_evaluate_code = function(aFragment) { | |
CPLog.debug("Evaling "+aFragment.file.path + " / " + aFragment.bundle.path); | |
var before = cloneProperties(scope); | |
if (evaledFragments) | |
{ | |
if (aFragment.info != patchString) | |
evaledFragments.push(aFragment); | |
} | |
var result = fragment_evaluate_code_original(aFragment); | |
var definedGlobals = {}; | |
diff(before, scope, ignore, definedGlobals, definedGlobals, null); | |
dependencies[aFragment.file.path] = definedGlobals; | |
return result; | |
} | |
runWithScope(context, scope, function(importName) { | |
objj_import(importName, true, NULL); | |
}, [rootPath]); | |
return dependencies; | |
} | |
function coalesceGlobalDefines(globals) | |
{ | |
var dependencies = {}; | |
for (var fileName in globals) | |
{ | |
var fileGlobals = globals[fileName]; | |
for (var globalName in fileGlobals) | |
{ | |
if (!dependencies[globalName]) | |
dependencies[globalName] = []; | |
dependencies[globalName].push(fileName); | |
} | |
} | |
return dependencies; | |
} | |
// create a new scope loaded with Objective-J | |
function makeObjjScope(context, debug) | |
{ | |
// init standard js scope objects | |
var scope = context.initStandardObjects(); | |
if (debug) | |
{ | |
scope.objj_alert = print; | |
scope.debug = true; | |
} | |
// give the scope "print" | |
scope.print = function(value) { Packages.java.lang.System.out.println(String(value)); }; | |
// HACK for Rhino bug #374918 (fix toll free bridging) | |
scope.__RHINO_FIRST_SCOPE = this; | |
CPLog.info("__RHINO_FIRST_SCOPE="+scope.__RHINO_FIRST_SCOPE); | |
// load and eval fake browser environment | |
//var envSource = readFile(envPath); | |
//if (envSource) | |
// context.evaluateString(scope, envSource, "env.js", 1, null); | |
//else | |
// CPLog.warn("Missing env.js"); | |
// load and eval the bridge | |
var bridgeSource = readFile(bridgePath); | |
if (bridgeSource) | |
context.evaluateString(scope, bridgeSource, "bridge.js", 1, null); | |
else | |
CPLog.warn("Missing bridge.js"); | |
// load and eval obj-j | |
var objjSource = readFile(objjPath); | |
if (objjSource) | |
context.evaluateString(scope, objjSource, "Objective-J.js", 1, null); | |
else | |
CPLog.warn("Missing Objective-J.js"); | |
return scope; | |
} | |
// run a function within the given scope (func can be a function object if the source of the function is returned by toString() as it is by default) | |
function runWithScope(context, scope, func, arguments) | |
{ | |
scope.__runWithScopeArgs = arguments || []; | |
var code = "("+func+").apply(this, this.__runWithScopeArgs); serviceTimeouts();"; | |
return context.evaluateString(scope, code, "<cmd>", 1, null); | |
} | |
// add a mock browser environment to the provided scope | |
function addMockBrowserEnvironment(scope) | |
{ | |
// TODO: complete this. or use env.js? | |
scope.Element = function() { | |
this.style = {} | |
} | |
scope.document = { | |
createElement : function() { | |
return new scope.Element(); | |
} | |
} | |
} | |
// does a shallow copy of an object. if onlyList is true, it sets each property to "true" instead of the actual value | |
function cloneProperties(object, onlyList) | |
{ | |
var results = {} | |
for (var memeber in object) | |
results[memeber] = onlyList ? true : object[memeber]; | |
return results; | |
} | |
function diff(objectA, objectB, ignore, added, changed, deleted) | |
{ | |
for (var i in objectB) | |
if (added && !ignore[i] && typeof objectA[i] == "undefined") | |
added[i] = true; | |
for (var i in objectB) | |
if (changed && !ignore[i] && typeof objectA[i] != "undefined" && typeof objectB[i] != "undefined" && objectA[i] !== objectB[i]) | |
changed[i] = true; | |
for (var i in objectA) | |
if (deleted && !ignore[i] && typeof objectB[i] == "undefined") | |
deleted[i] = true; | |
} | |
function allKeys(object) | |
{ | |
var result = []; | |
for (var i in object) | |
result.push(i) | |
return result.sort(); | |
} | |
function find(src, regex) | |
{ | |
var results = []; | |
var files = src.listFiles(); | |
for (var i = 0; i < files.length; i++) | |
{ | |
if (files[i].isFile() && regex.test(files[i].getAbsolutePath())) | |
results.push(files[i]); | |
else if (files[i].isDirectory()) | |
results = Array.prototype.concat.apply(results, find(files[i], regex)); | |
} | |
return results; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import <Foundation/Foundation.j> | |
import "objj-analysis-tools.j" | |
CPLogRegister(CPLogPrint); | |
var defaultMain = "main.j", | |
defaultFrameworks = "Frameworks"; | |
function main() | |
{ | |
var rootDirectory = null, | |
outputDirectory = null, | |
mainFilename = null, | |
frameworksDirectory = null, | |
optimizePNG = false; | |
var usageError = false; | |
while (args.length && !usageError) | |
{ | |
var arg = args.shift(); | |
switch(arg) | |
{ | |
case "--png": | |
optimizePNG = true; | |
break; | |
case "--main": | |
if (args.length) | |
mainFile = args.shift(); | |
else | |
usageError = true; | |
break; | |
case "--frameworks": | |
if (args.length) | |
frameworksDirectory = args.shift().replace(/\/$/, ""); | |
else | |
usageError = true; | |
break; | |
default: | |
if (rootDirectory == null) | |
rootDirectory = arg.replace(/\/$/, ""); | |
else if (outputDirectory == null) | |
outputDirectory = arg.replace(/\/$/, ""); | |
else | |
usageError = true; | |
} | |
} | |
if (rootDirectory == null || outputDirectory == null) | |
{ | |
print("Usage: press root_directory output_directory [--main override_main.j] [--frameworks override_frameworks] [--png]"); | |
return; | |
} | |
rootDirectory = absolutePath(rootDirectory); | |
// determine main and frameworks paths | |
var mainPath = rootDirectory + "/" + (mainFilename || defaultMain), | |
frameworksPath = rootDirectory + "/" + (frameworksDirectory || defaultFrameworks); | |
CPLog.info("root=" + rootDirectory); | |
CPLog.info("output=" + outputDirectory); | |
CPLog.info("main=" + mainPath) | |
CPLog.info("frameworks=" + frameworksPath); | |
// get Rhino context | |
var cx = Packages.org.mozilla.javascript.Context.getCurrentContext(), //Packages.org.mozilla.javascript.Context.enter(), | |
scope = makeObjjScope(cx); | |
// set OBJJ_INCLUDE_PATHS to include the frameworks path | |
scope.OBJJ_INCLUDE_PATHS = [frameworksPath]; | |
CPLog.info("OBJJ_INCLUDE_PATHS="+scope.OBJJ_INCLUDE_PATHS); | |
// flattening | |
var bundleArchives = [], | |
evaledFragments = []; | |
scope.objj_search.prototype.didReceiveBundleResponseOriginal = scope.objj_search.prototype.didReceiveBundleResponse; | |
scope.objj_search.prototype.didReceiveBundleResponse = function(aResponse) { | |
print("RESPONSE: " + aResponse); | |
var response = { | |
success : aResponse.success, | |
filePath : pathRelativeTo(aResponse.filePath, rootDirectory) | |
}; | |
if (aResponse.success) | |
{ | |
var xmlOutput = new Packages.java.io.ByteArrayOutputStream(); | |
outputTransformer(xmlOutput, aResponse.xml, "UTF-8"); | |
response.xml = String(xmlOutput.toString()); | |
print("SERIALIZED: " + response.xml.substring(0,100)); | |
} | |
bundleArchives.push(response); | |
this.didReceiveBundleResponseOriginal.apply(this, arguments); | |
} | |
// phase 1: get global defines | |
var globals = findGlobalDefines(cx, scope, mainPath, evaledFragments); | |
// coalesce the results | |
var dependencies = coalesceGlobalDefines(globals); | |
// phase 2: walk the dependency tree (both imports and references) to determine exactly which files need to be included | |
var requiredFiles = {}; | |
if (scope.objj_files[mainPath]) | |
{ | |
var context = { | |
scope : scope, | |
dependencies : dependencies, | |
processedFiles : {}, | |
ignoreFrameworkImports : true, | |
importCallback : function(importing, imported) { | |
requiredFiles[imported] = true; | |
}, | |
referenceCallback : function(referencing, referenced) { | |
requiredFiles[referenced] = true; | |
} | |
} | |
requiredFiles[mainPath] = true; | |
traverseDependencies(context, scope.objj_files[mainPath]); | |
var count = 0, | |
total = 0; | |
for (var path in scope.objj_files) | |
{ | |
if (requiredFiles[path]) | |
{ | |
CPLog.info("Included: " + path); | |
count++; | |
} | |
else | |
{ | |
CPLog.warn("Excluded: " + path); | |
} | |
total++; | |
} | |
CPLog.error("Total required files: " + count + " out of " + total); | |
for (var i in context.bundleImages) | |
{ | |
var images = context.bundleImages[i]; | |
CPLog.info("Bundle images for " + i); | |
for (var j in images) | |
CPLog.debug(j + " = " + images[j]); | |
} | |
} | |
else | |
{ | |
CPLog.error("Root file not loaded!"); | |
return; | |
} | |
var outputFiles = {}; | |
// HACK | |
requiredFiles["/Users/tlrobinson/scratch/MenuBarApp/AppController.j"] = true; | |
var flatten = true; | |
if (flatten) | |
{ | |
var application = []; | |
var fakeDidReceiveBundleResponse = function(aResponse) { | |
var bundle = new objj_bundle(); | |
bundle.path = aResponse.filePath; | |
if (aResponse.success) | |
bundle.info = CPPropertyListCreateFromXMLData({ string : aResponse.xml }); | |
else | |
bundle.info = new objj_dictionary(); | |
objj_bundles[aResponse.filePath] = bundle; | |
} | |
application.push("var cnt = 0; fakeDidReceiveBundleResponse = " + String(fakeDidReceiveBundleResponse)); | |
application.push("var bundleArchives = " + CPJSObjectCreateJSON(bundleArchives)+";"); | |
application.push("for (var i = 0; i < bundleArchives.length; i++) fakeDidReceiveBundleResponse(bundleArchives[i]);") | |
for (var i = 0; i < evaledFragments.length; i++) | |
{ | |
if (requiredFiles[evaledFragments[i].file.path]) | |
{ | |
CPLog.info("Required " + evaledFragments[i].file.path); | |
application.push("(function() {"); | |
application.push("var OBJJ_CURRENT_BUNDLE = objj_bundles['"+pathRelativeTo(evaledFragments[i].bundle.path, rootDirectory)+"'];"); | |
application.push("console.log('cnt=' + (cnt++) + ': ' + OBJJ_CURRENT_BUNDLE);"); | |
application.push(evaledFragments[i].info); | |
application.push("})();"); | |
} | |
else | |
{ | |
CPLog.warn("Ignored " + evaledFragments[i].file.path); | |
} | |
} | |
application.push("console.log('calling main');"); | |
application.push("main();"); | |
application.push("console.log('done calling main');"); | |
outputFiles[rootDirectory + "/Application.js"] = application.join("\n"); | |
//outputFiles[rootDirectory + "/index.html"] = readFile(rootDirectory + "/index.html").replace(/<script.*objj_import.*<\/script>/, '<script type="text/javascript" src="Application.js" charset="utf-8"></script><script type="text/javascript" charset="utf-8">main();</script>') | |
} | |
else | |
{ | |
// phase 3: rebuild .sj files with correct imports, copy .j files | |
var bundles = {}; | |
for (var path in requiredFiles) | |
{ | |
var file = scope.objj_files[path], | |
filename = basename(path), | |
directory = dirname(path); | |
if (file.path != path) | |
CPLog.warn("Sanity check (file path): " + file.path + " vs. " + path); | |
if (file.bundle) | |
{ | |
var bundleDirectory = dirname(file.bundle.path); | |
if (!bundles[file.bundle.path]) | |
bundles[file.bundle.path] = file.bundle; | |
if (bundleDirectory != directory) | |
CPLog.warn("Sanity check (directory path): " + directory + " vs. " + bundleDirectory); | |
// if it's in a .sj | |
var dict = file.bundle.info, | |
replacedFiles = [dict objectForKey:"CPBundleReplacedFiles"]; | |
if (replacedFiles && [replacedFiles containsObject:filename]) | |
{ | |
var staticPath = bundleDirectory + "/" + [dict objectForKey:"CPBundleExecutable"]; | |
if (!outputFiles[staticPath]) | |
{ | |
outputFiles[staticPath] = []; | |
outputFiles[staticPath].push("@STATIC;1.0;"); | |
} | |
outputFiles[staticPath].push("p;"); | |
outputFiles[staticPath].push(filename.length+";"); | |
outputFiles[staticPath].push(filename); | |
for (var i = 0; i < file.fragments.length; i++) | |
{ | |
if (file.fragments[i].type & FRAGMENT_CODE) | |
{ | |
outputFiles[staticPath].push("c;"); | |
outputFiles[staticPath].push(file.fragments[i].info.length+";"); | |
outputFiles[staticPath].push(file.fragments[i].info); | |
} | |
else if (file.fragments[i].type & FRAGMENT_FILE) | |
{ | |
var ignoreFragment = false; | |
if (file.fragments[i].conditionallyIgnore) | |
{ | |
var importPath = findImportInObjjFiles(scope, file.fragments[i]); | |
if (!importPath || !requiredFiles[importPath]) | |
{ | |
ignoreFragment = true; | |
} | |
} | |
if (!ignoreFragment) | |
{ | |
if (file.fragments[i].type & FRAGMENT_LOCAL) | |
{ | |
var relativePath = pathRelativeTo(file.fragments[i].info, directory) | |
outputFiles[staticPath].push("i;"); | |
outputFiles[staticPath].push(relativePath.length+";"); | |
outputFiles[staticPath].push(relativePath); | |
} | |
else | |
{ | |
outputFiles[staticPath].push("I;"); | |
outputFiles[staticPath].push(file.fragments[i].info.length+";"); | |
outputFiles[staticPath].push(file.fragments[i].info); | |
} | |
} | |
else | |
CPLog.warn("Ignoring import fragment " + file.fragments[i].info + " in " + path); | |
} | |
else | |
CPLog.error("Unknown fragment type"); | |
} | |
} | |
// always output individual .j files | |
else | |
{ | |
outputFiles[path] = file.contents; | |
} | |
} | |
else | |
CPLog.warn("No bundle for " + path) | |
} | |
// phase 3.5: bundle plists | |
for (var path in bundles) | |
{ | |
var bundle = bundles[path]; | |
CPLog.info("Bundle: " + path + " bundle=" + bundle); | |
var dict = file.bundle.info, | |
replacedFiles = [dict objectForKey:"CPBundleReplacedFiles"]; | |
if (replacedFiles) | |
{ | |
for (var i = 0; i < replacedFiles.length; i++) | |
{ | |
if (!requiredFiles[replacedFiles[i]]) | |
{ | |
CPLog.info("Removing: " + replacedFiles[i]); | |
replacedFiles.splice(i, 1); | |
} | |
} | |
} | |
outputFiles[path] = CPPropertyListCreateXMLData(bundle.info).string; | |
} | |
} | |
// phase 4: copy everything and write out the new files | |
var rootDirectoryFile = new Packages.java.io.File(rootDirectory), | |
outputDirectoryFile = new Packages.java.io.File(outputDirectory); | |
copyDirectory(rootDirectoryFile, outputDirectoryFile, optimizePNG); | |
for (var path in outputFiles) | |
{ | |
var file = new java.io.File(outputDirectoryFile, pathRelativeTo(path, rootDirectory)); | |
var parent = file.getParentFile(); | |
if (!parent.exists()) | |
{ | |
CPLog.warn(parent + " doesn't exist, creating directories."); | |
parent.mkdirs(); | |
} | |
CPLog.info("Writing out " + file); | |
var writer = new java.io.BufferedWriter(new java.io.FileWriter(file)); | |
if (typeof outputFiles[path] == "string") | |
writer.write(outputFiles[path]); | |
else | |
writer.write(outputFiles[path].join("")); | |
writer.close(); | |
} | |
} | |
// Helper Utilities | |
// TODO: moved elsewhere? | |
function copyDirectory(src, dst, optimizePNG) | |
{ | |
CPLog.trace("Copying directory " + src); | |
dst.mkdirs(); | |
var files = src.listFiles(); | |
for (var i = 0; i < files.length; i++) | |
{ | |
if (files[i].isFile()) | |
copyFile(files[i], new Packages.java.io.File(dst, files[i].getName()), optimizePNG); | |
else if (files[i].isDirectory()) | |
copyDirectory(files[i], new Packages.java.io.File(dst, files[i].getName()), optimizePNG); | |
} | |
} | |
function copyFile(src, dst, optimizePNG) | |
{ | |
if (optimizePNG && (/.png$/).test(src.getName())) | |
{ | |
CPLog.warn("Optimizing .png " + src); | |
exec(["pngcrush", "-rem", "alla", "-reduce", /*"-brute",*/ src.getAbsolutePath(), dst.getAbsolutePath()]); | |
} | |
else | |
{ | |
CPLog.trace("Copying file " + src); | |
var input = (new Packages.java.io.FileInputStream(src)).getChannel(), | |
output = (new Packages.java.io.FileOutputStream(dst)).getChannel(); | |
input.transferTo(0, input.size(), output); | |
input.close(); | |
output.close(); | |
} | |
} | |
function dirname(path) | |
{ | |
return path.substring(0, path.lastIndexOf("/")); | |
} | |
function basename(path) | |
{ | |
return path.substring(path.lastIndexOf("/") + 1); | |
} | |
function absolutePath(path) | |
{ | |
return String((new Packages.java.io.File(path)).getCanonicalPath()); | |
} | |
function pathRelativeTo(target, relativeTo) | |
{ | |
var components = [], | |
targetParts = target.split("/"), | |
relativeParts = relativeTo ? relativeTo.split("/") : []; | |
var i = 0; | |
while (i < targetParts.length) | |
{ | |
if (targetParts[i] != relativeParts[i]) | |
break; | |
i++; | |
} | |
for (var j = i; j < relativeParts.length; j++) | |
components.push(".."); | |
for (var j = i; j < targetParts.length; j++) | |
components.push(targetParts[j]); | |
var result = components.join("/"); | |
return result; | |
} | |
function exec() | |
{ | |
var printOutput = false; | |
var runtime = Packages.java.lang.Runtime.getRuntime() | |
var p = runtime.exec.apply(runtime, arguments); | |
var stdout = new Packages.java.io.BufferedReader(new Packages.java.io.InputStreamReader(p.getInputStream())), | |
stdoutString = "", | |
stderr = new Packages.java.io.BufferedReader(new Packages.java.io.InputStreamReader(p.getErrorStream())), | |
stderrString = ""; | |
var done = false; | |
while (!done) | |
{ | |
done = true; | |
if (s = stdout.readLine()) | |
{ | |
stdoutString += s; | |
if (printOutput) | |
CPLog.info("exec: " + s); | |
done = false; | |
} | |
if (s = stderr.readLine()) | |
{ | |
stderrString += s; | |
//if (printOutput) | |
CPLog.warn("exec: " + s); | |
done = false; | |
} | |
} | |
var code = p.waitFor(); | |
return { code : code, stdout : stdoutString, stderr : stderrString }; | |
} | |
function outputTransformer(os, document, encoding, standalone) | |
{ | |
var domSource = new Packages.javax.xml.transform.dom.DOMSource(document); | |
var streamResult = new Packages.javax.xml.transform.stream.StreamResult(os); | |
var tf = Packages.javax.xml.transform.TransformerFactory.newInstance(); | |
var serializer = tf.newTransformer(); | |
serializer.setOutputProperty(Packages.javax.xml.transform.OutputKeys.VERSION, "1.0"); | |
serializer.setOutputProperty(Packages.javax.xml.transform.OutputKeys.INDENT, "yes"); | |
if (encoding) | |
serializer.setOutputProperty(Packages.javax.xml.transform.OutputKeys.ENCODING, encoding); | |
if (standalone) | |
serializer.setOutputProperty(Packages.javax.xml.transform.OutputKeys.STANDALONE, (standalone ? "yes" : "no")); | |
serializer.transform(domSource, streamResult); | |
} | |
main(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment