[flutter_tool] New command project (#102118)
This commit is contained in:
parent
2bac06e73e
commit
780a6c422b
101
packages/flutter_tools/lib/src/commands/validate_project.dart
Normal file
101
packages/flutter_tools/lib/src/commands/validate_project.dart
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
// 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 '../base/file_system.dart';
|
||||||
|
import '../base/logger.dart';
|
||||||
|
import '../project.dart';
|
||||||
|
import '../project_validator.dart';
|
||||||
|
import '../project_validator_result.dart';
|
||||||
|
import '../runner/flutter_command.dart';
|
||||||
|
|
||||||
|
class ValidateProjectCommand extends FlutterCommand {
|
||||||
|
ValidateProjectCommand({
|
||||||
|
required this.fileSystem,
|
||||||
|
required this.logger,
|
||||||
|
required this.allProjectValidators,
|
||||||
|
this.verbose = false
|
||||||
|
});
|
||||||
|
|
||||||
|
final FileSystem fileSystem;
|
||||||
|
final Logger logger;
|
||||||
|
final bool verbose;
|
||||||
|
final List<ProjectValidator> allProjectValidators;
|
||||||
|
|
||||||
|
@override
|
||||||
|
final String name = 'validate-project';
|
||||||
|
|
||||||
|
@override
|
||||||
|
final String description = 'Show information about the current project.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
final String category = FlutterCommandCategory.project;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<FlutterCommandResult> runCommand() async {
|
||||||
|
final String userPath = getUserPath();
|
||||||
|
final Directory workingDirectory = userPath.isEmpty ? fileSystem.currentDirectory : fileSystem.directory(userPath);
|
||||||
|
|
||||||
|
final FlutterProject project = FlutterProject.fromDirectory(workingDirectory);
|
||||||
|
final Map<ProjectValidator, Future<List<ProjectValidatorResult>>> results = <ProjectValidator, Future<List<ProjectValidatorResult>>>{};
|
||||||
|
|
||||||
|
bool hasCrash = false;
|
||||||
|
for (final ProjectValidator validator in allProjectValidators) {
|
||||||
|
if (!results.containsKey(validator) && validator.supportsProject(project)) {
|
||||||
|
results[validator] = validator.start(project).catchError((Object exception, StackTrace trace) {
|
||||||
|
hasCrash = true;
|
||||||
|
return <ProjectValidatorResult>[ProjectValidatorResult.crash(exception, trace)];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final StringBuffer buffer = StringBuffer();
|
||||||
|
final List<String> resultsString = <String>[];
|
||||||
|
for (final ProjectValidator validator in results.keys) {
|
||||||
|
if (results[validator] != null) {
|
||||||
|
resultsString.add(validator.title);
|
||||||
|
addResultString(validator.title, await results[validator], resultsString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer.writeAll(resultsString, '\n');
|
||||||
|
logger.printBox(buffer.toString());
|
||||||
|
|
||||||
|
if (hasCrash) {
|
||||||
|
return const FlutterCommandResult(ExitStatus.fail);
|
||||||
|
}
|
||||||
|
return const FlutterCommandResult(ExitStatus.success);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void addResultString(final String title, final List<ProjectValidatorResult>? results, final List<String> resultsString) {
|
||||||
|
if (results != null) {
|
||||||
|
for (final ProjectValidatorResult result in results) {
|
||||||
|
resultsString.add(getStringResult(result));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String getStringResult(ProjectValidatorResult result) {
|
||||||
|
final String icon;
|
||||||
|
switch(result.status) {
|
||||||
|
case StatusProjectValidator.error:
|
||||||
|
icon = '[✗]';
|
||||||
|
break;
|
||||||
|
case StatusProjectValidator.success:
|
||||||
|
icon = '[✓]';
|
||||||
|
break;
|
||||||
|
case StatusProjectValidator.warning:
|
||||||
|
icon = '[!]';
|
||||||
|
break;
|
||||||
|
case StatusProjectValidator.crash:
|
||||||
|
icon = '[☠]';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return '$icon $result';
|
||||||
|
}
|
||||||
|
|
||||||
|
String getUserPath(){
|
||||||
|
return (argResults == null || argResults!.rest.isEmpty) ? '' : argResults!.rest[0];
|
||||||
|
}
|
||||||
|
}
|
17
packages/flutter_tools/lib/src/project_validator.dart
Normal file
17
packages/flutter_tools/lib/src/project_validator.dart
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// 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 'project.dart';
|
||||||
|
import 'project_validator_result.dart';
|
||||||
|
|
||||||
|
abstract class ProjectValidator {
|
||||||
|
String get title;
|
||||||
|
bool supportsProject(FlutterProject project);
|
||||||
|
/// Can return more than one result in case a file/command have a lot of info to share to the user
|
||||||
|
Future<List<ProjectValidatorResult>> start(FlutterProject project);
|
||||||
|
/// new ProjectValidators should be added here for the ValidateProjectCommand to run
|
||||||
|
static const List <ProjectValidator> allProjectValidators = <ProjectValidator>[
|
||||||
|
// TODO(jasguerrero): add validators
|
||||||
|
];
|
||||||
|
}
|
41
packages/flutter_tools/lib/src/project_validator_result.dart
Normal file
41
packages/flutter_tools/lib/src/project_validator_result.dart
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
enum StatusProjectValidator {
|
||||||
|
error,
|
||||||
|
warning,
|
||||||
|
success,
|
||||||
|
crash,
|
||||||
|
}
|
||||||
|
|
||||||
|
class ProjectValidatorResult {
|
||||||
|
|
||||||
|
const ProjectValidatorResult({
|
||||||
|
required this.name,
|
||||||
|
required this.value,
|
||||||
|
required this.status,
|
||||||
|
this.warning,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String name;
|
||||||
|
final String value;
|
||||||
|
final String? warning;
|
||||||
|
final StatusProjectValidator status;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
if (warning != null) {
|
||||||
|
return '$name: $value (warning: $warning)';
|
||||||
|
}
|
||||||
|
return '$name: $value';
|
||||||
|
}
|
||||||
|
|
||||||
|
static ProjectValidatorResult crash(Object exception, StackTrace trace) {
|
||||||
|
return ProjectValidatorResult(
|
||||||
|
name: exception.toString(),
|
||||||
|
value: trace.toString(),
|
||||||
|
status: StatusProjectValidator.crash
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,124 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// @dart = 2.8
|
||||||
|
|
||||||
|
import 'package:args/command_runner.dart';
|
||||||
|
import 'package:file/memory.dart';
|
||||||
|
import 'package:flutter_tools/src/base/file_system.dart';
|
||||||
|
import 'package:flutter_tools/src/base/logger.dart';
|
||||||
|
import 'package:flutter_tools/src/commands/validate_project.dart';
|
||||||
|
import 'package:flutter_tools/src/project.dart';
|
||||||
|
import 'package:flutter_tools/src/project_validator.dart';
|
||||||
|
import 'package:flutter_tools/src/project_validator_result.dart';
|
||||||
|
|
||||||
|
import '../../src/context.dart';
|
||||||
|
import '../../src/test_flutter_command_runner.dart';
|
||||||
|
|
||||||
|
class ProjectValidatorDummy extends ProjectValidator {
|
||||||
|
@override
|
||||||
|
Future<List<ProjectValidatorResult>> start(FlutterProject project) async{
|
||||||
|
return <ProjectValidatorResult>[
|
||||||
|
const ProjectValidatorResult(name: 'pass', value: 'value', status: StatusProjectValidator.success),
|
||||||
|
const ProjectValidatorResult(name: 'fail', value: 'my error', status: StatusProjectValidator.error),
|
||||||
|
const ProjectValidatorResult(name: 'pass two', value: 'pass', warning: 'my warning', status: StatusProjectValidator.warning),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool supportsProject(FlutterProject project) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get title => 'First Dummy';
|
||||||
|
}
|
||||||
|
|
||||||
|
class ProjectValidatorSecondDummy extends ProjectValidator {
|
||||||
|
@override
|
||||||
|
Future<List<ProjectValidatorResult>> start(FlutterProject project) async{
|
||||||
|
return <ProjectValidatorResult>[
|
||||||
|
const ProjectValidatorResult(name: 'second', value: 'pass', status: StatusProjectValidator.success),
|
||||||
|
const ProjectValidatorResult(name: 'other fail', value: 'second fail', status: StatusProjectValidator.error),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool supportsProject(FlutterProject project) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get title => 'Second Dummy';
|
||||||
|
}
|
||||||
|
|
||||||
|
class ProjectValidatorCrash extends ProjectValidator {
|
||||||
|
@override
|
||||||
|
Future<List<ProjectValidatorResult>> start(FlutterProject project) async{
|
||||||
|
throw Exception('my exception');
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool supportsProject(FlutterProject project) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get title => 'Crash';
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
FileSystem fileSystem;
|
||||||
|
|
||||||
|
group('analyze project command', () {
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
fileSystem = MemoryFileSystem.test();
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('success, error and warning', () async {
|
||||||
|
final BufferLogger loggerTest = BufferLogger.test();
|
||||||
|
final ValidateProjectCommand command = ValidateProjectCommand(
|
||||||
|
fileSystem: fileSystem,
|
||||||
|
logger: loggerTest,
|
||||||
|
allProjectValidators: <ProjectValidator>[
|
||||||
|
ProjectValidatorDummy(),
|
||||||
|
ProjectValidatorSecondDummy()
|
||||||
|
]
|
||||||
|
);
|
||||||
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
||||||
|
|
||||||
|
await runner.run(<String>['validate-project']);
|
||||||
|
|
||||||
|
const String expected = '\n'
|
||||||
|
'┌──────────────────────────────────────────┐\n'
|
||||||
|
'│ First Dummy │\n'
|
||||||
|
'│ [✓] pass: value │\n'
|
||||||
|
'│ [✗] fail: my error │\n'
|
||||||
|
'│ [!] pass two: pass (warning: my warning) │\n'
|
||||||
|
'│ Second Dummy │\n'
|
||||||
|
'│ [✓] second: pass │\n'
|
||||||
|
'│ [✗] other fail: second fail │\n'
|
||||||
|
'└──────────────────────────────────────────┘\n';
|
||||||
|
|
||||||
|
expect(loggerTest.statusText, contains(expected));
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('crash', () async {
|
||||||
|
final BufferLogger loggerTest = BufferLogger.test();
|
||||||
|
final ValidateProjectCommand command = ValidateProjectCommand(
|
||||||
|
fileSystem: fileSystem,
|
||||||
|
logger: loggerTest,
|
||||||
|
allProjectValidators: <ProjectValidator>[ProjectValidatorCrash()]
|
||||||
|
);
|
||||||
|
final CommandRunner<void> runner = createTestCommandRunner(command);
|
||||||
|
|
||||||
|
await runner.run(<String>['validate-project']);
|
||||||
|
|
||||||
|
const String expected = '[☠] Exception: my exception: #0 ProjectValidatorCrash.start';
|
||||||
|
|
||||||
|
expect(loggerTest.statusText, contains(expected));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
@ -0,0 +1,99 @@
|
|||||||
|
// 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:file/memory.dart';
|
||||||
|
import 'package:flutter_tools/src/project.dart';
|
||||||
|
import 'package:flutter_tools/src/project_validator.dart';
|
||||||
|
import 'package:flutter_tools/src/project_validator_result.dart';
|
||||||
|
|
||||||
|
import '../src/common.dart';
|
||||||
|
|
||||||
|
class ProjectValidatorTaskImpl extends ProjectValidator {
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<ProjectValidatorResult>> start(FlutterProject project) async {
|
||||||
|
const ProjectValidatorResult error = ProjectValidatorResult(
|
||||||
|
name: 'result_1',
|
||||||
|
value: 'this is an error',
|
||||||
|
status: StatusProjectValidator.error,
|
||||||
|
);
|
||||||
|
|
||||||
|
const ProjectValidatorResult success = ProjectValidatorResult(
|
||||||
|
name: 'result_2',
|
||||||
|
value: 'correct',
|
||||||
|
status: StatusProjectValidator.success,
|
||||||
|
);
|
||||||
|
|
||||||
|
const ProjectValidatorResult warning = ProjectValidatorResult(
|
||||||
|
name: 'result_3',
|
||||||
|
value: 'this passed',
|
||||||
|
status: StatusProjectValidator.success,
|
||||||
|
warning: 'with a warning'
|
||||||
|
);
|
||||||
|
|
||||||
|
return <ProjectValidatorResult>[error, success, warning];
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool supportsProject(FlutterProject project) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get title => 'Impl';
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('ProjectValidatorResult', () {
|
||||||
|
|
||||||
|
testWithoutContext('success status', () {
|
||||||
|
const ProjectValidatorResult result = ProjectValidatorResult(
|
||||||
|
name: 'name',
|
||||||
|
value: 'value',
|
||||||
|
status: StatusProjectValidator.success,
|
||||||
|
);
|
||||||
|
expect(result.toString(), 'name: value');
|
||||||
|
expect(result.status, StatusProjectValidator.success);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('success status with warning', () {
|
||||||
|
const ProjectValidatorResult result = ProjectValidatorResult(
|
||||||
|
name: 'name',
|
||||||
|
value: 'value',
|
||||||
|
status: StatusProjectValidator.success,
|
||||||
|
warning: 'my warning'
|
||||||
|
);
|
||||||
|
expect(result.toString(), 'name: value (warning: my warning)');
|
||||||
|
expect(result.status, StatusProjectValidator.success);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('error status', () {
|
||||||
|
const ProjectValidatorResult result = ProjectValidatorResult(
|
||||||
|
name: 'name',
|
||||||
|
value: 'my error',
|
||||||
|
status: StatusProjectValidator.error,
|
||||||
|
);
|
||||||
|
expect(result.toString(), 'name: my error');
|
||||||
|
expect(result.status, StatusProjectValidator.error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('ProjectValidatorTask', () {
|
||||||
|
late ProjectValidatorTaskImpl task;
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
task = ProjectValidatorTaskImpl();
|
||||||
|
});
|
||||||
|
|
||||||
|
testWithoutContext('error status', () async {
|
||||||
|
final MemoryFileSystem fs = MemoryFileSystem.test();
|
||||||
|
final FlutterProject project = FlutterProject.fromDirectoryTest(fs.currentDirectory);
|
||||||
|
final List<ProjectValidatorResult> results = await task.start(project);
|
||||||
|
expect(results.length, 3);
|
||||||
|
expect(results[0].toString(), 'result_1: this is an error');
|
||||||
|
expect(results[1].toString(), 'result_2: correct');
|
||||||
|
expect(results[2].toString(), 'result_3: this passed (warning: with a warning)');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user