Skip to content

Commit

Permalink
refactor: encapsulate log formatting in MelosLogger (#314)
Browse files Browse the repository at this point in the history
  • Loading branch information
blaugold authored Jun 8, 2022
1 parent 3e5807d commit ec808b0
Show file tree
Hide file tree
Showing 31 changed files with 518 additions and 335 deletions.
1 change: 1 addition & 0 deletions packages/melos/lib/melos.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export 'src/commands/runner.dart'
export 'src/common/exception.dart' show CancelledException, MelosException;
export 'src/common/validation.dart' show MelosConfigException;
export 'src/global_options.dart' show GlobalOptions;
export 'src/logging.dart' show MelosLogger, ToMelosLoggerExtension;
export 'src/package.dart' show Package, PackageFilter, PackageMap, PackageType;
export 'src/workspace.dart' show IdeWorkspace, MelosWorkspace;
export 'src/workspace_configs.dart'
Expand Down
4 changes: 3 additions & 1 deletion packages/melos/lib/src/command_runner/base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:cli_util/cli_logging.dart';
import '../common/glob.dart';
import '../common/utils.dart';
import '../global_options.dart';
import '../logging.dart';
import '../package.dart';
import '../workspace_configs.dart';

Expand All @@ -16,7 +17,8 @@ abstract class MelosCommand extends Command<void> {
/// The global Melos options parsed from the command line.
late final global = _parseGlobalOptions();

Logger? get logger => global.verbose ? Logger.verbose() : Logger.standard();
late final logger =
MelosLogger(global.verbose ? Logger.verbose() : Logger.standard());

/// The `melos.yaml` configuration for this command.
/// see [ArgParser.allowTrailingOptions]
Expand Down
4 changes: 2 additions & 2 deletions packages/melos/lib/src/command_runner/exec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ class ExecCommand extends MelosCommand {
final execArgs = argResults!.rest;

if (execArgs.isEmpty) {
logger?.stdout(description);
logger?.stdout(argParser.usage);
logger.log(description);
logger.log(argParser.usage);
exit(1);
}

Expand Down
6 changes: 2 additions & 4 deletions packages/melos/lib/src/command_runner/run.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
*
*/

import 'package:ansi_styles/ansi_styles.dart';

import '../commands/runner.dart';
import '../workspace_configs.dart';
import 'base.dart';
Expand Down Expand Up @@ -58,8 +56,8 @@ class RunCommand extends MelosCommand {
extraArgs: extraArgs,
);
} on NoPackageFoundScriptException catch (err) {
logger?.stderr(AnsiStyles.yellow(err.toString()));
logger?.stdout(usage);
logger.warning(err.toString(), label: false);
logger.log(usage);
}
}
}
6 changes: 2 additions & 4 deletions packages/melos/lib/src/command_runner/script.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
*
*/

import 'package:ansi_styles/ansi_styles.dart';

import '../commands/runner.dart';
import '../workspace_configs.dart';
import 'base.dart';
Expand Down Expand Up @@ -80,8 +78,8 @@ class ScriptCommand extends MelosCommand {
extraArgs: argResults!.rest,
);
} on NoPackageFoundScriptException catch (err) {
logger?.stderr(AnsiStyles.yellow(err.toString()));
logger?.stdout(usage);
logger.warning(err.toString(), label: false);
logger.log(usage);
}
}
}
32 changes: 14 additions & 18 deletions packages/melos/lib/src/command_runner/version.dart
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,10 @@ class VersionCommand extends MelosCommand {

if (argResults!.rest.isNotEmpty) {
if (argResults!.rest.length != 2) {
logger?.stdout(
'${AnsiStyles.redBright('ERROR:')} when manually setting a version to '
'apply to a package you must specify both <packageName> and <newVersion> '
'arguments when calling "melos version".',
logger.error(
'When manually setting a version to apply to a package you must '
'specify both <packageName> and <newVersion> arguments when calling '
'"melos version".',
);
exitCode = 1;
return;
Expand Down Expand Up @@ -200,18 +200,18 @@ class VersionCommand extends MelosCommand {
}

if (asPrerelease && asStableRelease) {
logger?.stdout(
'${AnsiStyles.yellow('WARNING:')} graduate & prerelease flags cannot '
'be combined. Versioning will continue with graduate off.',
logger.warning(
'graduate & prerelease flags cannot be combined. Versioning will '
'continue with graduate off.',
);
asStableRelease = false;
}

if (updateDependentsVersions && !updateDependentsConstraints) {
logger?.stdout(
'${AnsiStyles.yellow('WARNING:')} the setting --dependent-versions is '
'turned on but --dependent-constraints is turned off. Versioning '
'will continue with this setting turned off.',
logger.warning(
'The setting --dependent-versions is turned on but '
'--dependent-constraints is turned off. Versioning will continue '
'with this setting turned off.',
);
updateDependentsVersions = false;
}
Expand Down Expand Up @@ -255,10 +255,7 @@ class VersionCommand extends MelosCommand {
return ManualVersionChange(Version.parse(argument));
} catch (_) {
exitCode = 1;
logger?.stdout(
'${AnsiStyles.redBright('ERROR:')} version "$argument" is not a '
'valid package version.',
);
logger.error('version "$argument" is not a valid package version.');
return null;
}
}
Expand All @@ -272,9 +269,8 @@ class VersionCommand extends MelosCommand {
final parts = argument.split(':');
if (parts.length != 2) {
exitCode = 1;
logger?.stdout(
'${AnsiStyles.redBright('ERROR:')} --manual-version arguments must '
'be in the format '
logger.error(
'--manual-version arguments must be in the format '
'"<package name>:<major|patch|minor|build|exactVersion>".',
);
return null;
Expand Down
92 changes: 43 additions & 49 deletions packages/melos/lib/src/commands/bootstrap.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
part of 'runner.dart';

final _successLabel = AnsiStyles.green('SUCCESS');
final _warningLabel = AnsiStyles.yellow('WARNING');
final _checkLabel = AnsiStyles.greenBright('✓');

mixin _BootstrapMixin on _CleanMixin {
Future<void> bootstrap({GlobalOptions? global, PackageFilter? filter}) async {
final workspace = await createWorkspace(global: global, filter: filter);
Expand All @@ -20,17 +16,16 @@ mixin _BootstrapMixin on _CleanMixin {
'get'
].join(' ');

logger?.stdout(AnsiStyles.yellow.bold('melos bootstrap'));
logger?.stdout(' └> ${AnsiStyles.cyan.bold(workspace.path)}\n');
logger
..command('melos bootstrap')
..child(targetStyle(workspace.path))
..newLine();

logger?.stdout(
'Running "$pubCommandForLogging" in workspace packages...',
);
logger.log('Running "$pubCommandForLogging" in workspace packages...');
if (!utils.isCI && workspace.filteredPackages.keys.length > 20) {
logger?.stdout(
AnsiStyles.yellow(
'Note: this may take a while in large workspaces such as this one.',
),
logger.warning(
'Note: this may take a while in large workspaces such as this one.',
label: false,
);
}

Expand All @@ -45,20 +40,22 @@ mixin _BootstrapMixin on _CleanMixin {
rethrow;
}

logger?.stdout(' > $_successLabel');
logger.child(successLabel, prefix: '> ');

if (workspace.config.ide.intelliJ.enabled) {
logger?.stdout('');
logger?.stdout('Generating IntelliJ IDE files...');
logger
..newLine()
..log('Generating IntelliJ IDE files...');

await cleanIntelliJ(workspace);
await workspace.ide.intelliJ.generate();
logger?.stdout(' > $_successLabel');
logger.child(successLabel, prefix: '> ');
}

logger?.stdout(
'\n -> ${workspace.filteredPackages.length} packages bootstrapped',
);
logger
..newLine()
..log(
' -> ${workspace.filteredPackages.length} packages bootstrapped',
);
},
);
}
Expand All @@ -67,8 +64,8 @@ mixin _BootstrapMixin on _CleanMixin {
MelosWorkspace workspace,
) async {
if (!workspace.isPubspecOverridesSupported) {
logger?.stderr(
'$_warningLabel: Dart 2.17.0 or greater is required to use Melos with '
logger.warning(
'Dart 2.17.0 or greater is required to use Melos with '
'pubspec overrides.',
);
}
Expand All @@ -78,11 +75,7 @@ mixin _BootstrapMixin on _CleanMixin {
await _generatePubspecOverrides(workspace, package);
await _runPubGetForPackage(workspace, package);

logger?.stdout(
'''
$_checkLabel ${AnsiStyles.bold(package.name)}
└> ${AnsiStyles.blue(printablePath(package.pathRelativeToWorkspace))}''',
);
_logBootstrapSuccess(package);
},
parallelism: workspace.config.commands.bootstrap.runPubGetInParallel &&
workspace.canRunPubGetConcurrently
Expand Down Expand Up @@ -136,20 +129,18 @@ mixin _BootstrapMixin on _CleanMixin {
await _generateTemporaryProjects(workspace);

try {
// ignore: prefer_foreach
await for (final package in _runPubGet(workspace)) {
logger?.stdout(
'''
$_checkLabel ${AnsiStyles.bold(package.name)}
└> ${AnsiStyles.blue(printablePath(package.pathRelativeToWorkspace))}''',
);
_logBootstrapSuccess(package);
}
} catch (err) {
cleanWorkspace(workspace);
rethrow;
}

logger?.stdout('');
logger?.stdout('Linking workspace packages...');
logger
..newLine()
..log('Linking workspace packages...');

for (final package in workspace.filteredPackages.values) {
await package.linkPackages(workspace);
Expand Down Expand Up @@ -212,18 +203,18 @@ mixin _BootstrapMixin on _CleanMixin {

const logTimeout = Duration(seconds: 10);
final packagePrefix = '[${AnsiStyles.blue.bold(package.name)}]: ';
void Function(String) logLineTo(void Function(String)? log) =>
(line) => log?.call('$packagePrefix$line');
void Function(String) logLineTo(void Function(String) log) =>
(line) => log.call('$packagePrefix$line');

// We always fully consume stdout and stderr. This is required to prevent
// leaking resources and to ensure that the process exits.
final stdout = process.stdout.toStringAndLogAfterTimeout(
timeout: logTimeout,
log: logLineTo(logger?.stdout),
log: logLineTo(logger.stdout),
);
final stderr = process.stderr.toStringAndLogAfterTimeout(
timeout: logTimeout,
log: logLineTo(logger?.stderr),
log: logLineTo(logger.stderr),
);

final exitCode = await process.exitCode;
Expand All @@ -238,6 +229,12 @@ mixin _BootstrapMixin on _CleanMixin {
}
}

void _logBootstrapSuccess(Package package) {
logger.child(packageNameStyle(package.name), prefix: '$checkLabel ').child(
packagePathStyle(printablePath(package.pathRelativeToWorkspace)),
);
}

void _logBootstrapException(
BootstrapException exception,
MelosWorkspace workspace,
Expand Down Expand Up @@ -284,20 +281,17 @@ mixin _BootstrapMixin on _CleanMixin {
.toList()
.join('\n');

logger?.stdout(
'''
- ${AnsiStyles.bold.cyan(package.name)}
└> ${AnsiStyles.blue(printablePath(package.pathRelativeToWorkspace))}''',
);

logger?.stderr(' └> ${AnsiStyles.red(exception.message)}');
logger
.child(targetStyle(package.name), prefix: '- ')
.child(packagePathStyle(printablePath(package.pathRelativeToWorkspace)))
.child(errorMessageColor(exception.message), stderr: true)
.newLine();

logger?.stdout('');
if (processStdOutString != null) {
logger?.stdout(processStdOutString);
logger.stdout(processStdOutString);
}
if (processStdErrString != null) {
logger?.stderr(processStdErrString);
logger.stderr(processStdErrString);
}
}
}
Expand Down
12 changes: 7 additions & 5 deletions packages/melos/lib/src/commands/clean.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ mixin _CleanMixin on _Melos {
workspace,
ScriptLifecycle.clean,
() async {
logger?.stdout('Cleaning workspace...');
logger.log('Cleaning workspace...');

/// Cleans the workspace of all files generated by Melos.
cleanWorkspace(workspace);
Expand All @@ -17,10 +17,12 @@ mixin _CleanMixin on _Melos {

await cleanIntelliJ(workspace);

logger?.stdout(
'\nWorkspace cleaned. '
'You will need to run the bootstrap command again to use this workspace.',
);
logger
..newLine()
..log(
'Workspace cleaned. You will need to run the bootstrap command '
'again to use this workspace.',
);
},
);
}
Expand Down
Loading

0 comments on commit ec808b0

Please sign in to comment.