| // Copyright (c) 2018, 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:convert'; | |
| import 'dart:io'; | |
| import 'data_files.dart'; | |
| // Shared tools used by other libraries. | |
| /// Quick and dirty caching URI loader. | |
| /// | |
| /// Reads from [targetFile] if it exists and [forceLoad] is not `true`. | |
| /// Otherwise fetches from [location] URI and stores in [targetFile]. | |
| /// | |
| /// If [targetFile] is omitted, a file in the system temporary directory | |
| /// is used instead. | |
| Future<String> fetch( | |
| String location, { | |
| File? targetFile, | |
| bool forceLoad = false, | |
| }) async { | |
| if (targetFile == null) { | |
| var safeLocation = safePath(location); | |
| targetFile = File(path(Directory.systemTemp.path, safeLocation)); | |
| } | |
| if (!forceLoad && targetFile.existsSync()) { | |
| return targetFile.readAsString(); | |
| } | |
| var uri = Uri.parse(location); | |
| String contents; | |
| if (uri.isScheme('file')) { | |
| contents = File.fromUri(uri).readAsStringSync(); | |
| } else { | |
| var client = HttpClient(); | |
| var request = await client.getUrl(uri); | |
| var response = await request.close(); | |
| if (response.statusCode != HttpStatus.ok) { | |
| throw HttpException(response.reasonPhrase, uri: uri); | |
| } | |
| contents = await utf8.decoder.bind(response).join(); | |
| client.close(); | |
| } | |
| writeToPath(targetFile, contents); | |
| return contents; | |
| } | |
| /// Writes string to file. | |
| /// | |
| /// Ensures directory of file exits. | |
| void writeToPath(File targetFile, String contents) { | |
| var parentDir = Directory(parentPath(targetFile.path)); | |
| parentDir.createSync(recursive: true); | |
| targetFile.writeAsStringSync(contents); | |
| } | |
| // Parent directory path of file or directory path. | |
| String parentPath(String path) { | |
| var end = path.length; | |
| if (path.endsWith('/')) end -= 1; | |
| var lastSlash = path.lastIndexOf('/', end); | |
| if (lastSlash >= 0) { | |
| return path.substring(0, lastSlash + 1); | |
| } | |
| if (path == '/') return path; | |
| return './'; // Empty relative path. | |
| } | |
| Future<bool> checkLicense(bool acceptLicenseChange) async { | |
| if (await licenseFile.checkChange() case var changedLicensePath?) { | |
| if (!acceptLicenseChange) { | |
| stderr.writeln( | |
| licenseChangeWarning(licenseFile.targetLocation, changedLicensePath), | |
| ); | |
| return false; | |
| } | |
| stderr.writeln('LICENSE CHANGE ACCEPTED!'); | |
| licenseFile.copyFrom(changedLicensePath); | |
| } else if (acceptLicenseChange) { | |
| stderr.writeln('Accepting license change with no change.'); | |
| stderr.writeln('DO NOT AUTOMATE LICENSE ACCEPTANCE!'); | |
| return false; | |
| } | |
| return true; | |
| } | |
| /// Warning shown if the license has changed. | |
| String licenseChangeWarning(String originalPath, String newPath) => ''' | |
| **NOTICE** | |
| The license file has changed. Check that it has not changed meaning. | |
| See changes using: | |
| git diff ${_windowize(originalPath)} ${_windowize(newPath)} | |
| '''; | |
| const copyright = ''' | |
| // Copyright (c) 2023, 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. | |
| '''; | |
| // Generated file header: | |
| void writeHeader(StringSink output, List<DataFile> dependencies) { | |
| output | |
| ..write(copyright) | |
| ..writeln('// Generated code. Do not edit.') | |
| ..writeln('// Generated from:'); | |
| for (var sourceFile in dependencies) { | |
| output | |
| ..write('// - [') | |
| ..write(sourceFile.sourceLocation) | |
| ..write('](../../') | |
| ..write(sourceFile.targetLocation) | |
| ..writeln(')'); | |
| } | |
| output | |
| ..writeln('// Licensed under the Unicode Inc. License Agreement') | |
| ..writeln( | |
| '// (${licenseFile.sourceLocation}, ' | |
| '../../third_party/${licenseFile.targetLocation})', | |
| ); | |
| } | |
| /// Temporary directory. Created once and for all. | |
| Directory get tmpDirectory => _tmpDirectory ??= | |
| Directory.systemTemp.createTempSync('dart_pkg_characters'); | |
| Directory? _tmpDirectory; | |
| /// Combines file paths into one path. | |
| /// | |
| /// No fancy stuff, just adds path separator between parts, | |
| /// if previous part doesn't end with one. | |
| /// (Don't let later parts start with a path separator!) | |
| /// Converts forward slashes to backwards slashes in Windows. | |
| /// | |
| /// Empty parts are ignored. | |
| String path(String path, [String path2 = '', String path3 = '']) { | |
| var separator = Platform.pathSeparator; | |
| path = _windowize(path); | |
| if (path2.isEmpty && path3.isEmpty) return path; | |
| var buffer = StringBuffer(path); | |
| var prev = path; | |
| for (var part in [path2, path3]) { | |
| if (part.isEmpty) continue; | |
| part = _windowize(part); | |
| if (!prev.endsWith(separator)) { | |
| buffer.write(separator); | |
| } | |
| buffer.write(part); | |
| prev = part; | |
| } | |
| return buffer.toString(); | |
| } | |
| /// Converts path to Windows path if on Windows (`/` to `\`). | |
| /// | |
| /// Returns original path if not on Windows. | |
| String _windowize(String path) => | |
| Platform.isWindows ? path.replaceAll('/', r'') : path; | |
| /// Package root directory. | |
| String packageRoot = _findRootDir().path; | |
| /// A path relative to the [packageRoot]. | |
| String packagePath(String path2, [String path3 = '']) => | |
| path(packageRoot, path2, path3); | |
| /// A path relative to a temporary directory. | |
| String tmpPath(String path2, [String path3 = '']) => | |
| path(tmpDirectory.path, path2, path3); | |
| /// Finds package root in the parent chain of the current directory. | |
| /// | |
| /// Recognizes package root by `pubspec.yaml` file. | |
| Directory _findRootDir() { | |
| var dir = Directory.current; | |
| while (true) { | |
| var pubspec = File('${dir.path}${Platform.pathSeparator}pubspec.yaml'); | |
| if (pubspec.existsSync()) return dir; | |
| var parent = dir.parent; | |
| if (dir.path == parent.path) { | |
| throw UnsupportedError( | |
| 'Cannot find package root directory. Run tools from inside package!', | |
| ); | |
| } | |
| } | |
| } | |
| /// Leading-zero padding. | |
| String lz(int n, [int length = 2]) => n.toString().padLeft(length, '0'); | |
| final _unsafeCharsRE = RegExp(r'\W+'); | |
| // Convert URI path to safe file path. | |
| String safePath(String uriPath) => uriPath.replaceAll(_unsafeCharsRE, '-'); |