Copilot commented on code in PR #27:
URL: https://github.com/apache/maven-war-plugin/pull/27#discussion_r3665310373


##########
src/main/java/org/apache/maven/plugins/war/packaging/AbstractWarPackagingTask.java:
##########
@@ -372,6 +372,10 @@ protected boolean copyFile( WarPackagingContext context, 
File source, File desti
             }
             else
             {
+                if ( context.isForceOverwriteResources() && 
destination.exists() && !destination.canWrite() ) 
+                {
+                    destination.setWritable( true );
+                }
                 FileUtils.copyFile( source.getCanonicalFile(), destination );
                 // preserve timestamp

Review Comment:
   `File#setWritable(true)` returns a boolean that is currently ignored; if it 
fails (common on some platforms/filesystems), the subsequent copy can still 
fail with an access error. Please check the return value and either throw a 
clear exception (including the path) or fall back to a more robust permission 
change (e.g., NIO `Files.setPosixFilePermissions` where supported). Also 
consider whether permissions should be restored after the overwrite to avoid 
permanently changing the destination’s read-only state.



##########
src/main/java/org/apache/maven/plugins/war/packaging/WarPackagingContext.java:
##########
@@ -258,4 +258,10 @@ public interface WarPackagingContext
      * @since 3.3.0
      */
     String getOutputTimestamp();
+
+    /**
+     * If files are modified, but the target is readonly, force update.
+     * @return forceOverwriteResources
+     */
+    boolean isForceOverwriteResources();

Review Comment:
   Adding a new abstract method to a `public interface` is a 
source/binary-breaking change for any external implementations. To preserve 
compatibility, make this a `default` method returning `false` (or introduce a 
new sub-interface) so existing implementers don’t break at compile-time/runtime.



##########
src/test/java/org/apache/maven/plugins/war/WarExplodedMojoTest.java:
##########
@@ -147,6 +147,65 @@ public void testSimpleExplodedWarWTargetPath()
         expectedWebResourceFile.delete();
     }
 
+    /**
+     * @throws Exception in case of an error.
+     */
+    public void testReadOnlyFileInDestinationInExplodedWar()
+        throws Exception
+    {
+        // setup test data
+        String testId = "SimpleExplodedWar";
+        MavenProjectBasicStub project = new MavenProjectBasicStub();
+        File webAppSource = createWebAppSource( testId );
+        File classesDir = createClassesDir( testId, false );
+        File webAppResource = new File( getTestDirectory(), testId + 
"-resources" );
+        File webAppDirectory = new File( getTestDirectory(), testId );
+        File sampleResource = new File( webAppResource, "pix/panis_na.jpg" );
+        ResourceStub[] resources = new ResourceStub[] { new ResourceStub() };
+        
+        
+        createFile( sampleResource );
+        
+        File conflictingFile = new File( webAppDirectory, "pix/panis_na.jpg" );
+        if (conflictingFile.exists() )
+        {
+               conflictingFile.delete();
+        }
+        
+        createFile( conflictingFile );
+        conflictingFile.setWritable(false);
+        conflictingFile.setLastModified(System.currentTimeMillis()-100_000);
+        
+        assertTrue( "sampeResource not found", sampleResource.exists() );

Review Comment:
   Corrected spelling of 'sampeResource' to 'sampleResource' in the assertion 
message.



##########
src/test/java/org/apache/maven/plugins/war/WarExplodedMojoTest.java:
##########
@@ -147,6 +147,65 @@ public void testSimpleExplodedWarWTargetPath()
         expectedWebResourceFile.delete();
     }
 
+    /**
+     * @throws Exception in case of an error.
+     */
+    public void testReadOnlyFileInDestinationInExplodedWar()
+        throws Exception
+    {
+        // setup test data
+        String testId = "SimpleExplodedWar";
+        MavenProjectBasicStub project = new MavenProjectBasicStub();
+        File webAppSource = createWebAppSource( testId );
+        File classesDir = createClassesDir( testId, false );
+        File webAppResource = new File( getTestDirectory(), testId + 
"-resources" );
+        File webAppDirectory = new File( getTestDirectory(), testId );
+        File sampleResource = new File( webAppResource, "pix/panis_na.jpg" );
+        ResourceStub[] resources = new ResourceStub[] { new ResourceStub() };
+        
+        
+        createFile( sampleResource );
+        
+        File conflictingFile = new File( webAppDirectory, "pix/panis_na.jpg" );
+        if (conflictingFile.exists() )
+        {
+               conflictingFile.delete();
+        }
+        
+        createFile( conflictingFile );
+        conflictingFile.setWritable(false);
+        conflictingFile.setLastModified(System.currentTimeMillis()-100_000);
+        
+        assertTrue( "sampeResource not found", sampleResource.exists() );

Review Comment:
   This test currently asserts only file existence, which doesn’t prove that 
the read-only destination file was actually overwritten (it would still exist 
even if the overwrite failed). To make the test validate the behavior, write 
distinct content (or a distinct last-modified) to `sampleResource` and 
`conflictingFile`, run the mojo, and then assert that the destination’s content 
(or last-modified) matches the source (and/or differs from the pre-existing 
destination). Also, consider guarding the test with an assumption if the 
platform/filesystem doesn’t support making files read-only via 
`setWritable(false)`.



##########
src/main/java/org/apache/maven/plugins/war/AbstractWarMojo.java:
##########
@@ -146,6 +146,11 @@ public abstract class AbstractWarMojo
     @Parameter
     private Resource[] webResources;
 
+    /**
+     * If resources should be overwritten, even if they are read only
+     */
+    @Parameter( defaultValue = "false" )
+    boolean forceOverwriteResources;

Review Comment:
   Maven plugin parameters are typically `private` to match the rest of the 
Mojo’s encapsulation pattern and reduce accidental access/mutation. Consider 
making this field `private` (and keep passing it through via the existing 
wiring) and enhance the Javadoc with an `@since` tag and a clearer description 
(e.g., explicitly stating this affects overwriting read-only files in the 
exploded WAR output).



-- 
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]

Reply via email to