From fe769c0e5e1e10b2d839a0af8d47c86c9e330077 Mon Sep 17 00:00:00 2001 From: pron Date: Sat, 24 May 2014 21:04:51 +0300 Subject: [PATCH] 0.4.2 release --- README.md | 10 +++-- build.gradle | 2 +- src/main/java/Capsule.java | 35 ++++++++++++--- src/main/java/capsule/PomReader.java | 65 ++++++++++++++++++++-------- 4 files changed, 82 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index d029e247..e7c5b60a 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ With Capsule, you just distribute a single JAR and run it. or: - co.paralleluniverse:capsule:0.4.1 + co.paralleluniverse:capsule:0.4.2 On Maven Central. @@ -44,7 +44,9 @@ Discuss Capsule on the capsule-user [Google Group/Mailing List](https://groups.g ## Usage Examples -Before we delve into the specifics of defining a Capsule distribution, let us look at a few different ways of packaging a capsule. The examples are snippets of [Gradle](http://www.gradle.org/) build files, but the same could be achieved with [Ant](http://ant.apache.org/) or [Maven](http://maven.apache.org/). The full Gradle file is [here](https://github.com/puniverse/capsule-demo/blob/master/build.gradle), and a Maven POM is [here](https://github.com/puniverse/capsule-demo/blob/master/pom.xml). +Before we delve into the specifics of defining a Capsule distribution, let us look at a few different ways of packaging a capsule. The examples are snippets of [Gradle](http://www.gradle.org/) build files, but the same could be achieved with [Ant](http://ant.apache.org/) or [Maven](http://maven.apache.org/). + +**A complete usage example, for both Gradle and Maven**, is found in the [capsule-demo](https://github.com/puniverse/capsule-demo) project, which contains both a `build.gradle` file that creates a few kinds of capsules, as well as Maven POM and assemblies that create both a full capsule (with embedded dependencies) and a capsule with external dependencies (that are resolved at launch). We'll assume that the application's `gradle.build` file applies the [`java`](http://www.gradle.org/docs/current/userguide/java_plugin.html) and [`application`](http://www.gradle.org/docs/current/userguide/application_plugin.html) plugins, and that the build file declare the `capsule` configuration and contains the dependency `capsule 'co.paralleluniverse:capsule:VERSION'`. @@ -227,13 +229,13 @@ The dependencies are downloaded the first time the capsule is launched, and plac The `CAPSULE_REPOS` environment variable can be set to a colon (`:`) separated list of Maven repository URLS, which will override those specified in the manifest or the POM. -Capsule can make use of Maven repositories in another way: the `Application` manifest attribute can specify the Maven coordinates of the application's main JAR file, which can in itself be a module. The artifact can be given with a version range, for example: `Application: com.acme:foo:[1.0,2.0)` or with no version at all. The newest version matching the range (or the newest version if no range is given), will be downloaded, cached and launched. If the application's main artifact is a capsule, then all configurations will be taken based on those in the artifact capsule. +Capsule can make use of Maven repositories in another way: the `Application` manifest attribute can specify the Maven coordinates of the application's main JAR file, which can in itself be a capsule. The artifact can be given with a version range, for example: `Application: com.acme:foo:[1.0,2.0)` or with no version at all. The newest version matching the range (or the newest version if no range is given), will be downloaded, cached and launched. If the application's main artifact is a capsule, then all configurations will be taken based on those in the artifact capsule. Native dependencies can be specified in the `Native-Dependencies-Linux`/`Native-Dependencies-Win`/`Native-Dependencies-Mac` attributes, each for its respective OS. A native dependency is written as a plain dependency but can be followed by a comma and a new filename to give the artifact once downloaded (e.g.: `com.acme:foo-native-linux-x64:1.0,foo-native.so`). Each native artifact must be a single native library, with a suffix matching the OS (`.so` for Linux, `.dll` for windows, `.dylib` for Mac). The native libraries are downloaded and copied into the application cache (and renamed if requested). Adding `-Dcapsule.reset=true`, can force a re-download of SNAPSHOT versions. -The command: `java -Dcapsule.tree -jar app.jar`, will print out the dependency tree for the module, and then quit without launching the app. +The command: `java -Dcapsule.tree -jar app.jar`, will print the dependency tree for the capsule, and then quit without launching the app. Two more system properties affect the way Capsule searches for dependencies. If `capsule.offline` is defined or set to `true` (`-Dcapsule.offline` or `-Dcapsule.offline=true`), Capsule will not attempt to contact online repositories for dependencies (instead, it will use the local Maven repository/cache only). `capsule.local` determines the path for the local Maven repository/cache Capsule will use (which, by default, is the `deps` subdirectory of the Capsule cache). diff --git a/build.gradle b/build.gradle index 0f5dea37..e9bd2e6f 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ targetCompatibility = '1.7' [compileJava, compileTestJava]*.options*.encoding = 'UTF-8' group = "co.paralleluniverse" -version = "0.4.1" +version = "0.4.2" status = "integration" description = "Simple Java deployment" ext.url = "http://puniverse.github.com/java-launcher" diff --git a/src/main/java/Capsule.java b/src/main/java/Capsule.java index 34a33aa8..75abf55c 100644 --- a/src/main/java/Capsule.java +++ b/src/main/java/Capsule.java @@ -61,7 +61,7 @@ public final class Capsule implements Runnable { * We do a lot of data transformations that would have really benefitted from Java 8's lambdas and streams, * but we want Capsule to support Java 7. */ - private static final String VERSION = "0.4.1"; + private static final String VERSION = "0.4.2"; private static final String PROP_RESET = "capsule.reset"; private static final String PROP_VERSION = "capsule.version"; @@ -904,13 +904,36 @@ private List getDefaultCacheClassPath() { } private Path getPath(String p) { - if (isDependency(p)) + if (isDependency(p) && dependencyManager != null) return getDependencyPath(dependencyManager, p); - else { - if (appCache == null) - throw new IllegalStateException("Capsule not extracted. Cannot obtain path " + p); + + if (appCache == null) + throw new IllegalStateException( + (isDependency(p) ? "Dependency manager not found. Cannot resolve" : "Capsule not extracted. Cannot obtain path") + + " " + p); + if (isDependency(p)) { + Path f = appCache.resolve(dependencyToLocalJar(true, p)); + if (Files.isRegularFile(f)) + return f; + f = appCache.resolve(dependencyToLocalJar(false, p)); + if (Files.isRegularFile(f)) + return f; + throw new IllegalArgumentException("Dependency manager not found, and could not locate artifact " + p + " in capsule"); + } else return toAbsolutePath(appCache, p); - } + } + + private String dependencyToLocalJar(boolean withGroupId, String p) { + String[] coords = p.split(":"); + StringBuilder sb = new StringBuilder(); + if (withGroupId) + sb.append(coords[0]).append('-'); + sb.append(coords[1]).append('-'); + sb.append(coords[2]); + if (coords.length > 3) + sb.append('-').append(coords[3]); + sb.append(".jar"); + return sb.toString(); } private List getPath(List ps) { diff --git a/src/main/java/capsule/PomReader.java b/src/main/java/capsule/PomReader.java index 2385afcf..fc787535 100644 --- a/src/main/java/capsule/PomReader.java +++ b/src/main/java/capsule/PomReader.java @@ -49,35 +49,62 @@ public List getRepositories() { final List repos = pom.getRepositories(); if (repos == null) return null; - final List repositories = new ArrayList(); - for(Repository repo : repos) + final List repositories = new ArrayList(repos.size()); + for (Repository repo : repos) repositories.add(repo.getUrl()); return repositories; } public List getDependencies() { - List deps = pom.getDependencies(); + final List deps = pom.getDependencies(); if (deps == null) return null; - final List dependencies = new ArrayList(); + final List dependencies = new ArrayList(deps.size()); for (Dependency dep : deps) { - if (!dep.isOptional()) { - String coords = dep.getGroupId() + ":" + dep.getArtifactId() + ":" + dep.getVersion() - + (dep.getClassifier() != null && !dep.getClassifier().isEmpty() ? ":" + dep.getClassifier() : ""); - List exclusions = dep.getExclusions(); - if (exclusions != null && !exclusions.isEmpty()) { - StringBuilder sb = new StringBuilder(); - sb.append('('); - for (Exclusion ex : exclusions) - sb.append(ex.getGroupId()).append(':').append(ex.getArtifactId()).append(','); - sb.delete(sb.length() - 1, sb.length()); - sb.append(')'); - coords += sb.toString(); - } - dependencies.add(coords); - } + if (includeDependency(dep)) + dependencies.add(dep2desc(dep)); } return dependencies; } + + private static boolean includeDependency(Dependency dep) { + if (dep.isOptional()) + return false; + if ("co.paralleluniverse".equals(dep.getGroupId()) && "capsule".equals(dep.getArtifactId())) + return false; + + switch (dep.getScope().toLowerCase()) { + case "compile": + case "runtime": + return true; + default: + return false; + } + } + + private static String dep2desc(Dependency dep) { + String coords = dep2coords(dep); + List exclusions = dep.getExclusions(); + if (exclusions != null && !exclusions.isEmpty()) { + StringBuilder sb = new StringBuilder(); + sb.append('('); + for (Exclusion ex : exclusions) + sb.append(exclusion2coord(ex)).append(','); + sb.delete(sb.length() - 1, sb.length()); + sb.append(')'); + + coords += sb.toString(); + } + return coords; + } + + private static String dep2coords(Dependency dep) { + return dep.getGroupId() + ":" + dep.getArtifactId() + ":" + dep.getVersion() + + (dep.getClassifier() != null && !dep.getClassifier().isEmpty() ? ":" + dep.getClassifier() : ""); + } + + private static String exclusion2coord(Exclusion ex) { + return ex.getGroupId() + ":" + ex.getArtifactId(); + } }