| // 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, '-'); |