[Reland] Gradle Lockfile workaround (#178485)

Create a workaround for generating gradle lock files. When the ignore
files exist, gradle locking will be disabled. This will allow deps for
the embedder to be checked in, and then in a follow-up PR the lockfiles
can correctly be updated and the ignore files can be deleted.

Note: This does NOT include the addition of the new exifinterface dep
for the Android embedder.

Fixes: https://github.com/flutter/flutter/issues/177066

## 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 `///`).
- [X] 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.
This commit is contained in:
Matt Boetger 2025-11-13 15:25:13 -08:00 committed by GitHub
parent 33a30cb318
commit 91176cc349
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 108 additions and 36 deletions

View File

@ -23,7 +23,8 @@ subprojects {
dependencyLocking {
ignoredDependencies.add('io.flutter:*')
lockFile = file("${rootProject.projectDir}/project-${project.name}.lockfile")
if (!project.hasProperty('local-engine-repo')) {
def ignoreFile = file("${rootProject.projectDir}/.ignore-locking.md")
if (!ignoreFile.exists() && !project.hasProperty('local-engine-repo')) {
lockAllConfigurations()
}
}

View File

@ -23,7 +23,8 @@ subprojects {
dependencyLocking {
ignoredDependencies.add('io.flutter:*')
lockFile = file("${rootProject.projectDir}/project-${project.name}.lockfile")
if (!project.hasProperty('local-engine-repo')) {
def ignoreFile = file("${rootProject.projectDir}/.ignore-locking.md")
if (!ignoreFile.exists() && !project.hasProperty('local-engine-repo')) {
lockAllConfigurations()
}
}

View File

@ -23,7 +23,8 @@ subprojects {
dependencyLocking {
ignoredDependencies.add('io.flutter:*')
lockFile = file("${rootProject.projectDir}/project-${project.name}.lockfile")
if (!project.hasProperty('local-engine-repo')) {
def ignoreFile = file("${rootProject.projectDir}/.ignore-locking.md")
if (!ignoreFile.exists() && !project.hasProperty('local-engine-repo')) {
lockAllConfigurations()
}
}

View File

@ -23,7 +23,8 @@ subprojects {
dependencyLocking {
ignoredDependencies.add('io.flutter:*')
lockFile = file("${rootProject.projectDir}/project-${project.name}.lockfile")
if (!project.hasProperty('local-engine-repo')) {
def ignoreFile = file("${rootProject.projectDir}/.ignore-locking.md")
if (!ignoreFile.exists() && !project.hasProperty('local-engine-repo')) {
lockAllConfigurations()
}
}

View File

@ -23,7 +23,8 @@ subprojects {
dependencyLocking {
ignoredDependencies.add('io.flutter:*')
lockFile = file("${rootProject.projectDir}/project-${project.name}.lockfile")
if (!project.hasProperty('local-engine-repo')) {
def ignoreFile = file("${rootProject.projectDir}/.ignore-locking.md")
if (!ignoreFile.exists() && !project.hasProperty('local-engine-repo')) {
lockAllConfigurations()
}
}

View File

@ -23,7 +23,8 @@ subprojects {
dependencyLocking {
ignoredDependencies.add('io.flutter:*')
lockFile = file("${rootProject.projectDir}/project-${project.name}.lockfile")
if (!project.hasProperty('local-engine-repo')) {
def ignoreFile = file("${rootProject.projectDir}/.ignore-locking.md")
if (!ignoreFile.exists() && !project.hasProperty('local-engine-repo')) {
lockAllConfigurations()
}
}

View File

@ -23,7 +23,8 @@ subprojects {
dependencyLocking {
ignoredDependencies.add('io.flutter:*')
lockFile = file("${rootProject.projectDir}/project-${project.name}.lockfile")
if (!project.hasProperty('local-engine-repo')) {
def ignoreFile = file("${rootProject.projectDir}/.ignore-locking.md")
if (!ignoreFile.exists() && !project.hasProperty('local-engine-repo')) {
lockAllConfigurations()
}
}

View File

@ -23,7 +23,8 @@ subprojects {
dependencyLocking {
ignoredDependencies.add('io.flutter:*')
lockFile = file("${rootProject.projectDir}/project-${project.name}.lockfile")
if (!project.hasProperty('local-engine-repo')) {
def ignoreFile = file("${rootProject.projectDir}/.ignore-locking.md")
if (!ignoreFile.exists() && !project.hasProperty('local-engine-repo')) {
lockAllConfigurations()
}
}

View File

@ -23,7 +23,8 @@ subprojects {
dependencyLocking {
ignoredDependencies.add('io.flutter:*')
lockFile = file("${rootProject.projectDir}/project-${project.name}.lockfile")
if (!project.hasProperty('local-engine-repo')) {
def ignoreFile = file("${rootProject.projectDir}/.ignore-locking.md")
if (!ignoreFile.exists() && !project.hasProperty('local-engine-repo')) {
lockAllConfigurations()
}
}

View File

@ -23,7 +23,8 @@ subprojects {
dependencyLocking {
ignoredDependencies.add('io.flutter:*')
lockFile = file("${rootProject.projectDir}/project-${project.name}.lockfile")
if (!project.hasProperty('local-engine-repo')) {
def ignoreFile = file("${rootProject.projectDir}/.ignore-locking.md")
if (!ignoreFile.exists() && !project.hasProperty('local-engine-repo')) {
lockAllConfigurations()
}
}

View File

@ -31,7 +31,8 @@ subprojects {
dependencyLocking {
ignoredDependencies.add("io.flutter:*")
lockFile = file("${rootProject.projectDir}/project-${project.name}.lockfile")
if (!project.hasProperty("local-engine-repo")) {
var ignoreFile = file("${rootProject.projectDir}/.ignore-locking.md")
if (!ignoreFile.exists() && !project.hasProperty("local-engine-repo")) {
lockAllConfigurations()
}
}

View File

@ -23,7 +23,8 @@ subprojects {
dependencyLocking {
ignoredDependencies.add('io.flutter:*')
lockFile = file("${rootProject.projectDir}/project-${project.name}.lockfile")
if (!project.hasProperty('local-engine-repo')) {
def ignoreFile = file("${rootProject.projectDir}/.ignore-locking.md")
if (!ignoreFile.exists() && !project.hasProperty('local-engine-repo')) {
lockAllConfigurations()
}
}

View File

@ -23,7 +23,8 @@ subprojects {
dependencyLocking {
ignoredDependencies.add('io.flutter:*')
lockFile = file("${rootProject.projectDir}/project-${project.name}.lockfile")
if (!project.hasProperty('local-engine-repo')) {
def ignoreFile = file("${rootProject.projectDir}/.ignore-locking.md")
if (!ignoreFile.exists() && !project.hasProperty('local-engine-repo')) {
lockAllConfigurations()
}
}

View File

@ -23,7 +23,8 @@ subprojects {
dependencyLocking {
ignoredDependencies.add('io.flutter:*')
lockFile = file("${rootProject.projectDir}/project-${project.name}.lockfile")
if (!project.hasProperty('local-engine-repo')) {
def ignoreFile = file("${rootProject.projectDir}/.ignore-locking.md")
if (!ignoreFile.exists() && !project.hasProperty('local-engine-repo')) {
lockAllConfigurations()
}
}

View File

@ -23,7 +23,8 @@ subprojects {
dependencyLocking {
ignoredDependencies.add('io.flutter:*')
lockFile = file("${rootProject.projectDir}/project-${project.name}.lockfile")
if (!project.hasProperty('local-engine-repo')) {
def ignoreFile = file("${rootProject.projectDir}/.ignore-locking.md")
if (!ignoreFile.exists() && !project.hasProperty('local-engine-repo')) {
lockAllConfigurations()
}
}

View File

@ -23,7 +23,8 @@ subprojects {
dependencyLocking {
ignoredDependencies.add('io.flutter:*')
lockFile = file("${rootProject.projectDir}/project-${project.name}.lockfile")
if (!project.hasProperty('local-engine-repo')) {
def ignoreFile = file("${rootProject.projectDir}/.ignore-locking.md")
if (!ignoreFile.exists() && !project.hasProperty('local-engine-repo')) {
lockAllConfigurations()
}
}

View File

@ -23,7 +23,8 @@ subprojects {
dependencyLocking {
ignoredDependencies.add('io.flutter:*')
lockFile = file("${rootProject.projectDir}/project-${project.name}.lockfile")
if (!project.hasProperty('local-engine-repo')) {
def ignoreFile = file("${rootProject.projectDir}/.ignore-locking.md")
if (!ignoreFile.exists() && !project.hasProperty('local-engine-repo')) {
lockAllConfigurations()
}
}

View File

@ -23,7 +23,8 @@ subprojects {
dependencyLocking {
ignoredDependencies.add('io.flutter:*')
lockFile = file("${rootProject.projectDir}/project-${project.name}.lockfile")
if (!project.hasProperty('local-engine-repo')) {
def ignoreFile = file("${rootProject.projectDir}/.ignore-locking.md")
if (!ignoreFile.exists() && !project.hasProperty('local-engine-repo')) {
lockAllConfigurations()
}
}

View File

@ -26,6 +26,8 @@ void main(List<String> arguments) {
'defined at dev/tools/bin/config/lockfile_exclusion.yaml.\n'
'To disable this behavior, run with `--no-exclusion`.\n';
const String ignoreFilename = '.ignore-locking.md';
final ArgParser argParser = ArgParser()
..addFlag(
'gradle-generation',
@ -37,7 +39,12 @@ void main(List<String> arguments) {
help:
'Run the script using the config file at ./configs/lockfile_exclusion.yaml to skip the specified subdirectories.',
defaultsTo: true,
);
)
..addOption(
'ignore-locking',
help: 'Reason to disable gradle dependency locking. A reason must be given.',
)
..addFlag('stop-ignoring', help: 'Delete the ignore lockfile if it exists');
ArgResults args;
try {
@ -56,6 +63,27 @@ void main(List<String> arguments) {
// Skip android subdirectories specified in the ./config/lockfile_exclusion.yaml file.
final bool useExclusion = (args['exclusion'] as bool?) ?? true;
final bool ignoreLocking = args['ignore-locking'] != null;
final String ignoreReason = (args['ignore-locking'] as String?) ?? '';
// This is an explicit flag that insures the ignore
// lockfile isn't deleted unless specified. This should prevent
// automated scripts from deleting the file when they shouldn't.
final bool stopIgnoring = (args['stop-ignoring'] as bool?) ?? false;
if (ignoreLocking && ignoreReason.isEmpty) {
stderr.writeln('A reason must be provided for --ignore-locking.');
stderr.writeln(usageMessage);
exit(1);
}
if (ignoreLocking && stopIgnoring) {
stderr.writeln(
'Both --ignore-locking and --stop-ignoring cannot be used on the same invocation.',
);
stderr.writeln(usageMessage);
exit(1);
}
const FileSystem fileSystem = LocalFileSystem();
final Directory repoRoot = (() {
@ -164,6 +192,17 @@ void main(List<String> arguments) {
print('Processing ${androidDirectory.path}');
final File ignoreFile = androidDirectory.childFile(ignoreFilename);
if (ignoreLocking) {
print('Writing ignore file in ${ignoreFile.path}');
ignoreFile.writeAsStringSync(ignoreReason);
// When ignoring locking, we do not want to actually generate
// the lockfiles
continue;
} else if (stopIgnoring && ignoreFile.existsSync()) {
ignoreFile.deleteSync();
}
try {
androidDirectory.childFile('buildscript-gradle.lockfile').deleteSync();
} on FileSystemException {
@ -243,7 +282,8 @@ subprojects {
dependencyLocking {
ignoredDependencies.add('io.flutter:*')
lockFile = file("${rootProject.projectDir}/project-${project.name}.lockfile")
if (!project.hasProperty('local-engine-repo')) {
def ignoreFile = file("${rootProject.projectDir}/.ignore-locking.md")
if (!ignoreFile.exists() && !project.hasProperty('local-engine-repo')) {
lockAllConfigurations()
}
}
@ -336,7 +376,8 @@ subprojects {
dependencyLocking {
ignoredDependencies.add("io.flutter:*")
lockFile = file("${rootProject.projectDir}/project-${project.name}.lockfile")
if (!project.hasProperty("local-engine-repo")) {
var ignoreFile = file("${rootProject.projectDir}/.ignore-locking.md")
if (!ignoreFile.exists() && !project.hasProperty("local-engine-repo")) {
lockAllConfigurations()
}
}

View File

@ -34,11 +34,17 @@ below explain how to fetch the license information for the dependencies.
new tag: `last_updated:"$version_tag"`.
1. Update the GN list `embedding_dependencies_jars` in
`src/flutter/shell/platform/android/BUILD.gn`.
## Updating Gradle Lockfiles in the Framework After Adding Dependencies
If you land a pr that changes the versions of the embedding dependencies,
or adds a new dependency and makes use of it, you will also need to
perform a manual roll of that change to the framework that re-generates
the Gradle lockfiles using the script at
`<framework_repo>/dev/tools/bin/generate_gradle_lockfiles.dart`
(run with the `--no-gradle-generation` and `--no-exclusion` flags).
1. The Gradle lockfiles will need to be updated, but they cannot be
updated in this PR. They will need to be updated in a follow-up
PR. Instead run
`<repo_root>/dev/tools/bin/generate_gradle_lockfiles.dart
--no-gradle-generation --no-exclusion --ignore-locking=Reason: <ISSUE>`.
Replace <ISSUE> with a link to an issue. This will create a
'.ignore-locking.md' file that will disable Grdle locking and allow
tests to pass without locking.
1. Once the initial PR is submitted, you will need to create a follow-up
PR that updates the Gradle lockfiles and deletes the ignore file.
Run
`<repo_root>/dev/tools/bin/generate_gradle_lockfiles.dart
--no-gradle-generation --no-exclusion --stop-ignoring` to delete the
ignore file and update the Gradle lockfiles. Submit this PR as well.

View File

@ -23,7 +23,8 @@ subprojects {
dependencyLocking {
ignoredDependencies.add('io.flutter:*')
lockFile = file("${rootProject.projectDir}/project-${project.name}.lockfile")
if (!project.hasProperty('local-engine-repo')) {
def ignoreFile = file("${rootProject.projectDir}/.ignore-locking.md")
if (!ignoreFile.exists() && !project.hasProperty('local-engine-repo')) {
lockAllConfigurations()
}
}

View File

@ -31,7 +31,8 @@ subprojects {
dependencyLocking {
ignoredDependencies.add("io.flutter:*")
lockFile = file("${rootProject.projectDir}/project-${project.name}.lockfile")
if (!project.hasProperty("local-engine-repo")) {
var ignoreFile = file("${rootProject.projectDir}/.ignore-locking.md")
if (!ignoreFile.exists() && !project.hasProperty("local-engine-repo")) {
lockAllConfigurations()
}
}

View File

@ -23,7 +23,8 @@ subprojects {
dependencyLocking {
ignoredDependencies.add('io.flutter:*')
lockFile = file("${rootProject.projectDir}/project-${project.name}.lockfile")
if (!project.hasProperty('local-engine-repo')) {
def ignoreFile = file("${rootProject.projectDir}/.ignore-locking.md")
if (!ignoreFile.exists() && !project.hasProperty('local-engine-repo')) {
lockAllConfigurations()
}
}

View File

@ -23,7 +23,8 @@ subprojects {
dependencyLocking {
ignoredDependencies.add('io.flutter:*')
lockFile = file("${rootProject.projectDir}/project-${project.name}.lockfile")
if (!project.hasProperty('local-engine-repo')) {
def ignoreFile = file("${rootProject.projectDir}/.ignore-locking.md")
if (!ignoreFile.exists() && !project.hasProperty('local-engine-repo')) {
lockAllConfigurations()
}
}

View File

@ -23,7 +23,8 @@ subprojects {
dependencyLocking {
ignoredDependencies.add('io.flutter:*')
lockFile = file("${rootProject.projectDir}/project-${project.name}.lockfile")
if (!project.hasProperty('local-engine-repo')) {
def ignoreFile = file("${rootProject.projectDir}/.ignore-locking.md")
if (!ignoreFile.exists() && !project.hasProperty('local-engine-repo')) {
lockAllConfigurations()
}
}

View File

@ -23,7 +23,8 @@ subprojects {
dependencyLocking {
ignoredDependencies.add('io.flutter:*')
lockFile = file("${rootProject.projectDir}/project-${project.name}.lockfile")
if (!project.hasProperty('local-engine-repo')) {
def ignoreFile = file("${rootProject.projectDir}/.ignore-locking.md")
if (!ignoreFile.exists() && !project.hasProperty('local-engine-repo')) {
lockAllConfigurations()
}
}

View File

@ -31,7 +31,8 @@ subprojects {
dependencyLocking {
ignoredDependencies.add("io.flutter:*")
lockFile = file("${rootProject.projectDir}/project-${project.name}.lockfile")
if (!project.hasProperty("local-engine-repo")) {
var ignoreFile = file("${rootProject.projectDir}/.ignore-locking.md")
if (!ignoreFile.exists() && !project.hasProperty("local-engine-repo")) {
lockAllConfigurations()
}
}