| // Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file |
| // for details. 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:path/path.dart' as p; |
| |
| /// Returns a port that is probably, but not definitely, not in use. |
| /// |
| /// This has a built-in race condition: another process may bind this port at |
| /// any time after this call has returned. |
| Future<int> findUnusedPort() async { |
| int port; |
| ServerSocket socket; |
| try { |
| socket = await ServerSocket.bind(InternetAddress.loopbackIPv6, 0); |
| } on SocketException { |
| socket = await ServerSocket.bind(InternetAddress.loopbackIPv4, 0); |
| } |
| port = socket.port; |
| await socket.close(); |
| return port; |
| } |
| |
| /// Copy directory [from] to [to]. |
| /// |
| /// Updates contents of [to] if already exists. |
| Future<void> updatePath(String from, String to) async { |
| await _removeDeleted(from, to); |
| await _copyUpdated(from, to); |
| } |
| |
| // Update modified files. |
| Future<void> _copyUpdated(String from, String to) async { |
| if (!Directory(from).existsSync()) return; |
| await Directory(to).create(recursive: true); |
| |
| await for (final file in Directory(from).list()) { |
| final copyTo = p.join(to, p.relative(file.path, from: from)); |
| if (file is Directory) { |
| await _copyUpdated(file.path, copyTo); |
| } else if (file is File) { |
| final copyToFile = File(copyTo); |
| if (!copyToFile.existsSync() || |
| copyToFile.statSync().modified.compareTo(file.statSync().modified) < |
| 0) { |
| await File(file.path).copy(copyTo); |
| } |
| } else if (file is Link) { |
| await Link(copyTo).create(await file.target(), recursive: true); |
| } |
| } |
| } |
| |
| // Remove deleted files. |
| Future<void> _removeDeleted(String from, String to) async { |
| if (!Directory(from).existsSync()) { |
| if (Directory(to).existsSync()) { |
| await Directory(to).delete(recursive: true); |
| } |
| return; |
| } |
| |
| if (!Directory(to).existsSync()) return; |
| await for (final file in Directory(to).list()) { |
| final copyFrom = p.join(from, p.relative(file.path, from: to)); |
| if (file is File) { |
| final copyFromFile = File(copyFrom); |
| if (!copyFromFile.existsSync()) { |
| await File(file.path).delete(); |
| } |
| } else if (file is Directory) { |
| final copyFromDir = Directory(copyFrom); |
| await _removeDeleted(copyFromDir.path, file.path); |
| } else if (file is Link) { |
| final copyFromDir = Link(copyFrom); |
| if (!copyFromDir.existsSync()) { |
| await Link(file.path).delete(); |
| } |
| } |
| } |
| } |
| |
| /// Returns the absolute file path of the `package_config.json` file in the `.dart_tool` |
| /// directory, searching recursively from the current directory hierarchy. |
| String? findPackageConfigFilePath() { |
| var candidateDir = Directory(p.current).absolute; |
| |
| while (true) { |
| final candidatePackageConfigFile = |
| File(p.join(candidateDir.path, '.dart_tool', 'package_config.json')); |
| |
| if (candidatePackageConfigFile.existsSync()) { |
| return candidatePackageConfigFile.path; |
| } |
| |
| final parentDir = candidateDir.parent; |
| if (parentDir.path == candidateDir.path) { |
| // We've reached the root directory |
| return null; |
| } |
| |
| candidateDir = parentDir; |
| } |
| } |