blob: 529883177a9192c2e28045a51956a6ecc5a7e400 [file] [log] [blame]
// 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.
import 'dart:io';
import 'shared.dart' as util;
// Abstraction over files fetched from the `unicode.org/Public` UCD repository.
// If any of these URIs stop working, find out where they have moved to.
final graphemeBreakPropertyData = DataFile(
'https://unicode.org/Public/UCD/latest/ucd/auxiliary/GraphemeBreakProperty.txt',
'third_party/Unicode_Consortium/GraphemeBreakProperty.txt',
);
final emojiData = DataFile(
'https://unicode.org/Public/UCD/latest/ucd/emoji/emoji-data.txt',
'third_party/Unicode_Consortium/emoji_data.txt',
);
final graphemeTestData = DataFile(
'https://unicode.org/Public/UCD/latest/ucd/auxiliary/GraphemeBreakTest.txt',
'third_party/Unicode_Consortium/GraphemeBreakTest.txt',
);
final emojiTestData = DataFile(
'https://unicode.org/Public/emoji/latest/emoji-test.txt',
'third_party/Unicode_Consortium/emoji_test.txt',
);
final licenseFile = DataFile(
'https://www.unicode.org/license.txt',
'third_party/Unicode_Consortium/UNICODE_LICENSE.txt',
);
final derivedData = DataFile(
'https://unicode.org/Public/UCD/latest/ucd/DerivedCoreProperties.txt',
'third_party/Unicode_Consortium/DerivedCoreProperties.txt',
);
class DataFile {
/// Source URI.
final String sourceLocation;
/// Target file path relative to package root.
final String targetLocation;
/// Cached contents.
String? _contents;
DataFile(this.sourceLocation, this.targetLocation);
Future<String> get contents async => _contents ??= await load();
/// Loads file, fetching it from the source first if necessary.
///
/// If [checkForUpdate] is `false`, the content of an existing file at
/// [targetLocation] is read. If there is no file or if [checkForUpdate]
/// is `true`, new content is fetched from the [sourceLocation] URI
/// and written to the [targetLocation] file.
Future<String> load({bool checkForUpdate = false}) async =>
(checkForUpdate ? null : _contents) ??
(_contents = await util.fetch(
sourceLocation,
targetFile: _targetFile,
forceLoad: checkForUpdate,
));
/// Fetches content, compares to existing content.
///
/// Returns `null` if no change, a path to a temporary file containing the
/// new content if there are changes.
Future<String?> checkChange([bool Function(String, String)? equals]) async {
equals ??= _eq;
var contents = await this.contents;
var tmpFile = File(util.tmpPath(targetLocation));
var newContents = await util.fetch(
sourceLocation,
targetFile: tmpFile,
forceLoad: true,
);
if (equals(contents, newContents)) {
return null;
}
return tmpFile.path;
}
static bool _eq(String a, String b) => a == b;
void copyFrom(String contentPath) {
_contents = null;
File(contentPath).copySync(_targetFile.path);
}
File get _targetFile => File(util.packagePath(targetLocation));
}