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.cling.invoker.mvn;
20  
21  import java.util.Arrays;
22  import java.util.Collection;
23  import java.util.List;
24  import java.util.ListIterator;
25  import java.util.Map;
26  import java.util.Optional;
27  
28  import org.apache.commons.cli.CommandLine;
29  import org.apache.commons.cli.Option;
30  import org.apache.commons.cli.ParseException;
31  import org.apache.maven.api.cli.mvn.MavenOptions;
32  import org.apache.maven.cling.invoker.CommonsCliOptions;
33  import org.codehaus.plexus.interpolation.BasicInterpolator;
34  import org.codehaus.plexus.interpolation.InterpolationException;
35  
36  import static org.apache.maven.cling.invoker.Utils.createInterpolator;
37  
38  public class CommonsCliMavenOptions extends CommonsCliOptions implements MavenOptions {
39      public static CommonsCliMavenOptions parse(String source, String[] args) throws ParseException {
40          CLIManager cliManager = new CLIManager();
41          return new CommonsCliMavenOptions(source, cliManager, cliManager.parse(args));
42      }
43  
44      protected CommonsCliMavenOptions(String source, CLIManager cliManager, CommandLine commandLine) {
45          super(source, cliManager, commandLine);
46      }
47  
48      private static CommonsCliMavenOptions interpolate(
49              CommonsCliMavenOptions options, Collection<Map<String, String>> properties) {
50          try {
51              // now that we have properties, interpolate all arguments
52              BasicInterpolator interpolator = createInterpolator(properties);
53              CommandLine.Builder commandLineBuilder = new CommandLine.Builder();
54              commandLineBuilder.setDeprecatedHandler(o -> {});
55              for (Option option : options.commandLine.getOptions()) {
56                  if (!CLIManager.USER_PROPERTY.equals(option.getOpt())) {
57                      List<String> values = option.getValuesList();
58                      for (ListIterator<String> it = values.listIterator(); it.hasNext(); ) {
59                          it.set(interpolator.interpolate(it.next()));
60                      }
61                  }
62                  commandLineBuilder.addOption(option);
63              }
64              for (String arg : options.commandLine.getArgList()) {
65                  commandLineBuilder.addArg(interpolator.interpolate(arg));
66              }
67              return new CommonsCliMavenOptions(
68                      options.source, (CLIManager) options.cliManager, commandLineBuilder.build());
69          } catch (InterpolationException e) {
70              throw new IllegalArgumentException("Could not interpolate CommonsCliOptions", e);
71          }
72      }
73  
74      @Override
75      public Optional<String> alternatePomFile() {
76          if (commandLine.hasOption(CLIManager.ALTERNATE_POM_FILE)) {
77              return Optional.of(commandLine.getOptionValue(CLIManager.ALTERNATE_POM_FILE));
78          }
79          return Optional.empty();
80      }
81  
82      @Override
83      public Optional<Boolean> offline() {
84          if (commandLine.hasOption(CLIManager.OFFLINE)) {
85              return Optional.of(Boolean.TRUE);
86          }
87          return Optional.empty();
88      }
89  
90      @Override
91      public Optional<Boolean> nonRecursive() {
92          if (commandLine.hasOption(CLIManager.NON_RECURSIVE)) {
93              return Optional.of(Boolean.TRUE);
94          }
95          return Optional.empty();
96      }
97  
98      @Override
99      public Optional<Boolean> updateSnapshots() {
100         if (commandLine.hasOption(CLIManager.UPDATE_SNAPSHOTS)) {
101             return Optional.of(Boolean.TRUE);
102         }
103         return Optional.empty();
104     }
105 
106     @Override
107     public Optional<List<String>> activatedProfiles() {
108         if (commandLine.hasOption(CLIManager.ACTIVATE_PROFILES)) {
109             return Optional.of(Arrays.asList(commandLine.getOptionValues(CLIManager.ACTIVATE_PROFILES)));
110         }
111         return Optional.empty();
112     }
113 
114     @Override
115     public Optional<Boolean> suppressSnapshotUpdates() {
116         if (commandLine.hasOption(CLIManager.SUPPRESS_SNAPSHOT_UPDATES)) {
117             return Optional.of(Boolean.TRUE);
118         }
119         return Optional.empty();
120     }
121 
122     @Override
123     public Optional<Boolean> strictChecksums() {
124         if (commandLine.hasOption(CLIManager.CHECKSUM_FAILURE_POLICY)) {
125             return Optional.of(Boolean.TRUE);
126         }
127         return Optional.empty();
128     }
129 
130     @Override
131     public Optional<Boolean> relaxedChecksums() {
132         if (commandLine.hasOption(CLIManager.CHECKSUM_WARNING_POLICY)) {
133             return Optional.of(Boolean.TRUE);
134         }
135         return Optional.empty();
136     }
137 
138     @Override
139     public Optional<Boolean> failFast() {
140         if (commandLine.hasOption(CLIManager.FAIL_FAST)) {
141             return Optional.of(Boolean.TRUE);
142         }
143         return Optional.empty();
144     }
145 
146     @Override
147     public Optional<Boolean> failAtEnd() {
148         if (commandLine.hasOption(CLIManager.FAIL_AT_END)) {
149             return Optional.of(Boolean.TRUE);
150         }
151         return Optional.empty();
152     }
153 
154     @Override
155     public Optional<Boolean> failNever() {
156         if (commandLine.hasOption(CLIManager.FAIL_NEVER)) {
157             return Optional.of(Boolean.TRUE);
158         }
159         return Optional.empty();
160     }
161 
162     @Override
163     public Optional<Boolean> resume() {
164         if (commandLine.hasOption(CLIManager.RESUME)) {
165             return Optional.of(Boolean.TRUE);
166         }
167         return Optional.empty();
168     }
169 
170     @Override
171     public Optional<String> resumeFrom() {
172         if (commandLine.hasOption(CLIManager.RESUME_FROM)) {
173             return Optional.of(commandLine.getOptionValue(CLIManager.RESUME_FROM));
174         }
175         return Optional.empty();
176     }
177 
178     @Override
179     public Optional<List<String>> projects() {
180         if (commandLine.hasOption(CLIManager.PROJECT_LIST)) {
181             return Optional.of(Arrays.asList(commandLine.getOptionValues(CLIManager.PROJECT_LIST)));
182         }
183         return Optional.empty();
184     }
185 
186     @Override
187     public Optional<Boolean> alsoMake() {
188         if (commandLine.hasOption(CLIManager.ALSO_MAKE)) {
189             return Optional.of(Boolean.TRUE);
190         }
191         return Optional.empty();
192     }
193 
194     @Override
195     public Optional<Boolean> alsoMakeDependents() {
196         if (commandLine.hasOption(CLIManager.ALSO_MAKE_DEPENDENTS)) {
197             return Optional.of(Boolean.TRUE);
198         }
199         return Optional.empty();
200     }
201 
202     @Override
203     public Optional<String> threads() {
204         if (commandLine.hasOption(CLIManager.THREADS)) {
205             return Optional.of(commandLine.getOptionValue(CLIManager.THREADS));
206         }
207         return Optional.empty();
208     }
209 
210     @Override
211     public Optional<String> builder() {
212         if (commandLine.hasOption(CLIManager.BUILDER)) {
213             return Optional.of(commandLine.getOptionValue(CLIManager.BUILDER));
214         }
215         return Optional.empty();
216     }
217 
218     @Override
219     public Optional<Boolean> noTransferProgress() {
220         if (commandLine.hasOption(CLIManager.NO_TRANSFER_PROGRESS)) {
221             return Optional.of(Boolean.TRUE);
222         }
223         return Optional.empty();
224     }
225 
226     @Override
227     public Optional<Boolean> cacheArtifactNotFound() {
228         if (commandLine.hasOption(CLIManager.CACHE_ARTIFACT_NOT_FOUND)) {
229             return Optional.of(Boolean.parseBoolean(commandLine.getOptionValue(CLIManager.CACHE_ARTIFACT_NOT_FOUND)));
230         }
231         return Optional.empty();
232     }
233 
234     @Override
235     public Optional<Boolean> strictArtifactDescriptorPolicy() {
236         if (commandLine.hasOption(CLIManager.STRICT_ARTIFACT_DESCRIPTOR_POLICY)) {
237             return Optional.of(
238                     Boolean.parseBoolean(commandLine.getOptionValue(CLIManager.STRICT_ARTIFACT_DESCRIPTOR_POLICY)));
239         }
240         return Optional.empty();
241     }
242 
243     @Override
244     public Optional<Boolean> ignoreTransitiveRepositories() {
245         if (commandLine.hasOption(CLIManager.IGNORE_TRANSITIVE_REPOSITORIES)) {
246             return Optional.of(Boolean.TRUE);
247         }
248         return Optional.empty();
249     }
250 
251     @Override
252     public Optional<List<String>> goals() {
253         if (!commandLine.getArgList().isEmpty()) {
254             return Optional.of(commandLine.getArgList());
255         }
256         return Optional.empty();
257     }
258 
259     @Override
260     public MavenOptions interpolate(Collection<Map<String, String>> properties) {
261         return interpolate(this, properties);
262     }
263 
264     protected static class CLIManager extends CommonsCliOptions.CLIManager {
265         public static final String ALTERNATE_POM_FILE = "f";
266         public static final String OFFLINE = "o";
267         public static final String NON_RECURSIVE = "N";
268         public static final String UPDATE_SNAPSHOTS = "U";
269         public static final String ACTIVATE_PROFILES = "P";
270         public static final String SUPPRESS_SNAPSHOT_UPDATES = "nsu";
271         public static final String CHECKSUM_FAILURE_POLICY = "C";
272         public static final String CHECKSUM_WARNING_POLICY = "c";
273         public static final String FAIL_FAST = "ff";
274         public static final String FAIL_ON_SEVERITY = "fos";
275         public static final String FAIL_AT_END = "fae";
276         public static final String FAIL_NEVER = "fn";
277         public static final String RESUME = "r";
278         public static final String RESUME_FROM = "rf";
279         public static final String PROJECT_LIST = "pl";
280         public static final String ALSO_MAKE = "am";
281         public static final String ALSO_MAKE_DEPENDENTS = "amd";
282         public static final String THREADS = "T";
283         public static final String BUILDER = "b";
284         public static final String NO_TRANSFER_PROGRESS = "ntp";
285         public static final String CACHE_ARTIFACT_NOT_FOUND = "canf";
286         public static final String STRICT_ARTIFACT_DESCRIPTOR_POLICY = "sadp";
287         public static final String IGNORE_TRANSITIVE_REPOSITORIES = "itr";
288 
289         @Override
290         protected void prepareOptions(org.apache.commons.cli.Options options) {
291             super.prepareOptions(options);
292             options.addOption(Option.builder(ALTERNATE_POM_FILE)
293                     .longOpt("file")
294                     .hasArg()
295                     .desc("Force the use of an alternate POM file (or directory with pom.xml)")
296                     .build());
297             options.addOption(Option.builder(OFFLINE)
298                     .longOpt("offline")
299                     .desc("Work offline")
300                     .build());
301             options.addOption(Option.builder(NON_RECURSIVE)
302                     .longOpt("non-recursive")
303                     .desc(
304                             "Do not recurse into sub-projects. When used together with -pl, do not recurse into sub-projects of selected aggregators")
305                     .build());
306             options.addOption(Option.builder(UPDATE_SNAPSHOTS)
307                     .longOpt("update-snapshots")
308                     .desc("Forces a check for missing releases and updated snapshots on remote repositories")
309                     .build());
310             options.addOption(Option.builder(ACTIVATE_PROFILES)
311                     .longOpt("activate-profiles")
312                     .desc(
313                             "Comma-delimited list of profiles to activate. Prefixing a profile with ! excludes it, and ? marks it as optional")
314                     .hasArg()
315                     .build());
316             options.addOption(Option.builder(SUPPRESS_SNAPSHOT_UPDATES)
317                     .longOpt("no-snapshot-updates")
318                     .desc("Suppress SNAPSHOT updates")
319                     .build());
320             options.addOption(Option.builder(CHECKSUM_FAILURE_POLICY)
321                     .longOpt("strict-checksums")
322                     .desc("Fail the build if checksums don't match")
323                     .build());
324             options.addOption(Option.builder(CHECKSUM_WARNING_POLICY)
325                     .longOpt("lax-checksums")
326                     .desc("Warn if checksums don't match")
327                     .build());
328             options.addOption(Option.builder(FAIL_FAST)
329                     .longOpt("fail-fast")
330                     .desc("Stop at first failure in reactorized builds")
331                     .build());
332             options.addOption(Option.builder(FAIL_AT_END)
333                     .longOpt("fail-at-end")
334                     .desc("Only fail the build afterwards; allow all non-impacted builds to continue")
335                     .build());
336             options.addOption(Option.builder(FAIL_NEVER)
337                     .longOpt("fail-never")
338                     .desc("NEVER fail the build, regardless of project result")
339                     .build());
340             options.addOption(Option.builder(RESUME)
341                     .longOpt("resume")
342                     .desc(
343                             "Resume reactor from the last failed project, using the resume.properties file in the build directory")
344                     .build());
345             options.addOption(Option.builder(RESUME_FROM)
346                     .longOpt("resume-from")
347                     .hasArg()
348                     .desc("Resume reactor from specified project")
349                     .build());
350             options.addOption(Option.builder(PROJECT_LIST)
351                     .longOpt("projects")
352                     .desc(
353                             "Comma-delimited list of specified reactor projects to build instead of all projects. A project can be specified by [groupId]:artifactId or by its relative path. Prefixing a project with ! excludes it, and ? marks it as optional")
354                     .hasArg()
355                     .build());
356             options.addOption(Option.builder(ALSO_MAKE)
357                     .longOpt("also-make")
358                     .desc("If project list is specified, also build projects required by the list")
359                     .build());
360             options.addOption(Option.builder(ALSO_MAKE_DEPENDENTS)
361                     .longOpt("also-make-dependents")
362                     .desc("If project list is specified, also build projects that depend on projects on the list")
363                     .build());
364             options.addOption(Option.builder(THREADS)
365                     .longOpt("threads")
366                     .hasArg()
367                     .desc("Thread count, for instance 4 (int) or 2C/2.5C (int/float) where C is core multiplied")
368                     .build());
369             options.addOption(Option.builder(BUILDER)
370                     .longOpt("builder")
371                     .hasArg()
372                     .desc("The id of the build strategy to use")
373                     .build());
374             options.addOption(Option.builder(NO_TRANSFER_PROGRESS)
375                     .longOpt("no-transfer-progress")
376                     .desc("Do not display transfer progress when downloading or uploading")
377                     .build());
378             options.addOption(Option.builder(CACHE_ARTIFACT_NOT_FOUND)
379                     .longOpt("cache-artifact-not-found")
380                     .hasArg()
381                     .desc(
382                             "Defines caching behaviour for 'not found' artifacts. Supported values are 'true' (default), 'false'.")
383                     .build());
384             options.addOption(Option.builder(STRICT_ARTIFACT_DESCRIPTOR_POLICY)
385                     .longOpt("strict-artifact-descriptor-policy")
386                     .hasArg()
387                     .desc(
388                             "Defines 'strict' artifact descriptor policy. Supported values are 'true', 'false' (default).")
389                     .build());
390             options.addOption(Option.builder(IGNORE_TRANSITIVE_REPOSITORIES)
391                     .longOpt("ignore-transitive-repositories")
392                     .desc("If set, Maven will ignore remote repositories introduced by transitive dependencies.")
393                     .build());
394         }
395     }
396 }