|
15 | 15 | */ |
16 | 16 | package com.diffplug.webtools.node; |
17 | 17 |
|
18 | | -import com.github.eirslett.maven.plugins.frontend.lib.ProxyConfig; |
19 | 18 | import java.io.BufferedReader; |
20 | 19 | import java.io.File; |
21 | 20 | import java.io.IOException; |
| 21 | +import java.io.InputStream; |
22 | 22 | import java.io.InputStreamReader; |
23 | 23 | import java.nio.charset.StandardCharsets; |
24 | 24 | import java.nio.file.Files; |
25 | 25 | import java.util.ArrayList; |
26 | | -import java.util.Collections; |
27 | 26 | import java.util.List; |
28 | 27 | import java.util.Objects; |
29 | 28 | import java.util.TreeMap; |
30 | 29 | import java.util.concurrent.CompletableFuture; |
31 | | -import org.gradle.api.Action; |
32 | | -import org.gradle.api.DefaultTask; |
33 | | -import org.gradle.api.Plugin; |
34 | | -import org.gradle.api.Project; |
| 30 | +import org.gradle.api.*; |
35 | 31 | import org.gradle.api.file.DirectoryProperty; |
36 | 32 | import org.gradle.api.provider.Property; |
37 | 33 | import org.gradle.api.tasks.CacheableTask; |
@@ -99,125 +95,66 @@ public TreeMap<String, String> getEnvironment() { |
99 | 95 | @Internal |
100 | 96 | public abstract DirectoryProperty getProjectDir(); |
101 | 97 |
|
| 98 | + private static CompletableFuture<Void> readStream(InputStream inputStream, List<String> outputLines, String streamName) { |
| 99 | + return CompletableFuture.runAsync(() -> { |
| 100 | + try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { |
| 101 | + String line; |
| 102 | + while ((line = reader.readLine()) != null) { |
| 103 | + synchronized (outputLines) { |
| 104 | + outputLines.add(line); |
| 105 | + } |
| 106 | + } |
| 107 | + } catch (IOException e) { |
| 108 | + synchronized (outputLines) { |
| 109 | + outputLines.add("Error reading " + streamName + ": " + e.getMessage()); |
| 110 | + } |
| 111 | + } |
| 112 | + }); |
| 113 | + } |
| 114 | + |
102 | 115 | @TaskAction |
103 | 116 | public void npmCiRunTask() throws Exception { |
104 | 117 | SetupCleanupNode setup = getSetup().get(); |
105 | 118 | File projectDir = getProjectDir().get().getAsFile(); |
106 | | - |
107 | | - System.out.println("=== NPM Task: " + npmTaskName + " ==="); |
108 | | - System.out.println("Installing Node.js dependencies..."); |
109 | | - |
110 | 119 | // install node, npm, and package-lock.json |
111 | 120 | setup.start(projectDir); |
112 | | - |
113 | | - System.out.println("Running: npm run " + npmTaskName); |
114 | | - if (!environment.isEmpty()) { |
115 | | - System.out.println("Environment variables:"); |
116 | | - environment.forEach((key, value) -> System.out.println(" " + key + "=" + value)); |
| 121 | + |
| 122 | + // Use ProcessBuilder for direct console output instead of NpmRunner |
| 123 | + File installDir = new File(projectDir, "build/node-install"); |
| 124 | + File npmExe; |
| 125 | + if (System.getProperty("os.name").toLowerCase().contains("win")) { |
| 126 | + npmExe = new File(installDir, "node/npm.cmd"); |
| 127 | + } else { |
| 128 | + npmExe = new File(installDir, "node/npm"); |
117 | 129 | } |
118 | | - System.out.println(); |
119 | | - |
120 | | - try { |
121 | | - // Use ProcessBuilder for direct console output instead of NpmRunner |
122 | | - File installDir = new File(projectDir, "build/node-install"); |
123 | | - File npmExe; |
124 | | - |
125 | | - // Based on frontend-maven-plugin structure, npm is directly in the node directory |
126 | | - File nodeExe = new File(installDir, "node/node"); |
127 | | - if (System.getProperty("os.name").toLowerCase().contains("win")) { |
128 | | - nodeExe = new File(installDir, "node/node.exe"); |
129 | | - npmExe = new File(installDir, "node/npm.cmd"); |
130 | | - } else { |
131 | | - npmExe = new File(installDir, "node/npm"); |
132 | | - } |
133 | | - |
134 | | - System.out.println("Using node executable: " + nodeExe.getAbsolutePath()); |
135 | | - System.out.println("Node executable exists: " + nodeExe.exists()); |
136 | | - System.out.println("Using npm executable: " + npmExe.getAbsolutePath()); |
137 | | - System.out.println("NPM executable exists: " + npmExe.exists()); |
138 | | - |
139 | | - ProcessBuilder processBuilder = new ProcessBuilder(npmExe.getAbsolutePath(), "run", npmTaskName); |
140 | | - |
141 | | - processBuilder.directory(projectDir); |
142 | | - processBuilder.environment().putAll(environment); |
143 | | - |
144 | | - Process process = processBuilder.start(); |
145 | | - |
146 | | - // Buffer output to only show on failure |
147 | | - List<String> stdoutLines = new ArrayList<>(); |
148 | | - List<String> stderrLines = new ArrayList<>(); |
149 | | - |
150 | | - // Create threads to read stdout and stderr concurrently |
151 | | - CompletableFuture<Void> stdoutFuture = CompletableFuture.runAsync(() -> { |
152 | | - try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { |
153 | | - String line; |
154 | | - while ((line = reader.readLine()) != null) { |
155 | | - synchronized (stdoutLines) { |
156 | | - stdoutLines.add(line); |
157 | | - } |
158 | | - } |
159 | | - } catch (IOException e) { |
160 | | - synchronized (stdoutLines) { |
161 | | - stdoutLines.add("Error reading stdout: " + e.getMessage()); |
162 | | - } |
163 | | - } |
164 | | - }); |
165 | | - |
166 | | - CompletableFuture<Void> stderrFuture = CompletableFuture.runAsync(() -> { |
167 | | - try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) { |
168 | | - String line; |
169 | | - while ((line = reader.readLine()) != null) { |
170 | | - synchronized (stderrLines) { |
171 | | - stderrLines.add(line); |
172 | | - } |
173 | | - } |
174 | | - } catch (IOException e) { |
175 | | - synchronized (stderrLines) { |
176 | | - stderrLines.add("Error reading stderr: " + e.getMessage()); |
177 | | - } |
178 | | - } |
179 | | - }); |
180 | | - |
181 | | - int exitCode = process.waitFor(); |
182 | | - |
183 | | - // Wait for output streams to finish |
184 | | - CompletableFuture.allOf(stdoutFuture, stderrFuture).join(); |
185 | | - |
186 | | - System.out.println(); |
187 | | - if (exitCode == 0) { |
188 | | - System.out.println("✓ NPM task '" + npmTaskName + "' completed successfully"); |
189 | | - } else { |
190 | | - System.out.println("✗ NPM task '" + npmTaskName + "' failed with exit code " + exitCode); |
191 | | - System.out.println(); |
192 | | - System.out.println("=== NPM OUTPUT ==="); |
193 | | - |
194 | | - // Print stdout if there's any |
195 | | - if (!stdoutLines.isEmpty()) { |
196 | | - System.out.println("STDOUT:"); |
197 | | - for (String line : stdoutLines) { |
198 | | - System.out.println(line); |
199 | | - } |
200 | | - System.out.println(); |
201 | | - } |
202 | | - |
203 | | - // Print stderr if there's any |
204 | | - if (!stderrLines.isEmpty()) { |
205 | | - System.out.println("STDERR:"); |
206 | | - for (String line : stderrLines) { |
207 | | - System.out.println(line); |
208 | | - } |
209 | | - } |
210 | | - |
211 | | - System.out.println("=================="); |
212 | | - throw new RuntimeException("npm run " + npmTaskName + " failed with exit code " + exitCode); |
213 | | - } |
214 | | - } catch (Exception e) { |
215 | | - System.out.println(); |
216 | | - System.out.println("✗ NPM task '" + npmTaskName + "' failed"); |
217 | | - System.out.println("Command: npm run " + npmTaskName); |
218 | | - System.out.println("Error: " + e.getMessage()); |
219 | | - throw e; |
| 130 | + |
| 131 | + ProcessBuilder processBuilder = new ProcessBuilder(npmExe.getAbsolutePath(), "run", npmTaskName); |
| 132 | + processBuilder.directory(projectDir); |
| 133 | + processBuilder.environment().putAll(environment); |
| 134 | + Process process = processBuilder.start(); |
| 135 | + |
| 136 | + // Buffer output to only show on failure |
| 137 | + List<String> stdoutLines = new ArrayList<>(); |
| 138 | + List<String> stderrLines = new ArrayList<>(); |
| 139 | + |
| 140 | + // Create threads to read stdout and stderr concurrently |
| 141 | + CompletableFuture<Void> stdoutFuture = readStream(process.getInputStream(), stdoutLines, "stdout"); |
| 142 | + CompletableFuture<Void> stderrFuture = readStream(process.getErrorStream(), stderrLines, "stderr"); |
| 143 | + int exitCode = process.waitFor(); |
| 144 | + CompletableFuture.allOf(stdoutFuture, stderrFuture).join(); |
| 145 | + if (exitCode == 0) { |
| 146 | + return; |
| 147 | + } |
| 148 | + |
| 149 | + var cmd = new StringBuilder().append("> npm run ").append(npmTaskName).append(" FAILED\n"); |
| 150 | + environment.forEach((key, value) -> cmd.append(" env ").append(key).append("=").append(value).append("\n")); |
| 151 | + for (String line : stdoutLines) { |
| 152 | + cmd.append(line).append("\n"); |
| 153 | + } |
| 154 | + for (String line : stderrLines) { |
| 155 | + cmd.append(line).append("\n"); |
220 | 156 | } |
| 157 | + throw new GradleException(cmd.toString()); |
221 | 158 | } |
222 | 159 | } |
223 | 160 |
|
|
0 commit comments