diff --git a/bin/flutter.bat b/bin/flutter.bat index 8532b3d0f0..79f525e7d1 100644 --- a/bin/flutter.bat +++ b/bin/flutter.bat @@ -34,7 +34,7 @@ GOTO :after_snapshot CD "%flutter_tools_dir%" ECHO Updating flutter tool... CALL pub.bat get -CD "%flutter_dir" +CD "%flutter_dir%" REM Allows us to check if sky_engine's REVISION is correct CALL pub.bat get CD "%flutter_root%" diff --git a/packages/flutter_tools/lib/src/artifacts.dart b/packages/flutter_tools/lib/src/artifacts.dart index 69d0f3c5ec..80d0c443c3 100644 --- a/packages/flutter_tools/lib/src/artifacts.dart +++ b/packages/flutter_tools/lib/src/artifacts.dart @@ -6,7 +6,6 @@ import 'dart:io'; import 'package:path/path.dart' as path; -import 'base/process.dart'; import 'build_configuration.dart'; import 'globals.dart'; @@ -216,10 +215,12 @@ class ArtifactStore { File cachedFile = new File( path.join(_getBaseCacheDir().path, 'engine', artifact.platform, artifact.fileName) ); + if (!cachedFile.existsSync()) { printError('File not found in the platform artifacts: ${cachedFile.path}'); - throw new ProcessExit(2); + return null; + } else { + return cachedFile.path; } - return cachedFile.path; } } diff --git a/packages/flutter_tools/lib/src/base/logger.dart b/packages/flutter_tools/lib/src/base/logger.dart index 3c7b37cc66..4425aaec77 100644 --- a/packages/flutter_tools/lib/src/base/logger.dart +++ b/packages/flutter_tools/lib/src/base/logger.dart @@ -6,10 +6,13 @@ import 'dart:async'; import 'dart:io'; final _AnsiTerminal _terminal = new _AnsiTerminal(); +final String _sep = Platform.isWindows ? '-' : '•'; abstract class Logger { bool get isVerbose => false; + String get separator => _sep; + /// Display an error level message to the user. Commands should use this if they /// fail in some way. void printError(String message, [StackTrace stackTrace]); @@ -34,7 +37,7 @@ class Status { void cancel() { } } -class StdoutLogger implements Logger { +class StdoutLogger extends Logger { Status _status; @override @@ -79,7 +82,7 @@ class StdoutLogger implements Logger { void flush() { } } -class BufferLogger implements Logger { +class BufferLogger extends Logger { @override bool get isVerbose => false; @@ -110,7 +113,7 @@ class BufferLogger implements Logger { void flush() { } } -class VerboseLogger implements Logger { +class VerboseLogger extends Logger { _LogMessage lastMessage; @override @@ -170,10 +173,10 @@ class _LogMessage { stopwatch.stop(); int millis = stopwatch.elapsedMilliseconds; - String prefix = '${millis.toString().padLeft(4)} ms • '; + String prefix = '${millis.toString().padLeft(4)} ms $_sep '; String indent = ''.padLeft(prefix.length); if (millis >= 100) - prefix = _terminal.writeBold(prefix.substring(0, prefix.length - 3)) + ' • '; + prefix = _terminal.writeBold(prefix.substring(0, prefix.length - 3)) + ' $_sep '; String indentMessage = message.replaceAll('\n', '\n$indent'); if (type == _LogType.error) { @@ -190,6 +193,7 @@ class _LogMessage { class _AnsiTerminal { _AnsiTerminal() { + // TODO(devoncarew): This detection does not work for Windows. String term = Platform.environment['TERM']; _supportsColor = term != null && term != 'dumb'; } diff --git a/packages/flutter_tools/lib/src/base/os.dart b/packages/flutter_tools/lib/src/base/os.dart index 2773a2435c..7bdb35eb6f 100644 --- a/packages/flutter_tools/lib/src/base/os.dart +++ b/packages/flutter_tools/lib/src/base/os.dart @@ -5,10 +5,16 @@ import 'dart:async'; import 'dart:io'; +import 'package:archive/archive.dart'; +import 'package:path/path.dart' as path; + import 'context.dart'; +import 'process.dart'; /// Returns [OperatingSystemUtils] active in the current app context (i.e. zone). -OperatingSystemUtils get os => context[OperatingSystemUtils] ?? (context[OperatingSystemUtils] = new OperatingSystemUtils._()); +OperatingSystemUtils get os { + return context[OperatingSystemUtils] ?? (context[OperatingSystemUtils] = new OperatingSystemUtils._()); +} abstract class OperatingSystemUtils { factory OperatingSystemUtils._() { @@ -33,6 +39,8 @@ abstract class OperatingSystemUtils { /// Return the path (with symlinks resolved) to the given executable, or `null` /// if `which` was not able to locate the binary. File which(String execName); + + void unzip(File file, Directory targetDirectory); } class _PosixUtils extends OperatingSystemUtils { @@ -53,6 +61,12 @@ class _PosixUtils extends OperatingSystemUtils { String path = result.stdout.trim().split('\n').first.trim(); return new File(new File(path).resolveSymbolicLinksSync()); } + + // unzip -o -q zipfile -d dest + @override + void unzip(File file, Directory targetDirectory) { + runSync(['unzip', '-o', '-q', file.path, '-d', targetDirectory.path]); + } } class _WindowsUtils extends OperatingSystemUtils { @@ -66,7 +80,26 @@ class _WindowsUtils extends OperatingSystemUtils { @override File which(String execName) { - throw new UnimplementedError('_WindowsUtils.which'); + ProcessResult result = Process.runSync('where', [execName]); + if (result.exitCode != 0) + return null; + return new File(result.stdout.trim().split('\n').first.trim()); + } + + @override + void unzip(File file, Directory targetDirectory) { + Archive archive = new ZipDecoder().decodeBytes(file.readAsBytesSync()); + + for (ArchiveFile archiveFile in archive.files) { + // The archive package doesn't correctly set isFile. + if (!archiveFile.isFile || archiveFile.name.endsWith('/')) + continue; + + File destFile = new File(path.join(targetDirectory.path, archiveFile.name)); + if (!destFile.parent.existsSync()) + destFile.parent.createSync(recursive: true); + destFile.writeAsBytesSync(archiveFile.content); + } } } diff --git a/packages/flutter_tools/lib/src/cache.dart b/packages/flutter_tools/lib/src/cache.dart index 4a288236ed..db5d951d34 100644 --- a/packages/flutter_tools/lib/src/cache.dart +++ b/packages/flutter_tools/lib/src/cache.dart @@ -11,7 +11,6 @@ import 'artifacts.dart'; import 'base/context.dart'; import 'base/logger.dart'; import 'base/os.dart'; -import 'base/process.dart'; import 'globals.dart'; /// A warpper around the `bin/cache/` directory. @@ -129,8 +128,7 @@ class Cache { File tempFile = new File(path.join(Directory.systemTemp.path, '${url.toString().hashCode}.zip')); tempFile.writeAsBytesSync(fileBytes, flush: true); - // unzip -o -q zipfile -d dest - runSync(['unzip', '-o', '-q', tempFile.path, '-d', location.path]); + os.unzip(tempFile, location); tempFile.deleteSync(); } else { (location as File).writeAsBytesSync(fileBytes, flush: true); diff --git a/packages/flutter_tools/lib/src/commands/analyze.dart b/packages/flutter_tools/lib/src/commands/analyze.dart index 1f1d47ebad..7c503671a9 100644 --- a/packages/flutter_tools/lib/src/commands/analyze.dart +++ b/packages/flutter_tools/lib/src/commands/analyze.dart @@ -527,7 +527,7 @@ class AnalyzeCommand extends FlutterCommand { String files = '${analyzedPaths.length} ${pluralize('file', analyzedPaths.length)}'; String seconds = (analysisTimer.elapsedMilliseconds / 1000.0).toStringAsFixed(2); - printStatus('$errorsMessage • analyzed $files, $seconds seconds'); + printStatus('$errorsMessage ${logger.separator} analyzed $files, $seconds seconds'); firstAnalysis = false; } @@ -807,6 +807,7 @@ class AnalysisError implements Comparable { @override String toString() { String relativePath = path.relative(file); - return '${severity.toLowerCase().padLeft(7)} • $message • $relativePath:$startLine:$startColumn'; + String sep = logger.separator; + return '${severity.toLowerCase().padLeft(7)} $sep $message $sep $relativePath:$startLine:$startColumn'; } } diff --git a/packages/flutter_tools/lib/src/device.dart b/packages/flutter_tools/lib/src/device.dart index 637e005b63..4496be15a4 100644 --- a/packages/flutter_tools/lib/src/device.dart +++ b/packages/flutter_tools/lib/src/device.dart @@ -223,8 +223,8 @@ abstract class Device { for (Device device in devices) { String supportIndicator = device.isSupported() ? '' : ' (unsupported)'; - printStatus('${device.name.padRight(nameWidth)} • ' - '${device.id.padRight(idWidth)} • ' + printStatus('${device.name.padRight(nameWidth)} ${logger.separator} ' + '${device.id.padRight(idWidth)} ${logger.separator} ' '${getNameForTargetPlatform(device.platform)}$supportIndicator'); } } diff --git a/packages/flutter_tools/lib/src/doctor.dart b/packages/flutter_tools/lib/src/doctor.dart index 2bb9857616..e6e0760b06 100644 --- a/packages/flutter_tools/lib/src/doctor.dart +++ b/packages/flutter_tools/lib/src/doctor.dart @@ -109,11 +109,13 @@ class Doctor { else printStatus('${result.leadingBox} ${validator.title}'); + final String separator = Platform.isWindows ? ' ' : logger.separator; + for (ValidationMessage message in result.messages) { if (message.isError) { printStatus(' x ${message.message.replaceAll('\n', '\n ')}'); } else { - printStatus(' • ${message.message.replaceAll('\n', '\n ')}'); + printStatus(' $separator ${message.message.replaceAll('\n', '\n ')}'); } } } @@ -160,9 +162,9 @@ class ValidationResult { String get leadingBox { if (type == ValidationType.missing) - return '[ ]'; + return '[x]'; else if (type == ValidationType.installed) - return '[✓]'; + return Platform.isWindows ? '[+]' : '[✓]'; else return '[-]'; } @@ -185,6 +187,7 @@ class _FlutterValidator extends DoctorValidator { @override ValidationResult validate() { List messages = []; + ValidationType valid = ValidationType.installed; FlutterVersion version = FlutterVersion.getVersion(); @@ -195,7 +198,16 @@ class _FlutterValidator extends DoctorValidator { 'engine revision ${version.engineRevisionShort}' )); - return new ValidationResult(ValidationType.installed, messages, + if (Platform.isWindows) { + valid = ValidationType.missing; + + messages.add(new ValidationMessage.error( + 'Flutter tools are not (yet) supported on Windows: ' + 'https://github.com/flutter/flutter/issues/138.' + )); + } + + return new ValidationResult(valid, messages, statusInfo: 'on ${osName()}, channel ${version.channel}'); } } @@ -247,7 +259,9 @@ class _AtomValidator extends DoctorValidator { } return new ValidationResult( - installCount == 2 ? ValidationType.installed : installCount == 1 ? ValidationType.partial : ValidationType.missing, + installCount == 2 + ? ValidationType.installed + : installCount == 1 ? ValidationType.partial : ValidationType.missing, messages ); }