diff --git a/build.gradle b/build.gradle index 38d57f5..17f2a67 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,7 @@ apply plugin: 'groovy' apply plugin: 'maven' apply plugin: 'com.jfrog.bintray' -version = '0.2.1' +version = '0.3.0' group = 'com.github.jruby-gradle' description = 'A library for managing Ruby gems' defaultTasks 'check', 'assemble' diff --git a/src/main/java/com/github/jrubygradle/jem/GemInstallEvent.java b/src/main/java/com/github/jrubygradle/jem/GemInstallEvent.java index cc0d326..e7d342f 100644 --- a/src/main/java/com/github/jrubygradle/jem/GemInstallEvent.java +++ b/src/main/java/com/github/jrubygradle/jem/GemInstallEvent.java @@ -7,6 +7,9 @@ import java.io.File; * {@code GemInstaller} */ public interface GemInstallEvent { - public void onSuccess(Gem gem, File installationDir); - public void onFailure(Gem gem, File installationDir); + /** + * @param result Instance of {@code GemInstallResult} + * @return true if the installation should continue + */ + public boolean onInstall(GemInstallResult result); } diff --git a/src/main/java/com/github/jrubygradle/jem/GemInstallResult.java b/src/main/java/com/github/jrubygradle/jem/GemInstallResult.java new file mode 100644 index 0000000..6dc6e9a --- /dev/null +++ b/src/main/java/com/github/jrubygradle/jem/GemInstallResult.java @@ -0,0 +1,64 @@ +package com.github.jrubygradle.jem; + +import java.io.File; + +/** + * Plain-old-Java-object containing properties to tell the consumer something about + * an attempted (or successful) gem installation + */ +public class GemInstallResult { + public static enum Type { SUCCESS, FAILURE }; + + protected Type resultType; + protected Gem gem; + protected File gemFile; + protected File installationDir; + protected Exception exception; + + public GemInstallResult(Gem gem, + File gemFile, + File installDir, + Exception exception) { + this.gem = gem; + this.gemFile = gemFile; + this.installationDir = installDir; + this.exception = exception; + this.resultType = Type.FAILURE; + + if (exception == null) { + this.resultType = Type.SUCCESS; + } + } + + /** + * @return Metadata about the gem, null if the metadata could not be passed + */ + public Gem getGem() { + return gem; + } + + /** + * @return In the case of a failed installation, this contains a caught exception + */ + public Exception getException() { + return exception; + } + + /** + * @return File object for the .gem file which was used for the install + */ + public File getGemFile() { + return gemFile; + } + + /** + * @return File object for the intallation dir used for the install + */ + public File getInstallationDir() { + return installationDir; + } + + public Type getType() { + return resultType; + } +} diff --git a/src/main/java/com/github/jrubygradle/jem/GemInstaller.java b/src/main/java/com/github/jrubygradle/jem/GemInstaller.java index b98ca08..69688bf 100644 --- a/src/main/java/com/github/jrubygradle/jem/GemInstaller.java +++ b/src/main/java/com/github/jrubygradle/jem/GemInstaller.java @@ -15,6 +15,7 @@ public class GemInstaller { }; protected com.github.jrubygradle.jem.internal.GemInstaller impl; + protected GemInstallEvent callback; /** * Create an installer with the given installation directory and a single gem @@ -74,4 +75,10 @@ public class GemInstaller { public void install(DuplicateBehavior overwriteBehavior) { impl.install(overwriteBehavior); } + + /** + */ + public void install(GemInstallEvent eventCallback) { + impl.install(eventCallback, DuplicateBehavior.OVERWRITE); + } } diff --git a/src/main/java/com/github/jrubygradle/jem/internal/GemInstaller.java b/src/main/java/com/github/jrubygradle/jem/internal/GemInstaller.java index 18ec635..bd3dedd 100644 --- a/src/main/java/com/github/jrubygradle/jem/internal/GemInstaller.java +++ b/src/main/java/com/github/jrubygradle/jem/internal/GemInstaller.java @@ -1,5 +1,7 @@ package com.github.jrubygradle.jem.internal; +import com.github.jrubygradle.jem.GemInstallEvent; +import com.github.jrubygradle.jem.GemInstallResult; import org.jboss.shrinkwrap.api.ArchiveFormat; import org.jboss.shrinkwrap.api.ArchivePath; import org.jboss.shrinkwrap.api.GenericArchive; @@ -40,12 +42,36 @@ public class GemInstaller { } public void install(DuplicateBehavior onDuplicateBehavior) { + install(null, onDuplicateBehavior); + } + + public void install(GemInstallEvent eventCallback, DuplicateBehavior onDuplicateBehavior) { if (!mkdirs()) { /* raise some exception? */ } - for (File gem : this.gems) { - installGem(installDirectory, gem, onDuplicateBehavior); + for (File gemFile : this.gems) { + boolean shouldContinue = true; + Exception caughtException = null; + Gem gem = null; + + try { + gem = installGem(installDirectory, gemFile, onDuplicateBehavior); + } + catch (Exception exc) { + caughtException = exc; + } + + if (eventCallback instanceof GemInstallEvent) { + shouldContinue = eventCallback.onInstall(new GemInstallResult(gem, + gemFile, + installDirectory, + caughtException)); + } + + if (!shouldContinue) { + break; + } } } diff --git a/src/test/groovy/com/github/jrubygradle/jem/GemInstallerSpec.groovy b/src/test/groovy/com/github/jrubygradle/jem/GemInstallerSpec.groovy index c55f7f8..c0dcfd9 100644 --- a/src/test/groovy/com/github/jrubygradle/jem/GemInstallerSpec.groovy +++ b/src/test/groovy/com/github/jrubygradle/jem/GemInstallerSpec.groovy @@ -12,6 +12,7 @@ import com.github.jrubygradle.jem.internal.GemInstaller as GemInstallerImpl class GemInstallerSpec extends Specification { final String FIXTURES_ROOT = new File(['src', 'test', 'resources'].join(File.separator)).absolutePath final String GEM_FIXTURE = [FIXTURES_ROOT, 'thor-0.19.1.gem'].join(File.separator) + final String RACK_FIXTURE = [FIXTURES_ROOT, 'rack-1.6.4.gem'].join(File.separator) GemInstaller installer Path installDirPath = Files.createTempDirectory("geminstallerspec") @@ -70,10 +71,75 @@ class GemInstallerSpec extends Specification { given: GemInstaller.DuplicateBehavior behavior = GemInstaller.DuplicateBehavior.OVERWRITE GemInstallerImpl impl = mockedImpl() - GemInstaller installer = new GemInstaller(impl) + installer = new GemInstaller(impl) 1 * impl.install(behavior) expect: installer.install(behavior) } + + @Issue("https://github.com/jruby-gradle/jem/issues/6") + def "install() with a non-existent gem should call the callback with a failure"() { + given: + boolean calledBack = false + installer = new GemInstaller(installDir, [new File('foo.gem')]) + + when: + installer.install(new GemInstallEvent() { + @Override + public boolean onInstall(GemInstallResult result) { + calledBack = (result.type == GemInstallResult.Type.FAILURE) + return true; + } + }) + + then: + calledBack + } + + @Issue("https://github.com/jruby-gradle/jem/issues/6") + def "install() with a valid gem should call the callback with a success"() { + given: + boolean calledBack = false + installer = new GemInstaller(installDir, new File(GEM_FIXTURE)); + + when: + installer.install(new GemInstallEvent() { + @Override + public boolean onInstall(GemInstallResult result) { + calledBack = (result.type == GemInstallResult.Type.SUCCESS) + return true; + } + }) + + then: + calledBack + } + + @Issue("https://github.com/jruby-gradle/jem/issues/6") + def "install() with should stop with a false return"() { + given: + int calledBack = 0 + installer = new GemInstaller(installDir, [new File(GEM_FIXTURE), + new File(RACK_FIXTURE)]) + + when: + installer.install(new GemInstallEvent() { + @Override + public boolean onInstall(GemInstallResult result) { + calledBack += 1 + return false; + } + }) + + then: 'the first gem should be installed' + (new File(installDir, 'specifications/thor-0.19.1.gemspec')).exists() + + and: 'we should have been called back once' + calledBack == 1 + + and: 'the second gem should not be installed' + !(new File(installDir, 'specifications/rack-1.6.4.gemspec')).exists() + + } } diff --git a/src/test/resources/rack-1.6.4.gem b/src/test/resources/rack-1.6.4.gem new file mode 100644 index 0000000..6d06fed Binary files /dev/null and b/src/test/resources/rack-1.6.4.gem differ