From 29609897a293f2002429fd1d90945dbf4fb47ac2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakob=20H=C3=B8genes?= <1014990+jakhog@users.noreply.github.com> Date: Sat, 27 Mar 2021 14:58:16 +0100 Subject: [PATCH] Add support for specifying output directory --- Source/JavaScript/GenerateOptions.ts | 1 + Source/JavaScript/Generator.ts | 29 +++++++++++++++------------- Source/JavaScript/generateAction.ts | 2 ++ Source/JavaScript/index.ts | 5 ++++- 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/Source/JavaScript/GenerateOptions.ts b/Source/JavaScript/GenerateOptions.ts index 7c53d92..1a5961a 100644 --- a/Source/JavaScript/GenerateOptions.ts +++ b/Source/JavaScript/GenerateOptions.ts @@ -5,6 +5,7 @@ import { GenerationTarget } from './GenerationTarget'; export type GenerateOptions = { readonly target: GenerationTarget; + readonly output: string; readonly paths: readonly string[]; readonly includes: readonly string[]; readonly rewrites: readonly {readonly from: string, readonly to: string, readonly package: boolean}[]; diff --git a/Source/JavaScript/Generator.ts b/Source/JavaScript/Generator.ts index 932b423..4204676 100644 --- a/Source/JavaScript/Generator.ts +++ b/Source/JavaScript/Generator.ts @@ -2,7 +2,8 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. import os from 'os'; -import { dirname as pathDirname, join as pathJoin, relative as pathRelative } from 'path'; +import process from 'process'; +import { dirname as pathDirname, join as pathJoin, relative as pathRelative, normalize as pathNormalize, resolve as pathResolve } from 'path'; import { mkdir, mkdtemp, readdir, readFile, rmdir, stat, writeFile } from 'fs/promises'; import { protoc, protocTS } from './Compilers'; @@ -10,18 +11,14 @@ import { GenerateOptions } from './GenerateOptions'; import { GenerationTarget } from './GenerationTarget'; export class Generator { - constructor( - readonly outputDirectory: string - ) {} - async generate(options: GenerateOptions): Promise { try { console.log('Generating code for', options.target); console.log('With includes', options.includes.join(' ')); console.log('With rewrites', options.rewrites.map(_ => `${_.from}:${_.to}`).join(' ')); - console.log('To directory', this.outputDirectory); + console.log('To directory', options.output); - await this.ensureCleanOutputDirectory(); + await this.ensureCleanOutputDirectory(options); const protoFiles = await this.findAllProtoFilesIn(...options.paths); const tmpDir = await this.createTemporaryBuildDirectory(); @@ -67,7 +64,7 @@ export class Generator { if (!shouldInclude) continue; - const movedFilePath = pathJoin(this.outputDirectory, rewrittenPath); + const movedFilePath = pathJoin(options.output, rewrittenPath); const movedFileDirectory = pathDirname(movedFilePath); await mkdir(movedFileDirectory, { recursive: true }); await writeFile(movedFilePath, rewrittenContents); @@ -111,19 +108,25 @@ export class Generator { return [contents, true]; } - private async ensureCleanOutputDirectory(): Promise { + private async ensureCleanOutputDirectory(options: GenerateOptions): Promise { + const currentDirectory = pathResolve(process.cwd()); + const outputDirectory = pathResolve(options.output); + if (currentDirectory.startsWith(outputDirectory)) { + console.log('Output directory includes current directory, not cleaning'); + return; + } try { - const info = await stat(this.outputDirectory); + const info = await stat(outputDirectory); if (info.isDirectory()) { - await rmdir(this.outputDirectory, { recursive: true }); + await rmdir(outputDirectory, { recursive: true }); } else { - throw new Error(`Output directory '${this.outputDirectory}' is not a directory`); + throw new Error(`Output directory '${options.output}' is not a directory`); } } catch (error) { if (error.code !== 'ENOENT') throw error; } - await mkdir(this.outputDirectory, { recursive: true }); + await mkdir(outputDirectory, { recursive: true }); } private async createTemporaryBuildDirectory(): Promise { diff --git a/Source/JavaScript/generateAction.ts b/Source/JavaScript/generateAction.ts index 5e09271..f54f3cf 100644 --- a/Source/JavaScript/generateAction.ts +++ b/Source/JavaScript/generateAction.ts @@ -7,6 +7,7 @@ import { GenerationTarget } from './GenerationTarget'; type GenerateActionCallback = (options: GenerateOptions) => Promise | void; type Options = { + O: string, I: string[], R: string[], skipEmptyFiles?: boolean, @@ -16,6 +17,7 @@ export const generateAction = (target: GenerationTarget, action: GenerateActionC return (paths: string[], options: Options) => { action({ target, + output: options.O, paths, includes: options.I, rewrites: options.R.map(_ => { diff --git a/Source/JavaScript/index.ts b/Source/JavaScript/index.ts index 05b9b83..d20bb86 100644 --- a/Source/JavaScript/index.ts +++ b/Source/JavaScript/index.ts @@ -9,16 +9,18 @@ import { generateAction } from './generateAction'; import { GenerationTarget } from './GenerationTarget'; import { Generator } from './Generator'; -const generator = new Generator('./build'); +const generator = new Generator(); const program = new Command('dolittle_proto_build'); +const output = new Option('-O ', 'Output path').default('./build'); const includes = new Option('-I ', 'Include path (multiple allowed)'); const rewrite = new Option('-R ', 'Rewrite file paths (multiple allowed)'); const skipEmptyFiles = new Option('--skip-empty-files', 'Remove files generated without any content'); program .command('grpc-node ') + .addOption(output) .addOption(repeated(includes)) .addOption(repeated(rewrite)) .addOption(skipEmptyFiles) @@ -27,6 +29,7 @@ program program .command('grpc-web ') + .addOption(output) .addOption(repeated(includes)) .addOption(repeated(rewrite)) .addOption(skipEmptyFiles)