forked from firka/firka
codegen: add lock files
This commit is contained in:
18
firka_wear/codegen-lock.yaml
Normal file
18
firka_wear/codegen-lock.yaml
Normal file
@@ -0,0 +1,18 @@
|
||||
icons:
|
||||
"flutter_launcher_icons.yaml": "2c1bf9056dfe8db94333143643d2b46308fa332e08de9eda62046a941e83aaaa"
|
||||
"pubspec.yaml": "6be6ac0844c8554f0e2d3eb4d60adf3debae1b29528b4cfba2023d0ccc5e33bf"
|
||||
"assets/images/logos/colored_logo.png": "ff9c3452b1b0ed07ffa9067fa4cf4dae45dad3e46f5cb6ef4a62ac8c05d8c080"
|
||||
"assets/images/logos/monochrome_logo.png": "188d2b0a64c70323b09bcee721663d6698fb557066f20ddaec97bba6869c1c6c"
|
||||
"assets/images/logos/colored_logo_without_mustache.png": "d11cff9f38985885873bfdd2d84e61f8fab03803eada94d4caac1545ef3685f3"
|
||||
"assets/images/logos/colored_logo_only_mustache.png": "bad6220c11bdfb1dfe04e5173bd2ebedd3999689d4b3a68fc63dc520c96dd33b"
|
||||
l10n:
|
||||
"l10n.yml": "a57bc304cac4a2b0235593586f17f400a5165d67fc9aadeaa11893cfa36ee082"
|
||||
"lib/l10n/app_de.arb": "55f030b312cc07ff05cdc3d6ee10ef9bdec3243b507225e9a47196444518d955"
|
||||
"lib/l10n/app_en.arb": "efac3f14d8ecc3e278f80a3e5aff599a88e408d2e30ff9e30f889978f465823a"
|
||||
"lib/l10n/app_hu.arb": "a7f61bf4452a639d61c350f6674fdb5fd424f9ab31a195a200d446763fa8b396"
|
||||
isar:
|
||||
"lib/data/models/app_settings_model.dart": "2bf4d089ccfcb73edbca5b2d5757e1e698ddde2b8783d212a870aac3157fbb5b"
|
||||
"lib/data/models/generic_cache_model.dart": "dd9979a4f0ba37ce5fd733bf0966088a759b5f356d97ea09c65eefffe8984639"
|
||||
"lib/data/models/homework_cache_model.dart": "911748133c4bcb32bebe40a7c2f6f30d63c030b89a77c6825ec19643d8f8b3c6"
|
||||
"lib/data/models/timetable_cache_model.dart": "078cbc0c5b1e3f0303a56bfe1e55df7669f0b06687ba399ddcae2df2b565d4c7"
|
||||
"lib/data/models/token_model.dart": "3dc6211102c00d8382bfaa929e0ca7dedd7b1771c337f4e96d54e47572e5f6e1"
|
||||
@@ -65,9 +65,11 @@ dependencies:
|
||||
|
||||
dev_dependencies:
|
||||
build_runner: any
|
||||
crypto: ^3.0.6
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
flutter_lints: ^6.0.0
|
||||
yaml: ^3.1.2
|
||||
isar_community_generator: 3.3.0
|
||||
android_notification_icons: ^0.0.1
|
||||
integration_test:
|
||||
|
||||
@@ -1,32 +1,43 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:crypto/crypto.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:yaml/yaml.dart' as yaml;
|
||||
|
||||
const _lockFileName = 'codegen-lock.yaml';
|
||||
|
||||
void main() async {
|
||||
final root = _projectRoot();
|
||||
var ran = false;
|
||||
|
||||
if (_iconsOutOfDate(root)) {
|
||||
final inputs = _iconsInputs(root);
|
||||
stdout.writeln('Icons out of date, running flutter_launcher_icons...');
|
||||
await _run('dart', ['run', 'flutter_launcher_icons'], root);
|
||||
_updateLockWithHashes(root, 'icons', _computeHashes(root, inputs));
|
||||
ran = true;
|
||||
}
|
||||
|
||||
if (_l10nOutOfDate(root)) {
|
||||
final inputs = _l10nInputs(root);
|
||||
stdout.writeln('l10n out of date, running flutter gen-l10n...');
|
||||
await _run('flutter', [
|
||||
'gen-l10n',
|
||||
'--template-arb-file',
|
||||
'app_hu.arb',
|
||||
], root);
|
||||
_updateLockWithHashes(root, 'l10n', _computeHashes(root, inputs));
|
||||
ran = true;
|
||||
}
|
||||
|
||||
if (_isarOutOfDate(root)) {
|
||||
final inputs = _isarInputs(root);
|
||||
final hashes = _computeHashes(root, inputs);
|
||||
stdout.writeln(
|
||||
'Isar generated dart files out of date, running build_runner...',
|
||||
);
|
||||
await _run('dart', ['run', 'build_runner', 'build'], root);
|
||||
_updateLockWithHashes(root, 'isar', hashes);
|
||||
ran = true;
|
||||
}
|
||||
|
||||
@@ -37,7 +48,92 @@ void main() async {
|
||||
|
||||
String _projectRoot() {
|
||||
final script = p.canonicalize(Platform.script.toFilePath());
|
||||
return p.dirname(p.dirname(script));
|
||||
return p.canonicalize(p.dirname(p.dirname(script)));
|
||||
}
|
||||
|
||||
String _lockPath(String root) => p.join(root, _lockFileName);
|
||||
|
||||
Map<String, Map<String, String>>? _readLock(String root) {
|
||||
final file = File(_lockPath(root));
|
||||
if (!file.existsSync()) return null;
|
||||
try {
|
||||
final content = file.readAsStringSync();
|
||||
final decoded = yaml.loadYaml(content);
|
||||
if (decoded is! Map) return null;
|
||||
final result = <String, Map<String, String>>{};
|
||||
for (final entry in decoded.entries) {
|
||||
if (entry.value is! Map) continue;
|
||||
final inner = entry.value as Map;
|
||||
result[entry.key.toString()] = inner.map(
|
||||
(k, v) => MapEntry(
|
||||
Platform.isWindows ? k.toString().toLowerCase() : k.toString(),
|
||||
v?.toString() ?? '',
|
||||
),
|
||||
);
|
||||
}
|
||||
return result;
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
void _writeLock(String root, Map<String, Map<String, String>> lock) {
|
||||
final buf = StringBuffer();
|
||||
for (final stepEntry in lock.entries) {
|
||||
buf.writeln('${stepEntry.key}:');
|
||||
for (final fileEntry in stepEntry.value.entries) {
|
||||
buf.writeln(
|
||||
' "${_escapeYaml(fileEntry.key)}": "${_escapeYaml(fileEntry.value)}"',
|
||||
);
|
||||
}
|
||||
}
|
||||
File(_lockPath(root)).writeAsStringSync(buf.toString());
|
||||
}
|
||||
|
||||
String _escapeYaml(String s) =>
|
||||
s.replaceAll('\\', '\\\\').replaceAll('"', '\\"');
|
||||
|
||||
String _fileHash(File file) {
|
||||
final bytes = file.readAsBytesSync();
|
||||
final digest = sha256.convert(bytes);
|
||||
return digest.toString();
|
||||
}
|
||||
|
||||
String _relativePath(String root, File file) {
|
||||
final rel = p.relative(file.path, from: root);
|
||||
final normalized = rel.replaceAll('\\', '/');
|
||||
return Platform.isWindows ? normalized.toLowerCase() : normalized;
|
||||
}
|
||||
|
||||
bool _hashesMatch(
|
||||
String root,
|
||||
String stepName,
|
||||
List<File> inputs,
|
||||
Map<String, Map<String, String>>? lock,
|
||||
) {
|
||||
if (lock == null || !lock.containsKey(stepName)) return false;
|
||||
final stepHashes = lock[stepName]!;
|
||||
for (final f in inputs) {
|
||||
final rel = _relativePath(root, f);
|
||||
final stored = stepHashes[rel];
|
||||
if (stored == null || stored != _fileHash(f)) return false;
|
||||
}
|
||||
if (stepHashes.length != inputs.length) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
Map<String, String> _computeHashes(String root, List<File> inputs) {
|
||||
return {for (final f in inputs) _relativePath(root, f): _fileHash(f)};
|
||||
}
|
||||
|
||||
void _updateLockWithHashes(
|
||||
String root,
|
||||
String stepName,
|
||||
Map<String, String> hashes,
|
||||
) {
|
||||
final lock = _readLock(root) ?? <String, Map<String, String>>{};
|
||||
lock[stepName] = Map.from(hashes);
|
||||
_writeLock(root, lock);
|
||||
}
|
||||
|
||||
DateTime? _modified(File file) {
|
||||
@@ -55,7 +151,7 @@ bool _anyNewerThan(Iterable<File> inputs, File output) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool _iconsOutOfDate(String root) {
|
||||
List<File> _iconsInputs(String root) {
|
||||
final config = File(p.join(root, 'flutter_launcher_icons.yaml'));
|
||||
final pubspec = File(p.join(root, 'pubspec.yaml'));
|
||||
final imagePath = File(p.join(root, 'assets/images/logos/colored_logo.png'));
|
||||
@@ -68,25 +164,25 @@ bool _iconsOutOfDate(String root) {
|
||||
final foreground = File(
|
||||
p.join(root, 'assets/images/logos/colored_logo_only_mustache.png'),
|
||||
);
|
||||
return [config, pubspec, imagePath, monochrome, background, foreground]
|
||||
.where((f) => f.existsSync())
|
||||
.map((f) => File(p.canonicalize(f.path)))
|
||||
.toList();
|
||||
}
|
||||
|
||||
final inputs = [
|
||||
config,
|
||||
pubspec,
|
||||
imagePath,
|
||||
monochrome,
|
||||
background,
|
||||
foreground,
|
||||
].where((f) => f.existsSync()).map((f) => File(p.canonicalize(f.path)));
|
||||
bool _iconsOutOfDate(String root) {
|
||||
final inputs = _iconsInputs(root);
|
||||
final output = File(
|
||||
p.join(
|
||||
root,
|
||||
'android/app/src/main/res/mipmap-anydpi-v26/launcher_icon.xml',
|
||||
),
|
||||
);
|
||||
return _anyNewerThan(inputs, output);
|
||||
if (!_anyNewerThan(inputs, output)) return false;
|
||||
return !_hashesMatch(root, 'icons', inputs, _readLock(root));
|
||||
}
|
||||
|
||||
bool _l10nOutOfDate(String root) {
|
||||
List<File> _l10nInputs(String root) {
|
||||
final l10nDir = p.join(root, 'lib/l10n');
|
||||
final l10nYml = File(p.join(root, 'l10n.yml'));
|
||||
final arbs = Directory(l10nDir)
|
||||
@@ -95,25 +191,39 @@ bool _l10nOutOfDate(String root) {
|
||||
.where((f) => f.path.endsWith('.arb'))
|
||||
.map((f) => File(p.canonicalize(f.path)))
|
||||
.toList();
|
||||
final inputs = [l10nYml, ...arbs].where((f) => f.existsSync()).cast<File>();
|
||||
final output = File(p.join(root, 'lib/l10n/app_localizations.dart'));
|
||||
return _anyNewerThan(inputs, output);
|
||||
return [l10nYml, ...arbs].where((f) => f.existsSync()).cast<File>().toList();
|
||||
}
|
||||
|
||||
bool _isarOutOfDate(String root) {
|
||||
final modelsDir = p.join(root, 'lib/data/models');
|
||||
if (!Directory(modelsDir).existsSync()) return false;
|
||||
bool _l10nOutOfDate(String root) {
|
||||
final inputs = _l10nInputs(root);
|
||||
final output = File(p.join(root, 'lib/l10n/app_localizations.dart'));
|
||||
if (!_anyNewerThan(inputs, output)) return false;
|
||||
return !_hashesMatch(root, 'l10n', inputs, _readLock(root));
|
||||
}
|
||||
|
||||
List<File> _isarInputs(String root) {
|
||||
final modelsDir = p.join(root, 'lib/data/models');
|
||||
if (!Directory(modelsDir).existsSync()) return [];
|
||||
final list = <File>[];
|
||||
for (final entity in Directory(modelsDir).listSync()) {
|
||||
if (entity is! File || !entity.path.endsWith('.dart')) continue;
|
||||
final content = entity.readAsStringSync();
|
||||
if (!content.contains("part '") || !content.contains('.g.dart')) continue;
|
||||
list.add(File(p.canonicalize(entity.path)));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
final baseName = p.basenameWithoutExtension(entity.path);
|
||||
final gPath = p.join(modelsDir, '$baseName.g.dart');
|
||||
final dartFile = File(p.canonicalize(entity.path));
|
||||
final gFile = File(gPath);
|
||||
if (_anyNewerThan([dartFile], gFile)) return true;
|
||||
bool _isarOutOfDate(String root) {
|
||||
final inputs = _isarInputs(root);
|
||||
if (inputs.isEmpty) return false;
|
||||
final modelsDir = p.join(root, 'lib/data/models');
|
||||
for (final dartFile in inputs) {
|
||||
final baseName = p.basenameWithoutExtension(dartFile.path);
|
||||
final gFile = File(p.join(modelsDir, '$baseName.g.dart'));
|
||||
if (_anyNewerThan([dartFile], gFile)) {
|
||||
return !_hashesMatch(root, 'isar', inputs, _readLock(root));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user