<commit_before>import { Emulators, JavaEmulatorCommand, JavaEmulatorDetails } from "../emulator/types";
import { Constants } from "../emulator/constants";

import * as FirebaseError from "../error";
import * as childProcess from "child_process";
import * as utils from "../utils";
import * as logger from "../logger";

import * as clc from "cli-color";
import * as fs from "fs-extra";
import * as path from "path";
import * as os from "os";

const EMULATOR_INSTANCE_KILL_TIMEOUT = 2000; /* ms */

type JavaEmulators = Emulators.FIRESTORE | Emulators.DATABASE;

const CACHE_DIR =
  process.env.FIREBASE_EMULATORS_PATH || path.join(os.homedir(), ".cache", "firebase", "emulators");

const EmulatorDetails: { [s in JavaEmulators]: JavaEmulatorDetails } = {
  database: {
    name: Emulators.DATABASE,
    instance: null,
    stdout: null,
    cacheDir: CACHE_DIR,
    remoteUrl:
      "https://storage.googleapis.com/firebase-preview-drop/emulator/firebase-database-emulator-v3.5.0.jar",
    expectedSize: 17013124,
    expectedChecksum: "4bc8a67bc2a11d3e7ed226eda1b1a986",
    localPath: path.join(CACHE_DIR, "firebase-database-emulator-v3.5.0.jar"),
  },
  firestore: {
    name: Emulators.FIRESTORE,
    instance: null,
    stdout: null,
    cacheDir: CACHE_DIR,
    remoteUrl:
      "https://storage.googleapis.com/firebase-preview-drop/emulator/cloud-firestore-emulator-v1.4.5.jar",
    expectedSize: 56840576,
    expectedChecksum: "7fa4ebe4615650038c79ea260b0e7bf6",
    localPath: path.join(CACHE_DIR, "cloud-firestore-emulator-v1.4.5.jar"),
  },
};

const Commands: { [s in JavaEmulators]: JavaEmulatorCommand } = {
  database: {
    binary: "java",
    args: ["-Duser.language=en", "-jar", EmulatorDetails.database.localPath],
  },
  firestore: {
    binary: "java",
    args: ["-Duser.language=en", "-jar", EmulatorDetails.firestore.localPath],
  },
};

function _getLogFileName(name: string): string {
  return `${name}-debug.log`;
}

/**
 * Get a command to start the an emulator.
 * @param emulator - string identifier for the emulator to start.
 * @param args - map<string,string> of addittional args
 */
function _getCommand(emulator: JavaEmulators, args: { [s: string]: any }): JavaEmulatorCommand {
  const baseCmd = Commands[emulator];

  const defaultPort = Constants.getDefaultPort(emulator);
  if (!args.port) {
    args.port = defaultPort;
  }

  const cmdLineArgs = baseCmd.args.slice();
  Object.keys(args).forEach((key) => {
    const argKey = "--" + key;
    const argVal = args[key];

    cmdLineArgs.push(argKey, argVal);
  });

  return {
    binary: baseCmd.binary,
    args: cmdLineArgs,
  };
}

function _fatal(emulator: JavaEmulatorDetails, errorMsg: string): void {
  if (emulator.instance) {
    emulator.instance.kill("SIGINT");
  }
  throw new FirebaseError(emulator.name + ": " + errorMsg, { exit: 1 });
}

async function _runBinary(
  emulator: JavaEmulatorDetails,
  command: JavaEmulatorCommand
): Promise<void> {
  return new Promise((resolve) => {
    emulator.stdout = fs.createWriteStream(_getLogFileName(emulator.name));
    emulator.instance = childProcess.spawn(command.binary, command.args, {
      stdio: ["inherit", "pipe", "pipe"],
    });

    if (emulator.instance == null) {
      utils.logWarning(`Could not spawn child process for emulator ${emulator.name}`);
      return;
    }

    utils.logLabeledBullet(emulator.name, `Logging to ${clc.bold(_getLogFileName(emulator.name))}`);

    emulator.instance.stdout.on("data", (data) => {
      logger.debug(data.toString());
    });
    emulator.instance.stderr.on("data", (data) => {
      logger.debug(data.toString());
    });

    emulator.instance.on("error", (err: any) => {
      if (err.path === "java" && err.code === "ENOENT") {
        _fatal(
          emulator,
          "emulator has exited because java is not installed, you can install it from https://openjdk.java.net/install/"
        );
      } else {<commit_msg>Actually write emulator debug logs to the file. (#1298)<commit_after>import { Emulators, JavaEmulatorCommand, JavaEmulatorDetails } from "../emulator/types";
import { Constants } from "../emulator/constants";

import * as FirebaseError from "../error";
import * as childProcess from "child_process";
import * as utils from "../utils";
import * as logger from "../logger";

import * as clc from "cli-color";
import * as fs from "fs-extra";
import * as path from "path";
import * as os from "os";

const EMULATOR_INSTANCE_KILL_TIMEOUT = 2000; /* ms */

type JavaEmulators = Emulators.FIRESTORE | Emulators.DATABASE;

const CACHE_DIR =
  process.env.FIREBASE_EMULATORS_PATH || path.join(os.homedir(), ".cache", "firebase", "emulators");

const EmulatorDetails: { [s in JavaEmulators]: JavaEmulatorDetails } = {
  database: {
    name: Emulators.DATABASE,
    instance: null,
    stdout: null,
    cacheDir: CACHE_DIR,
    remoteUrl:
      "https://storage.googleapis.com/firebase-preview-drop/emulator/firebase-database-emulator-v3.5.0.jar",
    expectedSize: 17013124,
    expectedChecksum: "4bc8a67bc2a11d3e7ed226eda1b1a986",
    localPath: path.join(CACHE_DIR, "firebase-database-emulator-v3.5.0.jar"),
  },
  firestore: {
    name: Emulators.FIRESTORE,
    instance: null,
    stdout: null,
    cacheDir: CACHE_DIR,
    remoteUrl:
      "https://storage.googleapis.com/firebase-preview-drop/emulator/cloud-firestore-emulator-v1.4.5.jar",
    expectedSize: 56840576,
    expectedChecksum: "7fa4ebe4615650038c79ea260b0e7bf6",
    localPath: path.join(CACHE_DIR, "cloud-firestore-emulator-v1.4.5.jar"),
  },
};

const Commands: { [s in JavaEmulators]: JavaEmulatorCommand } = {
  database: {
    binary: "java",
    args: ["-Duser.language=en", "-jar", EmulatorDetails.database.localPath],
  },
  firestore: {
    binary: "java",
    args: ["-Duser.language=en", "-jar", EmulatorDetails.firestore.localPath],
  },
};

function _getLogFileName(name: string): string {
  return `${name}-debug.log`;
}

/**
 * Get a command to start the an emulator.
 * @param emulator - string identifier for the emulator to start.
 * @param args - map<string,string> of addittional args
 */
function _getCommand(emulator: JavaEmulators, args: { [s: string]: any }): JavaEmulatorCommand {
  const baseCmd = Commands[emulator];

  const defaultPort = Constants.getDefaultPort(emulator);
  if (!args.port) {
    args.port = defaultPort;
  }

  const cmdLineArgs = baseCmd.args.slice();
  Object.keys(args).forEach((key) => {
    const argKey = "--" + key;
    const argVal = args[key];

    cmdLineArgs.push(argKey, argVal);
  });

  return {
    binary: baseCmd.binary,
    args: cmdLineArgs,
  };
}

function _fatal(emulator: JavaEmulatorDetails, errorMsg: string): void {
  if (emulator.instance) {
    emulator.instance.kill("SIGINT");
  }
  throw new FirebaseError(emulator.name + ": " + errorMsg, { exit: 1 });
}

async function _runBinary(
  emulator: JavaEmulatorDetails,
  command: JavaEmulatorCommand
): Promise<void> {
  return new Promise((resolve) => {
    emulator.stdout = fs.createWriteStream(_getLogFileName(emulator.name));
    emulator.instance = childProcess.spawn(command.binary, command.args, {
      stdio: ["inherit", "pipe", "pipe"],
    });

    if (emulator.instance == null) {
      utils.logWarning(`Could not spawn child process for emulator ${emulator.name}`);
      return;
    }

    utils.logLabeledBullet(emulator.name, `Logging to ${clc.bold(_getLogFileName(emulator.name))}`);

    emulator.instance.stdout.on("data", (data) => {
      logger.debug(data.toString());
      emulator.stdout.write(data);
    });
    emulator.instance.stderr.on("data", (data) => {
      logger.debug(data.toString());
      emulator.stdout.write(data);
    });

    emulator.instance.on("error", (err: any) => {
      if (err.path === "java" && err.code === "ENOENT") {
        _fatal(
          emulator,
          "emulator has exited because java is not installed, you can install it from https://openjdk.java.net/install/"
        );
      } else {
{'fraction_non_alphanumeric': 0.14808318717113506, 'fraction_numerical': 0.01804059133049361, 'mean_word_length': 3.7348754448398576, 'pattern_counts': {'":': 2, '<': 7, '<?xml version=': 0, '>': 17, 'https://': 6, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2458184', 'n_tokens_mistral': 2748, 'n_tokens_neox': 2644, 'n_words': 556}