It turns out that loader.path=. was pathological and before this
change ended up making the classpath empty (loader.path=.,lib/
would have fixed it). With this change the old behaviour is still
supported, but if the only user-supplied path entry is "." (or
empty) then it is now kept, and translates into the root of the
current archive if running as "java -jar ...".
Fixes gh-270
Update the CLI Groovy InnerLoader to not expose URLs. This prevents the
'TLD skipped' log messages from Tomcat that occurred previously due to
the InnerLoader and parent returning the same URLs.
Fixes gh-277
Change CLI generated JARs to use the standard `JarLauncher` instead of
a custom `JarRunner`. The `PackagedSpringApplicationLauncher` is used
as the `Start-Class` which in turn calls `SpringApplication.run()`.
A new command, jar, has been added to the CLI. The command can be
used to create a self-contained executable JAR file from a CLI app.
Basic usage is:
spring jar <jar-name> <source-files>
For example:
spring jar my-app.jar *.groovy
The resulting jar will contain the classes generated by compiling the
source files, all of the application's dependencies, and entries
on the application's classpath.
By default a CLI application has the current working directory on
its classpath. This can be overridden using the --classpath option.
Any file that is referenced directly by the classpath is always
included in the jar. Any file that is found a result of being
contained within a directory that is on the classpath is subject to
filtering to determine whether or not it should be included. The
default includes are public/**, static/**, resources/**,
META-INF/**, *. The default excludes are .*, repository/**, build/**,
target/**. To be included in the jar, a file must match one of the
includes and none of the excludes. The filters can be overridden using
the --include and --exclude options.
Closes#241
By convention, Ruby code is indented using two spaces ( ) per-level.
The code used tabs (\t) previously and therefore wasn't idiomatic.
This change updates the indenting to use two spaces.
This change adds support for --HEAD builds to the Homebrew formula. It
defines a conditional dependency on Maven and builds the -cli project
during install. The location to install from is abstracted out so
that code is identical regardless of whether the build is --HEAD or
mainline.
Update `GroovyCompiler` and `AetherGrapeEngineFactory` to use the
recently added `spring-boot-dependency-tools` in favor of loading
dependency information from a generated properties file.
--verbose seems to be only for CLI logging (so really only
for dependency resolution). --debug is interpreted by SpringApplication
but up to now has been extracted and deleted from the command line
by the CommandRunner. This change makes --debug set a System property
*and* pass it down to the application (if used with -- separator).
Fixes gh-266
Use `maven-failsafe-plugin` to run CLI integration tests as part of
the `spring-boot-cli` project, removing the need for
`spring-boot-cli-integration-tests`.
Numerous updates to the Spring CLI, primarily for better embedded REPL
shell support:
* Refactor the CLI application to help separate concerts between the
main CLI and the embedded shell. Both the CLI and embedded shell now
delegate to a new `CommandRunner` to handle running commands. The
runner can be configured differently depending depending on need.
For example, the embedded shell adds the 'prompt' and 'clear'
commands.
* Most `Command` implementations have been moved to sub-packages so that
they can be co-located with the classes that they use.
* Option commands are now only used in the CLI, the embedded shell
does not user them and details have been removed from the Command
interface.
* The REPL shell has been significantly refactored to:
- Support CTRL-C to cancel the running process. This is supported
when running external commands and most internal commands.
- Fork a new JVM when running commands (primarily for CTRL-C support
but also for potential memory and classpath issues)
- Change the "continue" trigger from `<<` to `\`
- Support command completion of files
- Add ANSI color output
- Provide 'help' support for internal commands (such as 'clear')
- Remove the now redundant `stop` command
Fixes gh-227
The AST transformation that processes @Grab annotations is driven once
per source file. Previously, this meant that if an app consisted of
multiple source files then multiple, discrete dependency resolutions
would be performed.
This commit updates AetherGrapeEngine to cache a previous resolution's
outcome and use its dependency to influence the outcome of subsequent
resolutions. For example if a one resolution results in spring-core
4.0.0.RELEASE being added to the classpath, subsequent resolutions
that depend upon spring-core will always get the 4.0.0.RELEASE
version. This is achieved by using the dependencies found by earlier
resolutions as dependency management configuration of the current
resolution. This removes the possibility of multiple versions of the
same dependency ending up on the classpath.
In addition to using the results of earlier resolutions to provide
dependency management configuration, default dependency management
configuration is also provided. This configuration is specified by
the springcli.properties file and ensures that, where Boot prescribes
certain versions of a dependency, that is the version that will be
resolved. For example, this ensures that spring-data-redis, which
depends upon Spring 3.1.4, pulls in the version of Spring that Boot
requires instead.
Fixes#224
Actually System.in works fine, it's the output streams that get buffered.
We can fix it by diverting them for the duration of the command.
Fixes gh-217
We might also want to rethink "!" as a shell exec command (since it means
something in a real shell and in JLine). E.g. use "exec" or something.
Partial fix for gh-220 (ideally we'd process the events and catch
and handle exceptions).
In this commit we retain "init" as a command inside the ShellCommand
but not on the bash command line.
Seems to have an impact on performance so relevant to gh-212.
Update SpringApplication to run by default in 'headless' mode. This
prevents the AWT system from creating a Java icon (for example in the
OSX dock).
Also update builds to run tests in 'headless' mode.
This appears to be a significant improvement in performance
(checking for the existence of init.grooy is cheap, but compiling
it is expensive).
I'm going to say this fixes gh-212.
Replace references to 'files' throughout the code-base with 'sources'
following the rename of `FileOptions` to `SourceOptions`.
Also cleanup ResourceUtils a little
We check for existence of the sources and (as before) resolve multiple
resources on the classpath if a path is not a File. In addition supports
Spring pseudo-URL prefixes as well as normal URLs as source locations.
In addition sources can now be specified as a directory (searched
recursively by default), or a resource pattern (e.g. app/**/*.groovy).
Fixes gh-207
Recent changes to the repository configuration for @Grab
didn't update the tests which use the GroovyCompiler as
a standalone. Fixed that by using the
RepositoryConfigurationFactory.
Previously, there were two <manifestEntries> elements in the CLI's
pom.xml. With certain versions of Maven, this appeared to cause the
first element to be ignored in favour of the second. The problem did
not occur when built locally with Maven 3.1.1, but did occur when built
by Bamboo which, I believe, uses 3.0.x
This commit combines the two <manifestEntries> into one.
The test passes locally, both in Eclipse and on the command line, but
fails on the CI server. Revert the addition of the test while I
hopefully figure out why.
This reverts commit 2e81b1d0d0.
The grab command downloads the dependencies of one or more Groovy
scripts to ./repository. This commit ensures that those previously
downloaded dependencies can be used by a subsequent invocation of the
run command.
The location and behaviour of the local cache is unaffected by this
change. If the dependencies in ./repository do not exist in the local
cache, Aether will "download" them from ./repository and store them in
the local cache.
Fixes#191
Previously, Aether's configuration was largely hard-coded making it
impossible to configure a mirror, provide credentials for accessing
a repository, etc.
This commit adds support for configuring Aether via Maven's
settings.xml file. The support is optional and must be enabled by
grabbing spring-boot-maven-settings in an init script. The Aether
instance that's used when running the application will then be
configured using settings.xml. The settings file is expected to be
found in ${user.home}/.m2/settings.xml.
The configuration of the following items is currently supported:
- Offline
- Proxies
- Mirrors
- Server authentication
- Local repository location
If the support is not enabled, settings.xml does not exist, or
settings.xml does not configure certain things then sensible defaults
are applied.
When an init command is run, it may add entries to the classpath. This
commit adds a test that verifies that, if an entry that is added to
the classpath contains a CompilerAutoConfiguration file in
META-INF/services, then the CompilerAutoConfigurations declared in it
are found by subsequent ServiceLoader.load calls.
Previously, a transform was used to add @GrabResolver annotations
during compilation that added the Spring milestone and snapshot
repositories. This functionality is now handled by
RepositoryConfigurationFactory so the transform is no longer required.
Users can declare or Command, OptionHandler classes in an init script
or they can use a DSL, e.g.
command("foo") { args -> println "Do stuff with ${args} array" }
or
command("foo") {
options { option "bar", "Help text for bar option" ithOptionArg() ofType Integer }
run { options -> println "Do stuff with ${options.valueOf('bar')}" }
}
InitCommand runs on creation of SpringCli so it can search for additional
Commands in updated classpath. Also added as interactive command in Shell
session.
PropertiesLauncher now supports creating its own class loader
from looader.classLoader property. It will succeed if the
implementation specified has a default constructor or one
that takes a parent class loader, or one that takes a URL[]
and a parent class loader (like URLClassLoader).
Change SpringCli so that running without arguments no longer jumps into
the embedded REPL shell. This restores the ability to obtain quick usage
help by simply typing `spring` from the command prompt.
Windows users or developers that prefer the embedded shell can still
launch it using `spring shell`.
Change OptionHandler to support '-cp' instead of '--cp'. This update
to the original fix (045088e8b) renders `help` output correctly and
should prevent potential issues if a `-p` command is added in the future.
Fixes gh-178
Main user-facing interface is still Counter/GaugeService but the
back end behind that has more options. The Default*Services write
metrics to a MetricWriter and there are some variants of that, and
also variants of MetricReader (basic read-only actions).
MetricRepository is now a combination of MetricReader, MetricWriter
and some more methods that make it a bit more repository like.
There is also a MultiMetricReader and a MultiMetricRepository for
the common case where metrics are stored in related (often open
ended) groups. Examples would be complex metrics like histograms
and "rich" metrics with averages and statistics attached (which
are both closed) and "field counters" which count the occurrences
of values of a particular named field or slot in an incoming message
(e.g. counting Twitter hastags, open ended).
In memory and redis implementations are provided for the repositories.
Generally speaking the in memory repository should be used as a
local buffer and then scheduled "exports" can be executed to copy
metric values accross to a remote repository for aggregation.
There is an Exporter interface to support this and a few implementations
dealing with different strategies for storing the results (singly or
grouped).
Codahale metrics are also supported through the MetricWriter interface.
Currently implemented through a naming convention (since Codahale has
a fixed object model this makes sense): metrics beginning with "histogram"
are Histograms, "timer" for Timers, "meter" for Meters etc.
Support for message driven metric consumption and production are provided
through a MetricWriterMessageHandler and a MessageChannelMetricWriter.
No support yet for pagination in the repositories, or for HATEOAS style
HTTP endpoints.
User can add (a single) beans{} DSL declaration (see GroovyBeanDefinitionReader
in Spring 4 for more detail) anywhere at the top level of an application source
file. It will be compiled to a closure and fed in to the application context
through a GroovyBeanDefinitionReader. Cool!
The example spring-boot-cli/samples/beans.groovy runs in an integration test
and passes (see SampleIntegrationTests).
It's super useful to get a reference to the current SpringCli
instance in the CommandFactory. Potentially implementations can
react to the properties of the Cli, or wrap it into something
more complex.
...supports the likely implementation of the REPL use
case that @jbrisbin has been working on.
Previously, the default classpath was empty. Now, in the absence of the
user providing a classpath via the -cp option, the default classpath
will be ".". If the user does specify a classpath, the classpath that's
used will be exactly what they have specified, i.e. "." will no longer
be on the classpath unless specified by the user.
The app sample integration test has been updated to verify that "." is
only the classpath by default.
Fixes#115
The JreProxySelector is used it to adjust the repositories
as they are added to the GrapeEngine. It looks at standard
System proeprties like http.proxyHost and http.proxyPort
and in addition consults standard JRE Authenticator features
for credentials (falling back to System properties
http.proxyUser and http.proxyPassword).
Fixes gh-136
Aether apparently doesn't use the java.net.* APIs for
TCP connections so it doesn't notice when a user sets
-Dhttp.Proxy*. To fix it is painful, and leads me to
suspect that actually we might want to parse a
settings.xml at some point (however unpalatable that
is).
For now I have added a Proxy to all RemoteRepository
instances that we create in the CLI if the user
has set -Dhttp.proxyHost (and/or -Dhttps.proxyHost for
a secure repository).
TODO: authentication. Is there a standard way to specify
that globally via system properties.
TODO: maybe use per-repository settings if provided
(e.g. in settings.xml).
The autoconfiguration transformations (and loads of grabs
of spring-boot snapshots) were making the grab command
tests run really slowly. Snapshots are particularly bad.
Fixed by adding a --autoconfigure=false option to the
compiler configuration and using it in that test.
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.
Previously, the automatic addition of the group and version to a
@Grab annotation based on the module name would only work on standard
import statements. This commit adds support for this functionality
on wildcard imports, static imports and wildcard static imports.
All of the following are now supported:
@Grab('spring-core')
import org.springframework.util.Assert
@Grab('spring-core')
import org.springframework.util.*
@Grab('spring-core')
import static org.springframework.util.Assert.isTrue
@Grab('spring-core')
import static org.springframework.util.Assert.*
Refactor bash shell completion to move the majority of the logic into
the Java code. This commit also removes the need for the '--' prefix on
every command.
With the goal of making AetherGrapeEngine generally useful with Groovy,
this commit removes any Boot specifics from it. Specifically, there
is now only a single default repository: Maven Central. The
Boot-specific Spring milestone and snapshot repositories are now added
via @GrabResolver annotations that are added using an ASTTransformation.
As part of this change, AetherGrapeEngine has also been updated to store
its repositories using a LinkedHashSet, this ensures that the same
repository is not used more than once while maintaining their ordering.
Groovy's Grape allows a user to enable download reports using the
system property groovy.grape.report.downloads. This commit updates
AetherGrapeEngine to honour this property and produce a detailed
download report when the system property is set to true. In the
absence of the system property, or when it's set to a value other than
true, the existing summary report is still produced.
[bs-344]
[60145094]
@GrabExclude can now be used to exclude certain transitive dependencies.
In Aether (Maven), exclusions are applied to an individual dependency
rather than being global. In Grape, exclusions are global.
AetherGrapeEngine adheres to the Grape convention by applying every
exclusion create by @GrabExclude to every dependency, effectively making
them global.
@GrabResolver can now be used to add a repository to the list that is
used for dependency resolution. Any repository that is added via the
annotation will then be available for the lifetime of the
AetherGrapeEngine instance. In reality, this equates to the lifetime
of the Boot application. This is in keeping with the documented default
behaviour [1]: "By default, the grape subsystem is shared globally, so
added resolvers will become available for any subsequent grab calls".
[1] - http://groovy.codehaus.org/api/groovy/lang/GrabResolver.html
[bs-345]
[60145036]
b19f6bb238 updated the CLI so that it should be launched using Spring
Boot Loader's JarLauncher, however the spring and spring.bat shell
scripts were not updated so they still launched the CLI by using
SpringCli as the main class. This led to a NoClassDefFoundError
as none of the dependencies in the jar's /lib directory could be
found.
This commit updates the two shells scripts to use JarLauncher as the
main class.
By default it is on, but you can switch it
off (`-P '!integration'`) to ignore integration tests
and get a faster build.
.travis.yml uses this feature so that it doesn't keep
failing on a timeout.
Rework classloading for launched applications so that CLI classes and
dependencies are not visible. This change allows many of the previous
hacks and workarounds to be removed.
With the exception of the 'org.springframework.boot.groovy' package
and 'groovy-all' all user required depndencies are now pulled in
via @Grab annotations.
The updated classloading algorithm has enabled the following changes:
- AetherGrapeEngine is now back in the cli project and the
spring-boot-cli-grape project has been removed. The AetherGrapeEngine
has also been simplified.
- The TestCommand now launches a TestRunner (similar in design to the
SpringApplicationRunner) and report test failures directly using
the junit TextListener. Adding custom 'testers' source to the users
project is no longer required. The previous 'double compile' for
tests has also been removed.
- Utility classes have been removed in favor of using versions from
spring-core.
- The CLI jar is now packaged using the 'boot-loader' rather than using
the maven shade plugin.
This commit also applied minor polish refactoring to a number of
classes.
When running an application, --local can be used to collect the
application's dependencies in a local directory. Prior to
AetherGrapeEngine being introduced, using --local would result in the
dependencies being written to ./grapes. When AetherGrapeEngine was
introduced --local no longer had any effect.
This commit updates AetherGrapeEngine so that it honours --local,
writing its dependencies to ./repository. When --local is not specified
dependencies are written to ~/.m2/repository (the standard location
for the local Maven cache). As part of this change TestCommand has
been refactored so that it lazily initialises its GroovyCompiler. This
ensures that RunCommand has a chance to set the system property that
backs --local before AetherGrapeEngine is initialised and accesses the
property.
Fixes#99
3d714d301 allowed all integration tests to download snapshots and
milestones. The test for the integration sample, which depends upon a
milestone, no longer needs to be a special case.
Previously, GrapeEngineInstaller would only install its GrapeEngine
if an engine had not already been installed. As the Grape class stores
the engine in a static field, this meant that the engine would only be
installed once for the lifetime of Grape's classloader. This caused
an ordering issue in SampleIntegrationTests.
The test for the integration sample clears the
disableSpringSnapshotRepos system property to allow M1 of the
integration DSL to be resolved. However, this property is only
examined and honoured in AetherGrapeEngine's constructor. If another
test had run and had already created and installed an
AetherGrapeEngine, the new AetherGrapeEngine that allowed the use of
snapshot repositories would not be installed and the test would fail.
This commit updates GrapeEngineInstaller so that it always installs
its GrapeEngine, overwriting any previously installed engine.
Previously, the Ivy-based Grape engine used a system property,
disableSpringSnapshotRepos, to control whether or not Spring's
snapshot and milestone repositories were used for dependency
resolution. This commit adds the same capability to AetherGrapeEngine.
[#59489826]
@Grab allows a dependency to be declared, but for its transitive
dependencies to be excluded by setting transitive to false. This
commit enhances AetherGrapeEngine to honour this setting by using a
wildcard exclusion on any dependency so declared.
Prior to this commit, the Aether-based GrapeEngine was loaded in the
same class loader as the rest of Boot. This led to Aether's and its
dependencies' types polluting the application's class path. Most
notably, this caused problems with logging as the logging framework
could be permaturely initialized.
This commit isolates AetherGrapeEngine, Aether and its dependencies
into a separate class loader. This is done by customizing the
packaging of the CLI's jar file with the internal directory housing
all of the types that will be loaded by the separate class loader.
Previously, @Grab annotations would use Ivy to download the
dependencies with some of Ivy's known limitations being worked around
by GrapeEngineCustomizer.
This commit adds a GrapeEngine implementation that uses Aether,
the dependency resolution 'engine' used by Maven and Grails. To ensure
consistent behaviour with a Maven build, the Aether-powered dependency
resolution uses the dependency management configuration from the
spring-boot-starter-parent pom file.
Previously, simple @Grab annotations only worked on classes. This commit
updates the simple @Grab support so that they can be used on anything
that can be annotated with @Grab.
The simplified @Grab support relies upon springcli.properties having
been generated. This commit adds an M2E lifecycle mapping for the
antrun plugin so that springcli.properties is generated as part of an
Eclipse build, thereby making it easier to run tests in Eclipse that
rely upon the simplified @Grab support.
Previously, LocalM2Resource used the pom's packaging configuration to
determine the suffix of the file that it should look for, e.g. if
the pom's packaging was jar, it would look for a file with a .jar
suffix in artifactExists(). This logic fails for artifacts with bundle
packaging as it would look for a .bundle file rather than a .jar file,
fail to find the file, and incorrectly report that the artifact does not
exist.
This commit updates LocalM2Resource to look for a file with a .jar
suffix when the packaging configuration in the pom is bundle.
- Look for JUnit test symbols, and add JUnit automatically
- Look for Spock test symbols, and add Spock automatically
- Based on what test libraries were used, invoke relevant embedded testers
and accumulate results
- Make it so that multiple testers can be invoked through a single 'test' command
- Print out total results and write out detailed trace errors in results.txt
- Update based on the new artifact resolution mechanism
Usually, use of @Grab requires you to specify a group, module, and
version when identifying a dependency. This can be done in two
different ways:
@Grab(group='alpha', module='bravo', version='1.0.0')
@Grab('alpha:bravo:1.0.0')
This commit allows users to only specify a module: the group is
inferred and the version is the one dictated by the boot CLI. Both
forms are supported:
@Grab(module='bravo')
@Grab('bravo')
Groovy's global AST transformations, which is how Grab is implemented,
do not support ordering and we need to augment the AST for the Grab
annotation before its processed by the Grab AST transformation. To
work around this, reflection is used to get hold of the compile
operations in the conversion phase, and a new AST transformation is
inserted immediately before the first AST transformation operation.
To allow a module's groupId and version to be resolved consistently,
META-INF/springcli.properties has been enhanced to include properties
for each module that we want to support in the following form:
<module>.groudId = <groudId>
<module>.version = <version>
<groupId> and <version> are taken from the Maven project's
dependencies and VPP, a Velocity-based pre-processor, is used to
automatically generate the enhanced properties file.
To prevent pollution of spring-boot-cli's class path with the
dependencies that are only required to populate springcli.properties,
a separate project, spring-boot-cli-properties, has been created.
spring-boot-cli depends upon this now project causing it to, via the
shade plug, include the properties file in its jar.
Previously DependencyCustomizer allow a dependency to be added by
specifying its full coordinates, i.e. a group ID, artifact ID, and
version. This commit updates DependencyCustomizer to only require
an artifact/module ID. The group ID and version are then resolved
using the same mechanism as the enhanced @Grab support.
[#56328644] [bs-312] Allow @Grab without version
- If RabbitTemplate is on the classpath, turn on autodetection.
- Create a RabbitTemplate, a Rabbit ConnectionFactory, and a RabbitAdmin is spring.rabbitmq.dynamic:true
- Enable some **spring.rabbitmq** properties like host, port, username, password, and dynamic
- Add tests to verify functionality
- Add Groovy CLI functionality. Base it on @EnableRabbitMessaging. Add spring-amqp to the path.
- Create rabbit.groovy test to prove it all works.
- Make Queue and TopicExchange top-level Spring beans in rabbit.groovy test script
* application.properties support for spring.jms and spring.activemq
* more tests to verify ActiveMQConnectionFactory pooling
* Groovy support and simple sample with activemq
* Groovy detection mechanism is @EnableJmsMessaging annotation
* Add ability to detect spring-jms on the path and create a JmsTemplate with
ActiveMQConnectionFactory
* Create tests showing autoconfigured JmsTemplate with ActiveMQ, but prove it
backs off if a separate ConnectionFactory exists.
* Add support to spring-boot-cli to that it detects JmsTemplate, DefaultMessageListenerContainer,
or SimpleMessageListenerContainer, and turns on autoconfiguration as well as
add proper @Grab's and import statements.
* Write a jms.groovy test showing proper CLI support
Simplify ActiveMQ configuration
Update ActiveMQ to 5.7.0
* @EnableTransactionManagement triggers spring-tx imports
* Field or method of type JdbcTemplate or NamedParameterJdbcTemplate
of DataSource triggers spring-jdbc imports
A bug in ivy (tickled by maven leaving a pom
but no jar in the local repo) would make the
default Grapes ivy config fail (cannot grab...).
Phil's workaround now has a test case.
Fix the localm2 repository to only consider that a pom exists when
its artifact is contained in the repository.
This prevents a download error that can occur when the local m2
repository contains a POM file but not a JAR.
Issue: #55532358
The Boot resolver didn't transfer enough of the settings
of the default ChainResolver. Adding a boolean flag was
enough to make the chatter die down for dependencies
that were unneeded.
[Fixes#55358344] [bs-291]
Seems to work. I think the problem was the race conditions
that we hopefully already eliminated. I got an out of memory
error running the samples tests in Eclipse, but then it went
away again (something to look out for).
[Fixes#54925992] [bs-280]
* Added src/main/content/bash_completion.d/spring
* Also made all commands alias to "--<self>" so
"--help" is a synonym for "help" (for instance). This
helps with the completion generation.
[Fixes#54827292]
Update CLI to show a "Downloading Dependencies..." message if the
initial dependency resolution takes more than 3 seconds. Whilst
downloading dots are appended to the message.
Issue: #54589094
Rework main build POM to be an aggregator pom that does not inherit
from any parent. Introduce new spring-boot-dependencies module to
act as a parent for both spring-boot-starter-parent and
spring-boot-parent.