in src/firefox/index.js [376:444]
export async function installExtension({
asProxy = false,
manifestData,
profile,
extensionPath,
asyncFsStat = defaultAsyncFsStat,
}) {
// This more or less follows
// https://github.com/saadtazi/firefox-profile-js/blob/master/lib/firefox_profile.js#L531
// (which is broken for web extensions).
// TODO: maybe uplift a patch that supports web extensions instead?
if (!profile.extensionsDir) {
throw new WebExtError('profile.extensionsDir was unexpectedly empty');
}
try {
await asyncFsStat(profile.extensionsDir);
} catch (error) {
if (isErrorWithCode('ENOENT', error)) {
log.debug(`Creating extensions directory: ${profile.extensionsDir}`);
await fs.mkdir(profile.extensionsDir);
} else {
throw error;
}
}
const id = getManifestId(manifestData);
if (!id) {
throw new UsageError(
'An explicit extension ID is required when installing to ' +
'a profile (applications.gecko.id not found in manifest.json)',
);
}
if (asProxy) {
log.debug(`Installing as an extension proxy; source: ${extensionPath}`);
const isDir = await isDirectory(extensionPath);
if (!isDir) {
throw new WebExtError(
'proxy install: extensionPath must be the extension source ' +
`directory; got: ${extensionPath}`,
);
}
// Write a special extension proxy file containing the source
// directory. See:
// https://developer.mozilla.org/en-US/Add-ons/Setting_up_extension_development_environment#Firefox_extension_proxy_file
const destPath = path.join(profile.extensionsDir, `${id}`);
const writeStream = nodeFs.createWriteStream(destPath);
writeStream.write(extensionPath);
writeStream.end();
return await fromEvent(writeStream, 'close');
} else {
// Write the XPI file to the profile.
const readStream = nodeFs.createReadStream(extensionPath);
const destPath = path.join(profile.extensionsDir, `${id}.xpi`);
const writeStream = nodeFs.createWriteStream(destPath);
log.debug(`Installing extension from ${extensionPath} to ${destPath}`);
readStream.pipe(writeStream);
return await Promise.all([
fromEvent(readStream, 'close'),
fromEvent(writeStream, 'close'),
]);
}
}