From d2864d68592b95a4f669a7736b8036e4abf0367c Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Mon, 16 Dec 2019 21:50:21 +0100 Subject: [PATCH] Support reading MoorOptions in CLI analyzer --- .../lib/src/backends/common/driver.dart | 7 ++- .../lib/src/backends/plugin/plugin.dart | 6 ++- .../lib/src/backends/standalone.dart | 8 ++- moor_generator/lib/src/cli/cli.dart | 38 +++++++++++++- .../src/cli/commands/identify_databases.dart | 14 ++--- moor_generator/lib/src/cli/logging.dart | 28 ++++++++++ moor_generator/lib/src/cli/project.dart | 51 +++++++++++++++++++ moor_generator/pubspec.yaml | 5 +- 8 files changed, 138 insertions(+), 19 deletions(-) create mode 100644 moor_generator/lib/src/cli/logging.dart create mode 100644 moor_generator/lib/src/cli/project.dart diff --git a/moor_generator/lib/src/backends/common/driver.dart b/moor_generator/lib/src/backends/common/driver.dart index caced42e..58bf5e46 100644 --- a/moor_generator/lib/src/backends/common/driver.dart +++ b/moor_generator/lib/src/backends/common/driver.dart @@ -7,6 +7,7 @@ import 'package:analyzer/src/dart/analysis/driver.dart'; import 'package:analyzer/src/dart/analysis/file_state.dart'; import 'package:analyzer/src/generated/source.dart' show SourceKind; import 'package:logging/logging.dart'; +import 'package:moor_generator/src/analyzer/options.dart'; import 'package:moor_generator/src/analyzer/runner/file_graph.dart'; import 'package:moor_generator/src/analyzer/session.dart'; @@ -29,10 +30,12 @@ class MoorDriver implements AnalysisDriverGeneric { StreamSubscription _taskCompleteSubscription; MoorDriver(this._tracker, this._scheduler, this.dartDriver, - this.contentOverlay, this._resourceProvider) { + this.contentOverlay, this._resourceProvider, + [MoorOptions options]) { _scheduler.add(this); final backend = CommonBackend(this); - session = MoorSession(backend); + + session = MoorSession(backend, options: options ?? const MoorOptions()); _fileChangeSubscription = session.changedFiles.listen(_tracker.notifyFilesChanged); diff --git a/moor_generator/lib/src/backends/plugin/plugin.dart b/moor_generator/lib/src/backends/plugin/plugin.dart index 34a1a33e..edc82078 100644 --- a/moor_generator/lib/src/backends/plugin/plugin.dart +++ b/moor_generator/lib/src/backends/plugin/plugin.dart @@ -20,6 +20,7 @@ import 'package:analyzer_plugin/utilities/folding/folding.dart'; import 'package:analyzer_plugin/utilities/highlights/highlights.dart'; import 'package:analyzer_plugin/utilities/navigation/navigation.dart'; import 'package:analyzer_plugin/utilities/outline/outline.dart'; +import 'package:moor_generator/src/analyzer/options.dart'; import 'package:moor_generator/src/analyzer/runner/file_graph.dart'; import 'package:moor_generator/src/backends/common/driver.dart'; import 'package:moor_generator/src/backends/common/file_tracker.dart'; @@ -67,7 +68,8 @@ class MoorPlugin extends ServerPlugin AnalysisDriverScheduler dartScheduler; @override - MoorDriver createAnalysisDriver(plugin.ContextRoot contextRoot) { + MoorDriver createAnalysisDriver(plugin.ContextRoot contextRoot, + {MoorOptions options}) { // create an analysis driver we can use to resolve Dart files final analyzerRoot = ContextRoot(contextRoot.root, contextRoot.exclude, pathContext: resourceProvider.pathContext) @@ -89,7 +91,7 @@ class MoorPlugin extends ServerPlugin final errorService = ErrorService(this); final driver = MoorDriver(tracker, analysisDriverScheduler, dartDriver, - fileContentOverlay, resourceProvider); + fileContentOverlay, resourceProvider, options); driver.completedFiles().where((file) => file.isParsed).listen((file) { sendNotificationsForFile(file.uri.path); diff --git a/moor_generator/lib/src/backends/standalone.dart b/moor_generator/lib/src/backends/standalone.dart index 0cb33888..3592b8d6 100644 --- a/moor_generator/lib/src/backends/standalone.dart +++ b/moor_generator/lib/src/backends/standalone.dart @@ -4,6 +4,7 @@ import 'package:analyzer/file_system/file_system.dart'; import 'package:analyzer/file_system/memory_file_system.dart'; import 'package:analyzer_plugin/protocol/protocol_generated.dart'; import 'package:cli_util/cli_util.dart'; +import 'package:moor_generator/src/analyzer/options.dart'; import 'package:moor_generator/src/backends/common/driver.dart'; import 'package:path/path.dart' as p; @@ -41,7 +42,10 @@ class StandaloneMoorAnalyzer { } } - MoorDriver createAnalysisDriver(String path) { - return _fakePlugin.createAnalysisDriver(ContextRoot(path, [])); + MoorDriver createAnalysisDriver(String path, {MoorOptions options}) { + return _fakePlugin.createAnalysisDriver( + ContextRoot(path, []), + options: options, + ); } } diff --git a/moor_generator/lib/src/cli/cli.dart b/moor_generator/lib/src/cli/cli.dart index 269cfa75..2730fe96 100644 --- a/moor_generator/lib/src/cli/cli.dart +++ b/moor_generator/lib/src/cli/cli.dart @@ -1,22 +1,31 @@ import 'dart:async'; +import 'dart:io'; import 'package:analyzer/file_system/physical_file_system.dart'; import 'package:args/command_runner.dart'; +import 'package:logging/logging.dart'; +import 'package:moor_generator/src/backends/common/driver.dart'; import 'package:moor_generator/src/backends/standalone.dart'; -import 'package:moor_generator/src/cli/commands/debug_plugin.dart'; +import 'package:moor_generator/src/cli/project.dart'; +import 'commands/debug_plugin.dart'; import 'commands/identify_databases.dart'; +import 'logging.dart'; Future run(List args) { final cli = MoorCli(); - return cli._runner.run(args); + return cli.run(args); } class MoorCli { final StandaloneMoorAnalyzer _analyzer; final Completer _analyzerReadyCompleter = Completer(); + Logger get logger => Logger.root; CommandRunner _runner; + MoorProject project; + + bool verbose; Future get analyzer async { await _analyzerReadyCompleter.future; @@ -32,8 +41,33 @@ class MoorCli { ..addCommand(IdentifyDatabases(this)) ..addCommand(DebugPluginCommand(this)); + _runner.argParser + .addFlag('verbose', abbr: 'v', defaultsTo: false, negatable: false); + _runner.argParser.addFlag( + 'ansi', + abbr: 'a', + help: 'Whether to output colorful logs. Attempts to check whether this ' + 'is supported by the terminal by default.', + ); + _analyzerReadyCompleter.complete(_analyzer.init()); } + + Future createMoorDriver() async { + final analyzer = await this.analyzer; + return analyzer.createAnalysisDriver(project.directory.path, + options: project.moorOptions); + } + + Future run(Iterable args) async { + final results = _runner.parse(args); + verbose = results['verbose'] as bool; + + setupLogging(verbose: verbose); + project = await MoorProject.readFromDir(Directory.current); + + await _runner.runCommand(results); + } } abstract class MoorCommand extends Command { diff --git a/moor_generator/lib/src/cli/commands/identify_databases.dart b/moor_generator/lib/src/cli/commands/identify_databases.dart index c67f368a..1dd012af 100644 --- a/moor_generator/lib/src/cli/commands/identify_databases.dart +++ b/moor_generator/lib/src/cli/commands/identify_databases.dart @@ -18,21 +18,17 @@ class IdentifyDatabases extends MoorCommand { @override Future run() async { - final analyzer = await cli.analyzer; final directory = Directory.current; print('Starting to scan in ${directory.path}...'); - final driver = analyzer.createAnalysisDriver(directory.path); + final driver = await cli.createMoorDriver(); - await for (final entity in directory.list(recursive: true)) { - if (entity is! File) continue; - - final file = entity as File; + await for (final file in cli.project.sourceFiles) { if (p.extension(file.path) != '.dart') continue; - print('scanning - $file'); + cli.logger.fine('Scanning $file'); - final parsed = await driver.waitFileParsed(entity.path); + final parsed = await driver.waitFileParsed(file.path); final result = parsed.currentResult as ParsedDartFile; // result can be null when we're running into a part of file @@ -45,7 +41,7 @@ class IdentifyDatabases extends MoorCommand { .map((t) => t.declaration.fromClass.name) .join(', '); - print('$displayName has moor databases or daos: $names'); + cli.logger.info('$displayName has moor databases or daos: $names'); } } } diff --git a/moor_generator/lib/src/cli/logging.dart b/moor_generator/lib/src/cli/logging.dart new file mode 100644 index 00000000..d523bf58 --- /dev/null +++ b/moor_generator/lib/src/cli/logging.dart @@ -0,0 +1,28 @@ +import 'package:cli_util/cli_logging.dart' as cli; +import 'package:logging/logging.dart' as log; + +void setupLogging({bool verbose = false, bool useAnsi}) { + final ansi = cli.Ansi(useAnsi ?? cli.Ansi.terminalSupportsAnsi); + final cliLogger = verbose + ? cli.Logger.verbose(ansi: ansi) + : cli.Logger.standard(ansi: ansi); + + log.Logger.root.onRecord.listen((rec) { + final level = rec.level; + final msgBuffer = StringBuffer(); + + msgBuffer..write(rec.level.name)..write(': ')..write(rec.message); + + if (rec.error != null) { + msgBuffer..write(rec.error)..write('\n')..write(rec.stackTrace); + } + + if (level <= log.Level.CONFIG) { + cliLogger.trace(msgBuffer.toString()); + } else if (level <= log.Level.INFO) { + cliLogger.stdout(msgBuffer.toString()); + } else { + cliLogger.stderr(msgBuffer.toString()); + } + }); +} diff --git a/moor_generator/lib/src/cli/project.dart b/moor_generator/lib/src/cli/project.dart new file mode 100644 index 00000000..f3cd8898 --- /dev/null +++ b/moor_generator/lib/src/cli/project.dart @@ -0,0 +1,51 @@ +import 'dart:io'; + +import 'package:build_config/build_config.dart'; +import 'package:moor_generator/src/analyzer/options.dart'; +import 'package:path/path.dart' as p; +import 'package:stream_transform/stream_transform.dart'; + +/// A project using moor. This is typically a dart project with a dependency on +/// moor and moor_generator. +class MoorProject { + /// The build configuration for this project. + final BuildConfig buildConfig; + final MoorOptions moorOptions; + + final Directory directory; + + MoorProject(this.buildConfig, this.directory) + : moorOptions = _readOptions(buildConfig); + + Stream get sourceFiles { + const topLevelDirs = {'lib', 'test', 'bin', 'example'}; + + return directory.list().asyncExpand((entity) { + // report all top-level files and all (recursive) content in topLevelDirs + if (entity is File) { + return Stream.value(entity); + } else if (entity is Directory) { + if (topLevelDirs.contains(p.basename(entity.path))) { + return entity.list(recursive: true); + } + } + return const Stream.empty(); + }).whereType(); + } + + static MoorOptions _readOptions(BuildConfig config) { + final options = config.buildTargets.values + .map((t) => t.builders['moor_generator:moor_generator']?.options) + .where((t) => t != null) + .map((json) => MoorOptions.fromJson(json)); + + final iterator = options.iterator; + return iterator.moveNext() ? iterator.current : const MoorOptions(); + } + + static Future readFromDir(Directory directory) async { + final config = await BuildConfig.fromPackageDir(directory.path); + + return MoorProject(config, directory); + } +} diff --git a/moor_generator/pubspec.yaml b/moor_generator/pubspec.yaml index fa62c5e6..5fd4ed76 100644 --- a/moor_generator/pubspec.yaml +++ b/moor_generator/pubspec.yaml @@ -16,11 +16,13 @@ dependencies: recase: ^2.0.1 meta: ^1.1.0 path: ^1.6.0 - logging: '>=0.11.0 <1.0.0' json_annotation: ^3.0.0 + stream_transform: '>=0.0.20 <2.0.0' # CLI args: ^1.5.0 + logging: '>=0.11.0 <1.0.0' + cli_util: ^0.1.0 # Moor-specific analysis moor: ^2.0.1 @@ -30,7 +32,6 @@ dependencies: analyzer: '>=0.36.4 <0.40.0' analyzer_plugin: '>=0.1.0 <0.3.0' source_span: ^1.5.5 - cli_util: ^0.1.0 # Used to locate the Dart SDK # Build system build: ^1.1.0