aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Lukacs Berki <lberki@google.com>2015-06-09 06:53:43 +0000
committerGravatar Damien Martin-Guillerez <dmarting@google.com>2015-06-09 09:57:24 +0000
commit2b870d92d1ec33eadcad5a02058df750baf91fbf (patch)
tree6dd167b0daf01c0388c5de13b25c3887eddebbfd /src
parent121a4001b69319f7d98c225894fa4742fa5c6cd1 (diff)
Add stub implementations of the android_sdk_repository and android_ndk_repository rules that will be used to reference Android SDK/NDK to be used for Android builds.
-- MOS_MIGRATED_REVID=95507994
Diffstat (limited to 'src')
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java6
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/repository/NewHttpArchiveFunction.java13
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/repository/NewLocalRepositoryFunction.java167
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/repository/RepositoryFunction.java272
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java4
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidNdkRepositoryFunction.java63
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidNdkRepositoryRule.java53
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidSdkRepositoryFunction.java66
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidSdkRepositoryRule.java54
9 files changed, 481 insertions, 217 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java b/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java
index bd56910369..c43801a102 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/BazelRepositoryModule.java
@@ -31,6 +31,10 @@ import com.google.devtools.build.lib.bazel.repository.NewHttpArchiveFunction;
import com.google.devtools.build.lib.bazel.repository.NewLocalRepositoryFunction;
import com.google.devtools.build.lib.bazel.repository.RepositoryDelegatorFunction;
import com.google.devtools.build.lib.bazel.repository.RepositoryFunction;
+import com.google.devtools.build.lib.bazel.rules.android.AndroidNdkRepositoryFunction;
+import com.google.devtools.build.lib.bazel.rules.android.AndroidNdkRepositoryRule;
+import com.google.devtools.build.lib.bazel.rules.android.AndroidSdkRepositoryFunction;
+import com.google.devtools.build.lib.bazel.rules.android.AndroidSdkRepositoryRule;
import com.google.devtools.build.lib.bazel.rules.workspace.HttpArchiveRule;
import com.google.devtools.build.lib.bazel.rules.workspace.HttpJarRule;
import com.google.devtools.build.lib.bazel.rules.workspace.LocalRepositoryRule;
@@ -70,6 +74,8 @@ public class BazelRepositoryModule extends BlazeModule {
.put(MavenJarRule.NAME, new MavenJarFunction())
.put(NewHttpArchiveRule.NAME, new NewHttpArchiveFunction())
.put(NewLocalRepositoryRule.NAME, new NewLocalRepositoryFunction())
+ .put(AndroidSdkRepositoryRule.NAME, new AndroidSdkRepositoryFunction())
+ .put(AndroidNdkRepositoryRule.NAME, new AndroidNdkRepositoryFunction())
.build();
}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/NewHttpArchiveFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/NewHttpArchiveFunction.java
index f6e2037880..3000a95150 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/repository/NewHttpArchiveFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/NewHttpArchiveFunction.java
@@ -18,7 +18,6 @@ import com.google.devtools.build.lib.bazel.rules.workspace.NewHttpArchiveRule;
import com.google.devtools.build.lib.packages.PackageIdentifier.RepositoryName;
import com.google.devtools.build.lib.packages.Rule;
import com.google.devtools.build.lib.skyframe.FileValue;
-import com.google.devtools.build.lib.skyframe.RepositoryValue;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.skyframe.SkyFunction;
@@ -47,7 +46,7 @@ public class NewHttpArchiveFunction extends HttpArchiveFunction {
public SkyValue compute(SkyKey skyKey, SkyFunction.Environment env)
throws RepositoryFunctionException {
RepositoryName repositoryName = (RepositoryName) skyKey.argument();
- Rule rule = RepositoryFunction.getRule(repositoryName, NewHttpArchiveRule.NAME, env);
+ Rule rule = getRule(repositoryName, NewHttpArchiveRule.NAME, env);
if (rule == null) {
return null;
}
@@ -87,13 +86,7 @@ public class NewHttpArchiveFunction extends HttpArchiveFunction {
}
// Add WORKSPACE and BUILD files.
- NewLocalRepositoryFunction.createWorkspaceFile(decompressedDirectory, rule);
- FileValue buildFile = NewLocalRepositoryFunction.createBuildFile(
- rule, getWorkspace(), outputDirectory, env);
- if (buildFile == null) {
- return null;
- }
-
- return RepositoryValue.createNew(repositoryDirectory, buildFile);
+ createWorkspaceFile(decompressedDirectory, rule);
+ return symlinkBuildFile(rule, getWorkspace(), repositoryDirectory, env);
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/NewLocalRepositoryFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/NewLocalRepositoryFunction.java
index 7cc8b25a4a..eb01bebb37 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/repository/NewLocalRepositoryFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/NewLocalRepositoryFunction.java
@@ -16,29 +16,15 @@ package com.google.devtools.build.lib.bazel.repository;
import com.google.devtools.build.lib.analysis.RuleDefinition;
import com.google.devtools.build.lib.bazel.rules.workspace.NewLocalRepositoryRule;
-import com.google.devtools.build.lib.packages.AggregatingAttributeMapper;
import com.google.devtools.build.lib.packages.PackageIdentifier.RepositoryName;
import com.google.devtools.build.lib.packages.Rule;
-import com.google.devtools.build.lib.packages.Type;
-import com.google.devtools.build.lib.skyframe.FileSymlinkCycleException;
import com.google.devtools.build.lib.skyframe.FileValue;
-import com.google.devtools.build.lib.skyframe.InconsistentFilesystemException;
-import com.google.devtools.build.lib.skyframe.RepositoryValue;
-import com.google.devtools.build.lib.syntax.EvalException;
-import com.google.devtools.build.lib.vfs.FileSystem;
-import com.google.devtools.build.lib.vfs.FileSystemUtils;
-import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.PathFragment;
-import com.google.devtools.build.lib.vfs.RootedPath;
import com.google.devtools.build.skyframe.SkyFunctionException;
-import com.google.devtools.build.skyframe.SkyFunctionException.Transience;
import com.google.devtools.build.skyframe.SkyFunctionName;
import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;
-import java.io.IOException;
-import java.nio.charset.Charset;
-
/**
* Create a repository from a directory on the local filesystem.
*/
@@ -47,163 +33,26 @@ public class NewLocalRepositoryFunction extends RepositoryFunction {
@Override
public SkyValue compute(SkyKey skyKey, Environment env) throws SkyFunctionException {
RepositoryName repositoryName = (RepositoryName) skyKey.argument();
- Rule rule = RepositoryFunction.getRule(repositoryName, NewLocalRepositoryRule.NAME, env);
+ Rule rule = getRule(repositoryName, NewLocalRepositoryRule.NAME, env);
if (rule == null) {
return null;
}
- // Given a rule that looks like this:
- // new_local_repository(
- // name = 'x',
- // path = '/some/path/to/y',
- // build_file = 'x.BUILD'
- // )
- //
- // Assume /some/path/to/y contains files z, w, and v. This creates the following directory
- // structure:
- // .external-repository/
- // x/
- // WORKSPACE
- // BUILD -> <build_root>/x.BUILD
- // z -> /some/path/to/y/z
- // w -> /some/path/to/y/w
- // v -> /some/path/to/y/v
- //
- // Create x/
- Path repositoryDirectory = getExternalRepositoryDirectory().getRelative(rule.getName());
- try {
- FileSystemUtils.deleteTree(repositoryDirectory);
- FileSystemUtils.createDirectoryAndParents(repositoryDirectory);
- } catch (IOException e) {
- throw new RepositoryFunctionException(e, Transience.TRANSIENT);
- }
- FileValue directoryValue = getRepositoryDirectory(repositoryDirectory, env);
+ FileValue directoryValue = prepareLocalRepositorySymlinkTree(rule, env);
if (directoryValue == null) {
return null;
}
- // Add x/WORKSPACE.
- createWorkspaceFile(repositoryDirectory, rule);
-
- AggregatingAttributeMapper mapper = AggregatingAttributeMapper.of(rule);
- String path = mapper.get("path", Type.STRING);
- PathFragment pathFragment = new PathFragment(path);
- if (!pathFragment.isAbsolute()) {
- throw new RepositoryFunctionException(
- new EvalException(
- rule.getLocation(),
- "In " + rule + " the 'path' attribute must specify an absolute path"),
- Transience.PERSISTENT);
- }
-
+ PathFragment pathFragment = getTargetPath(rule);
+
// Link x/y/z to /some/path/to/y/z.
- FileSystem fs = getOutputBase().getFileSystem();
- Path targetDirectory = fs.getPath(pathFragment);
- try {
- for (Path target : targetDirectory.getDirectoryEntries()) {
- Path symlinkPath = repositoryDirectory.getRelative(target.getBaseName());
- if (createSymbolicLink(symlinkPath, target, env) == null) {
- return null;
- }
- }
- } catch (IOException e) {
- throw new RepositoryFunctionException(e, Transience.TRANSIENT);
- }
-
- // Link x/BUILD to <build_root>/x.BUILD.
- FileValue buildFile = createBuildFile(rule, getWorkspace(), repositoryDirectory, env);
- if (buildFile == null) {
- return null;
- }
-
- return RepositoryValue.createNew(directoryValue, buildFile);
- }
-
- public static void createWorkspaceFile(Path repositoryDirectory, Rule rule)
- throws RepositoryFunctionException {
- try {
- Path workspaceFile = repositoryDirectory.getRelative("WORKSPACE");
- FileSystemUtils.writeContent(workspaceFile, Charset.forName("UTF-8"),
- String.format("# DO NOT EDIT: automatically generated WORKSPACE file for %s\n", rule));
- } catch (IOException e) {
- throw new RepositoryFunctionException(e, Transience.TRANSIENT);
- }
- }
-
- /**
- * Symlinks a BUILD file from the local filesystem into the external repository's root.
- * @param rule the rule that declares the build_file path.
- * @param workspaceDirectory the workspace root for the build.
- * @param repositoryDirectory the external repository's root directory.
- * @param env the Skyframe environment.
- * @return the file value of the symlink created.
- * @throws RepositoryFunctionException if the BUILD file specified does not exist or cannot be
- * linked.
- */
- public static FileValue createBuildFile(
- Rule rule, Path workspaceDirectory, Path repositoryDirectory, Environment env)
- throws RepositoryFunctionException {
- AggregatingAttributeMapper mapper = AggregatingAttributeMapper.of(rule);
- PathFragment buildFile = new PathFragment(mapper.get("build_file", Type.STRING));
- Path buildFileTarget = workspaceDirectory.getRelative(buildFile);
- if (!buildFileTarget.exists()) {
- throw new RepositoryFunctionException(
- new EvalException(rule.getLocation(),
- String.format("In %s the 'build_file' attribute does not specify an existing file "
- + "(%s does not exist)", rule, buildFileTarget)),
- Transience.PERSISTENT);
- }
-
- RootedPath rootedBuild;
- if (buildFile.isAbsolute()) {
- rootedBuild = RootedPath.toRootedPath(
- buildFileTarget.getParentDirectory(), new PathFragment(buildFileTarget.getBaseName()));
- } else {
- rootedBuild = RootedPath.toRootedPath(workspaceDirectory, buildFile);
- }
- SkyKey buildFileKey = FileValue.key(rootedBuild);
- FileValue buildFileValue;
- try {
- buildFileValue = (FileValue) env.getValueOrThrow(buildFileKey, IOException.class,
- FileSymlinkCycleException.class, InconsistentFilesystemException.class);
- if (buildFileValue == null) {
- return null;
- }
- } catch (IOException | FileSymlinkCycleException | InconsistentFilesystemException e) {
- throw new RepositoryFunctionException(
- new IOException("Cannot lookup " + buildFile + ": " + e.getMessage()),
- Transience.TRANSIENT);
- }
-
- Path buildFilePath = repositoryDirectory.getRelative("BUILD");
- if (createSymbolicLink(buildFilePath, buildFileTarget, env) == null) {
+ if (!symlinkLocalRepositoryContents(
+ directoryValue, getOutputBase().getFileSystem().getPath(pathFragment), env)) {
return null;
}
- return buildFileValue;
- }
- private static FileValue createSymbolicLink(Path from, Path to, Environment env)
- throws RepositoryFunctionException {
- try {
- if (!from.exists()) {
- from.createSymbolicLink(to);
- }
- } catch (IOException e) {
- throw new RepositoryFunctionException(
- new IOException(String.format("Error creating symbolic link from %s to %s: %s",
- from, to, e.getMessage())), Transience.TRANSIENT);
- }
-
- SkyKey outputDirectoryKey = FileValue.key(RootedPath.toRootedPath(
- from, PathFragment.EMPTY_FRAGMENT));
- try {
- return (FileValue) env.getValueOrThrow(outputDirectoryKey, IOException.class,
- FileSymlinkCycleException.class, InconsistentFilesystemException.class);
- } catch (IOException | FileSymlinkCycleException | InconsistentFilesystemException e) {
- throw new RepositoryFunctionException(
- new IOException(String.format("Could not access %s: %s", from, e.getMessage())),
- Transience.PERSISTENT);
- }
+ // Link x/BUILD to <build_root>/x.BUILD.
+ return symlinkBuildFile(rule, getWorkspace(), directoryValue, env);
}
/**
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/RepositoryFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/RepositoryFunction.java
index e581252d61..efc2beb7d2 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/repository/RepositoryFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/RepositoryFunction.java
@@ -17,6 +17,7 @@ package com.google.devtools.build.lib.bazel.repository;
import com.google.common.base.Preconditions;
import com.google.devtools.build.lib.analysis.BlazeDirectories;
import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.packages.AggregatingAttributeMapper;
import com.google.devtools.build.lib.packages.BuildFileContainsErrorsException;
import com.google.devtools.build.lib.packages.BuildFileNotFoundException;
import com.google.devtools.build.lib.packages.ExternalPackage;
@@ -24,11 +25,14 @@ import com.google.devtools.build.lib.packages.NoSuchPackageException;
import com.google.devtools.build.lib.packages.PackageIdentifier;
import com.google.devtools.build.lib.packages.PackageIdentifier.RepositoryName;
import com.google.devtools.build.lib.packages.Rule;
+import com.google.devtools.build.lib.packages.Type;
import com.google.devtools.build.lib.skyframe.FileSymlinkCycleException;
import com.google.devtools.build.lib.skyframe.FileValue;
import com.google.devtools.build.lib.skyframe.InconsistentFilesystemException;
import com.google.devtools.build.lib.skyframe.PackageValue;
+import com.google.devtools.build.lib.skyframe.RepositoryValue;
import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.lib.vfs.RootedPath;
@@ -39,6 +43,7 @@ import com.google.devtools.build.skyframe.SkyFunctionName;
import com.google.devtools.build.skyframe.SkyKey;
import java.io.IOException;
+import java.nio.charset.Charset;
import javax.annotation.Nullable;
@@ -46,52 +51,204 @@ import javax.annotation.Nullable;
* Parent class for repository-related Skyframe functions.
*/
public abstract class RepositoryFunction implements SkyFunction {
- private BlazeDirectories directories;
+ /**
+ * Exception thrown when something goes wrong accessing a remote repository.
+ *
+ * <p>This exception should be used by child classes to limit the types of exceptions
+ * {@link RepositoryDelegatorFunction} has to know how to catch.</p>
+ */
+ public static final class RepositoryFunctionException extends SkyFunctionException {
+ public RepositoryFunctionException(NoSuchPackageException cause, Transience transience) {
+ super(cause, transience);
+ }
- @Override
- public String extractTag(SkyKey skyKey) {
- return null;
+ /**
+ * Error reading or writing to the filesystem.
+ */
+ public RepositoryFunctionException(IOException cause, Transience transience) {
+ super(cause, transience);
+ }
+
+ /**
+ * For errors in WORKSPACE file rules (e.g., malformed paths or URLs).
+ */
+ public RepositoryFunctionException(EvalException cause, Transience transience) {
+ super(cause, transience);
+ }
}
- /**
- * Gets Skyframe's name for this.
- */
- public abstract SkyFunctionName getSkyFunctionName();
+ private BlazeDirectories directories;
- /**
- * Sets up output path information.
- */
- public void setDirectories(BlazeDirectories directories) {
- this.directories = directories;
+ protected FileValue prepareLocalRepositorySymlinkTree(Rule rule, Environment env)
+ throws RepositoryFunctionException {
+ Path repositoryDirectory = getExternalRepositoryDirectory().getRelative(rule.getName());
+ try {
+ FileSystemUtils.deleteTree(repositoryDirectory);
+ FileSystemUtils.createDirectoryAndParents(repositoryDirectory);
+ } catch (IOException e) {
+ throw new RepositoryFunctionException(e, Transience.TRANSIENT);
+ }
+ FileValue directoryValue = getRepositoryDirectory(repositoryDirectory, env);
+
+ if (directoryValue == null) {
+ return null;
+ }
+
+ // Add x/WORKSPACE.
+ createWorkspaceFile(repositoryDirectory, rule);
+ return directoryValue;
}
- protected Path getExternalRepositoryDirectory() {
- return RepositoryFunction.getExternalRepositoryDirectory(directories);
+ protected void createWorkspaceFile(Path repositoryDirectory, Rule rule)
+ throws RepositoryFunctionException {
+ try {
+ Path workspaceFile = repositoryDirectory.getRelative("WORKSPACE");
+ FileSystemUtils.writeContent(workspaceFile, Charset.forName("UTF-8"),
+ String.format("# DO NOT EDIT: automatically generated WORKSPACE file for %s\n", rule));
+ } catch (IOException e) {
+ throw new RepositoryFunctionException(e, Transience.TRANSIENT);
+ }
}
- public static Path getExternalRepositoryDirectory(BlazeDirectories directories) {
- return directories.getOutputBase().getRelative(ExternalPackage.NAME);
+ protected RepositoryValue writeBuildFile(FileValue directoryValue, String contents)
+ throws RepositoryFunctionException {
+ Path buildFilePath = directoryValue.realRootedPath().asPath().getRelative("BUILD");
+ try {
+ FileSystemUtils.writeContentAsLatin1(buildFilePath, contents);
+ } catch (IOException e) {
+ throw new RepositoryFunctionException(e, Transience.TRANSIENT);
+ }
+
+ return RepositoryValue.create(directoryValue);
}
/**
- * Gets the base directory repositories should be stored in locally.
+ * Symlinks a BUILD file from the local filesystem into the external repository's root.
+ * @param rule the rule that declares the build_file path.
+ * @param workspaceDirectory the workspace root for the build.
+ * @param directoryValue the FileValue corresponding to the external repository's root directory.
+ * @param env the Skyframe environment.
+ * @return the file value of the symlink created.
+ * @throws com.google.devtools.build.lib.bazel.repository.RepositoryFunction.RepositoryFunctionException if the BUILD file specified does not exist or cannot be
+ * linked.
*/
- protected Path getOutputBase() {
- return directories.getOutputBase();
+ protected RepositoryValue symlinkBuildFile(
+ Rule rule, Path workspaceDirectory, FileValue directoryValue, Environment env)
+ throws RepositoryFunctionException {
+ AggregatingAttributeMapper mapper = AggregatingAttributeMapper.of(rule);
+ PathFragment buildFile = new PathFragment(mapper.get("build_file", Type.STRING));
+ Path buildFileTarget = workspaceDirectory.getRelative(buildFile);
+ if (!buildFileTarget.exists()) {
+ throw new RepositoryFunctionException(
+ new EvalException(rule.getLocation(),
+ String.format("In %s the 'build_file' attribute does not specify an existing file "
+ + "(%s does not exist)", rule, buildFileTarget)),
+ Transience.PERSISTENT);
+ }
+
+ RootedPath rootedBuild;
+ if (buildFile.isAbsolute()) {
+ rootedBuild = RootedPath.toRootedPath(
+ buildFileTarget.getParentDirectory(), new PathFragment(buildFileTarget.getBaseName()));
+ } else {
+ rootedBuild = RootedPath.toRootedPath(workspaceDirectory, buildFile);
+ }
+ SkyKey buildFileKey = FileValue.key(rootedBuild);
+ FileValue buildFileValue;
+ try {
+ buildFileValue = (FileValue) env.getValueOrThrow(buildFileKey, IOException.class,
+ FileSymlinkCycleException.class, InconsistentFilesystemException.class);
+ if (buildFileValue == null) {
+ return null;
+ }
+ } catch (IOException | FileSymlinkCycleException | InconsistentFilesystemException e) {
+ throw new RepositoryFunctionException(
+ new IOException("Cannot lookup " + buildFile + ": " + e.getMessage()),
+ Transience.TRANSIENT);
+ }
+
+ Path buildFilePath = directoryValue.realRootedPath().asPath().getRelative("BUILD");
+ if (createSymbolicLink(buildFilePath, buildFileTarget, env) == null) {
+ return null;
+ }
+
+ if (buildFileValue == null) {
+ return null;
+ }
+
+ return RepositoryValue.createNew(directoryValue, buildFileValue);
+ }
+
+ protected static PathFragment getTargetPath(Rule rule) throws RepositoryFunctionException {
+ AggregatingAttributeMapper mapper = AggregatingAttributeMapper.of(rule);
+ String path = mapper.get("path", Type.STRING);
+ PathFragment pathFragment = new PathFragment(path);
+ if (!pathFragment.isAbsolute()) {
+ throw new RepositoryFunctionException(
+ new EvalException(
+ rule.getLocation(),
+ "In " + rule + " the 'path' attribute must specify an absolute path"),
+ Transience.PERSISTENT);
+ }
+
+ return pathFragment;
}
/**
- * Gets the directory the WORKSPACE file for the build is in.
+ * Given a targetDirectory /some/path/to/y that contains files z, w, and v, create the following
+ * directory structure:
+ * <pre>
+ * .external-repository/
+ * x/
+ * WORKSPACE
+ * BUILD -> <build_root>/x.BUILD
+ * z -> /some/path/to/y/z
+ * w -> /some/path/to/y/w
+ * v -> /some/path/to/y/v
+ * </pre>
*/
- protected Path getWorkspace() {
- return directories.getWorkspace();
+ public static boolean symlinkLocalRepositoryContents(
+ FileValue repositoryDirectory, Path targetDirectory, Environment env)
+ throws RepositoryFunctionException {
+ try {
+ for (Path target : targetDirectory.getDirectoryEntries()) {
+ Path symlinkPath =
+ repositoryDirectory.realRootedPath().asPath().getRelative(target.getBaseName());
+ if (createSymbolicLink(symlinkPath, target, env) == null) {
+ return false;
+ }
+ }
+ } catch (IOException e) {
+ throw new RepositoryFunctionException(e, Transience.TRANSIENT);
+ }
+
+ return true;
}
+ private static FileValue createSymbolicLink(Path from, Path to, Environment env)
+ throws RepositoryFunctionException {
+ try {
+ if (!from.exists()) {
+ from.createSymbolicLink(to);
+ }
+ } catch (IOException e) {
+ throw new RepositoryFunctionException(
+ new IOException(String.format("Error creating symbolic link from %s to %s: %s",
+ from, to, e.getMessage())), Transience.TRANSIENT);
+ }
+
+ SkyKey outputDirectoryKey = FileValue.key(RootedPath.toRootedPath(
+ from, PathFragment.EMPTY_FRAGMENT));
+ try {
+ return (FileValue) env.getValueOrThrow(outputDirectoryKey, IOException.class,
+ FileSymlinkCycleException.class, InconsistentFilesystemException.class);
+ } catch (IOException | FileSymlinkCycleException | InconsistentFilesystemException e) {
+ throw new RepositoryFunctionException(
+ new IOException(String.format("Could not access %s: %s", from, e.getMessage())),
+ Transience.PERSISTENT);
+ }
+ }
- /**
- * Returns the RuleDefinition class for this type of repository.
- */
- public abstract Class<? extends RuleDefinition> getRuleDefinition();
/**
* Uses a remote repository name to fetch the corresponding Rule describing how to get it.
@@ -137,7 +294,7 @@ public abstract class RepositoryFunction implements SkyFunction {
* actual directory.
*/
@Nullable
- protected static FileValue getRepositoryDirectory(Path repositoryDirectory, Environment env)
+ public static FileValue getRepositoryDirectory(Path repositoryDirectory, Environment env)
throws RepositoryFunctionException {
SkyKey outputDirectoryKey = FileValue.key(RootedPath.toRootedPath(
repositoryDirectory, PathFragment.EMPTY_FRAGMENT));
@@ -153,29 +310,48 @@ public abstract class RepositoryFunction implements SkyFunction {
return value;
}
+ @Override
+ public String extractTag(SkyKey skyKey) {
+ return null;
+ }
+
/**
- * Exception thrown when something goes wrong accessing a remote repository.
- *
- * <p>This exception should be used by child classes to limit the types of exceptions
- * {@link RepositoryDelegatorFunction} has to know how to catch.</p>
+ * Gets Skyframe's name for this.
*/
- static final class RepositoryFunctionException extends SkyFunctionException {
- public RepositoryFunctionException(NoSuchPackageException cause, Transience transience) {
- super(cause, transience);
- }
+ public abstract SkyFunctionName getSkyFunctionName();
- /**
- * Error reading or writing to the filesystem.
- */
- public RepositoryFunctionException(IOException cause, Transience transience) {
- super(cause, transience);
- }
+ /**
+ * Sets up output path information.
+ */
+ public void setDirectories(BlazeDirectories directories) {
+ this.directories = directories;
+ }
- /**
- * For errors in WORKSPACE file rules (e.g., malformed paths or URLs).
- */
- public RepositoryFunctionException(EvalException cause, Transience transience) {
- super(cause, transience);
- }
+ protected Path getExternalRepositoryDirectory() {
+ return RepositoryFunction.getExternalRepositoryDirectory(directories);
+ }
+
+ public static Path getExternalRepositoryDirectory(BlazeDirectories directories) {
+ return directories.getOutputBase().getRelative(ExternalPackage.NAME);
}
+
+ /**
+ * Gets the base directory repositories should be stored in locally.
+ */
+ protected Path getOutputBase() {
+ return directories.getOutputBase();
+ }
+
+ /**
+ * Gets the directory the WORKSPACE file for the build is in.
+ */
+ protected Path getWorkspace() {
+ return directories.getWorkspace();
+ }
+
+
+ /**
+ * Returns the RuleDefinition class for this type of repository.
+ */
+ public abstract Class<? extends RuleDefinition> getRuleDefinition();
}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
index b7c95dcece..a95c2dfa37 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
@@ -30,6 +30,8 @@ import com.google.devtools.build.lib.analysis.config.ConfigurationEnvironment;
import com.google.devtools.build.lib.analysis.config.FragmentOptions;
import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
import com.google.devtools.build.lib.analysis.constraints.EnvironmentRule;
+import com.google.devtools.build.lib.bazel.rules.android.AndroidNdkRepositoryRule;
+import com.google.devtools.build.lib.bazel.rules.android.AndroidSdkRepositoryRule;
import com.google.devtools.build.lib.bazel.rules.common.BazelActionListenerRule;
import com.google.devtools.build.lib.bazel.rules.common.BazelExtraActionRule;
import com.google.devtools.build.lib.bazel.rules.common.BazelFilegroupRule;
@@ -301,6 +303,8 @@ public class BazelRuleClassProvider {
builder.addRuleDefinition(new MavenJarRule());
builder.addRuleDefinition(new NewHttpArchiveRule());
builder.addRuleDefinition(new NewLocalRepositoryRule());
+ builder.addRuleDefinition(new AndroidSdkRepositoryRule());
+ builder.addRuleDefinition(new AndroidNdkRepositoryRule());
builder.addConfigurationFragment(new BazelConfiguration.Loader());
builder.addConfigurationFragment(new CppConfigurationLoader(
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidNdkRepositoryFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidNdkRepositoryFunction.java
new file mode 100644
index 0000000000..c5c05bb053
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidNdkRepositoryFunction.java
@@ -0,0 +1,63 @@
+// Copyright 2015 Google Inc. 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.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.bazel.repository.RepositoryFunction;
+import com.google.devtools.build.lib.packages.PackageIdentifier.RepositoryName;
+import com.google.devtools.build.lib.packages.Rule;
+import com.google.devtools.build.lib.skyframe.FileValue;
+import com.google.devtools.build.lib.vfs.PathFragment;
+import com.google.devtools.build.skyframe.SkyFunctionException;
+import com.google.devtools.build.skyframe.SkyFunctionName;
+import com.google.devtools.build.skyframe.SkyKey;
+import com.google.devtools.build.skyframe.SkyValue;
+
+/**
+ * Implementation of the {@code android_ndk} repository rule.
+ */
+public class AndroidNdkRepositoryFunction extends RepositoryFunction {
+ @Override
+ public SkyValue compute(SkyKey skyKey, Environment env) throws SkyFunctionException {
+ RepositoryName repositoryName = (RepositoryName) skyKey.argument();
+ Rule rule = getRule(repositoryName, AndroidNdkRepositoryRule.NAME, env);
+ if (rule == null) {
+ return null;
+ }
+
+ FileValue directoryValue = prepareLocalRepositorySymlinkTree(rule, env);
+ if (directoryValue == null) {
+ return null;
+ }
+
+ PathFragment pathFragment = getTargetPath(rule);
+
+ if (!symlinkLocalRepositoryContents(
+ directoryValue, getOutputBase().getFileSystem().getPath(pathFragment), env)) {
+ return null;
+ }
+
+ return writeBuildFile(directoryValue, "filegroup(name='ndk')");
+ }
+
+ @Override
+ public SkyFunctionName getSkyFunctionName() {
+ return SkyFunctionName.computed(AndroidNdkRepositoryRule.NAME.toUpperCase());
+ }
+
+ @Override
+ public Class<? extends RuleDefinition> getRuleDefinition() {
+ return AndroidNdkRepositoryRule.class;
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidNdkRepositoryRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidNdkRepositoryRule.java
new file mode 100644
index 0000000000..2de9bd7b0d
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidNdkRepositoryRule.java
@@ -0,0 +1,53 @@
+// Copyright 2015 Google Inc. 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 static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.Type.INTEGER;
+import static com.google.devtools.build.lib.packages.Type.STRING;
+
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+import com.google.devtools.build.lib.bazel.rules.workspace.WorkspaceBaseRule;
+import com.google.devtools.build.lib.bazel.rules.workspace.WorkspaceConfiguredTargetFactory;
+import com.google.devtools.build.lib.packages.RuleClass;
+import com.google.devtools.build.lib.packages.RuleClass.Builder;
+import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType;
+
+/**
+ * Definition of the {@code android_ndk} rule.
+ */
+public class AndroidNdkRepositoryRule implements RuleDefinition {
+ public static final String NAME = "android_ndk_repository";
+
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
+ return builder
+ .setUndocumented()
+ .setWorkspaceOnly()
+ .add(attr("path", STRING).mandatory())
+ .add(attr("api_level", INTEGER).mandatory())
+ .build();
+ }
+
+ @Override
+ public Metadata getMetadata() {
+ return RuleDefinition.Metadata.builder()
+ .name(AndroidNdkRepositoryRule.NAME)
+ .type(RuleClassType.WORKSPACE)
+ .ancestors(WorkspaceBaseRule.class)
+ .factoryClass(WorkspaceConfiguredTargetFactory.class)
+ .build();
+ }
+}
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
new file mode 100644
index 0000000000..b03a94f482
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidSdkRepositoryFunction.java
@@ -0,0 +1,66 @@
+// Copyright 2015 Google Inc. 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.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.bazel.repository.RepositoryFunction;
+import com.google.devtools.build.lib.packages.PackageIdentifier.RepositoryName;
+import com.google.devtools.build.lib.packages.Rule;
+import com.google.devtools.build.lib.skyframe.FileValue;
+import com.google.devtools.build.lib.vfs.PathFragment;
+import com.google.devtools.build.skyframe.SkyFunctionException;
+import com.google.devtools.build.skyframe.SkyFunctionName;
+import com.google.devtools.build.skyframe.SkyKey;
+import com.google.devtools.build.skyframe.SkyValue;
+
+/**
+ * Implementation of the {@code android_sdk} repository rule.
+ */
+public class AndroidSdkRepositoryFunction extends RepositoryFunction {
+ @Override
+ public SkyValue compute(SkyKey skyKey, Environment env) throws SkyFunctionException {
+ RepositoryName repositoryName = (RepositoryName) skyKey.argument();
+ Rule rule = getRule(repositoryName, AndroidSdkRepositoryRule.NAME, env);
+ if (rule == null) {
+ return null;
+ }
+
+ FileValue directoryValue = prepareLocalRepositorySymlinkTree(rule, env);
+ if (directoryValue == null) {
+ return null;
+ }
+
+ PathFragment pathFragment = getTargetPath(rule);
+
+ if (!symlinkLocalRepositoryContents(
+ directoryValue, getOutputBase().getFileSystem().getPath(pathFragment), env)) {
+ return null;
+ }
+
+ return writeBuildFile(directoryValue, "filegroup(name='sdk')");
+ }
+
+ /**
+ * @see RepositoryFunction#getRule(RepositoryName, String, Environment)
+ */
+ @Override
+ public SkyFunctionName getSkyFunctionName() {
+ return SkyFunctionName.computed(AndroidSdkRepositoryRule.NAME.toUpperCase());
+ }
+
+ @Override
+ public Class<? extends RuleDefinition> getRuleDefinition() {
+ return AndroidSdkRepositoryRule.class;
+ }
+}
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
new file mode 100644
index 0000000000..2fbc6d6791
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/AndroidSdkRepositoryRule.java
@@ -0,0 +1,54 @@
+// Copyright 2015 Google Inc. 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 static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.Type.INTEGER;
+import static com.google.devtools.build.lib.packages.Type.STRING;
+
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+import com.google.devtools.build.lib.bazel.rules.workspace.WorkspaceBaseRule;
+import com.google.devtools.build.lib.bazel.rules.workspace.WorkspaceConfiguredTargetFactory;
+import com.google.devtools.build.lib.packages.RuleClass;
+import com.google.devtools.build.lib.packages.RuleClass.Builder;
+import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType;
+
+/**
+ * Definition of the {@code android_sdk} repository rule.
+ */
+public class AndroidSdkRepositoryRule implements RuleDefinition {
+ public static final String NAME = "android_sdk_repository";
+
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
+ return builder
+ .setUndocumented()
+ .setWorkspaceOnly()
+ .add(attr("path", STRING).mandatory())
+ .add(attr("build_tools", STRING).mandatory())
+ .add(attr("api_level", INTEGER).mandatory())
+ .build();
+ }
+
+ @Override
+ public Metadata getMetadata() {
+ return RuleDefinition.Metadata.builder()
+ .name(AndroidSdkRepositoryRule.NAME)
+ .type(RuleClassType.WORKSPACE)
+ .ancestors(WorkspaceBaseRule.class)
+ .factoryClass(WorkspaceConfiguredTargetFactory.class)
+ .build();
+ }
+}