package org.yinwang.pysonar; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.*; import java.lang.management.GarbageCollectorMXBean; import java.lang.management.ManagementFactory; import java.nio.charset.Charset; import java.security.MessageDigest; import java.text.DecimalFormat; import java.util.*; public class Util { public static final Charset UTF_8 = Charset.forName("UTF-8"); private static int gensymCount = -1; @NotNull public static String gensym(String base) { gensymCount++; return base + gensymCount; } public static String baseFileName(String filename) { return new File(filename).getName(); } public static String getSystemTempDir() { String tmp = System.getProperty("java.io.tmpdir"); String sep = System.getProperty("file.separator"); if (tmp.endsWith(sep)) { return tmp; } return tmp + sep; } /** * Returns the parent qname of {@code qname} -- everything up to the * last dot (exclusive), or if there are no dots, the empty string. */ public static String getQnameParent(@Nullable String qname) { if (qname == null || qname.isEmpty()) { return ""; } int index = qname.lastIndexOf("."); if (index == -1) { return ""; } return qname.substring(0, index); } /** * Determines the fully-qualified module name for the specified file. A * module's qname is a function of the module's absolute path and the sys * path; it does not depend on how the module name may have been specified * in import statements. The module qname is the relative path of the module * under the load path, with slashes converted to dots. * * @param file absolute canonical path to a file (__init__.py for dirs) * @return null if {@code file} is not somewhere under the load path */ @Nullable public static String moduleQname(@NotNull String file) { File f = new File(file); boolean initpy = f.getName().equals("__init__.py"); if (initpy) { file = f.getAbsolutePath(); } else if (file.endsWith(".py")) { file = file.substring(0, file.length() - ".py".length()); } for (String root : Indexer.idx.getLoadPath()) { if (file.startsWith(root)) { if (file.contains("/")) { return file.substring(root.length() + 1).replace('/', '.'); } else if (file.contains("\\")) { return file.substring(root.length() + 1).replace('\\', '.'); } } } return null; } @NotNull public static String arrayToString(@NotNull Collection<String> strings) { StringBuffer sb = new StringBuffer(); for (String s : strings) { sb.append(s).append("\n"); } return sb.toString(); } @NotNull public static String arrayToSortedStringSet(Collection<String> strings) { Set<String> sorter = new TreeSet<String>(); sorter.addAll(strings); return arrayToString(sorter); } /** * Given an absolute {@code path} to a file (not a directory), * returns the module name for the file. If the file is an __init__.py, * returns the last component of the file's parent directory, else * returns the filename without path or extension. */ public static String moduleNameFor(String path) { File f = new File(path); if (f.isDirectory()) { throw new IllegalStateException("failed assertion: " + path); } String fname = f.getName(); if (fname.equals("__init__.py")) { return f.getParentFile().getName(); } return fname.substring(0, fname.lastIndexOf('.')); } @NotNull public static File joinPath(@NotNull File dir, String file) { return joinPath(dir.getAbsolutePath(), file); } @NotNull public static File joinPath(String dir, String file) { File file1 = new File(dir); File file2 = new File(file1, file); return file2; } public static void writeFile(String path, String contents) throws Exception { PrintWriter out = null; try { out = new PrintWriter(new BufferedWriter(new FileWriter(path))); out.print(contents); out.flush(); } finally { if (out != null) { out.close(); } } } @NotNull public static String readFile(String filename) throws Exception { return readFile(new File(filename)); } @NotNull public static String readFile(@NotNull File path) throws Exception { // Don't use line-oriented file read -- need to retain CRLF if present // so the style-run and link offsets are correct. return new String(getBytesFromFile(path), UTF_8); } @NotNull public static byte[] getBytesFromFile(@NotNull File file) { InputStream is = null; try { is = new FileInputStream(file); long length = file.length(); if (length > Integer.MAX_VALUE) { throw new IOException("file too large: " + file); } byte[] bytes = new byte[(int)length]; int offset = 0; int numRead = 0; while (offset < bytes.length && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) { offset += numRead; } if (offset < bytes.length) { throw new IOException("Failed to read whole file " + file); } return bytes; } catch (Exception e) { return null; } finally { if (is != null) { try { is.close(); } catch (Exception e) { } } } } @NotNull public static String readWhole(@NotNull InputStream is) throws IOException { StringBuilder sb = new StringBuilder(); byte[] bytes = new byte[8192]; int nRead; while ((nRead = is.read(bytes, 0, 8192)) > 0) { sb.append(new String(bytes, 0, nRead)); } return sb.toString(); } @NotNull public static String getSHA1(@NotNull File path) { byte[] bytes = getBytesFromFile(path); if (bytes == null) { Util.msg("getSHA1: failed to read from file: " + path); System.exit(2); return ""; } else { return getMD5(bytes); } } @NotNull public static String getMD5(byte[] fileContents) { MessageDigest algorithm; try { algorithm = MessageDigest.getInstance("SHA-1"); } catch (Exception e) { Util.die("getSHA1: failed to get MD5, shouldn't happen"); return ""; } algorithm.reset(); algorithm.update(fileContents); byte messageDigest[] = algorithm.digest(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < messageDigest.length; i++) { sb.append(String.format("%02x", 0xFF & messageDigest[i])); } return sb.toString(); } static boolean isReadableFile(String path) { File f = new File(path); return f.canRead() && f.isFile(); } static public String escapeQname_(@NotNull String s) { return s.replaceAll("[.&@%-]", "_"); } @NotNull public static Collection<String> toStringCollection(@NotNull Collection<Integer> collection) { List<String> ret = new ArrayList<String>(); for (Integer x : collection) { ret.add(x.toString()); } return ret; } @NotNull static public String joinWithSep(@NotNull Collection<String> ls, String sep, @Nullable String start, @Nullable String end) { StringBuilder sb = new StringBuilder(); if (start != null && ls.size() > 1) { sb.append(start); } int i = 0; for (String s: ls) { if (i > 0) { sb.append(sep); } sb.append(s); i++; } if (end != null && ls.size() > 1) { sb.append(end); } return sb.toString(); } @NotNull public static String timeString(long millis) { long sec = millis / 1000; long min = sec / 60; sec = sec % 60; long hr = min / 60; min = min % 60; return hr + ":" + min + ":" + sec; } public static void msg(String m) { System.out.println(m); } @Nullable public static String readWholeFile(String filename) { try { return new Scanner(new File(filename)).useDelimiter("PYSONAR2END").next(); } catch (FileNotFoundException e) { return null; } } public static String readWholeStream(InputStream in) throws Exception { return new Scanner(in).useDelimiter("\\Z").next(); } @NotNull public static String percent(long num, long total) { double pct = ((double) num) * 100 / total; DecimalFormat df = new DecimalFormat("##"); String formatted = df.format(pct); return formatted + "%"; } public static void die(String msg) { die(msg, null); } public static void die(String msg, Exception e) { System.err.println(msg); if (e != null) { System.err.println("Exception: " + e + "\n"); } Thread.dumpStack(); System.exit(2); } public static boolean deleteDirectory(File directory) { if (directory.exists()) { File[] files = directory.listFiles(); if (files != null) { for (File f : files) { if (f.isDirectory()) { deleteDirectory(f); } else { f.delete(); } } } } return directory.delete(); } public static String newSessionId() { return UUID.randomUUID().toString(); } public static File makePath(String... files) { File ret = new File(files[0]); for (int i = 1; i < files.length; i++) { ret = new File(ret, files[i]); } return ret; } public static String makePathString(String... files) { return unifyPath(makePath(files).getPath()); } public static String unifyPath(String filename) { return unifyPath(new File(filename)); } public static String unifyPath(File file) { return file.getAbsolutePath(); } public static String relativize(String path1, String path2) { String a = unifyPath(path1); String b = unifyPath(path2); String[] as = a.split("[/\\\\]"); String[] bs = b.split("[/\\\\]"); int i; for (i = 0; i < Math.min(as.length, bs.length); i++) { if (!as[i].equals(bs[i])) { break; } } int ups = as.length - i - 1; File res = null; for (int x = 0; x < ups; x++) { res = new File(res, ".."); } for (int y = i; y < bs.length; y++) { res = new File(res, bs[y]); } if (res == null) { return null; } else { return res.getPath(); } } public static String printMem(long bytes) { double dbytes = (double) bytes; DecimalFormat df = new DecimalFormat("#.##"); if (dbytes < 1024) { return df.format(bytes); } else if (dbytes < 1024 * 1024) { return df.format(dbytes / 1024); } else if (dbytes < 1024 * 1024 * 1024) { return df.format(dbytes / 1024 / 1024) + "M"; } else if (dbytes < 1024 * 1024 * 1024 * 1024L) { return df.format(dbytes / 1024 / 1024 / 1024) + "G"; } else { return "Too big to show you"; } } public static String banner(String msg) { return "---------------- " + msg + " ----------------"; } public static String printGCStats() { long totalGC = 0; long gcTime = 0; for (GarbageCollectorMXBean gc : ManagementFactory.getGarbageCollectorMXBeans()) { long count = gc.getCollectionCount(); if (count >= 0) { totalGC += count; } long time = gc.getCollectionTime(); if (time >= 0) { gcTime += time; } } StringBuilder sb = new StringBuilder(); sb.append(banner("memory stats")); sb.append("\n- total collections: " + totalGC); sb.append("\n- total collection time: " + timeString(gcTime)); Runtime runtime = Runtime.getRuntime(); sb.append("\n- total memory: " + Util.printMem(runtime.totalMemory())); return sb.toString(); } }