| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
| Collector |
|
| 6.666666666666667;6,667 |
| 1 | /* | |
| 2 | * Geotoolkit - An Open Source Java GIS Tookit | |
| 3 | * http://www.geotoolkit.org | |
| 4 | * | |
| 5 | * (C) 2005-2012, Open Source Geospatial Foundation (OSGeo) | |
| 6 | * (C) 2009-2012, Geomatys | |
| 7 | * | |
| 8 | * This library is free software; you can redistribute it and/or | |
| 9 | * modify it under the terms of the GNU Lesser General Public | |
| 10 | * License as published by the Free Software Foundation; | |
| 11 | * version 2.1 of the License. | |
| 12 | * | |
| 13 | * This library is distributed in the hope that it will be useful, | |
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 16 | * Lesser General Public License for more details. | |
| 17 | */ | |
| 18 | package org.geotoolkit.maven.jar; | |
| 19 | ||
| 20 | import java.io.File; | |
| 21 | import java.io.FileFilter; | |
| 22 | import java.io.FileInputStream; | |
| 23 | import java.io.FileOutputStream; | |
| 24 | import java.io.IOException; | |
| 25 | import java.util.Set; | |
| 26 | ||
| 27 | import org.apache.maven.plugin.AbstractMojo; | |
| 28 | import org.apache.maven.plugin.MojoExecutionException; | |
| 29 | import org.apache.maven.project.MavenProject; | |
| 30 | import org.apache.maven.artifact.Artifact; | |
| 31 | ||
| 32 | ||
| 33 | /** | |
| 34 | * Copies <code>.jar</code> files in a single directory. Dependencies are copied as well, | |
| 35 | * except if already presents. | |
| 36 | * | |
| 37 | * @author Martin Desruisseaux (IRD, Geomatys) | |
| 38 | * @version 3.20 | |
| 39 | * | |
| 40 | * @since 2.2 | |
| 41 | * | |
| 42 | * @goal collect | |
| 43 | * @phase package | |
| 44 | * @requiresDependencyResolution runtime | |
| 45 | */ | |
| 46 | 0 | public class Collector extends AbstractMojo implements FileFilter { |
| 47 | /** | |
| 48 | * The sub directory to create inside the "target" directory. | |
| 49 | */ | |
| 50 | static final String SUB_DIRECTORY = "binaries"; | |
| 51 | ||
| 52 | /** | |
| 53 | * The directory where JARs are to be copied. It should | |
| 54 | * be the "target" directory of the parent {@code pom.xml}. | |
| 55 | */ | |
| 56 | private String collectDirectory; | |
| 57 | ||
| 58 | /** | |
| 59 | * Directory containing the generated JAR. | |
| 60 | * | |
| 61 | * @parameter expression="${project.build.directory}" | |
| 62 | * @required | |
| 63 | */ | |
| 64 | private String outputDirectory; | |
| 65 | ||
| 66 | /** | |
| 67 | * Name of the generated JAR. | |
| 68 | * | |
| 69 | * @parameter expression="${project.build.finalName}" | |
| 70 | * @required | |
| 71 | */ | |
| 72 | private String jarName; | |
| 73 | ||
| 74 | /** | |
| 75 | * The Maven project running this plugin. | |
| 76 | * | |
| 77 | * @parameter expression="${project}" | |
| 78 | * @required | |
| 79 | */ | |
| 80 | private MavenProject project; | |
| 81 | ||
| 82 | /** | |
| 83 | * Copies the {@code .jar} files to the collect directory. | |
| 84 | * | |
| 85 | * @throws MojoExecutionException if the plugin execution failed. | |
| 86 | */ | |
| 87 | @Override | |
| 88 | public void execute() throws MojoExecutionException { | |
| 89 | /* | |
| 90 | * Gets the parent "target" directory. | |
| 91 | */ | |
| 92 | 0 | MavenProject parent = project; |
| 93 | 0 | while (parent.hasParent()) { |
| 94 | 0 | parent = parent.getParent(); |
| 95 | } | |
| 96 | 0 | collectDirectory = parent.getBuild().getDirectory(); |
| 97 | 0 | if (collectDirectory.startsWith("${")) { |
| 98 | 0 | getLog().warn("Unresolved directory: " + collectDirectory); |
| 99 | 0 | return; |
| 100 | } | |
| 101 | /* | |
| 102 | * Now collects the JARs. | |
| 103 | */ | |
| 104 | try { | |
| 105 | 0 | collect(); |
| 106 | 0 | } catch (IOException e) { |
| 107 | 0 | throw new MojoExecutionException("Error collecting the JAR file.", e); |
| 108 | 0 | } |
| 109 | 0 | } |
| 110 | ||
| 111 | /** | |
| 112 | * Implementation of the {@link #execute()} method. | |
| 113 | */ | |
| 114 | private void collect() throws MojoExecutionException, IOException { | |
| 115 | /* | |
| 116 | * Make sure that we are collecting the JAR file from a module which produced | |
| 117 | * such file. Some modules use pom packaging, which do not produce any JAR file. | |
| 118 | */ | |
| 119 | 0 | final File jarFile = getProjectFile(); |
| 120 | 0 | if (jarFile == null) { |
| 121 | 0 | return; |
| 122 | } | |
| 123 | /* | |
| 124 | * Get the "target" directory of the parent pom.xml and make sure it exists. | |
| 125 | */ | |
| 126 | 0 | File collect = new File(collectDirectory); |
| 127 | 0 | if (!collect.exists()) { |
| 128 | 0 | if (!collect.mkdir()) { |
| 129 | 0 | throw new MojoExecutionException("Failed to create target directory."); |
| 130 | } | |
| 131 | } | |
| 132 | 0 | if (collect.getCanonicalFile().equals(jarFile.getParentFile().getCanonicalFile())) { |
| 133 | /* | |
| 134 | * The parent's directory is the same one than this module's directory. | |
| 135 | * In other words, this plugin is not executed from the parent POM. Do | |
| 136 | * not copy anything, since this is not the place where we want to | |
| 137 | * collect the JAR files. | |
| 138 | */ | |
| 139 | 0 | return; |
| 140 | } | |
| 141 | /* | |
| 142 | * Creates a "binaries" subdirectory inside the "target" directory, then copy the | |
| 143 | * JAR file compiled by Maven. If an JAR file already existed, it will be deleted. | |
| 144 | */ | |
| 145 | 0 | collect = new File(collect, SUB_DIRECTORY); |
| 146 | 0 | if (!collect.exists()) { |
| 147 | 0 | if (!collect.mkdir()) { |
| 148 | 0 | throw new MojoExecutionException("Failed to create binaries directory."); |
| 149 | } | |
| 150 | } | |
| 151 | 0 | File copy = new File(collect, jarFile.getName()); |
| 152 | 0 | copy.delete(); |
| 153 | 0 | copyFileToDirectory(jarFile, copy); |
| 154 | /* | |
| 155 | * Copies the dependencies. | |
| 156 | */ | |
| 157 | 0 | final Set<Artifact> dependencies = project.getArtifacts(); |
| 158 | 0 | if (dependencies != null) { |
| 159 | 0 | for (final Artifact artifact : dependencies) { |
| 160 | 0 | final String scope = artifact.getScope(); |
| 161 | 0 | if (scope != null && // Maven 2.0.6 bug? |
| 162 | (scope.equalsIgnoreCase(Artifact.SCOPE_COMPILE) || | |
| 163 | scope.equalsIgnoreCase(Artifact.SCOPE_RUNTIME))) | |
| 164 | { | |
| 165 | 0 | final File file = artifact.getFile(); |
| 166 | 0 | if (file != null) { // I'm not sure why the file is sometime null... |
| 167 | 0 | copy = new File(collect, getFinalName(file, artifact)); |
| 168 | 0 | if (!copy.exists()) { |
| 169 | /* | |
| 170 | * Copies the dependency only if it was not already copied. Note that | |
| 171 | * the module's JAR was copied unconditionally above (because it may | |
| 172 | * be the result of a new compilation). | |
| 173 | */ | |
| 174 | 0 | copyFileToDirectory(file, copy); |
| 175 | } | |
| 176 | } | |
| 177 | } | |
| 178 | 0 | } |
| 179 | } | |
| 180 | 0 | } |
| 181 | ||
| 182 | /** | |
| 183 | * Filters the content of the "target" directory in order to keep only the project | |
| 184 | * build result. We scan the directory because the final name may be different than | |
| 185 | * the {@link #jarName} declaration, because a classifier may have been added to the | |
| 186 | * name. | |
| 187 | * <p> | |
| 188 | * <b>Complain:</b> Why the hell peoples use the {@code ".jar"} file extension for what | |
| 189 | * should be plain source and javadoc {@code ".zip"} files? | |
| 190 | */ | |
| 191 | @Override | |
| 192 | public boolean accept(final File pathname) { | |
| 193 | 0 | final String name = pathname.getName(); |
| 194 | 0 | return name.startsWith(jarName) && name.endsWith(".jar") && |
| 195 | !name.endsWith("-sources.jar") && !name.endsWith("-javadoc.jar") && pathname.isFile(); | |
| 196 | } | |
| 197 | ||
| 198 | /** | |
| 199 | * Returns the JAR file, or {@code null} if none. | |
| 200 | * In case of doubt, conservatively returns {@code null}. | |
| 201 | */ | |
| 202 | private File getProjectFile() { | |
| 203 | 0 | final File[] files = new File(outputDirectory).listFiles(this); |
| 204 | 0 | if (files != null && files.length == 1) { |
| 205 | 0 | return files[0]; |
| 206 | } | |
| 207 | 0 | return null; |
| 208 | } | |
| 209 | ||
| 210 | /** | |
| 211 | * Returns the name of the given file. If the given file is a snapshot, then the | |
| 212 | * {@code "SNAPSHOT"} will be replaced by the timestamp if possible. | |
| 213 | * | |
| 214 | * @param file The file from which to get the filename. | |
| 215 | * @param artifact The artifact that produced the given file. | |
| 216 | * @return The filename to use. | |
| 217 | * | |
| 218 | * @since 3.18 | |
| 219 | */ | |
| 220 | private static String getFinalName(final File file, final Artifact artifact) { | |
| 221 | 0 | String filename = file.getName(); |
| 222 | 0 | final String baseVersion = artifact.getBaseVersion(); |
| 223 | 0 | if (baseVersion != null) { |
| 224 | 0 | final int pos = filename.lastIndexOf(baseVersion); |
| 225 | 0 | if (pos >= 0) { |
| 226 | 0 | final String version = artifact.getVersion(); |
| 227 | 0 | if (version != null && !baseVersion.equals(version)) { |
| 228 | 0 | filename = filename.substring(0, pos) + version + filename.substring(pos + baseVersion.length()); |
| 229 | } | |
| 230 | } | |
| 231 | } | |
| 232 | 0 | return filename; |
| 233 | } | |
| 234 | ||
| 235 | /** | |
| 236 | * Copies the given file to the given target file. | |
| 237 | * | |
| 238 | * @param file The source file to read. | |
| 239 | * @param copy The destination file to create. | |
| 240 | */ | |
| 241 | private static void copyFileToDirectory(final File file, final File copy) throws IOException { | |
| 242 | 0 | final FileInputStream in = new FileInputStream(file); |
| 243 | 0 | final FileOutputStream out = new FileOutputStream(copy); |
| 244 | 0 | final byte[] buffer = new byte[4096]; |
| 245 | int c; | |
| 246 | 0 | while ((c = in.read(buffer)) >= 0) { |
| 247 | 0 | out.write(buffer, 0, c); |
| 248 | } | |
| 249 | 0 | out.close(); |
| 250 | 0 | in.close(); |
| 251 | 0 | } |
| 252 | } |