Skip to content
Permalink
Browse files

feat(bazel): Hide Bazel files in Bazel builder (#29110)

This commit modifies the Bazel builder to copy the Bazel WORKSPACE and
BUILD.bazel files to the project root directory before invoking Bazel.

This hides the Bazel files from users.

PR Close #29110
  • Loading branch information...
kyliau authored and kara committed Mar 5, 2019
1 parent 14ce8a9 commit 7060d9038b11a7c67cdce6b58464a935e9a340c5
@@ -10,29 +10,29 @@
"@angular-devkit/core" "7.3.2"
rxjs "6.3.3"

"@angular-devkit/architect@^0.10.6":
version "0.10.7"
resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.10.7.tgz#c74b9f6b7f1b4261ada2d24c832328aa4c394464"
integrity sha512-S49LSslNRxIflHzrIrEgK7mGQ7HzETr/FU0fyTbB0vubcmfzMoYTsgYdK7SUz583lovc+UvASoUAhPJI3e35ng==
"@angular-devkit/architect@^0.13.4":
version "0.13.4"
resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.13.4.tgz#f5db62f028e3c0971db5719be9c17a78fd8a67a2"
integrity sha512-wJF8oz8MurtpFi0ik42bkI2F5gEnuOe79KHPO1i3SYfdhEp5NY8igVKZ6chB/eq4Ml50aHxas8Hh9ke12K+Pxw==
dependencies:
"@angular-devkit/core" "7.0.7"
"@angular-devkit/core" "7.3.4"
rxjs "6.3.3"

"@angular-devkit/core@7.0.7":
version "7.0.7"
resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-7.0.7.tgz#665176ad8421adfd5f3ea0b2c4a9a432a158b1bb"
integrity sha512-M8tTT9r3nUtWI3YyiyynHIQn+lQQgeKkxVZ+rdxvyvgE3U9+wn0yep5HkFLQETTuJetu9ARRRD94sD2XL3F/3A==
"@angular-devkit/core@7.3.2", "@angular-devkit/core@^7.0.4":
version "7.3.2"
resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-7.3.2.tgz#67ac2cfcbe47f1e457929c19ab1b04c9e061b2e2"
integrity sha512-W5KjkHRNVBcZRUNJamAn52IAj9Gl1zUjPA2r75JJK7k199xOA8UZqcIukQOgM1N7rwKCWht08i4FsdcTDghMhQ==
dependencies:
ajv "6.5.3"
ajv "6.9.1"
chokidar "2.0.4"
fast-json-stable-stringify "2.0.0"
rxjs "6.3.3"
source-map "0.7.3"

"@angular-devkit/core@7.3.2", "@angular-devkit/core@^7.0.4":
version "7.3.2"
resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-7.3.2.tgz#67ac2cfcbe47f1e457929c19ab1b04c9e061b2e2"
integrity sha512-W5KjkHRNVBcZRUNJamAn52IAj9Gl1zUjPA2r75JJK7k199xOA8UZqcIukQOgM1N7rwKCWht08i4FsdcTDghMhQ==
"@angular-devkit/core@7.3.4":
version "7.3.4"
resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-7.3.4.tgz#fae0521652c7430237025f117531ca3262ef8335"
integrity sha512-MBfen51iOBKfK4tlg5KwmPxePsF1QoFNUMGLuvUUwPkteonrGcupX1Q7NWTpf+HA+i08mOnZGuepeuQkD12IQw==
dependencies:
ajv "6.9.1"
chokidar "2.0.4"
@@ -51,11 +51,11 @@
"@angular/bazel@file:../../dist/packages-dist/bazel":
version "8.0.0-beta.6"
dependencies:
"@angular-devkit/architect" "^0.10.6"
"@angular-devkit/architect" "^0.13.4"
"@angular-devkit/core" "^7.0.4"
"@angular-devkit/schematics" "^7.3.0-rc.0"
"@bazel/typescript" "^0.26.0"
"@microsoft/api-extractor" "^7.0.17"
"@microsoft/api-extractor" "^7.0.21"
"@schematics/angular" "^7.0.4"
"@types/node" "6.0.84"
semver "^5.6.0"
@@ -112,26 +112,27 @@
source-map-support "0.5.9"
tsutils "2.27.2"

"@microsoft/api-extractor@^7.0.17":
version "7.0.18"
resolved "https://registry.yarnpkg.com/@microsoft/api-extractor/-/api-extractor-7.0.18.tgz#4eb931436495177dfcef8f2d8da3d084d10eebb6"
integrity sha512-puQisjyoYK1A0I8DqyBoLPV9noyFUlxTE3WsjhgJw//TrmegGHYmsRlD3rnHeXcKPM1F7sd/VKJXeXC3IPTf2Q==
"@microsoft/api-extractor@^7.0.21":
version "7.0.22"
resolved "https://registry.yarnpkg.com/@microsoft/api-extractor/-/api-extractor-7.0.22.tgz#9c6eb0500168811ed14194de413ddd310622533a"
integrity sha512-1mNMbmUeqtjNmS9hgrONio2uRZL2eeZk39zCKq04ReImFXnMR+fnMTQG98B+SAkFFGJuOucwke5U0bgWnrG6kw==
dependencies:
"@microsoft/node-core-library" "3.10.0"
"@microsoft/node-core-library" "3.12.0"
"@microsoft/ts-command-line" "4.2.3"
"@microsoft/tsdoc" "0.12.5"
"@microsoft/tsdoc" "0.12.7"
"@types/node" "8.5.8"
"@types/z-schema" "3.16.31"
colors "~1.2.1"
lodash "~4.17.5"
resolve "1.8.1"
source-map "~0.6.1"
typescript "~3.1.6"
z-schema "~3.18.3"

"@microsoft/node-core-library@3.10.0":
version "3.10.0"
resolved "https://registry.yarnpkg.com/@microsoft/node-core-library/-/node-core-library-3.10.0.tgz#70e089534d8e20f6a0f9c7a4a12a6aeafd6a1ddb"
integrity sha512-1SbU+XNYAabhV9noGXHtsUVPc5ELV+oEuJQtZQoCncbOd6WAMeTgB1xFwh96hmdEXyKQyML/pnByiKocmh/nbQ==
"@microsoft/node-core-library@3.12.0":
version "3.12.0"
resolved "https://registry.yarnpkg.com/@microsoft/node-core-library/-/node-core-library-3.12.0.tgz#f9c27b8bb6b55d60b91d4e1962f42b03b9f8f47f"
integrity sha512-9T2dEXmmxZqnqcpHuIB8mTAOM/DNSi/QcAwKYDjvZvkd+PGT5lCUXjM9GL7SaR2NPa3UrWDGgFhNoqLqLfEPbw==
dependencies:
"@types/fs-extra" "5.0.4"
"@types/jju" "~1.4.0"
@@ -152,10 +153,10 @@
argparse "~1.0.9"
colors "~1.2.1"

"@microsoft/tsdoc@0.12.5":
version "0.12.5"
resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.12.5.tgz#c448a38902ccb5601c1b2ef3b1a105012ef7712c"
integrity sha512-xEAyvLXo4Cter/b0EMCWUZTgXOfLOPJ/Xr52WdjVclPx9eDmNTGFtZl8Pn/nqSnZsQBNcHL0eHk/YyRyyXXpiQ==
"@microsoft/tsdoc@0.12.7":
version "0.12.7"
resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.12.7.tgz#8fb4a9f4fdf01f1469c9fc54b0ad2d36ec57c25d"
integrity sha512-0bqNlQT8aR4Iq9xx/OsY579Zeqon9uTZDIuvl+XXu16TPPN2sASeKojwm366jA2MjgXd9iyTWpJM5/P1QJ4Dxg==

"@schematics/angular@7.3.2", "@schematics/angular@^7.0.4":
version "7.3.2"
@@ -249,16 +250,6 @@ agentkeepalive@^3.4.1:
dependencies:
humanize-ms "^1.2.1"

ajv@6.5.3:
version "6.5.3"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.3.tgz#71a569d189ecf4f4f321224fecb166f071dd90f9"
integrity sha512-LqZ9wY+fx3UMiiPd741yB2pj3hhil+hQc8taf4o2QGRFpWgZ2V5C8HA165DY9sS3fJwsk7uT7ZlFEyC3Ig3lLg==
dependencies:
fast-deep-equal "^2.0.1"
fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"

ajv@6.9.1:
version "6.9.1"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.9.1.tgz#a4d3683d74abc5670e75f0b16520f70a20ea8dc1"
@@ -2154,7 +2145,7 @@ source-map@^0.5.6:
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=

source-map@^0.6.0:
source-map@^0.6.0, source-map@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
@@ -18,7 +18,7 @@
}
},
"dependencies": {
"@angular-devkit/architect": "^0.10.6",
"@angular-devkit/architect": "^0.13.4",
"@angular-devkit/core": "^7.0.4",
"@angular-devkit/schematics": "^7.3.0-rc.0",
"@bazel/typescript": "^0.26.0",
@@ -42,4 +42,4 @@
"ng-update": {
"packageGroup": "NG_UPDATE_PACKAGE_GROUP"
}
}
}
@@ -1,4 +1,4 @@
load("//tools:defaults.bzl", "ts_library")
load("//tools:defaults.bzl", "jasmine_node_test", "ts_library")

package(default_visibility = ["//visibility:public"])

@@ -19,7 +19,7 @@ ts_library(
],
data = [
"schema.json",
],
] + glob(["files/**/*"]),
module_name = "@angular/bazel/src/builders",
deps = [
"@npm//@angular-devkit/architect",
@@ -28,3 +28,24 @@ 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",
],
)
@@ -7,44 +7,145 @@
*/

/// <reference types='node'/>
import {spawn, spawnSync} from 'child_process';
import {Observable, Subject} from 'rxjs';

import {Path, basename, dirname, getSystemPath, join} from '@angular-devkit/core';
import {resolve} from '@angular-devkit/core/node';
import {Host} from '@angular-devkit/core/src/virtual-fs/host';
import {spawn} from 'child_process';

export type Executable = 'bazel' | 'ibazel';
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: string, executable: Executable, command: Command, workspaceTarget: string,
flags: string[]): Observable<void> {
const doneSubject = new Subject<void>();
const bin = require.resolve(`@bazel/${executable}`);
const buildProcess = spawn(bin, [command, workspaceTarget, ...flags], {
cwd: projectDir,
stdio: 'inherit',
shell: false,
});
projectDir: Path, binary: Path, command: Command, workspaceTarget: string, flags: string[]) {
return new Promise((resolve, reject) => {
const buildProcess = spawn(getSystemPath(binary), [command, workspaceTarget, ...flags], {
cwd: getSystemPath(projectDir),
stdio: 'inherit',
shell: false,
});

buildProcess.once('close', (code: number) => {
if (code === 0) {
doneSubject.next();
} else {
doneSubject.error(`${executable} failed with code ${code}.`);
}
});
process.on('SIGINT', (signal) => {
if (!buildProcess.killed) {
buildProcess.kill();
reject(new Error(`Bazel process received ${signal}.`));
}
});

return doneSubject.asObservable();
buildProcess.once('close', (code: number) => {
if (code === 0) {
resolve();
} else {
reject(new Error(`${basename(binary)} failed with code ${code}.`));
}
});
});
}

export function checkInstallation(executable: Executable, projectDir: string) {
let bin: string;
/**
* Resolves the path to `@bazel/bazel` or `@bazel/ibazel`.
*/
export function checkInstallation(name: Executable, projectDir: Path): string {
const packageName = `@bazel/${name}`;
try {
bin = require.resolve(`@bazel/${executable}`);
} catch {
return false;
return resolve(packageName, {
basedir: projectDir,
});
} catch (error) {
if (error.code === 'MODULE_NOT_FOUND') {
throw new Error(
`Could not run ${name}. Please make sure that the ` +
`"${name}" command is installed by running ` +
`"npm install ${packageName}" or "yarn install ${packageName}".`);
}
throw error;
}
const child = spawnSync(bin, ['version'], {
cwd: projectDir,
shell: false,
}

/**
* Returns the absolute path to the template directory in `@angular/bazel`.
*/
export async function getTemplateDir(host: Host, root: Path): Promise<Path> {
const packageJson = resolve('@angular/bazel', {
basedir: root,
resolvePackageJson: true,
});
return child.status === 0;
const packageDir = dirname(packageJson as Path);
const templateDir = join(packageDir, 'src', 'builders', 'files');
if (!await host.isDirectory(templateDir).toPromise()) {
throw new Error('Could not find Bazel template directory in "@angular/bazel".');
}
return templateDir;
}

/**
* Recursively list the specified 'dir' using depth-first approach. Paths
* returned are relative to 'dir'.
*/
function listR(host: Host, dir: Path): Promise<Path[]> {
async function list(dir: Path, root: Path, results: Path[]) {
const paths = await host.list(dir).toPromise();
for (const path of paths) {
const absPath = join(dir, path);
const relPath = join(root, path);
if (await host.isFile(absPath).toPromise()) {
results.push(relPath);
} else {
await 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();
}

/**
* Copy Bazel files (WORKSPACE, BUILD.bazel, etc) from the template directory to
* the project `root` directory, and return the absolute paths of the files
* 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);

await Promise.all(templates.map(async(template) => {
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);
bazelFiles.push(dest);
}
} catch {
}
}));

return bazelFiles;
}

/**
* Delete the specified 'files' and return a promise that always resolves.
*/
export function deleteBazelFiles(host: Host, files: Path[]) {
return Promise.all(files.map(async(file) => {
try {
await host.delete(file).toPromise();
} catch {
}
}));
}
Oops, something went wrong.

0 comments on commit 7060d90

Please sign in to comment.
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.