diff --git a/packages/angular_devkit/build_angular/src/angular-cli-files/models/build-options.ts b/packages/angular_devkit/build_angular/src/angular-cli-files/models/build-options.ts index 552b515b53cd..2bf4ea1b06d6 100644 --- a/packages/angular_devkit/build_angular/src/angular-cli-files/models/build-options.ts +++ b/packages/angular_devkit/build_angular/src/angular-cli-files/models/build-options.ts @@ -35,6 +35,7 @@ export interface BuildOptions { deployUrl?: string; verbose?: boolean; progress?: boolean; + progressType?: string; i18nFile?: string; i18nFormat?: string; i18nLocale?: string; diff --git a/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts b/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts index bab2266a41f7..e1daa5d5af99 100644 --- a/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts +++ b/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts @@ -14,6 +14,9 @@ import { CleanCssWebpackPlugin } from '../../plugins/cleancss-webpack-plugin'; import { ScriptsWebpackPlugin } from '../../plugins/scripts-webpack-plugin'; import { findUp } from '../../utilities/find-up'; import { isDirectory } from '../../utilities/is-directory'; +import { + selectProgressReporter, +} from '../../utilities/progress-reporters/progress-reporter-selector'; import { requireProjectModule } from '../../utilities/require-project-module'; import { BuildOptions, WebpackConfigOptions } from '../build-options'; import { getOutputHashFormat, normalizeExtraEntryPoints } from './utils'; @@ -149,8 +152,11 @@ export function getCommonConfig(wco: WebpackConfigOptions) { extraPlugins.push(copyWebpackPluginInstance); } - if (buildOptions.progress) { - extraPlugins.push(new ProgressPlugin({ profile: buildOptions.verbose })); + if (buildOptions.progress ) { + extraPlugins.push( + new ProgressPlugin( + selectProgressReporter(buildOptions.progressType) + .buildOptions(buildOptions))); } if (buildOptions.showCircularDependencies) { diff --git a/packages/angular_devkit/build_angular/src/angular-cli-files/utilities/progress-reporters/progress-reporter-selector.ts b/packages/angular_devkit/build_angular/src/angular-cli-files/utilities/progress-reporters/progress-reporter-selector.ts new file mode 100644 index 000000000000..f33f857a6453 --- /dev/null +++ b/packages/angular_devkit/build_angular/src/angular-cli-files/utilities/progress-reporters/progress-reporter-selector.ts @@ -0,0 +1,50 @@ +/** + * @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 { ProgressReporter } from './progress-reporter'; +import { SimpleProgressReporter } from './simple-progress-reporter'; +import { VerboseProgressReporter } from './verbose-progress-reporter'; +import { WebpackDefaultProgressReporter } from './webpack-default-progress-reporter'; + +const defaultProgressReporter = 'webpack-default'; + +const factories: { + // Mapping of string key to factory of a ProgressReporter + [key: string]: (() => ProgressReporter), +} = { + 'webpack-default': () => new WebpackDefaultProgressReporter(), + 'verbose-colors': () => new VerboseProgressReporter(true), + 'verbose-plain': () => new VerboseProgressReporter(false), + 'simple-plain': () => new SimpleProgressReporter(false), + 'simple-colors': () => new SimpleProgressReporter(true), + +}; + +const aliases: { + // Mapping of default to factory + [key: string]: (string), +} = { + 'ci-friendly': 'simple', + 'verbose': 'verbose-colors', + 'simple': 'simple-colors', + 'non-tty': 'simple', + 'tty': 'webpack-default', +}; + +export function selectProgressReporter(userInput?: string): ProgressReporter { + if (userInput) { + if (factories[userInput]) { + return factories[userInput](); + } + if (aliases[userInput]) { + return selectProgressReporter(aliases[userInput]); + } + throw new Error('Could not find progress reporter: ' + userInput); + } else { + return selectProgressReporter(defaultProgressReporter); + } +} diff --git a/packages/angular_devkit/build_angular/src/angular-cli-files/utilities/progress-reporters/progress-reporter.ts b/packages/angular_devkit/build_angular/src/angular-cli-files/utilities/progress-reporters/progress-reporter.ts new file mode 100644 index 000000000000..54158c0dff53 --- /dev/null +++ b/packages/angular_devkit/build_angular/src/angular-cli-files/utilities/progress-reporters/progress-reporter.ts @@ -0,0 +1,28 @@ +/** + * @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 { ProgressPluginOptions } from 'webpack/declarations/plugins/ProgressPlugin'; +import { BuildOptions } from '../../models/build-options'; + +export abstract class ProgressReporter { + + protected abstract handleProgress(percentage: number, msg: string, ...args: string[]): void; + + protected baseOptions(): ProgressPluginOptions { + return {}; + } + + public buildOptions(buildOptions: BuildOptions): ProgressPluginOptions { + const progressPluginOptions = this.baseOptions(); + progressPluginOptions.handler = ((percentage, msg, ...args) => + this.handleProgress(percentage, msg, ...args)); + progressPluginOptions.profile = buildOptions.verbose; + + return progressPluginOptions; + } + +} diff --git a/packages/angular_devkit/build_angular/src/angular-cli-files/utilities/progress-reporters/simple-progress-reporter.ts b/packages/angular_devkit/build_angular/src/angular-cli-files/utilities/progress-reporters/simple-progress-reporter.ts new file mode 100644 index 000000000000..ec856f091bea --- /dev/null +++ b/packages/angular_devkit/build_angular/src/angular-cli-files/utilities/progress-reporters/simple-progress-reporter.ts @@ -0,0 +1,56 @@ +/** + * @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 { terminal } from '@angular-devkit/core'; +import { ProgressReporter } from './progress-reporter'; + + +const { bold, green, white, yellow } = terminal; + +export class SimpleProgressReporter extends ProgressReporter { + + constructor(private colours: boolean) { + super(); + + } + + lastPercentage = -1; + lastMessage = ''; + + // ***% (msg) [detail] [detail] + + protected handleProgress(percentage: number, msg: string, ...args: string[]): void { + percentage = Math.floor(percentage * 100); + + if (this.lastMessage == msg && this.lastPercentage == percentage) { + return; + } + + this.lastMessage = msg; + this.lastPercentage = percentage; + + let buildingString = + (this.colours ? bold(percentage + '') : percentage) + + '%'; + if (percentage < 100) { // Shift string right + buildingString = ` ${buildingString}`; + } + + if (percentage < 10) { // Shift string right + buildingString = ` ${buildingString}`; + } + + if (msg) { + buildingString += ' (' + + (this.colours ? bold(yellow(msg)) : msg) + + ')'; + } + + console.log(buildingString); + } + +} diff --git a/packages/angular_devkit/build_angular/src/angular-cli-files/utilities/progress-reporters/verbose-progress-reporter.ts b/packages/angular_devkit/build_angular/src/angular-cli-files/utilities/progress-reporters/verbose-progress-reporter.ts new file mode 100644 index 000000000000..dd383bd1dcc4 --- /dev/null +++ b/packages/angular_devkit/build_angular/src/angular-cli-files/utilities/progress-reporters/verbose-progress-reporter.ts @@ -0,0 +1,53 @@ +/** + * @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 { terminal } from '@angular-devkit/core'; +import { ProgressReporter } from './progress-reporter'; + + +const { bold, green, white, yellow } = terminal; + +export class VerboseProgressReporter extends ProgressReporter { + + constructor(private colours: boolean) { + super(); + } + + // ***% (msg) [detail] [detail] + + protected handleProgress(percentage: number, msg: string, ...args: string[]): void { + percentage = Math.floor(percentage * 100); + let buildingString = + (this.colours ? bold(percentage + '') : percentage) + + '%'; + if (percentage < 100) { // Shift string right + buildingString = ` ${buildingString}`; + } + + if (percentage < 10) { // Shift string right + buildingString = ` ${buildingString}`; + } + + if (msg) { + buildingString += ' (' + + (this.colours ? bold(yellow(msg)) : msg) + + ')'; + } + + if (args) { + for (const arg of args) { + if (arg) { + buildingString += ' [' + + (this.colours ? green(arg) : arg) + + ']'; + } + } + } + console.log(buildingString); + } + +} diff --git a/packages/angular_devkit/build_angular/src/angular-cli-files/utilities/progress-reporters/webpack-default-progress-reporter.ts b/packages/angular_devkit/build_angular/src/angular-cli-files/utilities/progress-reporters/webpack-default-progress-reporter.ts new file mode 100644 index 000000000000..b9d0d5339f0e --- /dev/null +++ b/packages/angular_devkit/build_angular/src/angular-cli-files/utilities/progress-reporters/webpack-default-progress-reporter.ts @@ -0,0 +1,31 @@ +/** + * @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 { ProgressPluginOptions } from 'webpack/declarations/plugins/ProgressPlugin'; +import { BuildOptions } from '../../models/build-options'; +import { ProgressReporter } from './progress-reporter'; + +export class WebpackDefaultProgressReporter extends ProgressReporter { + + constructor() { + super(); + } + + protected handleProgress(percentage: number, msg: string, ...args: string[]): void { + throw new Error('This method is not to be called'); + } + + public buildOptions(buildOptions: BuildOptions): ProgressPluginOptions { + const progressPluginOptions = super.buildOptions(buildOptions); + // Reset handler to undefined, this will cause ProgressPlugin to use it's default handler + progressPluginOptions.handler = undefined; + + return progressPluginOptions; + } + +} diff --git a/packages/angular_devkit/build_angular/src/browser/index.ts b/packages/angular_devkit/build_angular/src/browser/index.ts index b13b08eb1823..57fbdf2eb07d 100644 --- a/packages/angular_devkit/build_angular/src/browser/index.ts +++ b/packages/angular_devkit/build_angular/src/browser/index.ts @@ -34,7 +34,7 @@ import { statsToString, statsWarningsToString, } from '../angular-cli-files/utilities/stats'; -import { defaultProgress, normalizeBuilderSchema } from '../utils'; +import { defaultProgress, defaultProgressType, normalizeBuilderSchema } from '../utils'; import { BrowserBuilderSchema, NormalizedBrowserBuilderSchema } from './schema'; const SpeedMeasurePlugin = require('speed-measure-webpack-plugin'); const webpackMerge = require('webpack-merge'); @@ -137,6 +137,7 @@ export class BrowserBuilder implements Builder { }; wco.buildOptions.progress = defaultProgress(wco.buildOptions.progress); + wco.buildOptions.progressType = defaultProgressType(wco.buildOptions.progressType); const webpackConfigs: {}[] = [ getCommonConfig(wco), diff --git a/packages/angular_devkit/build_angular/src/browser/schema.d.ts b/packages/angular_devkit/build_angular/src/browser/schema.d.ts index 243c8f84fc96..81a8fc1be89a 100644 --- a/packages/angular_devkit/build_angular/src/browser/schema.d.ts +++ b/packages/angular_devkit/build_angular/src/browser/schema.d.ts @@ -113,6 +113,11 @@ export interface BrowserBuilderSchema { */ progress?: boolean; + /** + * The method in which progress is logged to the console while building + */ + progressType?: string; + /** * Localization file to use for i18n. */ diff --git a/packages/angular_devkit/build_angular/src/browser/schema.json b/packages/angular_devkit/build_angular/src/browser/schema.json index 817379b9fb42..b438994bb05f 100644 --- a/packages/angular_devkit/build_angular/src/browser/schema.json +++ b/packages/angular_devkit/build_angular/src/browser/schema.json @@ -174,6 +174,10 @@ "type": "boolean", "description": "Log progress to the console while building." }, + "progressType": { + "type": "string", + "description": "The method in which progress is logged to the console while building." + }, "i18nFile": { "type": "string", "description": "Localization file to use for i18n." diff --git a/packages/angular_devkit/build_angular/src/karma/index.ts b/packages/angular_devkit/build_angular/src/karma/index.ts index fcb2a5881101..c3ee5220bd38 100644 --- a/packages/angular_devkit/build_angular/src/karma/index.ts +++ b/packages/angular_devkit/build_angular/src/karma/index.ts @@ -26,7 +26,7 @@ import { } from '../angular-cli-files/models/webpack-configs'; import { readTsconfig } from '../angular-cli-files/utilities/read-tsconfig'; import { requireProjectModule } from '../angular-cli-files/utilities/require-project-module'; -import { defaultProgress, normalizeBuilderSchema } from '../utils'; +import { defaultProgress, defaultProgressType, normalizeBuilderSchema } from '../utils'; import { KarmaBuilderSchema, NormalizedKarmaBuilderSchema } from './schema'; const webpackMerge = require('webpack-merge'); @@ -150,6 +150,7 @@ export class KarmaBuilder implements Builder { }; wco.buildOptions.progress = defaultProgress(wco.buildOptions.progress); + wco.buildOptions.progressType = defaultProgressType(wco.buildOptions.progressType); const webpackConfigs: {}[] = [ getCommonConfig(wco), diff --git a/packages/angular_devkit/build_angular/src/server/index.ts b/packages/angular_devkit/build_angular/src/server/index.ts index 0443c7020c51..f1bb41d92fc2 100644 --- a/packages/angular_devkit/build_angular/src/server/index.ts +++ b/packages/angular_devkit/build_angular/src/server/index.ts @@ -30,7 +30,7 @@ import { import { readTsconfig } from '../angular-cli-files/utilities/read-tsconfig'; import { requireProjectModule } from '../angular-cli-files/utilities/require-project-module'; import { getBrowserLoggingCb } from '../browser'; -import { defaultProgress, normalizeBuilderSchema } from '../utils'; +import { defaultProgress, defaultProgressType, normalizeBuilderSchema } from '../utils'; import { BuildWebpackServerSchema, NormalizedServerBuilderServerSchema } from './schema'; const webpackMerge = require('webpack-merge'); @@ -103,6 +103,7 @@ export class ServerBuilder implements Builder { }; wco.buildOptions.progress = defaultProgress(wco.buildOptions.progress); + wco.buildOptions.progressType = defaultProgressType(wco.buildOptions.progressType); const webpackConfigs: {}[] = [ getCommonConfig(wco), diff --git a/packages/angular_devkit/build_angular/src/utils/default-progress.ts b/packages/angular_devkit/build_angular/src/utils/default-progress.ts index 258412b460f1..08c737edae9e 100644 --- a/packages/angular_devkit/build_angular/src/utils/default-progress.ts +++ b/packages/angular_devkit/build_angular/src/utils/default-progress.ts @@ -8,8 +8,17 @@ export function defaultProgress(progress: boolean | undefined): boolean { if (progress === undefined) { - return process.stdout.isTTY === true; + return true; } return progress; } + + +export function defaultProgressType(progressType: string | undefined): string { + if (progressType === undefined) { + return process.stdout.isTTY ? 'tty' : 'non-tty'; + } + + return progressType; +}