@hominis/fireforge 0.24.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/README.md +1 -1
- package/dist/src/core/branding.js +72 -25
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.25.0
|
|
4
|
+
|
|
5
|
+
- Kept `MOZ_APP_VENDOR` in `browser/moz.configure` for Firefox ESR 140 project-flag trees instead of generated branding `configure.sh`.
|
|
6
|
+
- Added a regression for stale xpcshell install symlink repair under shared `_tests/testing/mochitest/` harness paths.
|
|
7
|
+
|
|
3
8
|
## 0.24.0
|
|
4
9
|
|
|
5
10
|
- Moved branding vendor identity into generated branding configure scripts and made `browser/moz.configure` vendor patching optional.
|
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ Inspired by [fern.js](https://github.com/ghostery/user-agent-desktop) and [Melon
|
|
|
20
20
|
|
|
21
21
|
## Requirements
|
|
22
22
|
|
|
23
|
-
- Node.js
|
|
23
|
+
- Node.js 22.22.1+
|
|
24
24
|
- Python 3
|
|
25
25
|
- Git
|
|
26
26
|
- The normal Firefox platform build tools: Xcode command line tools on macOS, `build-essential`-style packages on Linux, Visual Studio Build Tools on Windows (never tested on Windows tbh)
|
|
@@ -53,6 +53,7 @@ export class BrandingMozconfigMismatchError extends FireForgeError {
|
|
|
53
53
|
'The mismatch is caught before mach builds because resolving the build against the wrong branding tree fails deep in moz.build with a confusing "path does not exist" message.');
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
|
+
const MOZ_APP_VENDOR_IMPLY_REGEX = /imply_option\("MOZ_APP_VENDOR",\s*"[^"]*"\)/;
|
|
56
57
|
/**
|
|
57
58
|
* Sets up the custom branding directory for the browser.
|
|
58
59
|
*
|
|
@@ -76,29 +77,30 @@ export async function setupBranding(engineDir, config) {
|
|
|
76
77
|
if (!(await pathExists(brandingDir))) {
|
|
77
78
|
await copyDir(unofficialDir, brandingDir);
|
|
78
79
|
}
|
|
80
|
+
const vendorPlacement = await resolveVendorPlacement(engineDir);
|
|
79
81
|
// Create/update configure.sh with custom values
|
|
80
|
-
await createConfigureScript(brandingDir, config);
|
|
82
|
+
await createConfigureScript(brandingDir, config, vendorPlacement);
|
|
81
83
|
// Update localization files
|
|
82
84
|
await updateBrandProperties(brandingDir, config);
|
|
83
85
|
await updateBrandFtl(brandingDir, config);
|
|
84
86
|
// Patch moz.configure for MOZ_APP_VENDOR
|
|
85
|
-
await patchMozConfigure(engineDir, config);
|
|
87
|
+
await patchMozConfigure(engineDir, config, vendorPlacement);
|
|
86
88
|
}
|
|
87
89
|
/**
|
|
88
90
|
* Creates the branding configure.sh script.
|
|
89
91
|
*/
|
|
90
|
-
async function createConfigureScript(brandingDir, config) {
|
|
92
|
+
async function createConfigureScript(brandingDir, config, vendorPlacement) {
|
|
91
93
|
const configureShPath = join(brandingDir, 'configure.sh');
|
|
92
|
-
await writeTextIfChanged(configureShPath, buildConfigureScriptContent(config));
|
|
94
|
+
await writeTextIfChanged(configureShPath, buildConfigureScriptContent(config, vendorPlacement));
|
|
93
95
|
}
|
|
94
|
-
function buildConfigureScriptContent(config) {
|
|
96
|
+
function buildConfigureScriptContent(config, vendorPlacement) {
|
|
95
97
|
const header = getLicenseHeader(config.license ?? DEFAULT_LICENSE, 'hash');
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
MOZ_MACBUNDLE_ID="${escapeShellValue(config.appId)}"
|
|
101
|
-
`;
|
|
98
|
+
const lines = [`MOZ_APP_DISPLAYNAME="${escapeShellValue(config.name)}"`];
|
|
99
|
+
if (vendorPlacement === 'branding-configure') {
|
|
100
|
+
lines.push(`MOZ_APP_VENDOR="${escapeShellValue(config.vendor)}"`);
|
|
101
|
+
}
|
|
102
|
+
lines.push(`MOZ_MACBUNDLE_ID="${escapeShellValue(config.appId)}"`);
|
|
103
|
+
return `${header}\n\n${lines.join('\n')}\n`;
|
|
102
104
|
}
|
|
103
105
|
/**
|
|
104
106
|
* Updates the brand.properties localization file.
|
|
@@ -150,30 +152,66 @@ trademarkInfo = { " " }
|
|
|
150
152
|
}
|
|
151
153
|
/**
|
|
152
154
|
* Patches browser/moz.configure to set custom vendor when the upstream
|
|
153
|
-
* configure surface
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
* configure.sh instead, so an absent browser/moz.configure line is valid.
|
|
157
|
-
* Keeping this best-effort replacement preserves compatibility for queues
|
|
158
|
-
* that still carry the older process-wide registration line.
|
|
155
|
+
* configure surface owns MOZ_APP_VENDOR as a project flag. ESR 140 rejects
|
|
156
|
+
* branding configure.sh / confvars origins for that flag, so the value must
|
|
157
|
+
* come from imply_option.
|
|
159
158
|
*/
|
|
160
|
-
async function patchMozConfigure(engineDir, config) {
|
|
159
|
+
async function patchMozConfigure(engineDir, config, vendorPlacement) {
|
|
160
|
+
if (vendorPlacement !== 'moz-configure') {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
161
163
|
const mozConfigurePath = join(engineDir, 'browser', 'moz.configure');
|
|
162
164
|
if (!(await pathExists(mozConfigurePath))) {
|
|
163
165
|
return;
|
|
164
166
|
}
|
|
165
167
|
let content = await readText(mozConfigurePath);
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
168
|
+
if (MOZ_APP_VENDOR_IMPLY_REGEX.test(content)) {
|
|
169
|
+
content = content.replace(MOZ_APP_VENDOR_IMPLY_REGEX, buildMozConfigureVendorLine(config));
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
content = insertMozConfigureVendorLine(content, buildMozConfigureVendorLine(config));
|
|
170
173
|
}
|
|
171
|
-
content = content.replace(vendorRegex, buildMozConfigureVendorLine(config));
|
|
172
174
|
await writeTextIfChanged(mozConfigurePath, content);
|
|
173
175
|
}
|
|
174
176
|
function buildMozConfigureVendorLine(config) {
|
|
175
177
|
return `imply_option("MOZ_APP_VENDOR", "${escapeString(config.vendor)}")`;
|
|
176
178
|
}
|
|
179
|
+
async function resolveVendorPlacement(engineDir) {
|
|
180
|
+
const mozConfigurePath = join(engineDir, 'browser', 'moz.configure');
|
|
181
|
+
const toolkitMozConfigurePath = join(engineDir, 'toolkit', 'moz.configure');
|
|
182
|
+
const browserMozConfigureExists = await pathExists(mozConfigurePath);
|
|
183
|
+
const browserMozConfigureContent = browserMozConfigureExists
|
|
184
|
+
? await readText(mozConfigurePath)
|
|
185
|
+
: undefined;
|
|
186
|
+
if (browserMozConfigureContent !== undefined &&
|
|
187
|
+
MOZ_APP_VENDOR_IMPLY_REGEX.test(browserMozConfigureContent)) {
|
|
188
|
+
return 'moz-configure';
|
|
189
|
+
}
|
|
190
|
+
if (await toolkitMozConfigureUsesVendorProjectFlag(toolkitMozConfigurePath)) {
|
|
191
|
+
if (!browserMozConfigureExists) {
|
|
192
|
+
throw new BrandingError('Firefox toolkit configure declares MOZ_APP_VENDOR as a project_flag, but browser/moz.configure is missing, so FireForge cannot safely set the vendor identity.');
|
|
193
|
+
}
|
|
194
|
+
return 'moz-configure';
|
|
195
|
+
}
|
|
196
|
+
return 'branding-configure';
|
|
197
|
+
}
|
|
198
|
+
async function toolkitMozConfigureUsesVendorProjectFlag(filePath) {
|
|
199
|
+
if (!(await pathExists(filePath))) {
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
const content = await readText(filePath);
|
|
203
|
+
return /project_flag\(\s*(?:(?!\)\s*\n)[\s\S])*env\s*=\s*"MOZ_APP_VENDOR"/m.test(content);
|
|
204
|
+
}
|
|
205
|
+
function insertMozConfigureVendorLine(content, line) {
|
|
206
|
+
const includeRegex = /^include\((["'])\.\.\/toolkit\/moz\.configure\1\)\s*$/m;
|
|
207
|
+
const match = includeRegex.exec(content);
|
|
208
|
+
if (!match) {
|
|
209
|
+
return `${content.replace(/\s*$/, '')}\n\n${line}\n`;
|
|
210
|
+
}
|
|
211
|
+
const prefix = content.slice(0, match.index).replace(/\s*$/, '');
|
|
212
|
+
const suffix = content.slice(match.index);
|
|
213
|
+
return `${prefix}\n\n${line}\n${suffix}`;
|
|
214
|
+
}
|
|
177
215
|
/**
|
|
178
216
|
* Escapes a string for use in Python/configure file.
|
|
179
217
|
*/
|
|
@@ -230,8 +268,9 @@ export async function isBrandingSetup(engineDir, config) {
|
|
|
230
268
|
if (!(await pathExists(configureShPath))) {
|
|
231
269
|
return false;
|
|
232
270
|
}
|
|
271
|
+
const vendorPlacement = await resolveVendorPlacement(engineDir);
|
|
233
272
|
const configureContent = await readText(configureShPath);
|
|
234
|
-
if (configureContent !== buildConfigureScriptContent(config)) {
|
|
273
|
+
if (configureContent !== buildConfigureScriptContent(config, vendorPlacement)) {
|
|
235
274
|
return false;
|
|
236
275
|
}
|
|
237
276
|
if (await pathExists(propsPath)) {
|
|
@@ -246,7 +285,15 @@ export async function isBrandingSetup(engineDir, config) {
|
|
|
246
285
|
return false;
|
|
247
286
|
}
|
|
248
287
|
}
|
|
249
|
-
|
|
288
|
+
if (vendorPlacement === 'branding-configure') {
|
|
289
|
+
return configureContent.includes(`MOZ_APP_VENDOR="${escapeShellValue(config.vendor)}"`);
|
|
290
|
+
}
|
|
291
|
+
const mozConfigurePath = join(engineDir, 'browser', 'moz.configure');
|
|
292
|
+
if (!(await pathExists(mozConfigurePath))) {
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
const mozConfigureContent = await readText(mozConfigurePath);
|
|
296
|
+
return mozConfigureContent.includes(buildMozConfigureVendorLine(config));
|
|
250
297
|
}
|
|
251
298
|
/**
|
|
252
299
|
* Checks whether a file path belongs to the tool-managed branding directory.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hominis/fireforge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
4
4
|
"description": "FireForge — a build tool for customizing Firefox",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/src/index.js",
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
"vitest": "^4.0.18"
|
|
80
80
|
},
|
|
81
81
|
"engines": {
|
|
82
|
-
"node": ">=
|
|
82
|
+
"node": ">=22.22.1"
|
|
83
83
|
},
|
|
84
84
|
"packageManager": "npm@11.12.1",
|
|
85
85
|
"license": "EUPL-1.2",
|