* use dependency injection for logger

This will allow to later create a backfill API which will expose the
stderr and stdout to the users.
It decouples the implementations of the various functionality of the
logger.

* rename reporter to logger

* simpler composition for logger

* split logger responsibilities in different modules

* better type safety

* fix wrong dependencies

* remove commented-out code

* timer implementation more faithful to initial implementation

* fix broken yarn.lock

* pipe execa output to logger

* introduce mute log level

It is useful for tests and remove some ugly if-checks in prod code.

* fix test checking stderr

* more explicite name for logFilter

* fix imports

- use es module interrop
- arrange order of import in this order: external, internal, relative

Co-authored-by: Vincent Bailly <vibailly@tuta.io>
This commit is contained in:
VincentBailly 2020-04-03 13:09:37 +02:00 коммит произвёл GitHub
Родитель 108539c0b2
Коммит a6d8537648
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
63 изменённых файлов: 616 добавлений и 640 удалений

Просмотреть файл

@ -1,6 +1,7 @@
import * as fs from "fs-extra";
import * as path from "path";
import execa = require("execa");
import fs from "fs-extra";
import path from "path";
import execa from "execa";
import { setupFixture } from "backfill-utils-test";
import { findPathToBackfill } from "./helper";

Просмотреть файл

@ -4,16 +4,19 @@ import { setupFixture } from "backfill-utils-test";
import { getCacheStorageProvider } from "backfill-cache";
import { Hasher } from "backfill-hasher";
import { createConfig } from "backfill-config";
import { makeLogger } from "backfill-logger";
import { backfill } from "../index";
import { createBuildCommand } from "../commandRunner";
const logger = makeLogger("mute");
describe("backfill", () => {
it("with cache miss and then cache hit", async () => {
// Set up
await setupFixture("basic");
const config = createConfig();
const config = createConfig(logger);
const {
cacheStorageConfig,
clearOutput,
@ -25,15 +28,21 @@ describe("backfill", () => {
// Arrange
const cacheStorage = getCacheStorageProvider(
cacheStorageConfig,
internalCacheFolder
internalCacheFolder,
logger
);
const buildCommandRaw = "npm run compile";
const buildCommand = createBuildCommand(
[buildCommandRaw],
clearOutput,
outputGlob
outputGlob,
logger
);
const hasher = new Hasher(
{ packageRoot, outputGlob },
buildCommandRaw,
logger
);
const hasher = new Hasher({ packageRoot, outputGlob }, buildCommandRaw);
// Spy
const spiedCacheStorage = spy(cacheStorage);
@ -41,7 +50,7 @@ describe("backfill", () => {
const spiedHasher = spy(hasher);
// Execute
await backfill(config, cacheStorage, spiedBuildCommand, hasher);
await backfill(config, cacheStorage, spiedBuildCommand, hasher, logger);
// Assert
verify(spiedHasher.createPackageHash()).once();
@ -54,7 +63,7 @@ describe("backfill", () => {
jest.clearAllMocks();
// Execute
await backfill(config, cacheStorage, buildCommand, hasher);
await backfill(config, cacheStorage, buildCommand, hasher, logger);
// Assert
verify(spiedHasher.createPackageHash()).once();

Просмотреть файл

@ -1,11 +1,15 @@
import * as fs from "fs-extra";
import fs from "fs-extra";
import { setupFixture } from "backfill-utils-test";
import { makeLogger } from "backfill-logger";
import { createBuildCommand } from "../commandRunner";
const logger = makeLogger("mute");
describe("createBuildCommand", () => {
it("runs a command successfully", async () => {
const buildCommand = createBuildCommand(["echo foo"], false, [""]);
const buildCommand = createBuildCommand(["echo foo"], false, [""], logger);
const buildResult = await buildCommand();
@ -15,25 +19,51 @@ describe("createBuildCommand", () => {
});
it("resolves if no command can be found", async () => {
const buildCommand = createBuildCommand([""], false, [""]);
const buildCommand = createBuildCommand([""], false, [""], logger);
await expect(buildCommand()).rejects.toThrow("Command not provided");
});
it("prints the error command and throws if it fails", async () => {
const buildCommand = createBuildCommand(["somecommand"], false, [""]);
const stderr: string[] = [];
const stdout: string[] = [];
const mockConsole = {
info(...args: string[]): void {
args.forEach(a => stdout.push(a));
},
warn(...args: string[]): void {
args.forEach(a => stderr.push(a));
},
error(...args: string[]): void {
args.forEach(a => stderr.push(a));
}
};
const logger = makeLogger("error", { console: mockConsole });
const buildCommand = createBuildCommand(
["somecommand"],
false,
[""],
logger
)();
try {
await buildCommand();
} catch (err) {
expect(err.stderr).toContain("somecommand");
expect(err.code).not.toEqual(0);
}
await buildCommand;
} catch (e) {}
expect(buildCommand).rejects.toThrow();
expect(stderr.filter(m => m.includes("somecommand")).length).not.toBe(0);
});
it("clears the output folder", async () => {
await setupFixture("pre-built");
const buildCommand = createBuildCommand(["echo foo"], true, ["lib/**"]);
const buildCommand = createBuildCommand(
["echo foo"],
true,
["lib/**"],
logger
);
const index_js_ExistsBeforeBuild = await fs.pathExists("lib/index.js");
await buildCommand();

Просмотреть файл

@ -1,6 +1,7 @@
import * as path from "path";
import * as fs from "fs-extra";
import * as execa from "execa";
import path from "path";
import fs from "fs-extra";
import execa from "execa";
import { setupFixture } from "backfill-utils-test";
import { findPathToBackfill } from "./helper";

Просмотреть файл

@ -1,5 +1,5 @@
import * as findUp from "find-up";
import * as path from "path";
import findUp from "find-up";
import path from "path";
export async function findPathToBackfill() {
const commandPath = await findUp(path.join("bin", "backfill.js"), {

Просмотреть файл

@ -1,8 +1,9 @@
import * as chokidar from "chokidar";
import * as findUp from "find-up";
import * as path from "path";
import chokidar from "chokidar";
import findUp from "find-up";
import path from "path";
import anymatch from "anymatch";
import { logger } from "backfill-logger";
import { Logger } from "backfill-logger";
let changedFilesOutsideScope: string[] = [];
let changedFilesInsideScope: string[] = [];
@ -35,7 +36,8 @@ export function initializeWatcher(
internalCacheFolder: string,
logFolder: string,
outputGlob: string[],
hashGlobs: string[]
hashGlobs: string[],
logger: Logger
) {
// Trying to find the git root and using it as an approximation of code boundary
const repositoryRoot = getGitRepositoryRoot(packageRoot);
@ -94,7 +96,7 @@ async function delay(time: number) {
});
}
export async function closeWatcher() {
export async function closeWatcher(logger: Logger) {
// Wait for one second before closing, giving time for file changes to propagate
await delay(1000);

Просмотреть файл

@ -1,7 +1,8 @@
import * as execa from "execa";
import * as fs from "fs-extra";
import * as fg from "fast-glob";
import { logger } from "backfill-logger";
import execa from "execa";
import fs from "fs-extra";
import fg from "fast-glob";
import { Logger } from "backfill-logger";
export type ExecaReturns = execa.ExecaChildProcess;
export type BuildCommand = () => Promise<ExecaReturns | void>;
@ -13,7 +14,8 @@ export function getRawBuildCommand(): string {
export function createBuildCommand(
buildCommand: string[],
clearOutput: boolean,
outputGlob: string[]
outputGlob: string[],
logger: Logger
): () => Promise<ExecaReturns | void> {
return async (): Promise<ExecaReturns | void> => {
const parsedBuildCommand = buildCommand.join(" ");
@ -27,26 +29,20 @@ export function createBuildCommand(
await Promise.all(filesToClear.map(async file => await fs.remove(file)));
}
// Set up runner
logger.profile("buildCommand:run");
const runner = execa(parsedBuildCommand, {
shell: true,
...(process.env.NODE_ENV !== "test" ? { stdio: "inherit" } : {})
});
try {
// Set up runner
const tracer = logger.setTime("buildTime");
const runner = execa(parsedBuildCommand, {
shell: true
});
return (
runner
// Add build time to the performance logger
.then(() => {
logger.setTime("buildTime", "buildCommand:run");
})
// Catch to pretty-print the command that failed and re-throw
.catch(err => {
if (process.env.NODE_ENV !== "test") {
logger.error(`Failed while running: "${parsedBuildCommand}"`);
}
throw err;
})
);
logger.pipeProcessOutput(runner.stdout, runner.stderr);
await runner;
tracer.stop();
} catch (e) {
logger.error(`Failed while running: "${parsedBuildCommand}"`);
throw e;
}
};
}

Просмотреть файл

@ -1,18 +1,17 @@
import * as yargs from "yargs";
import yargs from "yargs";
import { loadDotenv } from "backfill-utils-dotenv";
import { getCacheStorageProvider, ICacheStorage } from "backfill-cache";
import { logger, setLogLevel } from "backfill-logger";
import { Logger, makeLogger } from "backfill-logger";
import { createConfig, Config } from "backfill-config";
import { IHasher, Hasher } from "backfill-hasher";
export { createDefaultConfig } from "backfill-config";
import {
getRawBuildCommand,
createBuildCommand,
BuildCommand
} from "./commandRunner";
import { IHasher, Hasher } from "backfill-hasher";
export { createDefaultConfig } from "backfill-config";
import { initializeWatcher, closeWatcher } from "./audit";
// Load environment variables
@ -22,7 +21,8 @@ export async function backfill(
config: Config,
cacheStorage: ICacheStorage,
buildCommand: BuildCommand,
hasher: IHasher
hasher: IHasher,
logger: Logger
): Promise<void> {
const {
cacheStorageConfig,
@ -35,7 +35,7 @@ export async function backfill(
} = config;
logger.setName(name);
logger.setMode(mode);
logger.setMode(mode, mode === "READ_WRITE" ? "info" : "verbose");
logger.setCacheProvider(cacheStorageConfig.provider);
const createPackageHash = async () => await hasher.createPackageHash();
@ -102,8 +102,9 @@ export async function backfill(
}
export async function main(): Promise<void> {
let logger = makeLogger("info");
try {
const config = createConfig();
const config = createConfig(logger);
const {
cacheStorageConfig,
clearOutput,
@ -116,7 +117,7 @@ export async function main(): Promise<void> {
} = config;
if (logLevel) {
setLogLevel(logLevel);
logger = makeLogger(logLevel);
}
const helpString = "Backfills unchanged packages.";
@ -131,16 +132,23 @@ export async function main(): Promise<void> {
type: "boolean"
}).argv;
const buildCommand = createBuildCommand(argv["_"], clearOutput, outputGlob);
const buildCommand = createBuildCommand(
argv["_"],
clearOutput,
outputGlob,
logger
);
const cacheStorage = getCacheStorageProvider(
cacheStorageConfig,
internalCacheFolder
internalCacheFolder,
logger
);
const hasher = new Hasher(
{ packageRoot, outputGlob },
getRawBuildCommand()
getRawBuildCommand(),
logger
);
if (argv["audit"]) {
@ -149,14 +157,15 @@ export async function main(): Promise<void> {
internalCacheFolder,
logFolder,
outputGlob,
hashGlobs
hashGlobs,
logger
);
}
await backfill(config, cacheStorage, buildCommand, hasher);
await backfill(config, cacheStorage, buildCommand, hasher, logger);
if (argv["audit"]) {
await closeWatcher();
await closeWatcher(logger);
}
} catch (err) {
logger.error(err);

9
packages/cache/src/AzureBlobCacheStorage.ts поставляемый
Просмотреть файл

@ -1,7 +1,8 @@
import { BlobServiceClient } from "@azure/storage-blob";
import * as tar from "tar";
import * as fg from "fast-glob";
import tar from "tar";
import fg from "fast-glob";
import { Logger } from "backfill-logger";
import { AzureBlobCacheStorageOptions } from "backfill-config";
import { CacheStorage } from "./CacheStorage";
@ -29,8 +30,8 @@ function createBlobClient(
}
export class AzureBlobCacheStorage extends CacheStorage {
constructor(private options: AzureBlobCacheStorageOptions) {
super();
constructor(private options: AzureBlobCacheStorageOptions, logger: Logger) {
super(logger);
}
protected async _fetch(hash: string): Promise<boolean> {

17
packages/cache/src/CacheStorage.ts поставляемый
Просмотреть файл

@ -1,5 +1,6 @@
import { logger } from "backfill-logger";
import * as fg from "fast-glob";
import fg from "fast-glob";
import { Logger } from "backfill-logger";
export interface ICacheStorage {
fetch: (hash: string) => Promise<Boolean>;
@ -7,18 +8,20 @@ export interface ICacheStorage {
}
export abstract class CacheStorage implements ICacheStorage {
public constructor(protected logger: Logger) {}
public async fetch(hash: string): Promise<Boolean> {
logger.profile("cache:fetch");
const tracer = this.logger.setTime("fetchTime");
const result = await this._fetch(hash);
logger.setTime("fetchTime", "cache:fetch");
logger.setHit(result);
tracer.stop();
this.logger.setHit(result);
return result;
}
public async put(hash: string, outputGlob: string[]): Promise<void> {
logger.profile("cache:put");
const tracer = this.logger.setTime("putTime");
const filesBeingCached = fg.sync(outputGlob);
if (filesBeingCached.length === 0) {
@ -30,7 +33,7 @@ export abstract class CacheStorage implements ICacheStorage {
}
await this._put(hash, outputGlob);
logger.setTime("putTime", "cache:put");
tracer.stop();
}
protected abstract async _fetch(hash: string): Promise<boolean>;

12
packages/cache/src/LocalCacheStorage.ts поставляемый
Просмотреть файл

@ -1,12 +1,14 @@
import * as fs from "fs-extra";
import * as path from "path";
import * as fg from "fast-glob";
import fs from "fs-extra";
import path from "path";
import fg from "fast-glob";
import { Logger } from "backfill-logger";
import { CacheStorage } from "./CacheStorage";
export class LocalCacheStorage extends CacheStorage {
constructor(private internalCacheFolder: string) {
super();
constructor(private internalCacheFolder: string, logger: Logger) {
super(logger);
}
protected getLocalCacheFolder(hash: string): string {

58
packages/cache/src/NpmCacheStorage.ts поставляемый
Просмотреть файл

@ -1,18 +1,20 @@
import * as execa from "execa";
import * as fs from "fs-extra";
import * as path from "path";
import * as fg from "fast-glob";
import execa from "execa";
import fs from "fs-extra";
import path from "path";
import fg from "fast-glob";
import { NpmCacheStorageOptions } from "backfill-config";
import { Logger } from "backfill-logger";
import { CacheStorage } from "./CacheStorage";
export class NpmCacheStorage extends CacheStorage {
constructor(
private options: NpmCacheStorageOptions,
private internalCacheFolder: string
private internalCacheFolder: string,
logger: Logger
) {
super();
super(logger);
}
protected async _fetch(hash: string): Promise<boolean> {
@ -34,25 +36,25 @@ export class NpmCacheStorage extends CacheStorage {
fs.mkdirpSync(temporaryNpmOutputFolder);
try {
await execa(
"npm",
[
"install",
"--prefix",
temporaryNpmOutputFolder,
`${npmPackageName}@0.0.0-${hash}`,
"--registry",
registryUrl,
"--prefer-offline",
"--ignore-scripts",
"--no-shrinkwrap",
"--no-package-lock",
"--loglevel",
"error",
...(npmrcUserconfig ? ["--userconfig", npmrcUserconfig] : [])
],
{ stdout: "inherit" }
);
const runner = execa("npm", [
"install",
"--prefix",
temporaryNpmOutputFolder,
`${npmPackageName}@0.0.0-${hash}`,
"--registry",
registryUrl,
"--prefer-offline",
"--ignore-scripts",
"--no-shrinkwrap",
"--no-package-lock",
"--loglevel",
"error",
...(npmrcUserconfig ? ["--userconfig", npmrcUserconfig] : [])
]);
this.logger.pipeProcessOutput(runner.stdout, runner.stderr);
await runner;
} catch (error) {
fs.removeSync(temporaryNpmOutputFolder);
@ -109,7 +111,7 @@ export class NpmCacheStorage extends CacheStorage {
// Upload package
try {
await execa(
const runner = execa(
"npm",
[
"publish",
@ -124,6 +126,10 @@ export class NpmCacheStorage extends CacheStorage {
stdout: "inherit"
}
);
this.logger.pipeProcessOutput(runner.stdout, runner.stderr);
await runner;
} catch (error) {
if (error.stderr.toString().indexOf("403") === -1) {
throw new Error(error);

Просмотреть файл

@ -1,8 +1,10 @@
import * as fs from "fs-extra";
import * as path from "path";
import fs from "fs-extra";
import path from "path";
import { makeLogger } from "backfill-logger";
import { setupFixture } from "backfill-utils-test";
import { CacheStorageConfig } from "backfill-config";
import { getCacheStorageProvider } from "../index";
const setupCacheStorage = async (fixtureName: string) => {
@ -12,10 +14,12 @@ const setupCacheStorage = async (fixtureName: string) => {
provider: "local"
};
const internalCacheFolder = path.join("node_modules", ".cache", "backfill");
const logger = makeLogger("mute");
const cacheStorage = getCacheStorageProvider(
cacheStorageConfig,
internalCacheFolder
internalCacheFolder,
logger
);
return { cacheStorage, internalCacheFolder };

15
packages/cache/src/index.ts поставляемый
Просмотреть файл

@ -1,27 +1,32 @@
import { CacheStorageConfig } from "backfill-config";
import { Logger } from "backfill-logger";
import { ICacheStorage } from "./CacheStorage";
import { AzureBlobCacheStorage } from "./AzureBlobCacheStorage";
import { LocalCacheStorage } from "./LocalCacheStorage";
import { NpmCacheStorage } from "./NpmCacheStorage";
export { ICacheStorage } from "./CacheStorage";
export function getCacheStorageProvider(
cacheStorageConfig: CacheStorageConfig,
internalCacheFolder: string
internalCacheFolder: string,
logger: Logger
): ICacheStorage {
let cacheStorage: ICacheStorage;
if (cacheStorageConfig.provider === "npm") {
cacheStorage = new NpmCacheStorage(
cacheStorageConfig.options,
internalCacheFolder
internalCacheFolder,
logger
);
} else if (cacheStorageConfig.provider === "azure-blob") {
cacheStorage = new AzureBlobCacheStorage(cacheStorageConfig.options);
cacheStorage = new AzureBlobCacheStorage(
cacheStorageConfig.options,
logger
);
} else {
cacheStorage = new LocalCacheStorage(internalCacheFolder);
cacheStorage = new LocalCacheStorage(internalCacheFolder, logger);
}
return cacheStorage;

Просмотреть файл

@ -16,7 +16,7 @@
"watch": "tsc -b -w"
},
"dependencies": {
"backfill-generic-logger": "^3.0.0",
"backfill-logger": "^3.0.0",
"find-up": "^4.0.0",
"fs-extra": "^8.1.0",
"pkg-dir": "^4.2.0"

Просмотреть файл

@ -1,6 +1,7 @@
import * as path from "path";
import path from "path";
import { setupFixture } from "backfill-utils-test";
import { makeLogger } from "backfill-logger";
import {
getName,
@ -21,6 +22,7 @@ describe("getName()", () => {
describe("getEnvConfig()", () => {
const originalEnv = process.env;
const logger = makeLogger("mute");
beforeEach(() => {
process.env = { ...originalEnv };
@ -33,21 +35,21 @@ describe("getEnvConfig()", () => {
it("sets log folder through ENV variable", async () => {
process.env["BACKFILL_LOG_FOLDER"] = "foo";
const config = getEnvConfig();
const config = getEnvConfig(logger);
expect(config).toStrictEqual({ logFolder: "foo" });
});
it("sets the performance logging flag through ENV variable", async () => {
process.env["BACKFILL_PRODUCE_PERFORMANCE_LOGS"] = "true";
const config = getEnvConfig();
const config = getEnvConfig(logger);
expect(config).toStrictEqual({ producePerformanceLogs: true });
});
it("sets local cache folder through ENV variable", async () => {
process.env["BACKFILL_INTERNAL_CACHE_FOLDER"] = "bar";
const config = getEnvConfig();
const config = getEnvConfig(logger);
expect(config).toStrictEqual({ internalCacheFolder: "bar" });
});
@ -65,14 +67,14 @@ describe("getEnvConfig()", () => {
cacheStorageConfig.options
);
const config = getEnvConfig();
const config = getEnvConfig(logger);
expect(config).toStrictEqual({ cacheStorageConfig: cacheStorageConfig });
});
it("sets performance report name through ENV variable", async () => {
process.env["BACKFILL_PERFORMANCE_REPORT_NAME"] = "report";
const config = getEnvConfig();
const config = getEnvConfig(logger);
expect(config).toStrictEqual({ performanceReportName: "report" });
});
});
@ -106,6 +108,7 @@ describe("getSearchPaths()", () => {
describe("createConfig()", () => {
const originalEnv = process.env;
const logger = makeLogger("info");
beforeAll(() => {
process.env = { ...originalEnv };
@ -117,7 +120,7 @@ describe("createConfig()", () => {
it("returns default config values when no config file and no ENV override is provided", async () => {
await setupFixture("basic");
const config = createConfig();
const config = createConfig(logger);
const defaultLocalCacheFolder = createDefaultConfig().internalCacheFolder;
expect(config.internalCacheFolder).toStrictEqual(defaultLocalCacheFolder);
@ -125,7 +128,7 @@ describe("createConfig()", () => {
it("returns config file value when config file is provided, and no ENV override", async () => {
await setupFixture("config");
const config = createConfig();
const config = createConfig(logger);
expect(config.internalCacheFolder).toStrictEqual("foo");
});
@ -134,7 +137,7 @@ describe("createConfig()", () => {
process.env["BACKFILL_INTERNAL_CACHE_FOLDER"] = "bar";
await setupFixture("config");
const config = createConfig();
const config = createConfig(logger);
expect(config.internalCacheFolder).toStrictEqual("bar");
});

Просмотреть файл

@ -1,4 +1,4 @@
import { logger } from "backfill-generic-logger";
import { Logger } from "backfill-logger";
export type AzureBlobCacheStorageOptions = {
connectionString: string;
@ -29,7 +29,8 @@ export type CacheStorageConfig =
| AzureBlobCacheStorageConfig;
export function getNpmConfigFromSerializedOptions(
options: string
options: string,
logger: Logger
): NpmCacheStorageConfig {
try {
const parsedOptions = JSON.parse(options);
@ -52,7 +53,8 @@ export function getNpmConfigFromSerializedOptions(
}
export function getAzureBlobConfigFromSerializedOptions(
options: string
options: string,
logger: Logger
): AzureBlobCacheStorageConfig {
try {
const parsedOptions = JSON.parse(options);

Просмотреть файл

@ -1,12 +1,12 @@
import { isCorrectLogLevel, Logger } from "backfill-logger";
import {
getAzureBlobConfigFromSerializedOptions,
getNpmConfigFromSerializedOptions
} from "./cacheConfig";
import { isCorrectLogLevel } from "backfill-generic-logger";
import { isCorrectMode, Config } from "./index";
export function getEnvConfig() {
export function getEnvConfig(logger: Logger) {
const config: Partial<Config> = {};
const cacheProvider = process.env["BACKFILL_CACHE_PROVIDER"];
@ -15,11 +15,13 @@ export function getEnvConfig() {
if (cacheProvider === "azure-blob" && serializedCacheProviderOptions) {
config["cacheStorageConfig"] = getAzureBlobConfigFromSerializedOptions(
serializedCacheProviderOptions
serializedCacheProviderOptions,
logger
);
} else if (cacheProvider === "npm" && serializedCacheProviderOptions) {
config["cacheStorageConfig"] = getNpmConfigFromSerializedOptions(
serializedCacheProviderOptions
serializedCacheProviderOptions,
logger
);
} else if (cacheProvider === "local") {
// local cache has no config at the moment

Просмотреть файл

@ -1,8 +1,8 @@
import * as path from "path";
import * as pkgDir from "pkg-dir";
import * as findUp from "find-up";
import path from "path";
import pkgDir from "pkg-dir";
import findUp from "find-up";
import { LogLevels } from "backfill-generic-logger";
import { LogLevel, Logger } from "backfill-logger";
import { CacheStorageConfig } from "./cacheConfig";
import { getEnvConfig } from "./envConfig";
@ -27,7 +27,7 @@ export type Config = {
hashGlobs: HashGlobs;
internalCacheFolder: string;
logFolder: string;
logLevel: LogLevels;
logLevel: LogLevel;
name: string;
mode: BackfillModes;
outputGlob: string[];
@ -94,7 +94,10 @@ export function createDefaultConfig(fromPath: string = process.cwd()): Config {
};
}
export function createConfig(fromPath: string = process.cwd()): Config {
export function createConfig(
logger: Logger,
fromPath: string = process.cwd()
): Config {
const defaultConfig = createDefaultConfig(fromPath);
const fileBasedConfig = getSearchPaths(fromPath).reduce((acc, configPath) => {
const config = require(configPath);
@ -111,7 +114,7 @@ export function createConfig(fromPath: string = process.cwd()): Config {
};
}, {});
const envBasedConfig = getEnvConfig();
const envBasedConfig = getEnvConfig(logger);
return {
...defaultConfig,

Просмотреть файл

@ -2,5 +2,5 @@
"extends": "backfill-utils-tsconfig/tsconfig.default.json",
"include": ["src"],
"compilerOptions": { "rootDir": "src", "outDir": "lib" },
"references": [{ "path": "../generic-logger" }, { "path": "../utils-test" }]
"references": [{ "path": "../logger" }, { "path": "../utils-test" }]
}

Просмотреть файл

@ -1,5 +0,0 @@
**/*
!lib/*
lib/**/__tests__/*
lib/**/*.d.ts.map
!bin/**/*

Просмотреть файл

@ -1,7 +0,0 @@
# `backfill-generic-logger`
> Backfill Generic Logger
## Usage
This package shouldn't be used directly. It's an internal package to backfill.

Просмотреть файл

@ -1,24 +0,0 @@
{
"name": "backfill-generic-logger",
"description": "Backfill Generic Logger",
"license": "MIT",
"author": "Benjamin Weggersen <bewegger@microsoft.com>",
"repository": {
"type": "git",
"url": "https://github.com/microsoft/backfill"
},
"version": "3.0.0",
"main": "lib/index.js",
"scripts": {
"build": "yarn compile",
"compile": "tsc -b",
"watch": "tsc -b -w"
},
"dependencies": {
"chalk": "^3.0.0"
},
"devDependencies": {
"backfill-utils-tsconfig": "^2.0.3",
"typescript": "3.7.4"
}
}

Просмотреть файл

@ -1,111 +0,0 @@
import chalk = require("chalk");
function logInternal(
method: "info" | "warn" | "error",
symbol: string,
...args: any[]
) {
console[method]("backfill:", symbol, ...args);
}
export const logLevelObject = {
error: "",
warn: "",
info: "",
verbose: "",
silly: ""
};
export type LogLevels = keyof typeof logLevelObject;
export function isCorrectLogLevel(logLevel: string): logLevel is LogLevels {
return logLevelObject.hasOwnProperty(logLevel);
}
let logLevel: LogLevels = "info";
export function setLogLevel(newLogLevel: LogLevels) {
logLevel = newLogLevel;
}
function logLevelNumber(logLevel: LogLevels) {
switch (logLevel) {
case "error":
return 0;
case "warn":
return 1;
case "info":
return 2;
case "verbose":
return 3;
case "silly":
return 4;
}
}
export interface Logger {
silly(...args: any[]): void;
verbose(...args: any[]): void;
info(...args: any[]): void;
warn(...args: any[]): void;
error(...args: any[]): void;
profile(marker: string, ...args: any[]): number | void;
}
const performanceMarkers: { [marker: string]: [number, number] } = {};
export const logger: Logger = {
silly(...args: any[]) {
if (logLevelNumber(logLevel) >= logLevelNumber("silly")) {
logInternal("info", chalk.gray("\u25C7"), ...args);
}
},
verbose(...args: any[]) {
if (logLevelNumber(logLevel) >= logLevelNumber("verbose")) {
logInternal("info", "\u25a1", ...args);
}
},
info(...args: any[]) {
if (logLevelNumber(logLevel) >= logLevelNumber("info")) {
logInternal("info", chalk.blue.bold("\u25a0"), ...args);
}
},
warn(...args: any[]) {
if (logLevelNumber(logLevel) >= logLevelNumber("warn")) {
logInternal("warn", chalk.yellow.bold("\u25B2"), ...args);
}
},
error(...args: any[]) {
logInternal("error", chalk.redBright("x"), ...args);
},
profile(marker: string, ...args: any[]) {
if (!performanceMarkers[marker]) {
performanceMarkers[marker] = process.hrtime();
} else {
const delta = process.hrtime(performanceMarkers[marker]);
delete performanceMarkers[marker];
if (delta) {
const ms = Math.round(delta[0] * 1000 + delta[1] / 1000000);
if (logLevelNumber(logLevel) >= logLevelNumber("verbose")) {
logInternal(
"info",
chalk.cyan("\u2023"),
`Profiling ${chalk.underline(marker)} took ${chalk.cyanBright(
`${ms}ms`
)}`,
...args
);
}
return ms;
}
}
}
};

Просмотреть файл

@ -1,6 +0,0 @@
{
"extends": "backfill-utils-tsconfig/tsconfig.default.json",
"include": ["src"],
"compilerOptions": { "rootDir": "src", "outDir": "lib" },
"references": []
}

Просмотреть файл

@ -1,6 +1,7 @@
import * as path from "path";
import path from "path";
import normalize from "normalize-path";
import { setupFixture } from "backfill-utils-test";
import normalize = require("normalize-path");
import { getYarnWorkspaces } from "../yarnWorkspaces";

Просмотреть файл

@ -1,13 +1,16 @@
import * as fs from "fs-extra";
import fs from "fs-extra";
import { setupFixture } from "backfill-utils-test";
import { makeLogger } from "backfill-logger";
import { createConfig, Config } from "backfill-config";
import { generateHashOfFiles } from "../hashOfFiles";
import { createConfig, Config } from "backfill-config";
const { createDefaultConfig } = jest.requireActual("backfill-config");
jest.mock("backfill-config");
const mockedDependency = <jest.Mock<Config>>createConfig;
const logger = makeLogger("mute");
describe("generateHashOfFiles()", () => {
it("excludes files provided by backfill config", async () => {
@ -16,13 +19,16 @@ describe("generateHashOfFiles()", () => {
// Need to mock getting the config
mockedDependency.mockReturnValue({ ...defaultConfig, hashGlobs: ["**"] });
const hashOfEverything = await generateHashOfFiles(packageRoot);
const hashOfEverything = await generateHashOfFiles(packageRoot, logger);
mockedDependency.mockReturnValue({
...defaultConfig,
hashGlobs: ["**", "!**/node_modules/**"]
});
const hashExcludeNodeModules = await generateHashOfFiles(packageRoot);
const hashExcludeNodeModules = await generateHashOfFiles(
packageRoot,
logger
);
expect(hashOfEverything).not.toEqual(hashExcludeNodeModules);
});
@ -33,19 +39,25 @@ describe("generateHashOfFiles()", () => {
mockedDependency.mockReturnValue(defaultConfig);
const hashOfPackage = await generateHashOfFiles(packageRoot);
const hashOfPackage = await generateHashOfFiles(packageRoot, logger);
fs.writeFileSync("foo.txt", "bar");
const hashOfPackageWithFoo = await generateHashOfFiles(packageRoot);
const hashOfPackageWithFoo = await generateHashOfFiles(packageRoot, logger);
expect(hashOfPackage).not.toEqual(hashOfPackageWithFoo);
fs.writeFileSync("foo.txt", "foo");
const hashOfPackageWithFoo2 = await generateHashOfFiles(packageRoot);
const hashOfPackageWithFoo2 = await generateHashOfFiles(
packageRoot,
logger
);
expect(hashOfPackageWithFoo).not.toEqual(hashOfPackageWithFoo2);
fs.unlinkSync("foo.txt");
const hashOfPackageWithoutFoo = await generateHashOfFiles(packageRoot);
const hashOfPackageWithoutFoo = await generateHashOfFiles(
packageRoot,
logger
);
expect(hashOfPackage).toEqual(hashOfPackageWithoutFoo);
});
});

Просмотреть файл

@ -1,10 +1,14 @@
import * as path from "path";
import path from "path";
import { setupFixture } from "backfill-utils-test";
import { makeLogger } from "backfill-logger";
import { PackageHashInfo } from "../hashOfPackage";
import { Hasher, addToQueue } from "../index";
import { WorkspaceInfo } from "../yarnWorkspaces";
const logger = makeLogger("mute");
describe("addToQueue", () => {
const setupAddToQueue = async () => {
const packageRoot = await setupFixture("monorepo");
@ -97,7 +101,7 @@ describe("The main Hasher class", () => {
const options = { packageRoot, outputGlob: ["lib/**"] };
const buildSignature = "yarn build";
const hasher = new Hasher(options, buildSignature);
const hasher = new Hasher(options, buildSignature, logger);
const hash = await hasher.createPackageHash();
return hash;

Просмотреть файл

@ -1,4 +1,5 @@
import { setupFixture } from "backfill-utils-test";
import { getYarnWorkspaces } from "../yarnWorkspaces";
export async function filterDependenciesInFixture(

Просмотреть файл

@ -1,8 +1,11 @@
import * as crypto from "crypto";
import * as fg from "fast-glob";
import * as fs from "fs-extra";
import * as path from "path";
import crypto from "crypto";
import fg from "fast-glob";
import fs from "fs-extra";
import path from "path";
import { createConfig } from "backfill-config";
import { Logger } from "backfill-logger";
import { hashStrings } from "./helpers";
const newline = /\r\n|\r|\n/g;
@ -10,10 +13,11 @@ const LF = "\n";
export async function generateHashOfFiles(
packageRoot: string,
logger: Logger,
glob?: string[]
): Promise<string> {
if (!glob) {
glob = createConfig(packageRoot).hashGlobs;
glob = createConfig(logger, packageRoot).hashGlobs;
}
const files = await fg(glob, {

Просмотреть файл

@ -1,6 +1,7 @@
import * as crypto from "crypto";
import * as path from "path";
import { logger } from "backfill-logger";
import crypto from "crypto";
import path from "path";
import { Logger } from "backfill-logger";
import { resolveInternalDependencies } from "./resolveInternalDependencies";
import { resolveExternalDependencies } from "./resolveExternalDependencies";
@ -35,7 +36,8 @@ export function generateHashOfInternalPackages(
export async function getPackageHash(
packageRoot: string,
workspaces: WorkspaceInfo,
yarnLock: ParsedYarnLock
yarnLock: ParsedYarnLock,
logger: Logger
): Promise<PackageHashInfo> {
const { name, dependencies, devDependencies } = require(path.join(
packageRoot,
@ -63,7 +65,7 @@ export async function getPackageHash(
...externalDeoendencies
];
const filesHash = await generateHashOfFiles(packageRoot);
const filesHash = await generateHashOfFiles(packageRoot, logger);
const dependenciesHash = hashStrings(resolvedDependencies);
logger.silly(name);

Просмотреть файл

@ -1,6 +1,6 @@
import * as path from "path";
import * as crypto from "crypto";
import * as findUp from "find-up";
import path from "path";
import crypto from "crypto";
import findUp from "find-up";
export function hashStrings(strings: string | string[]): string {
const hasher = crypto.createHash("sha1");

Просмотреть файл

@ -1,4 +1,4 @@
import { logger } from "backfill-logger";
import { Logger } from "backfill-logger";
import { generateHashOfFiles } from "./hashOfFiles";
import {
@ -50,14 +50,15 @@ export class Hasher implements IHasher {
constructor(
private options: { packageRoot: string; outputGlob: string[] },
private buildCommandSignature: string
private buildCommandSignature: string,
private logger: Logger
) {
this.packageRoot = this.options.packageRoot;
this.outputGlob = this.options.outputGlob;
}
public async createPackageHash(): Promise<string> {
logger.profile("hasher:calculateHash");
const tracer = this.logger.setTime("hashTime");
const packageRoot = await getPackageRoot(this.packageRoot);
const yarnLock = await parseLockFile(packageRoot);
@ -76,7 +77,8 @@ export class Hasher implements IHasher {
const packageHash = await getPackageHash(
packageRoot,
workspaces,
yarnLock
yarnLock,
this.logger
);
addToQueue(packageHash.internalDependencies, queue, done, workspaces);
@ -85,23 +87,20 @@ export class Hasher implements IHasher {
}
const internalPackagesHash = generateHashOfInternalPackages(done);
const buildCommandHash = await hashStrings(this.buildCommandSignature);
const combinedHash = await hashStrings([
internalPackagesHash,
buildCommandHash
]);
const buildCommandHash = hashStrings(this.buildCommandSignature);
const combinedHash = hashStrings([internalPackagesHash, buildCommandHash]);
logger.verbose(`Hash of internal packages: ${internalPackagesHash}`);
logger.verbose(`Hash of build command: ${buildCommandHash}`);
logger.verbose(`Combined hash: ${combinedHash}`);
this.logger.verbose(`Hash of internal packages: ${internalPackagesHash}`);
this.logger.verbose(`Hash of build command: ${buildCommandHash}`);
this.logger.verbose(`Combined hash: ${combinedHash}`);
logger.profile("hasher:calculateHash");
logger.setHash(combinedHash);
tracer.stop();
this.logger.setHash(combinedHash);
return combinedHash;
}
public async hashOfOutput(): Promise<string> {
return generateHashOfFiles(this.packageRoot, this.outputGlob);
return generateHashOfFiles(this.packageRoot, this.logger, this.outputGlob);
}
}

Просмотреть файл

@ -1,6 +1,6 @@
import * as findUp from "find-up";
import * as fs from "fs-extra";
import * as lockfile from "@yarnpkg/lockfile";
import findUp from "find-up";
import fs from "fs-extra";
import { parse } from "@yarnpkg/lockfile";
import { Dependencies } from "./resolveExternalDependencies";
import { nameAtVersion } from "./helpers";
@ -29,7 +29,7 @@ export async function parseLockFile(
}
const yarnLock = fs.readFileSync(yarnLockPath).toString();
return lockfile.parse(yarnLock);
return parse(yarnLock);
}
export function queryLockFile(

Просмотреть файл

@ -1,7 +1,6 @@
import * as path from "path";
import * as fg from "fast-glob";
import * as findWorkspaceRoot from "find-yarn-workspace-root";
import path from "path";
import fg from "fast-glob";
import findWorkspaceRoot from "find-yarn-workspace-root";
type PackageJsonWorkspaces = {
workspaces?:

Просмотреть файл

@ -1,6 +1,6 @@
# `backfill-logger`
> Backfill Logger
> Backfill logger
## Usage

Просмотреть файл

@ -1,8 +1,8 @@
{
"name": "backfill-logger",
"description": "Backfill Logger",
"description": "Handle backfill output",
"license": "MIT",
"author": "Benjamin Weggersen <bewegger@microsoft.com>",
"author": "Vincent Bailly <vibailly@microsoft.com>",
"repository": {
"type": "git",
"url": "https://github.com/microsoft/backfill"
@ -15,10 +15,12 @@
"watch": "tsc -b -w"
},
"dependencies": {
"backfill-generic-logger": "^3.0.0",
"backfill-performance-logger": "^3.0.0"
"chalk": "^3.0.0",
"filenamify": "^4.1.0",
"fs-extra": "^8.1.0"
},
"devDependencies": {
"@types/node": "^12.0.0",
"backfill-utils-tsconfig": "^2.0.3",
"typescript": "3.7.4"
}

Просмотреть файл

@ -0,0 +1,11 @@
export type Console = {
info(...args: string[]): void;
warn(...args: string[]): void;
error(...args: string[]): void;
};
export const defaultConsole = {
info: console.info,
warn: console.warn,
error: console.error
};

Просмотреть файл

@ -0,0 +1,67 @@
import { LogLevel } from ".";
import { Console, defaultConsole } from "./console";
import { defaultFormatter } from "./outputFormatter";
import { defaultLogFilter } from "./outputFilter";
export type LoggerOverrides = {
console?: Console;
};
export type ConsoleLogger = {
silly(...args: string[]): void;
verbose(...args: string[]): void;
info(...args: string[]): void;
warn(...args: string[]): void;
error(...args: string[]): void;
};
export function makeConsoleLogger(
logLevel: LogLevel,
overrides?: LoggerOverrides
): ConsoleLogger & {
trace(...args: string[]): void;
consoleOverride: Console;
} {
let consoleOverride = (overrides && overrides.console) || defaultConsole;
let formatter = defaultFormatter;
let logFilter = defaultLogFilter(logLevel);
return {
consoleOverride,
silly(...args: string[]): void {
if (logFilter.shouldLog("silly")) {
consoleOverride.info(...formatter.format("silly", ...args));
}
},
verbose(...args: string[]): void {
if (logFilter.shouldLog("verbose")) {
consoleOverride.info(...formatter.format("verbose", ...args));
}
},
info(...args: string[]): void {
if (logFilter.shouldLog("info")) {
consoleOverride.info(...formatter.format("info", ...args));
}
},
warn(...args: string[]): void {
if (logFilter.shouldLog("warn")) {
consoleOverride.warn(...formatter.format("warn", ...args));
}
},
error(...args: string[]): void {
if (logFilter.shouldLog("error")) {
consoleOverride.error(...formatter.format("error", ...args));
}
},
trace(...args: string[]): void {
if (logFilter.shouldLog("verbose")) {
consoleOverride.error(...formatter.format("trace", ...args));
}
}
};
}

Просмотреть файл

@ -1,13 +1,2 @@
import { logger as genericLogger } from "backfill-generic-logger";
import { performanceLogger } from "backfill-performance-logger";
export {
LogLevels,
setLogLevel,
isCorrectLogLevel
} from "backfill-generic-logger";
export const logger = {
...genericLogger,
...performanceLogger
};
export { isCorrectLogLevel, LogLevel } from "./logLevel";
export { Logger, makeLogger } from "./logger";

Просмотреть файл

@ -0,0 +1,14 @@
export const logLevelsObject = {
silly: 4,
verbose: 3,
info: 2,
warn: 1,
error: 0,
mute: -1
};
export type LogLevel = keyof typeof logLevelsObject;
export function isCorrectLogLevel(level: string): level is LogLevel {
return Object.keys(logLevelsObject).includes(level);
}

Просмотреть файл

@ -0,0 +1,133 @@
import fs from "fs-extra";
import path from "path";
import filenamify from "filenamify";
import { Readable } from "stream";
import chalk from "chalk";
import { LogLevel } from "./logLevel";
import { defaultTimer, Timer } from "./timer";
import {
ConsoleLogger,
LoggerOverrides,
makeConsoleLogger
} from "./consoleLogger";
export { isCorrectLogLevel, LogLevel } from "./logLevel";
type PerformanceReportData = {
timestamp: number;
name?: string;
hash?: string;
cacheProvider?: string;
hit?: boolean;
buildTime?: number;
putTime?: number;
hashTime?: number;
fetchTime?: number;
mode?: string;
hashOfOutput?: string;
};
type Times = "hashTime" | "buildTime" | "putTime" | "fetchTime";
function createFileName(performanceReportData: PerformanceReportData) {
return filenamify(
`perf-${performanceReportData.name}-${performanceReportData.timestamp}.json`
);
}
export type Logger = ConsoleLogger & {
setName(name: string): void;
setHash(hash: string): void;
setCacheProvider(cacheProvider: string): void;
setHit(hit: boolean): void;
setTime(type: Times): { stop(): void };
setMode(mode: string, logLevel: "verbose" | "info"): void;
setHashOfOutput(hash: string): void;
toFile(logFolder: string): Promise<void>;
pipeProcessOutput(stdout: Readable | null, stderr: Readable | null): void;
};
export function makeLogger(
logLevel: LogLevel,
overrides?: LoggerOverrides
): Logger {
const consoleLogger = makeConsoleLogger(logLevel, overrides);
const timer: Timer = defaultTimer;
const performanceReportData: PerformanceReportData = {
timestamp: Date.now()
};
return {
pipeProcessOutput(stdout: Readable | null, stderr: Readable | null): void {
stdout &&
stdout.on("data", chunk =>
consoleLogger.consoleOverride.info(chunk.toString())
);
stderr &&
stderr.on("data", chunk =>
consoleLogger.consoleOverride.error(chunk.toString())
);
},
silly: consoleLogger.silly,
verbose: consoleLogger.verbose,
info: consoleLogger.info,
warn: consoleLogger.warn,
error: consoleLogger.error,
setName(name: string) {
consoleLogger.info(`Package name: ${name}`);
performanceReportData["name"] = name;
},
setHash(hash: string) {
consoleLogger.verbose(`Package hash: ${hash}`);
performanceReportData["hash"] = hash;
},
setCacheProvider(cacheProvider: string) {
consoleLogger.verbose(`Cache provider: ${cacheProvider}`);
performanceReportData["cacheProvider"] = cacheProvider;
},
setHit(hit: boolean) {
consoleLogger.info(hit ? `Cache hit!` : `Cache miss!`);
performanceReportData["hit"] = hit;
},
setTime(type: Times): { stop(): void } {
const tracer = timer.start();
return {
stop: () => {
const time = tracer.stop();
consoleLogger.trace(
`Profiling ${chalk.underline(type)} took ${chalk.cyanBright(
`${time} ms`
)}`
);
performanceReportData[type] = time;
}
};
},
setMode(mode: string, logLevel: "verbose" | "info") {
consoleLogger[logLevel](`Running in ${mode} mode.`);
performanceReportData["mode"] = mode;
},
setHashOfOutput(hash: string) {
consoleLogger.verbose(`Hash of output: ${hash}`);
performanceReportData["hashOfOutput"] = hash;
},
async toFile(logFolder: string) {
const filepath = path.join(
logFolder,
createFileName(performanceReportData)
);
await fs.outputJson(filepath, performanceReportData, { spaces: 2 });
consoleLogger.silly(`Performance log created at ${filepath}`);
}
};
}

Просмотреть файл

@ -0,0 +1,19 @@
import { LogLevel, logLevelsObject } from "./logLevel";
export type LogFilter = {
shouldLog(logLevel: LogLevel): boolean;
};
export const defaultLogFilter: (logLevel: LogLevel) => LogFilter = (
logLevel: LogLevel
) => {
return {
shouldLog(level: LogLevel): boolean {
if (level === "mute") {
return false;
}
return logLevelsObject[level] <= logLevelsObject[logLevel];
}
};
};

Просмотреть файл

@ -0,0 +1,35 @@
import chalk from "chalk";
import { LogLevel } from ".";
export type OutputFormatter = {
format(logLevel: LogLevel, ...args: string[]): string[];
};
export const defaultFormatter = {
format(logLevel: LogLevel | "trace", ...args: string[]): string[] {
switch (logLevel) {
case "silly":
return ["backfill:", chalk.gray("\u25C7"), ...args];
case "verbose":
return ["backfill:", "\u25a1", ...args];
case "info":
return ["backfill:", chalk.blue("\u25a0"), ...args];
case "warn":
return ["backfill:", chalk.yellow("\u25B2"), ...args];
case "error":
return ["backfill:", chalk.redBright("x"), ...args];
case "trace":
return ["backfill:", chalk.cyan("\u2023"), ...args];
case "mute":
return [];
default:
return assertNever(logLevel);
}
}
};
function assertNever(x: never): never {
throw new Error("Unexpected object: " + x);
}

Просмотреть файл

@ -0,0 +1,14 @@
export type Timer = { start(): { stop(): number } };
export const defaultTimer = {
start() {
const start = process.hrtime();
return {
stop() {
const delta = process.hrtime(start);
const time = Math.round(delta[0] * 1000 + delta[1] / 1000000);
return time;
}
};
}
};

Просмотреть файл

@ -1,9 +1,10 @@
{
"extends": "backfill-utils-tsconfig/tsconfig.default.json",
"include": ["src"],
"compilerOptions": { "rootDir": "src", "outDir": "lib" },
"references": [
{ "path": "../generic-logger" },
{ "path": "../performance-logger" }
]
"compilerOptions": {
"esModuleInterop": true,
"rootDir": "src",
"outDir": "lib"
},
"references": []
}

Просмотреть файл

@ -1,5 +0,0 @@
**/*
!lib/*
lib/**/__tests__/*
lib/**/*.d.ts.map
!bin/**/*

Просмотреть файл

@ -1,7 +0,0 @@
# `backfill-performance-logger`
> Backfill Performance Logger
## Usage
This package shouldn't be used directly. It's an internal package to backfill.

Просмотреть файл

@ -1,5 +0,0 @@
**/*
!lib/*
lib/**/__tests__/*
lib/**/*.d.ts.map
!bin/**/*

Просмотреть файл

@ -1,7 +0,0 @@
# `backfill-performance-logger`
> Backfill Performance Logger
## Usage
This package shouldn't be used directly. It's an internal package to backfill.

Просмотреть файл

@ -1,28 +0,0 @@
{
"name": "backfill-performance-logger",
"description": "Backfill Performance Logger",
"license": "MIT",
"author": "Benjamin Weggersen <bewegger@microsoft.com>",
"repository": {
"type": "git",
"url": "https://github.com/microsoft/backfill"
},
"version": "3.0.0",
"main": "lib/index.js",
"scripts": {
"build": "yarn compile",
"compile": "tsc -b",
"watch": "tsc -b -w"
},
"dependencies": {
"backfill-generic-logger": "^3.0.0",
"filenamify": "^4.1.0",
"fs-extra": "^8.1.0"
},
"devDependencies": {
"@types/fs-extra": "^8.0.0",
"backfill-config": "^3.0.0",
"backfill-utils-tsconfig": "^2.0.3",
"typescript": "3.7.4"
}
}

Просмотреть файл

@ -1,83 +0,0 @@
import * as fs from "fs-extra";
import * as path from "path";
import * as filenamify from "filenamify";
import { logger } from "backfill-generic-logger";
import { BackfillModes } from "backfill-config";
type PerformanceReportData = {
timestamp: number;
name?: string;
hash?: string;
cacheProvider?: string;
hit?: boolean;
buildTime?: number;
putTime?: number;
fetchTime?: number;
mode?: BackfillModes;
hashOfOutput?: string;
};
type Times = "buildTime" | "putTime" | "fetchTime";
const performanceReportData: PerformanceReportData = {
timestamp: Date.now()
};
function createFileName() {
return filenamify(
`perf-${performanceReportData.name}-${performanceReportData.timestamp}.json`
);
}
export const performanceLogger = {
setName(name: string) {
logger.info(`Package name: ${name}`);
performanceReportData["name"] = name;
},
setHash(hash: string) {
logger.verbose(`Package hash: ${hash}`);
performanceReportData["hash"] = hash;
},
setCacheProvider(cacheProvider: string) {
logger.verbose(`Cache provider: ${cacheProvider}`);
performanceReportData["cacheProvider"] = cacheProvider;
},
setHit(hit: boolean) {
logger.info(hit ? `Cache hit!` : `Cache miss!`);
performanceReportData["hit"] = hit;
},
setTime(type: Times, marker: string) {
const ms = logger.profile(marker);
if (ms) {
performanceReportData[type] = ms;
}
},
setMode(mode: BackfillModes) {
if (mode !== "READ_WRITE") {
logger.info(`Running in ${mode} mode.`);
} else {
logger.verbose(`Running in ${mode} mode.`);
}
performanceReportData["mode"] = mode;
},
setHashOfOutput(hash: string) {
logger.verbose(`Hash of output: ${hash}`);
performanceReportData["hashOfOutput"] = hash;
},
async toFile(logFolder: string) {
const filepath = path.join(logFolder, createFileName());
await fs.outputJson(filepath, performanceReportData, { spaces: 2 });
logger.silly(`Performance log created at ${filepath}`);
}
};

Просмотреть файл

@ -1,6 +0,0 @@
{
"extends": "backfill-utils-tsconfig/tsconfig.default.json",
"include": ["src"],
"compilerOptions": { "rootDir": "src", "outDir": "lib" },
"references": [{ "path": "../config" }, { "path": "../generic-logger" }]
}

Просмотреть файл

@ -1,28 +0,0 @@
{
"name": "backfill-performance-logger",
"description": "Backfill Performance Logger",
"license": "MIT",
"author": "Benjamin Weggersen <bewegger@microsoft.com>",
"repository": {
"type": "git",
"url": "https://github.com/microsoft/backfill"
},
"version": "3.0.0",
"main": "lib/index.js",
"scripts": {
"build": "yarn compile",
"compile": "tsc -b",
"watch": "tsc -b -w"
},
"dependencies": {
"backfill-generic-logger": "^3.0.0",
"filenamify": "^4.1.0",
"fs-extra": "^8.1.0"
},
"devDependencies": {
"@types/fs-extra": "^8.0.0",
"backfill-config": "^3.0.0",
"backfill-utils-tsconfig": "^2.0.3",
"typescript": "3.7.4"
}
}

Просмотреть файл

@ -1,83 +0,0 @@
import * as fs from "fs-extra";
import * as path from "path";
import * as filenamify from "filenamify";
import { logger } from "backfill-generic-logger";
import { BackfillModes } from "backfill-config";
type PerformanceReportData = {
timestamp: number;
name?: string;
hash?: string;
cacheProvider?: string;
hit?: boolean;
buildTime?: number;
putTime?: number;
fetchTime?: number;
mode?: BackfillModes;
hashOfOutput?: string;
};
type Times = "buildTime" | "putTime" | "fetchTime";
const performanceReportData: PerformanceReportData = {
timestamp: Date.now()
};
function createFileName() {
return filenamify(
`perf-${performanceReportData.name}-${performanceReportData.timestamp}.json`
);
}
export const performanceLogger = {
setName(name: string) {
logger.info(`Package name: ${name}`);
performanceReportData["name"] = name;
},
setHash(hash: string) {
logger.verbose(`Package hash: ${hash}`);
performanceReportData["hash"] = hash;
},
setCacheProvider(cacheProvider: string) {
logger.verbose(`Cache provider: ${cacheProvider}`);
performanceReportData["cacheProvider"] = cacheProvider;
},
setHit(hit: boolean) {
logger.info(hit ? `Cache hit!` : `Cache miss!`);
performanceReportData["hit"] = hit;
},
setTime(type: Times, marker: string) {
const ms = logger.profile(marker);
if (ms) {
performanceReportData[type] = ms;
}
},
setMode(mode: BackfillModes) {
if (mode !== "READ_WRITE") {
logger.info(`Running in ${mode} mode.`);
} else {
logger.verbose(`Running in ${mode} mode.`);
}
performanceReportData["mode"] = mode;
},
setHashOfOutput(hash: string) {
logger.verbose(`Hash of output: ${hash}`);
performanceReportData["hashOfOutput"] = hash;
},
async toFile(logFolder: string) {
const filepath = path.join(logFolder, createFileName());
await fs.outputJson(filepath, performanceReportData, { spaces: 2 });
logger.silly(`Performance log created at ${filepath}`);
}
};

Просмотреть файл

@ -1,6 +0,0 @@
{
"extends": "backfill-utils-tsconfig/tsconfig.default.json",
"include": ["src"],
"compilerOptions": { "rootDir": "src", "outDir": "lib" },
"references": [{ "path": "../config" }, { "path": "../generic-logger" }]
}

Просмотреть файл

@ -1,5 +1,5 @@
import { config } from "dotenv";
import * as findUp from "find-up";
import findUp from "find-up";
export function loadDotenv() {
if (process.env.NODE_ENV === "test") {

Просмотреть файл

@ -15,7 +15,6 @@
"watch": "tsc -b -w"
},
"dependencies": {
"backfill-generic-logger": "^3.0.0",
"find-up": "^4.0.0",
"fs-extra": "^8.1.0",
"tempy": "^0.3.0"

Просмотреть файл

@ -1,7 +1,7 @@
import * as findUp from "find-up";
import * as fs from "fs-extra";
import * as path from "path";
import * as tempy from "tempy";
import findUp from "find-up";
import fs from "fs-extra";
import path from "path";
import tempy from "tempy";
async function findFixturePath(cwd: string, fixtureName: string) {
return await findUp(path.join("__fixtures__", fixtureName), {

Просмотреть файл

@ -1,6 +1,2 @@
import { setLogLevel } from "backfill-generic-logger";
// Set timeout to 30 seconds
jest.setTimeout(30 * 1000);
setLogLevel("error");

Просмотреть файл

@ -2,5 +2,5 @@
"extends": "backfill-utils-tsconfig/tsconfig.default.json",
"exclude": ["__fixtures__", "lib"],
"compilerOptions": { "rootDir": "src", "outDir": "lib" },
"references": [{ "path": "../generic-logger" }]
"references": []
}

Просмотреть файл

@ -7,6 +7,7 @@
"inlineSources": false,
"jsx": "react",
"module": "commonjs",
"esModuleInterop": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"outDir": "lib",

Просмотреть файл

@ -1377,6 +1377,11 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.7.0.tgz#b417deda18cf8400f278733499ad5547ed1abec4"
integrity sha512-GnZbirvmqZUzMgkFn70c74OQpTTUcCzlhQliTzYjQMqg+hVKcDnxdL19Ne3UdYzdMA/+W3eb646FWn/ZaT1NfQ==
"@types/node@^12.0.0":
version "12.12.34"
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.34.tgz#0a5d6ae5d22612f0cf5f10320e1fc5d2a745dcb8"
integrity sha512-BneGN0J9ke24lBRn44hVHNeDlrXRYF+VRp0HbSUNnEZahXGAysHZIqnf/hER6aabdBgzM4YOV4jrR8gj4Zfi0g==
"@types/normalize-path@^3.0.0":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@types/normalize-path/-/normalize-path-3.0.0.tgz#bb5c46cab77b93350b4cf8d7ff1153f47189ae31"