diff --git a/CHANGELOG.md b/CHANGELOG.md index c2c73444ebc..86405a4cd18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,3 +3,4 @@ - Fixes `firebase init database` failure when no project is selected (#2981) - Fix issue where `firebase init database` overwrites entire `firebase.json` (#3299) - Fixes import/export bug with Storage emulator download tokens (#3414) +- Improves errors when failing to start Storage emulator (#3443) diff --git a/src/emulator/downloadableEmulators.ts b/src/emulator/downloadableEmulators.ts index ebad1e4a65e..c40e4aa278a 100644 --- a/src/emulator/downloadableEmulators.ts +++ b/src/emulator/downloadableEmulators.ts @@ -253,15 +253,15 @@ export function _getCommand( }; } -async function _fatal(emulator: DownloadableEmulatorDetails, errorMsg: string): Promise { +async function _fatal(emulator: Emulators, errorMsg: string): Promise { // if we do not issue a stopAll here and _fatal is called during startup, we could leave emulators running // that did start already // for example: JAVA_HOME=/does/not/exist firebase emulators:start try { - const logger = EmulatorLogger.forEmulator(emulator.name); + const logger = EmulatorLogger.forEmulator(emulator); logger.logLabeled( "WARN", - emulator.name, + emulator, `Fatal error occurred: \n ${errorMsg}, \n stopping all running emulators` ); await EmulatorRegistry.stopAll(); @@ -270,6 +270,18 @@ async function _fatal(emulator: DownloadableEmulatorDetails, errorMsg: string): } } +export async function handleEmulatorProcessError(emulator: Emulators, err: any): Promise { + const description = Constants.description(emulator); + if (err.path === "java" && err.code === "ENOENT") { + await _fatal( + emulator, + `${description} has exited because java is not installed, you can install it from https://openjdk.java.net/install/` + ); + } else { + await _fatal(emulator, `${description} has exited: ${err}`); + } +} + async function _runBinary( emulator: DownloadableEmulatorDetails, command: DownloadableEmulatorCommand, @@ -298,7 +310,7 @@ async function _runBinary( `Could not spawn child process for emulator, check that java is installed and on your $PATH.` ); } - _fatal(emulator, e); + _fatal(emulator.name, e); } const description = Constants.description(emulator.name); @@ -331,21 +343,15 @@ async function _runBinary( } }); - emulator.instance.on("error", async (err: any) => { - if (err.path === "java" && err.code === "ENOENT") { - await _fatal( - emulator, - `${description} has exited because java is not installed, you can install it from https://openjdk.java.net/install/` - ); - } else { - await _fatal(emulator, `${description} has exited: ${err}`); - } + emulator.instance.on("error", (err) => { + handleEmulatorProcessError(emulator.name, err); }); + emulator.instance.once("exit", async (code, signal) => { if (signal) { utils.logWarning(`${description} has exited upon receiving signal: ${signal}`); } else if (code && code !== 0 && code !== /* SIGINT */ 130) { - await _fatal(emulator, `${description} has exited with code: ${code}`); + await _fatal(emulator.name, `${description} has exited with code: ${code}`); } }); resolve(); diff --git a/src/emulator/storage/rules/runtime.ts b/src/emulator/storage/rules/runtime.ts index 24d00b95220..b153bca85b5 100644 --- a/src/emulator/storage/rules/runtime.ts +++ b/src/emulator/storage/rules/runtime.ts @@ -21,7 +21,11 @@ import * as utils from "../../../utils"; import { Constants } from "../../constants"; import { downloadEmulator } from "../../download"; import * as fs from "fs-extra"; -import { DownloadDetails, _getCommand } from "../../downloadableEmulators"; +import { + _getCommand, + DownloadDetails, + handleEmulatorProcessError, +} from "../../downloadableEmulators"; export interface RulesetVerificationOpts { file: { @@ -142,16 +146,22 @@ export class StorageRulesRuntime { }; }); + // This catches error when spawning the java process + this._childprocess.on("error", (err) => { + handleEmulatorProcessError(Emulators.STORAGE, err); + }); + + // This catches errors from the java process (i.e. missing jar file) this._childprocess.stderr.on("data", (buf: Buffer) => { const error = buf.toString(); - if (error.includes("Invalid or corrupt jarfile")) { + if (error.includes("jarfile")) { throw new FirebaseError( "There was an issue starting the rules emulator, please run 'firebase setup:emulators:storage` again" ); } else { EmulatorLogger.forEmulator(Emulators.STORAGE).log( "WARN", - `Unexpected rules runtime output: ${buf.toString()}` + `Unexpected rules runtime error: ${buf.toString()}` ); } });