Skip to content

Commit

Permalink
[flutter_tools] inject output preferences at the top level (flutter#5…
Browse files Browse the repository at this point in the history
…8875)

The tool was setting the output preferences in a sub-context. Originally these were not injected before the arg parsers were created, though that was fixed by the lazy command creation. Once local engine is removed, the inner flutter_command Zone can be removed.
  • Loading branch information
jonahwilliams committed Jun 10, 2020
1 parent e7b4d2b commit dca6320
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 74 deletions.
8 changes: 7 additions & 1 deletion packages/flutter_tools/lib/executable.dart
Expand Up @@ -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';
Expand Down Expand Up @@ -135,6 +136,11 @@ Future<void> main(List<String> args) async {
stdio: globals.stdio,
terminal: globals.terminal,
outputPreferences: globals.outputPreferences,
))
)),
OutputPreferences: () => OutputPreferences.fromArguments(
args,
stdio: globals.stdio,
userMessages: globals.userMessages,
),
});
}
40 changes: 40 additions & 0 deletions packages/flutter_tools/lib/src/base/terminal.dart
Expand Up @@ -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,
Expand Down Expand Up @@ -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<String> 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<String> 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
Expand Down
27 changes: 0 additions & 27 deletions packages/flutter_tools/lib/src/runner/flutter_command_runner.dart
Expand Up @@ -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';
Expand Down Expand Up @@ -235,32 +234,6 @@ class FlutterCommandRunner extends CommandRunner<void> {
Future<void> runCommand(ArgResults topLevelResults) async {
final Map<Type, dynamic> contextOverrides = <Type, dynamic>{};

// 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;
Expand Down
120 changes: 120 additions & 0 deletions 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(
<String>[],
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(
<String>['--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(
<String>['--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(
<String>['--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(
<String>['--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(
<String>['--wrap-column=a'],
userMessages: userMessages,
stdio: stdio,
), throwsA(isA<ToolExit>()));
});

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(
<String>['--wrap-column='],
userMessages: userMessages,
stdio: stdio,
), throwsA(isA<ToolExit>()));
});
}

class MockUserMessage extends Mock implements UserMessages {}
class MockStdio extends Mock implements Stdio {}
Expand Up @@ -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(<String>['fake']);
expect(fakeCommand.preferences.wrapText, isTrue);
}, overrides: <Type, Generator>{
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(<String>['fake']);
expect(fakeCommand.preferences.wrapText, isFalse);
}, overrides: <Type, Generator>{
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(<String>['--no-wrap', 'fake']);
expect(fakeCommand.preferences.wrapText, isFalse);
}, overrides: <Type, Generator>{
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(<String>['--wrap', 'fake']);
expect(fakeCommand.preferences.wrapText, isTrue);
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
Stdio: () => FakeStdio(hasFakeTerminal: false),
}, initializeFlutterRoot: false);
});
});
}
class MockProcessManager extends Mock implements ProcessManager {}
Expand Down

0 comments on commit dca6320

Please sign in to comment.