diff --git a/lib/src/executable.dart b/lib/src/executable.dart index 7a1e9e3b..651b7f1f 100644 --- a/lib/src/executable.dart +++ b/lib/src/executable.dart @@ -4,50 +4,42 @@ import 'dart:io'; import 'package:analyzer/dart/analysis/utilities.dart'; import 'package:args/command_runner.dart'; import 'package:dart_dev/dart_dev.dart'; -import 'package:dart_dev/src/dart_dev_tool.dart'; -import 'package:dart_dev/src/utils/format_tool_builder.dart'; -import 'package:dart_dev/src/utils/parse_flag_from_args.dart'; import 'package:io/ansi.dart'; import 'package:io/io.dart' show ExitCode; import 'package:logging/logging.dart'; import 'package:path/path.dart' as p; -import '../utils.dart'; import 'dart_dev_runner.dart'; import 'tools/over_react_format_tool.dart'; import 'utils/assert_dir_is_dart_package.dart'; +import 'utils/cached_pubspec.dart'; +import 'utils/dart_dev_paths.dart'; import 'utils/dart_tool_cache.dart'; import 'utils/ensure_process_exit.dart'; +import 'utils/format_tool_builder.dart'; import 'utils/logging.dart'; +import 'utils/parse_flag_from_args.dart'; typedef _ConfigGetter = Map Function(); -final _runScriptPath = p.join(cacheDirPath, 'run.dart'); +final paths = DartDevPaths(); -final _runScript = File(_runScriptPath); - -const _configPath = 'tool/dart_dev/config.dart'; - -const _oldDevDartPath = 'tool/dev.dart'; - -final _relativeDevDartPath = p.relative( - p.absolute(_configPath), - from: p.absolute(p.dirname(_runScriptPath)), -); +final _runScript = File(paths.runScript); Future run(List args) async { attachLoggerToStdio(args); - final configExists = File(_configPath).existsSync(); - final oldDevDartExists = File(_oldDevDartPath).existsSync(); + + final configExists = File(paths.config).existsSync(); + final oldDevDartExists = File(paths.legacyConfig).existsSync(); if (!configExists) { - log.fine('No custom `tool/dart_dev/config.dart` file found; ' + log.fine('No custom `${paths.config}` file found; ' 'using default config.'); } if (oldDevDartExists) { log.warning(yellow.wrap( - 'dart_dev v3 now expects configuration to be at `$_configPath`,\n' - 'but `$_oldDevDartPath` still exists. View the guide to see how to upgrade:\n' + 'dart_dev v3 now expects configuration to be at `${paths.config}`,\n' + 'but `${paths.legacyConfig}` still exists. View the guide to see how to upgrade:\n' 'https://github.com/Workiva/dart_dev/blob/master/doc/v3-upgrade-guide.md')); } @@ -59,7 +51,7 @@ Future run(List args) async { generateRunScript(); final process = await Process.start( - Platform.executable, [_runScriptPath, ...args], + Platform.executable, [paths.runScript, ...args], mode: ProcessStartMode.inheritStdio); ensureProcessExit(process); exitCode = await process.exitCode; @@ -69,7 +61,7 @@ Future handleFastFormat(List args) async { assertDirIsDartPackage(); DevTool formatTool; - final configFile = File(_configPath); + final configFile = File(paths.config); if (configFile.existsSync()) { final toolBuilder = FormatToolBuilder(); parseString(content: configFile.readAsStringSync()) @@ -115,13 +107,13 @@ bool get shouldWriteRunScript => _runScript.readAsStringSync() != buildDartDevRunScriptContents(); String buildDartDevRunScriptContents() { - final hasCustomToolDevDart = File(_configPath).existsSync(); + final hasCustomToolDevDart = File(paths.config).existsSync(); return ''' import 'dart:io'; import 'package:dart_dev/src/core_config.dart'; import 'package:dart_dev/src/executable.dart' as executable; -${hasCustomToolDevDart ? "import '$_relativeDevDartPath' as custom_dev;" : ""} +${hasCustomToolDevDart ? "import '${paths.configFromRunScriptForDart}' as custom_dev;" : ""} void main(List args) async { await executable.runWithConfig(args, @@ -146,8 +138,7 @@ Future runWithConfig( config = configGetter(); } catch (error) { stderr - ..writeln( - 'Invalid "tool/dart_dev/config.dart" in ${p.absolute(p.current)}') + ..writeln('Invalid "${paths.config}" in ${p.absolute(p.current)}') ..writeln() ..writeln('It should provide a `Map config;` getter,' ' but it either does not exist or threw unexpectedly:') diff --git a/lib/src/tools/analyze_tool.dart b/lib/src/tools/analyze_tool.dart index 43188a86..57007a80 100644 --- a/lib/src/tools/analyze_tool.dart +++ b/lib/src/tools/analyze_tool.dart @@ -8,6 +8,7 @@ import 'package:logging/logging.dart'; import '../dart_dev_tool.dart'; import '../utils/arg_results_utils.dart'; import '../utils/assert_no_positional_args_nor_args_after_separator.dart'; +import '../utils/executables.dart' as exe; import '../utils/logging.dart'; import '../utils/process_declaration.dart'; import '../utils/run_process_and_ensure_exit.dart'; @@ -161,7 +162,7 @@ ProcessDeclaration buildProcess( verbose: context.verbose); final entrypoints = buildEntrypoints(include: include, root: path); logCommand(args, entrypoints, verbose: context.verbose); - return ProcessDeclaration('dartanalyzer', [...args, ...entrypoints], + return ProcessDeclaration(exe.dartanalyzer, [...args, ...entrypoints], mode: ProcessStartMode.inheritStdio); } diff --git a/lib/src/tools/format_tool.dart b/lib/src/tools/format_tool.dart index 4f1d5375..048f8675 100644 --- a/lib/src/tools/format_tool.dart +++ b/lib/src/tools/format_tool.dart @@ -12,6 +12,7 @@ import '../../utils.dart'; import '../dart_dev_tool.dart'; import '../utils/arg_results_utils.dart'; import '../utils/assert_no_positional_args_nor_args_after_separator.dart'; +import '../utils/executables.dart' as exe; import '../utils/logging.dart'; import '../utils/organize_directives/organize_directives_in_paths.dart'; import '../utils/package_is_immediate_dependency.dart'; @@ -537,10 +538,10 @@ FormatExecution buildExecution( ProcessDeclaration buildFormatProcess([Formatter formatter]) { switch (formatter) { case Formatter.dartStyle: - return ProcessDeclaration('pub', ['run', 'dart_style:format']); + return ProcessDeclaration(exe.pub, ['run', 'dart_style:format']); case Formatter.dartfmt: default: - return ProcessDeclaration('dartfmt', []); + return ProcessDeclaration(exe.dartfmt, []); } } diff --git a/lib/src/tools/over_react_format_tool.dart b/lib/src/tools/over_react_format_tool.dart index f9899d1b..2951a7b7 100644 --- a/lib/src/tools/over_react_format_tool.dart +++ b/lib/src/tools/over_react_format_tool.dart @@ -5,6 +5,7 @@ import 'package:dart_dev/dart_dev.dart'; import 'package:dart_dev/utils.dart'; import '../tools/format_tool.dart'; +import '../utils/executables.dart' as exe; class OverReactFormatTool extends DevTool { /// Wrap lines longer than this. @@ -31,9 +32,9 @@ class OverReactFormatTool extends DevTool { 'over_react_format', if (lineLength != null) '--line-length=$lineLength' ]; - final process = ProcessDeclaration('pub', [...args, ...paths], + final process = ProcessDeclaration(exe.pub, [...args, ...paths], mode: ProcessStartMode.inheritStdio); - logCommand('pub', paths, args, verbose: context?.verbose); + logCommand(exe.pub, paths, args, verbose: context?.verbose); return runProcessAndEnsureExit(process); } } diff --git a/lib/src/tools/test_tool.dart b/lib/src/tools/test_tool.dart index f621eda8..45d06da8 100644 --- a/lib/src/tools/test_tool.dart +++ b/lib/src/tools/test_tool.dart @@ -9,6 +9,7 @@ import 'package:logging/logging.dart'; import '../dart_dev_tool.dart'; import '../utils/arg_results_utils.dart'; +import '../utils/executables.dart' as exe; import '../utils/logging.dart'; import '../utils/package_is_immediate_dependency.dart'; import '../utils/process_declaration.dart'; @@ -315,7 +316,7 @@ TestExecution buildExecution( verbose: context.verbose); logSubprocessHeader(_log, 'pub ${args.join(' ')}'.trim()); return TestExecution.process( - ProcessDeclaration('pub', args, mode: ProcessStartMode.inheritStdio)); + ProcessDeclaration(exe.pub, args, mode: ProcessStartMode.inheritStdio)); } // NOTE: This currently depends on https://github.com/dart-lang/build/pull/2445 diff --git a/lib/src/tools/tuneup_check_tool.dart b/lib/src/tools/tuneup_check_tool.dart index 2af9e304..fa5206d8 100644 --- a/lib/src/tools/tuneup_check_tool.dart +++ b/lib/src/tools/tuneup_check_tool.dart @@ -9,6 +9,7 @@ import 'package:logging/logging.dart'; import '../dart_dev_tool.dart'; import '../utils/arg_results_utils.dart'; import '../utils/assert_no_positional_args_nor_args_after_separator.dart'; +import '../utils/executables.dart' as exe; import '../utils/logging.dart'; import '../utils/package_is_immediate_dependency.dart'; import '../utils/process_declaration.dart'; @@ -152,5 +153,5 @@ TuneupExecution buildExecution( verbose: context.verbose); logSubprocessHeader(_log, 'pub ${args.join(' ')}'); return TuneupExecution.process( - ProcessDeclaration('pub', args, mode: ProcessStartMode.inheritStdio)); + ProcessDeclaration(exe.pub, args, mode: ProcessStartMode.inheritStdio)); } diff --git a/lib/src/tools/webdev_serve_tool.dart b/lib/src/tools/webdev_serve_tool.dart index 69f3ba4f..dfabc339 100644 --- a/lib/src/tools/webdev_serve_tool.dart +++ b/lib/src/tools/webdev_serve_tool.dart @@ -10,6 +10,7 @@ import 'package:pub_semver/pub_semver.dart'; import '../dart_dev_tool.dart'; import '../utils/arg_results_utils.dart'; import '../utils/assert_no_positional_args_nor_args_after_separator.dart'; +import '../utils/executables.dart' as exe; import '../utils/global_package_is_active_and_compatible.dart'; import '../utils/logging.dart'; import '../utils/process_declaration.dart'; @@ -226,5 +227,5 @@ WebdevServeExecution buildExecution( verbose: context.verbose); logSubprocessHeader(_log, 'pub ${args.join(' ')}'.trim()); return WebdevServeExecution.process( - ProcessDeclaration('pub', args, mode: ProcessStartMode.inheritStdio)); + ProcessDeclaration(exe.pub, args, mode: ProcessStartMode.inheritStdio)); } diff --git a/lib/src/utils/dart_dev_paths.dart b/lib/src/utils/dart_dev_paths.dart new file mode 100644 index 00000000..6d83a038 --- /dev/null +++ b/lib/src/utils/dart_dev_paths.dart @@ -0,0 +1,31 @@ +import 'package:path/path.dart' as p; + +/// A collection of paths to files and directories constructed to be compatible +/// with a given [p.Context]. +class DartDevPaths { + final p.Context _context; + + DartDevPaths({p.Context context}) : _context = context ?? p.context; + + String cache([String subPath]) => _context.normalize( + _context.joinAll([..._cacheParts, if (subPath != null) subPath])); + + String get _cacheForDart => p.url.joinAll(_cacheParts); + + final List _cacheParts = ['.dart_tool', 'dart_dev']; + + String get config => _context.joinAll(_configParts); + + String get configForDart => p.url.joinAll(_configParts); + + final List _configParts = ['tool', 'dart_dev', 'config.dart']; + + String get configFromRunScriptForDart => p.url.relative( + p.url.absolute(configForDart), + from: p.url.absolute(_cacheForDart), + ); + + String get legacyConfig => _context.join('tool', 'dev.dart'); + + String get runScript => cache('run.dart'); +} diff --git a/lib/src/utils/dart_tool_cache.dart b/lib/src/utils/dart_tool_cache.dart index 00a6772b..21d05a00 100644 --- a/lib/src/utils/dart_tool_cache.dart +++ b/lib/src/utils/dart_tool_cache.dart @@ -1,15 +1,9 @@ import 'dart:io'; -import 'package:path/path.dart' as p; - -const cacheDirPath = '.dart_tool/dart_dev'; +import 'package:dart_dev/src/utils/dart_dev_paths.dart'; void createCacheDir({String subPath}) { - var path = cacheDirPath; - if (subPath != null) { - path = p.join(path, subPath); - } - final dir = Directory(path); + final dir = Directory(DartDevPaths().cache(subPath)); if (!dir.existsSync()) { dir.createSync(recursive: true); } diff --git a/lib/src/utils/executables.dart b/lib/src/utils/executables.dart new file mode 100644 index 00000000..7a5bac6d --- /dev/null +++ b/lib/src/utils/executables.dart @@ -0,0 +1,9 @@ +import 'dart:io'; + +final dart = 'dart'; + +final dartanalyzer = Platform.isWindows ? 'dartanalyzer.bat' : 'dartanalyzer'; + +final dartfmt = Platform.isWindows ? 'dartfmt.bat' : 'dartfmt'; + +final pub = Platform.isWindows ? 'pub.bat' : 'pub'; diff --git a/lib/src/utils/global_package_is_active_and_compatible.dart b/lib/src/utils/global_package_is_active_and_compatible.dart index 600187ea..33cb4ff2 100644 --- a/lib/src/utils/global_package_is_active_and_compatible.dart +++ b/lib/src/utils/global_package_is_active_and_compatible.dart @@ -3,6 +3,8 @@ import 'dart:io'; import 'package:pub_semver/pub_semver.dart'; +import 'executables.dart' as exe; + /// Returns `true` if [packageName] is globally activated at a version /// allowed by [constraint]. Returns `false` otherwise. /// @@ -16,9 +18,9 @@ import 'package:pub_semver/pub_semver.dart'; bool globalPackageIsActiveAndCompatible( String packageName, VersionConstraint constraint, {Map environment}) { - final executable = 'pub'; + final executable = exe.pub; final args = ['global', 'list']; - final result = Process.runSync('pub', ['global', 'list'], + final result = Process.runSync(exe.pub, ['global', 'list'], environment: environment, stderrEncoding: utf8, stdoutEncoding: utf8); if (result.exitCode != 0) { throw ProcessException( diff --git a/test/utils/dart_dev_paths_test.dart b/test/utils/dart_dev_paths_test.dart new file mode 100644 index 00000000..c64f7c2b --- /dev/null +++ b/test/utils/dart_dev_paths_test.dart @@ -0,0 +1,73 @@ +import 'package:dart_dev/src/utils/dart_dev_paths.dart'; +import 'package:path/path.dart' as p; +import 'package:test/test.dart'; + +void main() { + group('DartDevPaths', () { + group('posix', () { + DartDevPaths paths; + + setUp(() { + paths = DartDevPaths(context: p.posix); + }); + + test('cache', () { + expect(paths.cache(), '.dart_tool/dart_dev'); + }); + + test('cache with subpath', () { + expect(paths.cache('sub/path'), '.dart_tool/dart_dev/sub/path'); + }); + + test('config', () { + expect(paths.config, 'tool/dart_dev/config.dart'); + }); + + test('configFromRunScriptForDart', () { + expect(paths.configFromRunScriptForDart, + '../../tool/dart_dev/config.dart'); + }); + + test('legacyConfig', () { + expect(paths.legacyConfig, 'tool/dev.dart'); + }); + + test('runScript', () { + expect(paths.runScript, '.dart_tool/dart_dev/run.dart'); + }); + }); + + group('windows', () { + DartDevPaths paths; + + setUp(() { + paths = DartDevPaths(context: p.windows); + }); + + test('cache', () { + expect(paths.cache(), r'.dart_tool\dart_dev'); + }); + + test('cache with subpath', () { + expect(paths.cache('sub/path'), r'.dart_tool\dart_dev\sub\path'); + }); + + test('config', () { + expect(paths.config, r'tool\dart_dev\config.dart'); + }); + + test('configFromRunScriptForDart', () { + expect(paths.configFromRunScriptForDart, + r'../../tool/dart_dev/config.dart'); + }); + + test('legacyConfig', () { + expect(paths.legacyConfig, r'tool\dev.dart'); + }); + + test('runScript', () { + expect(paths.runScript, r'.dart_tool\dart_dev\run.dart'); + }); + }); + }); +}