diff --git a/.gitignore b/.gitignore index 57696b6cdc409..9abe6831d2794 100644 --- a/.gitignore +++ b/.gitignore @@ -49,7 +49,6 @@ xcuserdata .project .settings/ .vscode/ -!.vscode/extensions.json # packages file containing multi-root paths .packages.generated diff --git a/.vscode/extensions.json b/.vscode/extensions.json deleted file mode 100644 index 314960ffa5d1b..0000000000000 --- a/.vscode/extensions.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "recommendations": [ - // Uses github-styled markdown preview, which supports more features than the default markdown preview. - "bierner.github-markdown-preview", - - // Flutter and Dart extensions. - "Dart-Code.dart-code", - - // Supports C/C++ in the engine. - // See https://github.com/flutter/engine/blob/main/docs/contributing/Setting-up-the-Engine-development-environment.md#vscode-with-cc-intellisense-cc - "llvm-vs-code-extensions.vscode-clangd", - - // Auto-formats C/C++ code. - // https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#cc - "xaver.clang-format", - ] -} diff --git a/ci/licenses_golden/excluded_files b/ci/licenses_golden/excluded_files index 549608f4d5a5e..56b935eea2ae8 100644 --- a/ci/licenses_golden/excluded_files +++ b/ci/licenses_golden/excluded_files @@ -18,7 +18,6 @@ ../../../flutter/.github ../../../flutter/.gitignore ../../../flutter/.style.yapf -../../../flutter/.vscode ../../../flutter/AUTHORS ../../../flutter/CODEOWNERS ../../../flutter/CONTRIBUTING.md @@ -50,6 +49,7 @@ ../../../flutter/display_list/utils/dl_accumulation_rect_unittests.cc ../../../flutter/display_list/utils/dl_matrix_clip_tracker_unittests.cc ../../../flutter/docs +../../../flutter/engine.code-workspace ../../../flutter/examples ../../../flutter/flow/README.md ../../../flutter/flow/diff_context_unittests.cc diff --git a/ci/licenses_golden/tool_signature b/ci/licenses_golden/tool_signature index 22136f5b4a8a1..4cc7ffd679d25 100644 --- a/ci/licenses_golden/tool_signature +++ b/ci/licenses_golden/tool_signature @@ -1,2 +1,2 @@ -Signature: 53025d1261891c38c7bccb158862e09f +Signature: 8859e172e060ecb45aa665c3119d5d25 diff --git a/engine.code-workspace b/engine.code-workspace new file mode 100644 index 0000000000000..ae76943d85172 --- /dev/null +++ b/engine.code-workspace @@ -0,0 +1,258 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": { + "files.associations": { + "optional": "cpp", + "__bit_reference": "cpp", + "__bits": "cpp", + "__config": "cpp", + "__debug": "cpp", + "__errc": "cpp", + "__hash_table": "cpp", + "__locale": "cpp", + "__mutex_base": "cpp", + "__node_handle": "cpp", + "__nullptr": "cpp", + "__split_buffer": "cpp", + "__string": "cpp", + "__threading_support": "cpp", + "__tree": "cpp", + "__tuple": "cpp", + "any": "cpp", + "array": "cpp", + "atomic": "cpp", + "bitset": "cpp", + "cctype": "cpp", + "chrono": "cpp", + "cinttypes": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "codecvt": "cpp", + "compare": "cpp", + "complex": "cpp", + "concepts": "cpp", + "condition_variable": "cpp", + "csignal": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "exception": "cpp", + "forward_list": "cpp", + "fstream": "cpp", + "future": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "ios": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "list": "cpp", + "locale": "cpp", + "map": "cpp", + "memory": "cpp", + "mutex": "cpp", + "new": "cpp", + "numeric": "cpp", + "ostream": "cpp", + "queue": "cpp", + "random": "cpp", + "ratio": "cpp", + "regex": "cpp", + "set": "cpp", + "span": "cpp", + "sstream": "cpp", + "stack": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "string": "cpp", + "string_view": "cpp", + "strstream": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "typeinfo": "cpp", + "unordered_map": "cpp", + "unordered_set": "cpp", + "valarray": "cpp", + "variant": "cpp", + "vector": "cpp", + "algorithm": "cpp", + "filesystem": "cpp", + "memory_resource": "cpp", + "bit": "cpp", + "charconv": "cpp", + "format": "cpp", + "functional": "cpp", + "iterator": "cpp", + "utility": "cpp", + "__assert": "cpp", + "*.inc": "cpp", + "__verbose_abort": "cpp", + "*.def": "cpp", + "*.hpp11": "cpp", + "__functional_base": "cpp", + "shared_mutex": "cpp", + "coroutine": "cpp", + "hash_map": "cpp", + "hash_set": "cpp", + "thread": "cpp", + "propagate_const": "cpp", + "*.gen": "cpp", + "simd": "cpp", + "barrier": "cpp", + "cuchar": "cpp", + "latch": "cpp", + "numbers": "cpp", + "scoped_allocator": "cpp", + "semaphore": "cpp", + "typeindex": "cpp", + "__std_stream": "cpp", + "*.ipp": "cpp", + "csetjmp": "cpp", + "cfenv": "cpp" + }, + "C_Cpp.default.includePath": [ + "${default}", + "${workspaceFolder}/..", + "${workspaceFolder}", + ], + "dotnet.defaultSolution": "disable", + "dart.showTodos": false, + "testMate.cpp.test.advancedExecutables": [ + { + "name": "impeller_unittests_arm64", + "pattern": "../out/host_debug_unopt_arm64/impeller_unittests", + "runTask": { + "before": [ + "impeller_unittests_arm64" + ] + }, + "gtest": { + "prependTestRunningArgs": [ + "--enable_playground" + ] + } + } + ], + "testMate.cpp.debug.configTemplate": { + "type": "cppvsdbg", + "linux": { + "type": "cppdbg", + "MIMode": "gdb" + }, + "darwin": { + "type": "cppdbg", + "MIMode": "lldb", + "setupCommands": [ + { + "description": "Source map", + "text": "settings set target.source-map \"flutter/\" \"${workspaceFolder}\"", + "ignoreFailures": false + } + ], + }, + "win32": { + "type": "cppvsdbg" + }, + "program": "${exec}", + "args": "${argsArray}", + "cwd": "${cwd}", + "env": "${envObj}", + "environment": "${envObjArray}", + "sourceFileMap": "${sourceFileMapObj}", + } + }, + "tasks": { + "version": "2.0.0", + "tasks": [ + { + "label": "impeller_unittests_arm64", + "type": "shell", + "command": "./flutter/bin/et", + "args": [ + "build", + "-c", + "host_debug_unopt_arm64", + "//flutter/impeller:impeller_unittests" + ], + "options": { + "cwd": "${workspaceFolder}/.." + }, + "problemMatcher": [ + "$gcc" + ], + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared", + "clear": true + }, + "group": { + "kind": "build", + } + } + ] + }, + "extensions": { + "recommendations": [ + // C++ TestMate + "matepek.vscode-catch2-test-adapter", + // Uses github-styled markdown preview, which supports more features than the default markdown preview. + "bierner.github-markdown-preview", + // Flutter and Dart extensions. + "Dart-Code.dart-code", + // Supports C/C++ in the engine. + // See https://github.com/flutter/engine/blob/main/docs/contributing/Setting-up-the-Engine-development-environment.md#vscode-with-cc-intellisense-cc + "llvm-vs-code-extensions.vscode-clangd", + // Auto-formats C/C++ code. + // https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#cc + "xaver.clang-format", + ] + }, + "launch": { + "version": "0.2.0", + "configurations": [ + { + "name": "impeller_unittests_arm64", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/../out/host_debug_unopt_arm64/impeller_unittests", + "args": [ + "--enable_playground", + ], + "stopAtEntry": false, + "cwd": "${workspaceFolder}/../out/host_debug_unopt_arm64", + "environment": [], + "externalConsole": false, + "MIMode": "lldb", + "setupCommands": [ + { + "description": "Enable pretty-printing for lldb", + "text": "settings set target.pretty-printing true", + "ignoreFailures": true + }, + { + "description": "Source map", + "text": "settings set target.source-map \"flutter/\" \"${workspaceFolder}\"", + "ignoreFailures": false + } + ], + "preLaunchTask": "impeller_unittests_arm64", + } + ], + "compounds": [] + } +} \ No newline at end of file diff --git a/tools/json_injector/README.md b/tools/json_injector/README.md new file mode 100644 index 0000000000000..fe1391e3fbe45 --- /dev/null +++ b/tools/json_injector/README.md @@ -0,0 +1,25 @@ +# json_injector + +## Description + +This is a tool to manipulate json files. It's main purpose is to reduce +redundancy in VSCode workspaces. + +It can inject missing keys from one json file into another, treat List\s as +Maps for the purpose of merging and apply templates. + +## Usage + +The following invocation will update //engine.code-workspace, injecting the json +data from `injectors/engine.code-workspace` and also applying the templates at +`./injectors/engine-templates.json`. List\s who have the key named +'label' will be treated as Maps whose key is "label". + +```shell +dart run bin/main.dart \ + --input ~/dev/engine/src/flutter/engine.code-workspace \ + --injector injectors/engine.code-workspace \ + --output ~/dev/engine/src/flutter/engine.code-workspace \ + --name-key label \ + --templates injectors/engine-templates.json +``` \ No newline at end of file diff --git a/tools/json_injector/bin/main.dart b/tools/json_injector/bin/main.dart new file mode 100644 index 0000000000000..8e151a55c1ce2 --- /dev/null +++ b/tools/json_injector/bin/main.dart @@ -0,0 +1,69 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:convert' show JsonEncoder, jsonDecode, jsonEncode; +import 'dart:io'; + +import 'package:args/args.dart'; +import 'package:json_injector/json_injector.dart'; + +void main(List arguments) { + final parser = ArgParser() + ..addOption('input', + abbr: 'i', help: 'Path to the input JSON file', mandatory: true) + ..addOption('injector', + abbr: 'j', help: 'Path to the injector JSON file', mandatory: true) + ..addOption('output', + abbr: 'o', help: 'Path to the output JSON file', mandatory: true) + ..addOption('templates', + abbr: 't', help: 'Path to the templates JSON file', mandatory: false) + ..addOption('name-key', + abbr: 'n', help: 'Name key for processing', mandatory: false); + + late final String inputJson; + late final String injectorJson; + late final String outputPath; + + ArgResults argResults; + try { + argResults = parser.parse(arguments); + inputJson = File(argResults['input'] as String).readAsStringSync(); + injectorJson = File(argResults['injector'] as String).readAsStringSync(); + outputPath = argResults['output'] as String; + } catch (e) { + print('Error: $e\n'); + print('Usage:\n${parser.usage}'); + return; + } + + final String? nameKey = argResults['name-key'] as String?; + Map? templates; + final String? templatesPath = argResults['templates'] as String?; + if (templatesPath != null) { + final templateJson = File(templatesPath).readAsStringSync(); + templates = jsonDecode(templateJson) as Map?; + } + + late final dynamic input; + try { + input = jsonDecode(inputJson); + } catch (ex) { + print('failed to parse: ${argResults['input']}'); + print('Error: $ex'); + return; + } + late final dynamic injector; + try { + injector = jsonDecode(injectorJson); + } catch (ex) { + print('failed to parse: ${argResults['injector']}'); + print('Error: $ex'); + return; + } + + final dynamic result = + inject(input, injector, nameKey: nameKey, templates: templates); + File(outputPath) + .writeAsStringSync(const JsonEncoder.withIndent(' ').convert(result)); +} diff --git a/tools/json_injector/injectors/engine-templates.json b/tools/json_injector/injectors/engine-templates.json new file mode 100644 index 0000000000000..581d3b1fed754 --- /dev/null +++ b/tools/json_injector/injectors/engine-templates.json @@ -0,0 +1,23 @@ +{ + "et-task": { + "type": "shell", + "command": "./flutter/bin/et", + "options": { + "cwd": "${workspaceFolder}/.." + }, + "problemMatcher": [ + "$gcc" + ], + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared", + "clear": true + }, + "group": { + "kind": "build", + "isDefault": true + } + } +} \ No newline at end of file diff --git a/tools/json_injector/injectors/engine.code-workspace b/tools/json_injector/injectors/engine.code-workspace new file mode 100644 index 0000000000000..773071d924915 --- /dev/null +++ b/tools/json_injector/injectors/engine.code-workspace @@ -0,0 +1,26 @@ +{ + "tasks": { + "tasks": [ + { + "label": "display_list_unittests_arm64", + "json_injector:template": "et-task", + "args": [ + "build", + "-c", + "host_debug_unopt_arm64", + "//flutter/display_list:display_list_unittests" + ] + }, + { + "label": "impeller_unittests_arm64", + "json_injector:template": "et-task", + "args": [ + "build", + "-c", + "host_debug_unopt_arm64", + "//flutter/impeller:impeller_unittests" + ] + } + ] + } +} diff --git a/tools/json_injector/lib/json_injector.dart b/tools/json_injector/lib/json_injector.dart new file mode 100644 index 0000000000000..cc8a6bf023fc2 --- /dev/null +++ b/tools/json_injector/lib/json_injector.dart @@ -0,0 +1,98 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +const String _templateKey = 'json_injector:template'; + +bool _isListOf(List list) { + for (final item in list) { + if (item is! T) { + return false; + } + } + return list.isNotEmpty; +} + +dynamic _applyTemplate(dynamic item, Map? templates) { + if (item is Map) { + if (item.containsKey(_templateKey)) { + final String templateName = item[_templateKey] as String; + final Map? template = + templates?[templateName] as Map?; + + if (template == null) { + throw StateError('unknown template: $templateName'); + } + + final Map result = {}; + for (final x in item.keys) { + if (x != _templateKey) { + result[x] = item[x]; + } + } + for (final x in template.keys) { + result[x] = template[x]; + } + return result; + } else { + return item; + } + } else if (item is List) { + return item; + } else { + return item; + } +} + +Object? inject(Object? json, Object? injector, + {String? nameKey, Map? templates}) { + Object? recurse(Object? x, Object? y) => + inject(x, y, nameKey: nameKey, templates: templates); + if (json is Map && injector is Map) { + final result = {}; + for (final key in json.keys) { + if (!injector.containsKey(key)) { + result[key] = json[key]; + } + } + for (final key in injector.keys) { + if (key == _templateKey) { + final String templateName = injector[key] as String; + final Map? template = + templates?[templateName] as Map?; + if (template == null) { + throw StateError('unknown template: $templateName'); + } + for (final templateKey in template.keys) { + result[templateKey] = template[templateKey]; + } + } else if (json.containsKey(key)) { + result[key] = recurse(json[key], injector[key]); + } else { + result[key] = _applyTemplate(injector[key], templates); + } + } + return result; + } + if (json is List && + injector is List && + nameKey != null && + _isListOf>(json) && + _isListOf>(injector)) { + final Map jsonList = {}; + final Map injectorList = {}; + + for (final item in json) { + final Map map = item as Map; + jsonList[map[nameKey] as String] = item; + } + for (final item in injector) { + final Map map = item as Map; + injectorList[map[nameKey] as String] = item; + } + final joined = recurse(jsonList, injectorList) as Map?; + return joined?.values.toList(); + } + + return json; +} diff --git a/tools/json_injector/pubspec.yaml b/tools/json_injector/pubspec.yaml new file mode 100644 index 0000000000000..1d8ccbebc32ab --- /dev/null +++ b/tools/json_injector/pubspec.yaml @@ -0,0 +1,6 @@ +name: json_injector +environment: + sdk: '^3.6.0-255.0.dev' +dependencies: + test: any + args: any diff --git a/tools/json_injector/test/json_injector_test.dart b/tools/json_injector/test/json_injector_test.dart new file mode 100644 index 0000000000000..7846c4bb2988b --- /dev/null +++ b/tools/json_injector/test/json_injector_test.dart @@ -0,0 +1,201 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:convert' show jsonDecode, jsonEncode; + +import 'package:json_injector/json_injector.dart'; +import 'package:test/test.dart'; + +bool _deepEquals(dynamic x, dynamic y) { + if (x is Map && y is Map) { + if (x.length != y.length) { + return false; + } + + for (final key in x.keys) { + if (!_deepEquals(x[key], y[key])) { + return false; + } + } + return true; + } else if (x is List && y is List) { + if (x.length != y.length) { + return false; + } + + for (int i = 0; i < x.length; i++) { + if (!_deepEquals(x[i], y[i])) { + return false; + } + } + return true; + } else { + return x == y; + } +} + +class _DeepMatcher extends Matcher { + _DeepMatcher(this._target); + + final dynamic _target; + + @override + Description describe(Description description) { + description.add('equals $_target'); + return description; + } + + @override + bool matches(dynamic item, Map matchState) => + _deepEquals(item, _target); +} + +Matcher _isDeepEquals(dynamic x) => _DeepMatcher(x); + +void main() { + test('noop', () { + const json = { + 'configurations': [], + }; + final result = inject(json, {}); + + expect(result, _isDeepEquals(json)); + }); + + test('simple inject', () { + const json = { + 'configurations': [], + }; + const injector = { + 'bar': [], + }; + + expect( + inject(json, injector), + _isDeepEquals({ + 'configurations': [], + 'bar': [], + })); + }); + + test('simple recurse', () { + const json = { + 'configurations': { + 'foo': 1, + }, + }; + const injector = { + 'configurations': { + 'bar': 2, + }, + }; + + expect( + inject(json, injector), + _isDeepEquals({ + 'configurations': { + 'foo': 1, + 'bar': 2, + }, + })); + }); + + test('simple list', () { + const json = { + 'configurations': [ + {'name': 'foo', 'x': 1}, + ], + }; + const injector = { + 'configurations': [ + {'name': 'foo', 'y': 1}, + ], + }; + + expect( + inject(json, injector, nameKey: 'name'), + _isDeepEquals({ + 'configurations': [ + {'name': 'foo', 'x': 1, 'y': 1}, + ], + })); + }); + + test('simple template', () { + const json = { + 'configurations': [ + {'name': 'foo', 'x': 1}, + ], + }; + const injector = { + 'configurations': [ + {'name': 'foo', 'json_injector:template': 'super'}, + ], + }; + const templates = { + 'super': {'y': 2, 'z': 3} + }; + + expect( + inject(json, injector, nameKey: 'name', templates: templates), + _isDeepEquals({ + 'configurations': [ + {'name': 'foo', 'x': 1, 'y': 2, 'z': 3}, + ], + })); + }); + + test('simple template - json', () { + dynamic json = { + 'configurations': [ + {'name': 'foo', 'x': 1}, + ], + }; + dynamic injector = { + 'configurations': [ + {'name': 'foo', 'json_injector:template': 'super'}, + ], + }; + Map templates = { + 'super': {'y': 2, 'z': 3} + }; + + json = jsonDecode(jsonEncode(json)); + injector = jsonDecode(jsonEncode(injector)); + templates = jsonDecode(jsonEncode(templates)) as Map; + + expect( + inject(json, injector, nameKey: 'name', templates: templates), + _isDeepEquals({ + 'configurations': [ + {'name': 'foo', 'x': 1, 'y': 2, 'z': 3}, + ], + })); + }); + + test('new list item template', () { + const json = { + 'configurations': [ + {'name': 'foo', 'x': 1}, + ], + }; + const injector = { + 'configurations': [ + {'name': 'bar', 'json_injector:template': 'super'}, + ], + }; + const templates = { + 'super': {'y': 2, 'z': 3} + }; + + expect( + inject(json, injector, nameKey: 'name', templates: templates), + _isDeepEquals({ + 'configurations': [ + {'name': 'foo', 'x': 1}, + {'name': 'bar', 'y': 2, 'z': 3}, + ], + })); + }); +} diff --git a/tools/licenses/lib/paths.dart b/tools/licenses/lib/paths.dart index d2f2b93306c4f..35d17f3c676fd 100644 --- a/tools/licenses/lib/paths.dart +++ b/tools/licenses/lib/paths.dart @@ -25,6 +25,7 @@ final Set skippedPaths = { r'flutter/buildtools', // only used by build r'flutter/ci', r'flutter/docs', + r'flutter/engine.code-workspace', r'flutter/flutter_frontend_server', r'flutter/impeller/docs', r'flutter/lib/web_ui/build', // this is compiler-generated output diff --git a/tools/pub_get_offline.py b/tools/pub_get_offline.py index 2bf6b8ace54a0..bc43990eeb5c8 100644 --- a/tools/pub_get_offline.py +++ b/tools/pub_get_offline.py @@ -46,7 +46,7 @@ os.path.join(ENGINE_DIR, 'tools', 'githooks'), os.path.join(ENGINE_DIR, 'tools', 'golden_tests_harvester'), os.path.join(ENGINE_DIR, 'tools', 'header_guard_check'), - os.path.join(ENGINE_DIR, 'tools', 'licenses'), + os.path.join(ENGINE_DIR, 'tools', 'json_injector'), os.path.join(ENGINE_DIR, 'tools', 'path_ops', 'dart'), os.path.join(ENGINE_DIR, 'tools', 'pkg', 'engine_build_configs'), os.path.join(ENGINE_DIR, 'tools', 'pkg', 'engine_repo_tools'),