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.IOException;
22  import java.nio.file.Path;
23  import java.nio.file.Paths;
24  import java.util.ArrayList;
25  import java.util.List;
26  import java.util.Optional;
27  
28  import org.apache.maven.api.annotations.Experimental;
29  import org.apache.maven.api.annotations.Immutable;
30  import org.apache.maven.api.annotations.Nonnull;
31  import org.apache.maven.api.annotations.Nullable;
32  
33  import static java.util.Objects.requireNonNull;
34  
35  /**
36   * Represents a request to execute Maven with command-line arguments.
37   * This interface encapsulates all the necessary information needed to execute
38   * Maven command with arguments. The arguments were not parsed, they are just passed over
39   * to executed tool.
40   *
41   * @since 4.0.0
42   */
43  @Immutable
44  @Experimental
45  public interface ExecutorRequest {
46      /**
47       * The command to execute, ie "mvn".
48       */
49      @Nonnull
50      String command();
51  
52      /**
53       * The immutable list of arguments to pass to the command.
54       */
55      @Nonnull
56      List<String> arguments();
57  
58      /**
59       * Returns the current working directory for the Maven execution.
60       * This is typically the directory from which Maven was invoked.
61       *
62       * @return the current working directory path
63       */
64      @Nonnull
65      Path cwd();
66  
67      /**
68       * Returns the Maven installation directory.
69       * This is usually set by the Maven launcher script using the "maven.home" system property.
70       *
71       * @return the Maven installation directory path
72       */
73      @Nonnull
74      Path installationDirectory();
75  
76      /**
77       * Returns the user's home directory.
78       * This is typically obtained from the "user.home" system property.
79       *
80       * @return the user's home directory path
81       */
82      @Nonnull
83      Path userHomeDirectory();
84  
85      /**
86       * Returns the list of extra JVM arguments to be passed to the forked process.
87       * These arguments allow for customization of the JVM environment in which tool will run.
88       * This property is used ONLY by executors and invokers that spawn a new JVM.
89       *
90       * @return an Optional containing the list of extra JVM arguments, or empty if not specified
91       */
92      @Nonnull
93      Optional<List<String>> jvmArguments();
94  
95      /**
96       * Returns {@link Builder} for this instance.
97       */
98      @Nonnull
99      default Builder toBuilder() {
100         return new Builder(
101                 command(),
102                 arguments(),
103                 cwd(),
104                 installationDirectory(),
105                 userHomeDirectory(),
106                 jvmArguments().orElse(null));
107     }
108 
109     /**
110      * Returns new empty builder.
111      */
112     @Nonnull
113     static Builder empyBuilder() {
114         return new Builder();
115     }
116 
117     /**
118      * Returns new builder pre-set to run Maven. The discovery of maven home is attempted.
119      */
120     @Nonnull
121     static Builder mavenBuilder(@Nullable Path installationDirectory) {
122         return new Builder(
123                 "mvn",
124                 null,
125                 getCanonicalPath(Paths.get(System.getProperty("user.dir"))),
126                 installationDirectory != null ? getCanonicalPath(installationDirectory) : discoverMavenHome(),
127                 getCanonicalPath(Paths.get(System.getProperty("user.home"))),
128                 null);
129     }
130 
131     class Builder {
132         private String command;
133         private List<String> arguments;
134         private Path cwd;
135         private Path installationDirectory;
136         private Path userHomeDirectory;
137         private List<String> jvmArguments;
138 
139         private Builder() {}
140 
141         private Builder(
142                 String command,
143                 List<String> arguments,
144                 Path cwd,
145                 Path installationDirectory,
146                 Path userHomeDirectory,
147                 List<String> jvmArguments) {
148             this.command = command;
149             this.arguments = arguments;
150             this.cwd = cwd;
151             this.installationDirectory = installationDirectory;
152             this.userHomeDirectory = userHomeDirectory;
153             this.jvmArguments = jvmArguments;
154         }
155 
156         @Nonnull
157         public Builder command(String command) {
158             this.command = requireNonNull(command, "command");
159             return this;
160         }
161 
162         @Nonnull
163         public Builder arguments(List<String> arguments) {
164             this.arguments = requireNonNull(arguments, "arguments");
165             return this;
166         }
167 
168         @Nonnull
169         public Builder argument(String argument) {
170             if (arguments == null) {
171                 arguments = new ArrayList<>();
172             }
173             this.arguments.add(requireNonNull(argument, "argument"));
174             return this;
175         }
176 
177         @Nonnull
178         public Builder cwd(Path cwd) {
179             this.cwd = requireNonNull(cwd, "cwd");
180             return this;
181         }
182 
183         @Nonnull
184         public Builder installationDirectory(Path installationDirectory) {
185             this.installationDirectory = requireNonNull(installationDirectory, "installationDirectory");
186             return this;
187         }
188 
189         @Nonnull
190         public Builder userHomeDirectory(Path userHomeDirectory) {
191             this.userHomeDirectory = requireNonNull(userHomeDirectory, "userHomeDirectory");
192             return this;
193         }
194 
195         @Nonnull
196         public Builder jvmArguments(List<String> jvmArguments) {
197             this.jvmArguments = jvmArguments;
198             return this;
199         }
200 
201         @Nonnull
202         public Builder jvmArgument(String jvmArgument) {
203             if (jvmArguments == null) {
204                 jvmArguments = new ArrayList<>();
205             }
206             this.jvmArguments.add(requireNonNull(jvmArgument, "jvmArgument"));
207             return this;
208         }
209 
210         @Nonnull
211         public ExecutorRequest build() {
212             return new Impl(command, arguments, cwd, installationDirectory, userHomeDirectory, jvmArguments);
213         }
214 
215         private static class Impl implements ExecutorRequest {
216             private final String command;
217             private final List<String> arguments;
218             private final Path cwd;
219             private final Path installationDirectory;
220             private final Path userHomeDirectory;
221             private final List<String> jvmArguments;
222 
223             private Impl(
224                     String command,
225                     List<String> arguments,
226                     Path cwd,
227                     Path installationDirectory,
228                     Path userHomeDirectory,
229                     List<String> jvmArguments) {
230                 this.command = requireNonNull(command);
231                 this.arguments = arguments == null ? List.of() : List.copyOf(arguments);
232                 this.cwd = requireNonNull(cwd);
233                 this.installationDirectory = requireNonNull(installationDirectory);
234                 this.userHomeDirectory = requireNonNull(userHomeDirectory);
235                 this.jvmArguments = jvmArguments != null ? List.copyOf(jvmArguments) : null;
236             }
237 
238             @Override
239             public String command() {
240                 return command;
241             }
242 
243             @Override
244             public List<String> arguments() {
245                 return arguments;
246             }
247 
248             @Override
249             public Path cwd() {
250                 return cwd;
251             }
252 
253             @Override
254             public Path installationDirectory() {
255                 return installationDirectory;
256             }
257 
258             @Override
259             public Path userHomeDirectory() {
260                 return userHomeDirectory;
261             }
262 
263             @Override
264             public Optional<List<String>> jvmArguments() {
265                 return Optional.ofNullable(jvmArguments);
266             }
267 
268             @Override
269             public String toString() {
270                 return "ExecutionRequest{" + "command='"
271                         + command + '\'' + ", arguments="
272                         + arguments + ", cwd="
273                         + cwd + ", installationDirectory="
274                         + installationDirectory + ", userHomeDirectory="
275                         + userHomeDirectory + ", jvmArguments="
276                         + jvmArguments + '}';
277             }
278         }
279     }
280 
281     @Nonnull
282     static Path discoverMavenHome() {
283         String mavenHome = System.getProperty("maven.home");
284         if (mavenHome == null) {
285             throw new ExecutorException("requires maven.home Java System Property set");
286         }
287         return getCanonicalPath(Paths.get(mavenHome));
288     }
289 
290     @Nonnull
291     static Path getCanonicalPath(Path path) {
292         requireNonNull(path, "path");
293         try {
294             return path.toRealPath();
295         } catch (IOException e) {
296             return getCanonicalPath(path.getParent()).resolve(path.getFileName());
297         }
298     }
299 }