desruisseaux commented on code in PR #508: URL: https://github.com/apache/maven-jar-plugin/pull/508#discussion_r3923470413
########## src/main/java/org/apache/maven/plugins/jar/FileCollector.java: ########## @@ -0,0 +1,541 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.maven.plugins.jar; + +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.PathMatcher; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.apache.maven.api.annotations.Nonnull; +import org.apache.maven.api.annotations.Nullable; +import org.apache.maven.api.services.PathMatcherFactory; + +/** + * Dispatch the files from the output directory into the <abbr>JAR</abbr> files to create. + * Instead of just archiving as-is the content of the output directory, this class separates + * the following subdirectories to the options listed below: + * + * <ul> + * <li>The {@code META-INF/MANIFEST.MF} file will be given to the {@code --manifest} option.</li> + * <li>Files in the following directories will be given to the {@code --release} option: + * <ul> + * <li>{@code META-INF/versions/}</li> + * <li>{@code META-INF/versions-modular/<module>/}</li> + * <li>{@code <module>/META-INF/versions/}</li> + * </ul> + * </li> + * </ul> + * + * The reason for using the options is that they allow the {@code jar} tool to perform additional verifications. + * For example, when using the {@code --release} option, {@code jar} verifies the <abbr>API</abbr> compatibility. + */ +final class FileCollector extends SimpleFileVisitor<Path> { + /** + * The file to check for deciding whether the <abbr>JAR</abbr> is modular. + */ + static final String MODULE_DESCRIPTOR_FILE_NAME = "module-info.class"; + + /** + * The {@value} directory. + * This is part of <abbr>JAR</abbr> file specification. + */ + private static final String VERSIONS = "versions"; + + /** + * The {@value} directory. + * This is Maven-specific. + */ + private static final String VERSIONS_MODULAR = "versions-modular"; + + /** + * Context (logger, configuration) in which the <abbr>JAR</abbr> file are created. + */ + private final ToolExecutor context; + + /** + * Whether to detect multi-release <abbr>JAR</abbr> files. + * The default value is {@code true}. + * + * @see AbstractJarMojo#detectMultiReleaseJar + */ + private final boolean detectMultiReleaseJar; + + /** + * The root directory to traverse. It will be used for temporarily moving excluded files. + */ + private final Path rootDirectory; + + /** + * Combination of includes and excludes path matcher applied on files. + */ + @Nonnull + private final PathMatcher fileMatcher; + + /** + * Combination of includes and excludes path matcher applied on directories. + */ + @Nonnull + private final PathMatcher directoryMatcher; + + /** + * Files to exclude. These files will be moved to a temporary location + * for allowing {@link ToolExecutor} to specify whole directories to the {@code jar} tool. + * Specifying whole directories is preferable to enumerating the files because otherwise, + * the generated <abbr>JAR</abbr> file contains only entries for the files and is missing + * entries for the directories. + * + * <p>This field is {@code null} if it is not possible to have any excluded file + * (because there is no include/exclude filters).</p> + */ + @Nullable + private final List<Path> excludedFiles; + + /** + * Directories to exclude. This field serves the same purpose as {@link #excludedFiles}, + * but where the sources a directories instead of files. + */ + @Nullable + private final List<Path> excludedDirectories; + + /** + * Files found in the output directory when package hierarchy is used. + * At most one of {@code packageHierarchy} and {@link #moduleHierarchy} can be non-empty. + */ + @Nonnull + private final Archive packageHierarchy; + + /** + * Files found in the output directory when module hierarchy is used. Keys are module names. + * At most one of {@link #packageHierarchy} and {@code moduleHierarchy} can be non-empty. + */ + @Nonnull + private final Map<String, Archive> moduleHierarchy; + + /** + * The current module being archived. This field is updated every times that {@code FileCollector} + * visits a new module directory. + */ + @Nonnull + private Archive currentModule; + + /** + * The module and target Java release currently being scanned. This field is updated every times that + * {@code FileCollector} visits a new module directory or in a new target Java release for a given module. + */ + @Nonnull + private Archive.FileSet currentFilesToArchive; + + /** + * The current target Java release, or {@code null} if none. + */ + @Nullable + private Runtime.Version currentTargetVersion; + + /** + * Identification of the kinds of directories being traversed. + * The length of this list is the depth in the directory hierarchy. + * The last element identifies the type of the current directory. + */ + private final Deque<DirectoryRole> directoryRoles; + + /** + * Whether to check when a file is the {@code MANIFEST.MF} file. + * This is allowed only when scanning the content of a {@code META-INF} directory. + */ + private boolean checkForManifest; + + /** + * Creates a new file collector. + * + * @param mojo the <abbr>MOJO</abbr> from which to get the configuration + * @param context context (logger, configuration) in which the <abbr>JAR</abbr> file are created + * @param directory the base directory of the files to archive + */ + FileCollector(AbstractJarMojo mojo, ToolExecutor context, Path directory, PathMatcherFactory matcherFactory) { + this.context = context; + rootDirectory = directory; + detectMultiReleaseJar = mojo.detectMultiReleaseJar; + directoryRoles = new ArrayDeque<>(); + fileMatcher = matcherFactory.createPathMatcher(directory, mojo.getIncludes(), mojo.getExcludes(), false); + directoryMatcher = matcherFactory.deriveDirectoryMatcher(fileMatcher); + if (matcherFactory.isIncludesAll(fileMatcher) && matcherFactory.isIncludesAll(directoryMatcher)) { + excludedFiles = null; + excludedDirectories = null; + } else { + excludedFiles = new ArrayList<>(); + excludedDirectories = new ArrayList<>(); + } + packageHierarchy = context.newArchive(null, null, directory); + moduleHierarchy = new LinkedHashMap<>(); + resetToPackageHierarchy(); + } + + /** + * Resets this {@code FileCollector} to the state where a package hierarchy is presumed. + */ + private void resetToPackageHierarchy() { + currentModule = packageHierarchy; + currentFilesToArchive = currentModule.baseRelease(); + } + + /** + * Declares that the given directory is the base directory of a module. + * For an output generated by {@code javac} from a module source hierarchy, + * the directory name is guaranteed to be the module name. Review Comment: Done. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
