[SCM-772] GitStatusConsumer does not properly handle quoted paths output from GitStatusCommand
Original patch adjusted, just keep URI instead of String
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/status/GitStatusConsumer.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/status/GitStatusConsumer.java
index 7e54888..7d850da 100644
--- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/status/GitStatusConsumer.java
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/main/java/org/apache/maven/scm/provider/git/gitexe/command/status/GitStatusConsumer.java
@@ -20,6 +20,7 @@
*/
import java.io.File;
+import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
@@ -263,6 +264,106 @@
private static String stripQuotes( String str )
{
int strLen = str.length();
- return ( strLen > 0 && str.startsWith( "\"" ) && str.endsWith( "\"" ) ) ? str.substring( 1, strLen - 1 ) : str;
+ return ( strLen > 0 && str.startsWith( "\"" ) && str.endsWith( "\"" ) ) ? unescape( str.substring( 1, strLen - 1 ) ) : str;
+ }
+
+ /**
+ * Dequote a quoted string generated by git status --porcelain.
+ * The leading and trailing quotes have already been removed.
+ * @param fileEntry
+ * @return
+ */
+ private static String unescape( String fileEntry )
+ {
+ // If there are no escaped characters, just return the input argument
+ int pos = fileEntry.indexOf( '\\' );
+ if ( pos == -1 )
+ {
+ return fileEntry;
+ }
+
+ // We have escaped characters
+ byte[] inba = fileEntry.getBytes();
+ int inSub = 0; // Input subscript into fileEntry
+ byte[] outba = new byte[fileEntry.length()];
+ int outSub = 0; // Output subscript into outba
+
+ while ( true )
+ {
+ System.arraycopy( inba, inSub, outba, outSub, pos - inSub );
+ outSub += pos - inSub;
+ inSub = pos + 1;
+ switch ( (char) inba[inSub++] )
+ {
+ case '"':
+ outba[outSub++] = '"';
+ break;
+
+ case 'a':
+ outba[outSub++] = 7; // Bell
+ break;
+
+ case 'b':
+ outba[outSub++] = '\b';
+ break;
+
+ case 't':
+ outba[outSub++] = '\t';
+ break;
+
+ case 'n':
+ outba[outSub++] = '\n';
+ break;
+
+ case 'v':
+ outba[outSub++] = 11; // Vertical tab
+ break;
+
+ case 'f':
+ outba[outSub++] = '\f';
+ break;
+
+ case 'r':
+ outba[outSub++] = '\f';
+ break;
+
+ case '\\':
+ outba[outSub++] = '\\';
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ // This assumes that the octal escape here is valid.
+ byte b = (byte) ( ( inba[inSub - 1] - '0' ) << 6 );
+ b |= (byte) ( ( inba[inSub++] - '0' ) << 3 );
+ b |= (byte) ( inba[inSub++] - '0' );
+ outba[outSub++] = b;
+ break;
+
+ default:
+ //This is an invalid escape in a string. Just copy it.
+ outba[outSub++] = '\\';
+ inSub--;
+ break;
+ }
+ pos = fileEntry.indexOf( '\\', inSub);
+ if ( pos == -1 ) // No more backslashes; we're done
+ {
+ System.arraycopy( inba, inSub, outba, outSub, inba.length - inSub );
+ outSub += inba.length - inSub;
+ break;
+ }
+ }
+ try
+ {
+ // explicit say UTF-8, otherwise it'll fail at least on Windows cmdline
+ return new String(outba, 0, outSub, "UTF-8");
+ }
+ catch ( UnsupportedEncodingException e )
+ {
+ throw new RuntimeException( e );
+ }
}
}
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/test/java/org/apache/maven/scm/provider/git/gitexe/command/status/GitStatusConsumerTest.java b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/test/java/org/apache/maven/scm/provider/git/gitexe/command/status/GitStatusConsumerTest.java
index a2537f4..3b4d153 100644
--- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/test/java/org/apache/maven/scm/provider/git/gitexe/command/status/GitStatusConsumerTest.java
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/test/java/org/apache/maven/scm/provider/git/gitexe/command/status/GitStatusConsumerTest.java
@@ -94,6 +94,11 @@
assertNotNull( changedFiles );
assertEquals( 0, changedFiles.size() );
+
+ changedFiles = getChangedFiles( "?? \"test file with spaces and a special \\177 character.xml\"", null );
+
+ assertNotNull( changedFiles );
+ assertEquals( 0, changedFiles.size() );
}
public void testConsumerAddedFile()
@@ -102,6 +107,13 @@
assertNotNull( changedFiles );
assertEquals( 1, changedFiles.size() );
+ assertEquals( "project.xml", changedFiles.get( 0 ).getPath() );
+
+ changedFiles = getChangedFiles( "A \"test file with spaces and a special \\177 character.xml\"", null );
+
+ assertNotNull( changedFiles );
+ assertEquals( 1, changedFiles.size() );
+ assertEquals("test file with spaces and a special \u007f character.xml", changedFiles.get( 0 ).getPath() );
}
public void testConsumerAddedAndModifiedFile()
@@ -110,7 +122,13 @@
assertNotNull( changedFiles );
assertEquals( 1, changedFiles.size() );
- assertEquals( ScmFileStatus.ADDED, changedFiles.get( 0 ).getStatus() );
+ testScmFile( changedFiles.get( 0 ), "project.xml", ScmFileStatus.ADDED );
+
+ changedFiles = getChangedFiles( "AM \"test file with spaces and a special \\177 character.xml\"", null );
+
+ assertNotNull( changedFiles );
+ assertEquals( 1, changedFiles.size() );
+ testScmFile( changedFiles.get( 0 ), "test file with spaces and a special \u007f character.xml", ScmFileStatus.ADDED );
}
public void testConsumerAddedFileWithDirectoryAndNoFile()
@@ -123,6 +141,11 @@
assertNotNull( changedFiles );
assertEquals( 0, changedFiles.size() );
+ changedFiles = getChangedFiles( "A \"test file with spaces and a special \\177 character.xml\"", dir );
+
+ assertNotNull( changedFiles );
+ assertEquals( 0, changedFiles.size() );
+
FileUtils.deleteDirectory( dir );
}
@@ -136,6 +159,15 @@
assertNotNull( changedFiles );
assertEquals( 1, changedFiles.size() );
+ assertEquals( "project.xml", changedFiles.get( 0 ).getPath() );
+
+ FileUtils.write( new File( dir, "test file with spaces and a special \u007f character.xml" ), "data" );
+
+ changedFiles = getChangedFiles( "A \"test file with spaces and a special \\177 character.xml\"", dir );
+
+ assertNotNull( changedFiles );
+ assertEquals( 1, changedFiles.size() );
+ assertEquals("test file with spaces and a special \u007f character.xml", changedFiles.get( 0 ).getPath() );
FileUtils.deleteDirectory( dir );
}
@@ -146,6 +178,13 @@
assertNotNull( changedFiles );
assertEquals( 1, changedFiles.size() );
+ assertEquals( "project.xml", changedFiles.get( 0 ).getPath() );
+
+ changedFiles = getChangedFiles( "M \"test file with spaces and a special \\177 character.xml\"", null );
+
+ assertNotNull( changedFiles );
+ assertEquals( 1, changedFiles.size() );
+ assertEquals("test file with spaces and a special \u007f character.xml", changedFiles.get( 0 ).getPath() );
}
// SCM-740
@@ -160,15 +199,56 @@
assertNotNull( changedFiles );
assertEquals( 1, changedFiles.size() );
+ assertEquals( "subDirectory/project.xml", changedFiles.get( 0 ).getPath() );
+
+ FileUtils.write( new File( subdir, "test file with spaces and a déjà vu character.xml" ), "data" );
+
+ changedFiles = getChangedFiles( "M \"subDirectory/test file with spaces and a déjà vu character.xml\"", subdir, dir.toURI() );
+
+ assertNotNull( changedFiles );
+ assertEquals( 1, changedFiles.size() );
+ assertEquals( "subDirectory/test file with spaces and a déjà vu character.xml", changedFiles.get( 0 ).getPath() );
+
+ FileUtils.deleteDirectory( dir );
}
- public void testConsumerModifiedFileUnstaged()
+ public void testConsumerModifiedFileInComplexDirectoryWithSpaces() throws IOException {
+
+ File dir = createTempDirectory();
+ File subdir = new File( dir.getAbsolutePath() + "/sub Directory déjà vu special/" );
+ subdir.mkdir();
+ FileUtils.write( new File( subdir, "project.xml" ), "data" );
+
+ List<ScmFile> changedFiles = getChangedFiles( "M \"sub Directory déjà vu special/project.xml\"", subdir, dir.toURI() );
+
+ assertNotNull( changedFiles );
+ assertEquals( 1, changedFiles.size() );
+ assertEquals( "sub Directory déjà vu special/project.xml", changedFiles.get( 0 ).getPath() );
+
+ FileUtils.write( new File( subdir, "test file with spaces and a déjà vu character.xml" ), "data" );
+
+ changedFiles = getChangedFiles( "M \"sub Directory déjà vu special/test file with spaces and a déjà vu character.xml\"", subdir, dir.toURI() );
+
+ assertNotNull( changedFiles );
+ assertEquals( 1, changedFiles.size() );
+ assertEquals( "sub Directory déjà vu special/test file with spaces and a déjà vu character.xml", changedFiles.get( 0 ).getPath() );
+
+ FileUtils.deleteDirectory( dir );
+ }
+
+ public void testConsumerModifiedFileUnstaged()
{
List<ScmFile> changedFiles = getChangedFiles( "M project.xml", null );
assertNotNull( changedFiles );
assertEquals( 1, changedFiles.size() );
- assertEquals( ScmFileStatus.MODIFIED, changedFiles.get( 0 ).getStatus() );
+ testScmFile( changedFiles.get( 0 ), "project.xml", ScmFileStatus.MODIFIED);
+
+ changedFiles = getChangedFiles( "M \"test file with spaces and a special \\177 character.xml\"", null );
+
+ assertNotNull( changedFiles );
+ assertEquals( 1, changedFiles.size() );
+ testScmFile( changedFiles.get( 0 ), "test file with spaces and a special \u007f character.xml", ScmFileStatus.MODIFIED);
}
public void testConsumerModifiedFileBothStagedAndUnstaged()
@@ -177,7 +257,13 @@
assertNotNull( changedFiles );
assertEquals( 1, changedFiles.size() );
- assertEquals( ScmFileStatus.MODIFIED, changedFiles.get( 0 ).getStatus() );
+ testScmFile( changedFiles.get( 0 ), "project.xml", ScmFileStatus.MODIFIED);
+
+ changedFiles = getChangedFiles( "MM \"test file with spaces and a special \\177 character.xml\"", null );
+
+ assertNotNull( changedFiles );
+ assertEquals( 1, changedFiles.size() );
+ testScmFile( changedFiles.get( 0 ), "test file with spaces and a special \u007f character.xml", ScmFileStatus.MODIFIED);
}
public void testConsumerModifiedFileWithDirectoryAndNoFile()
@@ -190,6 +276,11 @@
assertNotNull( changedFiles );
assertEquals( 0, changedFiles.size() );
+ changedFiles = getChangedFiles( "M \"test file with spaces and a special \\177 character.xml\"", dir );
+
+ assertNotNull( changedFiles );
+ assertEquals( 0, changedFiles.size() );
+
FileUtils.deleteDirectory( dir );
}
@@ -203,6 +294,15 @@
assertNotNull( changedFiles );
assertEquals( 1, changedFiles.size() );
+ assertEquals( "project.xml", changedFiles.get( 0 ).getPath() );
+
+ FileUtils.write( new File( dir, "test file with spaces and a special \u007f character.xml" ), "data" );
+
+ changedFiles = getChangedFiles( "M \"test file with spaces and a special \\177 character.xml\"", dir );
+
+ assertNotNull( changedFiles );
+ assertEquals( 1, changedFiles.size() );
+ assertEquals( "test file with spaces and a special \u007f character.xml", changedFiles.get( 0 ).getPath() );
FileUtils.deleteDirectory( dir );
}
@@ -213,6 +313,13 @@
assertNotNull( changedFiles );
assertEquals( 1, changedFiles.size() );
+ assertEquals( "Capfile", changedFiles.get( 0 ).getPath() );
+
+ changedFiles = getChangedFiles( "D \"test file with spaces and a déjà vu character.xml\"", null );
+
+ assertNotNull( changedFiles );
+ assertEquals( 1, changedFiles.size() );
+ assertEquals( "test file with spaces and a déjà vu character.xml", changedFiles.get( 0 ).getPath() );
}
public void testConsumerRemovedFileUnstaged()
@@ -222,6 +329,12 @@
assertNotNull( changedFiles );
assertEquals( 1, changedFiles.size() );
assertEquals( ScmFileStatus.DELETED, changedFiles.get( 0 ).getStatus() );
+
+ changedFiles = getChangedFiles( "D \"test file with spaces and a special \\177 character.xml\"", null );
+
+ assertNotNull( changedFiles );
+ assertEquals( 1, changedFiles.size() );
+ assertEquals( ScmFileStatus.DELETED, changedFiles.get( 0 ).getStatus() );
}
public void testConsumerRemovedFileWithDirectoryAndNoFile()
@@ -233,6 +346,14 @@
assertNotNull( changedFiles );
assertEquals( 1, changedFiles.size() );
+ assertEquals( "Capfile", changedFiles.get( 0 ).getPath() );
+
+ changedFiles = getChangedFiles( "D \"test file with spaces and a special \\177 character.xml\"", dir );
+
+ assertNotNull( changedFiles );
+ assertEquals( 1, changedFiles.size() );
+ assertEquals( "test file with spaces and a special \u007f character.xml", changedFiles.get( 0 ).getPath() );
+
FileUtils.deleteDirectory( dir );
}
@@ -246,11 +367,18 @@
assertNotNull( changedFiles );
assertEquals( 0, changedFiles.size() );
+
+ FileUtils.write( new File( dir, "test file with spaces and a special \u007f character.xml" ), "data" );
+
+ changedFiles = getChangedFiles( "D \"test file with spaces and a special \\177 character.xml\"", dir );
+
+ assertNotNull( changedFiles );
+ assertEquals( 0, changedFiles.size() );
FileUtils.deleteDirectory( dir );
}
// Test reproducing SCM-694
- public void testConsumeRenamedFile()
+ public void testConsumerRenamedFile()
throws Exception
{
File dir = createTempDirectory();
@@ -265,6 +393,17 @@
assertEquals( 2, changedFiles.size() );
assertEquals( "OldCapfile", changedFiles.get(0).getPath() );
assertEquals( "NewCapFile", changedFiles.get(1).getPath() );
+
+ tmpFile = new File( dir, "New test file with spaces and a special \u007f character.xml" );
+
+ FileUtils.write( tmpFile, "data" );
+
+ changedFiles = getChangedFiles( "R \"Old test file with spaces and a special \\177 character.xml\" -> \"New test file with spaces and a special \\177 character.xml\"", dir );
+
+ assertNotNull( changedFiles );
+ assertEquals( 2, changedFiles.size() );
+ assertEquals( "Old test file with spaces and a special \u007f character.xml", changedFiles.get(0).getPath() );
+ assertEquals( "New test file with spaces and a special \u007f character.xml", changedFiles.get(1).getPath() );
FileUtils.deleteDirectory( dir );
}
@@ -273,10 +412,12 @@
{
List<ScmFile> changedFiles = getChangedFiles( getTestFile( "/src/test/resources/git/status/gitstatus1.gitlog" ) );
- assertEquals( 2, changedFiles.size() );
+ assertEquals( 4, changedFiles.size() );
testScmFile( changedFiles.get( 0 ), "project.xml", ScmFileStatus.ADDED );
testScmFile( changedFiles.get( 1 ), "readme.txt", ScmFileStatus.MODIFIED );
+ testScmFile( changedFiles.get( 2 ), "d\u00e9j\u00e0 vu.xml", ScmFileStatus.ADDED );
+ testScmFile( changedFiles.get( 3 ), "d\u00e9j\u00e0 vu.txt", ScmFileStatus.MODIFIED );
}
public void testEmptyLogConsumer()
@@ -287,7 +428,6 @@
assertEquals( 0, changedFiles.size() );
}
-
public void testLog2Consumer()
throws Exception
{
@@ -309,27 +449,6 @@
ScmFileStatus.MODIFIED );
}
- public void testLog3Consumer()
- throws Exception
- {
- List<ScmFile> changedFiles = getChangedFiles( getTestFile( "/src/test/resources/git/status/gitstatus2.gitlog" ), URI.create( "maven-scm-provider-gitexe" ) );
-
- assertEquals( 4, changedFiles.size() );
-
- testScmFile( changedFiles.get( 0 ),
- "src/main/java/org/apache/maven/scm/provider/git/gitexe/command/add/GitAddCommand.java",
- ScmFileStatus.MODIFIED );
- testScmFile( changedFiles.get( 1 ),
- "src/main/java/org/apache/maven/scm/provider/git/gitexe/command/checkin/GitCheckInCommand.java",
- ScmFileStatus.MODIFIED );
- testScmFile( changedFiles.get( 2 ),
- "src/main/java/org/apache/maven/scm/provider/git/gitexe/command/checkin/GitCheckInConsumer.java",
- ScmFileStatus.DELETED );
- testScmFile( changedFiles.get( 3 ),
- "src/main/java/org/apache/maven/scm/provider/git/gitexe/command/status/GitStatusConsumer.java",
- ScmFileStatus.MODIFIED );
- }
-
// SCM-709
public void testResolvePath()
{
diff --git a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/test/resources/git/status/gitstatus1.gitlog b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/test/resources/git/status/gitstatus1.gitlog
index 4f656a4..677cc9b 100644
--- a/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/test/resources/git/status/gitstatus1.gitlog
+++ b/maven-scm-providers/maven-scm-providers-git/maven-scm-provider-gitexe/src/test/resources/git/status/gitstatus1.gitlog
@@ -1,2 +1,4 @@
A project.xml
M readme.txt
+A "d\303\251j\303\240 vu.xml"
+ M "d\303\251j\303\240 vu.txt"