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.ArrayList;
28  import java.util.Collections;
29  import java.util.List;
30  import java.util.Map;
31  import java.util.Objects;
32  import java.util.Properties;
33  
34  import org.apache.maven.AbstractCoreMavenComponentTestCase;
35  import org.apache.maven.api.Session;
36  import org.apache.maven.artifact.Artifact;
37  import org.apache.maven.artifact.ArtifactUtils;
38  import org.apache.maven.artifact.repository.ArtifactRepository;
39  import org.apache.maven.bridge.MavenRepositorySystem;
40  import org.apache.maven.configuration.internal.EnhancedComponentConfigurator;
41  import org.apache.maven.execution.DefaultMavenExecutionRequest;
42  import org.apache.maven.execution.DefaultMavenExecutionResult;
43  import org.apache.maven.execution.MavenExecutionRequest;
44  import org.apache.maven.execution.MavenSession;
45  import org.apache.maven.internal.impl.DefaultProject;
46  import org.apache.maven.internal.impl.DefaultSession;
47  import org.apache.maven.model.Build;
48  import org.apache.maven.model.Dependency;
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.internal.impl.DefaultRepositorySystem;
65  import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory;
66  import org.eclipse.aether.repository.LocalRepository;
67  import org.eclipse.aether.repository.NoLocalRepositoryManagerException;
68  import org.junit.jupiter.api.Test;
69  
70  import static org.codehaus.plexus.testing.PlexusExtension.getTestFile;
71  import static org.junit.jupiter.api.Assertions.assertEquals;
72  import static org.junit.jupiter.api.Assertions.assertInstanceOf;
73  import static org.junit.jupiter.api.Assertions.assertNotNull;
74  import static org.junit.jupiter.api.Assertions.assertNull;
75  import static org.junit.jupiter.api.Assertions.assertSame;
76  import static org.junit.jupiter.api.Assertions.assertThrows;
77  import static org.junit.jupiter.api.Assertions.assertTrue;
78  
79  /**
80   */
81  public class PluginParameterExpressionEvaluatorV4Test extends AbstractCoreMavenComponentTestCase {
82      private static final String FS = File.separator;
83  
84      @Inject
85      private MavenRepositorySystem factory;
86  
87      private Path rootDirectory;
88  
89      @Test
90      public void testPluginDescriptorExpressionReference() throws Exception {
91          MojoExecution exec = newMojoExecution();
92  
93          Session session = newSession();
94  
95          Object result = new PluginParameterExpressionEvaluatorV4(session, null, exec).evaluate("${plugin}");
96  
97          System.out.println("Result: " + result);
98  
99          assertSame(
100                 exec.getMojoDescriptor().getPluginDescriptor(),
101                 result,
102                 "${plugin} expression does not return plugin descriptor.");
103     }
104 
105     @Test
106     public void testPluginArtifactsExpressionReference() throws Exception {
107         MojoExecution exec = newMojoExecution();
108 
109         Artifact depArtifact = createArtifact("group", "artifact", "1");
110 
111         List<Artifact> deps = new ArrayList<>();
112         deps.add(depArtifact);
113 
114         exec.getMojoDescriptor().getPluginDescriptor().setArtifacts(deps);
115 
116         Session session = newSession();
117 
118         @SuppressWarnings("unchecked")
119         List<Artifact> depResults = (List<Artifact>)
120                 new PluginParameterExpressionEvaluatorV4(session, null, exec).evaluate("${plugin.artifacts}");
121 
122         System.out.println("Result: " + depResults);
123 
124         assertNotNull(depResults);
125         assertEquals(1, depResults.size());
126         assertSame(depArtifact, depResults.get(0), "dependency artifact is wrong.");
127     }
128 
129     @Test
130     public void testPluginArtifactMapExpressionReference() throws Exception {
131         MojoExecution exec = newMojoExecution();
132 
133         Artifact depArtifact = createArtifact("group", "artifact", "1");
134 
135         List<Artifact> deps = new ArrayList<>();
136         deps.add(depArtifact);
137 
138         exec.getMojoDescriptor().getPluginDescriptor().setArtifacts(deps);
139 
140         Session session = newSession();
141 
142         @SuppressWarnings("unchecked")
143         Map<String, Artifact> depResults = (Map<String, Artifact>)
144                 new PluginParameterExpressionEvaluatorV4(session, null, exec).evaluate("${plugin.artifactMap}");
145 
146         System.out.println("Result: " + depResults);
147 
148         assertNotNull(depResults);
149         assertEquals(1, depResults.size());
150         assertSame(
151                 depArtifact,
152                 depResults.get(ArtifactUtils.versionlessKey(depArtifact)),
153                 "dependency artifact is wrong.");
154     }
155 
156     @Test
157     public void testPluginArtifactIdExpressionReference() throws Exception {
158         MojoExecution exec = newMojoExecution();
159 
160         Session session = newSession();
161 
162         Object result = new PluginParameterExpressionEvaluatorV4(session, null, exec).evaluate("${plugin.artifactId}");
163 
164         System.out.println("Result: " + result);
165 
166         assertSame(
167                 exec.getMojoDescriptor().getPluginDescriptor().getArtifactId(),
168                 result,
169                 "${plugin.artifactId} expression does not return plugin descriptor's artifactId.");
170     }
171 
172     @Test
173     public void testValueExtractionWithAPomValueContainingAPath() throws Exception {
174         String expected = getTestFile("target/test-classes/target/classes").getCanonicalPath();
175 
176         Build build = new Build();
177         build.setDirectory(expected.substring(0, expected.length() - "/classes".length()));
178 
179         Model model = new Model();
180         model.setBuild(build);
181 
182         MavenProject project = new MavenProject(model);
183         project.setFile(new File("pom.xml").getCanonicalFile());
184 
185         ExpressionEvaluator expressionEvaluator = createExpressionEvaluator(project, null, new Properties());
186 
187         Object value = expressionEvaluator.evaluate("${project.build.directory}/classes");
188         String actual = new File(value.toString()).getCanonicalPath();
189 
190         assertEquals(expected, actual);
191     }
192 
193     @Test
194     public void testEscapedVariablePassthrough() throws Exception {
195         String var = "${var}";
196 
197         Model model = new Model();
198         model.setVersion("1");
199 
200         MavenProject project = new MavenProject(model);
201 
202         ExpressionEvaluator ee = createExpressionEvaluator(project, null, new Properties());
203 
204         Object value = ee.evaluate("$" + var);
205 
206         assertEquals(var, value);
207     }
208 
209     @Test
210     public void testEscapedVariablePassthroughInLargerExpression() throws Exception {
211         String var = "${var}";
212         String key = var + " with version: ${project.version}";
213 
214         Model model = new Model();
215         model.setVersion("1");
216 
217         MavenProject project = new MavenProject(model);
218 
219         ExpressionEvaluator ee = createExpressionEvaluator(project, null, new Properties());
220 
221         Object value = ee.evaluate("$" + key);
222 
223         assertEquals("${var} with version: 1", value);
224     }
225 
226     @Test
227     public void testMultipleSubExpressionsInLargerExpression() throws Exception {
228         String key = "${project.artifactId} with version: ${project.version}";
229 
230         Model model = new Model();
231         model.setArtifactId("test");
232         model.setVersion("1");
233 
234         MavenProject project = new MavenProject(model);
235 
236         ExpressionEvaluator ee = createExpressionEvaluator(project, null, new Properties());
237 
238         Object value = ee.evaluate(key);
239 
240         assertEquals("test with version: 1", value);
241     }
242 
243     @Test
244     public void testMissingPOMPropertyRefInLargerExpression() throws Exception {
245         String expr = "/path/to/someproject-${baseVersion}";
246 
247         MavenProject project = new MavenProject(new Model());
248 
249         ExpressionEvaluator ee = createExpressionEvaluator(project, null, new Properties());
250 
251         Object value = ee.evaluate(expr);
252 
253         assertEquals(expr, value);
254     }
255 
256     @Test
257     public void testPOMPropertyExtractionWithMissingProject_WithDotNotation() throws Exception {
258         String key = "m2.name";
259         String checkValue = "value";
260 
261         Properties properties = new Properties();
262         properties.setProperty(key, checkValue);
263 
264         Model model = new Model();
265         model.setProperties(properties);
266 
267         MavenProject project = new MavenProject(model);
268 
269         ExpressionEvaluator ee = createExpressionEvaluator(project, null, new Properties());
270 
271         Object value = ee.evaluate("${" + key + "}");
272 
273         assertEquals(checkValue, value);
274     }
275 
276     @Test
277     public void testBasedirExtractionWithMissingProject() throws Exception {
278         ExpressionEvaluator ee = createExpressionEvaluator(null, null, new Properties());
279 
280         Object value = ee.evaluate("${basedir}");
281 
282         assertEquals(System.getProperty("user.dir"), value);
283     }
284 
285     @Test
286     public void testValueExtractionFromSystemPropertiesWithMissingProject() throws Exception {
287         String sysprop = "PPEET_sysprop1";
288 
289         Properties executionProperties = new Properties();
290 
291         if (executionProperties.getProperty(sysprop) == null) {
292             executionProperties.setProperty(sysprop, "value");
293         }
294 
295         ExpressionEvaluator ee = createExpressionEvaluator(null, null, executionProperties);
296 
297         Object value = ee.evaluate("${" + sysprop + "}");
298 
299         assertEquals("value", value);
300     }
301 
302     @Test
303     public void testValueExtractionFromSystemPropertiesWithMissingProject_WithDotNotation() throws Exception {
304         String sysprop = "PPEET.sysprop2";
305 
306         Properties executionProperties = new Properties();
307 
308         if (executionProperties.getProperty(sysprop) == null) {
309             executionProperties.setProperty(sysprop, "value");
310         }
311 
312         ExpressionEvaluator ee = createExpressionEvaluator(null, null, executionProperties);
313 
314         Object value = ee.evaluate("${" + sysprop + "}");
315 
316         assertEquals("value", value);
317     }
318 
319     @SuppressWarnings("deprecation")
320     private static MavenSession createSession(PlexusContainer container, ArtifactRepository repo, Properties properties)
321             throws CycleDetectedException, DuplicateProjectException, NoLocalRepositoryManagerException {
322         MavenExecutionRequest request = new DefaultMavenExecutionRequest()
323                 .setSystemProperties(properties)
324                 .setGoals(Collections.<String>emptyList())
325                 .setBaseDirectory(new File(""))
326                 .setLocalRepository(repo);
327 
328         DefaultRepositorySystemSession repositorySession = new DefaultRepositorySystemSession();
329         repositorySession.setLocalRepositoryManager(new SimpleLocalRepositoryManagerFactory()
330                 .newInstance(repositorySession, new LocalRepository(repo.getUrl())));
331         MavenSession session =
332                 new MavenSession(container, repositorySession, request, new DefaultMavenExecutionResult());
333         session.setProjects(Collections.<MavenProject>emptyList());
334         return session;
335     }
336 
337     @Test
338     public void testLocalRepositoryExtraction() throws Exception {
339         ExpressionEvaluator expressionEvaluator =
340                 createExpressionEvaluator(createDefaultProject(), null, new Properties());
341         Object value = expressionEvaluator.evaluate("${localRepository}");
342 
343         assertEquals("local", ((org.apache.maven.api.LocalRepository) value).getId());
344     }
345 
346     @Test
347     public void testTwoExpressions() throws Exception {
348         Build build = new Build();
349         build.setDirectory("expected-directory");
350         build.setFinalName("expected-finalName");
351 
352         Model model = new Model();
353         model.setBuild(build);
354 
355         ExpressionEvaluator expressionEvaluator =
356                 createExpressionEvaluator(new MavenProject(model), null, new Properties());
357 
358         Object value = expressionEvaluator.evaluate("${project.build.directory}" + FS + "${project.build.finalName}");
359 
360         assertEquals("expected-directory" + File.separatorChar + "expected-finalName", value);
361     }
362 
363     @Test
364     public void testShouldExtractPluginArtifacts() throws Exception {
365         PluginDescriptor pd = new PluginDescriptor();
366 
367         Artifact artifact = createArtifact("testGroup", "testArtifact", "1.0");
368 
369         pd.setArtifacts(Collections.singletonList(artifact));
370 
371         ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), pd, new Properties());
372 
373         Object value = ee.evaluate("${plugin.artifacts}");
374 
375         assertTrue(value instanceof List);
376 
377         @SuppressWarnings("unchecked")
378         List<Artifact> artifacts = (List<Artifact>) value;
379 
380         assertEquals(1, artifacts.size());
381 
382         Artifact result = artifacts.get(0);
383 
384         assertEquals("testGroup", result.getGroupId());
385     }
386 
387     @Test
388     void testRootDirectoryNotPrefixed() throws Exception {
389         ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), null, new Properties());
390         assertNull(ee.evaluate("${rootDirectory}"));
391     }
392 
393     @Test
394     void testRootDirectoryWithNull() throws Exception {
395         ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), null, new Properties());
396         Exception e = assertThrows(Exception.class, () -> ee.evaluate("${session.rootDirectory}"));
397         e = assertInstanceOf(IntrospectionException.class, e.getCause());
398         e = assertInstanceOf(IllegalStateException.class, e.getCause());
399         assertEquals(RootLocator.UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE, e.getMessage());
400     }
401 
402     @Test
403     void testRootDirectory() throws Exception {
404         this.rootDirectory = Paths.get("myRootDirectory");
405         ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), null, new Properties());
406         assertInstanceOf(Path.class, ee.evaluate("${session.rootDirectory}"));
407     }
408 
409     private MavenProject createDefaultProject() {
410         return new MavenProject(new Model());
411     }
412 
413     private ExpressionEvaluator createExpressionEvaluator(
414             MavenProject project, PluginDescriptor pluginDescriptor, Properties executionProperties) throws Exception {
415         ArtifactRepository repo = getLocalRepository();
416 
417         MutablePlexusContainer container = (MutablePlexusContainer) getContainer();
418         MavenSession mavenSession = createSession(container, repo, executionProperties);
419         mavenSession.setCurrentProject(project);
420         mavenSession.getRequest().setRootDirectory(rootDirectory);
421 
422         DefaultSession session =
423                 new DefaultSession(mavenSession, new DefaultRepositorySystem(), null, null, null, null);
424 
425         MojoDescriptor mojo = new MojoDescriptor();
426         mojo.setPluginDescriptor(pluginDescriptor);
427         mojo.setGoal("goal");
428 
429         MojoExecution mojoExecution = new MojoExecution(mojo);
430 
431         return new PluginParameterExpressionEvaluatorV4(
432                 session, project != null ? new DefaultProject(session, project) : null, mojoExecution);
433     }
434 
435     protected Artifact createArtifact(String groupId, String artifactId, String version) throws Exception {
436         Dependency dependency = new Dependency();
437         dependency.setGroupId(groupId);
438         dependency.setArtifactId(artifactId);
439         dependency.setVersion(version);
440         dependency.setType("jar");
441         dependency.setScope("compile");
442 
443         return factory.createDependencyArtifact(dependency);
444     }
445 
446     private MojoExecution newMojoExecution() {
447         PluginDescriptor pd = new PluginDescriptor();
448         pd.setArtifactId("my-plugin");
449         pd.setGroupId("org.myco.plugins");
450         pd.setVersion("1");
451 
452         MojoDescriptor md = new MojoDescriptor();
453         md.setPluginDescriptor(pd);
454 
455         pd.addComponentDescriptor(md);
456 
457         return new MojoExecution(md);
458     }
459 
460     private DefaultSession newSession() throws Exception {
461         return new DefaultSession(newMavenSession(), new DefaultRepositorySystem(), null, null, null, null);
462     }
463 
464     private MavenSession newMavenSession() throws Exception {
465         return createMavenSession(null);
466     }
467 
468     @Test
469     public void testUri() throws Exception {
470         Path path = Paths.get("").toAbsolutePath();
471 
472         MavenSession mavenSession = createMavenSession(null);
473         mavenSession.getRequest().setTopDirectory(path);
474         mavenSession.getRequest().setRootDirectory(path);
475 
476         Object result = new PluginParameterExpressionEvaluatorV4(mavenSession.getSession(), null)
477                 .evaluate("${session.rootDirectory.uri}");
478         assertEquals(path.toUri(), result);
479     }
480 
481     @Test
482     public void testPath() throws Exception {
483         Path path = Paths.get("").toAbsolutePath();
484 
485         MavenSession mavenSession = createMavenSession(null);
486         mavenSession.getRequest().setTopDirectory(path);
487         mavenSession.getRequest().setRootDirectory(path);
488 
489         Object result = new PluginParameterExpressionEvaluatorV4(mavenSession.getSession(), null)
490                 .evaluate("${session.rootDirectory/target}");
491         assertEquals(path.resolve("target"), result);
492     }
493 
494     @Test
495     public void testPluginInjection() throws Exception {
496         Path path = Paths.get("rép➜α").toAbsolutePath();
497 
498         MavenSession mavenSession = createMavenSession(null);
499         mavenSession.getRequest().setTopDirectory(path);
500         mavenSession.getRequest().setRootDirectory(path);
501         DefaultModelBuildingRequest mbr = new DefaultModelBuildingRequest();
502 
503         PluginParameterExpressionEvaluatorV4 evaluator =
504                 new PluginParameterExpressionEvaluatorV4(mavenSession.getSession(), null);
505 
506         DefaultPlexusConfiguration configuration = new DefaultPlexusConfiguration("config");
507         configuration.addChild("uri", "${session.rootDirectory.uri}");
508         configuration.addChild("path", "${session.rootDirectory}");
509         configuration.addChild("uriString", "${session.rootDirectory.uri.string}");
510         configuration.addChild("uriAsciiString", "${session.rootDirectory.uri.ASCIIString}");
511         configuration.addChild("pathString", "${session.rootDirectory.string}");
512 
513         Mojo mojo = new Mojo();
514         new EnhancedComponentConfigurator().configureComponent(mojo, configuration, evaluator, null);
515 
516         assertEquals(
517                 Objects.equals(path.toUri().toString(), path.toUri().toASCIIString()), !Os.isFamily(Os.FAMILY_WINDOWS));
518         assertEquals(mojo.uri, path.toUri());
519         assertEquals(mojo.path, path);
520         assertEquals(mojo.uriString, path.toUri().toString());
521         assertEquals(mojo.uriAsciiString, path.toUri().toASCIIString());
522         assertEquals(mojo.pathString, path.toString());
523     }
524 
525     @Override
526     protected String getProjectsDirectory() {
527         // TODO Auto-generated method stub
528         return null;
529     }
530 
531     public static class Mojo {
532         URI uri;
533         Path path;
534         String uriString;
535         String uriAsciiString;
536         String pathString;
537     }
538 }