diff --git a/packages/bazel/src/builders/BUILD.bazel b/packages/bazel/src/builders/BUILD.bazel index 142c80f60a..6f13b16fc9 100644 --- a/packages/bazel/src/builders/BUILD.bazel +++ b/packages/bazel/src/builders/BUILD.bazel @@ -28,24 +28,3 @@ ts_library( "@npm//rxjs", ], ) - -ts_library( - name = "test_lib", - testonly = True, - srcs = [ - "bazel_spec.ts", - ], - deps = [ - "builders", - "@npm//@angular-devkit/core", - ], -) - -jasmine_node_test( - name = "test", - bootstrap = ["angular/tools/testing/init_node_spec.js"], - deps = [ - ":test_lib", - "//tools/testing:node", - ], -) diff --git a/packages/bazel/src/builders/bazel.ts b/packages/bazel/src/builders/bazel.ts index 9c777372aa..547d882103 100644 --- a/packages/bazel/src/builders/bazel.ts +++ b/packages/bazel/src/builders/bazel.ts @@ -8,10 +8,9 @@ /// -import {Path, dirname, getSystemPath, join, normalize} from '@angular-devkit/core'; -import {Host} from '@angular-devkit/core/src/virtual-fs/host'; -import {spawn} from 'child_process'; -import * as path from 'path'; +import {fork} from 'child_process'; +import {copyFileSync, existsSync, readdirSync, statSync, unlinkSync} from 'fs'; +import {dirname, join, normalize} from 'path'; export type Executable = 'bazel' | 'ibazel'; export type Command = 'build' | 'test' | 'run' | 'coverage' | 'query'; @@ -20,12 +19,14 @@ export type Command = 'build' | 'test' | 'run' | 'coverage' | 'query'; * Spawn the Bazel process. Trap SINGINT to make sure Bazel process is killed. */ export function runBazel( - projectDir: Path, binary: string, command: Command, workspaceTarget: string, flags: string[]) { + projectDir: string, binary: string, command: Command, workspaceTarget: string, + flags: string[]) { + projectDir = normalize(projectDir); + binary = normalize(binary); return new Promise((resolve, reject) => { - const buildProcess = spawn(process.argv[0], [binary, command, workspaceTarget, ...flags], { - cwd: getSystemPath(projectDir), + const buildProcess = fork(binary, [command, workspaceTarget, ...flags], { + cwd: projectDir, stdio: 'inherit', - shell: false, }); process.on('SIGINT', (signal) => { @@ -48,14 +49,14 @@ export function runBazel( /** * Resolves the path to `@bazel/bazel` or `@bazel/ibazel`. */ -export function checkInstallation(name: Executable, projectDir: Path): string { +export function checkInstallation(name: Executable, projectDir: string): string { + projectDir = normalize(projectDir); const packageName = `@bazel/${name}/package.json`; try { const bazelPath = require.resolve(packageName, { - paths: [getSystemPath(projectDir)], + paths: [projectDir], }); - - return path.dirname(bazelPath); + return dirname(bazelPath); } catch (error) { if (error.code === 'MODULE_NOT_FOUND') { throw new Error( @@ -70,14 +71,14 @@ export function checkInstallation(name: Executable, projectDir: Path): string { /** * Returns the absolute path to the template directory in `@angular/bazel`. */ -export async function getTemplateDir(host: Host, root: Path): Promise { +export function getTemplateDir(root: string): string { + root = normalize(root); const packageJson = require.resolve('@angular/bazel/package.json', { - paths: [getSystemPath(root)], + paths: [root], }); - - const packageDir = dirname(normalize(packageJson)); + const packageDir = dirname(packageJson); const templateDir = join(packageDir, 'src', 'builders', 'files'); - if (!await host.isDirectory(templateDir).toPromise()) { + if (!statSync(templateDir).isDirectory()) { throw new Error('Could not find Bazel template directory in "@angular/bazel".'); } return templateDir; @@ -87,30 +88,22 @@ export async function getTemplateDir(host: Host, root: Path): Promise { * Recursively list the specified 'dir' using depth-first approach. Paths * returned are relative to 'dir'. */ -function listR(host: Host, dir: Path): Promise { - async function list(dir: Path, root: Path, results: Path[]) { - const paths = await host.list(dir).toPromise(); +function listR(dir: string): string[] { + function list(dir: string, root: string, results: string[]) { + const paths = readdirSync(dir); for (const path of paths) { const absPath = join(dir, path); const relPath = join(root, path); - if (await host.isFile(absPath).toPromise()) { + if (statSync(absPath).isFile()) { results.push(relPath); } else { - await list(absPath, relPath, results); + list(absPath, relPath, results); } } return results; } - return list(dir, '' as Path, []); -} - -/** - * Copy the file from 'source' to 'dest'. - */ -async function copyFile(host: Host, source: Path, dest: Path) { - const buffer = await host.read(source).toPromise(); - await host.write(dest, buffer).toPromise(); + return list(dir, '', []); } /** @@ -119,35 +112,36 @@ async function copyFile(host: Host, source: Path, dest: Path) { * copied, so that they can be deleted later. * Existing files in `root` will not be replaced. */ -export async function copyBazelFiles(host: Host, root: Path, templateDir: Path) { - const bazelFiles: Path[] = []; - const templates = await listR(host, templateDir); +export function copyBazelFiles(root: string, templateDir: string) { + root = normalize(root); + templateDir = normalize(templateDir); + const bazelFiles: string[] = []; + const templates = listR(templateDir); - await Promise.all(templates.map(async(template) => { + for (const template of templates) { const name = template.replace('__dot__', '.').replace('.template', ''); const source = join(templateDir, template); const dest = join(root, name); try { - const exists = await host.exists(dest).toPromise(); - if (!exists) { - await copyFile(host, source, dest); + if (!existsSync(dest)) { + copyFileSync(source, dest); bazelFiles.push(dest); } } catch { } - })); + } return bazelFiles; } /** - * Delete the specified 'files' and return a promise that always resolves. + * Delete the specified 'files'. This function never throws. */ -export function deleteBazelFiles(host: Host, files: Path[]) { - return Promise.all(files.map(async(file) => { +export function deleteBazelFiles(files: string[]) { + for (const file of files) { try { - await host.delete(file).toPromise(); + unlinkSync(file); } catch { } - })); + } } diff --git a/packages/bazel/src/builders/bazel_spec.ts b/packages/bazel/src/builders/bazel_spec.ts deleted file mode 100644 index 84bf86ddab..0000000000 --- a/packages/bazel/src/builders/bazel_spec.ts +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import {Path} from '@angular-devkit/core'; -import {test} from '@angular-devkit/core/src/virtual-fs/host/test'; - -import {copyBazelFiles, deleteBazelFiles} from './bazel'; - -describe('Bazel builder', () => { - it('should copy Bazel files', async() => { - const host = new test.TestHost({ - '/files/WORKSPACE.template': '', - '/files/BUILD.bazel.template': '', - '/files/__dot__bazelrc.template': '', - '/files/__dot__bazelignore.template': '', - '/files/e2e/BUILD.bazel.template': '', - '/files/src/BUILD.bazel.template': '', - }); - const root = '/' as Path; - const templateDir = '/files' as Path; - await copyBazelFiles(host, root, templateDir); - const {records} = host; - expect(records).toContain({kind: 'write', path: '/WORKSPACE' as Path}); - expect(records).toContain({kind: 'write', path: '/BUILD.bazel' as Path}); - }); - - it('should delete Bazel files', async() => { - const host = new test.TestHost({ - '/WORKSPACE': '', - '/BUILD.bazel': '', - }); - await deleteBazelFiles(host, ['/WORKSPACE', '/BUILD.bazel'] as Path[]); - const {records} = host; - expect(records).toContain({kind: 'delete', path: '/WORKSPACE' as Path}); - expect(records).toContain({kind: 'delete', path: '/BUILD.bazel' as Path}); - }); -}); diff --git a/packages/bazel/src/builders/index.ts b/packages/bazel/src/builders/index.ts index e0bc4dab96..7b34483429 100644 --- a/packages/bazel/src/builders/index.ts +++ b/packages/bazel/src/builders/index.ts @@ -9,33 +9,29 @@ */ import {BuilderContext, BuilderOutput, createBuilder,} from '@angular-devkit/architect/src/index2'; -import {JsonObject, normalize} from '@angular-devkit/core'; +import {JsonObject} from '@angular-devkit/core'; import {checkInstallation, copyBazelFiles, deleteBazelFiles, getTemplateDir, runBazel} from './bazel'; import {Schema} from './schema'; -import {NodeJsSyncHost} from '@angular-devkit/core/node'; async function _bazelBuilder(options: JsonObject & Schema, context: BuilderContext, ): Promise { - const root = normalize(context.workspaceRoot); - const {logger} = context; + const {logger, workspaceRoot} = context; const {bazelCommand, leaveBazelFilesOnDisk, targetLabel, watch} = options; const executable = watch ? 'ibazel' : 'bazel'; - const binary = checkInstallation(executable, root); - - const host = new NodeJsSyncHost(); - const templateDir = await getTemplateDir(host, root); - const bazelFiles = await copyBazelFiles(host, root, templateDir); + const binary = checkInstallation(executable, workspaceRoot); + const templateDir = getTemplateDir(workspaceRoot); + const bazelFiles = copyBazelFiles(workspaceRoot, templateDir); try { const flags: string[] = []; - await runBazel(root, binary, bazelCommand, targetLabel, flags); + await runBazel(workspaceRoot, binary, bazelCommand, targetLabel, flags); return {success: true}; } catch (err) { logger.error(err.message); return {success: false}; } finally { if (!leaveBazelFilesOnDisk) { - await deleteBazelFiles(host, bazelFiles); // this will never throw + deleteBazelFiles(bazelFiles); // this will never throw } } }