diff --git a/packages/flutter_tools/lib/executable.dart b/packages/flutter_tools/lib/executable.dart index 194ef5cef2c..4d7885c5167 100644 --- a/packages/flutter_tools/lib/executable.dart +++ b/packages/flutter_tools/lib/executable.dart @@ -11,6 +11,7 @@ import 'src/base/template.dart'; // The build_runner code generation is provided here to make it easier to // avoid introducing the dependency into google3. Not all build* packages // are synced internally. +import 'src/base/terminal.dart'; import 'src/build_runner/build_runner.dart'; import 'src/build_runner/mustache_template.dart'; import 'src/build_runner/resident_web_runner.dart'; @@ -135,6 +136,11 @@ Future main(List args) async { stdio: globals.stdio, terminal: globals.terminal, outputPreferences: globals.outputPreferences, - )) + )), + OutputPreferences: () => OutputPreferences.fromArguments( + args, + stdio: globals.stdio, + userMessages: globals.userMessages, + ), }); } diff --git a/packages/flutter_tools/lib/src/base/terminal.dart b/packages/flutter_tools/lib/src/base/terminal.dart index bdabd7febad..c0f2fb8ad03 100644 --- a/packages/flutter_tools/lib/src/base/terminal.dart +++ b/packages/flutter_tools/lib/src/base/terminal.dart @@ -8,9 +8,12 @@ import 'package:meta/meta.dart'; import '../convert.dart'; import '../globals.dart' as globals; +import 'common.dart'; import 'io.dart' as io; +import 'io.dart'; import 'logger.dart'; import 'platform.dart'; +import 'user_messages.dart'; enum TerminalColor { red, @@ -47,6 +50,43 @@ class OutputPreferences { OutputPreferences.test({this.wrapText = false, int wrapColumn = kDefaultTerminalColumns, this.showColor = false}) : _overrideWrapColumn = wrapColumn; + /// Create an [OutputPreferences] from a list of command line arguments. + static OutputPreferences fromArguments(List topLevelResults, { + @required UserMessages userMessages, + @required Stdio stdio, + }) { + // Don't set wrapColumns unless the user said to: if it's set, then all + // wrapping will occur at this width explicitly, and won't adapt if the + // terminal size changes during a run. + int wrapColumn; + final String rawWrapColumn = topLevelResults + .firstWhere((String line) => line.startsWith('--wrap-column='), orElse: () => null); + if (rawWrapColumn != null) { + final List parts = rawWrapColumn.split('='); + if (parts.length > 1) { + wrapColumn = int.tryParse(parts[1]); + } + if (wrapColumn == null) { + throwToolExit(userMessages.runnerWrapColumnInvalid(rawWrapColumn)); + } + } + + // If we're not writing to a terminal with a defined width, then don't wrap + // anything, unless the user explicitly said to. + final bool useWrapping = !topLevelResults.contains('--no-wrap'); + + // If no default width was provided, first default to the terminal width. If + // that is null, use `kDefaultTerminalColumns`. + if (useWrapping && wrapColumn == null) { + wrapColumn = stdio.terminalColumns ?? kDefaultTerminalColumns; + } + return OutputPreferences( + wrapText: useWrapping, + showColor: !topLevelResults.contains('--no-color'), + wrapColumn: wrapColumn, + ); + } + /// If [wrapText] is true, then any text sent to the context's [Logger] /// instance (e.g. from the [printError] or [printStatus] functions) will be /// wrapped (newlines added between words) to be no longer than the diff --git a/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart b/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart index 21be933e103..66e1c6accdc 100644 --- a/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart +++ b/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart @@ -15,7 +15,6 @@ import '../artifacts.dart'; import '../base/common.dart'; import '../base/context.dart'; import '../base/file_system.dart'; -import '../base/terminal.dart'; import '../base/user_messages.dart'; import '../base/utils.dart'; import '../cache.dart'; @@ -235,32 +234,6 @@ class FlutterCommandRunner extends CommandRunner { Future runCommand(ArgResults topLevelResults) async { final Map contextOverrides = {}; - // Don't set wrapColumns unless the user said to: if it's set, then all - // wrapping will occur at this width explicitly, and won't adapt if the - // terminal size changes during a run. - int wrapColumn; - if (topLevelResults.wasParsed('wrap-column')) { - try { - wrapColumn = int.parse(topLevelResults['wrap-column'] as String); - if (wrapColumn < 0) { - throwToolExit(userMessages.runnerWrapColumnInvalid(topLevelResults['wrap-column'])); - } - } on FormatException { - throwToolExit(userMessages.runnerWrapColumnParseError(topLevelResults['wrap-column'])); - } - } - - // If we're not writing to a terminal with a defined width, then don't wrap - // anything, unless the user explicitly said to. - final bool useWrapping = topLevelResults.wasParsed('wrap') - ? topLevelResults['wrap'] as bool - : globals.stdio.terminalColumns != null && topLevelResults['wrap'] as bool; - contextOverrides[OutputPreferences] = OutputPreferences( - wrapText: useWrapping, - showColor: topLevelResults['color'] as bool, - wrapColumn: wrapColumn, - ); - if (topLevelResults['show-test-device'] as bool || topLevelResults['device-id'] == FlutterTesterDevices.kTesterDeviceId) { FlutterTesterDevices.showFlutterTesterDevice = true; diff --git a/packages/flutter_tools/test/general.shard/output_preferences_test.dart b/packages/flutter_tools/test/general.shard/output_preferences_test.dart new file mode 100644 index 00000000000..fe0d1bafb4f --- /dev/null +++ b/packages/flutter_tools/test/general.shard/output_preferences_test.dart @@ -0,0 +1,120 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_tools/src/base/common.dart'; +import 'package:flutter_tools/src/base/io.dart'; +import 'package:flutter_tools/src/base/terminal.dart'; +import 'package:flutter_tools/src/base/user_messages.dart'; +import 'package:mockito/mockito.dart'; + +import '../src/common.dart'; + +void main() { + testWithoutContext('Defaults to a wrapped terminal columns with color if no ' + 'args are provided', () { + final MockUserMessage userMessages = MockUserMessage(); + final MockStdio stdio = MockStdio(); + when(stdio.terminalColumns).thenReturn(80); + + final OutputPreferences preferences = OutputPreferences.fromArguments( + [], + userMessages: userMessages, + stdio: stdio, + ); + + expect(preferences.showColor, true); + expect(preferences.wrapText, true); + expect(preferences.wrapColumn, 80); + }); + + testWithoutContext('Can be configured with --no-color', () { + final MockUserMessage userMessages = MockUserMessage(); + final MockStdio stdio = MockStdio(); + when(stdio.terminalColumns).thenReturn(80); + + final OutputPreferences preferences = OutputPreferences.fromArguments( + ['--no-color'], + userMessages: userMessages, + stdio: stdio, + ); + + expect(preferences.showColor, false); + expect(preferences.wrapText, true); + expect(preferences.wrapColumn, 80); + }); + + testWithoutContext('Can be configured with a specific wrap length', () { + final MockUserMessage userMessages = MockUserMessage(); + final MockStdio stdio = MockStdio(); + when(stdio.terminalColumns).thenReturn(80); + + final OutputPreferences preferences = OutputPreferences.fromArguments( + ['--wrap-column=123'], + userMessages: userMessages, + stdio: stdio, + ); + + expect(preferences.showColor, true); + expect(preferences.wrapText, true); + expect(preferences.wrapColumn, 123); + }); + + testWithoutContext('Will wrap to 100 when there is no terminal columns available', () { + final MockUserMessage userMessages = MockUserMessage(); + final MockStdio stdio = MockStdio(); + when(stdio.terminalColumns).thenReturn(null); + + final OutputPreferences preferences = OutputPreferences.fromArguments( + ['--wrap'], + userMessages: userMessages, + stdio: stdio, + ); + + expect(preferences.showColor, true); + expect(preferences.wrapText, true); + expect(preferences.wrapColumn, 100); + }); + + testWithoutContext('Can be configured to disable wrapping', () { + final MockUserMessage userMessages = MockUserMessage(); + final MockStdio stdio = MockStdio(); + when(stdio.terminalColumns).thenReturn(80); + + final OutputPreferences preferences = OutputPreferences.fromArguments( + ['--no-wrap'], + userMessages: userMessages, + stdio: stdio, + ); + + expect(preferences.showColor, true); + expect(preferences.wrapText, false); + }); + + testWithoutContext('Throws a tool exit when an invalid wrap number is given', () { + final MockUserMessage userMessages = MockUserMessage(); + final MockStdio stdio = MockStdio(); + when(stdio.terminalColumns).thenReturn(80); + + expect(() => OutputPreferences.fromArguments( + ['--wrap-column=a'], + userMessages: userMessages, + stdio: stdio, + ), throwsA(isA())); + }); + + testWithoutContext('Throws a tool exit when wrap is given without a number', () { + final MockUserMessage userMessages = MockUserMessage(); + final MockStdio stdio = MockStdio(); + when(stdio.terminalColumns).thenReturn(80); + + expect(() => OutputPreferences.fromArguments( + ['--wrap-column='], + userMessages: userMessages, + stdio: stdio, + ), throwsA(isA())); + }); +} + +class MockUserMessage extends Mock implements UserMessages {} +class MockStdio extends Mock implements Stdio {} diff --git a/packages/flutter_tools/test/general.shard/runner/flutter_command_runner_test.dart b/packages/flutter_tools/test/general.shard/runner/flutter_command_runner_test.dart index 13655aa848c..c6ffa5d86fd 100644 --- a/packages/flutter_tools/test/general.shard/runner/flutter_command_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/runner/flutter_command_runner_test.dart @@ -239,52 +239,6 @@ void main() { Platform: () => platform, }, initializeFlutterRoot: false); }); - - group('wrapping', () { - testUsingContext('checks that output wrapping is turned on when writing to a terminal', () async { - final FakeFlutterCommand fakeCommand = FakeFlutterCommand(); - runner.addCommand(fakeCommand); - await runner.run(['fake']); - expect(fakeCommand.preferences.wrapText, isTrue); - }, overrides: { - FileSystem: () => fs, - ProcessManager: () => FakeProcessManager.any(), - Stdio: () => FakeStdio(hasFakeTerminal: true), - }, initializeFlutterRoot: false); - - testUsingContext('checks that output wrapping is turned off when not writing to a terminal', () async { - final FakeFlutterCommand fakeCommand = FakeFlutterCommand(); - runner.addCommand(fakeCommand); - await runner.run(['fake']); - expect(fakeCommand.preferences.wrapText, isFalse); - }, overrides: { - FileSystem: () => fs, - ProcessManager: () => FakeProcessManager.any(), - Stdio: () => FakeStdio(hasFakeTerminal: false), - }, initializeFlutterRoot: false); - - testUsingContext('checks that output wrapping is turned off when set on the command line and writing to a terminal', () async { - final FakeFlutterCommand fakeCommand = FakeFlutterCommand(); - runner.addCommand(fakeCommand); - await runner.run(['--no-wrap', 'fake']); - expect(fakeCommand.preferences.wrapText, isFalse); - }, overrides: { - FileSystem: () => fs, - ProcessManager: () => FakeProcessManager.any(), - Stdio: () => FakeStdio(hasFakeTerminal: true), - }, initializeFlutterRoot: false); - - testUsingContext('checks that output wrapping is turned on when set on the command line, but not writing to a terminal', () async { - final FakeFlutterCommand fakeCommand = FakeFlutterCommand(); - runner.addCommand(fakeCommand); - await runner.run(['--wrap', 'fake']); - expect(fakeCommand.preferences.wrapText, isTrue); - }, overrides: { - FileSystem: () => fs, - ProcessManager: () => FakeProcessManager.any(), - Stdio: () => FakeStdio(hasFakeTerminal: false), - }, initializeFlutterRoot: false); - }); }); } class MockProcessManager extends Mock implements ProcessManager {}