From ab3f52e0d93b0dfacaea0b776dd2613f3a4297c7 Mon Sep 17 00:00:00 2001 From: Hiram Chirino Date: Wed, 16 Sep 2015 17:37:24 -0400 Subject: [PATCH] Support docker:watch correlating maven jars that end up in it's assembly dir so that a docker container update can be triggered if transitive dep jar is installed in the mvn local repo. --- .../org/jolokia/docker/maven/WatchMojo.java | 36 ++++- .../docker/maven/assembly/AssemblyFiles.java | 6 +- .../maven/assembly/DockerAssemblyManager.java | 7 +- .../maven/assembly/MappingTrackArchiver.java | 130 +++++++++++++++++- .../maven/config/AssemblyConfiguration.java | 4 +- .../docker/maven/service/BuildService.java | 9 +- .../assembly/DockerAssemblyManagerTest.java | 3 +- .../assembly/MappingTrackArchiverTest.java | 9 +- 8 files changed, 183 insertions(+), 21 deletions(-) diff --git a/src/main/java/org/jolokia/docker/maven/WatchMojo.java b/src/main/java/org/jolokia/docker/maven/WatchMojo.java index e0a5fb703..8fa8c1b73 100644 --- a/src/main/java/org/jolokia/docker/maven/WatchMojo.java +++ b/src/main/java/org/jolokia/docker/maven/WatchMojo.java @@ -15,16 +15,21 @@ * limitations under the License. */ +import java.io.File; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicReference; +import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; +import org.codehaus.plexus.util.FileUtils; import org.codehaus.plexus.util.StringUtils; import org.jolokia.docker.maven.access.*; import org.jolokia.docker.maven.assembly.AssemblyFiles; +import org.jolokia.docker.maven.assembly.BuildDirs; import org.jolokia.docker.maven.config.*; import org.jolokia.docker.maven.service.QueryService; import org.jolokia.docker.maven.service.RunService; @@ -69,6 +74,15 @@ public class WatchMojo extends AbstractBuildSupportMojo { */ private String watchPostGoal; + /** + * The local repository + * @parameter expression="${localRepository}" + * @required + * @readonly + */ + private ArtifactRepository localRepository; + + // Scheduler private ScheduledExecutorService executor; @@ -136,15 +150,27 @@ private Runnable createBuildWatchTask(final DockerAccess docker, final ImageWatc throws MojoExecutionException { final ImageConfiguration imageConfig = watcher.getImageConfiguration(); final String name = imageConfig.getName(); - final AssemblyFiles files = serviceHub.getBuildService().getAssemblyFiles(name, imageConfig, mojoParameters); + + final AssemblyFiles files = serviceHub.getBuildService().getAssemblyFiles(name, imageConfig, mojoParameters, localRepository); return new Runnable() { @Override public void run() { - List entry = files.getUpdatedEntriesAndRefresh(); - if (entry != null && entry.size() > 0) { + + AssemblyConfiguration assemblyConfig = imageConfig.getBuildConfiguration().getAssemblyConfiguration(); + if( assemblyConfig!=null ) { + assemblyConfig.skip = true; + } + + List entries = files.getUpdatedEntriesAndRefresh(); + if (entries != null && entries.size() > 0) { try { log.info(imageConfig.getDescription() + ": Assembly changed. Rebuild ..."); - // Rebuild whole image for now ... + + for (AssemblyFiles.Entry entry : entries) { + log.info("Copying from:"+entry.getSrcFile()+", to:"+entry.getDestFile()); + FileUtils.copyFile(entry.getSrcFile(), entry.getDestFile()); + } + buildImage(docker, imageConfig); watcher.setImageId(serviceHub.getQueryService().getImageId(name)); @@ -152,7 +178,7 @@ public void run() { restartContainer(watcher); } callPostGoal(watcher); - } catch (DockerAccessException | MojoExecutionException | MojoFailureException e) { + } catch (MojoExecutionException | MojoFailureException | IOException e) { log.error(imageConfig.getDescription() + ": Error when rebuilding " + e); } } diff --git a/src/main/java/org/jolokia/docker/maven/assembly/AssemblyFiles.java b/src/main/java/org/jolokia/docker/maven/assembly/AssemblyFiles.java index fbdea9533..fb5e98dc9 100644 --- a/src/main/java/org/jolokia/docker/maven/assembly/AssemblyFiles.java +++ b/src/main/java/org/jolokia/docker/maven/assembly/AssemblyFiles.java @@ -72,12 +72,12 @@ private Entry(File srcFile, File destFile) { if (!srcFile.exists()) { throw new IllegalArgumentException("Source " + srcFile + " does not exist"); } + if (!destFile.exists()) { + throw new IllegalArgumentException("Destination " + destFile + " does not exist"); + } if (srcFile.isDirectory()) { throw new IllegalArgumentException("Can only watch files, not directories: " + srcFile); } - if (destFile.isAbsolute()) { - throw new IllegalArgumentException("Destination " + destFile + " must not be absolute"); - } this.lastModified = this.srcFile.lastModified(); } diff --git a/src/main/java/org/jolokia/docker/maven/assembly/DockerAssemblyManager.java b/src/main/java/org/jolokia/docker/maven/assembly/DockerAssemblyManager.java index 1d82e4104..f987d86c3 100644 --- a/src/main/java/org/jolokia/docker/maven/assembly/DockerAssemblyManager.java +++ b/src/main/java/org/jolokia/docker/maven/assembly/DockerAssemblyManager.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.util.List; +import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.assembly.AssemblerConfigurationSource; import org.apache.maven.plugin.assembly.InvalidAssemblerConfigurationException; @@ -93,7 +94,7 @@ public File createDockerTarArchive(String imageName, MojoParameters params, Buil * Extract all files with a tracking archiver. These can be used to track changes in the filesystem and triggering * a rebuild of the image if needed */ - public AssemblyFiles getAssemblyFiles(String imageName, BuildImageConfiguration buildConfig, MojoParameters params) + public AssemblyFiles getAssemblyFiles(String imageName, BuildImageConfiguration buildConfig, MojoParameters params, ArtifactRepository localRepository, File outputDirectory) throws InvalidAssemblerConfigurationException, ArchiveCreationException, AssemblyFormattingException, MojoExecutionException { BuildDirs buildDirs = createBuildDirs(imageName,params); @@ -106,6 +107,8 @@ public AssemblyFiles getAssemblyFiles(String imageName, BuildImageConfiguration synchronized (trackArchiver) { MappingTrackArchiver ta = (MappingTrackArchiver) trackArchiver; ta.clear(); + ta.setLocalRepository(localRepository); + ta.setDestFile(outputDirectory); assembly.setId("tracker"); assemblyArchiver.createArchive(assembly, "maven", "track", source, false); return ta.getAssemblyFiles(); @@ -119,7 +122,7 @@ private BuildDirs createBuildDirs(String imageName, MojoParameters params) { } private boolean hasAssemblyConfiguration(AssemblyConfiguration assemblyConfig) { - return assemblyConfig != null && + return assemblyConfig != null && !assemblyConfig.skip && (assemblyConfig.getInline() != null || assemblyConfig.getDescriptor() != null || assemblyConfig.getDescriptorRef() != null); diff --git a/src/main/java/org/jolokia/docker/maven/assembly/MappingTrackArchiver.java b/src/main/java/org/jolokia/docker/maven/assembly/MappingTrackArchiver.java index 4ac151bff..0fc05fad3 100644 --- a/src/main/java/org/jolokia/docker/maven/assembly/MappingTrackArchiver.java +++ b/src/main/java/org/jolokia/docker/maven/assembly/MappingTrackArchiver.java @@ -15,8 +15,21 @@ * limitations under the License. */ -import java.io.File; +import java.io.*; +import java.util.ArrayList; +import java.util.Properties; +import java.util.Set; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.DefaultArtifact; +import org.apache.maven.artifact.InvalidArtifactRTException; +import org.apache.maven.artifact.handler.ArtifactHandler; +import org.apache.maven.artifact.handler.DefaultArtifactHandler; +import org.apache.maven.artifact.repository.ArtifactRepository; +import org.apache.maven.model.Repository; +import org.apache.maven.project.MavenProject; import org.apache.maven.shared.utils.io.DirectoryScanner; import org.codehaus.plexus.archiver.FileSet; import org.codehaus.plexus.archiver.diags.TrackingArchiver; @@ -31,6 +44,8 @@ */ public class MappingTrackArchiver extends TrackingArchiver { + private ArtifactRepository localRepository; + public void clear() { added.clear(); } @@ -42,28 +57,131 @@ public void clear() { */ public AssemblyFiles getAssemblyFiles() { AssemblyFiles ret = new AssemblyFiles(); + File destFile = getDestFile(); + destFile = new File(destFile.getParentFile(), "maven"); for (Addition addition : added) { Object resource = addition.resource; + File target = new File(destFile, addition.destination); if (resource instanceof File && addition.destination != null) { - ret.addEntry((File) resource, new File(addition.destination)); + File source = (File) resource; + ret.addEntry(source, target); + addLocalMavenRepoWatch(ret, source, target); } else if (resource instanceof PlexusIoFileResource) { - ret.addEntry(((PlexusIoFileResource) resource).getFile(),new File(addition.destination)); + File source = ((PlexusIoFileResource) resource).getFile(); + ret.addEntry(source, target); + addLocalMavenRepoWatch(ret, source, target); } else if (resource instanceof FileSet) { FileSet fs = (FileSet) resource; DirectoryScanner ds = new DirectoryScanner(); File base = addition.directory; ds.setBasedir(base); ds.setIncludes(fs.getIncludes()); - ds.setExcludes(fs.getExcludes());; + ds.setExcludes(fs.getExcludes()); + ; ds.setCaseSensitive(fs.isCaseSensitive()); ds.scan(); for (String f : ds.getIncludedFiles()) { - ret.addEntry(new File(base,f),new File(addition.destination,f)); + File source = new File(base, f); + File subTarget = new File(target, f); + ret.addEntry(source, subTarget); + addLocalMavenRepoWatch(ret, source, target); } } else { throw new IllegalStateException("Unknown resource type " + resource.getClass() + ": " + resource); } } return ret; - }; + } + + private void addLocalMavenRepoWatch(AssemblyFiles ret, File source, File target) { + try { + File localMavenRepoFile = getlocalMavenRepoFile(source); + if (localMavenRepoFile!=null && !source.getCanonicalFile().equals(localMavenRepoFile.getCanonicalFile())) { + ret.addEntry(localMavenRepoFile, target); + } + } catch (IOException e) { + // Looks like we could not figure out if that file had a local mvn repo version. + } + } + + private File getlocalMavenRepoFile(File source) { + + if (localRepository == null) { + return null; + } + + // Lets figure the real mvn source of file. + String type = null; + if (source.getName().endsWith(".jar")) { + type = "jar"; + } + if (source.getName().endsWith(".war")) { + type = "war"; + } + if (type != null) { + Properties pomPropertiesFromJar = getPomPropertiesFromJar(source); + if (pomPropertiesFromJar != null) { + try { + DefaultArtifact a = new DefaultArtifact( + pomPropertiesFromJar.getProperty("groupId"), + pomPropertiesFromJar.getProperty("artifactId"), + pomPropertiesFromJar.getProperty("version"), + "runtime", + type, + pomPropertiesFromJar.getProperty("classifier", ""), + new DefaultArtifactHandler(type) + ); + File file = new File(localRepository.getBasedir(), localRepository.pathOf(a)); + if( file !=null ) { + if( isSame(file, source) ) { + return file; + } + } + } catch (InvalidArtifactRTException e) { + return null; + } + } + } + return null; + } + + private boolean isSame(File file, File source) { + return true; + } + + private Properties getPomPropertiesFromJar(File jar) { + try { + ArrayList options = new ArrayList(); + try (ZipInputStream in = new ZipInputStream(new FileInputStream(jar))) { + ZipEntry entry; + while ((entry = in.getNextEntry()) != null) { + if (entry.getName().startsWith("META-INF/maven/") && entry.getName().endsWith("pom.properties")) { + byte[] buf = new byte[1024]; + int len; + ByteArrayOutputStream out = new ByteArrayOutputStream(); //change ouptut stream as required + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + Properties properties = new Properties(); + properties.load(new ByteArrayInputStream(out.toByteArray())); + options.add(properties); + } + } + } + if (options.size() == 1) { + return options.get(0); + } + } catch (IOException e) { + } + return null; + } + + public ArtifactRepository getLocalRepository() { + return localRepository; + } + + public void setLocalRepository(ArtifactRepository localRepository) { + this.localRepository = localRepository; + } + } diff --git a/src/main/java/org/jolokia/docker/maven/config/AssemblyConfiguration.java b/src/main/java/org/jolokia/docker/maven/config/AssemblyConfiguration.java index 0308bd2f4..2e2897b7f 100644 --- a/src/main/java/org/jolokia/docker/maven/config/AssemblyConfiguration.java +++ b/src/main/java/org/jolokia/docker/maven/config/AssemblyConfiguration.java @@ -51,7 +51,9 @@ public class AssemblyConfiguration { * @parameter */ private String user; - + + public boolean skip; + public AssemblyConfiguration() { } diff --git a/src/main/java/org/jolokia/docker/maven/service/BuildService.java b/src/main/java/org/jolokia/docker/maven/service/BuildService.java index a2b2c7578..b1ac8cd8f 100644 --- a/src/main/java/org/jolokia/docker/maven/service/BuildService.java +++ b/src/main/java/org/jolokia/docker/maven/service/BuildService.java @@ -2,6 +2,7 @@ import java.io.File; +import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.assembly.InvalidAssemblerConfigurationException; import org.apache.maven.plugin.assembly.archive.ArchiveCreationException; @@ -9,6 +10,7 @@ import org.jolokia.docker.maven.access.DockerAccess; import org.jolokia.docker.maven.access.DockerAccessException; import org.jolokia.docker.maven.assembly.AssemblyFiles; +import org.jolokia.docker.maven.assembly.BuildDirs; import org.jolokia.docker.maven.assembly.DockerAssemblyManager; import org.jolokia.docker.maven.config.BuildImageConfiguration; import org.jolokia.docker.maven.config.ImageConfiguration; @@ -60,11 +62,14 @@ public void buildImage(ImageConfiguration imageConfig, MojoParameters params) } } - public AssemblyFiles getAssemblyFiles(String name, ImageConfiguration imageConfig, MojoParameters mojoParameters) + public AssemblyFiles getAssemblyFiles(String name, ImageConfiguration imageConfig, MojoParameters mojoParameters, ArtifactRepository localRepository) throws MojoExecutionException { try { - return dockerAssemblyManager.getAssemblyFiles(name, imageConfig.getBuildConfiguration(), mojoParameters); + BuildDirs buildDirs = new BuildDirs(mojoParameters, imageConfig.getName()); + File outputDirectory = new File(buildDirs.getOutputDirectory(), "maven"); + + return dockerAssemblyManager.getAssemblyFiles(name, imageConfig.getBuildConfiguration(), mojoParameters, localRepository, outputDirectory); } catch (InvalidAssemblerConfigurationException | ArchiveCreationException | AssemblyFormattingException e) { throw new MojoExecutionException("Cannot extract assembly files for image " + name + ": " + e, e); } diff --git a/src/test/java/org/jolokia/docker/maven/assembly/DockerAssemblyManagerTest.java b/src/test/java/org/jolokia/docker/maven/assembly/DockerAssemblyManagerTest.java index d245b534e..c842a96b2 100644 --- a/src/test/java/org/jolokia/docker/maven/assembly/DockerAssemblyManagerTest.java +++ b/src/test/java/org/jolokia/docker/maven/assembly/DockerAssemblyManagerTest.java @@ -1,5 +1,6 @@ package org.jolokia.docker.maven.assembly; +import java.io.File; import java.util.Arrays; import mockit.*; @@ -81,5 +82,5 @@ public void assemblyFiles(@Injectable final MojoParameters mojoParams, .build()) .build(); - assemblyManager.getAssemblyFiles("testImage", buildConfig, mojoParams);} + assemblyManager.getAssemblyFiles("testImage", buildConfig, mojoParams, null, new File("."));} } diff --git a/src/test/java/org/jolokia/docker/maven/assembly/MappingTrackArchiverTest.java b/src/test/java/org/jolokia/docker/maven/assembly/MappingTrackArchiverTest.java index ce05538b1..8bac9e4f1 100644 --- a/src/test/java/org/jolokia/docker/maven/assembly/MappingTrackArchiverTest.java +++ b/src/test/java/org/jolokia/docker/maven/assembly/MappingTrackArchiverTest.java @@ -33,6 +33,7 @@ public class MappingTrackArchiverTest { @Test(expected = IllegalArgumentException.class) public void noDirectory() throws Exception { MappingTrackArchiver archiver = new MappingTrackArchiver(); + archiver.setDestFile(new File(".")); archiver.addDirectory(new File(System.getProperty("user.home")), "tmp"); AssemblyFiles files = archiver.getAssemblyFiles(); } @@ -40,7 +41,13 @@ public void noDirectory() throws Exception { @Test public void simple() throws Exception { MappingTrackArchiver archiver = new MappingTrackArchiver(); + archiver.setDestFile(new File("target/test-data/maven.tracker")); + new File(archiver.getDestFile(), "maven").mkdirs(); + File tempFile = File.createTempFile("tracker", "txt"); + File destination = new File("target/test-data/maven/test.txt"); + org.codehaus.plexus.util.FileUtils.copyFile(tempFile, destination); + archiver.addFile(tempFile, "test.txt"); AssemblyFiles files = archiver.getAssemblyFiles(); assertNotNull(files); @@ -52,6 +59,6 @@ public void simple() throws Exception { assertEquals(1,entries.size()); AssemblyFiles.Entry entry = entries.get(0); assertEquals(tempFile,entry.getSrcFile()); - assertEquals(new File("test.txt"),entry.getDestFile()); + assertEquals(destination, entry.getDestFile()); } }