blob: 7118de468b90532c597458e9cd49065c14e1add0 [file] [log] [blame]
// Copyright 2017 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.devtools.build.lib.bazel.rules.android;
import com.google.common.collect.ImmutableSortedSet;
import com.google.devtools.build.lib.actions.FileValue;
import com.google.devtools.build.lib.actions.InconsistentFilesystemException;
import com.google.devtools.build.lib.rules.repository.RepositoryFunction;
import com.google.devtools.build.lib.skyframe.DirectoryListingValue;
import com.google.devtools.build.lib.skyframe.Dirents;
import com.google.devtools.build.lib.vfs.Dirent;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.lib.vfs.Root;
import com.google.devtools.build.lib.vfs.RootedPath;
import com.google.devtools.build.skyframe.SkyFunction.Environment;
import com.google.devtools.build.skyframe.SkyFunctionException.Transience;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** This class contains the common logic between Android NDK and SDK repository functions. */
abstract class AndroidRepositoryFunction extends RepositoryFunction {
private static final Pattern PLATFORMS_API_LEVEL_PATTERN = Pattern.compile("android-(\\d+)");
/**
* Android rules depend on the contents in the SDK and NDK existing in the correct locations. This
* error is thrown when required files or directories are not found or believed to be tampered
* with.
*/
abstract void throwInvalidPathException(Path path, Exception e)
throws RepositoryFunctionException;
/**
* Gets a {@link DirectoryListingValue} for {@code dirPath} or returns null.
*
* <p>First, we get a {@link FileValue} to check the {@code dirPath} exists and is a directory. If
* not, we throw an exception.
*/
final DirectoryListingValue getDirectoryListing(Path root, PathFragment dirPath, Environment env)
throws RepositoryFunctionException, InterruptedException {
RootedPath rootedPath = RootedPath.toRootedPath(Root.fromPath(root), dirPath);
try {
FileValue dirFileValue =
(FileValue) env.getValueOrThrow(FileValue.key(rootedPath), IOException.class);
if (dirFileValue == null) {
return null;
}
if (!dirFileValue.exists() || !dirFileValue.isDirectory()) {
throwInvalidPathException(
root,
new IOException(
String.format(
"Expected directory at %s but it is not a directory or it does not exist.",
rootedPath.asPath().getPathString())));
}
return (DirectoryListingValue)
env.getValueOrThrow(
DirectoryListingValue.key(RootedPath.toRootedPath(Root.fromPath(root), dirPath)),
InconsistentFilesystemException.class);
} catch (IOException e) {
throw new RepositoryFunctionException(e, Transience.PERSISTENT);
}
}
/**
* Gets the numeric api levels from the contents of the platforms directory in descending order.
*
* <p>Note that the directory entries are assumed to match {@code android-[0-9]+}. Any directory
* entries that are not directories or do not match that pattern are ignored.
*/
static final 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();
}
}