From 7764caee10ccad561179c50e0e11baafec3b9c8a Mon Sep 17 00:00:00 2001 From: Dmitry Kalita Date: Thu, 24 Sep 2015 19:59:04 +0300 Subject: [PATCH 1/2] SDK Tools will be updated if version is older than defined in sdkManager.minSdkToolsVersion. Fixes issues #43 #14 Now for update Android SDK Tools just define necessary minSdkToolsVersion in your build.gradle, for example: sdkManager { minSdkToolsVersion '24.3.4' } --- CHANGELOG.md | 5 ++ .../sdkmanager/SdkManagerExtension.groovy | 1 + .../sdkmanager/internal/AndroidCommand.groovy | 2 +- .../internal/PackageResolver.groovy | 86 +++++++++++++++---- .../.android-sdk/tools/source.properties | 8 ++ .../project/src/main/AndroidManifest.xml | 8 ++ .../.android-sdk/tools/source.properties | 8 ++ .../project/src/main/AndroidManifest.xml | 8 ++ .../internal/PackageResolverTest.groovy | 46 ++++++++++ .../util/RecordingAndroidCommand.groovy | 13 +-- 10 files changed, 164 insertions(+), 21 deletions(-) create mode 100644 src/test/fixtures/outdated-sdk-tools/.android-sdk/tools/source.properties create mode 100644 src/test/fixtures/outdated-sdk-tools/project/src/main/AndroidManifest.xml create mode 100644 src/test/fixtures/up-to-date-sdk-tools/.android-sdk/tools/source.properties create mode 100644 src/test/fixtures/up-to-date-sdk-tools/project/src/main/AndroidManifest.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index 561cae3..5ffdd2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ Version 1.5.0 *(In Development)* -------------------------------- * New: Support for the 1.5.x Android plugin. + * New: SDK Tools will be updated if version is older than defined with sdkManager.minSdkToolsVersion + in build.gradle: + sdkManager { + minSdkToolsVersion '24.3.4' + } * 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 cf6d3f6..078ab2a 100644 --- a/src/main/groovy/com/jakewharton/sdkmanager/internal/PackageResolver.groovy +++ b/src/main/groovy/com/jakewharton/sdkmanager/internal/PackageResolver.groovy @@ -16,6 +16,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) { @@ -58,6 +59,7 @@ class PackageResolver { } def resolve() { + resolveSdkTools() resolveBuildTools() resolvePlatformTools() resolveCompileVersion() @@ -66,6 +68,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" @@ -222,21 +274,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()) { @@ -265,6 +303,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" } } From d04fe1f8e0439f524d7e64643b2fc53d3a671056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toms=20Kusi=C5=86=C5=A1?= Date: Thu, 7 Apr 2016 23:32:40 +0200 Subject: [PATCH 2/2] Make minSdkToolsVersion PR compatible with the removal of FullRevision class --- .../internal/PackageResolver.groovy | 6 +- .../sdkmanager/internal/VersionMatcher.groovy | 62 +++++++++++++++++++ 2 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 src/main/groovy/com/jakewharton/sdkmanager/internal/VersionMatcher.groovy diff --git a/src/main/groovy/com/jakewharton/sdkmanager/internal/PackageResolver.groovy b/src/main/groovy/com/jakewharton/sdkmanager/internal/PackageResolver.groovy index 078ab2a..c5c453d 100644 --- a/src/main/groovy/com/jakewharton/sdkmanager/internal/PackageResolver.groovy +++ b/src/main/groovy/com/jakewharton/sdkmanager/internal/PackageResolver.groovy @@ -80,8 +80,8 @@ class PackageResolver { def sdkToolsVersion = getPackageRevision(sdkToolsDir) log.debug "Found sdkToolsVersion: $sdkToolsVersion" - def minSdkToolsRevision = FullRevision.parseRevision(minSdkToolsVersion) - def sdkToolsRevision = FullRevision.parseRevision(sdkToolsVersion) + def minSdkToolsRevision = VersionMatcher.parse(minSdkToolsVersion) + def sdkToolsRevision = VersionMatcher.parse(sdkToolsVersion) def needsDownload = sdkToolsRevision < minSdkToolsRevision if (!needsDownload) { @@ -104,7 +104,7 @@ class PackageResolver { def currentSdkToolsVersion = matcher.group(1) log.debug "currentSdkToolsVersion: $currentSdkToolsVersion" - def currentSdkToolsRevision = FullRevision.parseRevision(currentSdkToolsVersion) + def currentSdkToolsRevision = VersionMatcher.parse(currentSdkToolsVersion) if (currentSdkToolsRevision < minSdkToolsRevision) { throw new StopExecutionException("Currently available SDK tools version($currentSdkToolsVersion)" + " is smaller than defined in minSdkToolsVersion: $minSdkToolsVersion") diff --git a/src/main/groovy/com/jakewharton/sdkmanager/internal/VersionMatcher.groovy b/src/main/groovy/com/jakewharton/sdkmanager/internal/VersionMatcher.groovy new file mode 100644 index 0000000..b05d933 --- /dev/null +++ b/src/main/groovy/com/jakewharton/sdkmanager/internal/VersionMatcher.groovy @@ -0,0 +1,62 @@ +package com.jakewharton.sdkmanager.internal + +import org.gradle.api.tasks.StopExecutionException + +import java.util.regex.Pattern + +class VersionMatcher implements Comparable { + private final int major + private final int minor + private final int micro + private final int preview + + private static final Pattern VERSION_PATTERN = + Pattern.compile("\\s*([0-9]+)(?:\\.([0-9]+)(?:\\.([0-9]+))?)?\\s*(?:rc([0-9]+))?\\s*") + + public VersionMatcher(int major, int minor, int micro, int preview) { + this.major = major + this.minor = minor + this.micro = micro + this.preview = preview + } + + public static VersionMatcher parse(String version) { + def m = VERSION_PATTERN.matcher(version) + if (m == null || !m.matches()) { + throw new StopExecutionException('Version string mismatched') + } + + int major = Integer.parseInt(m.group(1)) + String s = m.group(2) + int minor = s == null ? 0 : Integer.parseInt(s) + s = m.group(3) + int micro = s == null ? 0 : Integer.parseInt(s) + s = m.group(4) + // Something that isn't a release candidate is newer than something that is + // e.g. "18.0.0 rc1" < "18.0.0" + int preview = s == null ? Integer.MAX_VALUE : Integer.parseInt(s) + + return new VersionMatcher(major, minor, micro, preview) + } + + @Override + public int compareTo(VersionMatcher rhs) { + int delta = major - rhs.major + if (delta != 0) { + return delta + } + + delta = minor - rhs.minor + if (delta != 0) { + return delta + } + + delta = micro - rhs.micro; + if (delta != 0) { + return delta + } + + delta = preview - rhs.preview; + return delta + } +} \ No newline at end of file