Skip to content

Commit

Permalink
Merge pull request #687 from magieno/add-essential-classes-to-cli
Browse files Browse the repository at this point in the history
- Adds pathManager and shellManager.
  • Loading branch information
etiennenoel authored Apr 12, 2024
2 parents 43273e8 + 4c61101 commit aa62f74
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 2 deletions.
3 changes: 2 additions & 1 deletion packages/cli/src/errors/errors.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from "./command-not-found.error";
export * from "./command-not-found.error";
export * from "./path-already-contains-filename.error";
10 changes: 10 additions & 0 deletions packages/cli/src/errors/path-already-contains-filename.error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export class PathAlreadyContainsFilenameError extends Error {
public constructor(message: string) {
super(message);

// Set the prototype explicitly.
// As specified in the documentation in TypeScript
// https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work
Object.setPrototypeOf(this, PathAlreadyContainsFilenameError.prototype);
}
}
4 changes: 3 additions & 1 deletion packages/cli/src/managers/managers.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export * from "./console.manager";
export * from "./console.manager";
export * from "./path.manager";
export * from "./path.manager";
48 changes: 48 additions & 0 deletions packages/cli/src/managers/path.manager.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import "reflect-metadata"
import {PathManager} from "./path.manager";
import {PathAlreadyContainsFilenameError} from "../errors/path-already-contains-filename.error";

describe("Path Manager", () => {
it("should properly append a path that begins with a '/'.", () => {
const pathManager = new PathManager();

const path = pathManager.getPathRelativeToCurrentExecutionDirectory("/allo");

const pathParts = path.split("/").reverse();

expect(pathParts[0]).toBe("allo")
expect(pathParts[1]).toBe("cli")
expect(pathParts[2]).toBe("packages")
})

it("should properly append a path that ends with a '/'.", () => {
const pathManager = new PathManager();

const path = pathManager.getPathRelativeToCurrentExecutionDirectory("/allo/");

const pathParts = path.split("/").reverse();

expect(pathParts[0]).toBe("allo")
expect(pathParts[1]).toBe("cli")
expect(pathParts[2]).toBe("packages")
})

it("should throw an error when passing two filenames", () => {
const pathManager = new PathManager();

expect(() => pathManager.getPathRelativeToCurrentExecutionDirectory("/allo/test.txt", "data.bin")).toThrow(PathAlreadyContainsFilenameError);
})

it("should properly append a path and filename", () => {
const pathManager = new PathManager();

const path = pathManager.getPathRelativeToCurrentExecutionDirectory("/allo/", "test.txt");

const pathParts = path.split("/").reverse();

expect(pathParts[0]).toBe("test.txt")
expect(pathParts[1]).toBe("allo")
expect(pathParts[2]).toBe("cli")
expect(pathParts[3]).toBe("packages")
})
})
32 changes: 32 additions & 0 deletions packages/cli/src/managers/path.manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import {injectable} from "tsyringe";
import {PathAlreadyContainsFilenameError} from "../errors/path-already-contains-filename.error";

@injectable()
export class PathManager {
getCurrentExecutionDirectory(): string {
return process.cwd();
}

getPathRelativeToCurrentExecutionDirectory(path: string, filename?: string): string {
const currentExecutionDirectory = this.getCurrentExecutionDirectory();

// If it starts with a "/", remove this character.
path = path.replace(/^\//, '');

// If it ends with a "/", remove this character.
path = path.replace(/\/$/, '');

// If path already ends with a filename and a filename was also provided, throw an error
if (filename) {
if (path.match(/\.\w+$/)) {
throw new PathAlreadyContainsFilenameError(`The path '${path}' already contains a filename. Cannot add filename: '${filename}'.`)
}

filename = filename.replace(/^\//, '');

path += `/${filename}`
}

return currentExecutionDirectory + "/" + path;
}
}
67 changes: 67 additions & 0 deletions packages/cli/src/managers/shell.manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import {exec, spawn} from "child_process";
import {ConsoleManager} from "./console.manager";
import {injectable} from "tsyringe";
import {PathManager} from "./path.manager";

@injectable()
export class ShellManager {
constructor(private readonly consoleManager: ConsoleManager, private readonly pathManager: PathManager) {
}

execute(command: string, options?: {
directory?: string,
streamStdout?: boolean,
maxBuffer?: number,
}): Promise<string> {
return new Promise<string>((resolve, reject) => {
const env = process.env;
let finalCommand = command;

const streamStdout = options?.streamStdout ?? false;
const directory = options?.directory;

if(directory) {
const absoluteDirectory = this.pathManager.getPathRelativeToCurrentExecutionDirectory(directory);
finalCommand = "cd " + absoluteDirectory + " && " + command;
}

this.consoleManager.writeLine(finalCommand);

if(streamStdout) {
const child = spawn(finalCommand, [], { shell: true, env });
child.stdout.on('data', (data) => {
this.consoleManager.writeLine(`${data}`);
});

child.stderr.on('data', (data) => {
this.consoleManager.writeLine(`Stderr: ${data}`);
});

child.on('close', (code) => {
this.consoleManager.writeLine(`Command exited with code ${code}`);

if(code !== 0) {
return reject(code);
}

return resolve(code + "");
});
}

return exec(finalCommand, {env, maxBuffer: options?.maxBuffer}, (error, stdout, stderr) => {
if (error && error.code) {
this.consoleManager.writeLine("Error: " + error.message);
return reject(error);
}

if (stderr) {
this.consoleManager.writeLine("Stderr: " + stderr);
return resolve(stderr);
}

this.consoleManager.writeLine(stdout);
return resolve(stdout);
})
})
}
}

0 comments on commit aa62f74

Please sign in to comment.