diff --git a/CHANGELOG.md b/CHANGELOG.md index be26c03..8aebe72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ Change Log Version 1.2.0 *(In Development)* -------------------------------- + * New: SDK Tools will be updated if version is older than defined with sdkManager.minSdkToolsVersion + in build.gradle: + sdkManager { + minSdkToolsVersion '24.3.4' + } * New: Support for the 1.2.x Android plugin. * New: Download r24.2 Android SDK. diff --git a/src/main/groovy/com/jakewharton/sdkmanager/SdkManagerExtension.groovy b/src/main/groovy/com/jakewharton/sdkmanager/SdkManagerExtension.groovy index 7ca8f3b..6f95404 100644 --- a/src/main/groovy/com/jakewharton/sdkmanager/SdkManagerExtension.groovy +++ b/src/main/groovy/com/jakewharton/sdkmanager/SdkManagerExtension.groovy @@ -3,4 +3,5 @@ package com.jakewharton.sdkmanager; class SdkManagerExtension { String emulatorVersion String emulatorArchitecture + String minSdkToolsVersion } diff --git a/src/main/groovy/com/jakewharton/sdkmanager/internal/AndroidCommand.groovy b/src/main/groovy/com/jakewharton/sdkmanager/internal/AndroidCommand.groovy index db5b263..dda0553 100644 --- a/src/main/groovy/com/jakewharton/sdkmanager/internal/AndroidCommand.groovy +++ b/src/main/groovy/com/jakewharton/sdkmanager/internal/AndroidCommand.groovy @@ -66,7 +66,7 @@ interface AndroidCommand { def result = '' output.split('----------').each { - if (it.contains(filter)) { + if (it.contains("\"$filter\"")) { result += it } } diff --git a/src/main/groovy/com/jakewharton/sdkmanager/internal/PackageResolver.groovy b/src/main/groovy/com/jakewharton/sdkmanager/internal/PackageResolver.groovy index 9d60eb3..2a1d592 100644 --- a/src/main/groovy/com/jakewharton/sdkmanager/internal/PackageResolver.groovy +++ b/src/main/groovy/com/jakewharton/sdkmanager/internal/PackageResolver.groovy @@ -17,6 +17,7 @@ import static com.android.SdkConstants.FD_PLATFORMS import static com.android.SdkConstants.FD_ADDONS import static com.android.SdkConstants.FD_PLATFORM_TOOLS import static com.android.SdkConstants.FD_SYSTEM_IMAGES +import static com.android.SdkConstants.FD_TOOLS class PackageResolver { static void resolve(Project project, File sdk) { @@ -59,6 +60,7 @@ class PackageResolver { } def resolve() { + resolveSdkTools() resolveBuildTools() resolvePlatformTools() resolveCompileVersion() @@ -67,6 +69,56 @@ class PackageResolver { resolveEmulator() } + def resolveSdkTools() { + def minSdkToolsVersion = project.sdkManager.minSdkToolsVersion + if (minSdkToolsVersion == null) { + log.debug 'No minSdkToolsVersion defined' + return + } + log.debug "Found minSdkToolsVersion: $minSdkToolsVersion" + + def sdkToolsDir = new File(sdk, FD_TOOLS) + def sdkToolsVersion = getPackageRevision(sdkToolsDir) + log.debug "Found sdkToolsVersion: $sdkToolsVersion" + + def minSdkToolsRevision = FullRevision.parseRevision(minSdkToolsVersion) + def sdkToolsRevision = FullRevision.parseRevision(sdkToolsVersion) + def needsDownload = sdkToolsRevision < minSdkToolsRevision + + if (!needsDownload) { + log.debug "SDK tools are up to date." + return + } + + def sdkToolsPackage = "tools" + def currentSdkToolsInfo = androidCommand.list sdkToolsPackage + if (currentSdkToolsInfo == null || currentSdkToolsInfo.isEmpty()) { + throw new StopExecutionException('Could not get the current SDK tools revision.') + } + + def matcher = Pattern.compile("revision\\ (.+)").matcher(currentSdkToolsInfo) + if (!matcher.find()) { + throw new StopExecutionException("Could not find the current SDK tools revision." + + " currentSdkToolsInfo: $currentSdkToolsInfo") + } + + def currentSdkToolsVersion = matcher.group(1) + log.debug "currentSdkToolsVersion: $currentSdkToolsVersion" + + def currentSdkToolsRevision = FullRevision.parseRevision(currentSdkToolsVersion) + if (currentSdkToolsRevision < minSdkToolsRevision) { + throw new StopExecutionException("Currently available SDK tools version($currentSdkToolsVersion)" + + " is smaller than defined in minSdkToolsVersion: $minSdkToolsVersion") + } + + log.lifecycle "SDK tools $sdkToolsVersion outdated. Downloading update..." + + def code = androidCommand.update sdkToolsPackage + if (code != 0) { + throw new StopExecutionException("SDK tools download failed with code $code.") + } + } + def resolveBuildTools() { def buildToolsRevision = project.android.buildToolsRevision log.debug "Build tools version: $buildToolsRevision" @@ -223,21 +275,7 @@ class PackageResolver { needsDownload = true log.lifecycle "Emulator $emulatorVersion $emulatorArchitecture missing. Downloading..." } else { - def emulatorPropertiesFile = new File(emulatorDir, 'source.properties') - if (!emulatorPropertiesFile.canRead()) { - emulatorPropertiesFile = new File(alternativeEmulatorDir, 'source.properties') - if (!emulatorPropertiesFile.canRead()) { - throw new StopExecutionException('Could not read ' + emulatorPropertiesFile.absolutePath) - } - } - - def emulatorProperties = new Properties() - emulatorProperties.load(new FileInputStream(emulatorPropertiesFile)) - def emulatorRevision = emulatorProperties.getProperty('Pkg.Revision') - if (emulatorRevision == null) { - throw new StopExecutionException('Could not get the installed emulator revision for ' + - emulatorPackage) - } + def emulatorRevision = getPackageRevision(emulatorDir, alternativeEmulatorDir) def currentEmulatorInfo = androidCommand.list emulatorPackage if (currentEmulatorInfo == null || currentEmulatorInfo.isEmpty()) { @@ -266,6 +304,24 @@ class PackageResolver { } } + def getPackageRevision(File[] packageDirs) { + def propertiesFileName = 'source.properties' + def propertiesFile = packageDirs.collect { new File(it, propertiesFileName) }.find { it.canRead() } + if (propertiesFile == null) { + throw new StopExecutionException("Could not read '$propertiesFileName' from: $packageDirs") + } + + def properties = new Properties() + properties.load(new FileInputStream(propertiesFile)) + def revision = properties.getProperty('Pkg.Revision') + if (revision == null) { + throw new StopExecutionException("Could not read the revision from: ${propertiesFile.absolutePath}") + } + + log.debug "Found revision for package ${propertiesFile.absolutePath}: $revision" + return revision + } + def findDependenciesWithGroup(String group) { def deps = [] for (Configuration configuration : project.configurations) { diff --git a/src/test/fixtures/outdated-sdk-tools/.android-sdk/tools/source.properties b/src/test/fixtures/outdated-sdk-tools/.android-sdk/tools/source.properties new file mode 100644 index 0000000..2b262bc --- /dev/null +++ b/src/test/fixtures/outdated-sdk-tools/.android-sdk/tools/source.properties @@ -0,0 +1,8 @@ +### Android Tool: Source of this archive. +#Thu Sep 24 18:29:52 EEST 2015 +Archive.HostOs=macosx +Pkg.License=To get started with the Android SDK, you must agree to the following terms and conditions.\n +Pkg.LicenseRef=android-sdk-license +Pkg.Revision=22.6 +Pkg.SourceUrl=https\://dl-ssl.google.com/android/repository/repository-10.xml +Platform.MinPlatformToolsRev=20 diff --git a/src/test/fixtures/outdated-sdk-tools/project/src/main/AndroidManifest.xml b/src/test/fixtures/outdated-sdk-tools/project/src/main/AndroidManifest.xml new file mode 100644 index 0000000..ef0e03b --- /dev/null +++ b/src/test/fixtures/outdated-sdk-tools/project/src/main/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + diff --git a/src/test/fixtures/up-to-date-sdk-tools/.android-sdk/tools/source.properties b/src/test/fixtures/up-to-date-sdk-tools/.android-sdk/tools/source.properties new file mode 100644 index 0000000..d7bf894 --- /dev/null +++ b/src/test/fixtures/up-to-date-sdk-tools/.android-sdk/tools/source.properties @@ -0,0 +1,8 @@ +### Android Tool: Source of this archive. +#Thu Sep 24 18:29:52 EEST 2015 +Archive.HostOs=macosx +Pkg.License=To get started with the Android SDK, you must agree to the following terms and conditions.\n +Pkg.LicenseRef=android-sdk-license +Pkg.Revision=24.3.4 +Pkg.SourceUrl=https\://dl-ssl.google.com/android/repository/repository-10.xml +Platform.MinPlatformToolsRev=20 diff --git a/src/test/fixtures/up-to-date-sdk-tools/project/src/main/AndroidManifest.xml b/src/test/fixtures/up-to-date-sdk-tools/project/src/main/AndroidManifest.xml new file mode 100644 index 0000000..ef0e03b --- /dev/null +++ b/src/test/fixtures/up-to-date-sdk-tools/project/src/main/AndroidManifest.xml @@ -0,0 +1,8 @@ + + + diff --git a/src/test/groovy/com/jakewharton/sdkmanager/internal/PackageResolverTest.groovy b/src/test/groovy/com/jakewharton/sdkmanager/internal/PackageResolverTest.groovy index fc0c6e5..6557472 100644 --- a/src/test/groovy/com/jakewharton/sdkmanager/internal/PackageResolverTest.groovy +++ b/src/test/groovy/com/jakewharton/sdkmanager/internal/PackageResolverTest.groovy @@ -5,6 +5,7 @@ import com.jakewharton.sdkmanager.SdkManagerExtension import com.jakewharton.sdkmanager.TemporaryFixture import com.jakewharton.sdkmanager.util.RecordingAndroidCommand import org.gradle.api.Project +import org.gradle.api.tasks.StopExecutionException import org.gradle.testfixtures.ProjectBuilder import org.junit.Before import org.junit.Rule @@ -13,6 +14,7 @@ import org.junit.Test import static com.android.SdkConstants.FN_LOCAL_PROPERTIES import static com.android.SdkConstants.SDK_DIR_PROPERTY import static org.fest.assertions.api.Assertions.assertThat +import static org.fest.assertions.api.Assertions.failBecauseExceptionWasNotThrown class PackageResolverTest { @Rule public TemporaryFixture fixture = new TemporaryFixture(); @@ -339,4 +341,48 @@ class PackageResolverTest { packageResolver.resolveEmulator() assertThat(androidCommand).contains('update sys-img-armeabi-v7a-android-19') } + + @FixtureName("up-to-date-sdk-tools") + @Test public void upToDateSdkToolsRecognized() { + project.apply plugin: 'com.android.application' + project.extensions.create("sdkManager", SdkManagerExtension) + project.sdkManager { + minSdkToolsVersion '24.3.4' + } + + packageResolver.resolveSdkTools() + assertThat(androidCommand).doesNotContain('update tools') + } + + @FixtureName("outdated-sdk-tools") + @Test public void outdatedSdkToolsDownloaded() { + project.apply plugin: 'com.android.application' + project.extensions.create("sdkManager", SdkManagerExtension) + project.sdkManager { + minSdkToolsVersion '24.3.4' + } + + packageResolver.resolveSdkTools() + assertThat(androidCommand).contains('update tools') + } + + @FixtureName("up-to-date-sdk-tools") + @Test public void sdkToolsUnavailable() { + def tooBigMinSdkToolsVersion = '100500' + + project.apply plugin: 'com.android.application' + project.extensions.create("sdkManager", SdkManagerExtension) + project.sdkManager { + minSdkToolsVersion tooBigMinSdkToolsVersion + } + + try { + packageResolver.resolveSdkTools() + failBecauseExceptionWasNotThrown(StopExecutionException.class); + } catch (Exception e) { + assertThat(e) + .isInstanceOf(StopExecutionException.class) + .hasMessageEndingWith(tooBigMinSdkToolsVersion) + } + } } diff --git a/src/test/groovy/com/jakewharton/sdkmanager/util/RecordingAndroidCommand.groovy b/src/test/groovy/com/jakewharton/sdkmanager/util/RecordingAndroidCommand.groovy index ffdb4d5..d0f47df 100644 --- a/src/test/groovy/com/jakewharton/sdkmanager/util/RecordingAndroidCommand.groovy +++ b/src/test/groovy/com/jakewharton/sdkmanager/util/RecordingAndroidCommand.groovy @@ -16,10 +16,13 @@ final class RecordingAndroidCommand extends ArrayList implements Android @Override String list(String filter) { add("list -a -e" as String) - return "id: 55 or \"sys-img-armeabi-v7a-android-19\"\n" + - " Type: SystemImage\n" + - " Desc: Android SDK Platform 4.4.2\n" + - " Revision 2\n" + - " Requires SDK Platform Android API 19\n" + return "id: 1 or \"tools\"\n" + + " Type: Tool\n" + + " Desc: Android SDK Tools, revision 24.3.4\n" + + "id: 55 or \"sys-img-armeabi-v7a-android-19\"\n" + + " Type: SystemImage\n" + + " Desc: Android SDK Platform 4.4.2\n" + + " Revision 2\n" + + " Requires SDK Platform Android API 19\n" } }