Files
cappuccino/Tests/Manual/TextEditor/Jakefile
T
David Richardson 416718a8d3 Tests: Configure manual test applications with explicit themes and theme tasks
* Tests/Manual/*/Info.plist: Set CPDefaultTheme to Aristo3 across all manual test applications, including those previously overriding to Aristo2.

* Tests/Manual/*/Jakefile: Add an orchestration task to update CPDefaultTheme (e.g., npx jake theme "Aristo3 Dark"). For testing convenience.

* Tests/Manual/*/Jakefile (Narwhal format): Migrate module imports and execution calls to Node equivalents from the capp application template, and remove syntax artifacts.
2026-11-03 21:26:03 -06:00

248 lines
8.8 KiB
JavaScript

/*
* Jakefile
* TextEditor
*
* Copyright (c) 2026 David Richardson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
const path = require("path");
const fs = require("fs");
var ENV = process.env,
task = JAKE.task,
FileList = JAKE.FileList,
app = CAPPUCCINO.Jake.applicationtask.app,
configuration = ENV["CONFIG"] || ENV["CONFIGURATION"] || ENV["c"] || "Debug",
OS = require("os"),
projectName = "TextEditor";
var buildDir = path.resolve(ENV["BUILD_PATH"] || ENV["CAPP_BUILD"] || "Build");
app (projectName, function(task)
{
ENV["OBJJ_INCLUDE_PATHS"] = "Frameworks";
if (configuration === "Debug")
ENV["OBJJ_INCLUDE_PATHS"] = path.join(ENV["OBJJ_INCLUDE_PATHS"], configuration);
task.setBuildIntermediatesPath(path.join(buildDir, "TextEditor.build", configuration));
task.setBuildPath(path.join(buildDir, configuration));
task.setProductName("TextEditor");
task.setIdentifier("dev.cappuccino.TextEditor");
task.setVersion("1.0");
task.setAuthor("David Richardson");
task.setSummary("TextEditor");
task.setSources(new FileList("**/*.j").exclude(path.join("Build", "**")).exclude(path.join("Frameworks", "Source", "**")));
task.setResources(new FileList("Resources/**"));
task.setIndexFilePath("index.html");
task.setInfoPlistPath("Info.plist");
if (configuration === "Debug")
task.setCompilerFlags("-DDEBUG -g -S --inline-msg-send");
else
task.setCompilerFlags("-O2");
});
task ("default", [projectName], function()
{
printResults(configuration);
});
task ("build", ["default"], function()
{
updateApplicationSize();
});
task ("debug", function()
{
configuration = ENV["CONFIGURATION"] = "Debug";
JAKE.subjake(["."], "build", ENV);
});
task ("release", function()
{
configuration = ENV["CONFIGURATION"] = "Release";
JAKE.subjake(["."], "build", ENV);
});
task ("run", ["debug"], function()
{
OS.system(["open", path.join(buildDir, "Debug", projectName, "index.html")]);
});
task ("run-release", ["release"], function()
{
OS.system(["open", path.join(buildDir, "Release", projectName, "index.html")]);
});
task ("deploy", ["release"], function()
{
FILE.mkdirs(path.join(buildDir, "Deployment", projectName));
OS.system(["press", "-f", path.join(buildDir, "Release", projectName), path.join(buildDir, "Deployment", projectName)]);
printResults("Deployment")
});
function printResults(configuration)
{
console.log("----------------------------");
console.log(configuration+" app built at path: " + path.join(buildDir, configuration, projectName));
console.log("----------------------------");
}
function updateApplicationSize()
{
console.log("Calculating application file sizes...");
var contents = fs.readFileSync(path.join(buildDir, configuration, projectName, "Info.plist"), { encoding: "utf8" }),
format = CFPropertyList.sniffedFormatOfString(contents),
plist = CFPropertyList.propertyListFromString(contents),
totalBytes = {executable:0, data:0, mhtml:0};
// Get the size of all framework executables and sprite data
var frameworksDir = "Frameworks";
if (configuration === "Debug")
frameworksDir = path.join(frameworksDir, "Debug");
var frameworks = [];
if (fs.existsSync(frameworksDir)) {
frameworks = fs.readdirSync(frameworksDir);
}
//var frameworks = FILE.list(frameworksDir);
frameworks.forEach(function(framework)
{
if (framework !== "Source")
addBundleFileSizes(path.join(frameworksDir, framework), totalBytes);
});
// Read in the default theme name, and attempt to get its size
var themeName = plist.valueForKey("CPDefaultTheme") || "Aristo2",
themePath = nil;
if (themeName === "Aristo" || themeName === "Aristo2")
themePath = path.join(frameworksDir, "AppKit", "Resources", themeName + ".blend");
else
themePath = path.join("Frameworks", "Resources", themeName + ".blend");
if (fs.existsSync(themePath) && fs.lstatSync(themePath).isDirectory())
addBundleFileSizes(themePath, totalBytes);
// Add sizes for the app
addBundleFileSizes(path.join(buildDir, configuration, projectName), totalBytes);
console.log("Executables: " + totalBytes.executable + ", sprite data: " + totalBytes.data + ", total: " + (totalBytes.executable + totalBytes.data));
var dict = new CFMutableDictionary();
dict.setValueForKey("executable", totalBytes.executable);
dict.setValueForKey("data", totalBytes.data);
dict.setValueForKey("mhtml", totalBytes.mhtml);
plist.setValueForKey("CPApplicationSize", dict);
fs.writeFileSync(path.join(buildDir, configuration, projectName, "Info.plist"), CFPropertyList.stringFromPropertyList(plist, format), { encoding: "utf8" });
//FILE.write(path.join(buildDir, configuration, projectName, "Info.plist"), CFPropertyList.stringFromPropertyList(plist, format), { charset:"UTF-8" });
}
function addBundleFileSizes(bundlePath, totalBytes)
{
var bundleName = path.basename(bundlePath),
environment = bundleName === "Foundation" ? "Objj" : "Browser",
bundlePath = path.join(bundlePath, environment + ".environment");
if (fs.existsSync(bundlePath) && fs.lstatSync(bundlePath).isDirectory())
{
var filename = bundleName + ".sj",
filePath = path.join(bundlePath, filename);
if (fs.existsSync(filePath)) {
totalBytes.executable += fs.lstatSync(filePath).size;
}
filePath = path.join(bundlePath, "dataURLs.txt");
if (fs.existsSync(filePath))
totalBytes.data += fs.lstatSync(filePath).size;
filePath = path.join(bundlePath, "MHTMLData.txt");
if (fs.existsSync(filePath))
totalBytes.mhtml += fs.lstatSync(filePath).size;
filePath = path.join(bundlePath, "MHTMLPaths.txt");
if (fs.existsSync(filePath))
totalBytes.mhtml += fs.lstatSync(filePath).size;
}
}
/*
Sets the theme this application uses, for example:
npx jake theme Aristo2
npx jake theme "Aristo3 Dark"
The name is written to CPDefaultTheme in Info.plist as given, with its case
kept and &, < and > escaped. Empty the browser cache afterwards, because the
browser keeps the old Info.plist.
Jake runs each word on the command line as a task, in order, and looks a task
up only when it reaches it. So this task declares the theme name as an empty
task, which Jake then runs without effect. A name that is already a task is
refused, because Jake would run that task after this one. So is a name that
starts with ^ or jake:, which Jake reads as a task scope.
*/
JAKE.task ("theme", function()
{
var fs = require("fs"),
path = require("path"),
themeName = process.argv[process.argv.indexOf("theme") + 1],
plistPath = path.join(__dirname, "Info.plist"),
themeKey = /(<key>CPDefaultTheme<\/key>\s*<string>)[^<]*(<\/string>)/;
if (!themeName || !themeName.trim())
throw new Error("Give a theme name, for example: npx jake theme \"Aristo3 Dark\"");
if (/^(\^|jake:)/.test(themeName))
throw new Error("A theme name cannot start with ^ or jake:, which Jake reads as a task scope");
if (JAKE.application().lookup(themeName))
throw new Error(themeName + " is a task in this Jakefile, not a theme name");
var plist = fs.readFileSync(plistPath, "utf8"),
plistValue = themeName.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
if (!themeKey.test(plist))
throw new Error("No CPDefaultTheme key in " + plistPath);
plist = plist.replace(themeKey, function(match, head, tail)
{
return head + plistValue + tail;
});
fs.writeFileSync(plistPath, plist);
JAKE.task(themeName);
console.log("Theme set to " + themeName + " in " + plistPath);
});