Skip to content

Commit 904c25a

Browse files
committed
Add imagej-maven-plugin's sources
The sources are based on imagej/imagej-maven-plugin#9240da2 with the sources moved into the correct packages already. In addition to the already available imagej.* properties, scijava.* properties have been added with compatibility between those properties.
1 parent fcb14cf commit 904c25a

File tree

3 files changed

+1038
-0
lines changed

3 files changed

+1038
-0
lines changed
Lines changed: 311 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,311 @@
1+
/*
2+
* #%L
3+
* ImageJ software for multidimensional image processing and analysis.
4+
* %%
5+
* Copyright (C) 2012 - 2016 Board of Regents of the University of
6+
* Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck
7+
* Institute of Molecular Cell Biology and Genetics.
8+
* %%
9+
* Redistribution and use in source and binary forms, with or without
10+
* modification, are permitted provided that the following conditions are met:
11+
*
12+
* 1. Redistributions of source code must retain the above copyright notice,
13+
* this list of conditions and the following disclaimer.
14+
* 2. Redistributions in binary form must reproduce the above copyright notice,
15+
* this list of conditions and the following disclaimer in the documentation
16+
* and/or other materials provided with the distribution.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28+
* POSSIBILITY OF SUCH DAMAGE.
29+
* #L%
30+
*/
31+
32+
package org.scijava.maven.plugin.install;
33+
34+
import java.io.File;
35+
import java.io.IOException;
36+
import java.nio.file.Files;
37+
import java.nio.file.Path;
38+
import java.nio.file.Paths;
39+
import java.util.ArrayList;
40+
import java.util.Collection;
41+
import java.util.Collections;
42+
import java.util.List;
43+
import java.util.jar.JarEntry;
44+
import java.util.jar.JarFile;
45+
import java.util.regex.Matcher;
46+
import java.util.regex.Pattern;
47+
import java.util.stream.Collectors;
48+
49+
import org.apache.maven.artifact.Artifact;
50+
import org.apache.maven.execution.MavenSession;
51+
import org.apache.maven.model.Dependency;
52+
import org.apache.maven.plugin.AbstractMojo;
53+
import org.apache.maven.plugin.MojoExecutionException;
54+
import org.apache.maven.project.MavenProject;
55+
import org.codehaus.plexus.interpolation.EnvarBasedValueSource;
56+
import org.codehaus.plexus.interpolation.ObjectBasedValueSource;
57+
import org.codehaus.plexus.interpolation.PrefixAwareRecursionInterceptor;
58+
import org.codehaus.plexus.interpolation.PrefixedValueSourceWrapper;
59+
import org.codehaus.plexus.interpolation.PropertiesBasedValueSource;
60+
import org.codehaus.plexus.interpolation.RecursionInterceptor;
61+
import org.codehaus.plexus.interpolation.RegexBasedInterpolator;
62+
import org.codehaus.plexus.util.FileUtils;
63+
import org.scijava.util.VersionUtils;
64+
65+
/**
66+
* Base class for mojos to copy .jar artifacts and their dependencies into a
67+
* SciJava application directory structure.
68+
*
69+
* @author Johannes Schindelin
70+
*/
71+
public abstract class AbstractCopyJarsMojo extends AbstractMojo {
72+
73+
public static final String imagejDirectoryProperty = "imagej.app.directory";
74+
public static final String imagejSubdirectoryProperty = "imagej.app.subdirectory";
75+
public static final String deleteOtherVersionsProperty = "delete.other.versions";
76+
public static final String imagejDeleteOtherVersionsPolicyProperty = "imagej.deleteOtherVersions";
77+
78+
public static final String appDirectoryProperty = "scijava.app.directory";
79+
public static final String appSubdirectoryProperty = "scijava.app.subdirectory";
80+
public static final String deleteOtherVersionsPolicyProperty = "scijava.deleteOtherVersions";
81+
public static final String ignoreDependenciesProperty = "scijava.ignoreDependencies";
82+
83+
public enum OtherVersions {
84+
always, older, never
85+
}
86+
87+
protected boolean hasIJ1Dependency(final MavenProject project) {
88+
final List<Dependency> dependencies = project.getDependencies();
89+
for (final Dependency dependency : dependencies) {
90+
final String artifactId = dependency.getArtifactId();
91+
if ("ij".equals(artifactId) || "imagej".equals(artifactId)) return true;
92+
}
93+
return false;
94+
}
95+
96+
protected String interpolate(final String original,
97+
final MavenProject project, final MavenSession session)
98+
throws MojoExecutionException
99+
{
100+
if (original == null || original.indexOf("${") < 0) return original;
101+
try {
102+
RegexBasedInterpolator interpolator = new RegexBasedInterpolator();
103+
104+
interpolator.addValueSource(new EnvarBasedValueSource());
105+
interpolator.addValueSource(new PropertiesBasedValueSource(System
106+
.getProperties()));
107+
108+
List<String> synonymPrefixes = new ArrayList<>();
109+
synonymPrefixes.add("project.");
110+
synonymPrefixes.add("pom.");
111+
112+
if (project != null) {
113+
PrefixedValueSourceWrapper modelWrapper =
114+
new PrefixedValueSourceWrapper(new ObjectBasedValueSource(project
115+
.getModel()), synonymPrefixes, true);
116+
interpolator.addValueSource(modelWrapper);
117+
118+
PrefixedValueSourceWrapper pomPropertyWrapper =
119+
new PrefixedValueSourceWrapper(new PropertiesBasedValueSource(project
120+
.getModel().getProperties()), synonymPrefixes, true);
121+
interpolator.addValueSource(pomPropertyWrapper);
122+
}
123+
124+
if (session != null) {
125+
interpolator.addValueSource(new PropertiesBasedValueSource(session
126+
.getExecutionProperties()));
127+
}
128+
129+
RecursionInterceptor recursionInterceptor =
130+
new PrefixAwareRecursionInterceptor(synonymPrefixes, true);
131+
return interpolator.interpolate(original, recursionInterceptor);
132+
}
133+
catch (Exception e) {
134+
throw new MojoExecutionException("Could not interpolate '" + original +
135+
"'", e);
136+
}
137+
}
138+
139+
protected void installArtifact(final Artifact artifact,
140+
final File imagejDirectory, final boolean force,
141+
final OtherVersions otherVersionsPolicy) throws IOException
142+
{
143+
installArtifact(artifact, imagejDirectory, "", force, otherVersionsPolicy);
144+
}
145+
146+
protected void installArtifact(final Artifact artifact,
147+
final File imagejDirectory, final String subdirectory, final boolean force,
148+
final OtherVersions otherVersionsPolicy) throws IOException
149+
{
150+
if (!"jar".equals(artifact.getType())) return;
151+
152+
final File source = artifact.getFile();
153+
final File targetDirectory;
154+
155+
if (subdirectory != null && !subdirectory.equals("")) {
156+
targetDirectory = new File(imagejDirectory, subdirectory);
157+
} else if (isIJ1Plugin(source)) {
158+
targetDirectory = new File(imagejDirectory, "plugins");
159+
}
160+
else if ("ome".equals(artifact.getGroupId()) ||
161+
("loci".equals(artifact.getGroupId()) && (source.getName().startsWith(
162+
"scifio-4.4.") || source.getName().startsWith("jai_imageio-4.4."))))
163+
{
164+
targetDirectory = new File(imagejDirectory, "jars/bio-formats");
165+
}
166+
else {
167+
targetDirectory = new File(imagejDirectory, "jars");
168+
}
169+
final String fileName = "Fiji_Updater".equals(artifact.getArtifactId())
170+
? artifact.getArtifactId() + ".jar" : source.getName();
171+
final File target = new File(targetDirectory, fileName);
172+
173+
boolean newerVersion = false;
174+
final Path directoryPath = Paths.get(imagejDirectory.toURI());
175+
final Path targetPath = Paths.get(target.toURI());
176+
final Collection<Path> otherVersions = //
177+
getEncroachingVersions(directoryPath, targetPath);
178+
if (otherVersions != null && !otherVersions.isEmpty()) {
179+
for (final Path other : otherVersions) {
180+
final Path otherName = other.getFileName();
181+
switch (otherVersionsPolicy) {
182+
case never:
183+
getLog().warn("Possibly incompatible version exists: " + otherName);
184+
break;
185+
case older:
186+
final String toInstall = artifact.getVersion();
187+
final Matcher matcher = versionPattern.matcher(otherName.toString());
188+
if (!matcher.matches()) break;
189+
final String group = matcher.group(VERSION_INDEX);
190+
if (group == null) {
191+
newerVersion = true;
192+
getLog().warn("Impenetrable version suffix for file: " +
193+
otherName);
194+
}
195+
else {
196+
final String otherVersion = group.substring(1);
197+
newerVersion = VersionUtils.compare(toInstall, otherVersion) < 0;
198+
if (majorVersion(toInstall) != majorVersion(otherVersion)) {
199+
getLog().warn(
200+
"Found other version that is incompatible according to SemVer: " +
201+
otherVersion);
202+
}
203+
}
204+
if (newerVersion) break;
205+
//$FALL-THROUGH$
206+
case always:
207+
if (Files.deleteIfExists(other)) {
208+
getLog().info("Deleted overridden " + otherName);
209+
newerVersion = false;
210+
}
211+
else getLog().warn("Could not delete overridden " + otherName);
212+
break;
213+
}
214+
}
215+
}
216+
217+
if (!force && target.exists() &&
218+
target.lastModified() > source.lastModified())
219+
{
220+
getLog().info("Dependency " + fileName + " is already there; skipping");
221+
}
222+
else if (newerVersion) {
223+
getLog().info("A newer version for " + fileName + " was detected; skipping");
224+
}
225+
else {
226+
getLog().info("Copying " + fileName + " to " + targetDirectory);
227+
FileUtils.copyFile(source, target);
228+
}
229+
}
230+
231+
private static boolean isIJ1Plugin(final File file) {
232+
final String name = file.getName();
233+
if (name.indexOf('_') < 0 || !file.exists()) return false;
234+
if (file.isDirectory()) {
235+
return new File(file, "src/main/resources/plugins.config").exists();
236+
}
237+
if (!name.endsWith(".jar")) return false;
238+
239+
try (final JarFile jar = new JarFile(file)) {
240+
for (final JarEntry entry : Collections.list(jar.entries())) {
241+
if (entry.getName().equals("plugins.config")) {
242+
jar.close();
243+
return true;
244+
}
245+
}
246+
}
247+
catch (final Throwable t) {
248+
// obviously not a plugin...
249+
}
250+
return false;
251+
}
252+
253+
private final static Pattern versionPattern = Pattern.compile("(.+?)"
254+
+ "(-\\d+(\\.\\d+|\\d{7})+[a-z]?\\d?(-[A-Za-z0-9.]+?|\\.GA)*?)?"
255+
+ "((-(swing|swt|sources|javadoc|native|linux-x86|linux-x86_64|macosx-x86_64|windows-x86|windows-x86_64|android-arm|android-x86|natives-windows|natives-macos|natives-linux))?(\\.jar(-[a-z]*)?))");
256+
private final static int PREFIX_INDEX = 1;
257+
private final static int VERSION_INDEX = 2;
258+
private final static int SUFFIX_INDEX = 5;
259+
260+
/**
261+
* Extracts the major version (according to SemVer) from a version string.
262+
* If no dot is found, the input is returned.
263+
*
264+
* @param v
265+
* SemVer version string
266+
* @return The major version (according to SemVer) as {@code String}.
267+
*/
268+
private String majorVersion( String v )
269+
{
270+
final int dot = v.indexOf('.');
271+
return dot < 0 ? v : v.substring(0, dot);
272+
}
273+
274+
/**
275+
* Looks for files in {@code directory} with the same base name as
276+
* {@code file}.
277+
*
278+
* @param directory The directory to walk to find possible duplicates.
279+
* @param file A {@link Path} to the target (from which the base name is
280+
* derived).
281+
* @return A collection of {@link Path}s to files of the same base name.
282+
*/
283+
private Collection<Path> getEncroachingVersions(final Path directory, final Path file) {
284+
final Matcher matcher = versionPattern.matcher(file.getFileName().toString());
285+
if (!matcher.matches()) return null;
286+
287+
final String prefix = matcher.group(PREFIX_INDEX);
288+
final String suffix = matcher.group(SUFFIX_INDEX);
289+
290+
Collection<Path> result = new ArrayList<>();
291+
try {
292+
result = Files.walk(directory)
293+
.filter(path -> path.getFileName().toString().startsWith(prefix))
294+
.filter(path -> {
295+
final Matcher matcherIterator = versionPattern.matcher(path.getFileName().toString());
296+
return matcherIterator.matches() &&
297+
prefix.equals(matcherIterator.group(PREFIX_INDEX)) &&
298+
suffix.equals(matcherIterator.group(SUFFIX_INDEX));
299+
})
300+
.filter(path -> !path.getFileName().toString().equals(file.getFileName().toString()))
301+
.collect(Collectors.toCollection(ArrayList::new));
302+
return result;
303+
} catch (IOException e) {
304+
getLog().error(e);
305+
} finally {
306+
result = new ArrayList<>();
307+
}
308+
309+
return result;
310+
}
311+
}

0 commit comments

Comments
 (0)