flutter335: fix android build

The Flutter tools Gradle patch is still required with flutter335. The following patch is a rebased copy of the one for flutter332.

authored by

birros and committed by
GitHub
ba029e09 667083f5

+220
+220
pkgs/development/compilers/flutter/versions/3_35/patches/gradle-flutter-tools-wrapper.patch
··· 1 + This patch introduces an intermediate Gradle build step to alter the behavior 2 + of flutter_tools' Gradle project, specifically moving the creation of `build` 3 + and `.gradle` directories from within the Nix Store to somewhere in `$HOME/.cache/flutter/nix-flutter-tools-gradle/$engineShortRev`. 4 + 5 + Without this patch, flutter_tools' Gradle project tries to generate `build` and `.gradle` 6 + directories within the Nix Store. Resulting in read-only errors when trying to build a 7 + Flutter Android app at runtime. 8 + 9 + This patch takes advantage of the fact settings.gradle takes priority over settings.gradle.kts to build the intermediate Gradle project 10 + when a Flutter app runs `includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")` 11 + 12 + `rootProject.buildFileName = "/dev/null"` so that the intermediate project doesn't use `build.gradle.kts` that's in the same directory. 13 + 14 + The intermediate project makes a `settings.gradle` file in `$HOME/.cache/flutter/nix-flutter-tools-gradle/<short engine rev>/` and `includeBuild`s it. 15 + This Gradle project will build the actual `packages/flutter_tools/gradle` project by setting 16 + `rootProject.projectDir = new File("$settingsDir")` and `apply from: new File("$settingsDir/settings.gradle.kts")`. 17 + 18 + To move `build` to `$HOME/.cache/flutter/nix-flutter-tools-gradle/<short engine rev>/`, we need to set `buildDirectory`. 19 + To move `.gradle` as well, the `--project-cache-dir` argument must be passed to the Gradle wrapper. 20 + Changing the `GradleUtils.getExecutable` function signature is a delibarate choice, to ensure that no new unpatched usages slip in. 21 + --- /dev/null 22 + +++ b/packages/flutter_tools/gradle/settings.gradle 23 + @@ -0,0 +1,19 @@ 24 + +rootProject.buildFileName = "/dev/null" 25 + + 26 + +def engineShortRev = (new File("$settingsDir/../../../bin/internal/engine.version")).text.take(10) 27 + +def dir = new File("$System.env.HOME/.cache/flutter/nix-flutter-tools-gradle/$engineShortRev") 28 + +dir.mkdirs() 29 + +def file = new File(dir, "settings.gradle") 30 + + 31 + +file.text = """ 32 + +rootProject.projectDir = new File("$settingsDir") 33 + +apply from: new File("$settingsDir/settings.gradle.kts") 34 + + 35 + +gradle.allprojects { project -> 36 + + project.beforeEvaluate { 37 + + project.layout.buildDirectory = new File("$dir/build") 38 + + } 39 + +} 40 + +""" 41 + + 42 + +includeBuild(dir) 43 + --- a/packages/flutter_tools/gradle/build.gradle.kts 44 + +++ b/packages/flutter_tools/gradle/build.gradle.kts 45 + @@ -4,6 +4,11 @@ 46 + 47 + import org.jetbrains.kotlin.gradle.dsl.JvmTarget 48 + 49 + +// While flutter_tools runs Gradle with a --project-cache-dir, this startParameter 50 + +// is not passed correctly to the Kotlin Gradle plugin for some reason, and so 51 + +// must be set here as well. 52 + +gradle.startParameter.projectCacheDir = layout.buildDirectory.dir("cache").get().asFile 53 + + 54 + plugins { 55 + `java-gradle-plugin` 56 + groovy 57 + --- a/packages/flutter_tools/lib/src/android/gradle.dart 58 + +++ b/packages/flutter_tools/lib/src/android/gradle.dart 59 + @@ -474,9 +474,9 @@ class AndroidGradleBuilder implements AndroidBuilder { 60 + // from the local.properties file. 61 + updateLocalProperties(project: project, buildInfo: androidBuildInfo.buildInfo); 62 + 63 + - final options = <String>[]; 64 + - 65 + - final String gradleExecutablePath = _gradleUtils.getExecutable(project); 66 + + final [String gradleExecutablePath, ...List<String> options] = _gradleUtils.getExecutable( 67 + + project, 68 + + ); 69 + 70 + // All automatically created files should exist. 71 + if (configOnly) { 72 + @@ -797,7 +797,7 @@ class AndroidGradleBuilder implements AndroidBuilder { 73 + 'aar_init_script.gradle', 74 + ); 75 + final command = <String>[ 76 + - _gradleUtils.getExecutable(project), 77 + + ..._gradleUtils.getExecutable(project), 78 + '-I=$initScript', 79 + '-Pflutter-root=$flutterRoot', 80 + '-Poutput-dir=${outputDirectory.path}', 81 + @@ -912,6 +912,10 @@ class AndroidGradleBuilder implements AndroidBuilder { 82 + final results = <String>[]; 83 + 84 + try { 85 + + final [String gradleExecutablePath, ...List<String> options] = _gradleUtils.getExecutable( 86 + + project, 87 + + ); 88 + + 89 + exitCode = await _runGradleTask( 90 + _kBuildVariantTaskName, 91 + preRunTask: () { 92 + @@ -927,10 +931,10 @@ class AndroidGradleBuilder implements AndroidBuilder { 93 + ), 94 + ); 95 + }, 96 + - options: const <String>['-q'], 97 + + options: <String>[...options, '-q'], 98 + project: project, 99 + localGradleErrors: gradleErrors, 100 + - gradleExecutablePath: _gradleUtils.getExecutable(project), 101 + + gradleExecutablePath: gradleExecutablePath, 102 + outputParser: (String line) { 103 + if (_kBuildVariantRegex.firstMatch(line) case final RegExpMatch match) { 104 + results.add(match.namedGroup(_kBuildVariantRegexGroupName)!); 105 + @@ -964,6 +968,10 @@ class AndroidGradleBuilder implements AndroidBuilder { 106 + late Stopwatch sw; 107 + var exitCode = 1; 108 + try { 109 + + final [String gradleExecutablePath, ...List<String> options] = _gradleUtils.getExecutable( 110 + + project, 111 + + ); 112 + + 113 + exitCode = await _runGradleTask( 114 + taskName, 115 + preRunTask: () { 116 + @@ -979,10 +987,10 @@ class AndroidGradleBuilder implements AndroidBuilder { 117 + ), 118 + ); 119 + }, 120 + - options: <String>['-q', '-PoutputPath=$outputPath'], 121 + + options: <String>[...options, '-q', '-PoutputPath=$outputPath'], 122 + project: project, 123 + localGradleErrors: gradleErrors, 124 + - gradleExecutablePath: _gradleUtils.getExecutable(project), 125 + + gradleExecutablePath: gradleExecutablePath, 126 + ); 127 + } on Error catch (error) { 128 + _logger.printError(error.toString()); 129 + --- a/packages/flutter_tools/lib/src/android/gradle_errors.dart 130 + +++ b/packages/flutter_tools/lib/src/android/gradle_errors.dart 131 + @@ -228,7 +228,12 @@ final flavorUndefinedHandler = GradleHandledError( 132 + }, 133 + handler: ({required String line, required FlutterProject project, required bool usesAndroidX}) async { 134 + final RunResult tasksRunResult = await globals.processUtils.run( 135 + - <String>[globals.gradleUtils!.getExecutable(project), 'app:tasks', '--all', '--console=auto'], 136 + + <String>[ 137 + + ...globals.gradleUtils!.getExecutable(project), 138 + + 'app:tasks', 139 + + '--all', 140 + + '--console=auto', 141 + + ], 142 + throwOnError: true, 143 + workingDirectory: project.android.hostAppGradleRoot.path, 144 + environment: globals.java?.environment, 145 + --- a/packages/flutter_tools/lib/src/android/gradle_utils.dart 146 + +++ b/packages/flutter_tools/lib/src/android/gradle_utils.dart 147 + @@ -3,6 +3,7 @@ 148 + // found in the LICENSE file. 149 + 150 + import 'package:meta/meta.dart'; 151 + +import 'package:path/path.dart'; 152 + import 'package:process/process.dart'; 153 + import 'package:unified_analytics/unified_analytics.dart'; 154 + 155 + @@ -197,9 +198,29 @@ class GradleUtils { 156 + final Logger _logger; 157 + final OperatingSystemUtils _operatingSystemUtils; 158 + 159 + + List<String> get _requiredArguments { 160 + + final String cacheDir = join( 161 + + switch (globals.platform.environment['XDG_CACHE_HOME']) { 162 + + final String cacheHome => cacheHome, 163 + + _ => join( 164 + + globals.fsUtils.homeDirPath ?? throwToolExit('No cache directory has been specified.'), 165 + + '.cache', 166 + + ), 167 + + }, 168 + + 'flutter', 169 + + 'nix-flutter-tools-gradle', 170 + + globals.flutterVersion.engineRevision.substring(0, 10), 171 + + ); 172 + + 173 + + return <String>[ 174 + + '--project-cache-dir=${join(cacheDir, 'cache')}', 175 + + '-Pkotlin.project.persistent.dir=${join(cacheDir, 'kotlin')}', 176 + + ]; 177 + + } 178 + + 179 + /// Gets the Gradle executable path and prepares the Gradle project. 180 + /// This is the `gradlew` or `gradlew.bat` script in the `android/` directory. 181 + - String getExecutable(FlutterProject project) { 182 + + List<String> getExecutable(FlutterProject project) { 183 + final Directory androidDir = project.android.hostAppGradleRoot; 184 + injectGradleWrapperIfNeeded(androidDir); 185 + 186 + @@ -210,7 +231,7 @@ class GradleUtils { 187 + // If the Gradle executable doesn't have execute permission, 188 + // then attempt to set it. 189 + _operatingSystemUtils.makeExecutable(gradle); 190 + - return gradle.absolute.path; 191 + + return <String>[gradle.absolute.path, ..._requiredArguments]; 192 + } 193 + throwToolExit( 194 + 'Unable to locate gradlew script. Please check that ${gradle.path} ' 195 + --- a/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart 196 + +++ b/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart 197 + @@ -2606,8 +2606,8 @@ Gradle Crashed 198 + 199 + class FakeGradleUtils extends Fake implements GradleUtils { 200 + @override 201 + - String getExecutable(FlutterProject project) { 202 + - return 'gradlew'; 203 + + List<String> getExecutable(FlutterProject project) { 204 + + return const <String>['gradlew']; 205 + } 206 + } 207 + 208 + --- a/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart 209 + +++ b/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart 210 + @@ -1633,8 +1633,8 @@ Platform fakePlatform(String name) { 211 + 212 + class FakeGradleUtils extends Fake implements GradleUtils { 213 + @override 214 + - String getExecutable(FlutterProject project) { 215 + - return 'gradlew'; 216 + + List<String> getExecutable(FlutterProject project) { 217 + + return const <String>['gradlew']; 218 + } 219 + } 220 +