diff --git a/changelog.txt b/changelog.txt index 9d40b9bdb8b..303fd456b51 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,2 +1,3 @@ * Auto-download Firestore and RTDB emulators when using `emulators:start`. -* Make `functions:shell` respect the `--port` argument. \ No newline at end of file +* Make `functions:shell` respect the `--port` argument. +* Improve error message when `firebase serve` can't acquire the right port. \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 21b9974f920..95c3eb4cd37 100644 --- a/package-lock.json +++ b/package-lock.json @@ -230,7 +230,6 @@ "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-1.8.4.tgz", "integrity": "sha512-BoENMnu1Gav18HcpV9IleMPZ9exM+AvUjrAOV4Mzs/vfz2Lu/ABv451iEXByKiMPn2M140uul1txXCg83sAENw==", "dev": true, - "optional": true, "requires": { "abort-controller": "^3.0.0", "extend": "^3.0.2", @@ -320,8 +319,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "optional": true + "dev": true }, "retry-request": { "version": "4.0.0", @@ -401,8 +399,7 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-0.4.0.tgz", "integrity": "sha512-4yAHDC52TEMCNcMzVC8WlqnKKKq+Ssi2lXoUg9zWWkZ6U6tq9ZBRYLHHCRdfU+EU9YJsVmivwGcKYCjRGjnf4Q==", - "dev": true, - "optional": true + "dev": true }, "@google-cloud/storage": { "version": "2.5.0", @@ -518,36 +515,31 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=", - "dev": true, - "optional": true + "dev": true }, "@protobufjs/base64": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", - "dev": true, - "optional": true + "dev": true }, "@protobufjs/codegen": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", - "dev": true, - "optional": true + "dev": true }, "@protobufjs/eventemitter": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=", - "dev": true, - "optional": true + "dev": true }, "@protobufjs/fetch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", "dev": true, - "optional": true, "requires": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" @@ -557,36 +549,31 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=", - "dev": true, - "optional": true + "dev": true }, "@protobufjs/inquire": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=", - "dev": true, - "optional": true + "dev": true }, "@protobufjs/path": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=", - "dev": true, - "optional": true + "dev": true }, "@protobufjs/pool": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=", - "dev": true, - "optional": true + "dev": true }, "@protobufjs/utf8": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=", - "dev": true, - "optional": true + "dev": true }, "@sinonjs/commons": { "version": "1.4.0", @@ -787,8 +774,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.0.tgz", "integrity": "sha512-1w52Nyx4Gq47uuu0EVcsHBxZFJgurQ+rTKS3qMHxR1GY2T8c2AJYd6vZoZ9q1rupaDjU0yT+Jc2XTyXkjeMA+Q==", - "dev": true, - "optional": true + "dev": true }, "@types/mime": { "version": "2.0.1", @@ -954,7 +940,6 @@ "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", "dev": true, - "optional": true, "requires": { "event-target-shim": "^5.0.0" } @@ -985,7 +970,6 @@ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", "dev": true, - "optional": true, "requires": { "es6-promisify": "^5.0.0" } @@ -1279,8 +1263,7 @@ "version": "7.2.1", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==", - "dev": true, - "optional": true + "dev": true }, "binary-extensions": { "version": "1.13.1", @@ -2270,7 +2253,6 @@ "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", "dev": true, - "optional": true, "requires": { "end-of-stream": "^1.0.0", "inherits": "^2.0.1", @@ -2365,15 +2347,13 @@ "version": "4.2.8", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", - "dev": true, - "optional": true + "dev": true }, "es6-promisify": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", "dev": true, - "optional": true, "requires": { "es6-promise": "^4.0.3" } @@ -2593,8 +2573,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "dev": true, - "optional": true + "dev": true }, "execa": { "version": "0.7.0", @@ -2830,8 +2809,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.0.tgz", "integrity": "sha512-R9bHCvweUxxwkDwhjav5vxpFvdPGlVngtqmx4pIZfSUhM/Q4NiIUHB456BAf+Q1Nwu3HEZYONtu+Rya+af4jiQ==", - "dev": true, - "optional": true + "dev": true }, "fast-url-parser": { "version": "1.1.3", @@ -3215,8 +3193,7 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true, - "optional": true + "bundled": true }, "aproba": { "version": "1.2.0", @@ -3234,13 +3211,11 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true, - "optional": true + "bundled": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3253,18 +3228,15 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "concat-map": { "version": "0.0.1", - "bundled": true, - "optional": true + "bundled": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "core-util-is": { "version": "1.0.2", @@ -3367,8 +3339,7 @@ }, "inherits": { "version": "2.0.3", - "bundled": true, - "optional": true + "bundled": true }, "ini": { "version": "1.3.5", @@ -3378,7 +3349,6 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -3391,20 +3361,17 @@ "minimatch": { "version": "3.0.4", "bundled": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true, - "optional": true + "bundled": true }, "minipass": { "version": "2.3.5", "bundled": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -3421,7 +3388,6 @@ "mkdirp": { "version": "0.5.1", "bundled": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -3494,8 +3460,7 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, - "optional": true + "bundled": true }, "object-assign": { "version": "4.1.1", @@ -3505,7 +3470,6 @@ "once": { "version": "1.4.0", "bundled": true, - "optional": true, "requires": { "wrappy": "1" } @@ -3581,8 +3545,7 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true, - "optional": true + "bundled": true }, "safer-buffer": { "version": "2.1.2", @@ -3612,7 +3575,6 @@ "string-width": { "version": "1.0.2", "bundled": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -3630,7 +3592,6 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -3669,13 +3630,11 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true, - "optional": true + "bundled": true }, "yallist": { "version": "3.0.3", - "bundled": true, - "optional": true + "bundled": true } } }, @@ -3690,7 +3649,6 @@ "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-2.0.1.tgz", "integrity": "sha512-c1NXovTxkgRJTIgB2FrFmOFg4YIV6N/bAa4f/FZ4jIw13Ql9ya/82x69CswvotJhbV3DiGnlTZwoq2NVXk2Irg==", "dev": true, - "optional": true, "requires": { "abort-controller": "^3.0.0", "extend": "^3.0.2", @@ -3752,7 +3710,6 @@ "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-1.8.4.tgz", "integrity": "sha512-BoENMnu1Gav18HcpV9IleMPZ9exM+AvUjrAOV4Mzs/vfz2Lu/ABv451iEXByKiMPn2M140uul1txXCg83sAENw==", "dev": true, - "optional": true, "requires": { "abort-controller": "^3.0.0", "extend": "^3.0.2", @@ -3765,7 +3722,6 @@ "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", "dev": true, - "optional": true, "requires": { "event-target-shim": "^5.0.0" } @@ -3854,8 +3810,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "optional": true + "dev": true }, "write-file-atomic": { "version": "2.4.3", @@ -4116,8 +4071,7 @@ "version": "6.1.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.1.1.tgz", "integrity": "sha512-rWYq2e5iYW+fFe/oPPtYJxYgjBm8sC4rmoGdUOgBB7VnwKt6HrL793l2voH1UlsyYZpJ4g0wfjnTEO1s1NP2eQ==", - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.3", @@ -4321,7 +4275,6 @@ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", "dev": true, - "optional": true, "requires": { "agent-base": "^4.1.0", "debug": "^3.1.0" @@ -4332,7 +4285,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "dev": true, - "optional": true, "requires": { "ms": "^2.1.1" } @@ -4341,8 +4293,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "optional": true + "dev": true } } }, @@ -4848,7 +4799,6 @@ "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-0.3.0.tgz", "integrity": "sha1-DM2RLEuCcNBfBW+9E4FLU9OCWx4=", "dev": true, - "optional": true, "requires": { "bignumber.js": "^7.0.0" } @@ -5191,8 +5141,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==", - "dev": true, - "optional": true + "dev": true }, "lowercase-keys": { "version": "1.0.1", @@ -5660,8 +5609,7 @@ "version": "2.6.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==", - "dev": true, - "optional": true + "dev": true }, "node-forge": { "version": "0.7.6", @@ -6252,7 +6200,6 @@ "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.8.tgz", "integrity": "sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw==", "dev": true, - "optional": true, "requires": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", @@ -6293,7 +6240,6 @@ "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", "dev": true, - "optional": true, "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -6304,7 +6250,6 @@ "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", "dev": true, - "optional": true, "requires": { "duplexify": "^3.6.0", "inherits": "^2.0.3", @@ -7022,7 +6967,6 @@ "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", "integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==", "dev": true, - "optional": true, "requires": { "stubs": "^3.0.0" } @@ -7031,8 +6975,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", - "dev": true, - "optional": true + "dev": true }, "streamsearch": { "version": "0.1.2", @@ -7125,8 +7068,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", "integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls=", - "dev": true, - "optional": true + "dev": true }, "superagent": { "version": "3.8.3", @@ -7345,7 +7287,6 @@ "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-3.11.3.tgz", "integrity": "sha512-CKncqSF7sH6p4rzCgkb/z/Pcos5efl0DmolzvlqRQUNcpRIruOhY9+T1FsIlyEbfWd7MsFpodROOwHYh2BaXzw==", "dev": true, - "optional": true, "requires": { "https-proxy-agent": "^2.2.1", "node-fetch": "^2.2.0", diff --git a/src/emulator/controller.ts b/src/emulator/controller.ts index 1a2e3ba216f..95434c0eff7 100644 --- a/src/emulator/controller.ts +++ b/src/emulator/controller.ts @@ -18,7 +18,7 @@ import * as path from "path"; export const VALID_EMULATOR_STRINGS: string[] = ALL_EMULATORS; -async function checkPortOpen(port: number): Promise { +export async function checkPortOpen(port: number): Promise { try { await pf.getPortPromise({ port, stopPort: port }); return true; @@ -27,7 +27,7 @@ async function checkPortOpen(port: number): Promise { } } -async function waitForPortClosed(port: number): Promise { +export async function waitForPortClosed(port: number): Promise { const interval = 250; const timeout = 30000; @@ -67,10 +67,7 @@ export async function startEmulator(instance: EmulatorInstance): Promise { return utils.reject(`Could not start ${name} emulator, port taken.`, {}); } - // Start the emulator, wait for it to grab its port, and then mark it as started - // in the registry. await EmulatorRegistry.start(instance); - await waitForPortClosed(info.port); } export async function cleanShutdown(): Promise { diff --git a/src/emulator/emulatorServer.ts b/src/emulator/emulatorServer.ts index 2344a89695d..6c53f1e681a 100644 --- a/src/emulator/emulatorServer.ts +++ b/src/emulator/emulatorServer.ts @@ -1,8 +1,7 @@ -import * as clc from "cli-color"; - import { EmulatorInstance } from "./types"; import { EmulatorRegistry } from "./registry"; -import * as utils from "../utils"; +import * as controller from "./controller"; +import * as FirebaseError from "../error"; /** * Wrapper object to expose an EmulatorInstance for "firebase serve" that @@ -12,10 +11,16 @@ export class EmulatorServer { constructor(public instance: EmulatorInstance) {} async start(): Promise { - await EmulatorRegistry.start(this.instance); + const port = this.instance.getInfo().port; + const portOpen = await controller.checkPortOpen(port); - const name = this.instance.getName(); - const info = this.instance.getInfo(); + if (!portOpen) { + throw new FirebaseError( + `Port ${port} is not open, could not start ${this.instance.getName()} emulator.` + ); + } + + await EmulatorRegistry.start(this.instance); } async connect(): Promise { diff --git a/src/emulator/registry.ts b/src/emulator/registry.ts index e36aabebdce..8387e2dfc90 100644 --- a/src/emulator/registry.ts +++ b/src/emulator/registry.ts @@ -3,6 +3,7 @@ import * as clc from "cli-color"; import { ALL_EMULATORS, EmulatorInstance, Emulators } from "./types"; import * as FirebaseError from "../error"; import * as utils from "../utils"; +import * as controller from "./controller"; /** * Static registry for running emulators to discover each other. @@ -16,9 +17,11 @@ export class EmulatorRegistry { throw new FirebaseError(`Emulator ${instance.getName()} is already running!`, {}); } + // Start the emulator and wait for it to grab its assigned port. await instance.start(); - this.set(instance.getName(), instance); + await controller.waitForPortClosed(instance.getInfo().port); + this.set(instance.getName(), instance); const info = instance.getInfo(); utils.logLabeledSuccess( instance.getName(),