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.api.cli;
20  
21  import java.io.InputStream;
22  import java.io.OutputStream;
23  import java.nio.file.Path;
24  import java.util.Arrays;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.Optional;
28  
29  import org.apache.maven.api.annotations.Experimental;
30  import org.apache.maven.api.annotations.Immutable;
31  import org.apache.maven.api.annotations.Nonnull;
32  import org.apache.maven.api.annotations.Nullable;
33  import org.apache.maven.api.services.Lookup;
34  import org.apache.maven.api.services.LookupException;
35  import org.apache.maven.api.services.MessageBuilderFactory;
36  
37  import static java.util.Objects.requireNonNull;
38  
39  /**
40   * Represents a request to parse Maven command-line arguments.
41   * This interface encapsulates all the necessary information needed to parse
42   * Maven commands and arguments into an {@link InvokerRequest}.
43   *
44   * @since 4.0.0
45   */
46  @Immutable
47  @Experimental
48  public interface ParserRequest {
49      /**
50       * Returns the Maven command to be executed. This command is used in some invokers (ie forked) but also to
51       * present help to user.
52       *
53       * @return the command string
54       */
55      @Nonnull
56      String command();
57  
58      /**
59       * Returns the Maven command name (ie "Maven"). This string is used in some invokers to complete error messages.
60       *
61       * @return the command (human) name
62       */
63      @Nonnull
64      String commandName();
65  
66      /**
67       * Returns the logger to be used during the parsing process.
68       *
69       * @return the logger instance
70       */
71      @Nonnull
72      Logger logger();
73  
74      /**
75       * Returns the factory for creating message builders.
76       *
77       * @return the message builder factory
78       */
79      @Nonnull
80      MessageBuilderFactory messageBuilderFactory();
81  
82      /**
83       * Returns the command-line arguments to be parsed.
84       *
85       * @return a list of argument strings
86       */
87      @Nonnull
88      List<String> args();
89  
90      /**
91       * Per-request {@link Lookup} for customization.
92       *
93       * @return a lookup possibly with custom components
94       */
95      @Nonnull
96      Lookup lookup();
97  
98      /**
99       * Returns the current working directory for the Maven execution.
100      * If not explicitly set, this value will be detected during parsing.
101      *
102      * @return the current working directory path, or null if not set
103      */
104     @Nullable
105     Path cwd();
106 
107     /**
108      * Returns the Maven home directory.
109      * If not explicitly set, this value will be detected during parsing.
110      *
111      * @return the Maven home directory path, or null if not set
112      */
113     @Nullable
114     Path mavenHome();
115 
116     /**
117      * Returns the user's home directory.
118      * If not explicitly set, this value will be detected during parsing.
119      *
120      * @return the user's home directory path, or null if not set
121      */
122     @Nullable
123     Path userHome();
124 
125     /**
126      * Returns the input stream to be used for the Maven execution.
127      * If not set, System.in will be used by default.
128      *
129      * @return the input stream, or null if not set
130      */
131     @Nullable
132     InputStream in();
133 
134     /**
135      * Returns the output stream to be used for the Maven execution.
136      * If not set, System.out will be used by default.
137      *
138      * @return the output stream, or null if not set
139      */
140     @Nullable
141     OutputStream out();
142 
143     /**
144      * Returns the error stream to be used for the Maven execution.
145      * If not set, System.err will be used by default.
146      *
147      * @return the error stream, or null if not set
148      */
149     @Nullable
150     OutputStream err();
151 
152     /**
153      * Creates a new Builder instance for constructing a Maven ParserRequest.
154      *
155      * @param args the command-line arguments
156      * @param logger the logger to be used during parsing
157      * @param messageBuilderFactory the factory for creating message builders
158      * @return a new Builder instance
159      */
160     @Nonnull
161     static Builder mvn(
162             @Nonnull String[] args, @Nonnull Logger logger, @Nonnull MessageBuilderFactory messageBuilderFactory) {
163         return mvn(Arrays.asList(args), logger, messageBuilderFactory);
164     }
165 
166     /**
167      * Creates a new Builder instance for constructing a Maven ParserRequest.
168      *
169      * @param args the command-line arguments
170      * @param logger the logger to be used during parsing
171      * @param messageBuilderFactory the factory for creating message builders
172      * @return a new Builder instance
173      */
174     @Nonnull
175     static Builder mvn(
176             @Nonnull List<String> args, @Nonnull Logger logger, @Nonnull MessageBuilderFactory messageBuilderFactory) {
177         return builder(Tools.MVN_CMD, Tools.MVN_NAME, args, logger, messageBuilderFactory);
178     }
179 
180     /**
181      * Creates a new Builder instance for constructing a Maven Encrypting Tool ParserRequest.
182      *
183      * @param args the command-line arguments
184      * @param logger the logger to be used during parsing
185      * @param messageBuilderFactory the factory for creating message builders
186      * @return a new Builder instance
187      */
188     @Nonnull
189     static Builder mvnenc(
190             @Nonnull String[] args, @Nonnull Logger logger, @Nonnull MessageBuilderFactory messageBuilderFactory) {
191         return mvnenc(Arrays.asList(args), logger, messageBuilderFactory);
192     }
193 
194     /**
195      * Creates a new Builder instance for constructing a Maven Encrypting Tool ParserRequest.
196      *
197      * @param args the command-line arguments
198      * @param logger the logger to be used during parsing
199      * @param messageBuilderFactory the factory for creating message builders
200      * @return a new Builder instance
201      */
202     @Nonnull
203     static Builder mvnenc(
204             @Nonnull List<String> args, @Nonnull Logger logger, @Nonnull MessageBuilderFactory messageBuilderFactory) {
205         return builder(Tools.MVNENC_CMD, Tools.MVNENC_NAME, args, logger, messageBuilderFactory);
206     }
207 
208     /**
209      * Creates a new Builder instance for constructing a ParserRequest.
210      *
211      * @param command the Maven command to be executed
212      * @param commandName the Maven command Name to be executed
213      * @param args the command-line arguments
214      * @param logger the logger to be used during parsing
215      * @param messageBuilderFactory the factory for creating message builders
216      * @return a new Builder instance
217      */
218     @Nonnull
219     static Builder builder(
220             @Nonnull String command,
221             @Nonnull String commandName,
222             @Nonnull List<String> args,
223             @Nonnull Logger logger,
224             @Nonnull MessageBuilderFactory messageBuilderFactory) {
225         return new Builder(command, commandName, args, logger, messageBuilderFactory);
226     }
227 
228     class Builder {
229         private final String command;
230         private final String commandName;
231         private final List<String> args;
232         private final Logger logger;
233         private final MessageBuilderFactory messageBuilderFactory;
234         private Lookup lookup = EMPTY_LOOKUP;
235         private Path cwd;
236         private Path mavenHome;
237         private Path userHome;
238         private InputStream in;
239         private OutputStream out;
240         private OutputStream err;
241 
242         private Builder(
243                 String command,
244                 String commandName,
245                 List<String> args,
246                 Logger logger,
247                 MessageBuilderFactory messageBuilderFactory) {
248             this.command = requireNonNull(command, "command");
249             this.commandName = requireNonNull(commandName, "commandName");
250             this.args = requireNonNull(args, "args");
251             this.logger = requireNonNull(logger, "logger");
252             this.messageBuilderFactory = requireNonNull(messageBuilderFactory, "messageBuilderFactory");
253         }
254 
255         public Builder lookup(@Nonnull Lookup lookup) {
256             this.lookup = requireNonNull(lookup);
257             return this;
258         }
259 
260         public Builder cwd(Path cwd) {
261             this.cwd = cwd;
262             return this;
263         }
264 
265         public Builder mavenHome(Path mavenHome) {
266             this.mavenHome = mavenHome;
267             return this;
268         }
269 
270         public Builder userHome(Path userHome) {
271             this.userHome = userHome;
272             return this;
273         }
274 
275         public Builder in(InputStream in) {
276             this.in = in;
277             return this;
278         }
279 
280         public Builder out(OutputStream out) {
281             this.out = out;
282             return this;
283         }
284 
285         public Builder err(OutputStream err) {
286             this.err = err;
287             return this;
288         }
289 
290         public ParserRequest build() {
291             return new ParserRequestImpl(
292                     command,
293                     commandName,
294                     args,
295                     logger,
296                     messageBuilderFactory,
297                     lookup,
298                     cwd,
299                     mavenHome,
300                     userHome,
301                     in,
302                     out,
303                     err);
304         }
305 
306         @SuppressWarnings("ParameterNumber")
307         private static class ParserRequestImpl implements ParserRequest {
308             private final String command;
309             private final String commandName;
310             private final Logger logger;
311             private final MessageBuilderFactory messageBuilderFactory;
312             private final List<String> args;
313             private final Lookup lookup;
314             private final Path cwd;
315             private final Path mavenHome;
316             private final Path userHome;
317             private final InputStream in;
318             private final OutputStream out;
319             private final OutputStream err;
320 
321             private ParserRequestImpl(
322                     String command,
323                     String commandName,
324                     List<String> args,
325                     Logger logger,
326                     MessageBuilderFactory messageBuilderFactory,
327                     Lookup lookup,
328                     Path cwd,
329                     Path mavenHome,
330                     Path userHome,
331                     InputStream in,
332                     OutputStream out,
333                     OutputStream err) {
334                 this.command = requireNonNull(command, "command");
335                 this.commandName = requireNonNull(commandName, "commandName");
336                 this.args = List.copyOf(requireNonNull(args, "args"));
337                 this.logger = requireNonNull(logger, "logger");
338                 this.messageBuilderFactory = requireNonNull(messageBuilderFactory, "messageBuilderFactory");
339                 this.lookup = requireNonNull(lookup, "lookup");
340                 this.cwd = cwd;
341                 this.mavenHome = mavenHome;
342                 this.userHome = userHome;
343                 this.in = in;
344                 this.out = out;
345                 this.err = err;
346             }
347 
348             @Override
349             public String command() {
350                 return command;
351             }
352 
353             @Override
354             public String commandName() {
355                 return commandName;
356             }
357 
358             @Override
359             public Logger logger() {
360                 return logger;
361             }
362 
363             @Override
364             public MessageBuilderFactory messageBuilderFactory() {
365                 return messageBuilderFactory;
366             }
367 
368             @Override
369             public List<String> args() {
370                 return args;
371             }
372 
373             @Override
374             public Lookup lookup() {
375                 return lookup;
376             }
377 
378             @Override
379             public Path cwd() {
380                 return cwd;
381             }
382 
383             @Override
384             public Path mavenHome() {
385                 return mavenHome;
386             }
387 
388             @Override
389             public Path userHome() {
390                 return userHome;
391             }
392 
393             @Override
394             public InputStream in() {
395                 return in;
396             }
397 
398             @Override
399             public OutputStream out() {
400                 return out;
401             }
402 
403             @Override
404             public OutputStream err() {
405                 return err;
406             }
407         }
408 
409         private static final Lookup EMPTY_LOOKUP = new Lookup() {
410             @Override
411             public <T> T lookup(Class<T> type) {
412                 throw new LookupException("empty lookup");
413             }
414 
415             @Override
416             public <T> T lookup(Class<T> type, String name) {
417                 throw new LookupException("empty lookup");
418             }
419 
420             @Override
421             public <T> Optional<T> lookupOptional(Class<T> type) {
422                 return Optional.empty();
423             }
424 
425             @Override
426             public <T> Optional<T> lookupOptional(Class<T> type, String name) {
427                 return Optional.empty();
428             }
429 
430             @Override
431             public <T> List<T> lookupList(Class<T> type) {
432                 return List.of();
433             }
434 
435             @Override
436             public <T> Map<String, T> lookupMap(Class<T> type) {
437                 return Map.of();
438             }
439         };
440     }
441 }