Pre-format licenses script (flutter/engine#57219)
The license script has load-baring formatting: Changing its format makes signature checks fail. To ensure the formatting change goes in smoothly later this week I am taking it off the critical path by pre-formatting it. The script itself is fairly stable, so I am not expecting any changes to it between now and when we actually enforce formatting. Edit: The issue that surfaced with `ci/licenses_golden/licenses_dart` is another reason to take this off the critical path of enforcing formatting.
This commit is contained in:
parent
93d08f2c1a
commit
d00bfbb87a
@ -1,2 +1,2 @@
|
|||||||
Signature: 08cd2e281007e92182d3d540ff50e0ad
|
Signature: ddf9867e4034dc9bd94a9e107c31752e
|
||||||
|
|
||||||
|
@ -26,9 +26,17 @@ enum FileType {
|
|||||||
|
|
||||||
typedef Reader = List<int> Function();
|
typedef Reader = List<int> Function();
|
||||||
|
|
||||||
class BytesOf extends Key { BytesOf(super.value); }
|
class BytesOf extends Key {
|
||||||
class UTF8Of extends Key { UTF8Of(super.value); }
|
BytesOf(super.value);
|
||||||
class Latin1Of extends Key { Latin1Of(super.value); }
|
}
|
||||||
|
|
||||||
|
class UTF8Of extends Key {
|
||||||
|
UTF8Of(super.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Latin1Of extends Key {
|
||||||
|
Latin1Of(super.value);
|
||||||
|
}
|
||||||
|
|
||||||
bool matchesSignature(List<int> bytes, List<int> signature) {
|
bool matchesSignature(List<int> bytes, List<int> signature) {
|
||||||
if (bytes.length < signature.length) {
|
if (bytes.length < signature.length) {
|
||||||
@ -66,71 +74,136 @@ const String kMultiLicenseFileHeader = 'Notices for files contained in';
|
|||||||
|
|
||||||
bool isMultiLicenseNotice(Reader reader) {
|
bool isMultiLicenseNotice(Reader reader) {
|
||||||
final List<int> bytes = reader();
|
final List<int> bytes = reader();
|
||||||
return ascii.decode(bytes.take(kMultiLicenseFileHeader.length).toList(), allowInvalid: true) == kMultiLicenseFileHeader;
|
return ascii.decode(bytes.take(kMultiLicenseFileHeader.length).toList(), allowInvalid: true) ==
|
||||||
|
kMultiLicenseFileHeader;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileType identifyFile(String name, Reader reader) {
|
FileType identifyFile(String name, Reader reader) {
|
||||||
List<int>? bytes;
|
List<int>? bytes;
|
||||||
if ((path.split(name).reversed.take(6).toList().reversed.join('/') == 'third_party/icu/source/extra/uconv/README') || // This specific ICU README isn't in UTF-8.
|
if ((path.split(name).reversed.take(6).toList().reversed.join('/') ==
|
||||||
(path.split(name).reversed.take(6).toList().reversed.join('/') == 'third_party/icu/source/samples/uresb/sr.txt') || // This specific sample contains non-UTF-8 data (unlike other sr.txt files).
|
'third_party/icu/source/extra/uconv/README') || // This specific ICU README isn't in UTF-8.
|
||||||
(path.split(name).reversed.take(2).toList().reversed.join('/') == 'builds/detect.mk') || // This specific freetype sample contains non-UTF-8 data (unlike other .mk files).
|
(path.split(name).reversed.take(6).toList().reversed.join('/') ==
|
||||||
|
'third_party/icu/source/samples/uresb/sr.txt') || // This specific sample contains non-UTF-8 data (unlike other sr.txt files).
|
||||||
|
(path.split(name).reversed.take(2).toList().reversed.join('/') ==
|
||||||
|
'builds/detect.mk') || // This specific freetype sample contains non-UTF-8 data (unlike other .mk files).
|
||||||
(path.split(name).reversed.take(3).toList().reversed.join('/') == 'third_party/cares/cares.rc')) {
|
(path.split(name).reversed.take(3).toList().reversed.join('/') == 'third_party/cares/cares.rc')) {
|
||||||
return FileType.latin1Text;
|
return FileType.latin1Text;
|
||||||
}
|
}
|
||||||
if (path.split(name).reversed.take(6).toList().reversed.join('/') == 'dart/runtime/tests/vm/dart/bad_snapshot') { // Not any particular format
|
if (path.split(name).reversed.take(6).toList().reversed.join('/') ==
|
||||||
|
'dart/runtime/tests/vm/dart/bad_snapshot') {
|
||||||
|
// Not any particular format
|
||||||
return FileType.binary;
|
return FileType.binary;
|
||||||
}
|
}
|
||||||
if (path.split(name).reversed.take(9).toList().reversed.join('/') == 'fuchsia/sdk/linux/dart/zircon/lib/src/fakes/handle_disposition.dart' || // has bogus but benign "authors" reference, reported to jamesr@
|
if (path.split(name).reversed.take(9).toList().reversed.join('/') ==
|
||||||
path.split(name).reversed.take(6).toList().reversed.join('/') == 'third_party/angle/src/common/fuchsia_egl/fuchsia_egl.c' || // has bogus but benign "authors" reference, reported to author and legal team
|
'fuchsia/sdk/linux/dart/zircon/lib/src/fakes/handle_disposition.dart' || // has bogus but benign "authors" reference, reported to jamesr@
|
||||||
path.split(name).reversed.take(6).toList().reversed.join('/') == 'third_party/angle/src/common/fuchsia_egl/fuchsia_egl.h' || // has bogus but benign "authors" reference, reported to author and legal team
|
path.split(name).reversed.take(6).toList().reversed.join('/') ==
|
||||||
path.split(name).reversed.take(6).toList().reversed.join('/') == 'third_party/angle/src/common/fuchsia_egl/fuchsia_egl_backend.h') { // has bogus but benign "authors" reference, reported to author and legal team
|
'third_party/angle/src/common/fuchsia_egl/fuchsia_egl.c' || // has bogus but benign "authors" reference, reported to author and legal team
|
||||||
|
path.split(name).reversed.take(6).toList().reversed.join('/') ==
|
||||||
|
'third_party/angle/src/common/fuchsia_egl/fuchsia_egl.h' || // has bogus but benign "authors" reference, reported to author and legal team
|
||||||
|
path.split(name).reversed.take(6).toList().reversed.join('/') ==
|
||||||
|
'third_party/angle/src/common/fuchsia_egl/fuchsia_egl_backend.h') {
|
||||||
|
// has bogus but benign "authors" reference, reported to author and legal team
|
||||||
return FileType.binary;
|
return FileType.binary;
|
||||||
}
|
}
|
||||||
if (path.split(name).reversed.take(6).toList().reversed.join('/') == 'flutter/third_party/brotli/c/common/dictionary.bin.br') { // Brotli-compressed Brotli dictionary
|
if (path.split(name).reversed.take(6).toList().reversed.join('/') ==
|
||||||
|
'flutter/third_party/brotli/c/common/dictionary.bin.br') {
|
||||||
|
// Brotli-compressed Brotli dictionary
|
||||||
return FileType.binary;
|
return FileType.binary;
|
||||||
}
|
}
|
||||||
final String base = path.basename(name);
|
final String base = path.basename(name);
|
||||||
if (base.startsWith('._')) {
|
if (base.startsWith('._')) {
|
||||||
bytes ??= reader();
|
bytes ??= reader();
|
||||||
if (matchesSignature(bytes, <int>[0x00, 0x05, 0x16, 0x07, 0x00, 0x02, 0x00, 0x00, 0x4d, 0x61, 0x63, 0x20, 0x4f, 0x53, 0x20, 0x58])) {
|
if (matchesSignature(bytes, <int>[
|
||||||
|
0x00,
|
||||||
|
0x05,
|
||||||
|
0x16,
|
||||||
|
0x07,
|
||||||
|
0x00,
|
||||||
|
0x02,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x4d,
|
||||||
|
0x61,
|
||||||
|
0x63,
|
||||||
|
0x20,
|
||||||
|
0x4f,
|
||||||
|
0x53,
|
||||||
|
0x20,
|
||||||
|
0x58,
|
||||||
|
])) {
|
||||||
return FileType.notPartOfBuild;
|
return FileType.notPartOfBuild;
|
||||||
} // The ._* files in Mac OS X archives that gives icons and stuff
|
} // The ._* files in Mac OS X archives that gives icons and stuff
|
||||||
}
|
}
|
||||||
if (path.split(name).contains('cairo')) {
|
if (path.split(name).contains('cairo')) {
|
||||||
bytes ??= reader();
|
bytes ??= reader();
|
||||||
// "Copyright <latin1 copyright symbol> "
|
// "Copyright <latin1 copyright symbol> "
|
||||||
if (hasSubsequence(bytes, <int>[0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0xA9, 0x20], kMaxSize)) {
|
if (hasSubsequence(bytes, <int>[
|
||||||
|
0x43,
|
||||||
|
0x6f,
|
||||||
|
0x70,
|
||||||
|
0x79,
|
||||||
|
0x72,
|
||||||
|
0x69,
|
||||||
|
0x67,
|
||||||
|
0x68,
|
||||||
|
0x74,
|
||||||
|
0x20,
|
||||||
|
0xA9,
|
||||||
|
0x20,
|
||||||
|
], kMaxSize)) {
|
||||||
return FileType.latin1Text;
|
return FileType.latin1Text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch (base) {
|
switch (base) {
|
||||||
// Build files
|
// Build files
|
||||||
case 'DEPS': return FileType.text;
|
case 'DEPS':
|
||||||
case 'MANIFEST': return FileType.text;
|
return FileType.text;
|
||||||
|
case 'MANIFEST':
|
||||||
|
return FileType.text;
|
||||||
// Licenses
|
// Licenses
|
||||||
case 'COPYING': return FileType.text;
|
case 'COPYING':
|
||||||
case 'LICENSE': return FileType.text;
|
return FileType.text;
|
||||||
case 'NOTICE.txt': return isMultiLicenseNotice(reader) ? FileType.binary : FileType.text;
|
case 'LICENSE':
|
||||||
case 'NOTICE': return FileType.text;
|
return FileType.text;
|
||||||
|
case 'NOTICE.txt':
|
||||||
|
return isMultiLicenseNotice(reader) ? FileType.binary : FileType.text;
|
||||||
|
case 'NOTICE':
|
||||||
|
return FileType.text;
|
||||||
// Documentation
|
// Documentation
|
||||||
case 'Changes': return FileType.text;
|
case 'Changes':
|
||||||
case 'change.log': return FileType.text;
|
return FileType.text;
|
||||||
case 'ChangeLog': return FileType.text;
|
case 'change.log':
|
||||||
case 'CHANGES.0': return FileType.latin1Text;
|
return FileType.text;
|
||||||
case 'README': return FileType.text;
|
case 'ChangeLog':
|
||||||
case 'TODO': return FileType.text;
|
return FileType.text;
|
||||||
case 'NEWS': return FileType.text;
|
case 'CHANGES.0':
|
||||||
case 'README.chromium': return FileType.text;
|
return FileType.latin1Text;
|
||||||
case 'README.flutter': return FileType.text;
|
case 'README':
|
||||||
case 'README.tests': return FileType.text;
|
return FileType.text;
|
||||||
case 'OWNERS': return FileType.text;
|
case 'TODO':
|
||||||
case 'AUTHORS': return FileType.text;
|
return FileType.text;
|
||||||
|
case 'NEWS':
|
||||||
|
return FileType.text;
|
||||||
|
case 'README.chromium':
|
||||||
|
return FileType.text;
|
||||||
|
case 'README.flutter':
|
||||||
|
return FileType.text;
|
||||||
|
case 'README.tests':
|
||||||
|
return FileType.text;
|
||||||
|
case 'OWNERS':
|
||||||
|
return FileType.text;
|
||||||
|
case 'AUTHORS':
|
||||||
|
return FileType.text;
|
||||||
// Signatures (found in .jar files typically)
|
// Signatures (found in .jar files typically)
|
||||||
case 'CERT.RSA': return FileType.binary;
|
case 'CERT.RSA':
|
||||||
case 'ECLIPSE_.RSA': return FileType.binary;
|
return FileType.binary;
|
||||||
|
case 'ECLIPSE_.RSA':
|
||||||
|
return FileType.binary;
|
||||||
// Binary data files
|
// Binary data files
|
||||||
case 'tzdata': return FileType.binary;
|
case 'tzdata':
|
||||||
case 'compressed_atrace_data.txt': return FileType.binary;
|
return FileType.binary;
|
||||||
|
case 'compressed_atrace_data.txt':
|
||||||
|
return FileType.binary;
|
||||||
// Source files that don't use UTF-8
|
// Source files that don't use UTF-8
|
||||||
case 'Messages_de_DE.properties': // has a few non-ASCII characters they forgot to escape (from gnu-libstdc++)
|
case 'Messages_de_DE.properties': // has a few non-ASCII characters they forgot to escape (from gnu-libstdc++)
|
||||||
case 'mmx_blendtmp.h': // author name in comment contains latin1 (mesa)
|
case 'mmx_blendtmp.h': // author name in comment contains latin1 (mesa)
|
||||||
@ -154,101 +227,192 @@ FileType identifyFile(String name, Reader reader) {
|
|||||||
}
|
}
|
||||||
switch (path.extension(name)) {
|
switch (path.extension(name)) {
|
||||||
// C/C++ code
|
// C/C++ code
|
||||||
case '.h': return FileType.text;
|
case '.h':
|
||||||
case '.c': return FileType.text;
|
return FileType.text;
|
||||||
case '.cc': return FileType.text;
|
case '.c':
|
||||||
case '.cpp': return FileType.text;
|
return FileType.text;
|
||||||
case '.inc': return FileType.text;
|
case '.cc':
|
||||||
|
return FileType.text;
|
||||||
|
case '.cpp':
|
||||||
|
return FileType.text;
|
||||||
|
case '.inc':
|
||||||
|
return FileType.text;
|
||||||
// Go code
|
// Go code
|
||||||
case '.go': return FileType.text;
|
case '.go':
|
||||||
|
return FileType.text;
|
||||||
// ObjectiveC code
|
// ObjectiveC code
|
||||||
case '.m': return FileType.text;
|
case '.m':
|
||||||
|
return FileType.text;
|
||||||
// Assembler
|
// Assembler
|
||||||
case '.asm': return FileType.text;
|
case '.asm':
|
||||||
|
return FileType.text;
|
||||||
// Shell
|
// Shell
|
||||||
case '.sh': return FileType.notPartOfBuild;
|
case '.sh':
|
||||||
case '.bat': return FileType.notPartOfBuild;
|
return FileType.notPartOfBuild;
|
||||||
|
case '.bat':
|
||||||
|
return FileType.notPartOfBuild;
|
||||||
// Build files
|
// Build files
|
||||||
case '.ac': return FileType.notPartOfBuild;
|
case '.ac':
|
||||||
case '.am': return FileType.notPartOfBuild;
|
return FileType.notPartOfBuild;
|
||||||
case '.gn': return FileType.notPartOfBuild;
|
case '.am':
|
||||||
case '.gni': return FileType.notPartOfBuild;
|
return FileType.notPartOfBuild;
|
||||||
case '.gyp': return FileType.notPartOfBuild;
|
case '.gn':
|
||||||
case '.gypi': return FileType.notPartOfBuild;
|
return FileType.notPartOfBuild;
|
||||||
|
case '.gni':
|
||||||
|
return FileType.notPartOfBuild;
|
||||||
|
case '.gyp':
|
||||||
|
return FileType.notPartOfBuild;
|
||||||
|
case '.gypi':
|
||||||
|
return FileType.notPartOfBuild;
|
||||||
// Java code
|
// Java code
|
||||||
case '.java': return FileType.text;
|
case '.java':
|
||||||
case '.jar': return FileType.zip; // Java package
|
return FileType.text;
|
||||||
case '.class': return FileType.binary; // compiled Java bytecode (usually found inside .jar archives)
|
case '.jar':
|
||||||
case '.dex': return FileType.binary; // Dalvik Executable (usually found inside .jar archives)
|
return FileType.zip; // Java package
|
||||||
|
case '.class':
|
||||||
|
return FileType.binary; // compiled Java bytecode (usually found inside .jar archives)
|
||||||
|
case '.dex':
|
||||||
|
return FileType.binary; // Dalvik Executable (usually found inside .jar archives)
|
||||||
// Dart code
|
// Dart code
|
||||||
case '.dart': return FileType.text;
|
case '.dart':
|
||||||
case '.dill': return FileType.binary; // Compiled Dart code
|
return FileType.text;
|
||||||
|
case '.dill':
|
||||||
|
return FileType.binary; // Compiled Dart code
|
||||||
// LLVM bitcode
|
// LLVM bitcode
|
||||||
case '.bc': return FileType.binary;
|
case '.bc':
|
||||||
|
return FileType.binary;
|
||||||
// Python code
|
// Python code
|
||||||
case '.py':
|
case '.py':
|
||||||
bytes ??= reader();
|
bytes ??= reader();
|
||||||
// # -*- coding: Latin-1 -*-
|
// # -*- coding: Latin-1 -*-
|
||||||
if (matchesSignature(bytes, <int>[0x23, 0x20, 0x2d, 0x2a, 0x2d, 0x20, 0x63, 0x6f, 0x64,
|
if (matchesSignature(bytes, <int>[
|
||||||
0x69, 0x6e, 0x67, 0x3a, 0x20, 0x4c, 0x61, 0x74, 0x69,
|
0x23,
|
||||||
0x6e, 0x2d, 0x31, 0x20, 0x2d, 0x2a, 0x2d])) {
|
0x20,
|
||||||
|
0x2d,
|
||||||
|
0x2a,
|
||||||
|
0x2d,
|
||||||
|
0x20,
|
||||||
|
0x63,
|
||||||
|
0x6f,
|
||||||
|
0x64,
|
||||||
|
0x69,
|
||||||
|
0x6e,
|
||||||
|
0x67,
|
||||||
|
0x3a,
|
||||||
|
0x20,
|
||||||
|
0x4c,
|
||||||
|
0x61,
|
||||||
|
0x74,
|
||||||
|
0x69,
|
||||||
|
0x6e,
|
||||||
|
0x2d,
|
||||||
|
0x31,
|
||||||
|
0x20,
|
||||||
|
0x2d,
|
||||||
|
0x2a,
|
||||||
|
0x2d,
|
||||||
|
])) {
|
||||||
return FileType.latin1Text;
|
return FileType.latin1Text;
|
||||||
}
|
}
|
||||||
return FileType.text;
|
return FileType.text;
|
||||||
case '.pyc': return FileType.binary; // compiled Python bytecode
|
case '.pyc':
|
||||||
|
return FileType.binary; // compiled Python bytecode
|
||||||
// Machine code
|
// Machine code
|
||||||
case '.so': return FileType.binary; // ELF shared object
|
case '.so':
|
||||||
case '.xpt': return FileType.binary; // XPCOM Type Library
|
return FileType.binary; // ELF shared object
|
||||||
|
case '.xpt':
|
||||||
|
return FileType.binary; // XPCOM Type Library
|
||||||
// Graphics code
|
// Graphics code
|
||||||
case '.glsl': return FileType.text;
|
case '.glsl':
|
||||||
case '.spvasm': return FileType.text;
|
return FileType.text;
|
||||||
|
case '.spvasm':
|
||||||
|
return FileType.text;
|
||||||
// Documentation
|
// Documentation
|
||||||
case '.md': return FileType.text;
|
case '.md':
|
||||||
case '.txt': return FileType.text;
|
return FileType.text;
|
||||||
case '.html': return FileType.text;
|
case '.txt':
|
||||||
|
return FileType.text;
|
||||||
|
case '.html':
|
||||||
|
return FileType.text;
|
||||||
// Fonts
|
// Fonts
|
||||||
case '.ttf': return FileType.binary; // TrueType Font
|
case '.ttf':
|
||||||
|
return FileType.binary; // TrueType Font
|
||||||
case '.ttcf': // (mac)
|
case '.ttcf': // (mac)
|
||||||
case '.ttc': return FileType.binary; // TrueType Collection (windows)
|
case '.ttc':
|
||||||
case '.woff': return FileType.binary; // Web Open Font Format
|
return FileType.binary; // TrueType Collection (windows)
|
||||||
case '.otf': return FileType.binary; // OpenType Font
|
case '.woff':
|
||||||
|
return FileType.binary; // Web Open Font Format
|
||||||
|
case '.otf':
|
||||||
|
return FileType.binary; // OpenType Font
|
||||||
// Graphics formats
|
// Graphics formats
|
||||||
case '.gif': return FileType.binary; // GIF
|
case '.gif':
|
||||||
case '.png': return FileType.binary; // PNG
|
return FileType.binary; // GIF
|
||||||
case '.tga': return FileType.binary; // Truevision TGA (TARGA)
|
case '.png':
|
||||||
case '.dng': return FileType.binary; // Digial Negative (Adobe RAW format)
|
return FileType.binary; // PNG
|
||||||
|
case '.tga':
|
||||||
|
return FileType.binary; // Truevision TGA (TARGA)
|
||||||
|
case '.dng':
|
||||||
|
return FileType.binary; // Digial Negative (Adobe RAW format)
|
||||||
case '.jpg':
|
case '.jpg':
|
||||||
case '.jpeg': return FileType.binary; // JPEG
|
case '.jpeg':
|
||||||
case '.ico': return FileType.binary; // Windows icon format
|
return FileType.binary; // JPEG
|
||||||
case '.icns': return FileType.binary; // macOS icon format
|
case '.ico':
|
||||||
case '.bmp': return FileType.binary; // Windows bitmap format
|
return FileType.binary; // Windows icon format
|
||||||
case '.wbmp': return FileType.binary; // Wireless bitmap format
|
case '.icns':
|
||||||
case '.webp': return FileType.binary; // WEBP
|
return FileType.binary; // macOS icon format
|
||||||
case '.pdf': return FileType.binary; // PDF
|
case '.bmp':
|
||||||
case '.emf': return FileType.binary; // Windows enhanced metafile format
|
return FileType.binary; // Windows bitmap format
|
||||||
case '.skp': return FileType.binary; // Skia picture format
|
case '.wbmp':
|
||||||
case '.mskp': return FileType.binary; // Skia picture format
|
return FileType.binary; // Wireless bitmap format
|
||||||
case '.spv': return FileType.binary; // SPIR-V
|
case '.webp':
|
||||||
|
return FileType.binary; // WEBP
|
||||||
|
case '.pdf':
|
||||||
|
return FileType.binary; // PDF
|
||||||
|
case '.emf':
|
||||||
|
return FileType.binary; // Windows enhanced metafile format
|
||||||
|
case '.skp':
|
||||||
|
return FileType.binary; // Skia picture format
|
||||||
|
case '.mskp':
|
||||||
|
return FileType.binary; // Skia picture format
|
||||||
|
case '.spv':
|
||||||
|
return FileType.binary; // SPIR-V
|
||||||
// Videos
|
// Videos
|
||||||
case '.ogg': return FileType.binary; // Ogg media
|
case '.ogg':
|
||||||
case '.mp4': return FileType.binary; // MPEG media
|
return FileType.binary; // Ogg media
|
||||||
case '.ts': return FileType.binary; // MPEG2 transport stream
|
case '.mp4':
|
||||||
|
return FileType.binary; // MPEG media
|
||||||
|
case '.ts':
|
||||||
|
return FileType.binary; // MPEG2 transport stream
|
||||||
// Other binary files
|
// Other binary files
|
||||||
case '.raw': return FileType.binary; // raw audio or graphical data
|
case '.raw':
|
||||||
case '.bin': return FileType.binary; // some sort of binary data
|
return FileType.binary; // raw audio or graphical data
|
||||||
case '.rsc': return FileType.binary; // some sort of resource data
|
case '.bin':
|
||||||
case '.arsc': return FileType.binary; // Android compiled resources
|
return FileType.binary; // some sort of binary data
|
||||||
case '.apk': return FileType.zip; // Android Package
|
case '.rsc':
|
||||||
case '.crx': return FileType.binary; // Chrome extension
|
return FileType.binary; // some sort of resource data
|
||||||
case '.keystore': return FileType.binary;
|
case '.arsc':
|
||||||
case '.icc': return FileType.binary; // Color profile
|
return FileType.binary; // Android compiled resources
|
||||||
case '.swp': return FileType.binary; // Vim swap file
|
case '.apk':
|
||||||
case '.bfbs': return FileType.binary; // Flatbuffers Binary Schema
|
return FileType.zip; // Android Package
|
||||||
|
case '.crx':
|
||||||
|
return FileType.binary; // Chrome extension
|
||||||
|
case '.keystore':
|
||||||
|
return FileType.binary;
|
||||||
|
case '.icc':
|
||||||
|
return FileType.binary; // Color profile
|
||||||
|
case '.swp':
|
||||||
|
return FileType.binary; // Vim swap file
|
||||||
|
case '.bfbs':
|
||||||
|
return FileType.binary; // Flatbuffers Binary Schema
|
||||||
// Archives
|
// Archives
|
||||||
case '.zip': return FileType.zip; // ZIP
|
case '.zip':
|
||||||
case '.tar': return FileType.tar; // Tar
|
return FileType.zip; // ZIP
|
||||||
case '.gz': return FileType.gz; // GZip
|
case '.tar':
|
||||||
case '.bzip2': return FileType.bzip2; // BZip2
|
return FileType.tar; // Tar
|
||||||
|
case '.gz':
|
||||||
|
return FileType.gz; // GZip
|
||||||
|
case '.bzip2':
|
||||||
|
return FileType.bzip2; // BZip2
|
||||||
// Image file types from the Fuchsia SDK.
|
// Image file types from the Fuchsia SDK.
|
||||||
case '.blk':
|
case '.blk':
|
||||||
case '.vboot':
|
case '.vboot':
|
||||||
@ -340,7 +504,24 @@ FileType identifyFile(String name, Reader reader) {
|
|||||||
if (matchesSignature(bytes, <int>[0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0a])) {
|
if (matchesSignature(bytes, <int>[0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0a])) {
|
||||||
return FileType.binary;
|
return FileType.binary;
|
||||||
} // PNG
|
} // PNG
|
||||||
if (matchesSignature(bytes, <int>[0x58, 0x50, 0x43, 0x4f, 0x4d, 0x0a, 0x54, 0x79, 0x70, 0x65, 0x4c, 0x69, 0x62, 0x0d, 0x0a, 0x1a])) {
|
if (matchesSignature(bytes, <int>[
|
||||||
|
0x58,
|
||||||
|
0x50,
|
||||||
|
0x43,
|
||||||
|
0x4f,
|
||||||
|
0x4d,
|
||||||
|
0x0a,
|
||||||
|
0x54,
|
||||||
|
0x79,
|
||||||
|
0x70,
|
||||||
|
0x65,
|
||||||
|
0x4c,
|
||||||
|
0x69,
|
||||||
|
0x62,
|
||||||
|
0x0d,
|
||||||
|
0x0a,
|
||||||
|
0x1a,
|
||||||
|
])) {
|
||||||
return FileType.binary;
|
return FileType.binary;
|
||||||
} // XPCOM Type Library
|
} // XPCOM Type Library
|
||||||
if (matchesSignature(bytes, <int>[0x23, 0x21])) {
|
if (matchesSignature(bytes, <int>[0x23, 0x21])) {
|
||||||
@ -356,7 +537,6 @@ String _normalize(String fileContents) {
|
|||||||
return fileContents;
|
return fileContents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// INTERFACE
|
// INTERFACE
|
||||||
|
|
||||||
// base class
|
// base class
|
||||||
@ -423,7 +603,7 @@ abstract class Directory extends IoNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// interface
|
// interface
|
||||||
abstract class Link extends IoNode { }
|
abstract class Link extends IoNode {}
|
||||||
|
|
||||||
mixin ZipFile on File implements Directory {
|
mixin ZipFile on File implements Directory {
|
||||||
ArchiveDirectory? _root;
|
ArchiveDirectory? _root;
|
||||||
@ -462,7 +642,8 @@ mixin GZipFile on File implements Directory {
|
|||||||
Iterable<IoNode> get walk sync* {
|
Iterable<IoNode> get walk sync* {
|
||||||
try {
|
try {
|
||||||
final String innerName = path.basenameWithoutExtension(fullName);
|
final String innerName = path.basenameWithoutExtension(fullName);
|
||||||
_data ??= InMemoryFile.parse('$fullName!$innerName', a.GZipDecoder().decodeBytes(readBytes()!))!;
|
_data ??=
|
||||||
|
InMemoryFile.parse('$fullName!$innerName', a.GZipDecoder().decodeBytes(readBytes()!))!;
|
||||||
if (_data != null) {
|
if (_data != null) {
|
||||||
yield _data!;
|
yield _data!;
|
||||||
}
|
}
|
||||||
@ -480,7 +661,8 @@ mixin BZip2File on File implements Directory {
|
|||||||
Iterable<IoNode> get walk sync* {
|
Iterable<IoNode> get walk sync* {
|
||||||
try {
|
try {
|
||||||
final String innerName = path.basenameWithoutExtension(fullName);
|
final String innerName = path.basenameWithoutExtension(fullName);
|
||||||
_data ??= InMemoryFile.parse('$fullName!$innerName', a.BZip2Decoder().decodeBytes(readBytes()!))!;
|
_data ??=
|
||||||
|
InMemoryFile.parse('$fullName!$innerName', a.BZip2Decoder().decodeBytes(readBytes()!))!;
|
||||||
if (_data != null) {
|
if (_data != null) {
|
||||||
yield _data!;
|
yield _data!;
|
||||||
}
|
}
|
||||||
@ -491,7 +673,6 @@ mixin BZip2File on File implements Directory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// FILESYSTEM IMPLEMENTATIoN
|
// FILESYSTEM IMPLEMENTATIoN
|
||||||
|
|
||||||
class FileSystemDirectory extends IoNode implements Directory {
|
class FileSystemDirectory extends IoNode implements Directory {
|
||||||
@ -527,14 +708,22 @@ class FileSystemDirectory extends IoNode implements Directory {
|
|||||||
final io.File fileEntity = entity as io.File;
|
final io.File fileEntity = entity as io.File;
|
||||||
if (fileEntity.lengthSync() > 0) {
|
if (fileEntity.lengthSync() > 0) {
|
||||||
switch (identifyFile(fileEntity.path, () => _readBytes(fileEntity))) {
|
switch (identifyFile(fileEntity.path, () => _readBytes(fileEntity))) {
|
||||||
case FileType.binary: yield FileSystemFile(fileEntity);
|
case FileType.binary:
|
||||||
case FileType.zip: yield FileSystemZipFile(fileEntity);
|
yield FileSystemFile(fileEntity);
|
||||||
case FileType.tar: yield FileSystemTarFile(fileEntity);
|
case FileType.zip:
|
||||||
case FileType.gz: yield FileSystemGZipFile(fileEntity);
|
yield FileSystemZipFile(fileEntity);
|
||||||
case FileType.bzip2: yield FileSystemBZip2File(fileEntity);
|
case FileType.tar:
|
||||||
case FileType.text: yield FileSystemUTF8TextFile(fileEntity);
|
yield FileSystemTarFile(fileEntity);
|
||||||
case FileType.latin1Text: yield FileSystemLatin1TextFile(fileEntity);
|
case FileType.gz:
|
||||||
case FileType.notPartOfBuild: break; // ignore this file
|
yield FileSystemGZipFile(fileEntity);
|
||||||
|
case FileType.bzip2:
|
||||||
|
yield FileSystemBZip2File(fileEntity);
|
||||||
|
case FileType.text:
|
||||||
|
yield FileSystemUTF8TextFile(fileEntity);
|
||||||
|
case FileType.latin1Text:
|
||||||
|
yield FileSystemLatin1TextFile(fileEntity);
|
||||||
|
case FileType.notPartOfBuild:
|
||||||
|
break; // ignore this file
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -595,7 +784,6 @@ class FileSystemBZip2File extends FileSystemFile with BZip2File {
|
|||||||
FileSystemBZip2File(super.file);
|
FileSystemBZip2File(super.file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ARCHIVES
|
// ARCHIVES
|
||||||
|
|
||||||
class ArchiveDirectory extends IoNode implements Directory {
|
class ArchiveDirectory extends IoNode implements Directory {
|
||||||
@ -613,22 +801,32 @@ class ArchiveDirectory extends IoNode implements Directory {
|
|||||||
void _add(a.ArchiveFile entry, List<String> remainingPath) {
|
void _add(a.ArchiveFile entry, List<String> remainingPath) {
|
||||||
if (remainingPath.length > 1) {
|
if (remainingPath.length > 1) {
|
||||||
final String subdirectoryName = remainingPath.removeAt(0);
|
final String subdirectoryName = remainingPath.removeAt(0);
|
||||||
_subdirectories.putIfAbsent(
|
_subdirectories
|
||||||
subdirectoryName,
|
.putIfAbsent(
|
||||||
() => ArchiveDirectory('$fullName/$subdirectoryName', subdirectoryName)
|
subdirectoryName,
|
||||||
)._add(entry, remainingPath);
|
() => ArchiveDirectory('$fullName/$subdirectoryName', subdirectoryName),
|
||||||
|
)
|
||||||
|
._add(entry, remainingPath);
|
||||||
} else {
|
} else {
|
||||||
if (entry.size > 0) {
|
if (entry.size > 0) {
|
||||||
final String entryFullName = '$fullName/${path.basename(entry.name)}';
|
final String entryFullName = '$fullName/${path.basename(entry.name)}';
|
||||||
switch (identifyFile(entry.name, () => entry.content as List<int>)) {
|
switch (identifyFile(entry.name, () => entry.content as List<int>)) {
|
||||||
case FileType.binary: _files.add(ArchiveFile(entryFullName, entry));
|
case FileType.binary:
|
||||||
case FileType.zip: _files.add(ArchiveZipFile(entryFullName, entry));
|
_files.add(ArchiveFile(entryFullName, entry));
|
||||||
case FileType.tar: _files.add(ArchiveTarFile(entryFullName, entry));
|
case FileType.zip:
|
||||||
case FileType.gz: _files.add(ArchiveGZipFile(entryFullName, entry));
|
_files.add(ArchiveZipFile(entryFullName, entry));
|
||||||
case FileType.bzip2: _files.add(ArchiveBZip2File(entryFullName, entry));
|
case FileType.tar:
|
||||||
case FileType.text: _files.add(ArchiveUTF8TextFile(entryFullName, entry));
|
_files.add(ArchiveTarFile(entryFullName, entry));
|
||||||
case FileType.latin1Text: _files.add(ArchiveLatin1TextFile(entryFullName, entry));
|
case FileType.gz:
|
||||||
case FileType.notPartOfBuild: break; // ignore this file
|
_files.add(ArchiveGZipFile(entryFullName, entry));
|
||||||
|
case FileType.bzip2:
|
||||||
|
_files.add(ArchiveBZip2File(entryFullName, entry));
|
||||||
|
case FileType.text:
|
||||||
|
_files.add(ArchiveUTF8TextFile(entryFullName, entry));
|
||||||
|
case FileType.latin1Text:
|
||||||
|
_files.add(ArchiveLatin1TextFile(entryFullName, entry));
|
||||||
|
case FileType.notPartOfBuild:
|
||||||
|
break; // ignore this file
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -692,7 +890,6 @@ class ArchiveBZip2File extends ArchiveFile with BZip2File {
|
|||||||
ArchiveBZip2File(super.fullName, super.file);
|
ArchiveBZip2File(super.fullName, super.file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// IN-MEMORY FILES (e.g. contents of GZipped files)
|
// IN-MEMORY FILES (e.g. contents of GZipped files)
|
||||||
|
|
||||||
class InMemoryFile extends IoNode implements File {
|
class InMemoryFile extends IoNode implements File {
|
||||||
@ -703,14 +900,22 @@ class InMemoryFile extends IoNode implements File {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
switch (identifyFile(fullName, () => bytes)) {
|
switch (identifyFile(fullName, () => bytes)) {
|
||||||
case FileType.binary: return InMemoryFile(fullName, bytes);
|
case FileType.binary:
|
||||||
case FileType.zip: return InMemoryZipFile(fullName, bytes);
|
return InMemoryFile(fullName, bytes);
|
||||||
case FileType.tar: return InMemoryTarFile(fullName, bytes);
|
case FileType.zip:
|
||||||
case FileType.gz: return InMemoryGZipFile(fullName, bytes);
|
return InMemoryZipFile(fullName, bytes);
|
||||||
case FileType.bzip2: return InMemoryBZip2File(fullName, bytes);
|
case FileType.tar:
|
||||||
case FileType.text: return InMemoryUTF8TextFile(fullName, bytes);
|
return InMemoryTarFile(fullName, bytes);
|
||||||
case FileType.latin1Text: return InMemoryLatin1TextFile(fullName, bytes);
|
case FileType.gz:
|
||||||
case FileType.notPartOfBuild: break; // ignore this file
|
return InMemoryGZipFile(fullName, bytes);
|
||||||
|
case FileType.bzip2:
|
||||||
|
return InMemoryBZip2File(fullName, bytes);
|
||||||
|
case FileType.text:
|
||||||
|
return InMemoryUTF8TextFile(fullName, bytes);
|
||||||
|
case FileType.latin1Text:
|
||||||
|
return InMemoryLatin1TextFile(fullName, bytes);
|
||||||
|
case FileType.notPartOfBuild:
|
||||||
|
break; // ignore this file
|
||||||
}
|
}
|
||||||
assert(false);
|
assert(false);
|
||||||
return null;
|
return null;
|
||||||
|
@ -38,7 +38,8 @@ bool _stripIndentation(List<String> lines) {
|
|||||||
} else {
|
} else {
|
||||||
prefix = leadingDecorations.matchAsPrefix(lines.first)?.group(0);
|
prefix = leadingDecorations.matchAsPrefix(lines.first)?.group(0);
|
||||||
}
|
}
|
||||||
if (prefix != null && lines.skip(1).every((String line) => line.startsWith(prefix!) || prefix.startsWith(line))) {
|
if (prefix != null &&
|
||||||
|
lines.skip(1).every((String line) => line.startsWith(prefix!) || prefix.startsWith(line))) {
|
||||||
final int prefixLength = prefix.length;
|
final int prefixLength = prefix.length;
|
||||||
for (int index = 0; index < lines.length; index += 1) {
|
for (int index = 0; index < lines.length; index += 1) {
|
||||||
final String line = lines[index];
|
final String line = lines[index];
|
||||||
@ -168,7 +169,8 @@ String stripAsciiArt(String input) {
|
|||||||
for (final List<String> image in asciiArtImages) {
|
for (final List<String> image in asciiArtImages) {
|
||||||
assert(image.isNotEmpty);
|
assert(image.isNotEmpty);
|
||||||
// Look for the image starting on each line.
|
// Look for the image starting on each line.
|
||||||
search: for (int index = 0; index < lines.length - image.length; index += 1) {
|
search:
|
||||||
|
for (int index = 0; index < lines.length - image.length; index += 1) {
|
||||||
final int x = lines[index].indexOf(image[0]);
|
final int x = lines[index].indexOf(image[0]);
|
||||||
if (x >= 0) {
|
if (x >= 0) {
|
||||||
int width = image[0].length;
|
int width = image[0].length;
|
||||||
@ -186,7 +188,8 @@ String stripAsciiArt(String input) {
|
|||||||
final String text = lines[index + imageLine];
|
final String text = lines[index + imageLine];
|
||||||
assert(text.length > x);
|
assert(text.length > x);
|
||||||
if (text.length >= x + width) {
|
if (text.length >= x + width) {
|
||||||
lines[index + imageLine] = text.substring(0, x) + text.substring(x + width, text.length);
|
lines[index + imageLine] =
|
||||||
|
text.substring(0, x) + text.substring(x + width, text.length);
|
||||||
} else {
|
} else {
|
||||||
lines[index + imageLine] = text.substring(0, x);
|
lines[index + imageLine] = text.substring(0, x);
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -187,7 +187,16 @@ class _RepositoryGeneralSingleLicenseFile extends _RepositorySingleLicenseFile {
|
|||||||
// (e.g. having the copyright for one above the terms for the other and so on).
|
// (e.g. having the copyright for one above the terms for the other and so on).
|
||||||
class _RepositoryOpaqueLicenseFile extends _RepositorySingleLicenseFile {
|
class _RepositoryOpaqueLicenseFile extends _RepositorySingleLicenseFile {
|
||||||
_RepositoryOpaqueLicenseFile(_RepositoryDirectory parent, fs.TextFile io)
|
_RepositoryOpaqueLicenseFile(_RepositoryDirectory parent, fs.TextFile io)
|
||||||
: super(parent, io, License.unique(io.readString(), LicenseType.unknown, origin: io.fullName, yesWeKnowWhatItLooksLikeButItIsNot: true));
|
: super(
|
||||||
|
parent,
|
||||||
|
io,
|
||||||
|
License.unique(
|
||||||
|
io.readString(),
|
||||||
|
LicenseType.unknown,
|
||||||
|
origin: io.fullName,
|
||||||
|
yesWeKnowWhatItLooksLikeButItIsNot: true,
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class _RepositoryReadmeIjgFile extends _RepositorySingleLicenseFile {
|
class _RepositoryReadmeIjgFile extends _RepositorySingleLicenseFile {
|
||||||
@ -197,7 +206,8 @@ class _RepositoryReadmeIjgFile extends _RepositorySingleLicenseFile {
|
|||||||
// The message we are required to include in our output.
|
// The message we are required to include in our output.
|
||||||
//
|
//
|
||||||
// We include it by just including the whole license.
|
// We include it by just including the whole license.
|
||||||
static const String _message = 'this software is based in part on the work of the Independent JPEG Group';
|
static const String _message =
|
||||||
|
'this software is based in part on the work of the Independent JPEG Group';
|
||||||
|
|
||||||
// The license text that says we should output _message.
|
// The license text that says we should output _message.
|
||||||
//
|
//
|
||||||
@ -212,7 +222,9 @@ class _RepositoryReadmeIjgFile extends _RepositorySingleLicenseFile {
|
|||||||
r'unaltered; and any additions, deletions, or changes to the original files\n'
|
r'unaltered; and any additions, deletions, or changes to the original files\n'
|
||||||
r'must be clearly indicated in accompanying documentation\.\n'
|
r'must be clearly indicated in accompanying documentation\.\n'
|
||||||
r'\(2\) If only executable code is distributed, then the accompanying\n'
|
r'\(2\) If only executable code is distributed, then the accompanying\n'
|
||||||
r'documentation must state that "' '${_message.replaceAll(" ", "[ \n]+")}' r'"\.\n'
|
r'documentation must state that "'
|
||||||
|
'${_message.replaceAll(" ", "[ \n]+")}'
|
||||||
|
r'"\.\n'
|
||||||
r'\(3\) Permission for use of this software is granted only if the user accepts\n'
|
r'\(3\) Permission for use of this software is granted only if the user accepts\n'
|
||||||
r'full responsibility for any undesirable consequences; the authors accept\n'
|
r'full responsibility for any undesirable consequences; the authors accept\n'
|
||||||
r'NO LIABILITY for damages of any kind\.\n',
|
r'NO LIABILITY for damages of any kind\.\n',
|
||||||
@ -239,9 +251,7 @@ class _RepositoryDartLicenseFile extends _RepositorySingleLicenseFile {
|
|||||||
_RepositoryDartLicenseFile(_RepositoryDirectory parent, fs.TextFile io)
|
_RepositoryDartLicenseFile(_RepositoryDirectory parent, fs.TextFile io)
|
||||||
: super(parent, io, _parseLicense(io));
|
: super(parent, io, _parseLicense(io));
|
||||||
|
|
||||||
static final RegExp _pattern = RegExp(
|
static final RegExp _pattern = RegExp(r'(Copyright (?:.|\n)+)$');
|
||||||
r'(Copyright (?:.|\n)+)$',
|
|
||||||
);
|
|
||||||
|
|
||||||
static License _parseLicense(fs.TextFile io) {
|
static License _parseLicense(fs.TextFile io) {
|
||||||
final Match? match = _pattern.firstMatch(io.readString());
|
final Match? match = _pattern.firstMatch(io.readString());
|
||||||
@ -290,7 +300,7 @@ class _RepositoryLibJpegTurboLicenseFile extends _RepositoryLicenseFile {
|
|||||||
r'- The zlib License, which is listed in \[simd/jsimdext\.inc\]\(simd/jsimdext\.inc\)\n'
|
r'- The zlib License, which is listed in \[simd/jsimdext\.inc\]\(simd/jsimdext\.inc\)\n'
|
||||||
r'\n'
|
r'\n'
|
||||||
r' This license is a subset of the other two, and it covers the libjpeg-turbo\n'
|
r' This license is a subset of the other two, and it covers the libjpeg-turbo\n'
|
||||||
r' SIMD extensions\.\n'
|
r' SIMD extensions\.\n',
|
||||||
);
|
);
|
||||||
|
|
||||||
static void _parseLicense(fs.TextFile io) {
|
static void _parseLicense(fs.TextFile io) {
|
||||||
@ -318,10 +328,13 @@ class _RepositoryLibJpegTurboLicenseFile extends _RepositoryLicenseFile {
|
|||||||
@override
|
@override
|
||||||
List<License> get licenses {
|
List<License> get licenses {
|
||||||
if (_licenses == null) {
|
if (_licenses == null) {
|
||||||
final _RepositoryLicenseFile readme = parent!.getChildByName('README.ijg') as _RepositoryReadmeIjgFile;
|
final _RepositoryLicenseFile readme =
|
||||||
final _RepositorySourceFile main = parent!.getChildByName('turbojpeg.c') as _RepositorySourceFile;
|
parent!.getChildByName('README.ijg') as _RepositoryReadmeIjgFile;
|
||||||
|
final _RepositorySourceFile main =
|
||||||
|
parent!.getChildByName('turbojpeg.c') as _RepositorySourceFile;
|
||||||
final _RepositoryDirectory simd = parent!.getChildByName('simd') as _RepositoryDirectory;
|
final _RepositoryDirectory simd = parent!.getChildByName('simd') as _RepositoryDirectory;
|
||||||
final _RepositorySourceFile zlib = simd.getChildByName('jsimdext.inc') as _RepositorySourceFile;
|
final _RepositorySourceFile zlib =
|
||||||
|
simd.getChildByName('jsimdext.inc') as _RepositorySourceFile;
|
||||||
_licenses = <License>[];
|
_licenses = <License>[];
|
||||||
_licenses!.addAll(readme.licenses);
|
_licenses!.addAll(readme.licenses);
|
||||||
_licenses!.add(main.extractInternalLicense());
|
_licenses!.add(main.extractInternalLicense());
|
||||||
@ -332,8 +345,7 @@ class _RepositoryLibJpegTurboLicenseFile extends _RepositoryLicenseFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _RepositoryFreetypeLicenseFile extends _RepositoryLicenseFile {
|
class _RepositoryFreetypeLicenseFile extends _RepositoryLicenseFile {
|
||||||
_RepositoryFreetypeLicenseFile(super.parent, super.io)
|
_RepositoryFreetypeLicenseFile(super.parent, super.io) : _target = _parseLicense(io);
|
||||||
: _target = _parseLicense(io);
|
|
||||||
|
|
||||||
static final RegExp _pattern = RegExp(
|
static final RegExp _pattern = RegExp(
|
||||||
r'FREETYPE LICENSES\n'
|
r'FREETYPE LICENSES\n'
|
||||||
@ -376,7 +388,7 @@ class _RepositoryFreetypeLicenseFile extends _RepositoryLicenseFile {
|
|||||||
r'The MD5 checksum support \(only used for debugging in development\n'
|
r'The MD5 checksum support \(only used for debugging in development\n'
|
||||||
r'builds\) is in the public domain\.\n'
|
r'builds\) is in the public domain\.\n'
|
||||||
r'\n*'
|
r'\n*'
|
||||||
r'--- end of LICENSE\.TXT ---\n*$'
|
r'--- end of LICENSE\.TXT ---\n*$',
|
||||||
);
|
);
|
||||||
|
|
||||||
static String _parseLicense(fs.TextFile io) {
|
static String _parseLicense(fs.TextFile io) {
|
||||||
@ -426,7 +438,10 @@ class _RepositoryIcuLicenseFile extends _RepositorySingleLicenseFile {
|
|||||||
throw 'could not parse ICU license file';
|
throw 'could not parse ICU license file';
|
||||||
}
|
}
|
||||||
const int groupCount = 22;
|
const int groupCount = 22;
|
||||||
assert(match.groupCount == groupCount, 'ICU: expected $groupCount groups, but got ${match.groupCount}');
|
assert(
|
||||||
|
match.groupCount == groupCount,
|
||||||
|
'ICU: expected $groupCount groups, but got ${match.groupCount}',
|
||||||
|
);
|
||||||
const int timeZoneGroup = 18;
|
const int timeZoneGroup = 18;
|
||||||
if (match.group(timeZoneGroup)!.contains(copyrightMentionPattern)) {
|
if (match.group(timeZoneGroup)!.contains(copyrightMentionPattern)) {
|
||||||
throw 'ICU: unexpected copyright in time zone database group\n:${match.group(timeZoneGroup)}';
|
throw 'ICU: unexpected copyright in time zone database group\n:${match.group(timeZoneGroup)}';
|
||||||
@ -436,21 +451,24 @@ class _RepositoryIcuLicenseFile extends _RepositorySingleLicenseFile {
|
|||||||
}
|
}
|
||||||
const int gplGroup1 = 20;
|
const int gplGroup1 = 20;
|
||||||
const int gplGroup2 = 21;
|
const int gplGroup2 = 21;
|
||||||
if (!match.group(gplGroup1)!.contains(gplExceptionExplanation1) || !match.group(gplGroup2)!.contains(gplExceptionExplanation2)) {
|
if (!match.group(gplGroup1)!.contains(gplExceptionExplanation1) ||
|
||||||
|
!match.group(gplGroup2)!.contains(gplExceptionExplanation2)) {
|
||||||
throw 'ICU: did not find GPL exception in GPL-licensed files';
|
throw 'ICU: did not find GPL exception in GPL-licensed files';
|
||||||
}
|
}
|
||||||
const Set<int> skippedGroups = <int>{ timeZoneGroup, gplGroup1, gplGroup2 };
|
const Set<int> skippedGroups = <int>{timeZoneGroup, gplGroup1, gplGroup2};
|
||||||
return _RepositoryIcuLicenseFile._(
|
return _RepositoryIcuLicenseFile._(
|
||||||
parent,
|
parent,
|
||||||
io,
|
io,
|
||||||
License.template(match.group(2)!, LicenseType.bsd, origin: io.fullName),
|
License.template(match.group(2)!, LicenseType.bsd, origin: io.fullName),
|
||||||
License.fromMultipleBlocks(
|
License.fromMultipleBlocks(
|
||||||
match.groups(
|
match
|
||||||
Iterable<int>
|
.groups(
|
||||||
.generate(groupCount, (int index) => index + 1)
|
Iterable<int>.generate(
|
||||||
.where((int index) => !skippedGroups.contains(index))
|
groupCount,
|
||||||
.toList()
|
(int index) => index + 1,
|
||||||
).cast<String>(),
|
).where((int index) => !skippedGroups.contains(index)).toList(),
|
||||||
|
)
|
||||||
|
.cast<String>(),
|
||||||
LicenseType.icu,
|
LicenseType.icu,
|
||||||
origin: io.fullName,
|
origin: io.fullName,
|
||||||
yesWeKnowWhatItLooksLikeButItIsNot: true,
|
yesWeKnowWhatItLooksLikeButItIsNot: true,
|
||||||
@ -458,8 +476,12 @@ class _RepositoryIcuLicenseFile extends _RepositorySingleLicenseFile {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_RepositoryIcuLicenseFile._(_RepositoryDirectory parent, fs.TextFile io, this.template, License license)
|
_RepositoryIcuLicenseFile._(
|
||||||
: super(parent, io, license);
|
_RepositoryDirectory parent,
|
||||||
|
fs.TextFile io,
|
||||||
|
this.template,
|
||||||
|
License license,
|
||||||
|
) : super(parent, io, license);
|
||||||
|
|
||||||
// Every paragraph of the license is mentioned. All newlines are disregarded [\n+].
|
// Every paragraph of the license is mentioned. All newlines are disregarded [\n+].
|
||||||
static final RegExp _pattern = RegExp(
|
static final RegExp _pattern = RegExp(
|
||||||
@ -563,29 +585,29 @@ class _RepositoryIcuLicenseFile extends _RepositorySingleLicenseFile {
|
|||||||
);
|
);
|
||||||
|
|
||||||
static const String gplExceptionExplanation1 =
|
static const String gplExceptionExplanation1 =
|
||||||
'As a special exception to the GNU General Public License, if you\n'
|
'As a special exception to the GNU General Public License, if you\n'
|
||||||
'distribute this file as part of a program that contains a\n'
|
'distribute this file as part of a program that contains a\n'
|
||||||
'configuration script generated by Autoconf, you may include it under\n'
|
'configuration script generated by Autoconf, you may include it under\n'
|
||||||
'the same distribution terms that you use for the rest of that\n'
|
'the same distribution terms that you use for the rest of that\n'
|
||||||
'program.\n'
|
'program.\n'
|
||||||
'\n'
|
'\n'
|
||||||
'\n'
|
'\n'
|
||||||
'(The condition for the exception is fulfilled because\n'
|
'(The condition for the exception is fulfilled because\n'
|
||||||
'ICU4C includes a configuration script generated by Autoconf,\n'
|
'ICU4C includes a configuration script generated by Autoconf,\n'
|
||||||
'namely the `configure` script.)';
|
'namely the `configure` script.)';
|
||||||
|
|
||||||
static const String gplExceptionExplanation2 =
|
static const String gplExceptionExplanation2 =
|
||||||
'As a special exception to the GNU General Public License, if you\n'
|
'As a special exception to the GNU General Public License, if you\n'
|
||||||
'distribute this file as part of a program that contains a\n'
|
'distribute this file as part of a program that contains a\n'
|
||||||
'configuration script generated by Autoconf, you may include it under\n'
|
'configuration script generated by Autoconf, you may include it under\n'
|
||||||
'the same distribution terms that you use for the rest of that\n'
|
'the same distribution terms that you use for the rest of that\n'
|
||||||
'program. This Exception is an additional permission under section 7\n'
|
'program. This Exception is an additional permission under section 7\n'
|
||||||
'of the GNU General Public License, version 3 ("GPLv3").\n'
|
'of the GNU General Public License, version 3 ("GPLv3").\n'
|
||||||
'\n'
|
'\n'
|
||||||
'\n'
|
'\n'
|
||||||
'(The condition for the exception is fulfilled because\n'
|
'(The condition for the exception is fulfilled because\n'
|
||||||
'ICU4C includes a configuration script generated by Autoconf,\n'
|
'ICU4C includes a configuration script generated by Autoconf,\n'
|
||||||
'namely the `configure` script.)';
|
'namely the `configure` script.)';
|
||||||
|
|
||||||
// Fixes an error in the license's formatting that our reformatter wouldn't be
|
// Fixes an error in the license's formatting that our reformatter wouldn't be
|
||||||
// able to figure out on its own and which would otherwise completely mess up
|
// able to figure out on its own and which would otherwise completely mess up
|
||||||
@ -609,8 +631,7 @@ class _RepositoryIcuLicenseFile extends _RepositorySingleLicenseFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _RepositoryCxxStlDualLicenseFile extends _RepositoryLicenseFile {
|
class _RepositoryCxxStlDualLicenseFile extends _RepositoryLicenseFile {
|
||||||
_RepositoryCxxStlDualLicenseFile(super.parent, super.io)
|
_RepositoryCxxStlDualLicenseFile(super.parent, super.io) : _licenses = _parseLicenses(io);
|
||||||
: _licenses = _parseLicenses(io);
|
|
||||||
|
|
||||||
static final RegExp _pattern = RegExp(
|
static final RegExp _pattern = RegExp(
|
||||||
r'^'
|
r'^'
|
||||||
@ -750,8 +771,7 @@ class _RepositoryCxxStlDualLicenseFile extends _RepositoryLicenseFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _RepositoryKhronosLicenseFile extends _RepositoryLicenseFile {
|
class _RepositoryKhronosLicenseFile extends _RepositoryLicenseFile {
|
||||||
_RepositoryKhronosLicenseFile(super.parent, super.io)
|
_RepositoryKhronosLicenseFile(super.parent, super.io) : _licenses = _parseLicenses(io);
|
||||||
: _licenses = _parseLicenses(io);
|
|
||||||
|
|
||||||
static final RegExp _pattern = RegExp(
|
static final RegExp _pattern = RegExp(
|
||||||
r'^(Copyright .+?)\n'
|
r'^(Copyright .+?)\n'
|
||||||
@ -852,16 +872,21 @@ class _RepositoryFuchsiaSdkLinuxLicenseFile extends _RepositorySingleLicenseFile
|
|||||||
_RepositoryFuchsiaSdkLinuxLicenseFile(_RepositoryDirectory parent, fs.TextFile io)
|
_RepositoryFuchsiaSdkLinuxLicenseFile(_RepositoryDirectory parent, fs.TextFile io)
|
||||||
: super(parent, io, _parseLicense(io));
|
: super(parent, io, _parseLicense(io));
|
||||||
|
|
||||||
static const String _pattern = 'The majority of files in this project use the Apache 2.0 License.\n'
|
static const String _pattern =
|
||||||
'There are a few exceptions and their license can be found in the source.\n'
|
'The majority of files in this project use the Apache 2.0 License.\n'
|
||||||
'Any license deviations from Apache 2.0 are "more permissive" licenses.\n';
|
'There are a few exceptions and their license can be found in the source.\n'
|
||||||
|
'Any license deviations from Apache 2.0 are "more permissive" licenses.\n';
|
||||||
|
|
||||||
static License _parseLicense(fs.TextFile io) {
|
static License _parseLicense(fs.TextFile io) {
|
||||||
final String body = io.readString();
|
final String body = io.readString();
|
||||||
if (!body.startsWith(_pattern)) {
|
if (!body.startsWith(_pattern)) {
|
||||||
throw 'unexpected Fuchsia license file contents';
|
throw 'unexpected Fuchsia license file contents';
|
||||||
}
|
}
|
||||||
return License.fromBodyAndType(body.substring(_pattern.length), LicenseType.apache, origin: io.fullName);
|
return License.fromBodyAndType(
|
||||||
|
body.substring(_pattern.length),
|
||||||
|
LicenseType.apache,
|
||||||
|
origin: io.fullName,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -875,13 +900,13 @@ class _RepositoryVulkanApacheLicenseFile extends _RepositorySingleLicenseFile {
|
|||||||
: super(parent, io, _parseLicense(io));
|
: super(parent, io, _parseLicense(io));
|
||||||
|
|
||||||
static const String _prefix =
|
static const String _prefix =
|
||||||
'The majority of files in this project use the Apache 2.0 License.\n'
|
'The majority of files in this project use the Apache 2.0 License.\n'
|
||||||
'There are a few exceptions and their license can be found in the source.\n'
|
'There are a few exceptions and their license can be found in the source.\n'
|
||||||
'Any license deviations from Apache 2.0 are "more permissive" licenses.\n'
|
'Any license deviations from Apache 2.0 are "more permissive" licenses.\n'
|
||||||
"Any file without a license in it's source defaults to the repository Apache 2.0 License.\n"
|
"Any file without a license in it's source defaults to the repository Apache 2.0 License.\n"
|
||||||
'\n'
|
'\n'
|
||||||
'===========================================================================================\n'
|
'===========================================================================================\n'
|
||||||
'\n';
|
'\n';
|
||||||
|
|
||||||
static License _parseLicense(fs.TextFile io) {
|
static License _parseLicense(fs.TextFile io) {
|
||||||
final String body = io.readString();
|
final String body = io.readString();
|
||||||
@ -892,7 +917,6 @@ class _RepositoryVulkanApacheLicenseFile extends _RepositorySingleLicenseFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// DIRECTORIES
|
// DIRECTORIES
|
||||||
|
|
||||||
typedef _Constructor = _RepositoryFile Function(_RepositoryDirectory parent, fs.TextFile);
|
typedef _Constructor = _RepositoryFile Function(_RepositoryDirectory parent, fs.TextFile);
|
||||||
@ -912,7 +936,7 @@ class _RepositoryDirectory extends _RepositoryEntry implements LicenseSource {
|
|||||||
|
|
||||||
List<_RepositoryDirectory> get subdirectories => _subdirectories;
|
List<_RepositoryDirectory> get subdirectories => _subdirectories;
|
||||||
|
|
||||||
final Map<String,_RepositoryEntry> _childrenByName = <String,_RepositoryEntry>{};
|
final Map<String, _RepositoryEntry> _childrenByName = <String, _RepositoryEntry>{};
|
||||||
|
|
||||||
void crawl() {
|
void crawl() {
|
||||||
for (final fs.IoNode entry in ioDirectory.walk) {
|
for (final fs.IoNode entry in ioDirectory.walk) {
|
||||||
@ -987,7 +1011,10 @@ class _RepositoryDirectory extends _RepositoryEntry implements LicenseSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// the bit at the beginning excludes files like "license.py".
|
// the bit at the beginning excludes files like "license.py".
|
||||||
static final RegExp _licenseNamePattern = RegExp(r'^(?!.*\.py$)(?!.*(?:no|update)-copyright)(?!.*mh-bsd-gcc).*\b_*(?:license(?!\.html)|copying|copyright|notice|l?gpl|GPLv2|bsd|mit|mpl?|ftl|Apache)_*\b', caseSensitive: false);
|
static final RegExp _licenseNamePattern = RegExp(
|
||||||
|
r'^(?!.*\.py$)(?!.*(?:no|update)-copyright)(?!.*mh-bsd-gcc).*\b_*(?:license(?!\.html)|copying|copyright|notice|l?gpl|GPLv2|bsd|mit|mpl?|ftl|Apache)_*\b',
|
||||||
|
caseSensitive: false,
|
||||||
|
);
|
||||||
|
|
||||||
static const Map<String, _Constructor> _specialCaseFiles = <String, _Constructor>{
|
static const Map<String, _Constructor> _specialCaseFiles = <String, _Constructor>{
|
||||||
'/flutter/third_party/boringssl/src/LICENSE': _RepositoryOpenSSLLicenseFile.new,
|
'/flutter/third_party/boringssl/src/LICENSE': _RepositoryOpenSSLLicenseFile.new,
|
||||||
@ -1002,7 +1029,8 @@ class _RepositoryDirectory extends _RepositoryEntry implements LicenseSource {
|
|||||||
'/flutter/third_party/libpng/LICENSE': _RepositoryLibPngLicenseFile.new,
|
'/flutter/third_party/libpng/LICENSE': _RepositoryLibPngLicenseFile.new,
|
||||||
'/flutter/third_party/rapidjson/LICENSE': _RepositoryOpaqueLicenseFile.new,
|
'/flutter/third_party/rapidjson/LICENSE': _RepositoryOpaqueLicenseFile.new,
|
||||||
'/flutter/third_party/rapidjson/license.txt': _RepositoryOpaqueLicenseFile.new,
|
'/flutter/third_party/rapidjson/license.txt': _RepositoryOpaqueLicenseFile.new,
|
||||||
'/flutter/third_party/vulkan-deps/vulkan-validation-layers/src/LICENSE.txt': _RepositoryVulkanApacheLicenseFile.new,
|
'/flutter/third_party/vulkan-deps/vulkan-validation-layers/src/LICENSE.txt':
|
||||||
|
_RepositoryVulkanApacheLicenseFile.new,
|
||||||
'/fuchsia/sdk/linux/LICENSE.vulkan': _RepositoryFuchsiaSdkLinuxLicenseFile.new,
|
'/fuchsia/sdk/linux/LICENSE.vulkan': _RepositoryFuchsiaSdkLinuxLicenseFile.new,
|
||||||
'/fuchsia/sdk/mac/LICENSE.vulkan': _RepositoryFuchsiaSdkLinuxLicenseFile.new,
|
'/fuchsia/sdk/mac/LICENSE.vulkan': _RepositoryFuchsiaSdkLinuxLicenseFile.new,
|
||||||
'/third_party/khronos/LICENSE': _RepositoryKhronosLicenseFile.new,
|
'/third_party/khronos/LICENSE': _RepositoryKhronosLicenseFile.new,
|
||||||
@ -1023,7 +1051,9 @@ class _RepositoryDirectory extends _RepositoryEntry implements LicenseSource {
|
|||||||
return _RepositoryBinaryFile(this, entry as fs.File);
|
return _RepositoryBinaryFile(this, entry as fs.File);
|
||||||
}
|
}
|
||||||
|
|
||||||
int get count => _files.length + _subdirectories.fold<int>(0, (int count, _RepositoryDirectory child) => count + child.count);
|
int get count =>
|
||||||
|
_files.length +
|
||||||
|
_subdirectories.fold<int>(0, (int count, _RepositoryDirectory child) => count + child.count);
|
||||||
|
|
||||||
bool _canGoUp() {
|
bool _canGoUp() {
|
||||||
assert(parent != null || isLicenseRoot);
|
assert(parent != null || isLicenseRoot);
|
||||||
@ -1063,13 +1093,14 @@ class _RepositoryDirectory extends _RepositoryEntry implements LicenseSource {
|
|||||||
|
|
||||||
/// Searches the current directory for licenses of the specified type.
|
/// Searches the current directory for licenses of the specified type.
|
||||||
License? _localLicenseWithType(LicenseType type) {
|
License? _localLicenseWithType(LicenseType type) {
|
||||||
final List<License> licenses = _licenses.expand((_RepositoryLicenseFile license) {
|
final List<License> licenses =
|
||||||
final License? result = license.licenseOfType(type);
|
_licenses.expand((_RepositoryLicenseFile license) {
|
||||||
if (result != null) {
|
final License? result = license.licenseOfType(type);
|
||||||
return <License>[result];
|
if (result != null) {
|
||||||
}
|
return <License>[result];
|
||||||
return const <License>[];
|
}
|
||||||
}).toList();
|
return const <License>[];
|
||||||
|
}).toList();
|
||||||
if (licenses.length > 1) {
|
if (licenses.length > 1) {
|
||||||
print('unexpectedly found multiple matching licenses in $name of type $type');
|
print('unexpectedly found multiple matching licenses in $name of type $type');
|
||||||
return null;
|
return null;
|
||||||
@ -1083,8 +1114,11 @@ class _RepositoryDirectory extends _RepositoryEntry implements LicenseSource {
|
|||||||
/// Searches all subdirectories (depth-first) for a license of the specified type.
|
/// Searches all subdirectories (depth-first) for a license of the specified type.
|
||||||
License? _fullWalkDownForLicenseWithType(LicenseType type) {
|
License? _fullWalkDownForLicenseWithType(LicenseType type) {
|
||||||
for (final _RepositoryDirectory directory in _subdirectories) {
|
for (final _RepositoryDirectory directory in _subdirectories) {
|
||||||
if (directory._canGoUp()) { // avoid crawling into other license scopes
|
if (directory._canGoUp()) {
|
||||||
final License? result = directory._localLicenseWithType(type) ?? directory._fullWalkDownForLicenseWithType(type);
|
// avoid crawling into other license scopes
|
||||||
|
final License? result =
|
||||||
|
directory._localLicenseWithType(type) ??
|
||||||
|
directory._fullWalkDownForLicenseWithType(type);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -1108,13 +1142,13 @@ class _RepositoryDirectory extends _RepositoryEntry implements LicenseSource {
|
|||||||
if (_canGoUp()) {
|
if (_canGoUp()) {
|
||||||
return parent!.nearestLicenseWithName(name, authors: authors);
|
return parent!.nearestLicenseWithName(name, authors: authors);
|
||||||
}
|
}
|
||||||
return _fullWalkDownForLicenseWithName(name, authors: authors)
|
return _fullWalkDownForLicenseWithName(name, authors: authors) ??
|
||||||
?? (authors != null ? parent?._fullWalkUpForLicenseWithName(name, authors: authors) : null);
|
(authors != null ? parent?._fullWalkUpForLicenseWithName(name, authors: authors) : null);
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
License? _localLicenseWithName(String name, { String? authors }) {
|
License? _localLicenseWithName(String name, {String? authors}) {
|
||||||
final _RepositoryEntry? entry = _childrenByName[name];
|
final _RepositoryEntry? entry = _childrenByName[name];
|
||||||
License? license;
|
License? license;
|
||||||
if (entry is _RepositoryLicensedFile) {
|
if (entry is _RepositoryLicensedFile) {
|
||||||
@ -1132,7 +1166,7 @@ class _RepositoryDirectory extends _RepositoryEntry implements LicenseSource {
|
|||||||
return license;
|
return license;
|
||||||
}
|
}
|
||||||
|
|
||||||
License? _fullWalkUpForLicenseWithName(String name, { required String authors }) {
|
License? _fullWalkUpForLicenseWithName(String name, {required String authors}) {
|
||||||
// When looking for a license specific to certain authors, we want to walk
|
// When looking for a license specific to certain authors, we want to walk
|
||||||
// to the top of the local license root, then from there check all the
|
// to the top of the local license root, then from there check all the
|
||||||
// ancestors and all the descendants.
|
// ancestors and all the descendants.
|
||||||
@ -1143,14 +1177,16 @@ class _RepositoryDirectory extends _RepositoryEntry implements LicenseSource {
|
|||||||
// Authors license is at the root, and is sometimes mentioned in various
|
// Authors license is at the root, and is sometimes mentioned in various
|
||||||
// files deep inside third party directories).
|
// files deep inside third party directories).
|
||||||
return _localLicenseWithName(name, authors: authors) ??
|
return _localLicenseWithName(name, authors: authors) ??
|
||||||
parent?._fullWalkUpForLicenseWithName(name, authors: authors);
|
parent?._fullWalkUpForLicenseWithName(name, authors: authors);
|
||||||
}
|
}
|
||||||
|
|
||||||
License? _fullWalkDownForLicenseWithName(String name, { String? authors }) {
|
License? _fullWalkDownForLicenseWithName(String name, {String? authors}) {
|
||||||
for (final _RepositoryDirectory directory in _subdirectories) {
|
for (final _RepositoryDirectory directory in _subdirectories) {
|
||||||
if (directory._canGoUp()) { // avoid crawling into other license scopes
|
if (directory._canGoUp()) {
|
||||||
final License? result = directory._localLicenseWithName(name, authors: authors)
|
// avoid crawling into other license scopes
|
||||||
?? directory._fullWalkDownForLicenseWithName(name, authors: authors);
|
final License? result =
|
||||||
|
directory._localLicenseWithName(name, authors: authors) ??
|
||||||
|
directory._fullWalkDownForLicenseWithName(name, authors: authors);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -1246,8 +1282,10 @@ class _RepositoryDirectory extends _RepositoryEntry implements LicenseSource {
|
|||||||
/// this directory tree.
|
/// this directory tree.
|
||||||
Future<String> get signature async {
|
Future<String> get signature async {
|
||||||
final List<_RepositoryLicensedFile> allFiles = _signatureFiles.toList();
|
final List<_RepositoryLicensedFile> allFiles = _signatureFiles.toList();
|
||||||
allFiles.sort((_RepositoryLicensedFile a, _RepositoryLicensedFile b) =>
|
allFiles.sort(
|
||||||
a.io.fullName.compareTo(b.io.fullName));
|
(_RepositoryLicensedFile a, _RepositoryLicensedFile b) =>
|
||||||
|
a.io.fullName.compareTo(b.io.fullName),
|
||||||
|
);
|
||||||
final crypto.Digest digest = await crypto.md5.bind(_signatureStream(allFiles)).single;
|
final crypto.Digest digest = await crypto.md5.bind(_signatureStream(allFiles)).single;
|
||||||
return digest.bytes.map((int e) => e.toRadixString(16).padLeft(2, '0')).join();
|
return digest.bytes.map((int e) => e.toRadixString(16).padLeft(2, '0')).join();
|
||||||
}
|
}
|
||||||
@ -1277,12 +1315,19 @@ class _RepositoryReachOutFile extends _RepositoryLicensedFile {
|
|||||||
directory = directory.parent;
|
directory = directory.parent;
|
||||||
index -= 1;
|
index -= 1;
|
||||||
}
|
}
|
||||||
return directory!.nearestLicensesFor(name).map((License license) => license.assignLicenses(io.fullName, parent!));
|
return directory!
|
||||||
|
.nearestLicensesFor(name)
|
||||||
|
.map((License license) => license.assignLicenses(io.fullName, parent!));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _RepositoryReachOutDirectory extends _RepositoryDirectory {
|
class _RepositoryReachOutDirectory extends _RepositoryDirectory {
|
||||||
_RepositoryReachOutDirectory(_RepositoryDirectory super.parent, super.io, this.reachOutFilenames, this.offset);
|
_RepositoryReachOutDirectory(
|
||||||
|
_RepositoryDirectory super.parent,
|
||||||
|
super.io,
|
||||||
|
this.reachOutFilenames,
|
||||||
|
this.offset,
|
||||||
|
);
|
||||||
|
|
||||||
final Set<String> reachOutFilenames;
|
final Set<String> reachOutFilenames;
|
||||||
final int offset;
|
final int offset;
|
||||||
@ -1356,13 +1401,25 @@ class _RepositoryInjaJsonFile extends _RepositorySourceFile {
|
|||||||
throw '${io.fullName} has changed contents.';
|
throw '${io.fullName} has changed contents.';
|
||||||
}
|
}
|
||||||
final String license = match.group(3)!;
|
final String license = match.group(3)!;
|
||||||
_internalLicenses = match.groups(const <int>[ 2, 6, 8 ]).map<License>((String? copyright) {
|
_internalLicenses =
|
||||||
assert(copyright!.contains('Copyright'));
|
match.groups(const <int>[2, 6, 8]).map<License>((String? copyright) {
|
||||||
return License.fromCopyrightAndLicense(copyright!, license, LicenseType.mit, origin: io.fullName);
|
assert(copyright!.contains('Copyright'));
|
||||||
}).toList();
|
return License.fromCopyrightAndLicense(
|
||||||
assert(!match.groups(const <int>[ 1, 4, 5, 7, 9, 10, 11]).any((String? text) => text!.contains(copyrightMentionPattern)));
|
copyright!,
|
||||||
|
license,
|
||||||
|
LicenseType.mit,
|
||||||
|
origin: io.fullName,
|
||||||
|
);
|
||||||
|
}).toList();
|
||||||
|
assert(
|
||||||
|
!match
|
||||||
|
.groups(const <int>[1, 4, 5, 7, 9, 10, 11])
|
||||||
|
.any((String? text) => text!.contains(copyrightMentionPattern)),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return _internalLicenses!.map((License license) => license.assignLicenses(io.fullName, parent!));
|
return _internalLicenses!.map(
|
||||||
|
(License license) => license.assignLicenses(io.fullName, parent!),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1390,8 +1447,10 @@ class _EngineSrcDirectory extends _RepositoryDirectory {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool shouldRecurse(fs.IoNode entry) {
|
bool shouldRecurse(fs.IoNode entry) {
|
||||||
return entry.name != 'third_party' // all third_party components have been moved to flutter/third_party
|
return entry.name !=
|
||||||
&& super.shouldRecurse(entry);
|
'third_party' // all third_party components have been moved to flutter/third_party
|
||||||
|
&&
|
||||||
|
super.shouldRecurse(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -1520,7 +1579,10 @@ class _RepositoryFallbackRootCertificatesDirectory extends _RepositoryDirectory
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get officialSourceLocation {
|
String get officialSourceLocation {
|
||||||
final system.ProcessResult result = system.Process.runSync('git', <String>['rev-parse', 'HEAD'], workingDirectory: '$this');
|
final system.ProcessResult result = system.Process.runSync('git', <String>[
|
||||||
|
'rev-parse',
|
||||||
|
'HEAD',
|
||||||
|
], workingDirectory: '$this');
|
||||||
if (result.exitCode != 0) {
|
if (result.exitCode != 0) {
|
||||||
throw 'Failed to run "git rev-parse HEAD"; got non-zero exit code ${result.exitCode}\nstdout:\n${result.stdout}\nstderr:\n${result.stderr}';
|
throw 'Failed to run "git rev-parse HEAD"; got non-zero exit code ${result.exitCode}\nstdout:\n${result.stdout}\nstderr:\n${result.stderr}';
|
||||||
}
|
}
|
||||||
@ -1538,7 +1600,7 @@ class _RepositoryZLibDirectory extends _RepositoryDirectory {
|
|||||||
// exact same license text as in LICENSE.
|
// exact same license text as in LICENSE.
|
||||||
|
|
||||||
@override
|
@override
|
||||||
License? nearestLicenseWithName(String name, { String? authors }) {
|
License? nearestLicenseWithName(String name, {String? authors}) {
|
||||||
if (name == 'MiniZip_info.txt') {
|
if (name == 'MiniZip_info.txt') {
|
||||||
return super.nearestLicenseWithName('LICENSE', authors: authors)!;
|
return super.nearestLicenseWithName('LICENSE', authors: authors)!;
|
||||||
}
|
}
|
||||||
@ -1663,7 +1725,9 @@ class _RepositoryBoringSSLDirectory extends _RepositoryDirectory {
|
|||||||
@override
|
@override
|
||||||
License? nearestLicenseWithName(String name, {String? authors}) {
|
License? nearestLicenseWithName(String name, {String? authors}) {
|
||||||
assert(!src._canGoUp());
|
assert(!src._canGoUp());
|
||||||
final License? result = super.nearestLicenseWithName(name, authors: authors) ?? src.nearestLicenseWithName(name, authors: authors);
|
final License? result =
|
||||||
|
super.nearestLicenseWithName(name, authors: authors) ??
|
||||||
|
src.nearestLicenseWithName(name, authors: authors);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1713,9 +1777,13 @@ class _RepositoryFlutterThirdPartyDirectory extends _RepositoryGenericThirdParty
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool shouldRecurse(fs.IoNode entry) {
|
bool shouldRecurse(fs.IoNode entry) {
|
||||||
return entry.name != 'skia' // handled as a virtual directory of the root
|
return entry.name !=
|
||||||
&& entry.name != 'dart' // handled as a virtual directory of the root
|
'skia' // handled as a virtual directory of the root
|
||||||
&& super.shouldRecurse(entry);
|
&&
|
||||||
|
entry.name !=
|
||||||
|
'dart' // handled as a virtual directory of the root
|
||||||
|
&&
|
||||||
|
super.shouldRecurse(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -1756,7 +1824,6 @@ class _RepositoryGpuShimDirectory extends _RepositoryDirectory {
|
|||||||
String get libraryName => 'engine';
|
String get libraryName => 'engine';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// The license tool directory.
|
/// The license tool directory.
|
||||||
///
|
///
|
||||||
/// This is a special-case root node that is not used for license aggregation,
|
/// This is a special-case root node that is not used for license aggregation,
|
||||||
@ -1772,13 +1839,14 @@ class _RepositoryFlutterLicenseToolDirectory extends _RepositoryDirectory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// BOOTSTRAPPING LOGIC
|
// BOOTSTRAPPING LOGIC
|
||||||
|
|
||||||
fs.Directory? findChildDirectory(fs.Directory parent, String name) {
|
fs.Directory? findChildDirectory(fs.Directory parent, String name) {
|
||||||
return parent.walk.firstWhereOrNull( // from IterableExtension in package:collection
|
return parent.walk.firstWhereOrNull(
|
||||||
(fs.IoNode child) => child.name == name,
|
// from IterableExtension in package:collection
|
||||||
) as fs.Directory?;
|
(fs.IoNode child) => child.name == name,
|
||||||
|
)
|
||||||
|
as fs.Directory?;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _Progress {
|
class _Progress {
|
||||||
@ -1821,7 +1889,9 @@ class _Progress {
|
|||||||
|
|
||||||
Stopwatch? _lastUpdate;
|
Stopwatch? _lastUpdate;
|
||||||
void update({bool flush = false}) {
|
void update({bool flush = false}) {
|
||||||
if (_lastUpdate == null || _lastUpdate!.elapsedMilliseconds >= millisecondsBetweenUpdates || flush) {
|
if (_lastUpdate == null ||
|
||||||
|
_lastUpdate!.elapsedMilliseconds >= millisecondsBetweenUpdates ||
|
||||||
|
flush) {
|
||||||
_lastUpdate ??= Stopwatch();
|
_lastUpdate ??= Stopwatch();
|
||||||
if (!quiet) {
|
if (!quiet) {
|
||||||
final String line = toString();
|
final String line = toString();
|
||||||
@ -1842,13 +1912,17 @@ class _Progress {
|
|||||||
String toString() {
|
String toString() {
|
||||||
final int percent = (100.0 * (_withLicense + _withoutLicense) / max).round();
|
final int percent = (100.0 * (_withLicense + _withoutLicense) / max).round();
|
||||||
return '${(_withLicense + _withoutLicense).toString().padLeft(10)} of ${max.toString().padRight(6)} '
|
return '${(_withLicense + _withoutLicense).toString().padLeft(10)} of ${max.toString().padRight(6)} '
|
||||||
'${'█' * (percent ~/ 10)}${'░' * (10 - (percent ~/ 10))} $percent% '
|
'${'█' * (percent ~/ 10)}${'░' * (10 - (percent ~/ 10))} $percent% '
|
||||||
'${ _withoutLicense > 0 ? "($_withoutLicense missing licenses) " : ""}'
|
'${_withoutLicense > 0 ? "($_withoutLicense missing licenses) " : ""}'
|
||||||
'$label';
|
'$label';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final RegExp _signaturePattern = RegExp(r'^Signature: (\w+)$', multiLine: true, expectNoMatch: true);
|
final RegExp _signaturePattern = RegExp(
|
||||||
|
r'^Signature: (\w+)$',
|
||||||
|
multiLine: true,
|
||||||
|
expectNoMatch: true,
|
||||||
|
);
|
||||||
|
|
||||||
/// Reads the signature from a golden file.
|
/// Reads the signature from a golden file.
|
||||||
String? _readSignature(String goldenPath) {
|
String? _readSignature(String goldenPath) {
|
||||||
@ -1879,11 +1953,17 @@ void _writeSignature(String signature, system.IOSink sink) {
|
|||||||
// Checks for changes to the license tool itself.
|
// Checks for changes to the license tool itself.
|
||||||
//
|
//
|
||||||
// Returns true if changes are detected.
|
// Returns true if changes are detected.
|
||||||
Future<bool> _computeLicenseToolChanges(_RepositoryDirectory root, { required String goldenSignaturePath, required String outputSignaturePath }) async {
|
Future<bool> _computeLicenseToolChanges(
|
||||||
|
_RepositoryDirectory root, {
|
||||||
|
required String goldenSignaturePath,
|
||||||
|
required String outputSignaturePath,
|
||||||
|
}) async {
|
||||||
final fs.Directory flutterNode = findChildDirectory(root.ioDirectory, 'flutter')!;
|
final fs.Directory flutterNode = findChildDirectory(root.ioDirectory, 'flutter')!;
|
||||||
final fs.Directory toolsNode = findChildDirectory(flutterNode, 'tools')!;
|
final fs.Directory toolsNode = findChildDirectory(flutterNode, 'tools')!;
|
||||||
final fs.Directory licenseNode = findChildDirectory(toolsNode, 'licenses')!;
|
final fs.Directory licenseNode = findChildDirectory(toolsNode, 'licenses')!;
|
||||||
final _RepositoryDirectory licenseToolDirectory = _RepositoryFlutterLicenseToolDirectory(licenseNode);
|
final _RepositoryDirectory licenseToolDirectory = _RepositoryFlutterLicenseToolDirectory(
|
||||||
|
licenseNode,
|
||||||
|
);
|
||||||
final String toolSignature = await licenseToolDirectory.signature;
|
final String toolSignature = await licenseToolDirectory.signature;
|
||||||
final system.IOSink sink = system.File(outputSignaturePath).openWrite();
|
final system.IOSink sink = system.File(outputSignaturePath).openWrite();
|
||||||
_writeSignature(toolSignature, sink);
|
_writeSignature(toolSignature, sink);
|
||||||
@ -1896,7 +1976,8 @@ Future<bool> _computeLicenseToolChanges(_RepositoryDirectory root, { required St
|
|||||||
///
|
///
|
||||||
/// If [writeSignature] is set, the signature is written to the output file.
|
/// If [writeSignature] is set, the signature is written to the output file.
|
||||||
/// If [force] is set, collection is run regardless of whether or not the signature matches.
|
/// If [force] is set, collection is run regardless of whether or not the signature matches.
|
||||||
Future<void> _collectLicensesForComponent(_RepositoryDirectory componentRoot, {
|
Future<void> _collectLicensesForComponent(
|
||||||
|
_RepositoryDirectory componentRoot, {
|
||||||
required String inputGoldenPath,
|
required String inputGoldenPath,
|
||||||
String? outputGoldenPath,
|
String? outputGoldenPath,
|
||||||
required bool writeSignature,
|
required bool writeSignature,
|
||||||
@ -1929,7 +2010,8 @@ Future<void> _collectLicensesForComponent(_RepositoryDirectory componentRoot, {
|
|||||||
}
|
}
|
||||||
progress.label = 'Dumping results...';
|
progress.label = 'Dumping results...';
|
||||||
progress.flush();
|
progress.flush();
|
||||||
final List<String> output = licenses.map((GroupedLicense license) => license.toStringDebug()).toList();
|
final List<String> output =
|
||||||
|
licenses.map((GroupedLicense license) => license.toStringDebug()).toList();
|
||||||
for (int index = 0; index < output.length; index += 1) {
|
for (int index = 0; index < output.length; index += 1) {
|
||||||
// The strings we look for here are strings which we do not expect to see in
|
// The strings we look for here are strings which we do not expect to see in
|
||||||
// any of the licenses we use. They either represent examples of misparsing
|
// any of the licenses we use. They either represent examples of misparsing
|
||||||
@ -1943,7 +2025,9 @@ Future<void> _collectLicensesForComponent(_RepositoryDirectory componentRoot, {
|
|||||||
if (output[index].contains('Version: MPL 1.1/GPL 2.0/LGPL 2.1')) {
|
if (output[index].contains('Version: MPL 1.1/GPL 2.0/LGPL 2.1')) {
|
||||||
throw 'Unexpected trilicense block found in:\n${output[index]}';
|
throw 'Unexpected trilicense block found in:\n${output[index]}';
|
||||||
}
|
}
|
||||||
if (output[index].contains('The contents of this file are subject to the Mozilla Public License Version')) {
|
if (output[index].contains(
|
||||||
|
'The contents of this file are subject to the Mozilla Public License Version',
|
||||||
|
)) {
|
||||||
throw 'Unexpected MPL block found in:\n${output[index]}';
|
throw 'Unexpected MPL block found in:\n${output[index]}';
|
||||||
}
|
}
|
||||||
if (output[index].contains('You should have received a copy of the GNU')) {
|
if (output[index].contains('You should have received a copy of the GNU')) {
|
||||||
@ -1952,16 +2036,22 @@ Future<void> _collectLicensesForComponent(_RepositoryDirectory componentRoot, {
|
|||||||
if (output[index].contains('Contents of this folder are ported from')) {
|
if (output[index].contains('Contents of this folder are ported from')) {
|
||||||
throw 'Unexpected block found in:\n${output[index]}';
|
throw 'Unexpected block found in:\n${output[index]}';
|
||||||
}
|
}
|
||||||
if (output[index].contains('https://github.com/w3c/web-platform-tests/tree/master/selectors-api')) {
|
if (output[index].contains(
|
||||||
|
'https://github.com/w3c/web-platform-tests/tree/master/selectors-api',
|
||||||
|
)) {
|
||||||
throw 'Unexpected W3C content found in:\n${output[index]}';
|
throw 'Unexpected W3C content found in:\n${output[index]}';
|
||||||
}
|
}
|
||||||
if (output[index].contains('http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html')) {
|
if (output[index].contains(
|
||||||
|
'http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html',
|
||||||
|
)) {
|
||||||
throw 'Unexpected W3C copyright found in:\n${output[index]}';
|
throw 'Unexpected W3C copyright found in:\n${output[index]}';
|
||||||
}
|
}
|
||||||
if (output[index].contains('It is based on commit')) {
|
if (output[index].contains('It is based on commit')) {
|
||||||
throw 'Unexpected content found in:\n${output[index]}';
|
throw 'Unexpected content found in:\n${output[index]}';
|
||||||
}
|
}
|
||||||
if (output[index].contains('The original code is covered by the dual-licensing approach described in:')) {
|
if (output[index].contains(
|
||||||
|
'The original code is covered by the dual-licensing approach described in:',
|
||||||
|
)) {
|
||||||
throw 'Unexpected old license reference found in:\n${output[index]}';
|
throw 'Unexpected old license reference found in:\n${output[index]}';
|
||||||
}
|
}
|
||||||
if (output[index].contains('must choose')) {
|
if (output[index].contains('must choose')) {
|
||||||
@ -1980,13 +2070,17 @@ Future<void> _collectLicensesForComponent(_RepositoryDirectory componentRoot, {
|
|||||||
// MAIN
|
// MAIN
|
||||||
|
|
||||||
Future<void> main(List<String> arguments) async {
|
Future<void> main(List<String> arguments) async {
|
||||||
final ArgParser parser = ArgParser()
|
final ArgParser parser =
|
||||||
..addOption('src', help: 'The root of the engine source.')
|
ArgParser()
|
||||||
..addOption('out', help: 'The directory where output is written. (Ignored if used with --release.)')
|
..addOption('src', help: 'The root of the engine source.')
|
||||||
..addOption('golden', help: 'The directory containing golden results.')
|
..addOption(
|
||||||
..addFlag('quiet', help: 'If set, the diagnostic output is much less verbose.')
|
'out',
|
||||||
..addFlag('verbose', help: 'If set, print additional information to help with development.')
|
help: 'The directory where output is written. (Ignored if used with --release.)',
|
||||||
..addFlag('release', help: 'Print output in the format used for product releases.');
|
)
|
||||||
|
..addOption('golden', help: 'The directory containing golden results.')
|
||||||
|
..addFlag('quiet', help: 'If set, the diagnostic output is much less verbose.')
|
||||||
|
..addFlag('verbose', help: 'If set, print additional information to help with development.')
|
||||||
|
..addFlag('release', help: 'Print output in the format used for product releases.');
|
||||||
|
|
||||||
final ArgResults argResults = parser.parse(arguments);
|
final ArgResults argResults = parser.parse(arguments);
|
||||||
final bool quiet = argResults['quiet'] as bool;
|
final bool quiet = argResults['quiet'] as bool;
|
||||||
@ -1999,7 +2093,9 @@ Future<void> main(List<String> arguments) async {
|
|||||||
}
|
}
|
||||||
if (!releaseMode) {
|
if (!releaseMode) {
|
||||||
if (argResults['out'] == null || argResults['golden'] == null) {
|
if (argResults['out'] == null || argResults['golden'] == null) {
|
||||||
print('Flutter license script: Must provide --out and --golden directories in non-release mode');
|
print(
|
||||||
|
'Flutter license script: Must provide --out and --golden directories in non-release mode',
|
||||||
|
);
|
||||||
print(parser.usage);
|
print(parser.usage);
|
||||||
system.exit(1);
|
system.exit(1);
|
||||||
}
|
}
|
||||||
@ -2016,7 +2112,9 @@ Future<void> main(List<String> arguments) async {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
system.stderr.writeln('Finding files...');
|
system.stderr.writeln('Finding files...');
|
||||||
final fs.FileSystemDirectory rootDirectory = fs.FileSystemDirectory.fromPath(argResults['src'] as String);
|
final fs.FileSystemDirectory rootDirectory = fs.FileSystemDirectory.fromPath(
|
||||||
|
argResults['src'] as String,
|
||||||
|
);
|
||||||
final _RepositoryDirectory root = _EngineSrcDirectory(rootDirectory);
|
final _RepositoryDirectory root = _EngineSrcDirectory(rootDirectory);
|
||||||
|
|
||||||
if (releaseMode) {
|
if (releaseMode) {
|
||||||
@ -2029,9 +2127,9 @@ Future<void> main(List<String> arguments) async {
|
|||||||
progress.label = 'Dumping results...';
|
progress.label = 'Dumping results...';
|
||||||
progress.flush();
|
progress.flush();
|
||||||
final String output = licenses
|
final String output = licenses
|
||||||
.where((GroupedLicense license) => license.body.isNotEmpty)
|
.where((GroupedLicense license) => license.body.isNotEmpty)
|
||||||
.map((GroupedLicense license) => license.toStringFormal())
|
.map((GroupedLicense license) => license.toStringFormal())
|
||||||
.join('\n${"-" * 80}\n');
|
.join('\n${"-" * 80}\n');
|
||||||
print(output);
|
print(output);
|
||||||
progress.label = 'Done.';
|
progress.label = 'Done.';
|
||||||
progress.flush();
|
progress.flush();
|
||||||
@ -2047,7 +2145,9 @@ Future<void> main(List<String> arguments) async {
|
|||||||
outputSignaturePath: path.join(argResults['out'] as String, toolSignatureFilename),
|
outputSignaturePath: path.join(argResults['out'] as String, toolSignatureFilename),
|
||||||
);
|
);
|
||||||
if (forceRunAll) {
|
if (forceRunAll) {
|
||||||
system.stderr.writeln('Detected changes to license tool. Forcing license collection for all components.');
|
system.stderr.writeln(
|
||||||
|
'Detected changes to license tool. Forcing license collection for all components.',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
final List<String> usedGoldens = <String>[];
|
final List<String> usedGoldens = <String>[];
|
||||||
bool isFirstComponent = true;
|
bool isFirstComponent = true;
|
||||||
@ -2061,9 +2161,9 @@ Future<void> main(List<String> arguments) async {
|
|||||||
} else {
|
} else {
|
||||||
// For other components, we need a clean repository that does not
|
// For other components, we need a clean repository that does not
|
||||||
// contain any state left over from previous components.
|
// contain any state left over from previous components.
|
||||||
componentRoot = _EngineSrcDirectory(rootDirectory)
|
componentRoot = _EngineSrcDirectory(
|
||||||
.subdirectories
|
rootDirectory,
|
||||||
.firstWhere((_RepositoryDirectory dir) => dir.name == component.name);
|
).subdirectories.firstWhere((_RepositoryDirectory dir) => dir.name == component.name);
|
||||||
}
|
}
|
||||||
final String goldenFileName = 'licenses_${component.io.name}';
|
final String goldenFileName = 'licenses_${component.io.name}';
|
||||||
await _collectLicensesForComponent(
|
await _collectLicensesForComponent(
|
||||||
@ -2080,23 +2180,30 @@ Future<void> main(List<String> arguments) async {
|
|||||||
);
|
);
|
||||||
usedGoldens.add(goldenFileName);
|
usedGoldens.add(goldenFileName);
|
||||||
}
|
}
|
||||||
final Set<String> unusedGoldens = system.Directory(argResults['golden'] as String).listSync()
|
final Set<String> unusedGoldens =
|
||||||
.map<String>((system.FileSystemEntity file) => path.basename(file.path))
|
system.Directory(argResults['golden'] as String)
|
||||||
.where((String name) => name.startsWith('licenses_'))
|
.listSync()
|
||||||
.toSet()
|
.map<String>((system.FileSystemEntity file) => path.basename(file.path))
|
||||||
..removeAll(usedGoldens);
|
.where((String name) => name.startsWith('licenses_'))
|
||||||
|
.toSet()
|
||||||
|
..removeAll(usedGoldens);
|
||||||
if (unusedGoldens.isNotEmpty) {
|
if (unusedGoldens.isNotEmpty) {
|
||||||
system.stderr.writeln('The following golden files in ${argResults['golden']} are unused and need to be deleted:');
|
system.stderr.writeln(
|
||||||
|
'The following golden files in ${argResults['golden']} are unused and need to be deleted:',
|
||||||
|
);
|
||||||
unusedGoldens.map((String s) => ' * $s').forEach(system.stderr.writeln);
|
unusedGoldens.map((String s) => ' * $s').forEach(system.stderr.writeln);
|
||||||
system.exit(1);
|
system.exit(1);
|
||||||
}
|
}
|
||||||
// write to disk the list of files we did _not_ cover, so it's easier to catch in diffs
|
// write to disk the list of files we did _not_ cover, so it's easier to catch in diffs
|
||||||
final String excluded = (_RepositoryDirectory._excluded.map(
|
final String excluded = (_RepositoryDirectory._excluded
|
||||||
(fs.IoNode node) => node.fullName,
|
.map((fs.IoNode node) => node.fullName)
|
||||||
).toSet().toList()..sort()).join('\n');
|
.toSet()
|
||||||
system.File(path.join(argResults['out'] as String, 'excluded_files')).writeAsStringSync(
|
.toList()
|
||||||
'$excluded\n',
|
..sort())
|
||||||
);
|
.join('\n');
|
||||||
|
system.File(
|
||||||
|
path.join(argResults['out'] as String, 'excluded_files'),
|
||||||
|
).writeAsStringSync('$excluded\n');
|
||||||
}
|
}
|
||||||
} catch (e, stack) {
|
} catch (e, stack) {
|
||||||
system.stderr.writeln();
|
system.stderr.writeln();
|
||||||
|
@ -467,10 +467,16 @@ final List<Pattern> skippedFilePatterns = <Pattern>[
|
|||||||
RegExp(r'/CHANGELOG(?:\.[.A-Z0-9]+)?$', caseSensitive: false),
|
RegExp(r'/CHANGELOG(?:\.[.A-Z0-9]+)?$', caseSensitive: false),
|
||||||
RegExp(r'/INSTALL(?:\.[a-zA-Z0-9]+)?$'),
|
RegExp(r'/INSTALL(?:\.[a-zA-Z0-9]+)?$'),
|
||||||
RegExp(r'/Makefile(?:\.[.A-Z0-9]+)?$', caseSensitive: false),
|
RegExp(r'/Makefile(?:\.[.A-Z0-9]+)?$', caseSensitive: false),
|
||||||
RegExp(r'\.~[0-9]+~$', expectNoMatch: true), // files that end in ".~1~", a backup convention of some IDEs
|
RegExp(
|
||||||
|
r'\.~[0-9]+~$',
|
||||||
|
expectNoMatch: true,
|
||||||
|
), // files that end in ".~1~", a backup convention of some IDEs
|
||||||
RegExp(r'\bmanual\.txt$'),
|
RegExp(r'\bmanual\.txt$'),
|
||||||
RegExp(r'^flutter/(?:.+/)*[^/]+_unittests?\.[^/]+$'),
|
RegExp(r'^flutter/(?:.+/)*[^/]+_unittests?\.[^/]+$'),
|
||||||
RegExp(r'^flutter/lib/web_ui/lib/assets/ahem\.ttf$', expectNoMatch: true), // this gitignored file exists only for testing purposes
|
RegExp(
|
||||||
|
r'^flutter/lib/web_ui/lib/assets/ahem\.ttf$',
|
||||||
|
expectNoMatch: true,
|
||||||
|
), // this gitignored file exists only for testing purposes
|
||||||
RegExp(r'^flutter/sky/packages/sky_engine/LICENSE$'), // that is the output of this script
|
RegExp(r'^flutter/sky/packages/sky_engine/LICENSE$'), // that is the output of this script
|
||||||
RegExp(r'^flutter/third_party/abseil-cpp/(?:.+/)*[^/]+_test\.[^/]+$'),
|
RegExp(r'^flutter/third_party/abseil-cpp/(?:.+/)*[^/]+_test\.[^/]+$'),
|
||||||
RegExp(r'^flutter/third_party/angle/(?:.+/)*[^/]+_unittest\.[^/]+$'),
|
RegExp(r'^flutter/third_party/angle/(?:.+/)*[^/]+_unittest\.[^/]+$'),
|
||||||
@ -478,6 +484,8 @@ final List<Pattern> skippedFilePatterns = <Pattern>[
|
|||||||
RegExp(r'^flutter/third_party/boringssl/src/crypto/fipsmodule/bn/[^/]+.go$'),
|
RegExp(r'^flutter/third_party/boringssl/src/crypto/fipsmodule/bn/[^/]+.go$'),
|
||||||
RegExp(r'^flutter/third_party/boringssl/src/crypto/fipsmodule/ec/[^/]+.go$'),
|
RegExp(r'^flutter/third_party/boringssl/src/crypto/fipsmodule/ec/[^/]+.go$'),
|
||||||
RegExp(r'^flutter/third_party/dart/(?:.+/)*[^/]+_test\.[^/]+$'),
|
RegExp(r'^flutter/third_party/dart/(?:.+/)*[^/]+_test\.[^/]+$'),
|
||||||
RegExp(r'^flutter/third_party/freetype2/docs/(?!FTL\.TXT$).+'), // ignore all documentation except the license
|
RegExp(
|
||||||
|
r'^flutter/third_party/freetype2/docs/(?!FTL\.TXT$).+',
|
||||||
|
), // ignore all documentation except the license
|
||||||
RegExp(r'^flutter/third_party/zlib/(?:.+/)*[^/]+_unittest\.[^/]+$'),
|
RegExp(r'^flutter/third_party/zlib/(?:.+/)*[^/]+_unittest\.[^/]+$'),
|
||||||
];
|
];
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -14,8 +14,16 @@ class RegExp implements core.RegExp {
|
|||||||
bool unicode = false,
|
bool unicode = false,
|
||||||
bool dotAll = false,
|
bool dotAll = false,
|
||||||
this.expectNoMatch = false,
|
this.expectNoMatch = false,
|
||||||
}) : _pattern = core.RegExp(source, multiLine: multiLine, caseSensitive: caseSensitive, unicode: unicode, dotAll: dotAll),
|
}) : _pattern = core.RegExp(
|
||||||
source = _stripFrameNumber(StackTrace.current.toString().split('\n').skip(1).take(1).single) {
|
source,
|
||||||
|
multiLine: multiLine,
|
||||||
|
caseSensitive: caseSensitive,
|
||||||
|
unicode: unicode,
|
||||||
|
dotAll: dotAll,
|
||||||
|
),
|
||||||
|
source = _stripFrameNumber(
|
||||||
|
StackTrace.current.toString().split('\n').skip(1).take(1).single,
|
||||||
|
) {
|
||||||
_allPatterns.add(this);
|
_allPatterns.add(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,28 +51,36 @@ class RegExp implements core.RegExp {
|
|||||||
stderr.writeln('Top ten patterns:');
|
stderr.writeln('Top ten patterns:');
|
||||||
patterns.sort((RegExp a, RegExp b) => b._stopwatch.elapsed.compareTo(a._stopwatch.elapsed));
|
patterns.sort((RegExp a, RegExp b) => b._stopwatch.elapsed.compareTo(a._stopwatch.elapsed));
|
||||||
for (final RegExp pattern in patterns.take(10)) {
|
for (final RegExp pattern in patterns.take(10)) {
|
||||||
stderr.writeln('${pattern._stopwatch.elapsedMicroseconds.toString().padLeft(10)}μs tests -- /${pattern.pattern}/ (${pattern.testCount} tests, ${pattern.matchCount} matches, ${pattern.source})');
|
stderr.writeln(
|
||||||
|
'${pattern._stopwatch.elapsedMicroseconds.toString().padLeft(10)}μs tests -- /${pattern.pattern}/ (${pattern.testCount} tests, ${pattern.matchCount} matches, ${pattern.source})',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
stderr.writeln();
|
stderr.writeln();
|
||||||
stderr.writeln('Unmatched patterns:');
|
stderr.writeln('Unmatched patterns:');
|
||||||
patterns.sort((RegExp a, RegExp b) => a.pattern.compareTo(b.pattern));
|
patterns.sort((RegExp a, RegExp b) => a.pattern.compareTo(b.pattern));
|
||||||
for (final RegExp pattern in patterns) {
|
for (final RegExp pattern in patterns) {
|
||||||
if (pattern.matchCount == 0 && !pattern.expectNoMatch && pattern.testCount > 0) {
|
if (pattern.matchCount == 0 && !pattern.expectNoMatch && pattern.testCount > 0) {
|
||||||
stderr.writeln('/${pattern.pattern}/ (${pattern.testCount} tests, ${pattern.matchCount} matches, ${pattern.source})');
|
stderr.writeln(
|
||||||
|
'/${pattern.pattern}/ (${pattern.testCount} tests, ${pattern.matchCount} matches, ${pattern.source})',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stderr.writeln();
|
stderr.writeln();
|
||||||
stderr.writeln('Unexpectedly matched patterns:');
|
stderr.writeln('Unexpectedly matched patterns:');
|
||||||
for (final RegExp pattern in patterns) {
|
for (final RegExp pattern in patterns) {
|
||||||
if (pattern.matchCount > 0 && pattern.expectNoMatch) {
|
if (pattern.matchCount > 0 && pattern.expectNoMatch) {
|
||||||
stderr.writeln('/${pattern.pattern}/ (${pattern.testCount} tests, ${pattern.matchCount} matches, ${pattern.source})');
|
stderr.writeln(
|
||||||
|
'/${pattern.pattern}/ (${pattern.testCount} tests, ${pattern.matchCount} matches, ${pattern.source})',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stderr.writeln();
|
stderr.writeln();
|
||||||
stderr.writeln('Unused patterns:');
|
stderr.writeln('Unused patterns:');
|
||||||
for (final RegExp pattern in patterns) {
|
for (final RegExp pattern in patterns) {
|
||||||
if (pattern.testCount == 0) {
|
if (pattern.testCount == 0) {
|
||||||
stderr.writeln('/${pattern.pattern}/ (${pattern.testCount} tests, ${pattern.matchCount} matches, ${pattern.source})');
|
stderr.writeln(
|
||||||
|
'/${pattern.pattern}/ (${pattern.testCount} tests, ${pattern.matchCount} matches, ${pattern.source})',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,9 +18,15 @@ void main() {
|
|||||||
});
|
});
|
||||||
test('Indenting blocks', () {
|
test('Indenting blocks', () {
|
||||||
expect(reformat(' a\nb\n c'), 'a\nb\n c'); // strips leading indents
|
expect(reformat(' a\nb\n c'), 'a\nb\n c'); // strips leading indents
|
||||||
expect(reformat(' a\n b\n c'), 'a\nb\nc'); // strips common one-space indent, then strips stray one-space indents
|
expect(
|
||||||
|
reformat(' a\n b\n c'),
|
||||||
|
'a\nb\nc',
|
||||||
|
); // strips common one-space indent, then strips stray one-space indents
|
||||||
expect(reformat(' a\n b\n c'), 'a\nb\nc'); // strips common two-space indent
|
expect(reformat(' a\n b\n c'), 'a\nb\nc'); // strips common two-space indent
|
||||||
expect(reformat(' a\n b\n c'), 'a\nb\nc'); // strips common two-space indent, then strips stray one-space indent
|
expect(
|
||||||
|
reformat(' a\n b\n c'),
|
||||||
|
'a\nb\nc',
|
||||||
|
); // strips common two-space indent, then strips stray one-space indent
|
||||||
expect(reformat(' a\n b\n c'), 'a\n b\nc'); // streps common two-space indent
|
expect(reformat(' a\n b\n c'), 'a\n b\nc'); // streps common two-space indent
|
||||||
expect(reformat(' a\n b\n c'), 'a\n b\nc'); // streps common two-space indent
|
expect(reformat(' a\n b\n c'), 'a\n b\nc'); // streps common two-space indent
|
||||||
});
|
});
|
||||||
@ -46,42 +52,45 @@ void main() {
|
|||||||
expect(reformat(' a\n a\n b\nc'), 'a\na\n b\nc');
|
expect(reformat(' a\n a\n b\nc'), 'a\na\n b\nc');
|
||||||
});
|
});
|
||||||
test('Specific cases', () {
|
test('Specific cases', () {
|
||||||
expect(reformat(' Apache\n Version\n Bla bla\n\nBla bla bla'), 'Apache\nVersion\nBla bla\n\nBla bla bla');
|
|
||||||
expect(
|
expect(
|
||||||
reformat(
|
reformat(' Apache\n Version\n Bla bla\n\nBla bla bla'),
|
||||||
'/* Copyright (c) IBM Corporation, 2000-2012. All rights reserved. */\n'
|
'Apache\nVersion\nBla bla\n\nBla bla bla',
|
||||||
'/* */\n'
|
|
||||||
'/* This software is made available under the terms of the */\n'
|
|
||||||
'/* ICU License -- ICU 1.8.1 and later. */\n'
|
|
||||||
),
|
|
||||||
'Copyright (c) IBM Corporation, 2000-2012. All rights reserved.\n'
|
|
||||||
'\n'
|
|
||||||
'This software is made available under the terms of the\n'
|
|
||||||
'ICU License -- ICU 1.8.1 and later.'
|
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
reformat(
|
reformat(
|
||||||
'/* Copyright (c) IBM Corporation, 2000-2012. All rights reserved. */\n'
|
'/* Copyright (c) IBM Corporation, 2000-2012. All rights reserved. */\n'
|
||||||
'/* */\n'
|
'/* */\n'
|
||||||
'/* This software is made available under the terms of the */\n'
|
'/* This software is made available under the terms of the */\n'
|
||||||
'/* ICU License -- ICU 1.8.1 and later. */'
|
'/* ICU License -- ICU 1.8.1 and later. */\n',
|
||||||
),
|
),
|
||||||
'Copyright (c) IBM Corporation, 2000-2012. All rights reserved.\n'
|
'Copyright (c) IBM Corporation, 2000-2012. All rights reserved.\n'
|
||||||
'\n'
|
'\n'
|
||||||
'This software is made available under the terms of the\n'
|
'This software is made available under the terms of the\n'
|
||||||
'ICU License -- ICU 1.8.1 and later.'
|
'ICU License -- ICU 1.8.1 and later.',
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
reformat(
|
reformat(
|
||||||
'/* Copyright (c) IBM Corporation, 2000-2012. All rights reserved. */\n'
|
'/* Copyright (c) IBM Corporation, 2000-2012. All rights reserved. */\n'
|
||||||
'/* */\n'
|
'/* */\n'
|
||||||
'/* This software is made available under the terms of the */\n'
|
'/* This software is made available under the terms of the */\n'
|
||||||
'/* ICU License -- ICU 1.8.1 and later.'
|
'/* ICU License -- ICU 1.8.1 and later. */',
|
||||||
),
|
),
|
||||||
'Copyright (c) IBM Corporation, 2000-2012. All rights reserved.\n'
|
'Copyright (c) IBM Corporation, 2000-2012. All rights reserved.\n'
|
||||||
'\n'
|
'\n'
|
||||||
'This software is made available under the terms of the\n'
|
'This software is made available under the terms of the\n'
|
||||||
'ICU License -- ICU 1.8.1 and later.'
|
'ICU License -- ICU 1.8.1 and later.',
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
reformat(
|
||||||
|
'/* Copyright (c) IBM Corporation, 2000-2012. All rights reserved. */\n'
|
||||||
|
'/* */\n'
|
||||||
|
'/* This software is made available under the terms of the */\n'
|
||||||
|
'/* ICU License -- ICU 1.8.1 and later.',
|
||||||
|
),
|
||||||
|
'Copyright (c) IBM Corporation, 2000-2012. All rights reserved.\n'
|
||||||
|
'\n'
|
||||||
|
'This software is made available under the terms of the\n'
|
||||||
|
'ICU License -- ICU 1.8.1 and later.',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user