-
Notifications
You must be signed in to change notification settings - Fork 67
[native_assets_cli] Protocol environment variables #32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
This package contains the logic for building native assets. This package is the backend that invokes toplevel `build.dart` scripts. For more info on these scripts see https://github.com/dart-lang/native. This is a separate package so that dartdev and flutter_tools can reuse the same logic without flutter_tools having to import dartdev. Some design decisions: * We don't yet have `build_dependencies`, so we use the ordinary dependency graph for ordering of native assets builds. (If there is a cycle we refuse to run.) Bug: dart-lang/pub#3794 * Builds are cached based on all the configuration provided by the caller. Environment variables are ignored in caching. This CL also contains a unit test that invokes the build by not passing through environment variables. However, for Windows we need to pass through at least `SYSTEMROOT` for MSVC to run correctly. So we might need to further explore if we can/want to lock env variables down. Bug: dart-lang/native#32 Bug: dart-lang/native#33 Run tests: ``` dart tools/generate_package_config.dart && \ tools/test.py -n unittest-asserts-release-linux pkg/native_assets_builder ``` Bug: #50565 Change-Id: I133052d7195373e87d20924d61e1e96e3d34ce8f Cq-Include-Trybots: luci.dart.try:pkg-linux-debug-try,pkg-linux-release-try,pkg-mac-release-arm64-try,pkg-mac-release-try,pkg-win-release-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/300203 Reviewed-by: Liam Appelbe <[email protected]> Commit-Queue: Daco Harkes <[email protected]> Reviewed-by: Martin Kustermann <[email protected]> Reviewed-by: Hossein Yousefi <[email protected]>
This PR changes the caching behavior for hooks to be file content hashing instead of last modified timestamps. Closes: #1593. In addition to using file hashes, a timestamp is passed in to detect if files were modified during a build. The moment of hashing contents is after a build is finished, but we should consider files changed after the build started to invalidate the build. If this happens, the build succeeds, but the cache is invalidated and a warning is printed to the logger. The implementation was modeled after the [`FileStore` in flutter_tools](https://github.com/flutter/flutter/blob/1e824af6bd217beb0cc201394c9832316b6150da/packages/flutter_tools/lib/src/build_system/file_store.dart). However, it was adapted to support caching directories and to match the code style in this repository. Directory caching is defined as follows: the hash of the names of the children. This excludes recursive descendants, and excludes the contents of children. For recursive caching (and glob patterns), the populator of the cache should do the glob/recursion to add all directories and files. ### Testing * The existing caching tests (such as `pkgs/native_assets_builder/test/build_runner/build_runner_caching_test.dart`) cover caching behavior. * Now that last-modified are no longer used, some sleeps have been removed from tests. � ### Performance Adding a stopwatch to pkgs/native_assets_builder/test/build_runner/build_runner_caching_test.dart for the second invocation of the hooks so that it is cached. * `lastModified` timestamps: 0.028 seconds (pre this PR) * `package:crypto` `md5`: 0.047 seconds (current PR) * `package:xxh3` `xxh3`: 0.042 seconds The implementation does not use parallel system IO for loading files (no `Future.wait`), but does use async I/O to allow flutter_tools to run other `Target`s in parallel. The (pre and post this PR) implementation is fast enough for a handful of packages with native assets in a `flutter run`. The implementation (pre and post this PR) is not fast enough for hot restart / hot reload with 10+ packages with native assets. So, when exploring support for that, we'll need to revisit the implementation. ### Related issues not addressed in this PR * #32 * Changing environment variables should also cause the hook to rerun. * #1578 * Hook compilation can potentially be shared. (This requires taking more directory locks due to concurrent and re-entrant invocations.)
Originally posted by @mkustermann in #1759 (comment) Let's take this discussion to where we already have context.
I've been playing around a bit with restricting the environment variables: static const _environmentVariablesFilter = {
'ANDROID_HOME',
'PATH',
'PROGRAMDATA',
'SYSTEMROOT',
'TEMP',
'TMP',
}; That's the list of env vars needed to pass the tests on the CI which invoke clang, msvc, and the NDK.
For example, these can cause a rebuild when not needed:
This would probably cause a rebuild when restarting vscode, and a rebuild when updating (unrelated) packages.
@mkustermann The embedder? Or the user? Probably the user should be able to that, otherwise it would still require PRs on the embedder. But I'm slightly worried that that will make the CLI for If we want to allowlist, how much should we add? static const _environmentVariablesFilter = {
// minimum to pass testing
'ANDROID_HOME',
'PATH',
'PROGRAMDATA',
'SYSTEMROOT',
'TEMP',
'TMP',
// used in our own code to locate compilers (not exercised on GitHub CI)
'HOME',
'USER_PROFILE',
// more of the same
'ANDROID_AVD_HOME',
'HOMEDRIVE',
'HOMEPATH',
'SYSTEMDRIVE',
'SYSTEMROOT',
'TMPDIR', // Otherwise Directory.systemTemp defaults to `/tmp` on Unix / MacOS
'USER',
'USERNAME',
// flutter already does code signing, so we could skip?
'CODE_SIGN_IDENTITY',
// more access to things on Windows, who knows what things on Windows depend on.
'ALLUSERSPROFILE',
'APPDATA',
'COMMONPROGRAMFILES',
'COMMONPROGRAMFILES(X86)',
'COMMONPROGRAMW6432',
'LOCALAPPDATA',
'PROGRAMDATA',
'PROGRAMFILES',
'PROGRAMFILES(X86)',
'PROGRAMW6432',
'WINDIR',
// other compilers
'EMSDK_NODE',
'EMSDK_PYTHON',
'EMSDK',
'NVM_BIN',
'NVM_CD_FLAGS',
'NVM_DIR',
'NVM_INC',
// access to the Dart and Flutter SDK?
'DART_SDK_PATH',
'DART',
'FLUTTER_ROOT',
};
|
…ge (#1759) This PR makes the native assets builder save the `Platform.environment` a hook is run in. Subsequent invocations check if the environment didn't change. This removes the `includeParentEnvironment` parameter everywhere. It was always set to true in `dartdev` and `flutter_tools` (This will require a manual roll into the Dart SDK and Flutter tools.) A follow up PR should restrict the list of environment variables (#1764), this PR is about caching correctness. Bug: * #32
Follow up of #160672 to filter the environment keys being passed in to build hooks. ~~Failures don't reproduce locally, so this is a draft PR to see which environment keys are needed for the tests to succeed on CI.~~ Edit: Fixed issues by stopping to use the Flutter-self-update-dart-executable and instead using the Dart-sdk-dart-executable. Relevant bug (already addressed in Dart standalone). * dart-lang/native#32 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
Leaning towards passing in all environment variables, and reinvoking the hooks on any environment variable change.
Problem
With what environment variables should we invoke
build.dart
?build.dart
is invoked with aBuildConfig
(which is read from args/env/file), but the CLI itself most likely invokes other processes (for example a C compiler). These processes are influenced by which environment variables are set.Minimum env variables
Let's say we get
rust_compiler
package that tries to findrustc
onPATH
, then we must at least pass throughPATH
on ourbuild.dart
invocation.On Windows, various tools rely on a host of other environment variables as well:
SYSTEMROOT
is required forcl.exe
from MSVCTMP
andTEMP
are required forcl.exe
in some cases in order to be able to write temporary files.So the minimum list of environment variables we should pass through are the ones mentioned above.
Maximum environment variables
Conversely, there are also environment variables which are conflicting with the Dart ecosystem and native tooling.
SDKROOT
is set bytools/test.py
which breaksxcodebuild
invocations as it interprets theSDKROOT
as a path for the iOS or MacOS SDK rather than the Dart SDK.Caching correctness and cache misses
If any of the environment variables influences the build, it could throw off caching of builds:
Possible solutions
We could consider listing the environment variables we pass through, making an allow list.
Or we could consider listing the environment variables we use for caching, but passing through all except for a deny list.
1. SDK: Pass through everything except deny list + use these for caching
Pros:
Cons:
(We should probably change
SDKROOT
toDARTSDKROOT
intest.py
and it's users.)Even when implementing the env-filtering in the Dart and Flutter SDK, we should probably make the deny list (or allow list) part of this package, so that this package contains the whole protocol spec.
2. SDK: Pass through only an allow list + use these for caching
Pros:
Cons:
3. SDK: Pass through everything except for deny list + use allowlist for caching
Pros:
Cons:
4.
package:native_assets_cli
solutionAlways just invoke
build.dart
with all environment variables, but add theallowList
ordenyList
topackage:native_assets_cli
.There would be an
.environment
getter onBuildConfig
likely.Pro:
allowList
/denyList
does not require Dart SDK / Flutter updates.Isolate.spawnUri
to run build rather thanProcess.run
(but that would mean noexit(int)
calling in anybuild.dart
script, and tougher handling of unhandled exceptions etc.) [native_assets_cli] Protocol exit codes / unhandled exceptions #33Con:
build.dart
requires explicitly passingenvironment
andincludeParentEnvironment: false
.native_assets_cli
rolls into the Dart SDK.Maybe there are solutions I haven't thought about yet. I'm open to suggestions. (Otherwise I might lean towards solution 1 or 2.)
internal design doc with some initial discussion about the env vars
cc @mkustermann @liamappelbe @HosseinYousefi
The text was updated successfully, but these errors were encountered: