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.executor.internal;
20  
21  import java.io.ByteArrayInputStream;
22  import java.io.ByteArrayOutputStream;
23  import java.io.IOException;
24  import java.util.HashMap;
25  import java.util.Map;
26  import java.util.Properties;
27  import java.util.stream.Collectors;
28  
29  import org.apache.maven.api.cli.ExecutorException;
30  import org.apache.maven.api.cli.ExecutorRequest;
31  import org.apache.maven.cling.executor.ExecutorHelper;
32  import org.apache.maven.cling.executor.ExecutorTool;
33  
34  import static java.util.Objects.requireNonNull;
35  
36  /**
37   * {@link ExecutorTool} implementation based on Maveniverse Toolbox. It uses Toolbox mojos to implement all the
38   * required operations.
39   *
40   * @see <a href="https://github.com/maveniverse/toolbox">Maveniverse Toolbox</a>
41   */
42  public class ToolboxTool implements ExecutorTool {
43      private static final String TOOLBOX = "eu.maveniverse.maven.plugins:toolbox:0.5.2:";
44  
45      private final ExecutorHelper helper;
46  
47      public ToolboxTool(ExecutorHelper helper) {
48          this.helper = requireNonNull(helper);
49      }
50  
51      @Override
52      public Map<String, String> dump(ExecutorRequest.Builder executorRequest) throws ExecutorException {
53          ByteArrayOutputStream stdout = new ByteArrayOutputStream();
54          ByteArrayOutputStream stderr = new ByteArrayOutputStream();
55          ExecutorRequest.Builder builder = mojo(executorRequest, "gav-dump")
56                  .argument("-DasProperties")
57                  .stdoutConsumer(stdout)
58                  .stderrConsumer(stderr);
59          doExecute(builder);
60          try {
61              Properties properties = new Properties();
62              properties.load(new ByteArrayInputStream(stdout.toByteArray()));
63              return properties.entrySet().stream()
64                      .collect(Collectors.toMap(
65                              e -> String.valueOf(e.getKey()),
66                              e -> String.valueOf(e.getValue()),
67                              (prev, next) -> next,
68                              HashMap::new));
69          } catch (IOException e) {
70              throw new ExecutorException("Unable to parse properties", e);
71          }
72      }
73  
74      @Override
75      public String localRepository(ExecutorRequest.Builder executorRequest) throws ExecutorException {
76          ByteArrayOutputStream stdout = new ByteArrayOutputStream();
77          ByteArrayOutputStream stderr = new ByteArrayOutputStream();
78          ExecutorRequest.Builder builder = mojo(executorRequest, "gav-local-repository-path")
79                  .stdoutConsumer(stdout)
80                  .stderrConsumer(stderr);
81          doExecute(builder);
82          return shaveStdout(stdout);
83      }
84  
85      @Override
86      public String artifactPath(ExecutorRequest.Builder executorRequest, String gav, String repositoryId)
87              throws ExecutorException {
88          ByteArrayOutputStream stdout = new ByteArrayOutputStream();
89          ByteArrayOutputStream stderr = new ByteArrayOutputStream();
90          ExecutorRequest.Builder builder = mojo(executorRequest, "gav-artifact-path")
91                  .argument("-Dgav=" + gav)
92                  .stdoutConsumer(stdout)
93                  .stderrConsumer(stderr);
94          if (repositoryId != null) {
95              builder.argument("-Drepository=" + repositoryId + "::unimportant");
96          }
97          doExecute(builder);
98          return shaveStdout(stdout);
99      }
100 
101     @Override
102     public String metadataPath(ExecutorRequest.Builder executorRequest, String gav, String repositoryId)
103             throws ExecutorException {
104         ByteArrayOutputStream stdout = new ByteArrayOutputStream();
105         ByteArrayOutputStream stderr = new ByteArrayOutputStream();
106         ExecutorRequest.Builder builder = mojo(executorRequest, "gav-metadata-path")
107                 .argument("-Dgav=" + gav)
108                 .stdoutConsumer(stdout)
109                 .stderrConsumer(stderr);
110         if (repositoryId != null) {
111             builder.argument("-Drepository=" + repositoryId + "::unimportant");
112         }
113         doExecute(builder);
114         return shaveStdout(stdout);
115     }
116 
117     private ExecutorRequest.Builder mojo(ExecutorRequest.Builder builder, String mojo) {
118         if (helper.mavenVersion().startsWith("4.")) {
119             builder.argument("--raw-streams");
120         }
121         return builder.argument(TOOLBOX + mojo).argument("--quiet").argument("-DforceStdout");
122     }
123 
124     private void doExecute(ExecutorRequest.Builder builder) {
125         ExecutorRequest request = builder.build();
126         int ec = helper.execute(request);
127         if (ec != 0) {
128             throw new ExecutorException("Unexpected exit code=" + ec + "; stdout="
129                     + request.stdoutConsumer().orElse(null) + "; stderr="
130                     + request.stderrConsumer().orElse(null));
131         }
132     }
133 
134     private String shaveStdout(ByteArrayOutputStream stdout) {
135         return stdout.toString().replace("\n", "").replace("\r", "");
136     }
137 }