Skip to content
This repository has been archived by the owner on Oct 3, 2024. It is now read-only.

Commit

Permalink
A new utility to generate macOS application bundles
Browse files Browse the repository at this point in the history
Such a bundle launches firefox with an embedded profile, has its own logo and can run alongside the regular firefox
  • Loading branch information
Joris-van-der-Wel committed Dec 10, 2017
1 parent 28df7dc commit d11d238
Show file tree
Hide file tree
Showing 12 changed files with 104 additions and 0 deletions.
1 change: 1 addition & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
"import/no-extraneous-dependencies": [
"error", {
"devDependencies": [
"bin/**",
"test/**"
]
}
Expand Down
103 changes: 103 additions & 0 deletions bin/build-mac-bundle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
'use strict';
/* eslint-env node */
const {resolve: resolvePath, join: joinPath} = require('path');
const yargs = require('yargs');
const fs = require('fs-extra');
const {JSDOM} = require('jsdom');

const {version} = require('../package.json');

const {argv} = (
yargs
.option('profile', {
alias: 'p',
describe: 'Input directory containing a previously generated profile',
demandOption: true,
})
.option('app', {
alias: 'a',
describe: 'Input directory containing a firefox nightly / developer edition macOS bundle',
demandOption: true,
default: '/Applications/FirefoxDeveloperEdition.app',
})
.option('output', {
alias: 'o',
describe: 'Output directory for the macOS application bundle',
demandOption: true,
})
.help('help')
);
const bootstrapScript = `#!/usr/bin/env bash
MY_PATH="$( cd "$(dirname "$0")" ; pwd -P )"
"$MY_PATH/firefox" --no-remote --profile "$MY_PATH/../profile" "$@"
`;

const modifyInfoPlist = async path => {
const input = await fs.readFile(path, 'utf8');
const dom = new JSDOM(input, {
contentType: 'text/xml',
});
const {document} = dom.window;
const findKeyElement = keyName => {
return document.evaluate(`/plist/dict/key[text() = "${keyName}"]`, document, null, 9, null).singleNodeValue;
};
const valueElementForKey = keyName => {
// note: injection in the xpath expression here. however we are only using this function by passing our own constant values
const keyElement = findKeyElement(keyName);
return keyElement.nextElementSibling;
};
const removeKey = keyName => {
const keyElement = findKeyElement(keyName);
const valueElement = keyElement.nextElementSibling;
keyElement.remove();
valueElement.remove();
};

const firefoxVersionElement = valueElementForKey('CFBundleShortVersionString');
const firefoxVersion = firefoxVersionElement.textContent;
valueElementForKey('CFBundleIdentifier').textContent = `nl.computest.openrunner`;
valueElementForKey('CFBundleName').textContent = `Openrunner`;
valueElementForKey('CFBundleGetInfoString').textContent = `Openrunner ${version} (F${firefoxVersion})`;
valueElementForKey('CFBundleVersion').textContent = version;
valueElementForKey('CFBundleExecutable').textContent = 'openrunner';
valueElementForKey('CFBundleIconFile').textContent = `openrunner.icns`;
removeKey('CFBundleSignature');

const output = dom.serialize();
await fs.writeFile(path, output);
};

(async () => {
try {
const profilePath = resolvePath(argv.profile);
const appPath = resolvePath(argv.app);
const outputPath = resolvePath(argv.output);

console.log(
'*** Creating a new macOS application bundle with the profile',
profilePath,
'and firefox application bundle',
appPath,
'at',
outputPath
);

await fs.copy(appPath, outputPath, {preserveTimestamps: true});
await Promise.all([
fs.copy(profilePath, joinPath(outputPath, 'Contents', 'profile'), {preserveTimestamps: true}),
fs.copy(
require.resolve('../icons/openrunner.icns'),
joinPath(outputPath, 'Contents', 'Resources', 'openrunner.icns'),
{preserveTimestamps: true}
),
fs.writeFile(joinPath(outputPath, 'Contents', 'MacOS', 'openrunner'), bootstrapScript, {mode: 0o777}),
modifyInfoPlist(joinPath(outputPath, 'Contents', 'Info.plist')),
]);

console.log('*** Done!');
}
catch (err) {
console.error('Error during build!', err);
process.exitCode = 1;
}
})();
Binary file added icons/openrunner-128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified icons/openrunner-16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added icons/openrunner-256.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified icons/openrunner-32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified icons/openrunner-48.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed icons/openrunner-500.png
Binary file not shown.
Binary file added icons/openrunner-512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified icons/openrunner-64.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified icons/openrunner-96.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added icons/openrunner.icns
Binary file not shown.

0 comments on commit d11d238

Please sign in to comment.