Skip to content

Add thin jar launcher (downloads dependencies as required on startup) #7216

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions spring-boot-cli/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-loader-tools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-aether</artifactId>
</dependency>
<dependency>
<groupId>jline</groupId>
<artifactId>jline</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,10 @@

package org.springframework.boot.cli.compiler;

import java.io.File;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;

import org.apache.maven.settings.Profile;
import org.apache.maven.settings.Repository;
import org.codehaus.plexus.interpolation.InterpolationException;
import org.codehaus.plexus.interpolation.Interpolator;
import org.codehaus.plexus.interpolation.PropertiesBasedValueSource;
import org.codehaus.plexus.interpolation.RegexBasedInterpolator;

import org.springframework.boot.cli.compiler.grape.RepositoryConfiguration;
import org.springframework.boot.cli.compiler.maven.MavenSettings;
import org.springframework.boot.cli.compiler.maven.MavenSettingsReader;
import org.springframework.util.StringUtils;

/**
* Factory used to create {@link RepositoryConfiguration}s.
Expand All @@ -41,15 +29,6 @@
*/
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);

private RepositoryConfigurationFactory() {
}

Expand All @@ -58,74 +37,19 @@ private RepositoryConfigurationFactory() {
* @return the newly-created default repository configuration
*/
public static List<RepositoryConfiguration> createDefaultRepositoryConfiguration() {
MavenSettings mavenSettings = new MavenSettingsReader().readSettings();
List<RepositoryConfiguration> repositoryConfiguration = new ArrayList<RepositoryConfiguration>();
repositoryConfiguration.add(MAVEN_CENTRAL);
if (!Boolean.getBoolean("disableSpringSnapshotRepos")) {
repositoryConfiguration.add(SPRING_MILESTONE);
repositoryConfiguration.add(SPRING_SNAPSHOT);
}
addDefaultCacheAsRepository(mavenSettings.getLocalRepository(),
repositoryConfiguration);
addActiveProfileRepositories(mavenSettings.getActiveProfiles(),
repositoryConfiguration);
return repositoryConfiguration;
}

private static void addDefaultCacheAsRepository(String localRepository,
List<RepositoryConfiguration> repositoryConfiguration) {
RepositoryConfiguration repository = new RepositoryConfiguration("local",
getLocalRepositoryDirectory(localRepository).toURI(), true);
if (!repositoryConfiguration.contains(repository)) {
repositoryConfiguration.add(0, repository);
}
}

private static void addActiveProfileRepositories(List<Profile> activeProfiles,
List<RepositoryConfiguration> configurations) {
for (Profile activeProfile : activeProfiles) {
Interpolator interpolator = new RegexBasedInterpolator();
interpolator.addValueSource(
new PropertiesBasedValueSource(activeProfile.getProperties()));
for (Repository repository : activeProfile.getRepositories()) {
configurations.add(getRepositoryConfiguration(interpolator, repository));
}
}
}

private static RepositoryConfiguration getRepositoryConfiguration(
Interpolator interpolator, Repository repository) {
String name = interpolate(interpolator, repository.getId());
String url = interpolate(interpolator, repository.getUrl());
boolean snapshotsEnabled = false;
if (repository.getSnapshots() != null) {
snapshotsEnabled = repository.getSnapshots().isEnabled();
}
return new RepositoryConfiguration(name, URI.create(url), snapshotsEnabled);
}

private static String interpolate(Interpolator interpolator, String value) {
try {
return interpolator.interpolate(value);
}
catch (InterpolationException ex) {
return value;
}
}

private static File getLocalRepositoryDirectory(String localRepository) {
if (StringUtils.hasText(localRepository)) {
return new File(localRepository);
}
return new File(getM2HomeDirectory(), "repository");
return convert(org.springframework.boot.aether.RepositoryConfigurationFactory
.createDefaultRepositoryConfiguration());
}

private static File getM2HomeDirectory() {
String mavenRoot = System.getProperty("maven.home");
if (StringUtils.hasLength(mavenRoot)) {
return new File(mavenRoot);
private static List<RepositoryConfiguration> convert(
List<org.springframework.boot.aether.RepositoryConfiguration> repositoryConfigurations) {
List<RepositoryConfiguration> list = new ArrayList<RepositoryConfiguration>();
for (org.springframework.boot.aether.RepositoryConfiguration repositoryConfiguration : repositoryConfigurations) {
list.add(new RepositoryConfiguration(repositoryConfiguration.getName(),
repositoryConfiguration.getUri(),
repositoryConfiguration.getSnapshotsEnabled()));
}
return new File(System.getProperty("user.home"), ".m2");
return list;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,16 @@

import groovy.grape.GrapeEngine;
import groovy.lang.GroovyClassLoader;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.RepositorySystem;

import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.collection.CollectRequest;
import org.eclipse.aether.graph.Dependency;
import org.eclipse.aether.graph.Exclusion;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.resolution.ArtifactResolutionException;
import org.eclipse.aether.resolution.ArtifactResult;
import org.eclipse.aether.resolution.DependencyRequest;
import org.eclipse.aether.resolution.DependencyResult;
import org.eclipse.aether.util.artifact.JavaScopes;
import org.eclipse.aether.util.filter.DependencyFilterUtils;

import org.springframework.boot.aether.AetherEngine;
import org.springframework.boot.aether.DependencyResolutionFailedException;

/**
* A {@link GrapeEngine} implementation that uses
Expand All @@ -63,40 +59,15 @@ public class AetherGrapeEngine implements GrapeEngine {

private final DependencyResolutionContext resolutionContext;

private final ProgressReporter progressReporter;
private final AetherEngine engine;

private final GroovyClassLoader classLoader;

private final DefaultRepositorySystemSession session;

private final RepositorySystem repositorySystem;

private final List<RemoteRepository> repositories;

public AetherGrapeEngine(GroovyClassLoader classLoader,
RepositorySystem repositorySystem,
DefaultRepositorySystemSession repositorySystemSession,
List<RemoteRepository> remoteRepositories,
public AetherGrapeEngine(GroovyClassLoader classLoader, AetherEngine engine,
DependencyResolutionContext resolutionContext) {
this.classLoader = classLoader;
this.repositorySystem = repositorySystem;
this.session = repositorySystemSession;
this.engine = engine;
this.resolutionContext = resolutionContext;
this.repositories = new ArrayList<RemoteRepository>();
List<RemoteRepository> remotes = new ArrayList<RemoteRepository>(
remoteRepositories);
Collections.reverse(remotes); // priority is reversed in addRepository
for (RemoteRepository repository : remotes) {
addRepository(repository);
}
this.progressReporter = getProgressReporter(this.session);
}

private ProgressReporter getProgressReporter(DefaultRepositorySystemSession session) {
if (Boolean.getBoolean("groovy.grape.report.downloads")) {
return new DetailedProgressReporter(session, System.out);
}
return new SummaryProgressReporter(session, System.out);
}

@Override
Expand All @@ -115,9 +86,6 @@ public Object grab(Map args, Map... dependencyMaps) {
classLoader.addURL(file.toURI().toURL());
}
}
catch (ArtifactResolutionException ex) {
throw new DependencyResolutionFailedException(ex);
}
catch (MalformedURLException ex) {
throw new DependencyResolutionFailedException(ex);
}
Expand Down Expand Up @@ -196,23 +164,6 @@ private boolean isTransitive(Map<?, ?> dependencyMap) {
return (transitive == null ? true : transitive);
}

private List<Dependency> getDependencies(DependencyResult dependencyResult) {
List<Dependency> dependencies = new ArrayList<Dependency>();
for (ArtifactResult artifactResult : dependencyResult.getArtifactResults()) {
dependencies.add(
new Dependency(artifactResult.getArtifact(), JavaScopes.COMPILE));
}
return dependencies;
}

private List<File> getFiles(DependencyResult dependencyResult) {
List<File> files = new ArrayList<File>();
for (ArtifactResult result : dependencyResult.getArtifactResults()) {
files.add(result.getArtifact().getFile());
}
return files;
}

private GroovyClassLoader getClassLoader(Map args) {
GroovyClassLoader classLoader = (GroovyClassLoader) args.get("classLoader");
return (classLoader == null ? this.classLoader : classLoader);
Expand All @@ -229,41 +180,7 @@ public void addResolver(Map<String, Object> args) {
}

protected void addRepository(RemoteRepository repository) {
if (this.repositories.contains(repository)) {
return;
}
repository = getPossibleMirror(repository);
repository = applyProxy(repository);
repository = applyAuthentication(repository);
this.repositories.add(0, repository);
}

private RemoteRepository getPossibleMirror(RemoteRepository remoteRepository) {
RemoteRepository mirror = this.session.getMirrorSelector()
.getMirror(remoteRepository);
if (mirror != null) {
return mirror;
}
return remoteRepository;
}

private RemoteRepository applyProxy(RemoteRepository repository) {
if (repository.getProxy() == null) {
RemoteRepository.Builder builder = new RemoteRepository.Builder(repository);
builder.setProxy(this.session.getProxySelector().getProxy(repository));
repository = builder.build();
}
return repository;
}

private RemoteRepository applyAuthentication(RemoteRepository repository) {
if (repository.getAuthentication() == null) {
RemoteRepository.Builder builder = new RemoteRepository.Builder(repository);
builder.setAuthentication(this.session.getAuthenticationSelector()
.getAuthentication(repository));
repository = builder.build();
}
return repository;
this.engine.addRepository(repository);
}

@Override
Expand All @@ -280,54 +197,17 @@ public URI[] resolve(Map args, Map... dependencyMaps) {
public URI[] resolve(Map args, List depsInfo, Map... dependencyMaps) {
List<Exclusion> exclusions = createExclusions(args);
List<Dependency> dependencies = createDependencies(dependencyMaps, exclusions);
try {
List<File> files = resolve(dependencies);
List<URI> uris = new ArrayList<URI>(files.size());
for (File file : files) {
uris.add(file.toURI());
}
return uris.toArray(new URI[uris.size()]);
}
catch (Exception ex) {
throw new DependencyResolutionFailedException(ex);
List<File> files = resolve(dependencies);
List<URI> uris = new ArrayList<URI>(files.size());
for (File file : files) {
uris.add(file.toURI());
}
return uris.toArray(new URI[uris.size()]);
}

private List<File> resolve(List<Dependency> dependencies)
throws ArtifactResolutionException {
try {
CollectRequest collectRequest = getCollectRequest(dependencies);
DependencyRequest dependencyRequest = getDependencyRequest(collectRequest);
DependencyResult result = this.repositorySystem
.resolveDependencies(this.session, dependencyRequest);
addManagedDependencies(result);
return getFiles(result);
}
catch (Exception ex) {
throw new DependencyResolutionFailedException(ex);
}
finally {
this.progressReporter.finished();
}
}

private CollectRequest getCollectRequest(List<Dependency> dependencies) {
CollectRequest collectRequest = new CollectRequest((Dependency) null,
dependencies, new ArrayList<RemoteRepository>(this.repositories));
collectRequest
.setManagedDependencies(this.resolutionContext.getManagedDependencies());
return collectRequest;
}

private DependencyRequest getDependencyRequest(CollectRequest collectRequest) {
DependencyRequest dependencyRequest = new DependencyRequest(collectRequest,
DependencyFilterUtils.classpathFilter(JavaScopes.COMPILE,
JavaScopes.RUNTIME));
return dependencyRequest;
}

private void addManagedDependencies(DependencyResult result) {
this.resolutionContext.addManagedDependencies(getDependencies(result));
throws DependencyResolutionFailedException {
return this.engine.resolve(dependencies);
}

@Override
Expand Down
Loading