[MNG-5681] Properties on command line with leading or trailing quotes are stripped

Refactored out cleanArgs method from CLIManager into separate class
and added appropriate tests which proves the solution
of the issue.
This commit is contained in:
Karl Heinz Marbaise 2015-10-07 16:41:29 +02:00
parent c8a200a725
commit 8a51f9e512
5 changed files with 202 additions and 116 deletions

View File

@ -21,8 +21,6 @@ package org.apache.maven.cli;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
@ -154,107 +152,13 @@ public class CLIManager
throws ParseException
{
// We need to eat any quotes surrounding arguments...
String[] cleanArgs = cleanArgs( args );
String[] cleanArgs = CleanArgument.cleanArgs( args );
CommandLineParser parser = new GnuParser();
return parser.parse( options, cleanArgs );
}
private String[] cleanArgs( String[] args )
{
List<String> cleaned = new ArrayList<>();
StringBuilder currentArg = null;
for ( String arg : args )
{
boolean addedToBuffer = false;
if ( arg.startsWith( "\"" ) )
{
// if we're in the process of building up another arg, push it and start over.
// this is for the case: "-Dfoo=bar "-Dfoo2=bar two" (note the first unterminated quote)
if ( currentArg != null )
{
cleaned.add( currentArg.toString() );
}
// start building an argument here.
currentArg = new StringBuilder( arg.substring( 1 ) );
addedToBuffer = true;
}
// this has to be a separate "if" statement, to capture the case of: "-Dfoo=bar"
if ( arg.endsWith( "\"" ) )
{
String cleanArgPart = arg.substring( 0, arg.length() - 1 );
// if we're building an argument, keep doing so.
if ( currentArg != null )
{
// if this is the case of "-Dfoo=bar", then we need to adjust the buffer.
if ( addedToBuffer )
{
currentArg.setLength( currentArg.length() - 1 );
}
// otherwise, we trim the trailing " and append to the buffer.
else
{
// TODO: introducing a space here...not sure what else to do but collapse whitespace
currentArg.append( ' ' ).append( cleanArgPart );
}
cleaned.add( currentArg.toString() );
}
else
{
cleaned.add( cleanArgPart );
}
currentArg = null;
continue;
}
// if we haven't added this arg to the buffer, and we ARE building an argument
// buffer, then append it with a preceding space...again, not sure what else to
// do other than collapse whitespace.
// NOTE: The case of a trailing quote is handled by nullifying the arg buffer.
if ( !addedToBuffer )
{
if ( currentArg != null )
{
currentArg.append( ' ' ).append( arg );
}
else
{
cleaned.add( arg );
}
}
}
if ( currentArg != null )
{
cleaned.add( currentArg.toString() );
}
int cleanedSz = cleaned.size();
String[] cleanArgs;
if ( cleanedSz == 0 )
{
cleanArgs = args;
}
else
{
cleanArgs = cleaned.toArray( new String[cleanedSz] );
}
return cleanArgs;
}
public void displayHelp( PrintStream stdout )
{
stdout.println();

View File

@ -0,0 +1,122 @@
package org.apache.maven.cli;
/*
* 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.
*/
import java.util.ArrayList;
import java.util.List;
public class CleanArgument
{
public static String[] cleanArgs( String[] args )
{
List<String> cleaned = new ArrayList<>();
StringBuilder currentArg = null;
for ( String arg : args )
{
boolean addedToBuffer = false;
if ( arg.startsWith( "\"" ) )
{
// if we're in the process of building up another arg, push it and start over.
// this is for the case: "-Dfoo=bar "-Dfoo2=bar two" (note the first unterminated quote)
if ( currentArg != null )
{
cleaned.add( currentArg.toString() );
}
// start building an argument here.
currentArg = new StringBuilder( arg.substring( 1 ) );
addedToBuffer = true;
}
// this has to be a separate "if" statement, to capture the case of: "-Dfoo=bar"
if ( addedToBuffer && arg.endsWith( "\"" ) )
{
String cleanArgPart = arg.substring( 0, arg.length() - 1 );
// if we're building an argument, keep doing so.
if ( currentArg != null )
{
// if this is the case of "-Dfoo=bar", then we need to adjust the buffer.
if ( addedToBuffer )
{
currentArg.setLength( currentArg.length() - 1 );
}
// otherwise, we trim the trailing " and append to the buffer.
else
{
// TODO: introducing a space here...not sure what else to do but collapse whitespace
currentArg.append( ' ' ).append( cleanArgPart );
}
cleaned.add( currentArg.toString() );
}
else
{
cleaned.add( cleanArgPart );
}
currentArg = null;
addedToBuffer = false;
continue;
}
// if we haven't added this arg to the buffer, and we ARE building an argument
// buffer, then append it with a preceding space...again, not sure what else to
// do other than collapse whitespace.
// NOTE: The case of a trailing quote is handled by nullifying the arg buffer.
if ( !addedToBuffer )
{
if ( currentArg != null )
{
currentArg.append( ' ' ).append( arg );
}
else
{
cleaned.add( arg );
}
}
}
if ( currentArg != null )
{
cleaned.add( currentArg.toString() );
}
int cleanedSz = cleaned.size();
String[] cleanArgs;
if ( cleanedSz == 0 )
{
cleanArgs = args;
}
else
{
cleanArgs = cleaned.toArray( new String[cleanedSz] );
}
return cleanArgs;
}
}

View File

@ -32,11 +32,10 @@ import org.codehaus.plexus.PlexusTestCase;
import org.codehaus.plexus.util.FileUtils;
/**
* Pseudo test to generate documentation fragment about supported CLI options.
* TODO such documentation generation code should not be necessary as unit test but should be run
* during site generation (Velocity? Doxia macro?)
* Pseudo test to generate documentation fragment about supported CLI options. TODO such documentation generation code
* should not be necessary as unit test but should be run during site generation (Velocity? Doxia macro?)
*/
public class CLIManagerTest
public class CLIManagerDocumentationTest
extends PlexusTestCase
{
private final static String LS = System.getProperty( "line.separator" );
@ -55,7 +54,6 @@ public class CLIManagerTest
{
public Collection<Option> getOptions()
{
@SuppressWarnings( "unchecked" )
List<Option> optList = new ArrayList<>( options.getOptions() );
Collections.sort( optList, new OptionComparator() );
return optList;
@ -105,4 +103,5 @@ public class CLIManagerTest
File options = getTestFile( "target/test-classes/options.html" );
FileUtils.fileWrite( options, "UTF-8", getOptionsAsHtml() );
}
}

View File

@ -0,0 +1,61 @@
package org.apache.maven.cli;
/*
* 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.
*/
import static org.junit.Assert.assertEquals;
import org.junit.Test;
/**
* @author Karl Heinz Marbaise <khmarbaise@apache.org>
*/
public class CleanArgumentTest
{
@Test
public void cleanArgsShouldRemoveWrongSurroundingQuotes()
{
String[] args = { "\"-Dfoo=bar", "\"-Dfoo2=bar two\"" };
String[] cleanArgs = CleanArgument.cleanArgs( args );
assertEquals( args.length, cleanArgs.length );
assertEquals( "-Dfoo=bar", cleanArgs[0] );
assertEquals( "-Dfoo2=bar two", cleanArgs[1] );
}
@Test
public void testCleanArgsShouldNotTouchCorrectlyQuotedArgumentsUsingDoubleQuotes()
{
String information = "-Dinformation=\"The Information is important.\"";
String[] args = { information };
String[] cleanArgs = CleanArgument.cleanArgs( args );
assertEquals( args.length, cleanArgs.length );
assertEquals( information, cleanArgs[0] );
}
@Test
public void testCleanArgsShouldNotTouchCorrectlyQuotedArgumentsUsingSingleQuotes()
{
String information = "-Dinformation='The Information is important.'";
String[] args = { information };
String[] cleanArgs = CleanArgument.cleanArgs( args );
assertEquals( args.length, cleanArgs.length );
assertEquals( information, cleanArgs[0] );
}
}

28
pom.xml
View File

@ -1,19 +1,19 @@
<?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.
-->
<!--
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>