mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-08-26 13:37:03 +00:00
456 lines
14 KiB
JavaScript
456 lines
14 KiB
JavaScript
|
|
importClass(java.io.FileOutputStream);
|
|
importClass(java.io.BufferedWriter);
|
|
importClass(java.io.OutputStreamWriter);
|
|
|
|
function Target(dictionary)
|
|
{
|
|
this._name = dictionary_getValue(dictionary, "Name");
|
|
|
|
var flagsString = dictionary_getValue(dictionary, "Flags");
|
|
|
|
this._flags = flagsString ? flagsString.split(/\s+/) : [];
|
|
|
|
this._type = dictionary_getValue(dictionary, "Type");
|
|
|
|
if (!this._type)
|
|
this._type = "280N.application";
|
|
|
|
this._exclusions = [];
|
|
|
|
var exclusions = dictionary_getValue(dictionary, "Excluded");
|
|
|
|
if (exclusions)
|
|
{
|
|
var index = 0,
|
|
count = exclusions.length;
|
|
|
|
for (; index < count; ++index)
|
|
this._exclusions.push(new File((exclusions[index])).getCanonicalFile());
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
Target.prototype.name = function()
|
|
{
|
|
return this._name;
|
|
}
|
|
|
|
Target.prototype.exclusions = function()
|
|
{
|
|
return this._exclusions;
|
|
}
|
|
|
|
Target.prototype.flags = function()
|
|
{
|
|
return this._flags;
|
|
}
|
|
|
|
Target.prototype.type = function()
|
|
{
|
|
return this._type;
|
|
}
|
|
|
|
function Configuration(dictionary)
|
|
{
|
|
this._name = dictionary_getValue(dictionary, "Name");
|
|
|
|
var flagsString = dictionary_getValue(dictionary, "Flags");
|
|
|
|
this._flags = flagsString ? flagsString.split(/\s+/) : [];
|
|
|
|
return this;
|
|
}
|
|
|
|
Configuration.prototype.name = function()
|
|
{
|
|
return this._name;
|
|
}
|
|
|
|
Configuration.prototype.flags = function()
|
|
{
|
|
return this._flags;
|
|
}
|
|
|
|
function Project(/*String*/ aFilePath, /*String*/ aBuildPath)
|
|
{
|
|
this._file = new File(aFilePath).getCanonicalFile();
|
|
this._root = this._file.getParentFile();
|
|
|
|
// Read the project file (its just a plist).
|
|
this._properties = readPlist(this._file);
|
|
|
|
this._name = dictionary_getValue(this._properties, "Name");
|
|
|
|
// Read existing Info.plist if it exists.
|
|
var infoPlist = new File(this._root.getAbsolutePath() + "/Info.plist");
|
|
|
|
if (infoPlist.exists())
|
|
this._infoDictionary = readPlist(new File(this._root.getAbsolutePath() + "/Info.plist"));
|
|
else
|
|
this._infoDictionary = new objj_dictionary();
|
|
|
|
this.buildPath = aBuildPath;
|
|
|
|
// Covert target dictionaries to target objects.
|
|
var targetDictionaries = dictionary_getValue(this._properties, "Targets");
|
|
|
|
this._targets = [];
|
|
|
|
for (var index = 0, count = targetDictionaries.length; index < count; ++index)
|
|
this._targets.push(new Target(targetDictionaries[index]));
|
|
|
|
this.setActiveTarget(this._targets[0]);
|
|
|
|
// Covert target dictionaries to target objects.
|
|
var configurationDictionaries = dictionary_getValue(this._properties, "Configurations");
|
|
|
|
this._configurations = [];
|
|
|
|
for (index = 0, count = configurationDictionaries.length; index < count; ++index)
|
|
this._configurations.push(new Configuration(configurationDictionaries[index]));
|
|
|
|
this.setActiveConfiguration(this._configurations[0]);
|
|
|
|
// Grab the Resources Directory (if it exists)
|
|
this._resources = new File(this._root.getAbsolutePath() + "/Resources/").getCanonicalFile();
|
|
|
|
return this;
|
|
}
|
|
|
|
Project.prototype.name = function()
|
|
{
|
|
return this._name;
|
|
}
|
|
|
|
Project.prototype.targetWithName = function(/*String*/ aName)
|
|
{
|
|
var targets = this._targets,
|
|
index = 0,
|
|
count = targets.length;
|
|
|
|
for (; index < count; ++index)
|
|
{
|
|
var target = targets[index];
|
|
|
|
if (target.name() == aName)
|
|
return target;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
Project.prototype.configurationWithName = function(/*String*/ aName)
|
|
{
|
|
var configurations = this._configurations,
|
|
index = 0,
|
|
count = configurations.length;
|
|
|
|
for (; index < count; ++index)
|
|
{
|
|
var configuration = configurations[index];
|
|
|
|
if (configuration.name() == aName)
|
|
return configuration;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
Project.prototype.setActiveTarget = function(/*Target*/ aTarget)
|
|
{
|
|
this._activeTarget = aTarget;
|
|
|
|
this._buildProducts = null;
|
|
this._buildIntermediates = null;
|
|
this._buildObjects = null;
|
|
}
|
|
|
|
Project.prototype.activeTarget = function()
|
|
{
|
|
return this._activeTarget;
|
|
}
|
|
|
|
Project.prototype.setActiveConfiguration = function(/*Configuration*/ aConfiguration)
|
|
{
|
|
this._activeConfiguration = aConfiguration;
|
|
|
|
this._buildProducts = null;
|
|
this._buildIntermediates = null;
|
|
this._buildObjects = null;
|
|
}
|
|
|
|
Project.prototype.activeConfiguration = function()
|
|
{
|
|
return this._activeConfiguration;
|
|
}
|
|
|
|
Project.prototype.buildProducts = function()
|
|
{
|
|
if (!this._buildProducts)
|
|
{
|
|
this._buildProducts = new File(this.buildPath + '/' + this._activeConfiguration.name() + '/' + this._activeTarget.name()).getCanonicalFile();
|
|
this._buildProducts.mkdirs();
|
|
}
|
|
|
|
return this._buildProducts;
|
|
}
|
|
|
|
Project.prototype.buildIntermediates = function()
|
|
{
|
|
if (!this._buildIntermediates)
|
|
{
|
|
this._buildIntermediates = new File(this.buildPath + '/' + this._activeTarget.name() + ".build/" + this._activeConfiguration.name()).getCanonicalFile();
|
|
this._buildIntermediates.mkdirs();
|
|
}
|
|
|
|
return this._buildIntermediates;
|
|
}
|
|
|
|
Project.prototype.buildObjects = function()
|
|
{
|
|
if (!this._buildObjects)
|
|
{
|
|
this._buildObjects = new File(this.buildIntermediates().getAbsolutePath() + '/' + this._activeTarget.name()).getCanonicalFile();
|
|
this._buildObjects.mkdirs();
|
|
}
|
|
|
|
return this._buildObjects;
|
|
}
|
|
|
|
Project.prototype.activeFlags = function()
|
|
{
|
|
return this.activeTarget().flags().concat(this.activeConfiguration().flags());
|
|
}
|
|
|
|
Project.prototype.buildTheme = function()
|
|
{
|
|
var project = this/*,
|
|
frameworks = NULL;
|
|
|
|
// FIXME: OBJJ_INCLUDE_PATHS ENV VAR?
|
|
if (true)
|
|
{
|
|
OBJJ_INCLUDE_PATHS = [System.getenv("STEAM_BUILD") + "/Release-Rhino/", System.getenv("STEAM_BUILD") + "/Release/"];
|
|
frameworks = [System.getenv("STEAM_BUILD") + "/Release/Foundation", System.getenv("STEAM_BUILD") + "/Release-Rhino/AppKit"];
|
|
}
|
|
else
|
|
{
|
|
OBJJ_INCLUDE_PATHS = [OBJJ_HOME + "/lib/Frameworks-Rhino"];
|
|
frameworks = [OBJJ_HOME + "/lib/Frameworks-Rhino/Foundation", OBJJ_HOME + "/lib/Frameworks-Rhino/AppKit"];
|
|
}
|
|
|
|
// Load ALL of Foundation and AppKit, be nice to people.
|
|
loadFrameworks(frameworks, function()*/
|
|
|
|
// FIXME: This should be stubbed out. It is also in objj.js
|
|
var OBJJ_LIB = OBJJ_HOME + "/lib/";
|
|
|
|
var defaultFrameworks = OBJJ_LIB + "/Frameworks-Rhino";
|
|
|
|
OBJJ_INCLUDE_PATHS = [defaultFrameworks];
|
|
|
|
var OBJJ_INCLUDE_PATHS_STRING = getenv("OBJJ_INCLUDE_PATHS");
|
|
|
|
if (OBJJ_INCLUDE_PATHS_STRING)
|
|
{
|
|
OBJJ_INCLUDE_PATHS = OBJJ_INCLUDE_PATHS_STRING.split(":");
|
|
OBJJ_INCLUDE_PATHS.push(defaultFrameworks);
|
|
}
|
|
|
|
var activeConfigurationName = this.activeConfiguration().name();
|
|
|
|
OBJJ_INCLUDE_PATHS = [System.getenv("STEAM_BUILD") + "/" + activeConfigurationName + "-Rhino/", System.getenv("STEAM_BUILD") + "/" + activeConfigurationName + "/"];
|
|
|
|
// Load ALL of Foundation and AppKit, be nice to people.
|
|
loadFrameworks([System.getenv("STEAM_BUILD") + "/" + activeConfigurationName + "/Foundation", System.getenv("STEAM_BUILD") + "/" + activeConfigurationName + "-Rhino/AppKit"], function()
|
|
{
|
|
// Get .j files
|
|
var jFiles = getFiles(project._root, "j", project.activeTarget().exclusions().concat([new File("Frameworks/")]));
|
|
|
|
// Load 'em
|
|
importFiles(jFiles, function()
|
|
{
|
|
// Grab the application delegate.
|
|
var applicationDelegateClassName = dictionary_getValue(project._infoDictionary, "CPApplicationDelegateClass"),
|
|
applicationDelegate = objj_msgSend(objj_msgSend(objj_getClass(applicationDelegateClassName), "alloc"), "init"),
|
|
|
|
// Grab all the themes we plan to make.
|
|
themeNames = objj_msgSend(applicationDelegate, "themeNames"),
|
|
|
|
themeIndex = 0,
|
|
themeCount = themeNames.length,
|
|
|
|
replacedFiles = [],
|
|
|
|
staticContent = "";
|
|
|
|
for (; themeIndex < themeCount; ++themeIndex)
|
|
{
|
|
themeName = themeNames[themeIndex];
|
|
|
|
java.lang.System.out.println("Building " + themeName + " Theme.");
|
|
|
|
var views = objj_msgSend(applicationDelegate, "viewsFor" + themeName + "Theme"),
|
|
viewIndex = 0,
|
|
viewCount = views.length,
|
|
theme = objj_msgSend(objj_msgSend(CPTheme, "alloc"), "initWithName:", themeName);
|
|
|
|
if (!viewCount)
|
|
java.lang.System.out.println("There are no themed views in the " + themeName + " Theme.");
|
|
|
|
// Loop through each "themed" view, and take it's themed properties.
|
|
for (; viewIndex < viewCount; ++viewIndex)
|
|
{
|
|
var view = views[viewIndex];
|
|
|
|
java.lang.System.out.println(" Recording theme for " + objj_msgSend(views[viewIndex], "className") + ".");
|
|
|
|
objj_msgSend(theme, "takeThemeFromObject:", view);
|
|
}
|
|
|
|
// Archive our theme.
|
|
var filePath = themeName + ".keyedtheme";
|
|
fileContents = objj_msgSend(objj_msgSend(CPKeyedArchiver, "archivedDataWithRootObject:", theme), "string");
|
|
|
|
replacedFiles.push(filePath);
|
|
|
|
staticContent += MARKER_PATH + ';' + filePath.length + ';' + filePath + MARKER_TEXT + ';' + fileContents.length + ';' + fileContents;
|
|
}
|
|
|
|
staticContent = "@STATIC;1.0;" + staticContent;
|
|
|
|
var staticContentName = getFileNameWithoutExtension(project.activeTarget().name());
|
|
|
|
dictionary_setValue(project._infoDictionary, "CPBundleReplacedFiles", replacedFiles);
|
|
dictionary_setValue(project._infoDictionary, "CPBundleExecutable", staticContentName);
|
|
|
|
var writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(project.buildProducts().getCanonicalPath() + "/Info.plist"), "UTF-8"));
|
|
|
|
writer.write(CPPropertyListCreate280NorthData(project._infoDictionary).string);
|
|
|
|
writer.close();
|
|
|
|
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(project.buildProducts().getCanonicalPath() + "/" + staticContentName), "UTF-8"));
|
|
|
|
writer.write(staticContent);
|
|
|
|
writer.close();
|
|
});
|
|
});
|
|
|
|
serviceTimeouts();
|
|
|
|
this.copyResources();
|
|
}
|
|
|
|
Project.prototype.build = function()
|
|
{
|
|
java.lang.System.out.println("Building Target \"" + this.activeTarget().name() +
|
|
"\" of Project \"" + this.name() +
|
|
"\" with Configuration \"" + this.activeConfiguration().name() + "\".");
|
|
|
|
if (this.activeTarget().type() === "280N.theme")
|
|
return this.buildTheme();
|
|
|
|
var jFiles = getFiles(this._root, "j", this._activeTarget.exclusions()),
|
|
replacedFiles = [];
|
|
hasModifiedJFiles = false;
|
|
shouldObjjPreprocess = true,
|
|
shouldGzip = this._gzip,
|
|
objjcComponents = ["sh", OBJJ_HOME + "/bin/objjc"];
|
|
|
|
objjcComponents = objjcComponents.concat(this.activeFlags());
|
|
|
|
if (!shouldObjjPreprocess)
|
|
objjcComponents.push("-E");
|
|
|
|
var buildObjects = this.buildObjects(),
|
|
buildProducts = this.buildProducts();
|
|
|
|
for (index = 0, count = jFiles.length; index < count; ++index)
|
|
{
|
|
var file = jFiles[index],
|
|
builtFile = new File(buildObjects.getAbsolutePath() + '/' + getFileNameWithoutExtension(file) + '.o');
|
|
|
|
replacedFiles.push(file.getName() + "");
|
|
|
|
if (builtFile.exists() && file.lastModified() < builtFile.lastModified())
|
|
continue;
|
|
else
|
|
hasModifiedJFiles = true;
|
|
|
|
objjcComponents.push(file.getAbsolutePath());
|
|
|
|
objjcComponents.push("-o");
|
|
objjcComponents.push(buildObjects.getAbsolutePath() + '/' + getFileNameWithoutExtension(file) + '.o');
|
|
}
|
|
|
|
exec(objjcComponents, true);
|
|
|
|
var oFiles = getFiles(buildObjects, 'o'),
|
|
sjFile = new File(buildProducts.getCanonicalPath() + '/' + this._activeTarget.name() + ".sj");
|
|
|
|
if (hasModifiedJFiles)
|
|
{
|
|
// concatenate sjheader.txt and individual .o
|
|
exec(["sh", "-c", "cat '" + OBJJ_STEAM + "/sjheader.txt' '" + oFiles.join("' '") + "' > '" + sjFile.getCanonicalPath() + "'"], true);
|
|
}
|
|
|
|
if (shouldGzip)
|
|
{
|
|
// gzip and copy .htaccess file
|
|
exec(["sh", "-c", "gzip -c '" + sjFile.getCanonicalPath() + "' > '" + sjFile.getCanonicalPath() + ".gz'"], true);
|
|
exec(["cp", OBJJ_HOME + "/lib/htaccess", sjFile.getParentFile().getCanonicalPath() + "/.htaccess"], true);
|
|
}
|
|
else
|
|
{
|
|
// remove gzip and .htaccess file if present
|
|
exec(["rm", "-f", sjFile.getParentFile().getCanonicalPath() + "/.htaccess", sjFile.getCanonicalPath() + ".gz"], true);
|
|
}
|
|
|
|
dictionary_setValue(this._infoDictionary, "CPBundleExecutable", this._activeTarget.name() + ".sj");
|
|
dictionary_setValue(this._infoDictionary, "CPBundleReplacedFiles", replacedFiles);
|
|
|
|
this.writeInfoPlist();
|
|
|
|
this.copyResources();
|
|
|
|
// FIXME: This should be, if this is an app...
|
|
if (dictionary_getValue(this._infoDictionary, "CPBundlePackageType") == "280N")
|
|
this.copyIndexFile();
|
|
|
|
}
|
|
|
|
Project.prototype.clean = function()
|
|
{
|
|
java.lang.System.out.println("Cleaning Target \"" + this.activeTarget().name() +
|
|
"\" of Project \"" + this.name() +
|
|
"\" with Configuration \"" + this.activeConfiguration().name() + "\".");
|
|
|
|
exec(["rm", "-rf", this.buildIntermediates().getAbsolutePath()], true);
|
|
exec(["rm", "-rf", this.buildProducts().getAbsolutePath()], true);
|
|
}
|
|
|
|
Project.prototype.copyIndexFile = function()
|
|
{
|
|
var indexFile = new File(this._root.getAbsolutePath() + "/index.html").getCanonicalFile();
|
|
|
|
rsync(indexFile, this.buildProducts());
|
|
}
|
|
|
|
Project.prototype.writeInfoPlist = function()
|
|
{
|
|
var writer = new BufferedWriter(new FileWriter(this.buildProducts().getAbsolutePath() + '/' + "Info.plist"));
|
|
|
|
writer.write(CPPropertyListCreateXMLData(this._infoDictionary).string);
|
|
|
|
writer.close();
|
|
}
|
|
|
|
Project.prototype.copyResources = function()
|
|
{
|
|
rsync(this._resources, this.buildProducts());
|
|
}
|