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