diff --git a/src/com/facebook/buck/cli/BUCK b/src/com/facebook/buck/cli/BUCK index aeb6e0d6411..409f26e7d8c 100644 --- a/src/com/facebook/buck/cli/BUCK +++ b/src/com/facebook/buck/cli/BUCK @@ -70,9 +70,11 @@ java_library( '//src/com/facebook/buck/android/agent/util:util', '//src/com/facebook/buck/apple/xcode:project_generator', '//src/com/facebook/buck/apple:rules', - '//src/com/facebook/buck/event:event', '//src/com/facebook/buck/command:command', + '//src/com/facebook/buck/event:event', '//src/com/facebook/buck/event/listener:listener', + '//src/com/facebook/buck/file:downloader', + '//src/com/facebook/buck/file:file', '//src/com/facebook/buck/graph:graph', '//src/com/facebook/buck/io:io', '//src/com/facebook/buck/java:autodeps', diff --git a/src/com/facebook/buck/cli/Command.java b/src/com/facebook/buck/cli/Command.java index f3c54b0928e..cd375afd9e2 100644 --- a/src/com/facebook/buck/cli/Command.java +++ b/src/com/facebook/buck/cli/Command.java @@ -43,6 +43,10 @@ public enum Command { "deletes any generated files", CleanCommand.class, false), + FETCH( + "downloads remote resources to your local machine", + FetchCommand.class, + false), INSTALL( "builds and installs an APK", InstallCommand.class, diff --git a/src/com/facebook/buck/cli/FetchCommand.java b/src/com/facebook/buck/cli/FetchCommand.java new file mode 100644 index 00000000000..63c3a8e2187 --- /dev/null +++ b/src/com/facebook/buck/cli/FetchCommand.java @@ -0,0 +1,133 @@ +/* + * Copyright 2015-present Facebook, Inc. + * + * 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.facebook.buck.cli; + +import com.facebook.buck.command.Build; +import com.facebook.buck.file.Downloader; +import com.facebook.buck.file.HttpDownloader; +import com.facebook.buck.file.RemoteFileDescription; +import com.facebook.buck.json.BuildFileParseException; +import com.facebook.buck.model.BuildTarget; +import com.facebook.buck.model.BuildTargetException; +import com.facebook.buck.rules.ActionGraph; +import com.facebook.buck.rules.BuildEvent; +import com.facebook.buck.rules.Description; +import com.facebook.buck.rules.TargetGraph; +import com.facebook.buck.rules.TargetGraphToActionGraph; +import com.facebook.buck.step.TargetDevice; +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableSet; + +import java.io.IOException; +import java.net.Proxy; + +public class FetchCommand extends AbstractCommandRunner { + + public FetchCommand(CommandRunnerParams params) { + super(params); + } + + @Override + BuildCommandOptions createOptions(BuckConfig buckConfig) { + return new BuildCommandOptions(buckConfig); + } + + @Override + int runCommandWithOptionsInternal(BuildCommandOptions options) + throws IOException, InterruptedException { + + ImmutableSet buildTargets = + getBuildTargets(options.getArgumentsFormattedAsBuildTargets()); + + if (buildTargets.isEmpty()) { + console.printBuildFailure("Must specify at least one build target to fetch."); + return 1; + } + + // Post the build started event, setting it to the Parser recorded start time if appropriate. + if (getParser().getParseStartTime().isPresent()) { + getBuckEventBus().post( + BuildEvent.started(buildTargets), + getParser().getParseStartTime().get()); + } else { + getBuckEventBus().post(BuildEvent.started(buildTargets)); + } + + FetchTargetNodeToBuildRuleTransformer ruleGenerator = createFetchTransformer(options); + TargetGraphToActionGraph transformer = new TargetGraphToActionGraph( + getBuckEventBus(), + ruleGenerator); + + ActionGraph actionGraph; + try { + TargetGraph targetGraph = getParser().buildTargetGraphForBuildTargets( + buildTargets, + options.getDefaultIncludes(), + getBuckEventBus(), + console, + environment, + options.getEnableProfiling()); + + actionGraph = transformer.apply(targetGraph); + buildTargets = ruleGenerator.getDownloadableTargets(); + } catch (BuildTargetException | BuildFileParseException e) { + console.printBuildFailureWithoutStacktrace(e); + return 1; + } + + int exitCode; + try (Build build = options.createBuild( + options.getBuckConfig(), + actionGraph, + getProjectFilesystem(), + getAndroidDirectoryResolver(), + getBuildEngine(), + getArtifactCache(), + console, + getBuckEventBus(), + Optional.absent(), + getCommandRunnerParams().getPlatform(), + getCommandRunnerParams().getEnvironment(), + getCommandRunnerParams().getObjectMapper(), + getCommandRunnerParams().getClock())) { + exitCode = build.executeAndPrintFailuresToConsole( + buildTargets, + options.isKeepGoing(), + console, + options.getPathToBuildReport()); + } + + getBuckEventBus().post(BuildEvent.finished(buildTargets, exitCode)); + + return exitCode; + } + + private FetchTargetNodeToBuildRuleTransformer createFetchTransformer( + BuildCommandOptions options) { + Optional defaultMavenRepo = options.getBuckConfig().getValue("download", "maven_repo"); + Downloader downloader = new HttpDownloader(Optional.absent(), defaultMavenRepo); + Description description = new RemoteFileDescription(downloader); + return new FetchTargetNodeToBuildRuleTransformer( + ImmutableSet.>of(description) + ); + } + + @Override + String getUsageIntro() { + return "fetch remote resources"; + } +} diff --git a/src/com/facebook/buck/cli/FetchTargetNodeToBuildRuleTransformer.java b/src/com/facebook/buck/cli/FetchTargetNodeToBuildRuleTransformer.java new file mode 100644 index 00000000000..5a09e52e02d --- /dev/null +++ b/src/com/facebook/buck/cli/FetchTargetNodeToBuildRuleTransformer.java @@ -0,0 +1,66 @@ +/* + * Copyright 2015-present Facebook, Inc. + * + * 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.facebook.buck.cli; + +import com.facebook.buck.model.BuildTarget; +import com.facebook.buck.parser.NoSuchBuildTargetException; +import com.facebook.buck.rules.BuildRule; +import com.facebook.buck.rules.BuildRuleResolver; +import com.facebook.buck.rules.Description; +import com.facebook.buck.rules.TargetGraph; +import com.facebook.buck.rules.TargetNode; +import com.facebook.buck.rules.TargetNodeToBuildRuleTransformer; +import com.google.common.collect.ImmutableSet; + +class FetchTargetNodeToBuildRuleTransformer implements TargetNodeToBuildRuleTransformer { + + private final ImmutableSet> descriptions; + // TODO(user): Allow the TargetToActionGraph to be stateless. + private final ImmutableSet.Builder downloadableTargets; + private final BuildTargetNodeToBuildRuleTransformer delegate; + + public FetchTargetNodeToBuildRuleTransformer( + ImmutableSet> descriptions) { + this.descriptions = descriptions; + + this.downloadableTargets = ImmutableSet.builder(); + this.delegate = new BuildTargetNodeToBuildRuleTransformer(); + } + + @Override + public BuildRule transform( + TargetGraph targetGraph, + BuildRuleResolver ruleResolver, + TargetNode targetNode) throws NoSuchBuildTargetException { + TargetNode node = substituteTargetNodeIfNecessary(targetNode); + return delegate.transform(targetGraph, ruleResolver, node); + } + + public ImmutableSet getDownloadableTargets() { + return downloadableTargets.build(); + } + + private TargetNode substituteTargetNodeIfNecessary(TargetNode node) { + for (Description description : descriptions) { + if (node.getDescription().getBuildRuleType().equals(description.getBuildRuleType())) { + downloadableTargets.add(node.getBuildTarget()); + return node.amend(description); + } + } + return node; + } +} diff --git a/src/com/facebook/buck/file/BUCK b/src/com/facebook/buck/file/BUCK index 8c8a0b3eee8..b2b61f3bb12 100644 --- a/src/com/facebook/buck/file/BUCK +++ b/src/com/facebook/buck/file/BUCK @@ -4,6 +4,7 @@ java_library( 'Downloader.java', 'DownloadEvent.java', 'DownloadProgressEvent.java', + 'ExplodingDownloader.java', 'HttpDownloader.java', 'MavenUrlDecoder.java', ], @@ -24,18 +25,20 @@ java_library( ], deps = [ ':downloader', - '//third-party/java/guava:guava', - '//third-party/java/jsr:jsr305', '//src/com/facebook/buck/event:event', + '//src/com/facebook/buck/io:io', '//src/com/facebook/buck/model:model', '//src/com/facebook/buck/rules:build_rule', '//src/com/facebook/buck/rules:rules', '//src/com/facebook/buck/step/fs:fs', '//src/com/facebook/buck/step:step', '//src/com/facebook/buck/util:exceptions', + '//third-party/java/guava:guava', '//third-party/java/infer-annotations:infer-annotations', + '//third-party/java/jsr:jsr305', ], visibility = [ + '//src/com/facebook/buck/cli:cli', '//src/com/facebook/buck/rules:types', ], ) diff --git a/src/com/facebook/buck/file/DownloadStep.java b/src/com/facebook/buck/file/DownloadStep.java index 3a96aa663b5..daf9fe52fce 100644 --- a/src/com/facebook/buck/file/DownloadStep.java +++ b/src/com/facebook/buck/file/DownloadStep.java @@ -48,7 +48,8 @@ public DownloadStep(Downloader downloader, URI url, HashCode sha1, Path output) public int execute(ExecutionContext context) throws InterruptedException { BuckEventBus eventBus = context.getBuckEventBus(); try { - downloader.fetch(eventBus, url, output); + Path resolved = context.getProjectFilesystem().resolve(output); + downloader.fetch(eventBus, url, resolved); HashCode readHash = Files.asByteSource(output.toFile()).hash(Hashing.sha1()); if (!sha1.equals(readHash)) { diff --git a/src/com/facebook/buck/file/ExplodingDownloader.java b/src/com/facebook/buck/file/ExplodingDownloader.java new file mode 100644 index 00000000000..050157991f2 --- /dev/null +++ b/src/com/facebook/buck/file/ExplodingDownloader.java @@ -0,0 +1,32 @@ +/* + * Copyright 2015-present Facebook, Inc. + * + * 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.facebook.buck.file; + +import com.facebook.buck.event.BuckEventBus; +import com.facebook.buck.util.HumanReadableException; + +import java.io.IOException; +import java.net.URI; +import java.nio.file.Path; + +public class ExplodingDownloader implements Downloader { + @Override + public void fetch(BuckEventBus eventBus, URI uri, Path output) throws IOException { + throw new HumanReadableException( + "Downloading files at runtime is disabled, please run 'buck fetch' before your build"); + } +} diff --git a/src/com/facebook/buck/file/RemoteFile.java b/src/com/facebook/buck/file/RemoteFile.java index 443943bcfba..d055308462b 100644 --- a/src/com/facebook/buck/file/RemoteFile.java +++ b/src/com/facebook/buck/file/RemoteFile.java @@ -26,7 +26,6 @@ import com.facebook.buck.step.Step; import com.facebook.buck.step.fs.CopyStep; import com.facebook.buck.step.fs.MakeCleanDirectoryStep; -import com.facebook.buck.util.HumanReadableException; import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; @@ -41,7 +40,6 @@ * build. */ public class RemoteFile extends AbstractBuildRule { - private final boolean isBuildTimeDownloadingOk; private final URI uri; private final HashCode sha1; private final Path output; @@ -50,13 +48,12 @@ public class RemoteFile extends AbstractBuildRule { public RemoteFile( BuildRuleParams params, SourcePathResolver resolver, - boolean isBuildTimeDownloadingOk, Downloader downloader, URI uri, HashCode sha1, String out) { super(params, resolver); - this.isBuildTimeDownloadingOk = isBuildTimeDownloadingOk; + this.uri = uri; this.sha1 = sha1; this.downloader = downloader; @@ -74,7 +71,6 @@ protected ImmutableCollection getInputsToCompareToOutput() { @Override protected RuleKey.Builder appendDetailsToRuleKey(RuleKey.Builder builder) { return builder - .setReflectively("donwnload-at-runtime", isBuildTimeDownloadingOk) .setReflectively("sha1", sha1.toString()) .setReflectively("out", output.toString()) .setReflectively("url", uri.toString()); @@ -83,11 +79,6 @@ protected RuleKey.Builder appendDetailsToRuleKey(RuleKey.Builder builder) { @Override public ImmutableList getBuildSteps( BuildContext context, BuildableContext buildableContext) { - if (!isBuildTimeDownloadingOk) { - throw new HumanReadableException( - "Downloading files at runtime is disabled, please run 'buck fetch' before your build"); - } - ImmutableList.Builder steps = ImmutableList.builder(); Path tempFile = BuildTargets.getBinPath( diff --git a/src/com/facebook/buck/file/RemoteFileDescription.java b/src/com/facebook/buck/file/RemoteFileDescription.java index a099b1dc666..4a229756e0b 100644 --- a/src/com/facebook/buck/file/RemoteFileDescription.java +++ b/src/com/facebook/buck/file/RemoteFileDescription.java @@ -31,13 +31,9 @@ public class RemoteFileDescription implements Description { public static final BuildRuleType TYPE = new BuildRuleType("remote_file"); - private final boolean isBuildTimeDownloadingOk; private final Downloader downloader; - public RemoteFileDescription( - boolean isBuildTimeDownloadingOk, - Downloader downloader) { - this.isBuildTimeDownloadingOk = isBuildTimeDownloadingOk; + public RemoteFileDescription(Downloader downloader) { this.downloader = downloader; } @@ -63,7 +59,6 @@ public BuildRule createBuildRule( return new RemoteFile( params, new SourcePathResolver(resolver), - isBuildTimeDownloadingOk, downloader, args.url, sha1, diff --git a/src/com/facebook/buck/rules/KnownBuildRuleTypes.java b/src/com/facebook/buck/rules/KnownBuildRuleTypes.java index 9f4bdfe5e18..7ac5e955cdb 100644 --- a/src/com/facebook/buck/rules/KnownBuildRuleTypes.java +++ b/src/com/facebook/buck/rules/KnownBuildRuleTypes.java @@ -58,6 +58,7 @@ import com.facebook.buck.cxx.PrebuiltCxxLibraryDescription; import com.facebook.buck.extension.BuckExtensionDescription; import com.facebook.buck.file.Downloader; +import com.facebook.buck.file.ExplodingDownloader; import com.facebook.buck.file.HttpDownloader; import com.facebook.buck.file.RemoteFileDescription; import com.facebook.buck.gwt.GwtBinaryDescription; @@ -347,8 +348,12 @@ static Builder createBuilder( // Default maven repo, if set Optional defaultMavenRepo = config.getValue("download", "maven_repo"); boolean downloadAtRuntimeOk = config.getBooleanValue("download", "in_build", false); - Downloader downloader = new HttpDownloader(Optional.absent(), defaultMavenRepo); - + Downloader downloader; + if (downloadAtRuntimeOk) { + downloader = new HttpDownloader(Optional.absent(), defaultMavenRepo); + } else { + downloader = new ExplodingDownloader(); + } Builder builder = builder(); @@ -429,7 +434,7 @@ static Builder createBuilder( pythonEnv, defaultCxxPlatform, cxxPlatforms)); - builder.register(new RemoteFileDescription(downloadAtRuntimeOk, downloader)); + builder.register(new RemoteFileDescription(downloader)); builder.register(new RobolectricTestDescription(androidBinaryOptions, testRuleTimeoutMs)); builder.register(new ShBinaryDescription()); builder.register(new ShTestDescription()); diff --git a/src/com/facebook/buck/rules/TargetNode.java b/src/com/facebook/buck/rules/TargetNode.java index 7607a61dded..c77d316915d 100644 --- a/src/com/facebook/buck/rules/TargetNode.java +++ b/src/com/facebook/buck/rules/TargetNode.java @@ -259,6 +259,26 @@ public final String toString() { return getBuildTarget().getFullyQualifiedName(); } + /** + * Return a copy of the current TargetNode, with the {@link Description} used for creating + * {@link BuildRule} instances switched out. + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + public TargetNode amend(Description description) { + try { + return new TargetNode( + description, + constructorArg, + ruleFactoryParams, + declaredDeps, + visibilityPatterns); + } catch (InvalidSourcePathInputException | NoSuchBuildTargetException e) { + // This is extremely unlikely to happen --- we've already created a TargetNode with these + // values before. + throw new RuntimeException(e); + } + } + @SuppressWarnings("serial") public static class InvalidSourcePathInputException extends Exception implements ExceptionWithHumanReadableMessage{ diff --git a/test/com/facebook/buck/cli/BUCK b/test/com/facebook/buck/cli/BUCK index 722ecfd1ae5..74baf3ddecd 100644 --- a/test/com/facebook/buck/cli/BUCK +++ b/test/com/facebook/buck/cli/BUCK @@ -132,6 +132,7 @@ java_test( '//third-party/java/ini4j:ini4j', '//third-party/java/jackson:jackson-core', '//third-party/java/jackson:jackson-databind', + '//third-party/java/jetty:jetty', '//third-party/java/jsr:jsr305', '//third-party/java/junit:junit', '//third-party/java/nailgun:nailgun', diff --git a/test/com/facebook/buck/cli/FetchCommandIntegrationTest.java b/test/com/facebook/buck/cli/FetchCommandIntegrationTest.java new file mode 100644 index 00000000000..1c62e43eed3 --- /dev/null +++ b/test/com/facebook/buck/cli/FetchCommandIntegrationTest.java @@ -0,0 +1,167 @@ +/* + * Copyright 2015-present Facebook, Inc. + * + * 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.facebook.buck.cli; + +import static java.nio.charset.StandardCharsets.UTF_16; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import com.facebook.buck.model.BuildTarget; +import com.facebook.buck.model.BuildTargetFactory; +import com.facebook.buck.testutil.integration.BuckBuildLog; +import com.facebook.buck.testutil.integration.DebuggableTemporaryFolder; +import com.facebook.buck.testutil.integration.HttpdForTests; +import com.facebook.buck.testutil.integration.ProjectWorkspace; +import com.facebook.buck.testutil.integration.TestDataHelper; +import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableSet; +import com.google.common.hash.HashCode; +import com.google.common.hash.Hashing; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; + +public class FetchCommandIntegrationTest { + + @Rule + public DebuggableTemporaryFolder temp = new DebuggableTemporaryFolder(); + + private static HttpdForTests httpd; + + @BeforeClass + public static void startHttpd() throws Exception { + httpd = new HttpdForTests(); + + httpd.addStaticContent("cheese"); + httpd.start(); + } + + @AfterClass + public static void shutdownHttpd() throws Exception { + httpd.close(); + } + + @Test + public void shouldBuildNothingIfThereAreNoFetchableRules() throws IOException { + ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario( + this, + "fetch_nothing", + temp); + workspace.setUp(); + + ProjectWorkspace.ProcessResult result = workspace.runBuckCommand("fetch", "//:example"); + + result.assertSuccess(); + + BuckBuildLog log = workspace.getBuildLog(); + ImmutableSet allTargets = log.getAllTargets(); + + assertFalse(allTargets.contains(BuildTargetFactory.newInstance("//:example"))); + } + + @Test + public void shouldFetchARemoteResourceIfThatIsTheExactTargetRequested() + throws IOException, URISyntaxException { + ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario( + this, + "fetch_concrete", + temp); + workspace.setUp(); + + // We don't know the URL of the file beforehand. Fix that. + addRemoteFileTarget(workspace); + + ProjectWorkspace.ProcessResult result = workspace.runBuckCommand("fetch", "//:remote"); + + result.assertSuccess(); + + BuckBuildLog log = workspace.getBuildLog(); + ImmutableSet allTargets = log.getAllTargets(); + + assertTrue(allTargets.contains(BuildTargetFactory.newInstance("//:remote"))); + } + + @Test + public void shouldNotFetchARemoteResourceIfNotIncludedInTheSetOfTargetsToBuild() + throws IOException, URISyntaxException { + ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario( + this, + "fetch_concrete", + temp); + workspace.setUp(); + + // We don't know the URL of the file beforehand. Fix that. + addRemoteFileTarget(workspace); + + ProjectWorkspace.ProcessResult result = workspace.runBuckCommand("fetch", "//:no-download"); + + result.assertSuccess(); + + BuckBuildLog log = workspace.getBuildLog(); + ImmutableSet allTargets = log.getAllTargets(); + + assertFalse(allTargets.contains(BuildTargetFactory.newInstance("//:remote"))); + } + + @Test + public void shouldOnlyExecuteDownloadableTargets() throws IOException, URISyntaxException { + ProjectWorkspace workspace = TestDataHelper.createProjectWorkspaceForScenario( + this, + "fetch_concrete", + temp); + workspace.setUp(); + + // We don't know the URL of the file beforehand. Fix that. + addRemoteFileTarget(workspace); + + ProjectWorkspace.ProcessResult result = workspace.runBuckCommand("fetch", "//:needs-download"); + + result.assertSuccess(); + + BuckBuildLog log = workspace.getBuildLog(); + ImmutableSet allTargets = log.getAllTargets(); + + assertTrue(allTargets.contains(BuildTargetFactory.newInstance("//:remote"))); + assertFalse(allTargets.contains(BuildTargetFactory.newInstance("//:needs-download"))); + } + + private void addRemoteFileTarget(ProjectWorkspace workspace) + throws IOException, URISyntaxException { + Path buckFile = workspace.resolve("BUCK"); + + String existingBuck = new String(Files.readAllBytes(buckFile), UTF_8); + + HashCode expectedHash = Hashing.sha1().hashString("cheese", UTF_16); + + String newRule = Joiner.on("\n").join( + "remote_file(name = 'remote',", + String.format(" url = '%s',", httpd.getUri("/cheese")), + String.format(" sha1 = '%s',", expectedHash.toString()), + " out = 'example.txt',", + ")"); + + Files.write(buckFile, (existingBuck + "\n" + newRule).getBytes(UTF_8)); + } +} diff --git a/test/com/facebook/buck/cli/MainTest.java b/test/com/facebook/buck/cli/MainTest.java index 9325d303c79..73d2eb9bbc2 100644 --- a/test/com/facebook/buck/cli/MainTest.java +++ b/test/com/facebook/buck/cli/MainTest.java @@ -107,6 +107,7 @@ private String getUsageString() { " build builds the specified target", " cache makes calls to the artifact cache", " clean deletes any generated files", + " fetch downloads remote resources to your local machine", " install builds and installs an APK", " project generates project configuration files for an IDE", " quickstart generates a default project directory", diff --git a/test/com/facebook/buck/cli/testdata/fetch_concrete/BUCK b/test/com/facebook/buck/cli/testdata/fetch_concrete/BUCK new file mode 100644 index 00000000000..37664c24178 --- /dev/null +++ b/test/com/facebook/buck/cli/testdata/fetch_concrete/BUCK @@ -0,0 +1,12 @@ +genrule( + name = 'no-download', + cmd = 'echo "hello world" > $OUT', + out = 'greeting.txt', +) + +genrule( + name = 'needs-download', + cmd = 'cat $(location :remote) > $OUT', + out = 'greeting2.txt', +) + diff --git a/test/com/facebook/buck/cli/testdata/fetch_nothing/A.java b/test/com/facebook/buck/cli/testdata/fetch_nothing/A.java new file mode 100644 index 00000000000..70c13c53482 --- /dev/null +++ b/test/com/facebook/buck/cli/testdata/fetch_nothing/A.java @@ -0,0 +1,23 @@ +/* + * Copyright 2015-present Facebook, Inc. + * + * 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.facebook.buck.example; + +public class A { + public A() { + // Does nothing. + } +} diff --git a/test/com/facebook/buck/cli/testdata/fetch_nothing/BUCK b/test/com/facebook/buck/cli/testdata/fetch_nothing/BUCK new file mode 100644 index 00000000000..e3b404101eb --- /dev/null +++ b/test/com/facebook/buck/cli/testdata/fetch_nothing/BUCK @@ -0,0 +1,5 @@ +java_library( + name = 'example', + srcs = [ 'A.java' ], +) + diff --git a/third-party/java/jetty/BUCK b/third-party/java/jetty/BUCK index 27e376328d1..46666f8a2db 100644 --- a/third-party/java/jetty/BUCK +++ b/third-party/java/jetty/BUCK @@ -18,6 +18,7 @@ java_library( visibility = [ '//src/com/facebook/buck/httpserver:', '//test/com/facebook/buck/file:file', + '//test/com/facebook/buck/cli:cli', '//test/com/facebook/buck/httpserver:', '//test/com/facebook/buck/testutil/integration:integration', ],