зеркало из https://github.com/microsoft/backfill.git
refactor logger (#215)
* 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:
Родитель
108539c0b2
Коммит
a6d8537648
|
@ -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);
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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"
|
||||
|
|
Загрузка…
Ссылка в новой задаче