From 820f43d3bc7fb1aa1f257cccea3c7969d7627bbf Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 11 Nov 2013 17:07:22 +0000 Subject: [PATCH] Add grab command to collect script's dependencies Previously, run --local could be used to collect a script's dependencies in ./repository. However, with this mechanism it wasn't possible to collect the dependencies without running the application. This commit adds a new command, grab, that can be used to collect a script's dependencies in ./repository without having to run it. run is configured with ./repository as a location in which it can find its dependencies so that the previously collected dependencies can be used when subsequently running the app. As part of this work RunCommand and TestCommand have been refactored to use common code for their common options: --no-guess-imports --no-guess-dependencies --classpath Previously, the declaration and handling of the options was duplicated in the two classes. GrabCommand also has these three options and uses the same common code. --- spring-boot-cli/grab-samples/grab.groovy | 4 + .../cli/command/CompilerOptionHandler.java | 63 ++++++++++++++ .../cli/command/DefaultCommandFactory.java | 6 +- .../boot/cli/command/GrabCommand.java | 74 ++++++++++++++++ .../boot/cli/command/RunCommand.java | 78 +++++------------ .../boot/cli/command/ScriptCommand.java | 8 ++ .../boot/cli/command/TestCommand.java | 61 ++----------- .../boot/cli/compiler/GroovyCompiler.java | 26 +++++- .../compiler/GroovyCompilerConfiguration.java | 13 ++- .../GroovyCompilerConfigurationAdapter.java | 87 +++++++++++++++++++ .../RepositoryConfigurationFactory.java | 54 ++++++++++++ .../cli/compiler/grape/AetherGrapeEngine.java | 28 ++---- .../grape/RepositoryConfiguration.java | 70 +++++++++++++++ .../SpringApplicationRunnerConfiguration.java | 6 -- .../springframework/boot/cli/CliTester.java | 43 ++++----- .../boot/cli/GrabCommandIntegrationTests.java | 62 +++++++++++++ .../grape/AetherGrapeEngineTests.java | 4 +- 17 files changed, 525 insertions(+), 162 deletions(-) create mode 100644 spring-boot-cli/grab-samples/grab.groovy create mode 100644 spring-boot-cli/src/main/java/org/springframework/boot/cli/command/CompilerOptionHandler.java create mode 100644 spring-boot-cli/src/main/java/org/springframework/boot/cli/command/GrabCommand.java create mode 100644 spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/GroovyCompilerConfigurationAdapter.java create mode 100644 spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/RepositoryConfigurationFactory.java create mode 100644 spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/RepositoryConfiguration.java create mode 100644 spring-boot-cli/src/test/java/org/springframework/boot/cli/GrabCommandIntegrationTests.java diff --git a/spring-boot-cli/grab-samples/grab.groovy b/spring-boot-cli/grab-samples/grab.groovy new file mode 100644 index 0000000000..05a3b9d5fd --- /dev/null +++ b/spring-boot-cli/grab-samples/grab.groovy @@ -0,0 +1,4 @@ +@Grab('spring-jdbc') +class GrabTest { + +} \ No newline at end of file diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/CompilerOptionHandler.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/CompilerOptionHandler.java new file mode 100644 index 0000000000..dce0d79c8b --- /dev/null +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/CompilerOptionHandler.java @@ -0,0 +1,63 @@ +/* + * Copyright 2012-2013 the original author or authors. + * + * 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 org.springframework.boot.cli.command; + +import joptsimple.OptionSpec; + +import static java.util.Arrays.asList; + +/** + * An {@link OptionHandler} for commands that result in the compilation of one or more + * Groovy scripts + * + * @author Andy Wilkinson + */ +public class CompilerOptionHandler extends OptionHandler { + + private OptionSpec noGuessImportsOption; + + private OptionSpec noGuessDependenciesOption; + + private OptionSpec classpathOption; + + @Override + protected final void options() { + this.noGuessImportsOption = option("no-guess-imports", + "Do not attempt to guess imports"); + this.noGuessDependenciesOption = option("no-guess-dependencies", + "Do not attempt to guess dependencies"); + this.classpathOption = option(asList("classpath", "cp"), + "Additional classpath entries").withRequiredArg(); + doOptions(); + } + + protected void doOptions() { + } + + public OptionSpec getNoGuessImportsOption() { + return this.noGuessImportsOption; + } + + public OptionSpec getNoGuessDependenciesOption() { + return this.noGuessDependenciesOption; + } + + public OptionSpec getClasspathOption() { + return this.classpathOption; + } + +} diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/DefaultCommandFactory.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/DefaultCommandFactory.java index 08d7dc1b6d..ca05222207 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/DefaultCommandFactory.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/DefaultCommandFactory.java @@ -30,9 +30,9 @@ import org.springframework.boot.cli.CommandFactory; */ public class DefaultCommandFactory implements CommandFactory { - private static final List DEFAULT_COMMANDS = Arrays - . asList(new VersionCommand(), new RunCommand(), new CleanCommand(), - new TestCommand()); + private static final List DEFAULT_COMMANDS = Arrays. asList( + new VersionCommand(), new RunCommand(), new CleanCommand(), + new TestCommand(), new GrabCommand()); @Override public Collection getCommands() { diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/GrabCommand.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/GrabCommand.java new file mode 100644 index 0000000000..28cde0dfd7 --- /dev/null +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/GrabCommand.java @@ -0,0 +1,74 @@ +/* + * Copyright 2012-2013 the original author or authors. + * + * 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 org.springframework.boot.cli.command; + +import java.io.File; +import java.util.List; + +import joptsimple.OptionSet; + +import org.springframework.boot.cli.Command; +import org.springframework.boot.cli.compiler.GroovyCompiler; +import org.springframework.boot.cli.compiler.GroovyCompilerConfiguration; +import org.springframework.boot.cli.compiler.GroovyCompilerConfigurationAdapter; +import org.springframework.boot.cli.compiler.RepositoryConfigurationFactory; +import org.springframework.boot.cli.compiler.grape.RepositoryConfiguration; +import org.springframework.util.StringUtils; + +/** + * {@link Command} to grab the dependencies of one or more Groovy scripts + * + * @author Andy Wilkinson + */ +public class GrabCommand extends OptionParsingCommand { + + public GrabCommand() { + super("grab", "Download a spring groovy script's dependencies to ./repository", + new GrabOptionHandler()); + } + + private static final class GrabOptionHandler extends CompilerOptionHandler { + + @Override + protected void run(OptionSet options) throws Exception { + FileOptions fileOptions = new FileOptions(options); + + List repositoryConfiguration = RepositoryConfigurationFactory + .createDefaultRepositoryConfiguration(); + repositoryConfiguration.add(0, new RepositoryConfiguration("local", new File( + getM2HomeDirectory(), "repository").toURI(), true)); + + GroovyCompilerConfiguration configuration = new GroovyCompilerConfigurationAdapter( + options, this, repositoryConfiguration); + + if (System.getProperty("grape.root") == null) { + System.setProperty("grape.root", "."); + } + + GroovyCompiler groovyCompiler = new GroovyCompiler(configuration); + groovyCompiler.compile(fileOptions.getFilesArray()); + } + + private File getM2HomeDirectory() { + String mavenRoot = System.getProperty("maven.home"); + if (StringUtils.hasLength(mavenRoot)) { + return new File(mavenRoot); + } + return new File(System.getProperty("user.home"), ".m2"); + } + } +} diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/RunCommand.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/RunCommand.java index 5cc3357836..78667de4e5 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/RunCommand.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/RunCommand.java @@ -17,13 +17,18 @@ package org.springframework.boot.cli.command; import java.awt.Desktop; +import java.io.File; +import java.util.List; import java.util.logging.Level; import joptsimple.OptionSet; import joptsimple.OptionSpec; import org.springframework.boot.cli.Command; +import org.springframework.boot.cli.compiler.GroovyCompilerConfigurationAdapter; import org.springframework.boot.cli.compiler.GroovyCompilerScope; +import org.springframework.boot.cli.compiler.RepositoryConfigurationFactory; +import org.springframework.boot.cli.compiler.grape.RepositoryConfiguration; import org.springframework.boot.cli.runner.SpringApplicationRunner; import org.springframework.boot.cli.runner.SpringApplicationRunnerConfiguration; @@ -53,41 +58,25 @@ public class RunCommand extends OptionParsingCommand { } } - private static class RunOptionHandler extends OptionHandler { + private static class RunOptionHandler extends CompilerOptionHandler { private OptionSpec watchOption; private OptionSpec editOption; - private OptionSpec noGuessImportsOption; - - private OptionSpec noGuessDependenciesOption; - private OptionSpec verboseOption; private OptionSpec quietOption; - private OptionSpec localOption; - - private OptionSpec classpathOption; - private SpringApplicationRunner runner; @Override - protected void options() { + protected void doOptions() { this.watchOption = option("watch", "Watch the specified file for changes"); - this.localOption = option("local", - "Accumulate the dependencies in a local folder (./repository)"); this.editOption = option(asList("edit", "e"), "Open the file with the default system editor"); - this.noGuessImportsOption = option("no-guess-imports", - "Do not attempt to guess imports"); - this.noGuessDependenciesOption = option("no-guess-dependencies", - "Do not attempt to guess dependencies"); this.verboseOption = option(asList("verbose", "v"), "Verbose logging"); this.quietOption = option(asList("quiet", "q"), "Quiet logging"); - this.classpathOption = option(asList("classpath", "cp"), - "Additional classpath entries").withRequiredArg(); } @Override @@ -98,11 +87,14 @@ public class RunCommand extends OptionParsingCommand { Desktop.getDesktop().edit(fileOptions.getFiles().get(0)); } + List repositoryConfiguration = RepositoryConfigurationFactory + .createDefaultRepositoryConfiguration(); + repositoryConfiguration.add(0, new RepositoryConfiguration("local", new File( + "repository").toURI(), true)); + SpringApplicationRunnerConfiguration configuration = new SpringApplicationRunnerConfigurationAdapter( - options); - if (configuration.isLocal() && System.getProperty("grape.root") == null) { - System.setProperty("grape.root", "."); - } + options, this, repositoryConfiguration); + this.runner = new SpringApplicationRunner(configuration, fileOptions.getFilesArray(), fileOptions.getArgsArray()); this.runner.compileAndRun(); @@ -112,13 +104,14 @@ public class RunCommand extends OptionParsingCommand { * Simple adapter class to present the {@link OptionSet} as a * {@link SpringApplicationRunnerConfiguration}. */ - private class SpringApplicationRunnerConfigurationAdapter implements + private class SpringApplicationRunnerConfigurationAdapter extends + GroovyCompilerConfigurationAdapter implements SpringApplicationRunnerConfiguration { - private OptionSet options; - - public SpringApplicationRunnerConfigurationAdapter(OptionSet options) { - this.options = options; + public SpringApplicationRunnerConfigurationAdapter(OptionSet options, + CompilerOptionHandler optionHandler, + List repositoryConfiguration) { + super(options, optionHandler, repositoryConfiguration); } @Override @@ -128,44 +121,19 @@ public class RunCommand extends OptionParsingCommand { @Override public boolean isWatchForFileChanges() { - return this.options.has(RunOptionHandler.this.watchOption); - } - - @Override - public boolean isGuessImports() { - return !this.options.has(RunOptionHandler.this.noGuessImportsOption); - } - - @Override - public boolean isGuessDependencies() { - return !this.options.has(RunOptionHandler.this.noGuessDependenciesOption); - } - - @Override - public boolean isLocal() { - return this.options.has(RunOptionHandler.this.localOption); + return getOptions().has(RunOptionHandler.this.watchOption); } @Override public Level getLogLevel() { - if (this.options.has(RunOptionHandler.this.verboseOption)) { + if (getOptions().has(RunOptionHandler.this.verboseOption)) { return Level.FINEST; } - if (this.options.has(RunOptionHandler.this.quietOption)) { + if (getOptions().has(RunOptionHandler.this.quietOption)) { return Level.OFF; } return Level.INFO; } - - @Override - public String[] getClasspath() { - if (this.options.has(RunOptionHandler.this.classpathOption)) { - return this.options.valueOf(RunOptionHandler.this.classpathOption) - .split(":"); - } - return NO_CLASSPATH; - } - } } diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/ScriptCommand.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/ScriptCommand.java index 0c248514d9..a615134d0b 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/ScriptCommand.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/ScriptCommand.java @@ -28,6 +28,7 @@ import java.io.IOException; import java.net.URL; import java.util.Collection; import java.util.Collections; +import java.util.List; import joptsimple.OptionParser; @@ -37,6 +38,8 @@ import org.springframework.boot.cli.OptionHelp; import org.springframework.boot.cli.compiler.GroovyCompiler; import org.springframework.boot.cli.compiler.GroovyCompilerConfiguration; import org.springframework.boot.cli.compiler.GroovyCompilerScope; +import org.springframework.boot.cli.compiler.RepositoryConfigurationFactory; +import org.springframework.boot.cli.compiler.grape.RepositoryConfiguration; import org.springframework.util.FileCopyUtils; /** @@ -271,6 +274,11 @@ public class ScriptCommand implements Command { return NO_CLASSPATH; } + @Override + public List getRepositoryConfiguration() { + return RepositoryConfigurationFactory.createDefaultRepositoryConfiguration(); + } + } } diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/TestCommand.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/TestCommand.java index b612f066b5..6b7079f09b 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/TestCommand.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/TestCommand.java @@ -17,15 +17,12 @@ package org.springframework.boot.cli.command; import joptsimple.OptionSet; -import joptsimple.OptionSpec; import org.springframework.boot.cli.Command; -import org.springframework.boot.cli.compiler.GroovyCompilerScope; +import org.springframework.boot.cli.compiler.GroovyCompilerConfigurationAdapter; import org.springframework.boot.cli.testrunner.TestRunner; import org.springframework.boot.cli.testrunner.TestRunnerConfiguration; -import static java.util.Arrays.asList; - /** * {@link Command} to run a groovy test script or scripts. * @@ -43,31 +40,15 @@ public class TestCommand extends OptionParsingCommand { return "[options] [--] [args]"; } - private static class TestOptionHandler extends OptionHandler { - - private OptionSpec noGuessImportsOption; - - private OptionSpec noGuessDependenciesOption; - - private OptionSpec classpathOption; + private static class TestOptionHandler extends CompilerOptionHandler { private TestRunner runner; - @Override - protected void options() { - this.noGuessImportsOption = option("no-guess-imports", - "Do not attempt to guess imports"); - this.noGuessDependenciesOption = option("no-guess-dependencies", - "Do not attempt to guess dependencies"); - this.classpathOption = option(asList("classpath", "cp"), - "Additional classpath entries").withRequiredArg(); - } - @Override protected void run(OptionSet options) throws Exception { FileOptions fileOptions = new FileOptions(options); TestRunnerConfiguration configuration = new TestRunnerConfigurationAdapter( - options); + options, this); this.runner = new TestRunner(configuration, fileOptions.getFilesArray(), fileOptions.getArgsArray()); this.runner.compileAndRunTests(); @@ -77,39 +58,13 @@ public class TestCommand extends OptionParsingCommand { * Simple adapter class to present the {@link OptionSet} as a * {@link TestRunnerConfiguration}. */ - private class TestRunnerConfigurationAdapter implements TestRunnerConfiguration { + private class TestRunnerConfigurationAdapter extends + GroovyCompilerConfigurationAdapter implements TestRunnerConfiguration { - private OptionSet options; - - public TestRunnerConfigurationAdapter(OptionSet options) { - this.options = options; + public TestRunnerConfigurationAdapter(OptionSet options, + CompilerOptionHandler optionHandler) { + super(options, optionHandler); } - - @Override - public GroovyCompilerScope getScope() { - return GroovyCompilerScope.DEFAULT; - } - - @Override - public boolean isGuessImports() { - return !this.options.has(TestOptionHandler.this.noGuessImportsOption); - } - - @Override - public boolean isGuessDependencies() { - return !this.options - .has(TestOptionHandler.this.noGuessDependenciesOption); - } - - @Override - public String[] getClasspath() { - if (this.options.has(TestOptionHandler.this.classpathOption)) { - return this.options.valueOf(TestOptionHandler.this.classpathOption) - .split(":"); - } - return NO_CLASSPATH; - } - } } } diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/GroovyCompiler.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/GroovyCompiler.java index 3a06e3586c..d575a56e0f 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/GroovyCompiler.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/GroovyCompiler.java @@ -41,8 +41,11 @@ import org.codehaus.groovy.control.customizers.CompilationCustomizer; import org.codehaus.groovy.control.customizers.ImportCustomizer; import org.codehaus.groovy.transform.ASTTransformation; import org.codehaus.groovy.transform.ASTTransformationVisitor; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.repository.RepositoryPolicy; import org.springframework.boot.cli.compiler.grape.AetherGrapeEngine; import org.springframework.boot.cli.compiler.grape.GrapeEngineInstaller; +import org.springframework.boot.cli.compiler.grape.RepositoryConfiguration; import org.springframework.boot.cli.compiler.transformation.DependencyAutoConfigurationTransformation; import org.springframework.boot.cli.compiler.transformation.GrabResolversAutoConfigurationTransformation; import org.springframework.boot.cli.compiler.transformation.ResolveDependencyCoordinatesTransformation; @@ -88,7 +91,8 @@ public class GroovyCompiler { this.loader = createLoader(configuration); this.coordinatesResolver = new PropertiesArtifactCoordinatesResolver(this.loader); - GrapeEngineInstaller.install(new AetherGrapeEngine(this.loader)); + GrapeEngineInstaller.install(new AetherGrapeEngine(this.loader, + createRepositories(configuration.getRepositoryConfiguration()))); this.loader.getConfiguration().addCompilationCustomizers( new CompilerAutoConfigureCustomizer()); @@ -115,6 +119,26 @@ public class GroovyCompiler { return loader; } + private List createRepositories( + List repositoryConfigurations) { + List repositories = new ArrayList( + repositoryConfigurations.size()); + for (RepositoryConfiguration repositoryConfiguration : repositoryConfigurations) { + RemoteRepository.Builder builder = new RemoteRepository.Builder( + repositoryConfiguration.getName(), "default", repositoryConfiguration + .getUri().toASCIIString()); + + if (!repositoryConfiguration.getSnapshotsEnabled()) { + builder.setSnapshotPolicy(new RepositoryPolicy(false, + RepositoryPolicy.UPDATE_POLICY_NEVER, + RepositoryPolicy.CHECKSUM_POLICY_IGNORE)); + } + + repositories.add(builder.build()); + } + return repositories; + } + public void addCompilationCustomizers(CompilationCustomizer... customizers) { this.loader.getConfiguration().addCompilationCustomizers(customizers); } diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/GroovyCompilerConfiguration.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/GroovyCompilerConfiguration.java index dea85bc990..233869c12e 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/GroovyCompilerConfiguration.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/GroovyCompilerConfiguration.java @@ -16,15 +16,20 @@ package org.springframework.boot.cli.compiler; +import java.util.List; + +import org.springframework.boot.cli.compiler.grape.RepositoryConfiguration; + /** * Configuration for the {@link GroovyCompiler}. * * @author Phillip Webb + * @author Andy Wilkinson */ public interface GroovyCompilerConfiguration { /** - * Constant to be used when there is not {@link #getClasspath() classpath}. + * Constant to be used when there is no {@link #getClasspath() classpath}. */ public static final String[] NO_CLASSPATH = {}; @@ -48,4 +53,10 @@ public interface GroovyCompilerConfiguration { */ String[] getClasspath(); + /** + * @return the configuration for the repositories that will be used by the compiler to + * resolve dependencies. + */ + List getRepositoryConfiguration(); + } diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/GroovyCompilerConfigurationAdapter.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/GroovyCompilerConfigurationAdapter.java new file mode 100644 index 0000000000..b2688e5c4d --- /dev/null +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/GroovyCompilerConfigurationAdapter.java @@ -0,0 +1,87 @@ +/* + * Copyright 2012-2013 the original author or authors. + * + * 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 org.springframework.boot.cli.compiler; + +import java.util.List; + +import joptsimple.OptionSet; +import joptsimple.OptionSpec; + +import org.springframework.boot.cli.command.CompilerOptionHandler; +import org.springframework.boot.cli.compiler.grape.RepositoryConfiguration; + +/** + * Simple adapter class to present an {@link OptionSet} as a + * {@link GroovyCompilerConfiguration} + * + * @author Andy Wilkinson + */ +public class GroovyCompilerConfigurationAdapter implements GroovyCompilerConfiguration { + + private final OptionSet options; + + private final CompilerOptionHandler optionHandler; + + private final List repositoryConfiguration; + + protected GroovyCompilerConfigurationAdapter(OptionSet optionSet, + CompilerOptionHandler compilerOptionHandler) { + this(optionSet, compilerOptionHandler, RepositoryConfigurationFactory + .createDefaultRepositoryConfiguration()); + } + + public GroovyCompilerConfigurationAdapter(OptionSet optionSet, + CompilerOptionHandler compilerOptionHandler, + List repositoryConfiguration) { + this.options = optionSet; + this.optionHandler = compilerOptionHandler; + this.repositoryConfiguration = repositoryConfiguration; + } + + protected OptionSet getOptions() { + return this.options; + } + + @Override + public GroovyCompilerScope getScope() { + return GroovyCompilerScope.DEFAULT; + } + + @Override + public boolean isGuessImports() { + return !this.options.has(this.optionHandler.getNoGuessImportsOption()); + } + + @Override + public boolean isGuessDependencies() { + return !this.options.has(this.optionHandler.getNoGuessDependenciesOption()); + } + + @Override + public String[] getClasspath() { + OptionSpec classpathOption = this.optionHandler.getClasspathOption(); + if (this.options.has(classpathOption)) { + return this.options.valueOf(classpathOption).split(":"); + } + return NO_CLASSPATH; + } + + @Override + public List getRepositoryConfiguration() { + return this.repositoryConfiguration; + } +} diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/RepositoryConfigurationFactory.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/RepositoryConfigurationFactory.java new file mode 100644 index 0000000000..df560c3b10 --- /dev/null +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/RepositoryConfigurationFactory.java @@ -0,0 +1,54 @@ +/* + * Copyright 2012-2013 the original author or authors. + * + * 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 org.springframework.boot.cli.compiler; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +import org.springframework.boot.cli.compiler.grape.RepositoryConfiguration; + +/** + * @author Andy Wilkinson + */ +public final class RepositoryConfigurationFactory { + + private static final RepositoryConfiguration MAVEN_CENTRAL = new RepositoryConfiguration( + "central", URI.create("http://repo1.maven.org/maven2/"), false); + + private static final RepositoryConfiguration SPRING_MILESTONE = new RepositoryConfiguration( + "spring-milestone", URI.create("http://repo.spring.io/milestone"), false); + + private static final RepositoryConfiguration SPRING_SNAPSHOT = new RepositoryConfiguration( + "spring-snapshot", URI.create("http://repo.spring.io/snapshot"), true); + + /** + * @return the newly-created default repository configuration + */ + public static List createDefaultRepositoryConfiguration() { + List repositoryConfiguration = new ArrayList(); + + repositoryConfiguration.add(MAVEN_CENTRAL); + + if (!Boolean.getBoolean("disableSpringSnapshotRepos")) { + repositoryConfiguration.add(SPRING_SNAPSHOT); + repositoryConfiguration.add(SPRING_MILESTONE); + } + + return repositoryConfiguration; + } +} diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngine.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngine.java index dba7010833..60487a5a99 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngine.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngine.java @@ -25,10 +25,8 @@ import java.net.URI; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import java.util.Set; import org.apache.maven.repository.internal.MavenRepositorySystemUtils; import org.eclipse.aether.DefaultRepositorySystemSession; @@ -80,9 +78,10 @@ public class AetherGrapeEngine implements GrapeEngine { private final RepositorySystem repositorySystem; - private final Set repositories; + private final List repositories; - public AetherGrapeEngine(GroovyClassLoader classLoader) { + public AetherGrapeEngine(GroovyClassLoader classLoader, + List remoteRepositories) { this.classLoader = classLoader; this.repositorySystem = createServiceLocator().getService(RepositorySystem.class); DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession(); @@ -91,7 +90,7 @@ public class AetherGrapeEngine implements GrapeEngine { .newLocalRepositoryManager(session, localRepository); session.setLocalRepositoryManager(localRepositoryManager); this.session = session; - this.repositories = getRemoteRepositories(); + this.repositories = new ArrayList(remoteRepositories); this.progressReporter = getProgressReporter(session); } @@ -125,22 +124,6 @@ public class AetherGrapeEngine implements GrapeEngine { return new File(System.getProperty("user.home"), ".m2"); } - private Set getRemoteRepositories() { - LinkedHashSet repositories = new LinkedHashSet(); - String grapeRoot = System.getProperty("grape.root"); - if (StringUtils.hasLength(grapeRoot)) { - addRemoteRepository(repositories, "local", new File( - getDefaultM2HomeDirectory(), "repository").toURI().toASCIIString()); - } - addRemoteRepository(repositories, "central", "http://repo1.maven.org/maven2/"); - return repositories; - } - - private void addRemoteRepository(Set repositories, String id, - String url) { - repositories.add(new RemoteRepository.Builder(id, "default", url).build()); - } - private ProgressReporter getProgressReporter(DefaultRepositorySystemSession session) { if (Boolean.getBoolean("groovy.grape.report.downloads")) { return new DetailedProgressReporter(session, System.out); @@ -263,7 +246,8 @@ public class AetherGrapeEngine implements GrapeEngine { String name = (String) args.get("name"); String root = (String) args.get("root"); - addRemoteRepository(this.repositories, name, root); + this.repositories + .add(new RemoteRepository.Builder(name, "default", root).build()); } @Override diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/RepositoryConfiguration.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/RepositoryConfiguration.java new file mode 100644 index 0000000000..601c7db0b3 --- /dev/null +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/grape/RepositoryConfiguration.java @@ -0,0 +1,70 @@ +/* + * Copyright 2012-2013 the original author or authors. + * + * 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 org.springframework.boot.cli.compiler.grape; + +import java.net.URI; + +/** + * The configuration of a repository + * + * @author Andy Wilkinson + */ +public final class RepositoryConfiguration { + + private final String name; + + private final URI uri; + + private final boolean snapshotsEnabled; + + /** + * Creates a new {@code RepositoryConfiguration}. + * + * @param name The name of the repository + * @param uri The uri of the repository + * @param snapshotsEnabled {@code true} if the repository should enable access to + * snapshots, {@code false} otherwise + */ + public RepositoryConfiguration(String name, URI uri, boolean snapshotsEnabled) { + this.name = name; + this.uri = uri; + this.snapshotsEnabled = snapshotsEnabled; + } + + /** + * @return the name of the repository + */ + public String getName() { + return this.name; + } + + /** + * @return the uri of the repository + */ + public URI getUri() { + return this.uri; + } + + /** + * @return {@code true} if the repository should enable access to snapshots, + * {@code false} otherwise + */ + public boolean getSnapshotsEnabled() { + return this.snapshotsEnabled; + } + +} \ No newline at end of file diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/runner/SpringApplicationRunnerConfiguration.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/runner/SpringApplicationRunnerConfiguration.java index c587111f55..1c31131001 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/runner/SpringApplicationRunnerConfiguration.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/runner/SpringApplicationRunnerConfiguration.java @@ -37,10 +37,4 @@ public interface SpringApplicationRunnerConfiguration extends GroovyCompilerConf * Returns the logging level to use. */ Level getLogLevel(); - - /** - * Returns {@code true} if the dependencies should be cached locally - */ - boolean isLocal(); - } diff --git a/spring-boot-cli/src/test/java/org/springframework/boot/cli/CliTester.java b/spring-boot-cli/src/test/java/org/springframework/boot/cli/CliTester.java index 7431e4e537..2f1121b288 100644 --- a/spring-boot-cli/src/test/java/org/springframework/boot/cli/CliTester.java +++ b/spring-boot-cli/src/test/java/org/springframework/boot/cli/CliTester.java @@ -34,6 +34,8 @@ import org.junit.runners.model.Statement; import org.springframework.boot.OutputCapture; import org.springframework.boot.cli.command.AbstractCommand; import org.springframework.boot.cli.command.CleanCommand; +import org.springframework.boot.cli.command.GrabCommand; +import org.springframework.boot.cli.command.OptionParsingCommand; import org.springframework.boot.cli.command.RunCommand; import org.springframework.boot.cli.command.TestCommand; @@ -42,6 +44,7 @@ import org.springframework.boot.cli.command.TestCommand; * * @author Phillip Webb * @author Dave Syer + * @author Andy Wilkinson */ public class CliTester implements TestRule { @@ -62,35 +65,35 @@ public class CliTester implements TestRule { } public String run(String... args) throws Exception { - final String[] sources = getSources(args); - Future future = Executors.newSingleThreadExecutor().submit( - new Callable() { - @Override - public RunCommand call() throws Exception { - RunCommand command = new RunCommand(); - command.run(sources); - return command; - } - }); + Future future = submitCommand(new RunCommand(), args); this.commands.add(future.get(this.timeout, TimeUnit.MILLISECONDS)); return getOutput(); } public String test(String... args) throws Exception { - final String[] sources = getSources(args); - Future future = Executors.newSingleThreadExecutor().submit( - new Callable() { - @Override - public TestCommand call() throws Exception { - TestCommand command = new TestCommand(); - command.run(sources); - return command; - } - }); + Future future = submitCommand(new TestCommand(), args); this.commands.add(future.get(this.timeout, TimeUnit.MILLISECONDS)); return getOutput(); } + public String grab(String... args) throws Exception { + Future future = submitCommand(new GrabCommand(), args); + this.commands.add(future.get(this.timeout, TimeUnit.MILLISECONDS)); + return getOutput(); + } + + private Future submitCommand(final T command, + String... args) { + final String[] sources = getSources(args); + return Executors.newSingleThreadExecutor().submit(new Callable() { + @Override + public T call() throws Exception { + command.run(sources); + return command; + } + }); + } + protected String[] getSources(String... args) { final String[] sources = new String[args.length]; for (int i = 0; i < args.length; i++) { diff --git a/spring-boot-cli/src/test/java/org/springframework/boot/cli/GrabCommandIntegrationTests.java b/spring-boot-cli/src/test/java/org/springframework/boot/cli/GrabCommandIntegrationTests.java new file mode 100644 index 0000000000..bd2ef75541 --- /dev/null +++ b/spring-boot-cli/src/test/java/org/springframework/boot/cli/GrabCommandIntegrationTests.java @@ -0,0 +1,62 @@ +/* + * Copyright 2012-2013 the original author or authors. + * + * 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 org.springframework.boot.cli; + +import java.io.File; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.springframework.boot.cli.command.GrabCommand; +import org.springframework.util.FileSystemUtils; + +import static org.junit.Assert.assertTrue; + +/** + * Integration tests for {@link GrabCommand} + * + * @author Andy Wilkinson + */ +public class GrabCommandIntegrationTests { + + @Rule + public CliTester cli = new CliTester("grab-samples/"); + + @Before + @After + public void deleteLocalRepository() { + FileSystemUtils.deleteRecursively(new File("target/repository")); + } + + @Test + public void grab() throws Exception { + System.setProperty("grape.root", "target"); + System.setProperty("groovy.grape.report.downloads", "true"); + + try { + String output = this.cli.grab("grab.groovy"); + assertTrue(output.contains("Downloading: file:")); + assertTrue(new File("target/repository/org/springframework/spring-jdbc") + .isDirectory()); + } + finally { + System.clearProperty("grape.root"); + System.clearProperty("groovy.grape.report.downloads"); + } + } +} diff --git a/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngineTests.java b/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngineTests.java index 21880af3d0..2debedf152 100644 --- a/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngineTests.java +++ b/spring-boot-cli/src/test/java/org/springframework/boot/cli/compiler/grape/AetherGrapeEngineTests.java @@ -22,6 +22,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import org.eclipse.aether.repository.RemoteRepository; import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -36,7 +37,8 @@ public class AetherGrapeEngineTests { private final GroovyClassLoader groovyClassLoader = new GroovyClassLoader(); private final AetherGrapeEngine grapeEngine = new AetherGrapeEngine( - this.groovyClassLoader); + this.groovyClassLoader, Arrays.asList(new RemoteRepository.Builder("central", + "default", "http://repo1.maven.org/maven2/").build())); @Test public void dependencyResolution() {