mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-10-30 20:07:36 +00:00
It's alive! press appears to be working completely (minus removed --flatten feature)
This commit is contained in:
1 parent
1f64fce47c
commit
0d9d60466d
3 files changed
+151
-114
No files matched your search
@@ -104,3 +104,4 @@ global.objj_importFile = importFile;
|
||||
global.objj_import = importFile;
|
||||
*/
|
||||
exports.FileExecutable = FileExecutable;
|
||||
exports.FileExecutablesForPaths = FileExecutablesForPaths;
|
||||
+118
-80
@@ -96,9 +96,9 @@ function main(args)
|
||||
}
|
||||
|
||||
function press(rootPath, outputPath, options) {
|
||||
CPLog.info("===========================================");
|
||||
CPLog.info("Application root: " + rootPath);
|
||||
CPLog.info("Output directory: " + outputPath);
|
||||
stream.print("\0yellow("+Array(81).join("=")+"\0)");
|
||||
stream.print("Application root: \0green(" + rootPath + "\0)");
|
||||
stream.print("Output directory: \0green(" + outputPath + "\0)");
|
||||
|
||||
var outputFiles = {};
|
||||
|
||||
@@ -108,7 +108,7 @@ function press(rootPath, outputPath, options) {
|
||||
});
|
||||
|
||||
// phase 4: copy everything and write out the new files
|
||||
CPLog.error("PHASE 4: copy to output ("+rootPath+" to "+outputPath+")");
|
||||
stream.print("\0red(PHASE 4:\0) copy to output \0green(" + rootPath + "\0) => \0green(" + outputPath + "\0)");
|
||||
|
||||
FILE.copyTree(rootPath, outputPath);
|
||||
|
||||
@@ -124,7 +124,8 @@ function press(rootPath, outputPath, options) {
|
||||
if (typeof outputFiles[path] !== "string")
|
||||
outputFiles[path] = outputFiles[path].join("");
|
||||
|
||||
CPLog.info((file.exists() ? "Overwriting: " : "Writing: ") + file);
|
||||
stream.print((file.exists() ? "\0red(Overwriting:\0) " : "\0green(Writing:\0) ") + file);
|
||||
|
||||
FILE.write(file, outputFiles[path], { charset : "UTF-8" });
|
||||
}
|
||||
|
||||
@@ -144,10 +145,10 @@ function pressEnvironment(rootPath, outputFiles, environment, options) {
|
||||
var mainPath = String(rootPath.join(options.main));
|
||||
var frameworks = options.frameworks.map(function(framework) { return rootPath.join(framework); });
|
||||
|
||||
CPLog.info("===========================================");
|
||||
CPLog.info("Main file: " + mainPath)
|
||||
CPLog.info("Frameworks: " + frameworks);
|
||||
CPLog.info("Environment: " + environment);
|
||||
stream.print("\0yellow("+Array(81).join("=")+"\0)");
|
||||
stream.print("Main file: \0green(" + mainPath + "\0)");
|
||||
stream.print("Frameworks: \0green(" + frameworks + "\0)");
|
||||
stream.print("Environment: \0green(" + environment + "\0)");
|
||||
|
||||
var analyzer = new ObjectiveJRuntimeAnalyzer(rootPath);
|
||||
|
||||
@@ -163,7 +164,7 @@ function pressEnvironment(rootPath, outputFiles, environment, options) {
|
||||
var cibs = FILE.glob(rootPath.join("**", "*.cib")).filter(function(path) { return !(/Frameworks/).test(path); });
|
||||
|
||||
// phase 1: get global defines
|
||||
CPLog.error("PHASE 1: Loading application...");
|
||||
stream.print("\0red(PHASE 1:\0) Loading application...");
|
||||
|
||||
analyzer.initializeGlobalRecorder();
|
||||
|
||||
@@ -175,93 +176,83 @@ function pressEnvironment(rootPath, outputFiles, environment, options) {
|
||||
var dependencies = analyzer.mapGlobalsToFiles();
|
||||
|
||||
// log identifer => files defining
|
||||
CPLog.trace("Global defines:");
|
||||
stream.print("Global defines:");
|
||||
Object.keys(dependencies).sort().forEach(function(identifier) {
|
||||
CPLog.trace(" " + identifier + " => " + rootPath.relative(dependencies[identifier]));
|
||||
stream.print("\0blue(" + identifier + "\0) => \0cyan(" + dependencies[identifier].map(rootPath.relative.bind(rootPath)) + "\0)");
|
||||
});
|
||||
|
||||
// phase 2: walk the dependency tree (both imports and references) to determine exactly which files need to be included
|
||||
CPLog.error("PHASE 2: Walk dependency tree...");
|
||||
stream.print("\0red(PHASE 2:\0) Traverse dependency graph...");
|
||||
|
||||
var requiredFiles = null;
|
||||
var requiredFiles = {};
|
||||
requiredFiles[mainPath] = true;
|
||||
|
||||
if (options.nostrip)
|
||||
{
|
||||
// all files are required. no need for analysis
|
||||
throw "nostrip not implemented"
|
||||
// requiredFiles = scope.objj_files;
|
||||
var context = {
|
||||
ignoreFrameworkImports : true, // ignores "XXX/XXX.j" imports
|
||||
importCallback: function(importing, imported) { requiredFiles[imported] = true; },
|
||||
referenceCallback: function(referencing, referenced) { requiredFiles[referenced] = true; },
|
||||
progressCallback: function(relPath) { stream.print("Processing \0cyan("+relPath+"\0)"); },
|
||||
ignoreFrameworkImportsCallback : function(relPath) { stream.print("\0yellow(Ignoring imports in "+relPath+"\0)"); }
|
||||
}
|
||||
else
|
||||
{
|
||||
CPLog.warn("Analyzing dependencies...");
|
||||
|
||||
requiredFiles = {};
|
||||
mainExecutable = analyzer.executableForImport(mainPath);
|
||||
|
||||
var context = {
|
||||
ignoreFrameworkImports : true, // ignores "XXX/XXX.j" imports
|
||||
importCallback: function(importing, imported) { requiredFiles[imported] = true; },
|
||||
referenceCallback: function(referencing, referenced) { requiredFiles[referenced] = true; },
|
||||
importedFiles: {},
|
||||
referencedFiles: {}
|
||||
// check the code
|
||||
analyzer.traverseDependencies(mainExecutable, context);
|
||||
|
||||
// check the cibs
|
||||
var globalsToFiles = analyzer.mapGlobalsToFiles();
|
||||
cibs.forEach(function(cibPath) {
|
||||
var cibClasses = findCibClassDependencies(cibPath);
|
||||
stream.print("Cib: \0green("+rootPath.relative(cibPath)+"\0) => \0cyan("+cibClasses+"\0)");
|
||||
|
||||
var referencedFiles = {};
|
||||
markFilesReferencedByTokens(cibClasses, globalsToFiles, referencedFiles);
|
||||
analyzer.checkReferenced(context, null, referencedFiles);
|
||||
});
|
||||
|
||||
var included = 0, total = 0;
|
||||
var includedBytes = 0, totalBytes = 0;
|
||||
var allFiles = analyzer.fileExecutables();
|
||||
for (var path in allFiles) {
|
||||
// mark all ".keytheme"s as required
|
||||
if (/\.keyedtheme$/.test(path))
|
||||
requiredFiles[path] = true;
|
||||
|
||||
if (requiredFiles[path]) {
|
||||
stream.print("Included: \0green(" + rootPath.relative(path) + "\0)");
|
||||
included++;
|
||||
includedBytes += allFiles[path].code().length
|
||||
}
|
||||
|
||||
requiredFiles[mainPath] = true;
|
||||
|
||||
mainExecutable = analyzer.executableForImport(mainPath);
|
||||
|
||||
// check the code
|
||||
analyzer.traverseDependencies(context, mainExecutable);
|
||||
|
||||
// check the cibs
|
||||
var globalsToFiles = analyzer.mapGlobalsToFiles();
|
||||
cibs.forEach(function(cibPath) {
|
||||
var cibClasses = findCibClassDependencies(cibPath);
|
||||
CPLog.debug("CIB: " + rootPath.relative(cibPath) + " => " + cibClasses);
|
||||
|
||||
var referencedFiles = {};
|
||||
markFilesReferencedByTokens(cibClasses, globalsToFiles, referencedFiles);
|
||||
analyzer.checkReferenced(context, null, referencedFiles);
|
||||
});
|
||||
|
||||
var count = 0,
|
||||
total = 0;
|
||||
// var allFiles = analyzer.gatherDependencies(mainExecutable);
|
||||
// for (var path in allFiles) {
|
||||
for (var path in requiredFiles) {
|
||||
// mark all ".keytheme"s as required
|
||||
if (/\.keyedtheme$/.test(path))
|
||||
requiredFiles[path] = true;
|
||||
|
||||
if (requiredFiles[path])
|
||||
{
|
||||
CPLog.debug("Included: " + rootPath.relative(path));
|
||||
count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
CPLog.info("Excluded: " + rootPath.relative(path));
|
||||
}
|
||||
total++;
|
||||
else {
|
||||
stream.print("Excluded: \0red(" + rootPath.relative(path) + "\0)");
|
||||
}
|
||||
CPLog.warn("Total required files: " + count + " out of " + total);
|
||||
total++;
|
||||
totalBytes += allFiles[path].code().length
|
||||
}
|
||||
stream.print(sprintf(
|
||||
"Saved \0green(%f%%\0) (\0blue(%s\0)); Total required files: \0magenta(%d\0) (\0blue(%s\0)) of \0magenta(%d\0) (\0blue(%s\0));",
|
||||
Math.round(((includedBytes - totalBytes) / totalBytes) * -100),
|
||||
bytesToString(totalBytes - includedBytes),
|
||||
included, bytesToString(includedBytes),
|
||||
total, bytesToString(totalBytes)
|
||||
));
|
||||
|
||||
// phase 3b: rebuild .sj files with correct imports, copy .j files
|
||||
CPLog.error("PHASE 3b: Rebuild .sj");
|
||||
stream.print("\0red(PHASE 3b:\0) Rebuild .sj files");
|
||||
|
||||
for (var path in requiredFiles)
|
||||
{
|
||||
var executable = analyzer.executableForImport(path),
|
||||
bundle = _OBJJ.CFBundle.bundleContainingPath(executable.path()),
|
||||
fileContents = executable.code(),
|
||||
relativePath = FILE.relative(FILE.join(bundle.path(), ""), executable.path());
|
||||
|
||||
print("=======================================");
|
||||
print(" executable="+executable.path())
|
||||
print(" bundle="+bundle.path())
|
||||
print(" relativePath="+relativePath);
|
||||
print(" infoDictionary="+bundle.infoDictionary());
|
||||
print(" fileContents.length="+fileContents.length);
|
||||
|
||||
// stream.print(Array(81).join("="));
|
||||
// stream.print(" executable="+executable.path())
|
||||
// stream.print(" bundle="+bundle.path())
|
||||
// stream.print(" relativePath="+relativePath);
|
||||
// stream.print(" infoDictionary="+bundle.infoDictionary());
|
||||
// stream.print(" fileContents.length="+fileContents.length);
|
||||
|
||||
if (executable.path() !== path)
|
||||
CPLog.warn("Sanity check failed (file path): " + executable.path() + " vs. " + path);
|
||||
@@ -269,8 +260,8 @@ function pressEnvironment(rootPath, outputFiles, environment, options) {
|
||||
if (bundle && bundle.infoDictionary())
|
||||
{
|
||||
var executablePath = bundle.executablePath();
|
||||
print(" executablePath="+executablePath);
|
||||
|
||||
// print(" executablePath="+executablePath);
|
||||
|
||||
if (executablePath)
|
||||
{
|
||||
if (!outputFiles[executablePath])
|
||||
@@ -279,12 +270,50 @@ function pressEnvironment(rootPath, outputFiles, environment, options) {
|
||||
outputFiles[executablePath].push("@STATIC;1.0;");
|
||||
}
|
||||
|
||||
if (context.ignoredImports[path])
|
||||
{
|
||||
stream.print("Stripping extra imports from \0blue(" + path + "\0)");
|
||||
|
||||
var code = executable.code();
|
||||
var dependencies = executable.fileDependencies();
|
||||
for (var i = 0; i < dependencies.length; i++) {
|
||||
var dependency = dependencies[i];
|
||||
var dependencyExecutable = new _OBJJ.FileExecutableSearch(
|
||||
dependency.isLocal() ? FILE.join(FILE.dirname(path), dependency.path()) : dependency.path(),
|
||||
dependency.isLocal()
|
||||
).result();
|
||||
var dependencyPath = dependencyExecutable.path();
|
||||
if (!requiredFiles[dependencyPath]) {
|
||||
stream.print(" -> \0red(" + dependencyPath + "\0)");
|
||||
// build up a regex to match objj_executeFile file with optional whitespace
|
||||
var regex = new RegExp([
|
||||
RegExp.escape("objj_executeFile"),
|
||||
RegExp.escape("("),
|
||||
"[\"']"+RegExp.escape(dependency.path())+"[\"']",
|
||||
RegExp.escape(","),
|
||||
RegExp.escape(dependency.isLocal() ? "true" : "false"),
|
||||
RegExp.escape(")")
|
||||
].join("\\s*"), "g");
|
||||
// replace instances of "objj_executeFile()" with "(undefined)"
|
||||
code = code.replace(regex, "/* $& */ (undefined)");
|
||||
// remove from dependencies list (decrement i since we're removing an item)
|
||||
dependencies.splice(i--, 1);
|
||||
}
|
||||
}
|
||||
if (code !== executable.code())
|
||||
executable.setCode(code);
|
||||
}
|
||||
|
||||
var fileContents = executable.toMarkedString();
|
||||
|
||||
outputFiles[executablePath].push("p;" + relativePath.length + ";" + relativePath);
|
||||
outputFiles[executablePath].push("t;" + fileContents.length + ";" + fileContents);
|
||||
|
||||
stream.print("Adding \0green(" + rootPath.relative(path) + "\0) to \0cyan(" + rootPath.relative(executablePath) + "\0)");
|
||||
}
|
||||
else
|
||||
{
|
||||
CPLog.info("Passing .j through: " + rootPath.relative(path));
|
||||
stream.print("Passing .j through: \0green(" + rootPath.relative(path) + "\0)");
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -318,3 +347,12 @@ function pathRelativeTo(target, relativeTo)
|
||||
// TODO: fix FILE.relative to always treat the source as a directory
|
||||
return FILE.relative(FILE.join(relativeTo, ""), target);
|
||||
}
|
||||
|
||||
function bytesToString(bytes) {
|
||||
var n = 0;
|
||||
while (bytes > 1024) {
|
||||
bytes /= 1024;
|
||||
n++;
|
||||
}
|
||||
return Math.round(bytes*100)/100 + " " + ["", "K", "M"][n] + "B";
|
||||
}
|
||||
@@ -129,7 +129,7 @@ ObjectiveJRuntimeAnalyzer.prototype.mergeLibraryImports = function()
|
||||
for (var relativePath in this.files) {
|
||||
if (FILE.isRelative(relativePath)) {
|
||||
var absolutePath = this.executableForImport(relativePath, false).path();
|
||||
CPLog.debug("Merging " + relativePath + " => " + absolutePath);
|
||||
// CPLog.debug("Merging " + relativePath + " => " + absolutePath);
|
||||
|
||||
this.files[absolutePath] = this.files[absolutePath] || {};
|
||||
this.files[absolutePath].globals = this.files[absolutePath].globals || {};
|
||||
@@ -162,10 +162,14 @@ ObjectiveJRuntimeAnalyzer.prototype.executableForImport = function(path, isLocal
|
||||
|
||||
param file is an objj_file object containing path, fragments, content, bundle, etc
|
||||
*/
|
||||
ObjectiveJRuntimeAnalyzer.prototype.traverseDependencies = function(context, executable)
|
||||
ObjectiveJRuntimeAnalyzer.prototype.traverseDependencies = function(executable, context)
|
||||
{
|
||||
if (!context.processedFiles)
|
||||
context.processedFiles = {};
|
||||
context = context || {};
|
||||
|
||||
context.processedFiles = context.processedFiles || {};
|
||||
context.importedFiles = context.importedFiles || {};
|
||||
context.referencedFiles = context.referencedFiles || {};
|
||||
context.ignoredImports = context.ignoredImports || {};
|
||||
|
||||
var path = executable.path();
|
||||
|
||||
@@ -177,7 +181,7 @@ ObjectiveJRuntimeAnalyzer.prototype.traverseDependencies = function(context, exe
|
||||
var ignoreImports = false;
|
||||
if (context.ignoreAllImports)
|
||||
{
|
||||
CPLog.warn("Ignoring all import fragments. ("+this.rootPath.relative(path)+")");
|
||||
// CPLog.warn("Ignoring all import fragments. ("+this.rootPath.relative(path)+")");
|
||||
ignoreImports = true;
|
||||
}
|
||||
else if (context.ignoreFrameworkImports)
|
||||
@@ -185,7 +189,7 @@ ObjectiveJRuntimeAnalyzer.prototype.traverseDependencies = function(context, exe
|
||||
var matches = path.match(new RegExp("([^\\/]+)\\/([^\\/]+)\\.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. ("+this.rootPath.relative(path)+")");
|
||||
// CPLog.warn("Framework import file! Ignoring all import fragments. ("+this.rootPath.relative(path)+")");
|
||||
ignoreImports = true;
|
||||
}
|
||||
}
|
||||
@@ -193,7 +197,8 @@ ObjectiveJRuntimeAnalyzer.prototype.traverseDependencies = function(context, exe
|
||||
var referencedFiles = {},
|
||||
importedFiles = {};
|
||||
|
||||
CPLog.debug("Processing " + this.rootPath.relative(path));
|
||||
if (context.progressCallback)
|
||||
context.progressCallback(this.rootPath.relative(path), path);
|
||||
|
||||
// code
|
||||
var code = executable.code();
|
||||
@@ -203,13 +208,15 @@ ObjectiveJRuntimeAnalyzer.prototype.traverseDependencies = function(context, exe
|
||||
delete referencedFiles[path];
|
||||
|
||||
// imports
|
||||
executable.fileDependencies().forEach(function(fileDependency) {
|
||||
if (ignoreImports) {
|
||||
// FIXME
|
||||
// fragment.conditionallyIgnore = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ignoreImports)
|
||||
{
|
||||
if (context.ignoreImportsCallback)
|
||||
context.ignoreImportsCallback(this.rootPath.relative(path), path);
|
||||
context.ignoredImports[path] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
executable.fileDependencies().forEach(function(fileDependency) {
|
||||
var dependencyExecutable = null;
|
||||
if (fileDependency.isLocal())
|
||||
dependencyExecutable = this.executableForImport(FILE.normal(FILE.join(FILE.dirname(path), fileDependency.path())), true);
|
||||
@@ -227,20 +234,20 @@ ObjectiveJRuntimeAnalyzer.prototype.traverseDependencies = function(context, exe
|
||||
}
|
||||
else
|
||||
CPLog.error("Couldn't find file for import " + fileDependency.path() + " ("+fileDependency.isLocal()+")");
|
||||
}
|
||||
}, this);
|
||||
}, this);
|
||||
}
|
||||
|
||||
// check each imported file
|
||||
this.checkImported(context, path, importedFiles);
|
||||
|
||||
if (context.importedFiles)
|
||||
context.importedFiles[path] = importedFiles;
|
||||
context.importedFiles[path] = importedFiles;
|
||||
|
||||
// check each referenced file
|
||||
this.checkReferenced(context, path, referencedFiles);
|
||||
|
||||
if (context.referencedFiles)
|
||||
context.referencedFiles[path] = referencedFiles;
|
||||
context.referencedFiles[path] = referencedFiles;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
ObjectiveJRuntimeAnalyzer.prototype.checkImported = function(context, path, importedFiles) {
|
||||
@@ -253,7 +260,7 @@ ObjectiveJRuntimeAnalyzer.prototype.checkImported = function(context, path, impo
|
||||
|
||||
var executable = this.executableForImport(importedFile, true);
|
||||
if (executable)
|
||||
this.traverseDependencies(context, executable);
|
||||
this.traverseDependencies(executable, context);
|
||||
else
|
||||
CPLog.error("Missing imported file: " + importedFile);
|
||||
}
|
||||
@@ -270,25 +277,16 @@ ObjectiveJRuntimeAnalyzer.prototype.checkReferenced = function(context, path, re
|
||||
|
||||
var executable = this.executableForImport(referencedFile, true);
|
||||
if (executable)
|
||||
this.traverseDependencies(context, executable);
|
||||
this.traverseDependencies(executable, context);
|
||||
else
|
||||
CPLog.error("Missing referenced file: " + referencedFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ObjectiveJRuntimeAnalyzer.prototype.gatherDependencies = function(executable) {
|
||||
ObjectiveJRuntimeAnalyzer.prototype.fileExecutables = function() {
|
||||
var _OBJJ = this.require("objective-j");
|
||||
var files = {};
|
||||
var stack = [executable];
|
||||
while (stack.length) {
|
||||
var executable = stack.pop();
|
||||
if (files[executable.path()])
|
||||
continue;
|
||||
files[executable.path()] = executable;
|
||||
stack.push.apply(stack, executable.fileDependencies().map(function(dep) { return new _OBJJ.FileExecutableSearch(dep.path(), dep.isLocal()).result(); }));
|
||||
}
|
||||
return files;
|
||||
return _OBJJ.FileExecutablesForPaths;
|
||||
}
|
||||
|
||||
// returns a unique list of tokens for a piece of code.
|
||||
@@ -359,7 +357,7 @@ function setupObjectiveJ(context)
|
||||
|
||||
// get the Objective-J module from this scope, return the window object.
|
||||
var OBJJ = context.global.require("objective-j");
|
||||
|
||||
|
||||
// TODO: move this to browserjs and/or remove browser dependency in Objective-J/AppKit
|
||||
addMockBrowserEnvironment(OBJJ.window);
|
||||
|
||||
|
||||
Reference in new issue
Block a user