diff options
author | Lukacs Berki <lberki@google.com> | 2015-06-09 06:53:43 +0000 |
---|---|---|
committer | Damien Martin-Guillerez <dmarting@google.com> | 2015-06-09 09:57:24 +0000 |
commit | 2b870d92d1ec33eadcad5a02058df750baf91fbf (patch) | |
tree | 6dd167b0daf01c0388c5de13b25c3887eddebbfd | |
parent | 121a4001b69319f7d98c225894fa4742fa5c6cd1 (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
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(); + } +} |