mirror of
https://github.com/flutter/flutter
synced 2024-10-13 03:32:55 +00:00
Add missing files in the Gradle wrapper directory (#39145)
This commit is contained in:
parent
ddd31bcee7
commit
4a1c62c28b
|
@ -268,13 +268,10 @@ String _locateGradlewExecutable(Directory directory) {
|
|||
final File gradle = directory.childFile(
|
||||
platform.isWindows ? 'gradlew.bat' : 'gradlew',
|
||||
);
|
||||
|
||||
if (gradle.existsSync()) {
|
||||
os.makeExecutable(gradle);
|
||||
return gradle.absolute.path;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<String> _ensureGradle(FlutterProject project) async {
|
||||
|
@ -286,12 +283,12 @@ Future<String> _ensureGradle(FlutterProject project) async {
|
|||
// of validating the Gradle executable. This may take several seconds.
|
||||
Future<String> _initializeGradle(FlutterProject project) async {
|
||||
final Directory android = project.android.hostAppGradleRoot;
|
||||
final Status status = logger.startProgress('Initializing gradle...', timeout: timeoutConfiguration.slowOperation);
|
||||
String gradle = _locateGradlewExecutable(android);
|
||||
if (gradle == null) {
|
||||
injectGradleWrapper(android);
|
||||
gradle = _locateGradlewExecutable(android);
|
||||
}
|
||||
final Status status = logger.startProgress('Initializing gradle...',
|
||||
timeout: timeoutConfiguration.slowOperation);
|
||||
|
||||
injectGradleWrapperIfNeeded(android);
|
||||
|
||||
final String gradle = _locateGradlewExecutable(android);
|
||||
if (gradle == null)
|
||||
throwToolExit('Unable to locate gradlew script');
|
||||
printTrace('Using gradle from $gradle.');
|
||||
|
@ -302,11 +299,25 @@ Future<String> _initializeGradle(FlutterProject project) async {
|
|||
return gradle;
|
||||
}
|
||||
|
||||
/// Injects the Gradle wrapper into the specified directory.
|
||||
void injectGradleWrapper(Directory directory) {
|
||||
copyDirectorySync(cache.getArtifactDirectory('gradle_wrapper'), directory);
|
||||
_locateGradlewExecutable(directory);
|
||||
final File propertiesFile = directory.childFile(fs.path.join('gradle', 'wrapper', 'gradle-wrapper.properties'));
|
||||
/// Injects the Gradle wrapper files if any of these files don't exist in [directory].
|
||||
void injectGradleWrapperIfNeeded(Directory directory) {
|
||||
copyDirectorySync(
|
||||
cache.getArtifactDirectory('gradle_wrapper'),
|
||||
directory,
|
||||
shouldCopyFile: (File sourceFile, File destinationFile) {
|
||||
// Don't override the existing files in the project.
|
||||
return !destinationFile.existsSync();
|
||||
},
|
||||
onFileCopied: (File sourceFile, File destinationFile) {
|
||||
final String modes = sourceFile.statSync().modeString();
|
||||
if (modes != null && modes.contains('x')) {
|
||||
os.makeExecutable(destinationFile);
|
||||
}
|
||||
},
|
||||
);
|
||||
// Add the `gradle-wrapper.properties` file if it doesn't exist.
|
||||
final File propertiesFile = directory.childFile(
|
||||
fs.path.join('gradle', 'wrapper', 'gradle-wrapper.properties'));
|
||||
if (!propertiesFile.existsSync()) {
|
||||
final String gradleVersion = getGradleVersionForAndroidPlugin(directory);
|
||||
propertiesFile.writeAsStringSync('''
|
||||
|
|
|
@ -64,11 +64,18 @@ void ensureDirectoryExists(String filePath) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Recursively copies `srcDir` to `destDir`, invoking [onFileCopied] if
|
||||
/// specified for each source/destination file pair.
|
||||
/// Creates `destDir` if needed, then recursively copies `srcDir` to `destDir`,
|
||||
/// invoking [onFileCopied], if specified, for each source/destination file pair.
|
||||
///
|
||||
/// Creates `destDir` if needed.
|
||||
void copyDirectorySync(Directory srcDir, Directory destDir, [ void onFileCopied(File srcFile, File destFile) ]) {
|
||||
/// Skips files if [shouldCopyFile] returns `false`.
|
||||
void copyDirectorySync(
|
||||
Directory srcDir,
|
||||
Directory destDir,
|
||||
{
|
||||
bool shouldCopyFile(File srcFile, File destFile),
|
||||
void onFileCopied(File srcFile, File destFile),
|
||||
}
|
||||
) {
|
||||
if (!srcDir.existsSync())
|
||||
throw Exception('Source directory "${srcDir.path}" does not exist, nothing to copy');
|
||||
|
||||
|
@ -79,11 +86,18 @@ void copyDirectorySync(Directory srcDir, Directory destDir, [ void onFileCopied(
|
|||
final String newPath = destDir.fileSystem.path.join(destDir.path, entity.basename);
|
||||
if (entity is File) {
|
||||
final File newFile = destDir.fileSystem.file(newPath);
|
||||
if (shouldCopyFile != null && !shouldCopyFile(entity, newFile)) {
|
||||
continue;
|
||||
}
|
||||
newFile.writeAsBytesSync(entity.readAsBytesSync());
|
||||
onFileCopied?.call(entity, newFile);
|
||||
} else if (entity is Directory) {
|
||||
copyDirectorySync(
|
||||
entity, destDir.fileSystem.directory(newPath));
|
||||
entity,
|
||||
destDir.fileSystem.directory(newPath),
|
||||
shouldCopyFile: shouldCopyFile,
|
||||
onFileCopied: onFileCopied,
|
||||
);
|
||||
} else {
|
||||
throw Exception('${entity.path} is neither File nor Directory');
|
||||
}
|
||||
|
|
|
@ -628,7 +628,7 @@ To edit platform code in an IDE see https://flutter.dev/developing-packages/#edi
|
|||
copyDirectorySync(
|
||||
cache.getArtifactDirectory('gradle_wrapper'),
|
||||
project.android.hostAppGradleRoot,
|
||||
(File sourceFile, File destinationFile) {
|
||||
onFileCopied: (File sourceFile, File destinationFile) {
|
||||
filesCreated++;
|
||||
final String modes = sourceFile.statSync().modeString();
|
||||
if (modes != null && modes.contains('x')) {
|
||||
|
|
|
@ -580,7 +580,7 @@ class AndroidProject {
|
|||
_overwriteFromTemplate(fs.path.join('module', 'android', 'host_app_common'), _editableHostAppDirectory);
|
||||
_overwriteFromTemplate(fs.path.join('module', 'android', 'host_app_editable'), _editableHostAppDirectory);
|
||||
_overwriteFromTemplate(fs.path.join('module', 'android', 'gradle'), _editableHostAppDirectory);
|
||||
gradle.injectGradleWrapper(_editableHostAppDirectory);
|
||||
gradle.injectGradleWrapperIfNeeded(_editableHostAppDirectory);
|
||||
gradle.writeLocalProperties(_editableHostAppDirectory.childFile('local.properties'));
|
||||
await injectPlugins(parent);
|
||||
}
|
||||
|
@ -593,7 +593,7 @@ class AndroidProject {
|
|||
_deleteIfExistsSync(ephemeralDirectory);
|
||||
_overwriteFromTemplate(fs.path.join('module', 'android', 'library'), ephemeralDirectory);
|
||||
_overwriteFromTemplate(fs.path.join('module', 'android', 'gradle'), ephemeralDirectory);
|
||||
gradle.injectGradleWrapper(ephemeralDirectory);
|
||||
gradle.injectGradleWrapperIfNeeded(ephemeralDirectory);
|
||||
}
|
||||
|
||||
void _overwriteFromTemplate(String path, Directory target) {
|
||||
|
|
|
@ -13,6 +13,7 @@ import 'package:flutter_tools/src/base/logger.dart';
|
|||
import 'package:flutter_tools/src/artifacts.dart';
|
||||
import 'package:flutter_tools/src/base/common.dart';
|
||||
import 'package:flutter_tools/src/base/file_system.dart';
|
||||
import 'package:flutter_tools/src/base/os.dart';
|
||||
import 'package:flutter_tools/src/build_info.dart';
|
||||
import 'package:flutter_tools/src/cache.dart';
|
||||
import 'package:flutter_tools/src/ios/xcodeproj.dart';
|
||||
|
@ -848,6 +849,125 @@ flutter:
|
|||
});
|
||||
});
|
||||
|
||||
group('injectGradleWrapperIfNeeded', () {
|
||||
MemoryFileSystem memoryFileSystem;
|
||||
Directory tempDir;
|
||||
Directory gradleWrapperDirectory;
|
||||
|
||||
setUp(() {
|
||||
memoryFileSystem = MemoryFileSystem();
|
||||
tempDir = memoryFileSystem.systemTempDirectory.createTempSync('artifacts_test.');
|
||||
gradleWrapperDirectory = memoryFileSystem.directory(
|
||||
memoryFileSystem.path.join(tempDir.path, 'bin', 'cache', 'artifacts', 'gradle_wrapper'));
|
||||
gradleWrapperDirectory.createSync(recursive: true);
|
||||
gradleWrapperDirectory
|
||||
.childFile('gradlew')
|
||||
.writeAsStringSync('irrelevant');
|
||||
gradleWrapperDirectory
|
||||
.childDirectory('gradle')
|
||||
.childDirectory('wrapper')
|
||||
.createSync(recursive: true);
|
||||
gradleWrapperDirectory
|
||||
.childDirectory('gradle')
|
||||
.childDirectory('wrapper')
|
||||
.childFile('gradle-wrapper.jar')
|
||||
.writeAsStringSync('irrelevant');
|
||||
});
|
||||
|
||||
testUsingContext('Inject the wrapper when all files are missing', () {
|
||||
final Directory sampleAppAndroid = fs.directory('/sample-app/android');
|
||||
sampleAppAndroid.createSync(recursive: true);
|
||||
|
||||
injectGradleWrapperIfNeeded(sampleAppAndroid);
|
||||
|
||||
expect(sampleAppAndroid.childFile('gradlew').existsSync(), isTrue);
|
||||
|
||||
expect(sampleAppAndroid
|
||||
.childDirectory('gradle')
|
||||
.childDirectory('wrapper')
|
||||
.childFile('gradle-wrapper.jar')
|
||||
.existsSync(), isTrue);
|
||||
|
||||
expect(sampleAppAndroid
|
||||
.childDirectory('gradle')
|
||||
.childDirectory('wrapper')
|
||||
.childFile('gradle-wrapper.properties')
|
||||
.existsSync(), isTrue);
|
||||
|
||||
expect(sampleAppAndroid
|
||||
.childDirectory('gradle')
|
||||
.childDirectory('wrapper')
|
||||
.childFile('gradle-wrapper.properties')
|
||||
.readAsStringSync(),
|
||||
'distributionBase=GRADLE_USER_HOME\n'
|
||||
'distributionPath=wrapper/dists\n'
|
||||
'zipStoreBase=GRADLE_USER_HOME\n'
|
||||
'zipStorePath=wrapper/dists\n'
|
||||
'distributionUrl=https\\://services.gradle.org/distributions/gradle-4.10.2-all.zip\n');
|
||||
}, overrides: <Type, Generator>{
|
||||
Cache: () => Cache(rootOverride: tempDir),
|
||||
FileSystem: () => memoryFileSystem,
|
||||
});
|
||||
|
||||
testUsingContext('Inject the wrapper when some files are missing', () {
|
||||
final Directory sampleAppAndroid = fs.directory('/sample-app/android');
|
||||
sampleAppAndroid.createSync(recursive: true);
|
||||
|
||||
// There's an existing gradlew
|
||||
sampleAppAndroid.childFile('gradlew').writeAsStringSync('existing gradlew');
|
||||
|
||||
injectGradleWrapperIfNeeded(sampleAppAndroid);
|
||||
|
||||
expect(sampleAppAndroid.childFile('gradlew').existsSync(), isTrue);
|
||||
expect(sampleAppAndroid.childFile('gradlew').readAsStringSync(),
|
||||
equals('existing gradlew'));
|
||||
|
||||
expect(sampleAppAndroid
|
||||
.childDirectory('gradle')
|
||||
.childDirectory('wrapper')
|
||||
.childFile('gradle-wrapper.jar')
|
||||
.existsSync(), isTrue);
|
||||
|
||||
expect(sampleAppAndroid
|
||||
.childDirectory('gradle')
|
||||
.childDirectory('wrapper')
|
||||
.childFile('gradle-wrapper.properties')
|
||||
.existsSync(), isTrue);
|
||||
|
||||
expect(sampleAppAndroid
|
||||
.childDirectory('gradle')
|
||||
.childDirectory('wrapper')
|
||||
.childFile('gradle-wrapper.properties')
|
||||
.readAsStringSync(),
|
||||
'distributionBase=GRADLE_USER_HOME\n'
|
||||
'distributionPath=wrapper/dists\n'
|
||||
'zipStoreBase=GRADLE_USER_HOME\n'
|
||||
'zipStorePath=wrapper/dists\n'
|
||||
'distributionUrl=https\\://services.gradle.org/distributions/gradle-4.10.2-all.zip\n');
|
||||
}, overrides: <Type, Generator>{
|
||||
Cache: () => Cache(rootOverride: tempDir),
|
||||
FileSystem: () => memoryFileSystem,
|
||||
});
|
||||
|
||||
testUsingContext('Gives executable permission to gradle', () {
|
||||
final Directory sampleAppAndroid = fs.directory('/sample-app/android');
|
||||
sampleAppAndroid.createSync(recursive: true);
|
||||
|
||||
// Make gradlew in the wrapper executable.
|
||||
os.makeExecutable(gradleWrapperDirectory.childFile('gradlew'));
|
||||
|
||||
injectGradleWrapperIfNeeded(sampleAppAndroid);
|
||||
|
||||
final File gradlew = sampleAppAndroid.childFile('gradlew');
|
||||
expect(gradlew.existsSync(), isTrue);
|
||||
expect(gradlew.statSync().modeString().contains('x'), isTrue);
|
||||
}, overrides: <Type, Generator>{
|
||||
Cache: () => Cache(rootOverride: tempDir),
|
||||
FileSystem: () => memoryFileSystem,
|
||||
OperatingSystemUtils: () => OperatingSystemUtils(),
|
||||
});
|
||||
});
|
||||
|
||||
group('gradle build', () {
|
||||
MockAndroidSdk mockAndroidSdk;
|
||||
MockAndroidStudio mockAndroidStudio;
|
||||
|
@ -855,6 +975,7 @@ flutter:
|
|||
MockProcessManager mockProcessManager;
|
||||
FakePlatform android;
|
||||
FileSystem fs;
|
||||
Cache cache;
|
||||
|
||||
setUp(() {
|
||||
fs = MemoryFileSystem();
|
||||
|
@ -863,6 +984,28 @@ flutter:
|
|||
mockArtifacts = MockLocalEngineArtifacts();
|
||||
mockProcessManager = MockProcessManager();
|
||||
android = fakePlatform('android');
|
||||
|
||||
final Directory tempDir = fs.systemTempDirectory.createTempSync('artifacts_test.');
|
||||
cache = Cache(rootOverride: tempDir);
|
||||
|
||||
final Directory gradleWrapperDirectory = tempDir
|
||||
.childDirectory('bin')
|
||||
.childDirectory('cache')
|
||||
.childDirectory('artifacts')
|
||||
.childDirectory('gradle_wrapper');
|
||||
gradleWrapperDirectory.createSync(recursive: true);
|
||||
gradleWrapperDirectory
|
||||
.childFile('gradlew')
|
||||
.writeAsStringSync('irrelevant');
|
||||
gradleWrapperDirectory
|
||||
.childDirectory('gradle')
|
||||
.childDirectory('wrapper')
|
||||
.createSync(recursive: true);
|
||||
gradleWrapperDirectory
|
||||
.childDirectory('gradle')
|
||||
.childDirectory('wrapper')
|
||||
.childFile('gradle-wrapper.jar')
|
||||
.writeAsStringSync('irrelevant');
|
||||
});
|
||||
|
||||
testUsingContext('build aar uses selected local engine', () async {
|
||||
|
@ -928,6 +1071,7 @@ flutter:
|
|||
AndroidSdk: () => mockAndroidSdk,
|
||||
AndroidStudio: () => mockAndroidStudio,
|
||||
Artifacts: () => mockArtifacts,
|
||||
Cache: () => cache,
|
||||
ProcessManager: () => mockProcessManager,
|
||||
Platform: () => android,
|
||||
FileSystem: () => fs,
|
||||
|
|
|
@ -39,17 +39,20 @@ void main() {
|
|||
AndroidSdk sdk;
|
||||
ProcessManager mockProcessManager;
|
||||
MemoryFileSystem fs;
|
||||
Cache mockCache;
|
||||
File gradle;
|
||||
final Map<Type, Generator> overrides = <Type, Generator>{
|
||||
AndroidSdk: () => sdk,
|
||||
ProcessManager: () => mockProcessManager,
|
||||
FileSystem: () => fs,
|
||||
Cache: () => mockCache,
|
||||
};
|
||||
|
||||
setUp(() async {
|
||||
sdk = MockitoAndroidSdk();
|
||||
mockProcessManager = MockitoProcessManager();
|
||||
fs = MemoryFileSystem();
|
||||
mockCache = MockCache();
|
||||
Cache.flutterRoot = '../..';
|
||||
when(sdk.licensesAvailable).thenReturn(true);
|
||||
when(mockProcessManager.canRun(any)).thenReturn(true);
|
||||
|
@ -100,6 +103,14 @@ void main() {
|
|||
platform.isWindows ? 'gradlew.bat' : 'gradlew',
|
||||
)..createSync(recursive: true);
|
||||
|
||||
final Directory gradleWrapperDir = fs.systemTempDirectory.createTempSync('gradle_wrapper.');
|
||||
when(mockCache.getArtifactDirectory('gradle_wrapper')).thenReturn(gradleWrapperDir);
|
||||
|
||||
fs.directory(gradleWrapperDir.childDirectory('gradle').childDirectory('wrapper'))
|
||||
.createSync(recursive: true);
|
||||
fs.file(fs.path.join(gradleWrapperDir.path, 'gradlew')).writeAsStringSync('irrelevant');
|
||||
fs.file(fs.path.join(gradleWrapperDir.path, 'gradlew.bat')).writeAsStringSync('irrelevant');
|
||||
|
||||
await ApplicationPackageFactory.instance.getPackageForPlatform(
|
||||
TargetPlatform.android_arm,
|
||||
applicationBinary: fs.file('app.apk'),
|
||||
|
@ -606,4 +617,5 @@ const String plistData = '''
|
|||
{"CFBundleIdentifier": "fooBundleId"}
|
||||
''';
|
||||
|
||||
class MockCache extends Mock implements Cache {}
|
||||
class MockOperatingSystemUtils extends Mock implements OperatingSystemUtils { }
|
||||
|
|
|
@ -58,6 +58,29 @@ void main() {
|
|||
// There's still 3 things in the original directory as there were initially.
|
||||
expect(sourceMemoryFs.directory(sourcePath).listSync().length, 3);
|
||||
});
|
||||
|
||||
testUsingContext('Skip files if shouldCopyFile returns false', () {
|
||||
final Directory origin = fs.directory('/origin');
|
||||
origin.createSync();
|
||||
fs.file(fs.path.join('origin', 'a.txt')).writeAsStringSync('irrelevant');
|
||||
fs.directory('/origin/nested').createSync();
|
||||
fs.file(fs.path.join('origin', 'nested', 'a.txt')).writeAsStringSync('irrelevant');
|
||||
fs.file(fs.path.join('origin', 'nested', 'b.txt')).writeAsStringSync('irrelevant');
|
||||
|
||||
final Directory destination = fs.directory('/destination');
|
||||
copyDirectorySync(origin, destination, shouldCopyFile: (File origin, File dest) {
|
||||
return origin.basename == 'b.txt';
|
||||
});
|
||||
|
||||
expect(destination.existsSync(), isTrue);
|
||||
expect(destination.childDirectory('nested').existsSync(), isTrue);
|
||||
expect(destination.childDirectory('nested').childFile('b.txt').existsSync(), isTrue);
|
||||
|
||||
expect(destination.childFile('a.txt').existsSync(), isFalse);
|
||||
expect(destination.childDirectory('nested').childFile('a.txt').existsSync(), isFalse);
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => MemoryFileSystem(),
|
||||
});
|
||||
});
|
||||
|
||||
group('canonicalizePath', () {
|
||||
|
|
Loading…
Reference in a new issue