Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
34 changes: 20 additions & 14 deletions src/emulator/downloadableEmulators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,15 +253,15 @@ export function _getCommand(
};
}

async function _fatal(emulator: DownloadableEmulatorDetails, errorMsg: string): Promise<void> {
async function _fatal(emulator: Emulators, errorMsg: string): Promise<void> {
// 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();
Expand All @@ -270,6 +270,18 @@ async function _fatal(emulator: DownloadableEmulatorDetails, errorMsg: string):
}
}

export async function handleEmulatorProcessError(emulator: Emulators, err: any): Promise<void> {
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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();
Expand Down
16 changes: 13 additions & 3 deletions src/emulator/storage/rules/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down Expand Up @@ -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()}`
);
}
});
Expand Down