29
29
import java .io .PrintStream ;
30
30
import java .nio .charset .Charset ;
31
31
import java .nio .file .Files ;
32
+ import java .nio .file .Path ;
33
+ import java .nio .file .Paths ;
32
34
import java .util .ArrayList ;
33
35
import java .util .Collections ;
34
36
import java .util .HashSet ;
35
37
import java .util .LinkedHashMap ;
36
38
import java .util .List ;
39
+ import java .util .ListIterator ;
37
40
import java .util .Map ;
38
41
import java .util .Map .Entry ;
39
42
import java .util .Properties ;
102
105
import org .codehaus .plexus .classworlds .realm .ClassRealm ;
103
106
import org .codehaus .plexus .classworlds .realm .NoSuchRealmException ;
104
107
import org .codehaus .plexus .component .repository .exception .ComponentLookupException ;
108
+ import org .codehaus .plexus .interpolation .AbstractValueSource ;
109
+ import org .codehaus .plexus .interpolation .InterpolationException ;
110
+ import org .codehaus .plexus .interpolation .StringSearchInterpolator ;
105
111
import org .codehaus .plexus .logging .LoggerManager ;
106
112
import org .codehaus .plexus .util .StringUtils ;
107
113
import org .codehaus .plexus .util .xml .pull .XmlPullParserException ;
@@ -140,9 +146,14 @@ public class MavenCli {
140
146
141
147
private static final String EXT_CLASS_PATH = "maven.ext.class.path" ;
142
148
143
- private static final String EXTENSIONS_FILENAME = ".mvn/extensions.xml " ;
149
+ private static final String DOT_MVN = ".mvn" ;
144
150
145
- private static final String MVN_MAVEN_CONFIG = ".mvn/maven.config" ;
151
+ private static final String UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE = "Unable to find the root directory. Create a "
152
+ + DOT_MVN + " directory in the project root directory to identify it." ;
153
+
154
+ private static final String EXTENSIONS_FILENAME = DOT_MVN + "/extensions.xml" ;
155
+
156
+ private static final String MVN_MAVEN_CONFIG = DOT_MVN + "/maven.config" ;
146
157
147
158
public static final String STYLE_COLOR_PROPERTY = "style.color" ;
148
159
@@ -309,6 +320,47 @@ void initialize(CliRequest cliRequest) throws ExitException {
309
320
}
310
321
}
311
322
323
+ // We need to locate the top level project which may be pointed at using
324
+ // the -f/--file option. However, the command line isn't parsed yet, so
325
+ // we need to iterate through the args to find it and act upon it.
326
+ Path topDirectory = Paths .get (cliRequest .workingDirectory );
327
+ boolean isAltFile = false ;
328
+ for (String arg : cliRequest .args ) {
329
+ if (isAltFile ) {
330
+ // this is the argument following -f/--file
331
+ Path path = topDirectory .resolve (arg );
332
+ if (Files .isDirectory (path )) {
333
+ topDirectory = path ;
334
+ } else if (Files .isRegularFile (path )) {
335
+ topDirectory = path .getParent ();
336
+ if (!Files .isDirectory (topDirectory )) {
337
+ System .err .println ("Directory " + topDirectory
338
+ + " extracted from the -f/--file command-line argument " + arg + " does not exist" );
339
+ throw new ExitException (1 );
340
+ }
341
+ } else {
342
+ System .err .println (
343
+ "POM file " + arg + " specified with the -f/--file command line argument does not exist" );
344
+ throw new ExitException (1 );
345
+ }
346
+ break ;
347
+ } else {
348
+ // Check if this is the -f/--file option
349
+ isAltFile = arg .equals (String .valueOf (CLIManager .ALTERNATE_POM_FILE )) || arg .equals ("file" );
350
+ }
351
+ }
352
+ try {
353
+ topDirectory = topDirectory .toAbsolutePath ().toRealPath ();
354
+ } catch (IOException e ) {
355
+ System .err .println ("Error computing real path from " + topDirectory + ": " + e .getMessage ());
356
+ throw new ExitException (1 );
357
+ }
358
+ cliRequest .topDirectory = topDirectory ;
359
+ // We're very early in the process and we don't have the container set up yet,
360
+ // so we on searchAcceptableRootDirectory method to find us acceptable directory.
361
+ // The method may return null if nothing acceptable found.
362
+ cliRequest .rootDirectory = searchAcceptableRootDirectory (topDirectory );
363
+
312
364
//
313
365
// Make sure the Maven home directory is an absolute path to save us from confusion with say drive-relative
314
366
// Windows paths.
@@ -526,8 +578,39 @@ private void commands(CliRequest cliRequest) {
526
578
527
579
// Needed to make this method package visible to make writing a unit test possible
528
580
// Maybe it's better to move some of those methods to separate class (SoC).
529
- void properties (CliRequest cliRequest ) {
530
- populateProperties (cliRequest .commandLine , cliRequest .systemProperties , cliRequest .userProperties );
581
+ void properties (CliRequest cliRequest ) throws ExitException {
582
+ try {
583
+ populateProperties (cliRequest , cliRequest .systemProperties , cliRequest .userProperties );
584
+
585
+ StringSearchInterpolator interpolator =
586
+ createInterpolator (cliRequest , cliRequest .systemProperties , cliRequest .userProperties );
587
+ CommandLine .Builder commandLineBuilder = new CommandLine .Builder ();
588
+ for (Option option : cliRequest .commandLine .getOptions ()) {
589
+ if (!String .valueOf (CLIManager .SET_USER_PROPERTY ).equals (option .getOpt ())) {
590
+ List <String > values = option .getValuesList ();
591
+ for (ListIterator <String > it = values .listIterator (); it .hasNext (); ) {
592
+ it .set (interpolator .interpolate (it .next ()));
593
+ }
594
+ }
595
+ commandLineBuilder .addOption (option );
596
+ }
597
+ for (String arg : cliRequest .commandLine .getArgList ()) {
598
+ commandLineBuilder .addArg (interpolator .interpolate (arg ));
599
+ }
600
+ cliRequest .commandLine = commandLineBuilder .build ();
601
+ } catch (InterpolationException e ) {
602
+ String message = "ERROR: Could not interpolate properties and/or arguments: " + e .getMessage ();
603
+ System .err .println (message );
604
+ throw new ExitException (1 ); // user error
605
+ } catch (IllegalUseOfUndefinedProperty e ) {
606
+ String message = "ERROR: Illegal use of undefined property: " + e .property ;
607
+ System .err .println (message );
608
+ if (cliRequest .rootDirectory == null ) {
609
+ System .err .println ();
610
+ System .err .println (UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE );
611
+ }
612
+ throw new ExitException (1 ); // user error
613
+ }
531
614
}
532
615
533
616
PlexusContainer container (CliRequest cliRequest ) throws Exception {
@@ -1405,27 +1488,54 @@ int calculateDegreeOfConcurrency(String threadConfiguration) {
1405
1488
// Properties handling
1406
1489
// ----------------------------------------------------------------------
1407
1490
1408
- static void populateProperties (CommandLine commandLine , Properties systemProperties , Properties userProperties ) {
1409
- EnvironmentUtils . addEnvVars ( systemProperties );
1491
+ static void populateProperties (CliRequest cliRequest , Properties systemProperties , Properties userProperties )
1492
+ throws InterpolationException {
1410
1493
1411
1494
// ----------------------------------------------------------------------
1412
1495
// Options that are set on the command line become system properties
1413
1496
// and therefore are set in the session properties. System properties
1414
1497
// are most dominant.
1415
1498
// ----------------------------------------------------------------------
1416
1499
1417
- if (commandLine .hasOption (CLIManager .SET_USER_PROPERTY )) {
1418
- String [] defStrs = commandLine .getOptionValues (CLIManager .SET_USER_PROPERTY );
1500
+ Properties cliProperties = new Properties ();
1501
+ if (cliRequest .commandLine .hasOption (CLIManager .SET_USER_PROPERTY )) {
1502
+ String [] defStrs = cliRequest .commandLine .getOptionValues (CLIManager .SET_USER_PROPERTY );
1419
1503
1420
1504
if (defStrs != null ) {
1421
- for (String defStr : defStrs ) {
1422
- setCliProperty (defStr , userProperties );
1505
+ String name ;
1506
+ String value ;
1507
+ for (String property : defStrs ) {
1508
+ int i = property .indexOf ('=' );
1509
+ if (i <= 0 ) {
1510
+ name = property .trim ();
1511
+ value = "true" ;
1512
+ } else {
1513
+ name = property .substring (0 , i ).trim ();
1514
+ value = property .substring (i + 1 );
1515
+ }
1516
+ cliProperties .setProperty (name , value );
1423
1517
}
1424
1518
}
1425
1519
}
1426
1520
1521
+ EnvironmentUtils .addEnvVars (systemProperties );
1427
1522
SystemProperties .addSystemProperties (systemProperties );
1428
1523
1524
+ StringSearchInterpolator interpolator = createInterpolator (cliRequest , cliProperties , systemProperties );
1525
+ for (Map .Entry <Object , Object > e : cliProperties .entrySet ()) {
1526
+ String name = (String ) e .getKey ();
1527
+ String value = interpolator .interpolate ((String ) e .getValue ());
1528
+ userProperties .setProperty (name , value );
1529
+ }
1530
+
1531
+ systemProperties .putAll (userProperties );
1532
+
1533
+ // ----------------------------------------------------------------------
1534
+ // I'm leaving the setting of system properties here as not to break
1535
+ // the SystemPropertyProfileActivator. This won't harm embedding. jvz.
1536
+ // ----------------------------------------------------------------------
1537
+ userProperties .forEach ((k , v ) -> System .setProperty ((String ) k , (String ) v ));
1538
+
1429
1539
// ----------------------------------------------------------------------
1430
1540
// Properties containing info about the currently running version of Maven
1431
1541
// These override any corresponding properties set on the command line
@@ -1440,31 +1550,56 @@ static void populateProperties(CommandLine commandLine, Properties systemPropert
1440
1550
systemProperties .setProperty ("maven.build.version" , mavenBuildVersion );
1441
1551
}
1442
1552
<
F438
/td>1443
- private static void setCliProperty (String property , Properties properties ) {
1444
- String name ;
1445
-
1446
- String value ;
1447
-
1448
- int i = property .indexOf ('=' );
1449
-
1450
- if (i <= 0 ) {
1451
- name = property .trim ();
1452
-
1453
- value = "true" ;
1454
- } else {
1455
- name = property .substring (0 , i ).trim ();
1553
+ protected boolean isAcceptableRootDirectory (Path path ) {
1554
+ return path != null && Files .isDirectory (path .resolve (DOT_MVN ));
1555
+ }
1456
1556
1457
- value = property .substring (i + 1 );
1557
+ protected Path searchAcceptableRootDirectory (Path path ) {
1558
+ if (path == null ) {
1559
+ return null ;
1458
1560
}
1561
+ if (isAcceptableRootDirectory (path )) {
1562
+ return path ;
1563
+ }
1564
+ return searchAcceptableRootDirectory (path .getParent ());
1565
+ }
1459
1566
1460
- properties .setProperty (name , value );
1461
-
1462
- // ----------------------------------------------------------------------
1463
- // I'm leaving the setting of system properties here as not to break
1464
- // the SystemPropertyProfileActivator. This won't harm embedding. jvz.
1465
- // ----------------------------------------------------------------------
1466
-
1467
- System .setProperty (name , value );
1567
+ protected static StringSearchInterpolator createInterpolator (CliRequest cliRequest , Properties ... properties ) {
1568
+ StringSearchInterpolator interpolator = new StringSearchInterpolator ();
1569
+ interpolator .addValueSource (new AbstractValueSource (false ) {
1570
+ @ Override
1571
+ public Object getValue (String expression ) {
1572
+ if ("session.topDirectory" .equals (expression )) {
1573
+ Path topDirectory = cliRequest .topDirectory ;
1574
+ if (topDirectory != null ) {
1575
+ return topDirectory .toString ();
1576
+ } else {
1577
+ throw new IllegalUseOfUndefinedProperty (expression );
1578
+ }
1579
+ } else if ("session.rootDirectory" .equals (expression )) {
1580
+ Path rootDirectory = cliRequest .rootDirectory ;
1581
+ if (rootDirectory != null ) {
1582
+ return rootDirectory .toString ();
1583
+ } else {
1584
+ throw new IllegalUseOfUndefinedProperty (expression );
1585
+ }
1586
+ }
1587
+ return null ;
1588
+ }
1589
+ });
1590
+ interpolator .addValueSource (new AbstractValueSource (false ) {
1591
+ @ Override
1592
+ public Object getValue (String expression ) {
1593
+ for (Properties props : properties ) {
1594
+ Object val = props .getProperty (expression );
1595
+ if (val != null ) {
1596
+ return val ;
1597
+ }
1598
+ }
1599
+ return null ;
1600
+ }
1601
+ });
1602
+ return interpolator ;
1468
1603
}
1469
1604
1470
1605
static class ExitException extends Exception {
@@ -1475,6 +1610,14 @@ static class ExitException extends Exception {
1475
1610
}
1476
1611
}
1477
1612
1613
+ static class IllegalUseOfUndefinedProperty extends IllegalArgumentException {
1614
+ final String property ;
1615
+
1616
+ IllegalUseOfUndefinedProperty (String property ) {
1617
+ this .property = property ;
1618
+ }
1619
+ }
1620
+
1478
1621
//
1479
1622
// Customizations available via the CLI
1480
1623
//
0 commit comments