diff --git a/boot/src/main/java/com/taobao/arthas/boot/Bootstrap.java b/boot/src/main/java/com/taobao/arthas/boot/Bootstrap.java index 58179aeca..b74e997e4 100644 --- a/boot/src/main/java/com/taobao/arthas/boot/Bootstrap.java +++ b/boot/src/main/java/com/taobao/arthas/boot/Bootstrap.java @@ -24,6 +24,7 @@ import com.taobao.middleware.cli.CommandLine; import com.taobao.middleware.cli.UsageMessageFormatter; import com.taobao.middleware.cli.annotations.Argument; import com.taobao.middleware.cli.annotations.CLIConfigurator; +import com.taobao.middleware.cli.annotations.DefaultValue; import com.taobao.middleware.cli.annotations.Description; import com.taobao.middleware.cli.annotations.Name; import com.taobao.middleware.cli.annotations.Option; @@ -137,7 +138,7 @@ public class Bootstrap { this.repoMirror = repoMirror; } - @Option(longName = "use-https") + @Option(longName = "use-https", flag = true) @Description("Use https to download, default true") public void setUseHttps(boolean useHttps) { this.useHttps = useHttps; @@ -165,7 +166,7 @@ public class Bootstrap { return verbose; } - @Option(shortName = "v", longName = "verbose") + @Option(shortName = "v", longName = "verbose", flag = true) @Description("Verbose, print debug info.") public void setVerbose(boolean verbose) { this.verbose = verbose; @@ -274,19 +275,52 @@ public class Bootstrap { System.getProperty("user.home") + File.separator + ".arthas" + File.separator + "lib"); arthasLibDir.mkdirs(); + /** + *
+             * 1. get local latest version
+             * 2. get remote latest version
+             * 3. compare two version
+             * 
+ */ List versionList = listNames(arthasLibDir); + Collections.sort(versionList); + + String localLastestVersion = null; + if (!versionList.isEmpty()) { + localLastestVersion = versionList.get(versionList.size() - 1); + } - if (versionList.isEmpty()) { + String remoteLastestVersion = DownloadUtils.getLastestVersion(bootStrap.getRepoMirror(), + bootStrap.isUseHttps()); + + boolean needDownload = false; + if (localLastestVersion == null) { + if (remoteLastestVersion == null) { + // exit + AnsiLog.error("Can not find Arthas under local: {} and remote: {}", arthasLibDir, + bootStrap.getRepoMirror()); + System.exit(1); + } else { + needDownload = true; + } + } else { + if (remoteLastestVersion != null) { + if (localLastestVersion.compareTo(remoteLastestVersion) < 0) { + AnsiLog.info("local lastest version: {}, remote lastest version: {}, try to download from remote.", + localLastestVersion, remoteLastestVersion); + needDownload = true; + } + } + } + if (needDownload) { // try to download arthas from remote server. DownloadUtils.downArthasPackaging(bootStrap.getRepoMirror(), bootStrap.isUseHttps(), - arthasLibDir.getAbsolutePath()); - versionList = listNames(arthasLibDir); + remoteLastestVersion, arthasLibDir.getAbsolutePath()); + localLastestVersion = remoteLastestVersion; } - Collections.sort(versionList); - // get the latest version - arthasHomeDir = new File(arthasLibDir, versionList.get(versionList.size() - 1) + File.separator + "arthas"); + arthasHomeDir = new File(arthasLibDir, localLastestVersion + File.separator + "arthas"); } verifyArthasHome(arthasHomeDir.getAbsolutePath()); diff --git a/boot/src/main/java/com/taobao/arthas/boot/DownloadUtils.java b/boot/src/main/java/com/taobao/arthas/boot/DownloadUtils.java index 61c90585a..d8e5d9b5d 100644 --- a/boot/src/main/java/com/taobao/arthas/boot/DownloadUtils.java +++ b/boot/src/main/java/com/taobao/arthas/boot/DownloadUtils.java @@ -5,8 +5,12 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; +import java.net.URLConnection; +import java.text.DecimalFormat; +import java.util.List; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -28,6 +32,8 @@ public class DownloadUtils { private static final String MAVEN_METADATA_URL = "${REPO}/com/taobao/arthas/arthas-packaging/maven-metadata.xml"; private static final String REMOTE_DOWNLOAD_URL = "${REPO}/com/taobao/arthas/arthas-packaging/${VERSION}/arthas-packaging-${VERSION}-bin.zip"; + private static final int CONNECTION_TIMEOUT = 3000; + /** * Read release version from maven-metadata.xml * @@ -37,10 +43,15 @@ public class DownloadUtils { * @throws SAXException * @throws IOException */ - public static String readMavenReleaseVersion(String mavenMetaDataUrl) - throws ParserConfigurationException, SAXException, IOException { - InputStream inputStream = new URL(mavenMetaDataUrl).openStream(); + public static String readMavenReleaseVersion(String mavenMetaDataUrl) { + InputStream inputStream = null; try { + URLConnection connection = new URL(mavenMetaDataUrl).openConnection(); + if (connection instanceof HttpURLConnection) { + ((HttpURLConnection) connection).setConnectTimeout(CONNECTION_TIMEOUT); + } + inputStream = connection.getInputStream(); + DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); Document document = dBuilder.parse(inputStream); @@ -48,13 +59,21 @@ public class DownloadUtils { NodeList nodeList = document.getDocumentElement().getElementsByTagName("release"); return nodeList.item(0).getTextContent(); + } catch (Throwable t) { + AnsiLog.debug("Can not read release version from: " + mavenMetaDataUrl); + AnsiLog.debug(t); } finally { IOUtils.close(inputStream); } + return null; } - public static void downArthasPackaging(String repoMirror, boolean https, String savePath) - throws ParserConfigurationException, SAXException, IOException { + public static String getLastestVersion(String repoMirror, boolean https) { + String repoUrl = getRepoUrl(repoMirror, https); + return readMavenReleaseVersion(MAVEN_METADATA_URL.replace("${REPO}", repoUrl)); + } + + public static String getRepoUrl(String repoMirror, boolean https) { repoMirror = repoMirror.trim(); String repoUrl = ""; if (repoMirror.equals("center")) { @@ -71,8 +90,12 @@ public class DownloadUtils { if (https && repoUrl.startsWith("http")) { repoUrl = "https" + repoUrl.substring("http".length(), repoUrl.length()); } + return repoUrl; + } - String arthasVersion = readMavenReleaseVersion(MAVEN_METADATA_URL.replace("${REPO}", repoUrl)); + public static void downArthasPackaging(String repoMirror, boolean https, String arthasVersion, String savePath) + throws ParserConfigurationException, SAXException, IOException { + String repoUrl = getRepoUrl(repoMirror, https); File unzipDir = new File(savePath, arthasVersion + File.separator + "arthas"); @@ -80,22 +103,46 @@ public class DownloadUtils { String remoteDownloadUrl = REMOTE_DOWNLOAD_URL.replace("${REPO}", repoUrl).replace("${VERSION}", arthasVersion); AnsiLog.info("Start download arthas from remote server: " + remoteDownloadUrl); - saveUrl(tempFile.getAbsolutePath(), remoteDownloadUrl); + saveUrl(tempFile.getAbsolutePath(), remoteDownloadUrl, true); IOUtils.unzip(tempFile.getAbsolutePath(), unzipDir.getAbsolutePath()); } - public static void saveUrl(final String filename, final String urlString) + public static void saveUrl(final String filename, final String urlString, boolean printProgress) throws MalformedURLException, IOException { BufferedInputStream in = null; FileOutputStream fout = null; try { - in = new BufferedInputStream(new URL(urlString).openStream()); + URLConnection connection = new URL(urlString).openConnection(); + if (connection instanceof HttpURLConnection) { + ((HttpURLConnection) connection).setConnectTimeout(CONNECTION_TIMEOUT); + } + in = new BufferedInputStream(connection.getInputStream()); + List values = connection.getHeaderFields().get("Content-Length"); + int fileSize = 0; + if (values != null && !values.isEmpty()) { + String contentLength = (String) values.get(0); + if (contentLength != null) { + // parse the length into an integer... + fileSize = Integer.parseInt(contentLength); + } + } + fout = new FileOutputStream(filename); - final byte data[] = new byte[1024]; + final byte data[] = new byte[1024 * 1024]; + int totalCount = 0; int count; - while ((count = in.read(data, 0, 1024)) != -1) { + long lastPrintTime = System.currentTimeMillis(); + while ((count = in.read(data, 0, 1024 * 1024)) != -1) { + totalCount += count; + long now = System.currentTimeMillis(); + if (now - lastPrintTime > 3000) { + AnsiLog.info("File size: {}, Downloaded size: {}", formatFileSize(fileSize), + formatFileSize(totalCount)); + lastPrintTime = now; + } + fout.write(data, 0, count); } } finally { @@ -104,4 +151,30 @@ public class DownloadUtils { } } + private static String formatFileSize(long size) { + String hrSize = null; + + double b = size; + double k = size / 1024.0; + double m = ((size / 1024.0) / 1024.0); + double g = (((size / 1024.0) / 1024.0) / 1024.0); + double t = ((((size / 1024.0) / 1024.0) / 1024.0) / 1024.0); + + DecimalFormat dec = new DecimalFormat("0.00"); + + if (t > 1) { + hrSize = dec.format(t).concat(" TB"); + } else if (g > 1) { + hrSize = dec.format(g).concat(" GB"); + } else if (m > 1) { + hrSize = dec.format(m).concat(" MB"); + } else if (k > 1) { + hrSize = dec.format(k).concat(" KB"); + } else { + hrSize = dec.format(b).concat(" Bytes"); + } + + return hrSize; + } + }