-
Notifications
You must be signed in to change notification settings - Fork 56
feat: add purge-check goal to detect and remove orphaned build directories #356
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
gnodet
wants to merge
11
commits into
apache:master
Choose a base branch
from
gnodet:feat/purge-check-orphan-build-dirs
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+388
−0
Open
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
5d9f25b
feat: add purge-check goal to detect and remove orphaned build direct…
gnodet fb5f3cf
fix: apply spotless formatting to IT pom files
gnodet 59acbe7
refactor: single DirectoryStream per candidate dir in purge-check
gnodet 83452d7
refactor: move post-loop checks outside try-with-resources in orphanB…
gnodet 90e0375
refactor: remove entire orphaned directory, not just its target/ subd…
gnodet 70233df
fix: remove unused Session injection from CleanOrphansMojo
gnodet a5b5e68
fix: remove incorrect @since tags on parameters, fix class @since ver…
gnodet 221f14a
Use Files.isHidden() instead of custom isVisible() method
gnodet e92d1eb
Reorder conditions: check filename before Files.isDirectory()
gnodet b6b800b
fix: apply spotless formatting to CleanOrphansMojo
gnodet 2cc8c28
Exclude symlinks from orphan scan and improve error resilience
gnodet File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| # 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. | ||
|
|
||
| # purge-check is a Maven 4 feature (uses Maven 4 API mojos) | ||
| invoker.maven.version = [4.0.0,) | ||
| invoker.goals = initialize |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <!-- | ||
| 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. | ||
| --> | ||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
| <modelVersion>4.0.0</modelVersion> | ||
|
|
||
| <groupId>test</groupId> | ||
| <artifactId>purge-check-orphan</artifactId> | ||
| <version>1.0-SNAPSHOT</version> | ||
| <packaging>pom</packaging> | ||
|
|
||
| <description>Verify that purge-check removes a child directory whose only non-hidden entry is target/ | ||
| (simulating a sub-project removed from the reactor after a git operation), | ||
| while leaving intact a child directory that still has other content alongside target/.</description> | ||
|
|
||
| <modules> | ||
| <module>sub-existing</module> | ||
| </modules> | ||
|
|
||
| <build> | ||
| <plugins> | ||
| <plugin> | ||
| <groupId>org.apache.maven.plugins</groupId> | ||
| <artifactId>maven-clean-plugin</artifactId> | ||
| <version>@project.version@</version> | ||
| <executions> | ||
| <execution> | ||
| <id>purge-check</id> | ||
| <goals> | ||
| <goal>purge-check</goal> | ||
| </goals> | ||
| <phase>initialize</phase> | ||
| </execution> | ||
| </executions> | ||
| </plugin> | ||
| </plugins> | ||
| </build> | ||
| </project> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| // 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. | ||
|
|
||
| // Setup: create the orphaned sub-project structure that simulates a module removed | ||
| // from the reactor after a git operation. The directory has only a target/ subdirectory | ||
| // (no pom.xml, no src/) — exactly what is left when a sub-project is deleted from git. | ||
|
|
||
| def orphan = new File(basedir, 'sub-orphan') | ||
| def orphanTarget = new File(orphan, 'target/classes') | ||
| orphanTarget.mkdirs() | ||
| new File(orphanTarget, 'Foo.class').bytes = new byte[0] | ||
|
|
||
| // Also create a target/ inside sub-existing to make sure it is NOT removed. | ||
| def existingTarget = new File(basedir, 'sub-existing/target/classes') | ||
| existingTarget.mkdirs() | ||
| new File(existingTarget, 'Bar.class').bytes = new byte[0] | ||
|
|
||
| return true |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <!-- | ||
| 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. | ||
| --> | ||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
| <modelVersion>4.0.0</modelVersion> | ||
|
|
||
| <parent> | ||
| <groupId>test</groupId> | ||
| <artifactId>purge-check-orphan</artifactId> | ||
| <version>1.0-SNAPSHOT</version> | ||
| </parent> | ||
|
|
||
| <artifactId>sub-existing</artifactId> | ||
| <packaging>jar</packaging> | ||
|
|
||
| <description>An active sub-project: has src/ alongside target/, must NOT be cleaned.</description> | ||
| </project> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| // 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. | ||
|
|
||
| // Verify purge-check behaviour: | ||
| // - sub-orphan/ must have been removed entirely (only non-hidden child was target/) | ||
| // - sub-existing/ must remain (pom.xml + src/ are siblings of target/) | ||
|
|
||
| def log = new File(basedir, 'build.log').text | ||
| assert log.contains('BUILD SUCCESS') : 'expected BUILD SUCCESS' | ||
|
|
||
| // Orphaned directory must be gone entirely — not just its target/ subdirectory | ||
| def orphanDir = new File(basedir, 'sub-orphan') | ||
| assert !orphanDir.exists() : "sub-orphan/ should have been removed entirely by purge-check, but still exists" | ||
|
|
||
| // Active sub-project's directory must be untouched | ||
| // (purge-check runs on initialize; clean:clean runs later and removes it — so we only | ||
| // check the log to confirm purge-check did NOT report it as orphaned) | ||
| assert !log.find('Removing orphaned.*sub-existing') \ | ||
| : "sub-existing/ must not be treated as orphaned" | ||
|
|
||
| assert log.contains('Removing orphaned directory') : 'expected purge-check to report removal' | ||
214 changes: 214 additions & 0 deletions
214
src/main/java/org/apache/maven/plugins/clean/CleanOrphansMojo.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,214 @@ | ||||||||||||||||||||||
| /* | ||||||||||||||||||||||
| * 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.clean; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| import java.io.IOException; | ||||||||||||||||||||||
| import java.nio.file.DirectoryStream; | ||||||||||||||||||||||
| import java.nio.file.Files; | ||||||||||||||||||||||
| import java.nio.file.LinkOption; | ||||||||||||||||||||||
| import java.nio.file.Path; | ||||||||||||||||||||||
| import java.util.ArrayList; | ||||||||||||||||||||||
| import java.util.List; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| import org.apache.maven.api.Project; | ||||||||||||||||||||||
| import org.apache.maven.api.di.Inject; | ||||||||||||||||||||||
| import org.apache.maven.api.plugin.Log; | ||||||||||||||||||||||
| import org.apache.maven.api.plugin.MojoException; | ||||||||||||||||||||||
| import org.apache.maven.api.plugin.annotations.Mojo; | ||||||||||||||||||||||
| import org.apache.maven.api.plugin.annotations.Parameter; | ||||||||||||||||||||||
| import org.apache.maven.api.services.PathMatcherFactory; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| /** | ||||||||||||||||||||||
| * Removes orphaned build output directories left behind by sub-projects that have been | ||||||||||||||||||||||
| * deleted or renamed since the last build. | ||||||||||||||||||||||
| * | ||||||||||||||||||||||
| * <p>When a sub-project is removed from the reactor (e.g. after a {@code git pull} or a branch | ||||||||||||||||||||||
| * switch), its {@code target/} directory may remain on disk even though its {@code pom.xml} is | ||||||||||||||||||||||
| * gone. Because the sub-project is no longer part of the reactor, {@code mvn clean} cannot know | ||||||||||||||||||||||
| * about it and will skip it. This goal detects such orphaned directories and removes them.</p> | ||||||||||||||||||||||
| * | ||||||||||||||||||||||
| * <p>Detection heuristic: a direct child directory of the current project's {@code basedir} is | ||||||||||||||||||||||
| * considered orphaned when its <em>only non-hidden child</em> is the build output directory | ||||||||||||||||||||||
| * (typically {@code target/}). A freshly checked-out or live sub-project always has at least a | ||||||||||||||||||||||
| * {@code pom.xml} alongside its build directory, so a directory whose sole visible content is a | ||||||||||||||||||||||
| * {@code target/} folder can safely be assumed to be a leftover. The entire child directory | ||||||||||||||||||||||
| * (not just its build output subdirectory) is removed, since an orphaned directory with no | ||||||||||||||||||||||
| * source files has no reason to remain on disk.</p> | ||||||||||||||||||||||
| * | ||||||||||||||||||||||
| * @since 4.0.0-beta-3 | ||||||||||||||||||||||
| */ | ||||||||||||||||||||||
| @Mojo(name = "purge-check", defaultPhase = "initialize") | ||||||||||||||||||||||
| public class CleanOrphansMojo implements org.apache.maven.api.plugin.Mojo { | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| /** | ||||||||||||||||||||||
| * The logger where to send information about what the plugin is doing. | ||||||||||||||||||||||
| */ | ||||||||||||||||||||||
| @Inject | ||||||||||||||||||||||
| private Log logger; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| /** | ||||||||||||||||||||||
| * The current project instance, used to resolve {@code basedir}. | ||||||||||||||||||||||
| */ | ||||||||||||||||||||||
| @Inject | ||||||||||||||||||||||
| private Project project; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| /** | ||||||||||||||||||||||
| * The build output directory of the current project. Used only to determine the directory | ||||||||||||||||||||||
| * name (e.g. {@code target}) so that the same name is recognised in sibling directories. | ||||||||||||||||||||||
| */ | ||||||||||||||||||||||
| @Parameter(defaultValue = "${project.build.directory}", readonly = true, required = true) | ||||||||||||||||||||||
| private Path directory; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| /** | ||||||||||||||||||||||
| * The service to use for creating include and exclude filters (shared with {@link CleanMojo}). | ||||||||||||||||||||||
| */ | ||||||||||||||||||||||
| @Inject | ||||||||||||||||||||||
| private PathMatcherFactory matcherFactory; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| /** | ||||||||||||||||||||||
| * Whether to force the deletion of read-only files inside orphaned build directories. | ||||||||||||||||||||||
| */ | ||||||||||||||||||||||
| @Parameter(property = "maven.clean.force", defaultValue = "false") | ||||||||||||||||||||||
| private boolean force; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| /** | ||||||||||||||||||||||
| * Indicates whether the build will continue even if there are errors while deleting orphaned | ||||||||||||||||||||||
| * build directories. | ||||||||||||||||||||||
| */ | ||||||||||||||||||||||
| @Parameter(property = "maven.clean.failOnError", defaultValue = "true") | ||||||||||||||||||||||
| private boolean failOnError; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| /** | ||||||||||||||||||||||
| * Indicates whether the plugin should undertake additional attempts (after a short delay) to | ||||||||||||||||||||||
| * delete a file if the first attempt failed. | ||||||||||||||||||||||
| */ | ||||||||||||||||||||||
| @Parameter(property = "maven.clean.retryOnError", defaultValue = "true") | ||||||||||||||||||||||
| private boolean retryOnError; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| /** | ||||||||||||||||||||||
| * Disables the plugin execution. | ||||||||||||||||||||||
| */ | ||||||||||||||||||||||
| @Parameter(property = "maven.clean.purgeCheck.skip", defaultValue = "false") | ||||||||||||||||||||||
| private boolean skip; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| /** | ||||||||||||||||||||||
| * Sets whether the plugin runs in verbose mode. | ||||||||||||||||||||||
| */ | ||||||||||||||||||||||
| @Parameter(property = "maven.clean.verbose") | ||||||||||||||||||||||
| private Boolean verbose; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| /** | ||||||||||||||||||||||
| * Scans direct children of the project {@code basedir} for orphaned build output directories | ||||||||||||||||||||||
| * and deletes them. | ||||||||||||||||||||||
| * | ||||||||||||||||||||||
| * @throws MojoException if an orphaned directory cannot be deleted and {@link #failOnError} is | ||||||||||||||||||||||
| * {@code true} | ||||||||||||||||||||||
| */ | ||||||||||||||||||||||
| @Override | ||||||||||||||||||||||
| public void execute() { | ||||||||||||||||||||||
| if (skip) { | ||||||||||||||||||||||
| logger.info("Orphan build directory check is skipped."); | ||||||||||||||||||||||
| return; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| Path basedir = project.getBasedir(); | ||||||||||||||||||||||
| String buildDirName = directory.getFileName().toString(); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| List<Path> orphans = findOrphanBuildDirectories(basedir, buildDirName); | ||||||||||||||||||||||
| if (orphans.isEmpty()) { | ||||||||||||||||||||||
| return; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| Cleaner cleaner = new Cleaner(matcherFactory, logger, isVerbose(), false, force, failOnError, retryOnError); | ||||||||||||||||||||||
| try { | ||||||||||||||||||||||
| for (Path orphan : orphans) { | ||||||||||||||||||||||
| logger.info("Removing orphaned directory: " + orphan); | ||||||||||||||||||||||
| cleaner.delete(orphan); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } catch (IOException e) { | ||||||||||||||||||||||
| throw new MojoException("Failed to remove orphaned build directories: " + e.getMessage(), e); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| /** | ||||||||||||||||||||||
| * Returns the list of orphaned child directories found as direct children of {@code basedir}. | ||||||||||||||||||||||
| * | ||||||||||||||||||||||
| * <p>A direct child directory is considered orphaned when its only non-hidden child entry is a | ||||||||||||||||||||||
| * directory whose name matches {@code buildDirName}. The entire child directory is returned | ||||||||||||||||||||||
| * (not just the build subdirectory inside it).</p> | ||||||||||||||||||||||
| * | ||||||||||||||||||||||
| * @param basedir the directory to scan | ||||||||||||||||||||||
| * @param buildDirName the name of the build output directory (e.g. {@code target}) | ||||||||||||||||||||||
| * @return a possibly-empty list of orphaned child directories to delete | ||||||||||||||||||||||
| */ | ||||||||||||||||||||||
| private List<Path> findOrphanBuildDirectories(Path basedir, String buildDirName) { | ||||||||||||||||||||||
| List<Path> result = new ArrayList<>(); | ||||||||||||||||||||||
| if (!Files.isDirectory(basedir)) { | ||||||||||||||||||||||
| return result; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| try (DirectoryStream<Path> children = | ||||||||||||||||||||||
| Files.newDirectoryStream(basedir, p -> Files.isDirectory(p, LinkOption.NOFOLLOW_LINKS))) { | ||||||||||||||||||||||
| for (Path child : children) { | ||||||||||||||||||||||
| try { | ||||||||||||||||||||||
| if (isOrphanDirectory(child, buildDirName)) { | ||||||||||||||||||||||
| result.add(child); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } catch (IOException e) { | ||||||||||||||||||||||
| logger.warn("Could not inspect " + child + ": " + e.getMessage()); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } catch (IOException e) { | ||||||||||||||||||||||
| logger.warn("Could not scan " + basedir + " for orphaned build directories: " + e.getMessage()); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| return result; | ||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Copilot finding confirmed: If
Suggested change
|
||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| /** | ||||||||||||||||||||||
| * Returns {@code true} if {@code child} is an orphaned sub-project directory. | ||||||||||||||||||||||
| * | ||||||||||||||||||||||
| * <p>A single {@link DirectoryStream} is opened on {@code child}: if its only non-hidden entry | ||||||||||||||||||||||
| * is a directory named {@code buildDirName} then {@code child} is considered orphaned.</p> | ||||||||||||||||||||||
| * | ||||||||||||||||||||||
| * @param child the candidate sub-directory to inspect | ||||||||||||||||||||||
| * @param buildDirName the name of the build output directory (e.g. {@code target}) | ||||||||||||||||||||||
| * @return {@code true} if {@code child} is an orphaned directory | ||||||||||||||||||||||
| */ | ||||||||||||||||||||||
| private boolean isOrphanDirectory(Path child, String buildDirName) throws IOException { | ||||||||||||||||||||||
| Path sole = null; | ||||||||||||||||||||||
| try (DirectoryStream<Path> entries = Files.newDirectoryStream(child, p -> !Files.isHidden(p))) { | ||||||||||||||||||||||
| for (Path entry : entries) { | ||||||||||||||||||||||
| if (sole != null) { | ||||||||||||||||||||||
|
desruisseaux marked this conversation as resolved.
|
||||||||||||||||||||||
| // More than one visible entry — not orphaned. | ||||||||||||||||||||||
| return false; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| sole = entry; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| return sole != null | ||||||||||||||||||||||
| && sole.getFileName().toString().equals(buildDirName) | ||||||||||||||||||||||
| && Files.isDirectory(sole, LinkOption.NOFOLLOW_LINKS); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| /** | ||||||||||||||||||||||
| * Indicates whether verbose output is enabled. | ||||||||||||||||||||||
| */ | ||||||||||||||||||||||
| private boolean isVerbose() { | ||||||||||||||||||||||
| return (verbose != null) ? verbose : logger.isDebugEnabled(); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.