blob: c3356a2a28156b3ec406869957574965071c4711 [file] [log] [blame] [edit]
// Copyright 2014 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.
// This script generates `android/build.gradle` for each directory specify in the stdin.
// Then it generate the lockfiles for each Gradle project.
// To regenerate these files, run `find . -type d -name 'android' | dart dev/tools/bin/generate_gradle_lockfiles.dart`
import 'dart:io';
import 'package:file/file.dart';
import 'package:file/local.dart';
import 'package:path/path.dart' as path;
void main(List<String> arguments) {
print(
"Usage: find . -type d -name 'android' | dart dev/tools/bin/generate_gradle_lockfiles.dart\n"
'If you would rather enter the files manually, just run `dart dev/tools/bin/generate_gradle_lockfiles.dart`,\n'
"enter the absolute paths to the app's android directory, then press CTRL-D.\n"
);
const FileSystem fileSystem = LocalFileSystem();
final List<String> androidDirectories = getFilesFromStdin();
for (final String androidDirectoryPath in androidDirectories) {
final Directory androidDirectory = fileSystem.directory(path.normalize(androidDirectoryPath));
if (!androidDirectory.existsSync()) {
throw '$androidDirectory does not exist';
}
final File rootBuildGradle = androidDirectory.childFile('build.gradle');
if (!rootBuildGradle.existsSync()) {
print('${rootBuildGradle.path} does not exist - skipping');
continue;
}
final File settingsGradle = androidDirectory.childFile('settings.gradle');
if (!settingsGradle.existsSync()) {
print('${settingsGradle.path} does not exist - skipping');
continue;
}
if (settingsGradle.readAsStringSync().contains('include_flutter.groovy')) {
print('${settingsGradle.path} add to app - skipping');
continue;
}
if (!androidDirectory.childDirectory('app').existsSync()) {
print('${rootBuildGradle.path} is not an app - skipping');
continue;
}
if (!androidDirectory.parent.childFile('pubspec.yaml').existsSync()) {
print('${rootBuildGradle.path} no pubspec.yaml in parent directory - skipping');
continue;
}
if (androidDirectory.parent.childFile('pubspec.yaml').readAsStringSync().contains('deferred-components')) {
print('${rootBuildGradle.path} uses deferred components - skipping');
continue;
}
if (!androidDirectory.parent
.childDirectory('lib')
.childFile('main.dart')
.existsSync()) {
print('${rootBuildGradle.path} no main.dart under lib - skipping');
continue;
}
print('Processing ${androidDirectory.path}');
try {
androidDirectory.childFile('buildscript-gradle.lockfile').deleteSync();
} on FileSystemException {
// noop
}
rootBuildGradle.writeAsStringSync(rootGradleFileContent);
settingsGradle.writeAsStringSync(settingGradleFile);
final String appDirectory = androidDirectory.parent.absolute.path;
// Fetch pub dependencies.
exec('flutter', <String>['pub', 'get'], workingDirectory: appDirectory);
// Verify that the Gradlew wrapper exists.
final File gradleWrapper = androidDirectory.childFile('gradlew');
// Generate Gradle wrapper if it doesn't exists.
// This logic is embedded within the Flutter tool.
// To generate the wrapper, build a flavor that doesn't exist.
if (!gradleWrapper.existsSync()) {
Process.runSync(
'flutter',
<String>['build', 'apk', '--debug', '--flavor=does-not-exist'],
workingDirectory: appDirectory,
);
}
// Generate lock files.
exec(
gradleWrapper.absolute.path,
<String>[':generateLockfiles'],
workingDirectory: androidDirectory.absolute.path,
);
print('Processed');
}
}
List<String> getFilesFromStdin() {
final List<String> files = <String>[];
while (true) {
final String? file = stdin.readLineSync();
if (file == null) {
break;
}
files.add(file);
}
return files;
}
void exec(
String cmd,
List<String> args, {
String? workingDirectory,
}) {
final ProcessResult result = Process.runSync(cmd, args, workingDirectory: workingDirectory);
if (result.exitCode != 0) {
throw ProcessException(
cmd, args, '${result.stdout}${result.stderr}', result.exitCode);
}
}
const String rootGradleFileContent = r'''
// Copyright 2014 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.
// This file is auto generated.
// To update all the build.gradle files in the Flutter repo,
// See dev/tools/bin/generate_gradle_lockfiles.dart.
buildscript {
ext.kotlin_version = '1.7.10'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.2.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
configurations.classpath {
resolutionStrategy.activateDependencyLocking()
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
dependencyLocking {
ignoredDependencies.add('io.flutter:*')
lockFile = file("${rootProject.projectDir}/project-${project.name}.lockfile")
if (!project.hasProperty('local-engine-repo')) {
lockAllConfigurations()
}
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
''';
const String settingGradleFile = r'''
// Copyright 2014 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.
// This file is auto generated.
// To update all the settings.gradle files in the Flutter repo,
// See dev/tools/bin/generate_gradle_lockfiles.dart.
include ':app'
enableFeaturePreview('ONE_LOCKFILE_PER_PROJECT')
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
def properties = new Properties()
assert localPropertiesFile.exists()
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
''';