Skip to content

Commit 0895130

Browse files
authored
Migrate status (#102785)
1 parent 3da9eee commit 0895130

File tree

4 files changed

+393
-6
lines changed

4 files changed

+393
-6
lines changed

packages/flutter_tools/lib/src/commands/migrate.dart

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,34 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
import 'package:process/process.dart';
56

7+
import '../base/file_system.dart';
68
import '../base/logger.dart';
9+
import '../base/platform.dart';
710
import '../base/terminal.dart';
811
import '../migrate/migrate_utils.dart';
912
import '../runner/flutter_command.dart';
10-
13+
import 'migrate_status.dart';
1114

1215
/// Base command for the migration tool.
1316
class MigrateCommand extends FlutterCommand {
1417
MigrateCommand({
18+
bool verbose = false,
1519
required this.logger,
16-
// TODO(garyq): Add each parameters in as subcommands land.
20+
// TODO(garyq): Add parameter in as they are needed for subcommands.
21+
required FileSystem fileSystem,
22+
required Platform platform,
23+
required ProcessManager processManager,
1724
}) {
18-
// TODO(garyq): Add subcommands.
25+
// TODO(garyq): Add each subcommand back in as they land.
26+
addSubcommand(MigrateStatusCommand(
27+
verbose: verbose,
28+
logger: logger,
29+
fileSystem: fileSystem,
30+
platform: platform,
31+
processManager: processManager
32+
));
1933
}
2034

2135
final Logger logger;
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
// Copyright 2014 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:process/process.dart';
6+
7+
import '../base/file_system.dart';
8+
import '../base/logger.dart';
9+
import '../base/platform.dart';
10+
import '../base/terminal.dart';
11+
import '../migrate/migrate_manifest.dart';
12+
import '../migrate/migrate_utils.dart';
13+
import '../project.dart';
14+
import '../runner/flutter_command.dart';
15+
import 'migrate.dart';
16+
17+
/// Flutter migrate subcommand to check the migration status of the project.
18+
class MigrateStatusCommand extends FlutterCommand {
19+
MigrateStatusCommand({
20+
bool verbose = false,
21+
required this.logger,
22+
required this.fileSystem,
23+
required Platform platform,
24+
required ProcessManager processManager,
25+
}) : _verbose = verbose,
26+
migrateUtils = MigrateUtils(
27+
logger: logger,
28+
fileSystem: fileSystem,
29+
platform: platform,
30+
processManager: processManager,
31+
) {
32+
requiresPubspecYaml();
33+
argParser.addOption(
34+
'staging-directory',
35+
help: 'Specifies the custom migration working directory used to stage '
36+
'and edit proposed changes. This path can be absolute or relative '
37+
'to the flutter project root. This defaults to '
38+
'`$kDefaultMigrateStagingDirectoryName`',
39+
valueHelp: 'path',
40+
);
41+
argParser.addOption(
42+
'project-directory',
43+
help: 'The root directory of the flutter project. This defaults to the '
44+
'current working directory if omitted.',
45+
valueHelp: 'path',
46+
);
47+
argParser.addFlag(
48+
'diff',
49+
defaultsTo: true,
50+
help: 'Shows the diff output when enabled. Enabled by default.',
51+
);
52+
argParser.addFlag(
53+
'show-added-files',
54+
help: 'Shows the contents of added files. Disabled by default.',
55+
);
56+
}
57+
58+
final bool _verbose;
59+
60+
final Logger logger;
61+
62+
final FileSystem fileSystem;
63+
64+
final MigrateUtils migrateUtils;
65+
66+
@override
67+
final String name = 'status';
68+
69+
@override
70+
final String description = 'Prints the current status of the in progress migration.';
71+
72+
@override
73+
String get category => FlutterCommandCategory.project;
74+
75+
@override
76+
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => const <DevelopmentArtifact>{};
77+
78+
/// Manually marks the lines in a diff that should be printed unformatted for visbility.
79+
///
80+
/// This is used to ensure the initial lines that display the files being diffed and the
81+
/// git revisions are printed and never skipped.
82+
final Set<int> _initialDiffLines = <int>{0, 1};
83+
84+
@override
85+
Future<FlutterCommandResult> runCommand() async {
86+
final String? projectDirectory = stringArg('project-directory');
87+
final FlutterProjectFactory flutterProjectFactory = FlutterProjectFactory(logger: logger, fileSystem: fileSystem);
88+
final FlutterProject project = projectDirectory == null
89+
? FlutterProject.current()
90+
: flutterProjectFactory.fromDirectory(fileSystem.directory(projectDirectory));
91+
Directory stagingDirectory = project.directory.childDirectory(kDefaultMigrateStagingDirectoryName);
92+
final String? customStagingDirectoryPath = stringArg('staging-directory');
93+
if (customStagingDirectoryPath != null) {
94+
if (fileSystem.path.isAbsolute(customStagingDirectoryPath)) {
95+
stagingDirectory = fileSystem.directory(customStagingDirectoryPath);
96+
} else {
97+
stagingDirectory = project.directory.childDirectory(customStagingDirectoryPath);
98+
}
99+
}
100+
if (!stagingDirectory.existsSync()) {
101+
logger.printStatus('No migration in progress in $stagingDirectory. Start a new migration with:');
102+
printCommandText('flutter migrate start', logger);
103+
return const FlutterCommandResult(ExitStatus.fail);
104+
}
105+
106+
final File manifestFile = MigrateManifest.getManifestFileFromDirectory(stagingDirectory);
107+
if (!manifestFile.existsSync()) {
108+
logger.printError('No migrate manifest in the migrate working directory '
109+
'at ${stagingDirectory.path}. Fix the working directory '
110+
'or abandon and restart the migration.');
111+
return const FlutterCommandResult(ExitStatus.fail);
112+
}
113+
final MigrateManifest manifest = MigrateManifest.fromFile(manifestFile);
114+
115+
final bool showDiff = boolArg('diff') ?? true;
116+
final bool showAddedFiles = boolArg('show-added-files') ?? true;
117+
if (showDiff || _verbose) {
118+
if (showAddedFiles || _verbose) {
119+
for (final String localPath in manifest.addedFiles) {
120+
logger.printStatus('Newly added file at $localPath:\n');
121+
try {
122+
logger.printStatus(stagingDirectory.childFile(localPath).readAsStringSync(), color: TerminalColor.green);
123+
} on FileSystemException {
124+
logger.printStatus('Contents are byte data\n', color: TerminalColor.grey);
125+
}
126+
}
127+
}
128+
final List<String> files = <String>[];
129+
files.addAll(manifest.mergedFiles);
130+
files.addAll(manifest.resolvedConflictFiles(stagingDirectory));
131+
files.addAll(manifest.remainingConflictFiles(stagingDirectory));
132+
for (final String localPath in files) {
133+
final DiffResult result = await migrateUtils.diffFiles(project.directory.childFile(localPath), stagingDirectory.childFile(localPath));
134+
if (result.diff != '' && result.diff != null) {
135+
// Print with different colors for better visibility.
136+
int lineNumber = -1;
137+
for (final String line in result.diff!.split('\n')) {
138+
lineNumber++;
139+
if (line.startsWith('---') || line.startsWith('+++') || line.startsWith('&&') || _initialDiffLines.contains(lineNumber)) {
140+
logger.printStatus(line);
141+
continue;
142+
}
143+
if (line.startsWith('-')) {
144+
logger.printStatus(line, color: TerminalColor.red);
145+
continue;
146+
}
147+
if (line.startsWith('+')) {
148+
logger.printStatus(line, color: TerminalColor.green);
149+
continue;
150+
}
151+
logger.printStatus(line, color: TerminalColor.grey);
152+
}
153+
}
154+
}
155+
}
156+
157+
logger.printBox('Working directory at `${stagingDirectory.path}`');
158+
159+
checkAndPrintMigrateStatus(manifest, stagingDirectory, logger: logger);
160+
161+
final bool readyToApply = manifest.remainingConflictFiles(stagingDirectory).isEmpty;
162+
163+
if (!readyToApply) {
164+
logger.printStatus('Guided conflict resolution wizard:');
165+
printCommandText('flutter migrate resolve-conflicts', logger);
166+
logger.printStatus('Resolve conflicts and accept changes with:');
167+
} else {
168+
logger.printStatus('All conflicts resolved. Review changes above and '
169+
'apply the migration with:',
170+
color: TerminalColor.green);
171+
}
172+
printCommandText('flutter migrate apply', logger);
173+
174+
return const FlutterCommandResult(ExitStatus.success);
175+
}
176+
}

packages/flutter_tools/lib/src/migrate/migrate_utils.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import '../base/platform.dart';
1414
import '../base/process.dart';
1515

1616
/// The default name of the migrate working directory used to stage proposed changes.
17-
const String kDefaultMigrateWorkingDirectoryName = 'migrate_working_dir';
17+
const String kDefaultMigrateStagingDirectoryName = 'migrate_staging_dir';
1818

1919
/// Utility class that contains methods that wrap git and other shell commands.
2020
class MigrateUtils {
@@ -179,14 +179,14 @@ class MigrateUtils {
179179
}
180180

181181
/// Returns true if the workingDirectory git repo has any uncommited changes.
182-
Future<bool> hasUncommittedChanges(String workingDirectory, {String? migrateWorkingDir}) async {
182+
Future<bool> hasUncommittedChanges(String workingDirectory, {String? migrateStagingDir}) async {
183183
final List<String> cmdArgs = <String>[
184184
'git',
185185
'ls-files',
186186
'--deleted',
187187
'--modified',
188188
'--others',
189-
'--exclude=${migrateWorkingDir ?? kDefaultMigrateWorkingDirectoryName}'
189+
'--exclude=${migrateStagingDir ?? kDefaultMigrateStagingDirectoryName}'
190190
];
191191
final RunResult result = await _processUtils.run(cmdArgs, workingDirectory: workingDirectory);
192192
checkForErrors(result, allowedExitCodes: <int>[-1], commandDescription: cmdArgs.join(' '));

0 commit comments

Comments
 (0)