Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions packages/flutter_migrate/bin/flutter_migrate
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
# 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.

SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )

dart run $SCRIPT_DIR/flutter_migrate.dart "$@"
29 changes: 29 additions & 0 deletions packages/flutter_migrate/bin/flutter_migrate.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
@ECHO off
REM Copyright 2014 The Flutter Authors. All rights reserved.
REM Use of this source code is governed by a BSD-style license that can be
REM found in the LICENSE file.

REM If available, add location of bundled mingit to PATH
SET mingit_path=%FLUTTER_ROOT%\bin\mingit\cmd
IF EXIST "%mingit_path%" SET PATH=%PATH%;%mingit_path%

REM Test if Git is available on the Host
where /q git || ECHO Error: Unable to find git in your PATH. && EXIT /B 1

rem SET flutter_tools_dir=%FLUTTER_ROOT%\packages\flutter_tools
SET cache_dir=%FLUTTER_ROOT%\bin\cache
rem SET snapshot_path=%cache_dir%\flutter_tools.snapshot
SET dart_sdk_path=%cache_dir%\dart-sdk
SET dart=%dart_sdk_path%\bin\dart.exe

SET exit_with_errorlevel=%FLUTTER_ROOT%/bin/internal/exit_with_errorlevel.bat

REM Chaining the call to 'dart' and 'exit' with an ampersand ensures that
REM Windows reads both commands into memory once before executing them. This
REM avoids nasty errors that may otherwise occur when the dart command (e.g. as
REM part of 'flutter upgrade') modifies this batch script while it is executing.
REM
REM Do not use the CALL command in the next line to execute Dart. CALL causes
REM Windows to re-read the line from disk after the CALL command has finished
REM regardless of the ampersand chain.
"%dart%" --disable-dart-dev --packages="%flutter_tools_dir%\.dart_tool\package_config.json" %FLUTTER_TOOL_ARGS% "%snapshot_path%" %* & "%exit_with_errorlevel%"
11 changes: 11 additions & 0 deletions packages/flutter_migrate/bin/flutter_migrate.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// 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.9

import 'package:flutter_migrate/executable.dart' as executable;

void main(List<String> args) {
executable.main(args);
}
133 changes: 133 additions & 0 deletions packages/flutter_migrate/lib/executable.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// 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 'dart:async';
import 'dart:io';

import 'package:process/process.dart';

import 'src/base/command.dart';
import 'src/base/common.dart';
import 'src/base/file_system.dart';
import 'src/base/io.dart';
import 'src/base/logger.dart';
import 'src/base/signals.dart';
import 'src/base/terminal.dart';

import 'src/commands/abandon.dart';
import 'src/commands/apply.dart';
import 'src/commands/resolve_conflicts.dart';
import 'src/commands/start.dart';
import 'src/commands/status.dart';

Future<void> main(List<String> args) async {
final bool veryVerbose = args.contains('-vv');
final bool verbose =
args.contains('-v') || args.contains('--verbose') || veryVerbose;

const ProcessManager localProcessManager = LocalProcessManager();
final FileSystem fileSystem = LocalFileSystem(
LocalSignals.instance, Signals.defaultExitSignals, ShutdownHooks());

// flutterRoot must be set early because other features use it (e.g.
// enginePath's initializer uses it). This can only work with the real
// instances of the platform or filesystem, so just use those.
flutterRoot = defaultFlutterRoot(fileSystem: fileSystem);

final Stdio stdio = Stdio();
final Terminal terminal = AnsiTerminal(stdio: stdio);

final LoggerFactory loggerFactory = LoggerFactory(
outputPreferences: OutputPreferences(
wrapText: stdio.hasTerminal,
showColor: stdout.supportsAnsiEscapes,
stdio: stdio,
),
terminal: terminal,
stdio: stdio,
);
final Logger logger = loggerFactory.createLogger(
windows: isWindows,
);

final List<MigrateCommand> commands = <MigrateCommand>[
MigrateStartCommand(
verbose: verbose,
logger: logger,
fileSystem: fileSystem,
processManager: localProcessManager,
),
MigrateStatusCommand(
verbose: verbose,
logger: logger,
fileSystem: fileSystem,
processManager: localProcessManager,
),
MigrateResolveConflictsCommand(
logger: logger,
fileSystem: fileSystem,
terminal: terminal,
),
MigrateAbandonCommand(
logger: logger,
fileSystem: fileSystem,
terminal: terminal,
processManager: localProcessManager),
MigrateApplyCommand(
verbose: verbose,
logger: logger,
fileSystem: fileSystem,
terminal: terminal,
processManager: localProcessManager),
];

for (final MigrateCommand command in commands) {
if (command.name == args[0]) {
command.run();
break;
}
}
}

/// An abstraction for instantiation of the correct logger type.
///
/// Our logger class hierarchy and runtime requirements are overly complicated.
class LoggerFactory {
LoggerFactory({
required Terminal terminal,
required Stdio stdio,
required OutputPreferences outputPreferences,
StopwatchFactory stopwatchFactory = const StopwatchFactory(),
}) : _terminal = terminal,
_stdio = stdio,
_stopwatchFactory = stopwatchFactory,
_outputPreferences = outputPreferences;

final Terminal _terminal;
final Stdio _stdio;
final StopwatchFactory _stopwatchFactory;
final OutputPreferences _outputPreferences;

/// Create the appropriate logger for the current platform and configuration.
Logger createLogger({
required bool windows,
}) {
Logger logger;
if (windows) {
logger = WindowsStdoutLogger(
terminal: _terminal,
stdio: _stdio,
outputPreferences: _outputPreferences,
stopwatchFactory: _stopwatchFactory,
);
} else {
logger = StdoutLogger(
terminal: _terminal,
stdio: _stdio,
outputPreferences: _outputPreferences,
stopwatchFactory: _stopwatchFactory);
}
return logger;
}
}
5 changes: 5 additions & 0 deletions packages/flutter_migrate/lib/flutter_migrate.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// 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.

library flutter_migrate;
140 changes: 140 additions & 0 deletions packages/flutter_migrate/lib/src/commands/abandon.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// 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:process/process.dart';

import '../base/command.dart';
import '../base/file_system.dart';
import '../base/logger.dart';
import '../base/project.dart';
import '../base/terminal.dart';

import '../utils.dart';

/// Abandons the existing migration by deleting the migrate working directory.
class MigrateAbandonCommand extends MigrateCommand {
MigrateAbandonCommand({
required this.logger,
required this.fileSystem,
required this.terminal,
required ProcessManager processManager,
}) : migrateUtils = MigrateUtils(
logger: logger,
fileSystem: fileSystem,
processManager: processManager,
) {
argParser.addOption(
'staging-directory',
help: 'Specifies the custom migration working directory used to stage '
'and edit proposed changes. This path can be absolute or relative '
'to the flutter project root. This defaults to '
'`$kDefaultMigrateStagingDirectoryName`',
valueHelp: 'path',
);
argParser.addOption(
'project-directory',
help: 'The root directory of the flutter project. This defaults to the '
'current working directory if omitted.',
valueHelp: 'path',
);
argParser.addFlag(
'force',
abbr: 'f',
help:
'Delete the migrate working directory without asking for confirmation.',
);
argParser.addFlag(
'flutter-subcommand',
help:
'Enable when using the flutter tool as a subcommand. This changes the '
'wording of log messages to indicate the correct suggested commands to use.',
);
}

final Logger logger;

final FileSystem fileSystem;

final Terminal terminal;

final MigrateUtils migrateUtils;

@override
final String name = 'abandon';

@override
final String description =
'Deletes the current active migration working directory.';

@override
Future<CommandResult> runCommand() async {
final String? projectDirectory = stringArg('project-directory');
final FlutterProjectFactory flutterProjectFactory = FlutterProjectFactory();
final FlutterProject project = projectDirectory == null
? FlutterProject.current(fileSystem)
: flutterProjectFactory
.fromDirectory(fileSystem.directory(projectDirectory));
final bool isSubcommand = boolArg('flutter-subcommand') ?? false;
Directory stagingDirectory =
project.directory.childDirectory(kDefaultMigrateStagingDirectoryName);
final String? customStagingDirectoryPath = stringArg('staging-directory');
if (customStagingDirectoryPath != null) {
if (fileSystem.path.isAbsolute(customStagingDirectoryPath)) {
stagingDirectory = fileSystem.directory(customStagingDirectoryPath);
} else {
stagingDirectory =
project.directory.childDirectory(customStagingDirectoryPath);
}
if (!stagingDirectory.existsSync()) {
logger.printError(
'Provided staging directory `$customStagingDirectoryPath` '
'does not exist or is not valid.');
return const CommandResult(ExitStatus.fail);
}
}
if (!stagingDirectory.existsSync()) {
logger
.printStatus('No migration in progress. Start a new migration with:');
printCommandText('start', logger, standalone: !isSubcommand);
return const CommandResult(ExitStatus.fail);
}

logger.printStatus('\nAbandoning the existing migration will delete the '
'migration staging directory at ${stagingDirectory.path}');
final bool force = boolArg('force') ?? false;
if (!force) {
String selection = 'y';
terminal.usesTerminalUi = true;
try {
selection = await terminal.promptForCharInput(
<String>['y', 'n'],
logger: logger,
prompt:
'Are you sure you wish to continue with abandoning? (y)es, (N)o',
defaultChoiceIndex: 1,
);
} on StateError catch (e) {
logger.printError(
e.message,
indent: 0,
);
}
if (selection != 'y') {
return const CommandResult(ExitStatus.success);
}
}

try {
stagingDirectory.deleteSync(recursive: true);
} on FileSystemException catch (e) {
logger.printError('Deletion failed with: $e');
logger.printError(
'Please manually delete the staging directory at `${stagingDirectory.path}`');
}

logger.printStatus('\nAbandon complete. Start a new migration with:');
printCommandText('start', logger, standalone: !isSubcommand);
return const CommandResult(ExitStatus.success);
}
}
Loading