diff --git a/packages/cli/src/managers/shell.manager.ts b/packages/cli/src/managers/shell.manager.ts index 085a961be..ea833d05d 100644 --- a/packages/cli/src/managers/shell.manager.ts +++ b/packages/cli/src/managers/shell.manager.ts @@ -2,10 +2,13 @@ import {exec, spawn} from "child_process"; import {ConsoleManager} from "./console.manager"; import {injectable} from "tsyringe"; import {PathManager} from "./path.manager"; +import {DateUtil} from "@pristine-ts/common" @injectable() export class ShellManager { - constructor(private readonly consoleManager: ConsoleManager, private readonly pathManager: PathManager) { + constructor(private readonly consoleManager: ConsoleManager, + private readonly pathManager: PathManager, + private readonly dateUtil: DateUtil) { } execute(command: string, options?: { @@ -14,6 +17,8 @@ export class ShellManager { maxBuffer?: number, outputStdout?: boolean, outputStderr?: boolean, + outputDuration?: boolean, + outputTimeBeforeExecutingCommand?: boolean, }): Promise { return new Promise((resolve, reject) => { const env = process.env; @@ -24,13 +29,22 @@ export class ShellManager { const outputStdout = options?.outputStdout ?? true; const outputStderr = options?.outputStderr ?? true; + const outputDuration = options?.outputDuration ?? true; + const outputTimeBeforeExecutingCommand = options?.outputTimeBeforeExecutingCommand ?? true; if(directory) { const absoluteDirectory = this.pathManager.getPathRelativeToCurrentExecutionDirectory(directory); finalCommand = "cd " + absoluteDirectory + " && " + command; } - outputStdout && this.consoleManager.writeLine(finalCommand); + const start = new Date(); + + if(outputTimeBeforeExecutingCommand) { + this.consoleManager.writeLine(start.toISOString() + ": " + finalCommand); + } else { + outputStdout && this.consoleManager.writeLine(finalCommand); + } + if(streamStdout) { const child = spawn(finalCommand, [], { shell: true, env }); @@ -49,6 +63,13 @@ export class ShellManager { return reject(code); } + // Output the duration in human readable format + if(outputDuration) { + const end = new Date(); + const duration = end.getTime() - start.getTime(); + this.consoleManager.writeLine(`Executed in: ${this.dateUtil.formatDuration(duration)}`); + } + return resolve(code + ""); }); } @@ -64,9 +85,16 @@ export class ShellManager { return resolve(stderr); } + // Output the duration in human readable format + if(outputDuration) { + const end = new Date(); + const duration = end.getTime() - start.getTime(); + this.consoleManager.writeLine(`Executed in: ${this.dateUtil.formatDuration(duration)}`); + } + outputStdout && this.consoleManager.writeLine(stdout); return resolve(stdout); }) }) } -} \ No newline at end of file +} diff --git a/packages/common/src/utils/date.util.spec.ts b/packages/common/src/utils/date.util.spec.ts new file mode 100644 index 000000000..88ada3b71 --- /dev/null +++ b/packages/common/src/utils/date.util.spec.ts @@ -0,0 +1,54 @@ +import {DateUtil} from "./date.util"; + +describe("DateUtil", () => { + let dateUtil: DateUtil; + + beforeEach(() => { + dateUtil = new DateUtil(); + }); + + it('should format duration correctly for milliseconds', () => { + const result = dateUtil.formatDuration(500); + expect(result).toBe("500 ms"); + }); + + it('should format duration correctly for seconds', () => { + const result = dateUtil.formatDuration(1000); + expect(result).toBe("1 second and 0 ms"); + }); + + it('should format duration correctly for minutes', () => { + const result = dateUtil.formatDuration(60000); + expect(result).toBe("1 minute, 0 second and 0 ms"); + }); + + it('should format duration correctly for hours', () => { + const result = dateUtil.formatDuration(3600000); + expect(result).toBe("1 hour, 0 minute, 0 second and 0 ms"); + }); + + it('should format duration correctly for days', () => { + const result = dateUtil.formatDuration(86400000); + expect(result).toBe("1 day, 0 hour, 0 minute, 0 second and 0 ms"); + }); + + it('should format duration correctly for years', () => { + const result = dateUtil.formatDuration(31536000000); + expect(result).toBe("1 year, 0 day, 0 hour, 0 minute, 0 second and 0 ms"); + }); + + it('should format duration correctly for multiple time units', () => { + const result = dateUtil.formatDuration(90061000); + expect(result).toBe("1 day, 1 hour, 1 minute, 1 second and 0 ms"); + }); + + it('should handle zero duration', () => { + const result = dateUtil.formatDuration(0); + expect(result).toBe("0 ms"); + }); + + it('should handle negative duration', () => { + const result = dateUtil.formatDuration(-1000); + expect(result).toBe("0 ms"); + }); +}); \ No newline at end of file diff --git a/packages/common/src/utils/date.util.ts b/packages/common/src/utils/date.util.ts new file mode 100644 index 000000000..fe2f7ab4b --- /dev/null +++ b/packages/common/src/utils/date.util.ts @@ -0,0 +1,28 @@ +import "reflect-metadata" +import {injectable} from "tsyringe" + +@injectable() +export class DateUtil { + formatDuration(milliseconds: number) { + const parts = []; + const units = [ + { name: "year", duration: 31536000000 }, // 1000ms*60s*60m*24h*365d + { name: "day", duration: 86400000 }, // 1000*60*60*24 + { name: "hour", duration: 3600000 }, // 1000*60*60 + { name: "minute", duration: 60000 }, // 1000*60 + { name: "second", duration: 1000 }, // 1000 + { name: "ms", duration: 1 }, // 1 + ] + + for(let i = 0; i < units.length; i++) { + const unit = units[i]; + const value = Math.floor(milliseconds / unit.duration); + if(value > 0 || (parts.length > 0 && value === 0)) { + parts.push(`${value} ${unit.name}${value > 1 && unit.name !== "ms" ? 's' : ''}`); + milliseconds -= value * unit.duration; + } + } + + return parts.join(", ").replace(/, ([a-zA-Z0-9 ]*)$/, " and $1") || '0 ms'; + } +} \ No newline at end of file diff --git a/packages/common/src/utils/utils.ts b/packages/common/src/utils/utils.ts index 145500e59..8b73a190b 100644 --- a/packages/common/src/utils/utils.ts +++ b/packages/common/src/utils/utils.ts @@ -1,2 +1,3 @@ +export * from "./date.util"; export * from "./metadata.util"; export * from "./request.util"; \ No newline at end of file