1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 package org.utgenome.shell;
26
27 import java.io.BufferedInputStream;
28 import java.io.BufferedReader;
29 import java.io.File;
30 import java.io.FileOutputStream;
31 import java.io.FileReader;
32 import java.io.FileWriter;
33 import java.io.IOException;
34 import java.io.InputStream;
35 import java.io.InputStreamReader;
36 import java.net.URL;
37 import java.net.URLConnection;
38 import java.util.Date;
39 import java.util.Map.Entry;
40 import java.util.Properties;
41 import java.util.concurrent.ExecutorService;
42 import java.util.concurrent.Executors;
43 import java.util.concurrent.Future;
44 import java.util.concurrent.TimeUnit;
45
46 import org.apache.tools.bzip2.CBZip2InputStream;
47 import org.apache.tools.tar.TarEntry;
48 import org.apache.tools.tar.TarInputStream;
49 import org.xerial.core.XerialException;
50 import org.xerial.lens.SilkLens;
51 import org.xerial.silk.SilkWriter;
52 import org.xerial.util.FileResource;
53 import org.xerial.util.StringUtil;
54 import org.xerial.util.log.Logger;
55
56
57
58
59
60
61
62 public class Maven extends UTGBShellCommand {
63
64 private static Logger _logger = Logger.getLogger(Maven.class);
65
66 private static String MAVEN_VERSION = "3.0-beta-1";
67
68 public static boolean isMavenInstalled() {
69 String utgbHome = System.getProperty("utgb.home");
70 if (utgbHome == null)
71 return false;
72 else
73 return new File(utgbHome, "maven").exists();
74 }
75
76 private static class MavenArchiveInfo {
77 public long extracted = -1;
78 public String mavenFolder;
79 }
80
81
82
83
84
85
86
87 static String extractMaven() throws IOException {
88
89 final String utgbFolder = System.getProperty("user.home") + "/.utgb";
90 final String mavenFolderName = utgbFolder + "/maven";
91
92 File mavenFolder = new File(mavenFolderName);
93 if (!mavenFolder.exists())
94 mavenFolder.mkdirs();
95
96 MavenArchiveInfo archiveInfo = new MavenArchiveInfo();
97 File mavenArchiveInfoFile = new File(mavenFolderName, "maven-archive.silk");
98 if (mavenArchiveInfoFile.exists()) {
99 try {
100 SilkLens.loadSilk(archiveInfo, new FileReader(mavenArchiveInfoFile));
101 }
102 catch (XerialException e) {
103 _logger.error(e);
104 }
105 }
106
107 String mavenBinParentFolder = null;
108
109 URL mavenArchive = FileResource.find("org.utgenome.shell.archive", "apache-maven-" + MAVEN_VERSION + "-bin.tar.bz2");
110
111 URLConnection openConnection = mavenArchive.openConnection();
112 long archiveDate = openConnection.getLastModified();
113
114 if (archiveInfo.extracted > archiveDate) {
115 if (archiveInfo.mavenFolder != null) {
116 File mavenFolderWithVersion = new File(mavenFolder, archiveInfo.mavenFolder);
117 if (mavenFolderWithVersion.exists()) {
118 if (new File(mavenFolderWithVersion, "bin/mvn").exists()) {
119 _logger.info("Maven is already installed.");
120
121 return mavenFolderWithVersion.getAbsolutePath();
122 }
123 }
124 }
125 }
126
127 _logger.info("Extracting Maven binaries...");
128
129 String relativePathOfMavenArchiveFolder = null;
130 BufferedInputStream bufferedInputStream = new BufferedInputStream(openConnection.getInputStream());
131 try {
132
133 bufferedInputStream.read();
134 bufferedInputStream.read();
135 TarInputStream tis = new TarInputStream(new CBZip2InputStream(bufferedInputStream));
136 TarEntry nextEntry = null;
137 while ((nextEntry = tis.getNextEntry()) != null) {
138 int mode = nextEntry.getMode();
139 String name = nextEntry.getName();
140 Date modTime = nextEntry.getModTime();
141
142 if (name.endsWith("/bin/mvn")) {
143 relativePathOfMavenArchiveFolder = name.replace("/bin/mvn", "");
144 mavenBinParentFolder = new File(mavenFolderName, relativePathOfMavenArchiveFolder).getAbsolutePath();
145 }
146
147 File extractedFile = new File(mavenFolder, name);
148
149 if (extractedFile.exists() && extractedFile.lastModified() == modTime.getTime())
150 continue;
151
152 if (!nextEntry.isDirectory()) {
153 _logger.info(String.format("extracted %s into %s", name, mavenFolder.getPath()));
154
155 File parent = extractedFile.getParentFile();
156 if (parent != null && !parent.exists())
157 parent.mkdirs();
158
159 FileOutputStream fo = new FileOutputStream(extractedFile);
160 try {
161 tis.copyEntryContents(fo);
162 }
163 finally {
164 fo.close();
165 }
166
167 }
168 else {
169 if (!extractedFile.exists())
170 extractedFile.mkdirs();
171 }
172
173
174 if (!System.getProperty("os.name").contains("Windows")) {
175 try {
176 int m = mode & 00777;
177 String modeStr = Integer.toOctalString(m);
178 String cmd = String.format("chmod %s %s", modeStr, extractedFile.getAbsolutePath());
179
180 CommandExecutor.exec(String.format(cmd));
181 }
182 catch (Throwable e) {
183 _logger.error(e);
184 }
185 }
186
187 extractedFile.setLastModified(modTime.getTime());
188
189 }
190
191 if (mavenBinParentFolder == null)
192 throw new IllegalStateException("maven binary is not found in the archive");
193 }
194 finally {
195 bufferedInputStream.close();
196 }
197
198
199 archiveInfo.mavenFolder = relativePathOfMavenArchiveFolder;
200 archiveInfo.extracted = new Date().getTime();
201
202 SilkWriter silk = new SilkWriter(new FileWriter(mavenArchiveInfoFile));
203 silk.preamble();
204 silk.node("archive").toSilk(archiveInfo);
205 silk.endDocument();
206 silk.close();
207
208 return mavenBinParentFolder;
209 }
210
211 static String getMavenBinary() {
212
213 String utgbHome = System.getProperty("utgb.home");
214 String osName = System.getProperty("os.name");
215 if (osName == null)
216 throw new IllegalStateException("cannot find out your OS name or os.name JVM property is wrongly set somewhere");
217
218 String mavenStartupScript = (osName.contains("Windows")) ? "mvn.bat" : "mvn";
219
220 if (utgbHome == null) {
221 try {
222 String mavenHome = extractMaven();
223 return new File(mavenHome, "bin/" + mavenStartupScript).getPath();
224 }
225 catch (IOException e) {
226 throw new IllegalStateException("cannot extract Maven binaries: " + e.getMessage());
227 }
228 }
229 else
230 return new File(utgbHome, "maven/bin/" + mavenStartupScript).getPath();
231 }
232
233 public static void runMaven(String arg) throws UTGBShellException {
234 runMaven(arg.split("[\\s]+"));
235 }
236
237 public static void runMaven(String arg, File workingDir) throws UTGBShellException {
238 runMaven(arg.split("[\\s]+"), workingDir);
239
240 }
241
242 public static void runMaven(String[] args) throws UTGBShellException {
243 runMaven(args, null);
244
245 }
246
247 private static abstract class ProcessOutputReader implements Runnable {
248 private final BufferedReader reader;
249
250 public ProcessOutputReader(InputStream in) {
251 reader = new BufferedReader(new InputStreamReader(in));
252 }
253
254 public abstract void output(String line);
255
256 public void run() {
257 try {
258 String line;
259 while ((line = reader.readLine()) != null) {
260 output(line);
261 }
262 }
263 catch (IOException e) {
264
265 _logger.debug(e);
266 }
267 }
268 }
269
270 public static class CommandExecutor {
271 final ExecutorService threadManager = Executors.newFixedThreadPool(2);
272 Process proc = null;
273 Future<?> stdoutReader;
274 Future<?> stderrReader;
275
276 private void dispose() {
277 if (proc != null) {
278 proc.destroy();
279 proc = null;
280 }
281
282 threadManager.shutdown();
283 try {
284 while (!threadManager.awaitTermination(1L, TimeUnit.SECONDS)) {
285 }
286 }
287 catch (InterruptedException e) {
288 _logger.error(e);
289 }
290 }
291
292 public int execCommand(String commandLine, String[] envp, File workingDir) throws IOException {
293 try {
294 if (_logger.isDebugEnabled())
295 _logger.debug(commandLine);
296
297 proc = Runtime.getRuntime().exec(commandLine, envp, workingDir);
298
299
300 stdoutReader = threadManager.submit(new ProcessOutputReader(proc.getInputStream()) {
301 @Override
302 public void output(String line) {
303 _logger.info(line);
304 }
305 });
306 stderrReader = threadManager.submit(new ProcessOutputReader(proc.getErrorStream()) {
307 @Override
308 public void output(String line) {
309 _logger.error(line);
310 }
311 });
312
313 int ret = proc.waitFor();
314 return ret;
315 }
316 catch (InterruptedException e) {
317 _logger.error(e);
318 return 0;
319 }
320 finally {
321 dispose();
322 }
323
324 }
325
326 public static int exec(String commandLine) throws IOException {
327 return exec(commandLine, null, null);
328 }
329
330 public static int exec(String commandLine, String[] envp, File workingDir) throws IOException {
331 CommandExecutor e = new CommandExecutor();
332 return e.execCommand(commandLine, envp, workingDir);
333 }
334
335 }
336
337 public static String[] prepareEnvironmentVariables(File mavenHome) {
338 Properties env = new Properties();
339 for (Entry<String, String> eachEnv : System.getenv().entrySet()) {
340 env.setProperty(eachEnv.getKey(), eachEnv.getValue());
341 }
342 if (!env.contains("JAVA_HOME") || env.getProperty("JAVA_HOME").contains("jre")) {
343 env.setProperty("JAVA_HOME", System.getProperty("java.home"));
344 }
345 if (mavenHome != null && !env.contains("M2_HOME")) {
346 env.setProperty("M2_HOME", mavenHome.getAbsolutePath());
347 }
348
349 String[] envp = new String[env.size()];
350 int index = 0;
351 for (Object each : env.keySet()) {
352 String key = each.toString();
353 envp[index++] = String.format("%s=%s", key, env.getProperty(key));
354 }
355
356 _logger.trace("environment variables: " + env);
357 return envp;
358 }
359
360 public static int runMaven(String[] args, File workingDir) throws UTGBShellException {
361
362 try {
363
364
365 Runtime.getRuntime().addShutdownHook(new Thread() {
366 @Override
367 public void run() {
368 _logger.debug("shutdown hook is called");
369 }
370 });
371
372 String mavenBinary = getMavenBinary();
373
374 _logger.debug("Maven binary: " + mavenBinary);
375 File mavenHome = new File(mavenBinary).getParentFile().getParentFile();
376
377 String[] envp = prepareEnvironmentVariables(mavenHome);
378
379 String cmdLineFormat = System.getProperty("os.name").contains("Windows") ? "\"%s\" %s" : "%s %s";
380 int returnCode = CommandExecutor.exec(String.format(cmdLineFormat, mavenBinary, StringUtil.join(args, " ")), envp, workingDir);
381
382 if (returnCode != 0)
383 throw new UTGBShellException("error: " + returnCode);
384
385 return returnCode;
386 }
387 catch (Exception e) {
388 throw new UTGBShellException(e);
389 }
390 }
391
392 @Override
393 public void execute(String[] args) throws Exception {
394 runMaven(args);
395 }
396
397 @Override
398 public String name() {
399 return "maven";
400 }
401
402 @Override
403 public String getOneLinerDescription() {
404 return "execute maven tasks";
405 }
406
407 }