// 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:core' as core_internals show print; import 'dart:core' hide print; import 'dart:io' as system show exit; import 'dart:io' hide exit; import 'package:meta/meta.dart'; final bool hasColor = stdout.supportsAnsiEscapes; final String bold = hasColor ? '\x1B[1m' : ''; // used for shard titles final String red = hasColor ? '\x1B[31m' : ''; // used for errors final String green = hasColor ? '\x1B[32m' : ''; // used for section titles, commands final String yellow = hasColor ? '\x1B[33m' : ''; // used for skips final String cyan = hasColor ? '\x1B[36m' : ''; // used for paths final String reverse = hasColor ? '\x1B[7m' : ''; // used for clocks final String reset = hasColor ? '\x1B[0m' : ''; final String redLine = '$red━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━$reset'; typedef PrintCallback = void Function(Object line); // Allow print() to be overridden, for tests. PrintCallback print = core_internals.print; bool get hasError => _hasError; bool _hasError = false; Iterable get errorMessages => _errorMessages; List _errorMessages = []; void foundError(List messages) { assert(messages.isNotEmpty); print(redLine); messages.forEach(print); print(redLine); _errorMessages.addAll(messages); _hasError = true; } @visibleForTesting void resetErrorStatus() { _hasError = false; _errorMessages.clear(); } Never reportErrorsAndExit() { print(redLine); print('For your convenience, the error messages reported above are repeated here:'); _errorMessages.forEach(print); print(redLine); system.exit(1); } String get clock { final DateTime now = DateTime.now(); return '$reverse▌' '${now.hour.toString().padLeft(2, "0")}:' '${now.minute.toString().padLeft(2, "0")}:' '${now.second.toString().padLeft(2, "0")}' '▐$reset'; } String prettyPrintDuration(Duration duration) { String result = ''; final int minutes = duration.inMinutes; if (minutes > 0) { result += '${minutes}min '; } final int seconds = duration.inSeconds - minutes * 60; final int milliseconds = duration.inMilliseconds - (seconds * 1000 + minutes * 60 * 1000); result += '$seconds.${milliseconds.toString().padLeft(3, "0")}s'; return result; } void printProgress(String action, String workingDir, String command) { print('$clock $action: cd $cyan$workingDir$reset; $green$command$reset'); } int _portCounter = 8080; /// Finds the next available local port. Future findAvailablePort() async { while (!await _isPortAvailable(_portCounter)) { _portCounter += 1; } return _portCounter++; } Future _isPortAvailable(int port) async { try { final RawSocket socket = await RawSocket.connect('localhost', port); socket.shutdown(SocketDirection.both); await socket.close(); return false; } on SocketException { return true; } }