View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.plugin;
20  
21  import javax.inject.Inject;
22  
23  import java.io.File;
24  import java.net.URI;
25  import java.nio.file.Path;
26  import java.nio.file.Paths;
27  import java.util.Collection;
28  import java.util.Collections;
29  import java.util.Map;
30  import java.util.Objects;
31  import java.util.Properties;
32  
33  import org.apache.maven.AbstractCoreMavenComponentTestCase;
34  import org.apache.maven.RepositoryUtils;
35  import org.apache.maven.api.Artifact;
36  import org.apache.maven.api.MojoExecution;
37  import org.apache.maven.api.Session;
38  import org.apache.maven.artifact.DefaultArtifact;
39  import org.apache.maven.artifact.handler.DefaultArtifactHandler;
40  import org.apache.maven.artifact.repository.ArtifactRepository;
41  import org.apache.maven.bridge.MavenRepositorySystem;
42  import org.apache.maven.configuration.internal.EnhancedComponentConfigurator;
43  import org.apache.maven.execution.DefaultMavenExecutionRequest;
44  import org.apache.maven.execution.DefaultMavenExecutionResult;
45  import org.apache.maven.execution.MavenExecutionRequest;
46  import org.apache.maven.execution.MavenSession;
47  import org.apache.maven.internal.impl.*;
48  import org.apache.maven.model.Build;
49  import org.apache.maven.model.Model;
50  import org.apache.maven.model.building.DefaultModelBuildingRequest;
51  import org.apache.maven.model.interpolation.reflection.IntrospectionException;
52  import org.apache.maven.model.root.RootLocator;
53  import org.apache.maven.plugin.descriptor.MojoDescriptor;
54  import org.apache.maven.plugin.descriptor.PluginDescriptor;
55  import org.apache.maven.project.CycleDetectedException;
56  import org.apache.maven.project.DuplicateProjectException;
57  import org.apache.maven.project.MavenProject;
58  import org.codehaus.plexus.MutablePlexusContainer;
59  import org.codehaus.plexus.PlexusContainer;
60  import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
61  import org.codehaus.plexus.configuration.DefaultPlexusConfiguration;
62  import org.codehaus.plexus.util.Os;
63  import org.eclipse.aether.DefaultRepositorySystemSession;
64  import org.eclipse.aether.RepositorySystem;
65  import org.eclipse.aether.graph.DefaultDependencyNode;
66  import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory;
67  import org.eclipse.aether.repository.LocalRepository;
68  import org.eclipse.aether.repository.NoLocalRepositoryManagerException;
69  import org.junit.jupiter.api.Test;
70  
71  import static org.codehaus.plexus.testing.PlexusExtension.getTestFile;
72  import static org.junit.jupiter.api.Assertions.assertEquals;
73  import static org.junit.jupiter.api.Assertions.assertInstanceOf;
74  import static org.junit.jupiter.api.Assertions.assertNotNull;
75  import static org.junit.jupiter.api.Assertions.assertNull;
76  import static org.junit.jupiter.api.Assertions.assertSame;
77  import static org.junit.jupiter.api.Assertions.assertThrows;
78  import static org.junit.jupiter.api.Assertions.assertTrue;
79  import static org.mockito.Mockito.mock;
80  
81  /**
82   */
83  public class PluginParameterExpressionEvaluatorV4Test extends AbstractCoreMavenComponentTestCase {
84      private static final String FS = File.separator;
85  
86      @Inject
87      PlexusContainer container;
88  
89      @Inject
90      private MavenRepositorySystem factory;
91  
92      private Path rootDirectory;
93  
94      @Test
95      public void testPluginDescriptorExpressionReference() throws Exception {
96          Session session = newSession();
97          MojoExecution exec = newMojoExecution(session);
98  
99          Object result =
100                 new PluginParameterExpressionEvaluatorV4(session, null, exec).evaluate("${mojo.plugin.descriptor}");
101 
102         System.out.println("Result: " + result);
103 
104         assertSame(
105                 exec.getPlugin().getDescriptor(),
106                 result,
107                 "${mojo.plugin.descriptor} expression does not return plugin descriptor.");
108     }
109 
110     @Test
111     public void testPluginArtifactsExpressionReference() throws Exception {
112         Session session = newSession();
113         MojoExecution exec = newMojoExecution(session);
114 
115         @SuppressWarnings("unchecked")
116         Collection<Artifact> depResults = (Collection<Artifact>)
117                 new PluginParameterExpressionEvaluatorV4(session, null, exec).evaluate("${mojo.plugin.dependencies}");
118 
119         System.out.println("Result: " + depResults);
120 
121         assertNotNull(depResults);
122         assertEquals(1, depResults.size());
123         assertEquals(
124                 exec.getPlugin().getArtifact().key(),
125                 depResults.iterator().next().key(),
126                 "dependency artifact is wrong.");
127     }
128 
129     @Test
130     public void testPluginArtifactMapExpressionReference() throws Exception {
131         Session session = newSession();
132 
133         MojoExecution exec = newMojoExecution(session);
134 
135         @SuppressWarnings("unchecked")
136         Map<String, org.apache.maven.api.Dependency> depResults = (Map<String, org.apache.maven.api.Dependency>)
137                 new PluginParameterExpressionEvaluatorV4(session, null, exec)
138                         .evaluate("${mojo.plugin.dependenciesMap}");
139 
140         System.out.println("Result: " + depResults);
141 
142         assertNotNull(depResults);
143         assertEquals(1, depResults.size());
144         assertTrue(depResults.containsKey("org.myco.plugins:my-plugin"));
145         assertEquals(
146                 exec.getPlugin().getArtifact().key(),
147                 depResults.get("org.myco.plugins:my-plugin").key(),
148                 "dependency artifact is wrong.");
149     }
150 
151     @Test
152     public void testPluginArtifactIdExpressionReference() throws Exception {
153         Session session = newSession();
154 
155         MojoExecution exec = newMojoExecution(session);
156 
157         Object result = new PluginParameterExpressionEvaluatorV4(session, null, exec)
158                 .evaluate("${mojo.plugin.artifact.artifactId}");
159 
160         System.out.println("Result: " + result);
161 
162         assertSame(
163                 exec.getPlugin().getArtifact().getArtifactId(),
164                 result,
165                 "${plugin.artifactId} expression does not return plugin descriptor's artifactId.");
166     }
167 
168     @Test
169     public void testValueExtractionWithAPomValueContainingAPath() throws Exception {
170         String expected = getTestFile("target/test-classes/target/classes").getCanonicalPath();
171 
172         Build build = new Build();
173         build.setDirectory(expected.substring(0, expected.length() - "/classes".length()));
174 
175         Model model = new Model();
176         model.setBuild(build);
177 
178         MavenProject project = new MavenProject(model);
179         project.setFile(new File("pom.xml").getCanonicalFile());
180 
181         ExpressionEvaluator expressionEvaluator = createExpressionEvaluator(project, new Properties());
182 
183         Object value = expressionEvaluator.evaluate("${project.build.directory}/classes");
184         String actual = new File(value.toString()).getCanonicalPath();
185 
186         assertEquals(expected, actual);
187     }
188 
189     @Test
190     public void testEscapedVariablePassthrough() throws Exception {
191         String var = "${var}";
192 
193         Model model = new Model();
194         model.setVersion("1");
195 
196         MavenProject project = new MavenProject(model);
197 
198         ExpressionEvaluator ee = createExpressionEvaluator(project, new Properties());
199 
200         Object value = ee.evaluate("$" + var);
201 
202         assertEquals(var, value);
203     }
204 
205     @Test
206     public void testEscapedVariablePassthroughInLargerExpression() throws Exception {
207         String var = "${var}";
208         String key = var + " with version: ${project.version}";
209 
210         Model model = new Model();
211         model.setVersion("1");
212 
213         MavenProject project = new MavenProject(model);
214 
215         ExpressionEvaluator ee = createExpressionEvaluator(project, new Properties());
216 
217         Object value = ee.evaluate("$" + key);
218 
219         assertEquals("${var} with version: 1", value);
220     }
221 
222     @Test
223     public void testMultipleSubExpressionsInLargerExpression() throws Exception {
224         String key = "${project.artifactId} with version: ${project.version}";
225 
226         Model model = new Model();
227         model.setArtifactId("test");
228         model.setVersion("1");
229 
230         MavenProject project = new MavenProject(model);
231 
232         ExpressionEvaluator ee = createExpressionEvaluator(project, new Properties());
233 
234         Object value = ee.evaluate(key);
235 
236         assertEquals("test with version: 1", value);
237     }
238 
239     @Test
240     public void testMissingPOMPropertyRefInLargerExpression() throws Exception {
241         String expr = "/path/to/someproject-${baseVersion}";
242 
243         MavenProject project = new MavenProject(new Model());
244 
245         ExpressionEvaluator ee = createExpressionEvaluator(project, new Properties());
246 
247         Object value = ee.evaluate(expr);
248 
249         assertEquals(expr, value);
250     }
251 
252     @Test
253     public void testPOMPropertyExtractionWithMissingProject_WithDotNotation() throws Exception {
254         String key = "m2.name";
255         String checkValue = "value";
256 
257         Properties properties = new Properties();
258         properties.setProperty(key, checkValue);
259 
260         Model model = new Model();
261         model.setProperties(properties);
262 
263         MavenProject project = new MavenProject(model);
264 
265         ExpressionEvaluator ee = createExpressionEvaluator(project, new Properties());
266 
267         Object value = ee.evaluate("${" + key + "}");
268 
269         assertEquals(checkValue, value);
270     }
271 
272     @Test
273     public void testValueExtractionFromSystemPropertiesWithMissingProject() throws Exception {
274         String sysprop = "PPEET_sysprop1";
275 
276         Properties executionProperties = new Properties();
277 
278         if (executionProperties.getProperty(sysprop) == null) {
279             executionProperties.setProperty(sysprop, "value");
280         }
281 
282         ExpressionEvaluator ee = createExpressionEvaluator(null, executionProperties);
283 
284         Object value = ee.evaluate("${" + sysprop + "}");
285 
286         assertEquals("value", value);
287     }
288 
289     @Test
290     public void testValueExtractionFromSystemPropertiesWithMissingProject_WithDotNotation() throws Exception {
291         String sysprop = "PPEET.sysprop2";
292 
293         Properties executionProperties = new Properties();
294 
295         if (executionProperties.getProperty(sysprop) == null) {
296             executionProperties.setProperty(sysprop, "value");
297         }
298 
299         ExpressionEvaluator ee = createExpressionEvaluator(null, executionProperties);
300 
301         Object value = ee.evaluate("${" + sysprop + "}");
302 
303         assertEquals("value", value);
304     }
305 
306     @SuppressWarnings("deprecation")
307     private static MavenSession createSession(PlexusContainer container, ArtifactRepository repo, Properties properties)
308             throws CycleDetectedException, DuplicateProjectException, NoLocalRepositoryManagerException {
309         MavenExecutionRequest request = new DefaultMavenExecutionRequest()
310                 .setSystemProperties(properties)
311                 .setGoals(Collections.<String>emptyList())
312                 .setBaseDirectory(new File(""))
313                 .setLocalRepository(repo);
314 
315         DefaultRepositorySystemSession repositorySession =
316                 new DefaultRepositorySystemSession(h -> false); // no close handle
317         repositorySession.setLocalRepositoryManager(new SimpleLocalRepositoryManagerFactory()
318                 .newInstance(repositorySession, new LocalRepository(repo.getUrl())));
319         MavenSession session =
320                 new MavenSession(container, repositorySession, request, new DefaultMavenExecutionResult());
321         session.setProjects(Collections.<MavenProject>emptyList());
322         return session;
323     }
324 
325     @Test
326     public void testTwoExpressions() throws Exception {
327         Build build = new Build();
328         build.setDirectory("expected-directory");
329         build.setFinalName("expected-finalName");
330 
331         Model model = new Model();
332         model.setBuild(build);
333 
334         ExpressionEvaluator expressionEvaluator = createExpressionEvaluator(new MavenProject(model), new Properties());
335 
336         Object value = expressionEvaluator.evaluate("${project.build.directory}" + FS + "${project.build.finalName}");
337 
338         assertEquals("expected-directory" + File.separatorChar + "expected-finalName", value);
339     }
340 
341     @Test
342     public void testShouldExtractPluginArtifacts() throws Exception {
343         ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), new Properties());
344 
345         Object value = ee.evaluate("${mojo.plugin.dependencies}");
346 
347         assertTrue(value instanceof Collection);
348 
349         @SuppressWarnings("unchecked")
350         Collection<Artifact> artifacts = (Collection<Artifact>) value;
351 
352         assertEquals(1, artifacts.size());
353 
354         Artifact result = artifacts.iterator().next();
355 
356         assertEquals("org.myco.plugins", result.getGroupId());
357     }
358 
359     @Test
360     void testRootDirectoryNotPrefixed() throws Exception {
361         ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), new Properties());
362         assertNull(ee.evaluate("${rootDirectory}"));
363     }
364 
365     @Test
366     void testRootDirectoryWithNull() throws Exception {
367         ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), new Properties());
368         Exception e = assertThrows(Exception.class, () -> ee.evaluate("${session.rootDirectory}"));
369         e = assertInstanceOf(IntrospectionException.class, e.getCause());
370         e = assertInstanceOf(IllegalStateException.class, e.getCause());
371         assertEquals(RootLocator.UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE, e.getMessage());
372     }
373 
374     @Test
375     void testRootDirectory() throws Exception {
376         this.rootDirectory = Paths.get("myRootDirectory");
377         ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), new Properties());
378         assertInstanceOf(Path.class, ee.evaluate("${session.rootDirectory}"));
379     }
380 
381     private MavenProject createDefaultProject() {
382         return new MavenProject(new Model());
383     }
384 
385     private ExpressionEvaluator createExpressionEvaluator(MavenProject project, Properties executionProperties)
386             throws Exception {
387         ArtifactRepository repo = getLocalRepository();
388 
389         MutablePlexusContainer container = (MutablePlexusContainer) getContainer();
390         MavenSession mavenSession = createSession(container, repo, executionProperties);
391         mavenSession.setCurrentProject(project);
392         mavenSession.getRequest().setRootDirectory(rootDirectory);
393         mavenSession.getRequest().setTopDirectory(rootDirectory);
394 
395         DefaultSession session = new DefaultSession(
396                 mavenSession, mock(RepositorySystem.class), null, null, new DefaultLookup(container), null);
397 
398         MojoExecution mojoExecution = newMojoExecution(session);
399 
400         return new PluginParameterExpressionEvaluatorV4(
401                 session, project != null ? new DefaultProject(session, project) : null, mojoExecution);
402     }
403 
404     private MojoExecution newMojoExecution(Session session) {
405         PluginDescriptor pd = new PluginDescriptor();
406         pd.setArtifactId("my-plugin");
407         pd.setGroupId("org.myco.plugins");
408         pd.setVersion("1");
409 
410         DefaultArtifact artifact = new DefaultArtifact(
411                 pd.getGroupId(),
412                 pd.getArtifactId(),
413                 pd.getVersion(),
414                 "compile",
415                 "maven-plugin",
416                 "",
417                 new DefaultArtifactHandler("maven-plugin"));
418         pd.setPluginArtifact(artifact);
419 
420         pd.setArtifacts(Collections.singletonList(artifact));
421         DefaultDependencyNode node = new DefaultDependencyNode(
422                 new org.eclipse.aether.graph.Dependency(RepositoryUtils.toArtifact(artifact), "compile"));
423         pd.setDependencyNode(node);
424 
425         MojoDescriptor md = new MojoDescriptor();
426         md.setGoal("my-goal");
427         md.setPluginDescriptor(pd);
428 
429         pd.addComponentDescriptor(md);
430 
431         return new DefaultMojoExecution((AbstractSession) session, new org.apache.maven.plugin.MojoExecution(md));
432     }
433 
434     private DefaultSession newSession() throws Exception {
435         DefaultSession session = new DefaultSession(
436                 newMavenSession(), mock(RepositorySystem.class), null, null, new DefaultLookup(container), null);
437         return session;
438     }
439 
440     private MavenSession newMavenSession() throws Exception {
441         return createMavenSession(null);
442     }
443 
444     @Test
445     public void testUri() throws Exception {
446         Path path = Paths.get("").toAbsolutePath();
447 
448         MavenSession mavenSession = createMavenSession(null);
449         mavenSession.getRequest().setTopDirectory(path);
450         mavenSession.getRequest().setRootDirectory(path);
451 
452         Object result = new PluginParameterExpressionEvaluatorV4(mavenSession.getSession(), null)
453                 .evaluate("${session.rootDirectory.uri}");
454         assertEquals(path.toUri(), result);
455     }
456 
457     @Test
458     public void testPath() throws Exception {
459         Path path = Paths.get("").toAbsolutePath();
460 
461         MavenSession mavenSession = createMavenSession(null);
462         mavenSession.getRequest().setTopDirectory(path);
463         mavenSession.getRequest().setRootDirectory(path);
464 
465         Object result = new PluginParameterExpressionEvaluatorV4(mavenSession.getSession(), null)
466                 .evaluate("${session.rootDirectory/target}");
467         assertEquals(path.resolve("target"), result);
468     }
469 
470     @Test
471     public void testPluginInjection() throws Exception {
472         Path path = Paths.get("rép➜α").toAbsolutePath();
473 
474         MavenSession mavenSession = createMavenSession(null);
475         mavenSession.getRequest().setTopDirectory(path);
476         mavenSession.getRequest().setRootDirectory(path);
477         DefaultModelBuildingRequest mbr = new DefaultModelBuildingRequest();
478 
479         PluginParameterExpressionEvaluatorV4 evaluator =
480                 new PluginParameterExpressionEvaluatorV4(mavenSession.getSession(), null);
481 
482         DefaultPlexusConfiguration configuration = new DefaultPlexusConfiguration("config");
483         configuration.addChild("uri", "${session.rootDirectory.uri}");
484         configuration.addChild("path", "${session.rootDirectory}");
485         configuration.addChild("uriString", "${session.rootDirectory.uri.string}");
486         configuration.addChild("uriAsciiString", "${session.rootDirectory.uri.ASCIIString}");
487         configuration.addChild("pathString", "${session.rootDirectory.string}");
488 
489         Mojo mojo = new Mojo();
490         new EnhancedComponentConfigurator().configureComponent(mojo, configuration, evaluator, null);
491 
492         assertEquals(
493                 Objects.equals(path.toUri().toString(), path.toUri().toASCIIString()), !Os.isFamily(Os.FAMILY_WINDOWS));
494         assertEquals(mojo.uri, path.toUri());
495         assertEquals(mojo.path, path);
496         assertEquals(mojo.uriString, path.toUri().toString());
497         assertEquals(mojo.uriAsciiString, path.toUri().toASCIIString());
498         assertEquals(mojo.pathString, path.toString());
499     }
500 
501     @Override
502     protected String getProjectsDirectory() {
503         // TODO Auto-generated method stub
504         return null;
505     }
506 
507     public static class Mojo {
508         URI uri;
509         Path path;
510         String uriString;
511         String uriAsciiString;
512         String pathString;
513     }
514 }