test/jdk/tools/pack200/Utils.java
changeset 47216 71c04702a3d5
parent 43185 d75d9ff8d4e7
child 50603 95c0644a1c47
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/tools/pack200/Utils.java	Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,666 @@
+/*
+ * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.nio.file.Path;
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.net.URI;
+import java.nio.charset.Charset;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.FileVisitResult;
+import java.nio.file.FileVisitor;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Pack200;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import static java.nio.file.StandardCopyOption.*;
+import static java.nio.file.StandardOpenOption.*;
+
+
+/**
+ *
+ * @author ksrini
+ */
+
+/*
+ * This class contains the commonly used utilities.
+ */
+class Utils {
+    static final String JavaHome = System.getProperty("test.java",
+            System.getProperty("java.home"));
+    static final boolean IsWindows =
+            System.getProperty("os.name").startsWith("Windows");
+    static final boolean Is64Bit =
+            System.getProperty("sun.arch.data.model", "32").equals("64");
+    static final File   JavaSDK =  new File(JavaHome);
+
+    static final String PACK_FILE_EXT   = ".pack";
+    static final String JAVA_FILE_EXT   = ".java";
+    static final String CLASS_FILE_EXT  = ".class";
+    static final String JAR_FILE_EXT    = ".jar";
+
+    static final File   TEST_SRC_DIR = new File(System.getProperty("test.src"));
+    static final File   TEST_CLS_DIR = new File(System.getProperty("test.classes"));
+    static final String VERIFIER_DIR_NAME = "pack200-verifier";
+    static final File   VerifierJar = new File(VERIFIER_DIR_NAME + JAR_FILE_EXT);
+    static final File   XCLASSES = new File("xclasses");
+
+    private Utils() {} // all static
+
+    private static void init() throws IOException {
+        if (VerifierJar.exists()) {
+            return;
+        }
+        File srcDir = new File(getVerifierDir(), "src");
+        List<File> javaFileList = findFiles(srcDir, createFilter(JAVA_FILE_EXT));
+        File tmpFile = File.createTempFile("javac", ".tmp", new File("."));
+        XCLASSES.mkdirs();
+        FileOutputStream fos = null;
+        PrintStream ps = null;
+        try {
+            fos = new FileOutputStream(tmpFile);
+            ps = new PrintStream(fos);
+            for (File f : javaFileList) {
+                ps.println(f.getAbsolutePath());
+            }
+        } finally {
+            close(ps);
+            close(fos);
+        }
+
+        compiler("-d",
+                XCLASSES.getName(),
+                "--add-modules=jdk.jdeps",
+                "--add-exports=jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED",
+                "@" + tmpFile.getAbsolutePath());
+
+        jar("cvfe",
+            VerifierJar.getName(),
+            "sun.tools.pack.verify.Main",
+            "-C",
+            XCLASSES.getName(),
+            ".");
+    }
+
+    private static File getVerifierDir() {
+        File srcDir = new File(TEST_SRC_DIR, VERIFIER_DIR_NAME);
+        if (!srcDir.exists()) {
+            // if not available try one level above
+            srcDir = new File(TEST_SRC_DIR.getParentFile(), VERIFIER_DIR_NAME);
+        }
+        return srcDir;
+    }
+
+    static File getGoldenJar() {
+        return new File(new File(getVerifierDir(), "data"), "golden.jar");
+    }
+    static void dirlist(File dir) {
+        File[] files = dir.listFiles();
+        System.out.println("--listing " + dir.getAbsolutePath() + "---");
+        for (File f : files) {
+            StringBuffer sb = new StringBuffer();
+            sb.append(f.isDirectory() ? "d " : "- ");
+            sb.append(f.getName());
+            System.out.println(sb);
+        }
+    }
+    static void doCompareVerify(File reference, File specimen) throws IOException {
+        init();
+        List<String> cmds = new ArrayList<String>();
+        cmds.add(getJavaCmd());
+        cmds.add("--add-exports=jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED");
+        cmds.add("-cp");
+        cmds.add(VerifierJar.getName());
+        cmds.add("sun.tools.pack.verify.Main");
+        cmds.add(reference.getAbsolutePath());
+        cmds.add(specimen.getAbsolutePath());
+        cmds.add("-O");
+        runExec(cmds);
+    }
+
+    static void doCompareBitWise(File reference, File specimen)
+            throws IOException {
+        init();
+        List<String> cmds = new ArrayList<String>();
+        cmds.add(getJavaCmd());
+        cmds.add("-cp");
+        cmds.add(VerifierJar.getName());
+        cmds.add("sun.tools.pack.verify.Main");
+        cmds.add(reference.getName());
+        cmds.add(specimen.getName());
+        cmds.add("-O");
+        cmds.add("-b");
+        runExec(cmds);
+    }
+
+    static FileFilter createFilter(final String extension) {
+        return new FileFilter() {
+            @Override
+            public boolean accept(File pathname) {
+                String name = pathname.getName();
+                if (name.endsWith(extension)) {
+                    return true;
+                }
+                return false;
+            }
+        };
+    }
+
+    /*
+     * clean up all the usual suspects
+     */
+    static void cleanup() throws IOException {
+        recursiveDelete(XCLASSES);
+        List<File> toDelete = new ArrayList<>();
+        toDelete.addAll(Utils.findFiles(new File("."),
+                Utils.createFilter(".out")));
+        toDelete.addAll(Utils.findFiles(new File("."),
+                Utils.createFilter(".bak")));
+        toDelete.addAll(Utils.findFiles(new File("."),
+                Utils.createFilter(".jar")));
+        toDelete.addAll(Utils.findFiles(new File("."),
+                Utils.createFilter(".pack")));
+        toDelete.addAll(Utils.findFiles(new File("."),
+                Utils.createFilter(".bnd")));
+        toDelete.addAll(Utils.findFiles(new File("."),
+                Utils.createFilter(".txt")));
+        toDelete.addAll(Utils.findFiles(new File("."),
+                Utils.createFilter(".idx")));
+        toDelete.addAll(Utils.findFiles(new File("."),
+                Utils.createFilter(".gidx")));
+        toDelete.addAll(Utils.findFiles(new File("."),
+                Utils.createFilter(".tmp")));
+        toDelete.addAll(Utils.findFiles(new File("."),
+                Utils.createFilter(".class")));
+        for (File f : toDelete) {
+            f.delete();
+        }
+    }
+
+    static final FileFilter DIR_FILTER = new FileFilter() {
+        public boolean accept(File pathname) {
+            if (pathname.isDirectory()) {
+                return true;
+            }
+            return false;
+        }
+    };
+
+    static final FileFilter FILE_FILTER = new FileFilter() {
+        public boolean accept(File pathname) {
+            if (pathname.isFile()) {
+                return true;
+            }
+            return false;
+        }
+    };
+
+    static void copyFile(File src, File dst) throws IOException {
+        Path parent = dst.toPath().getParent();
+        if (parent != null) {
+            Files.createDirectories(parent);
+        }
+        Files.copy(src.toPath(), dst.toPath(), COPY_ATTRIBUTES, REPLACE_EXISTING);
+        if (dst.isDirectory() && !dst.canWrite()) {
+            dst.setWritable(true);
+        }
+    }
+
+    static String baseName(File file, String extension) {
+        return baseName(file.getAbsolutePath(), extension);
+    }
+
+    static String baseName(String name, String extension) {
+        int cut = name.length() - extension.length();
+        return name.lastIndexOf(extension) == cut
+                ? name.substring(0, cut)
+                : name;
+
+    }
+   static void createFile(File outFile, List<String> content) throws IOException {
+        Files.write(outFile.getAbsoluteFile().toPath(), content,
+                Charset.defaultCharset(), CREATE_NEW, TRUNCATE_EXISTING);
+    }
+
+    /*
+     * Suppose a path is provided which consists of a full path
+     * this method returns the sub path for a full path ex: /foo/bar/baz/foobar.z
+     * and the base path is /foo/bar it will will return baz/foobar.z.
+     */
+    private static String getEntryPath(String basePath, String fullPath) {
+        if (!fullPath.startsWith(basePath)) {
+            return null;
+        }
+        return fullPath.substring(basePath.length());
+    }
+
+    static String getEntryPath(File basePathFile, File fullPathFile) {
+        return getEntryPath(basePathFile.toString(), fullPathFile.toString());
+    }
+
+    public static void recursiveCopy(File src, File dest) throws IOException {
+        if (!src.exists() || !src.canRead()) {
+            throw new IOException("file not found or readable: " + src);
+        }
+        if (dest.exists() && !dest.isDirectory() && !dest.canWrite()) {
+            throw new IOException("file not found or writeable: " + dest);
+        }
+        if (!dest.exists()) {
+            dest.mkdirs();
+        }
+        List<File> a = directoryList(src);
+        for (File f : a) {
+            copyFile(f, new File(dest, getEntryPath(src, f)));
+        }
+    }
+
+    static List<File> directoryList(File dirname) {
+        List<File>  dirList = new ArrayList<File>();
+        return directoryList(dirname, dirList, null);
+    }
+
+    private static List<File> directoryList(File dirname, List<File> dirList,
+            File[] dirs) {
+        dirList.addAll(Arrays.asList(dirname.listFiles(FILE_FILTER)));
+        dirs = dirname.listFiles(DIR_FILTER);
+        for (File f : dirs) {
+            if (f.isDirectory() && !f.equals(dirname)) {
+                dirList.add(f);
+                directoryList(f, dirList, dirs);
+            }
+        }
+        return dirList;
+    }
+
+    static void recursiveDelete(File dir) throws IOException {
+        if (dir.isFile()) {
+            dir.delete();
+        } else if (dir.isDirectory()) {
+            File[] entries = dir.listFiles();
+            for (int i = 0; i < entries.length; i++) {
+                if (entries[i].isDirectory()) {
+                    recursiveDelete(entries[i]);
+                }
+                entries[i].delete();
+            }
+            dir.delete();
+        }
+    }
+
+    static List<File> findFiles(File startDir, FileFilter filter)
+            throws IOException {
+        List<File> list = new ArrayList<File>();
+        findFiles0(startDir, list, filter);
+        return list;
+    }
+    /*
+     * finds files in the start directory using the the filter, appends
+     * the files to the dirList.
+     */
+    private static void findFiles0(File startDir, List<File> list,
+                                    FileFilter filter) throws IOException {
+        File[] foundFiles = startDir.listFiles(filter);
+        if (foundFiles == null) {
+            return;
+        }
+        list.addAll(Arrays.asList(foundFiles));
+        File[] dirs = startDir.listFiles(DIR_FILTER);
+        for (File dir : dirs) {
+            findFiles0(dir, list, filter);
+        }
+    }
+
+    static void close(Closeable c) {
+        if (c == null) {
+            return;
+        }
+        try {
+            c.close();
+        } catch (IOException ignore) {
+        }
+    }
+
+    static void compiler(String... javacCmds) {
+        List<String> cmdList = new ArrayList<>();
+        cmdList.add(getJavacCmd());
+        for (String x : javacCmds) {
+            cmdList.add(x);
+        }
+        runExec(cmdList);
+    }
+
+    static void jar(String... jargs) {
+        List<String> cmdList = new ArrayList<>();
+        cmdList.add(getJarCmd());
+        for (String x : jargs) {
+            cmdList.add(x);
+        }
+        runExec(cmdList);
+    }
+
+    static void testWithRepack(File inFile, String... repackOpts) throws IOException {
+        File cwd = new File(".");
+        // pack using --repack in native mode
+        File nativejarFile = new File(cwd, "out-n" + Utils.JAR_FILE_EXT);
+        repack(inFile, nativejarFile, false, repackOpts);
+        doCompareVerify(inFile, nativejarFile);
+
+        // ensure bit compatibility between the unpacker variants
+        File javajarFile = new File(cwd, "out-j" + Utils.JAR_FILE_EXT);
+        repack(inFile, javajarFile, true, repackOpts);
+        doCompareBitWise(javajarFile, nativejarFile);
+    }
+
+    static List<String> repack(File inFile, File outFile,
+            boolean disableNative, String... extraOpts) {
+        List<String> cmdList = new ArrayList<>();
+        cmdList.clear();
+        cmdList.add(Utils.getJavaCmd());
+        cmdList.add("-ea");
+        cmdList.add("-esa");
+        if (disableNative) {
+            cmdList.add("-Dcom.sun.java.util.jar.pack.disable.native=true");
+        }
+        cmdList.add("com.sun.java.util.jar.pack.Driver");
+        cmdList.add("--repack");
+        if (extraOpts != null) {
+           for (String opt: extraOpts) {
+               cmdList.add(opt);
+           }
+        }
+        cmdList.add(outFile.getName());
+        cmdList.add(inFile.getName());
+        return Utils.runExec(cmdList);
+    }
+
+    // given a jar file foo.jar will write to foo.pack
+    static void pack(JarFile jarFile, File packFile) throws IOException {
+        Pack200.Packer packer = Pack200.newPacker();
+        Map<String, String> p = packer.properties();
+        // Take the time optimization vs. space
+        p.put(packer.EFFORT, "1");  // CAUTION: do not use 0.
+        // Make the memory consumption as effective as possible
+        p.put(packer.SEGMENT_LIMIT, "10000");
+        // ignore all JAR deflation requests to save time
+        p.put(packer.DEFLATE_HINT, packer.FALSE);
+        // save the file ordering of the original JAR
+        p.put(packer.KEEP_FILE_ORDER, packer.TRUE);
+        FileOutputStream fos = null;
+        try {
+            // Write out to a jtreg scratch area
+            fos = new FileOutputStream(packFile);
+            // Call the packer
+            packer.pack(jarFile, fos);
+        } finally {
+            close(fos);
+        }
+    }
+
+    // uses java unpacker, slow but useful to discover issues with the packer
+    static void unpackj(File inFile, JarOutputStream jarStream)
+            throws IOException {
+        unpack0(inFile, jarStream, true);
+
+    }
+
+    // uses native unpacker using the java APIs
+    static void unpackn(File inFile, JarOutputStream jarStream)
+            throws IOException {
+        unpack0(inFile, jarStream, false);
+    }
+
+    // given a packed file, create the jar file in the current directory.
+    private static void unpack0(File inFile, JarOutputStream jarStream,
+            boolean useJavaUnpack) throws IOException {
+        // Unpack the files
+        Pack200.Unpacker unpacker = Pack200.newUnpacker();
+        Map<String, String> props = unpacker.properties();
+        if (useJavaUnpack) {
+            props.put("com.sun.java.util.jar.pack.disable.native", "true");
+        }
+        // Call the unpacker
+        unpacker.unpack(inFile, jarStream);
+    }
+
+    static byte[] getBuffer(ZipFile zf, ZipEntry ze) throws IOException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        byte buf[] = new byte[8192];
+        InputStream is = null;
+        try {
+            is = zf.getInputStream(ze);
+            int n = is.read(buf);
+            while (n > 0) {
+                baos.write(buf, 0, n);
+                n = is.read(buf);
+            }
+            return baos.toByteArray();
+        } finally {
+            close(is);
+        }
+    }
+
+    static ArrayList<String> getZipFileEntryNames(ZipFile z) {
+        ArrayList<String> out = new ArrayList<String>();
+        for (ZipEntry ze : Collections.list(z.entries())) {
+            out.add(ze.getName());
+        }
+        return out;
+    }
+
+    static List<String> runExec(String... cmds) {
+        return runExec(Arrays.asList(cmds));
+    }
+
+    static List<String> runExec(List<String> cmdsList) {
+        return runExec(cmdsList, null);
+    }
+
+    static List<String> runExec(List<String> cmdsList, Map<String, String> penv) {
+        ArrayList<String> alist = new ArrayList<String>();
+        ProcessBuilder pb =
+                new ProcessBuilder(cmdsList);
+        Map<String, String> env = pb.environment();
+        if (penv != null && !penv.isEmpty()) {
+            env.putAll(penv);
+        }
+        pb.directory(new File("."));
+        dirlist(new File("."));
+        for (String x : cmdsList) {
+            System.out.print(x + " ");
+        }
+        System.out.println("");
+        int retval = 0;
+        Process p = null;
+        InputStreamReader ir = null;
+        BufferedReader rd = null;
+        InputStream is = null;
+        try {
+            pb.redirectErrorStream(true);
+            p = pb.start();
+            is = p.getInputStream();
+            ir = new InputStreamReader(is);
+            rd = new BufferedReader(ir, 8192);
+
+            String in = rd.readLine();
+            while (in != null) {
+                alist.add(in);
+                System.out.println(in);
+                in = rd.readLine();
+            }
+            retval = p.waitFor();
+            if (retval != 0) {
+                throw new RuntimeException("process failed with non-zero exit");
+            }
+        } catch (Exception ex) {
+            throw new RuntimeException(ex.getMessage());
+        } finally {
+            close(rd);
+            close(ir);
+            close(is);
+            if (p != null) {
+                p.destroy();
+            }
+        }
+        return alist;
+    }
+
+    static String getUnpack200Cmd() {
+        return getAjavaCmd("unpack200");
+    }
+
+    static String getPack200Cmd() {
+        return getAjavaCmd("pack200");
+    }
+
+    static String getJavaCmd() {
+        return getAjavaCmd("java");
+    }
+
+    static String getJavacCmd() {
+        return getAjavaCmd("javac");
+    }
+
+    static String getJarCmd() {
+        return getAjavaCmd("jar");
+    }
+
+    static String getAjavaCmd(String cmdStr) {
+        File binDir = new File(JavaHome, "bin");
+        File unpack200File = IsWindows
+                ? new File(binDir, cmdStr + ".exe")
+                : new File(binDir, cmdStr);
+
+        String cmd = unpack200File.getAbsolutePath();
+        if (!unpack200File.canExecute()) {
+            throw new RuntimeException("please check" +
+                    cmd + " exists and is executable");
+        }
+        return cmd;
+    }
+
+    // used to get all classes
+    static File createRtJar() throws Exception {
+        File rtJar = new File("rt.jar");
+        new JrtToZip(".*\\.class", rtJar).run();
+        return rtJar;
+    }
+
+    // used to select the contents
+    static File createRtJar(String pattern) throws Exception {
+        File rtJar = new File("rt.jar");
+        new JrtToZip(pattern, rtJar).run();
+        return rtJar;
+    }
+
+    /*
+     * A helper class to create a pseudo rt.jar.
+     */
+    static class JrtToZip {
+
+        final File outFile;
+        final Pattern pattern;
+
+        public static void main(String[] args) throws Exception {
+            new JrtToZip(args[0], new File(args[1])).run();
+        }
+
+        JrtToZip(String pattern, File outFile) throws Exception {
+            this.pattern = Pattern.compile(pattern);
+            this.outFile = outFile;
+        }
+
+        void run() throws Exception {
+            URI uri = URI.create("jar:" + outFile.toURI());
+            Map<String, String> env = new HashMap<>();
+            env.put("create", "true");
+            try (FileSystem zipfs = FileSystems.newFileSystem(uri, env)) {
+                toZipfs(zipfs);
+            }
+        }
+
+        void toZipfs(FileSystem zipfs) throws Exception {
+            FileSystem jrtfs = FileSystems.getFileSystem(URI.create("jrt:/"));
+            for (Path root : jrtfs.getRootDirectories()) {
+                Files.walkFileTree(root, new FileVisitor<Path>() {
+                    @Override
+                    public FileVisitResult preVisitDirectory(Path dir,
+                            BasicFileAttributes attrs) throws IOException {
+                        // ignore unneeded directory
+                        if (dir.startsWith("/packages"))
+                            return FileVisitResult.SKIP_SUBTREE;
+
+                        // pre-create required directories
+                        Path zpath = zipfs.getPath(dir.toString());
+                        Files.createDirectories(zpath);
+                        return FileVisitResult.CONTINUE;
+                    }
+
+                    @Override
+                    public FileVisitResult visitFile(Path file,
+                            BasicFileAttributes attrs) throws IOException {
+                        Matcher matcher = pattern.matcher(file.toString());
+                        if (matcher.matches()) {
+                            // System.out.println("x: " + file);
+                            Path zpath = zipfs.getPath(file.toString());
+                            Files.copy(file, zpath, REPLACE_EXISTING);
+                        }
+                        return FileVisitResult.CONTINUE;
+                    }
+
+                    @Override
+                    public FileVisitResult visitFileFailed(Path file,
+                            IOException exc) throws IOException {
+                        return FileVisitResult.CONTINUE;
+                    }
+
+                    @Override
+                    public FileVisitResult postVisitDirectory(Path dir,
+                            IOException exc) throws IOException {
+                        return FileVisitResult.CONTINUE;
+                    }
+                });
+            }
+        }
+    }
+}