diff options
author | 2017-01-11 23:37:51 +0000 | |
---|---|---|
committer | 2017-01-12 09:12:48 +0000 | |
commit | 43b1d20f44fe697366fabcc91aedad5bf568002e (patch) | |
tree | 82b8a16e23cad9118f20bafe0154dfca5dd13c5d /src/main/java | |
parent | 7fc35ae6890f4130b4d99a6c5007dcee91c5a8cc (diff) |
Make android_sdk_repository create one android_sdk per api level in the SDK.
api_level is no longer required. It now sets the default android_sdk that is used if the --android_sdk flag is not passed. If it is not set, the highest api_level will be used as the default.
The new behavior is demonstrated by the following example:
$ ls $ANDROID_HOME/platforms
android-21 android-22 android-23
$ cat WORKSPACE
android_sdk_repository(
name = "foo",
)
$ bazel build //java/my/app # uses api level 23
$ bazel build --android_sdk=@foo//:sdk-22 //java/my/app # uses api level 22
$ cat > WORKSPACE <<EOF
android_sdk_repository(
name = "foo",
api_level = 21,
)
EOF
$ bazel build //java/my/app # uses api level 21
$ bazel build --android_sdk=@foo//:sdk-23 //java/my/app # uses api level 23
See https://github.com/bazelbuild/bazel/issues/2284 for the master plan for android_sdk_repository.
RELNOTES: android_sdk_repository no longer requires api_level. If one is not specified, the highest android platform installed will be used. Furthermore, android_sdk's are created for all android platforms installed and can be specified with the --android_sdk flag.
--
PiperOrigin-RevId: 144258881
MOS_MIGRATED_REVID=144258881
Diffstat (limited to 'src/main/java')
3 files changed, 66 insertions, 25 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidSdkRepositoryFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidSdkRepositoryFunction.java index 28ae86cd98..1ab7d63842 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidSdkRepositoryFunction.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidSdkRepositoryFunction.java @@ -16,6 +16,7 @@ package com.google.devtools.build.lib.bazel.rules.android; import com.android.repository.Revision; import com.google.common.base.Predicate; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.Iterables; import com.google.devtools.build.lib.analysis.BlazeDirectories; import com.google.devtools.build.lib.analysis.RuleDefinition; @@ -44,6 +45,8 @@ import com.google.devtools.build.skyframe.SkyValue; import java.io.IOException; import java.util.Map; import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.annotation.Nullable; /** @@ -51,6 +54,8 @@ import javax.annotation.Nullable; */ public class AndroidSdkRepositoryFunction extends RepositoryFunction { private static final String BUILD_TOOLS_DIR_NAME = "build-tools"; + private static final String PLATFORMS_DIR_NAME = "platforms"; + private static final Pattern PLATFORMS_API_LEVEL_PATTERN = Pattern.compile("android-(\\d+)"); private static final Revision MIN_BUILD_TOOLS_REVISION = new Revision(24, 0, 3); private static final String PATH_ENV_VAR = "ANDROID_HOME"; @@ -66,11 +71,13 @@ public class AndroidSdkRepositoryFunction extends RepositoryFunction { prepareLocalRepositorySymlinkTree(rule, outputDirectory); WorkspaceAttributeMapper attributes = WorkspaceAttributeMapper.of(rule); - PathFragment pathFragment; + FileSystem fs = directories.getOutputBase().getFileSystem(); + Path androidSdkPath; if (attributes.isAttributeValueExplicitlySpecified("path")) { - pathFragment = getTargetPath(rule, directories.getWorkspace()); + androidSdkPath = fs.getPath(getTargetPath(rule, directories.getWorkspace())); } else if (clientEnvironment.containsKey(PATH_ENV_VAR)){ - pathFragment = getAndroidHomeEnvironmentVar(directories.getWorkspace(), clientEnvironment); + androidSdkPath = + fs.getPath(getAndroidHomeEnvironmentVar(directories.getWorkspace(), clientEnvironment)); } else { throw new RepositoryFunctionException( new EvalException( @@ -80,16 +87,38 @@ public class AndroidSdkRepositoryFunction extends RepositoryFunction { Transience.PERSISTENT); } - if (!symlinkLocalRepositoryContents( - outputDirectory, directories.getOutputBase().getFileSystem().getPath(pathFragment))) { + if (!symlinkLocalRepositoryContents(outputDirectory, androidSdkPath)) { return null; } - String apiLevel; - try { - apiLevel = attributes.get("api_level", Type.INTEGER).toString(); - } catch (EvalException e) { - throw new RepositoryFunctionException(e, Transience.PERSISTENT); + DirectoryListingValue platformsDirectoryValue = + getDirectoryListing(fs, androidSdkPath.getChild(PLATFORMS_DIR_NAME), env); + if (platformsDirectoryValue == null) { + return null; + } + + ImmutableSortedSet<Integer> apiLevels = getApiLevels(platformsDirectoryValue.getDirents()); + if (apiLevels.isEmpty()) { + throw new RepositoryFunctionException( + new EvalException( + rule.getLocation(), + "android_sdk_repository requires that at least one Android SDK Platform is installed " + + "in the Android SDK. Please install an Android SDK Platform through the " + + "Android SDK manager."), + Transience.PERSISTENT); + } + + String defaultApiLevel; + if (attributes.isAttributeValueExplicitlySpecified("api_level")) { + try { + defaultApiLevel = attributes.get("api_level", Type.INTEGER).toString(); + } catch (EvalException e) { + throw new RepositoryFunctionException(e, Transience.PERSISTENT); + } + } else { + // If the api_level attribute is not explicitly set, we select the highest api level that is + // available in the SDK. + defaultApiLevel = String.valueOf(apiLevels.first()); } String buildToolsDirectory; @@ -103,8 +132,7 @@ public class AndroidSdkRepositoryFunction extends RepositoryFunction { // If the build_tools_version attribute is not explicitly set, we select the highest version // installed in the SDK. DirectoryListingValue directoryValue = - getBuildToolsDirectoryListing( - directories.getOutputBase().getFileSystem(), pathFragment, env); + getDirectoryListing(fs, androidSdkPath.getChild(BUILD_TOOLS_DIR_NAME), env); if (directoryValue == null) { return null; } @@ -143,7 +171,8 @@ public class AndroidSdkRepositoryFunction extends RepositoryFunction { .replace("%repository_name%", rule.getName()) .replace("%build_tools_version%", buildToolsVersion) .replace("%build_tools_directory%", buildToolsDirectory) - .replace("%api_level%", apiLevel); + .replace("%api_levels%", Iterables.toString(apiLevels)) + .replace("%default_api_level%", defaultApiLevel); // All local maven repositories that are shipped in the Android SDK. // TODO(ajmichael): Create SkyKeys so that if the SDK changes, this function will get rerun. @@ -188,20 +217,14 @@ public class AndroidSdkRepositoryFunction extends RepositoryFunction { } } - /** - * Gets a DirectoryListingValue for the build-tools directory under the sdkRepoPathFragment - * or returns null. - */ - private static DirectoryListingValue getBuildToolsDirectoryListing( - FileSystem fs, PathFragment sdkRepoPathFragment, Environment env) + /** Gets a DirectoryListingValue for {@code dirPath} or returns null. */ + private static DirectoryListingValue getDirectoryListing( + FileSystem fs, Path dirPath, Environment env) throws RepositoryFunctionException, InterruptedException { try { return (DirectoryListingValue) env.getValueOrThrow( - DirectoryListingValue.key( - RootedPath.toRootedPath( - fs.getRootDirectory(), - fs.getPath(sdkRepoPathFragment).getChild(BUILD_TOOLS_DIR_NAME))), + DirectoryListingValue.key(RootedPath.toRootedPath(fs.getRootDirectory(), dirPath)), InconsistentFilesystemException.class); } catch (InconsistentFilesystemException e) { throw new RepositoryFunctionException(new IOException(e), Transience.PERSISTENT); @@ -209,6 +232,23 @@ public class AndroidSdkRepositoryFunction extends RepositoryFunction { } /** + * Gets the numeric api levels from the contents of the platforms directory in descending order. + */ + private static ImmutableSortedSet<Integer> getApiLevels(Dirents platformsDirectories) { + ImmutableSortedSet.Builder<Integer> apiLevels = ImmutableSortedSet.reverseOrder(); + for (Dirent platformDirectory : platformsDirectories) { + if (platformDirectory.getType() != Dirent.Type.DIRECTORY) { + continue; + } + Matcher matcher = PLATFORMS_API_LEVEL_PATTERN.matcher(platformDirectory.getName()); + if (matcher.matches()) { + apiLevels.add(Integer.parseInt(matcher.group(1))); + } + } + return apiLevels.build(); + } + + /** * Gets the newest build tools directory according to {@link Revision}. * * @throws RepositoryFunctionException if none of the buildToolsDirectories are directories and diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidSdkRepositoryRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidSdkRepositoryRule.java index 899601a326..1282d816fc 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidSdkRepositoryRule.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidSdkRepositoryRule.java @@ -67,7 +67,7 @@ public class AndroidSdkRepositoryRule implements RuleDefinition { // If build_tools_version is not specified explicitly, the highest build tools version // installed will be used. .add(attr("build_tools_version", STRING).nonconfigurable("WORKSPACE rule")) - .add(attr("api_level", INTEGER).mandatory().nonconfigurable("WORKSPACE rule")) + .add(attr("api_level", INTEGER).nonconfigurable("WORKSPACE rule")) .build(); } diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/android_sdk_repository_template.txt b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/android_sdk_repository_template.txt index 2630685589..35d86a0554 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/android_sdk_repository_template.txt +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/android_sdk_repository_template.txt @@ -6,7 +6,8 @@ create_android_sdk_rules( name = "%repository_name%", build_tools_version = "%build_tools_version%", build_tools_directory = "%build_tools_directory%", - api_level = %api_level%, + api_levels = %api_levels%, + default_api_level = %default_api_level%, ) exports_files([ |