Author: kenney
Date: Fri Jun 22 04:34:53 2007
New Revision: 549786

URL: http://svn.apache.org/viewvc?view=rev&rev=549786
Log:
PR: MNG-2339 - ${project.*} evaluated badly

This commit makes sure that pom.* and project.* are resolved using the model 
reflector,
but if the prefix isn't pom or project, context and model properties are 
consulted.
If the value still isn't found, the model reflector is used as a legacy 
fallback,
and a warning is printed.

Also, project.* is deprecated in favour of pom.*.

TODO: env.*.

N.B.: there's loads of warnings about ${artifactId}. I can turn these off,
but if you specify -DartifactId on the commandline, all hell breaks loose.

See http://docs.codehaus.org/display/MAVEN/Refactoring+Interpolation

Modified:
    
maven/components/trunk/maven-project/src/main/java/org/apache/maven/project/interpolation/RegexBasedModelInterpolator.java
    
maven/components/trunk/maven-project/src/test/java/org/apache/maven/project/interpolation/RegexBasedModelInterpolatorTest.java

Modified: 
maven/components/trunk/maven-project/src/main/java/org/apache/maven/project/interpolation/RegexBasedModelInterpolator.java
URL: 
http://svn.apache.org/viewvc/maven/components/trunk/maven-project/src/main/java/org/apache/maven/project/interpolation/RegexBasedModelInterpolator.java?view=diff&rev=549786&r1=549785&r2=549786
==============================================================================
--- 
maven/components/trunk/maven-project/src/main/java/org/apache/maven/project/interpolation/RegexBasedModelInterpolator.java
 (original)
+++ 
maven/components/trunk/maven-project/src/main/java/org/apache/maven/project/interpolation/RegexBasedModelInterpolator.java
 Fri Jun 22 04:34:53 2007
@@ -31,7 +31,9 @@
 import java.io.IOException;
 import java.io.StringReader;
 import java.io.StringWriter;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -67,6 +69,7 @@
      *
      * @param model   The inbound Model instance, to serialize and reference 
for expression resolution
      * @param context The other context map to be used during resolution
+     * @param strict  This parameter is ignored!
      * @return The resolved instance of the inbound Model. This is a different 
instance!
      */
     public Model interpolate( Model model, Map context, boolean strict )
@@ -108,58 +111,94 @@
         return model;
     }
 
+    /**
+     * Interpolates all expressions in the src parameter.
+     * <p>
+     * The algorithm used for each expression is:
+     * <ul>
+     *   <li>If it starts with either "pom." or "project.", the expression is 
evaluated against the model.</li>
+     *   <li>If the value is null, get the value from the context.</li>
+     *   <li>If the value is null, but the context contains the expression, 
don't replace the expression string
+     *       with the value, and continue to find other expressions.</li>
+     *   <li>If the value is null, get it from the model properties.</li>
+     *   <li>
+     *
+     *
+     */
     private String interpolateInternal( String src, Model model, Map context )
         throws ModelInterpolationException
     {
+        Logger logger = getLogger();
+
         String result = src;
         Matcher matcher = EXPRESSION_PATTERN.matcher( result );
         while ( matcher.find() )
         {
             String wholeExpr = matcher.group( 0 );
+            String prefix = matcher.group( 1 );
             String realExpr = matcher.group( 2 );
 
-            Object value = context.get( realExpr );
+            prefix = prefix == null ? "" : prefix;
+
+            Object value = null;
+
+            boolean isPomExpression = "pom.".equals( prefix ) || 
"project.".equals( prefix );
+
+            if ( logger != null && "project.".equals( prefix ) )
+            {
+                logger.warn( "Deprecated expression: " + wholeExpr + " - 
'project.' prefix is deprecated."
+                    + " Use 'pom.': ${pom." + realExpr + "} (model: " + 
model.getId() + ")" );
+            }
+
+            if ( isPomExpression )
+            {
+                value = getValueFromModel( realExpr, model, wholeExpr, logger 
);
+            }
 
             if ( value == null )
             {
+                value = context.get( realExpr );
+
                 // This may look out of place, but its here for the 
MNG-2124/MNG-1927 fix described in the project builder
-                if ( context.containsKey( realExpr ) )
+                if ( value == null && context.containsKey( realExpr ) )
                 {
                     // It existed, but was null. Leave it alone.
                     continue;
                 }
-
-                value = model.getProperties().getProperty( realExpr );
             }
 
             if ( value == null )
             {
-                try
-                {
-                    // NOTE: We've already trimmed off any leading expression 
parts like 'project.'
-                    // or 'pom.', and now we have to ensure that the 
ReflectionValueExtractor
-                    // doesn't try to do it again.
-                    value = ReflectionValueExtractor.evaluate( realExpr, 
model, false );
-                }
-                catch ( Exception e )
-                {
-                    Logger logger = getLogger();
-                    if ( logger != null )
-                    {
-                        logger.debug( "POM interpolation cannot proceed with 
expression: " + wholeExpr + ". Skipping...", e );
-                    }
-                }
+                value = model.getProperties().getProperty( realExpr );
             }
 
-            // if the expression refers to itself, skip it.
-            if ( String.valueOf( value ).indexOf( wholeExpr ) > -1 )
+            // Any expression, not just artifactId, version etc., but also 
scm.repository 
+            // were evaluated against the model, even if there is no prefix.
+            // If the 2.1 strategy fails, try the legacy approach. If it 
yields a result, warn for it.
+            if ( value == null && prefix.length() == 0 )
             {
-                throw new ModelInterpolationException( wholeExpr, "Expression 
value '" + value + "' references itself in '" + model.getId() + "'." );
+                value = getValueFromModel( realExpr, model, wholeExpr, logger 
);
+
+                if ( value != null && logger != null )
+                {
+                    logger.warn( "Deprecated expression: " + wholeExpr + " - 
missing prefix. Use ${pom."
+                        + realExpr + "} (model: " + model.getId() + ")" );
+                }
             }
 
             if ( value != null )
             {
-                result = StringUtils.replace( result, wholeExpr, 
String.valueOf( value ) );
+                // if the expression refers to itself, skip it.
+                // replace project. expressions with pom. expressions to 
circumvent self-referencing expressions using
+                // the 2 different model expressions.
+                if ( StringUtils.replace( value.toString(), "${project.", 
"${pom." ).indexOf(
+                    StringUtils.replace( wholeExpr, "${project.", "${pom." ) ) 
> -1 )
+                {
+                    throw new ModelInterpolationException( wholeExpr, 
"Expression value '" + value
+                        + "' references itself in '" + model.getId() + "'." );
+                }
+
+                result = StringUtils.replace( result, wholeExpr, 
value.toString() );
                 // could use:
                 // result = matcher.replaceFirst( stringValue );
                 // but this could result in multiple lookups of stringValue, 
and replaceAll is not correct behaviour
@@ -180,4 +219,23 @@
         return result;
     }
 
+    private static Object getValueFromModel( String realExpr, Model model, 
String wholeExpr, Logger logger )
+    {
+        try
+        {
+            // NOTE: We've already trimmed off any leading expression parts 
like 'project.'
+            // or 'pom.', and now we have to ensure that the 
ReflectionValueExtractor
+            // doesn't try to do it again.
+            return ReflectionValueExtractor.evaluate( realExpr, model, false );
+        }
+        catch ( Exception e )
+        {
+            if ( logger != null )
+            {
+                logger.debug( "POM interpolation cannot proceed with 
expression: " + wholeExpr + ". Skipping...", e );
+            }
+
+            return null;
+        }
+    }
 }

Modified: 
maven/components/trunk/maven-project/src/test/java/org/apache/maven/project/interpolation/RegexBasedModelInterpolatorTest.java
URL: 
http://svn.apache.org/viewvc/maven/components/trunk/maven-project/src/test/java/org/apache/maven/project/interpolation/RegexBasedModelInterpolatorTest.java?view=diff&rev=549786&r1=549785&r2=549786
==============================================================================
--- 
maven/components/trunk/maven-project/src/test/java/org/apache/maven/project/interpolation/RegexBasedModelInterpolatorTest.java
 (original)
+++ 
maven/components/trunk/maven-project/src/test/java/org/apache/maven/project/interpolation/RegexBasedModelInterpolatorTest.java
 Fri Jun 22 04:34:53 2007
@@ -129,11 +129,16 @@
         Dependency dep = new Dependency();
         dep.setVersion( "${version}" );
 
+        Dependency dep2 = new Dependency();
+        dep2.setVersion( "${pom.version}" );
+
         model.addDependency( dep );
+        model.addDependency( dep2 );
 
         Model out = new RegexBasedModelInterpolator().interpolate( model, 
context );
 
         assertEquals( "3.8.1", ( (Dependency) out.getDependencies().get( 0 ) 
).getVersion() );
+        assertEquals( "3.8.1", ( (Dependency) out.getDependencies().get( 1 ) 
).getVersion() );
     }
 
     public void testShouldNotInterpolateDependencyVersionWithInvalidReference()
@@ -177,11 +182,16 @@
         Dependency dep = new Dependency();
         dep.setVersion( "${artifactId}-${version}" );
 
+        Dependency dep2 = new Dependency();
+        dep2.setVersion( "${pom.artifactId}-${pom.version}" );
+
         model.addDependency( dep );
+        model.addDependency( dep2 );
 
         Model out = new RegexBasedModelInterpolator().interpolate( model, 
context );
 
         assertEquals( "foo-3.8.1", ( (Dependency) out.getDependencies().get( 0 
) ).getVersion() );
+        assertEquals( "foo-3.8.1", ( (Dependency) out.getDependencies().get( 1 
) ).getVersion() );
     }
 
     public void testBasedir()
@@ -197,6 +207,8 @@
 
         model.addRepository( repository );
 
+        assertNotNull( context.get( "basedir" ) );
+
         Model out = new RegexBasedModelInterpolator().interpolate( model, 
context );
 
         assertEquals( "file://localhost/myBasedir/temp-repo", ( (Repository) 
out.getRepositories().get( 0 ) ).getUrl() );
@@ -217,4 +229,37 @@
 
         assertEquals( out.getProperties().getProperty( "outputDirectory" ), 
"${DOES_NOT_EXIST}" );
     }
+
+    public void testPOMExpressionDoesNotUseSystemProperty()
+        throws Exception
+    {
+        Model model = new Model();
+        model.setVersion( "1.0" );
+
+        Properties modelProperties = new Properties();
+        modelProperties.setProperty( "version", "prop version" );
+        modelProperties.setProperty( "foo.version", "prop foo.version" );
+        modelProperties.setProperty( "pom.version", "prop pom.version" );
+        modelProperties.setProperty( "project.version", "prop project.version" 
);
+
+        model.setProperties( modelProperties );
+
+        Dependency dep = new Dependency();
+        model.addDependency( dep );
+
+        checkDep( "prop version", "${version}", model );
+        checkDep( "1.0", "${pom.version}", model );
+        checkDep( "1.0", "${project.version}", model );
+        checkDep( "prop foo.version", "${foo.version}", model );
+    }
+
+    private void checkDep( String expectedVersion, String depVersionExpr, 
Model model )
+        throws Exception
+    {
+        ( (Dependency) model.getDependencies().get( 0 ) ).setVersion( 
depVersionExpr );
+        Model out = new RegexBasedModelInterpolator().interpolate( model, 
context );
+        String result = ( (Dependency) out.getDependencies().get( 0 ) 
).getVersion();
+        assertEquals( "Expected '" + expectedVersion + "' for version 
expression '" + depVersionExpr + "', but was '" + result + "'", 
expectedVersion, result );
+    }
+
 }


Reply via email to