841N/A/*
1132N/A * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
841N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
841N/A *
841N/A * This code is free software; you can redistribute it and/or modify it
841N/A * under the terms of the GNU General Public License version 2 only, as
841N/A * published by the Free Software Foundation.
841N/A *
841N/A * This code is distributed in the hope that it will be useful, but WITHOUT
841N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
841N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
841N/A * version 2 for more details (a copy is included in the LICENSE file that
841N/A * accompanied this code).
841N/A *
841N/A * You should have received a copy of the GNU General Public License version
841N/A * 2 along with this work; if not, write to the Free Software Foundation,
841N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
841N/A *
841N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
841N/A * or visit www.oracle.com if you need additional information or have any
841N/A * questions.
841N/A */
841N/A
841N/A/**
841N/A * @test
1132N/A * @bug 7013272 7127924
841N/A * @summary Automatically generate info about how compiler resource keys are used
841N/A * @build Example ArgTypeCompilerFactory MessageFile MessageInfo
1132N/A * @run main/othervm MessageInfo
1132N/A */
1132N/A/*
1132N/A * See CR 7127924 for info on why othervm is used.
841N/A */
841N/A
841N/Aimport java.io.*;
841N/Aimport java.text.SimpleDateFormat;
841N/Aimport java.util.*;
841N/A
841N/A/**
841N/A * Utility to manipulate compiler.properties, and suggest info comments based
841N/A * on information derived from running examples.
841N/A *
841N/A * Options:
841N/A * -examples dir location of examples directory
841N/A * -o file output file
841N/A * -check just check message file
841N/A * -ensureNewlines ensure newline after each entry
841N/A * -fixIndent fix indentation of continuation lines
841N/A * -sort sort messages
841N/A * -verbose verbose output
841N/A * -replace replace comments instead of merging comments
841N/A * file javac compiler.properties file
841N/A *
841N/A */
841N/Apublic class MessageInfo {
841N/A public static void main(String... args) throws Exception {
841N/A jtreg = (System.getProperty("test.src") != null);
841N/A File tmpDir;
841N/A if (jtreg) {
841N/A // use standard jtreg scratch directory: the current directory
841N/A tmpDir = new File(System.getProperty("user.dir"));
841N/A } else {
841N/A tmpDir = new File(System.getProperty("java.io.tmpdir"),
841N/A MessageInfo.class.getName()
841N/A + (new SimpleDateFormat("yyMMddHHmmss")).format(new Date()));
841N/A }
841N/A Example.setTempDir(tmpDir);
841N/A Example.Compiler.factory = new ArgTypeCompilerFactory();
841N/A
841N/A MessageInfo mi = new MessageInfo();
841N/A
841N/A try {
841N/A if (mi.run(args))
841N/A return;
841N/A } finally {
841N/A /* VERY IMPORTANT NOTE. In jtreg mode, tmpDir is set to the
841N/A * jtreg scratch directory, which is the current directory.
841N/A * In case someone is faking jtreg mode, make sure to only
841N/A * clean tmpDir when it is reasonable to do so.
841N/A */
841N/A if (tmpDir.isDirectory() &&
841N/A tmpDir.getName().startsWith(MessageInfo.class.getName())) {
841N/A if (clean(tmpDir))
841N/A tmpDir.delete();
841N/A }
841N/A }
841N/A
841N/A if (jtreg)
841N/A throw new Exception(mi.errors + " errors occurred");
841N/A else
841N/A System.exit(1);
841N/A }
841N/A
841N/A void usage() {
841N/A System.out.println("Usage:");
841N/A System.out.println(" java MessageInfo [options] [file]");
841N/A System.out.println("where options include");
841N/A System.out.println(" -examples dir location of examples directory");
841N/A System.out.println(" -o file output file");
841N/A System.out.println(" -check just check message file");
841N/A System.out.println(" -ensureNewlines ensure newline after each entry");
841N/A System.out.println(" -fixIndent fix indentation of continuation lines");
841N/A System.out.println(" -sort sort messages");
841N/A System.out.println(" -verbose verbose output");
841N/A System.out.println(" -replace replace comments instead of merging comments");
841N/A System.out.println(" file javac compiler.properties file");
841N/A }
841N/A
841N/A boolean run(String... args) {
841N/A File testSrc = new File(System.getProperty("test.src", "."));
841N/A File examplesDir = new File(testSrc, "examples");
841N/A File notYetFile = null;
841N/A File msgFile = null;
841N/A File outFile = null;
841N/A boolean verbose = false;
841N/A boolean ensureNewlines = false;
841N/A boolean fixIndent = false;
841N/A boolean sort = false;
841N/A boolean replace = false;
841N/A boolean check = jtreg; // default true in jtreg mode
841N/A
841N/A for (int i = 0; i < args.length; i++) {
841N/A String arg = args[i];
841N/A if (arg.equals("-examples") && (i + 1) < args.length)
841N/A examplesDir = new File(args[++i]);
841N/A else if(arg.equals("-notyet") && (i + 1) < args.length)
841N/A notYetFile = new File(args[++i]);
841N/A else if (arg.equals("-ensureNewlines"))
841N/A ensureNewlines = true;
841N/A else if (arg.equals("-fixIndent"))
841N/A fixIndent = true;
841N/A else if (arg.equals("-sort"))
841N/A sort = true;
841N/A else if (arg.equals("-verbose"))
841N/A verbose = true;
841N/A else if (arg.equals("-replace"))
841N/A replace = true;
841N/A else if (arg.equals("-check"))
841N/A check = true;
841N/A else if (arg.equals("-o") && (i + 1) < args.length)
841N/A outFile = new File(args[++i]);
841N/A else if (arg.startsWith("-")) {
841N/A error("unknown option: " + arg);
841N/A return false;
841N/A } else if (i == args.length - 1) {
841N/A msgFile = new File(arg);
841N/A } else {
841N/A error("unknown arg: " + arg);
841N/A return false;
841N/A }
841N/A }
841N/A
841N/A if (!check && outFile == null) {
841N/A usage();
841N/A return true;
841N/A }
841N/A
841N/A if ((ensureNewlines || fixIndent || sort) && outFile == null) {
841N/A error("must set output file for these options");
841N/A return false;
841N/A }
841N/A
841N/A if (notYetFile == null) {
841N/A notYetFile = new File(examplesDir.getParentFile(), "examples.not-yet.txt");
841N/A }
841N/A
841N/A if (msgFile == null) {
841N/A for (File d = testSrc; d != null; d = d.getParentFile()) {
841N/A if (new File(d, "TEST.ROOT").exists()) {
841N/A d = d.getParentFile();
841N/A File f = new File(d, "src/share/classes/com/sun/tools/javac/resources/compiler.properties");
841N/A if (f.exists()) {
841N/A msgFile = f;
841N/A break;
841N/A }
841N/A }
841N/A }
841N/A if (msgFile == null) {
842N/A if (jtreg) {
842N/A System.err.println("Warning: no message file available, test skipped");
842N/A return true;
842N/A }
841N/A error("no message file available");
841N/A return false;
841N/A }
841N/A }
841N/A
841N/A MessageFile mf;
841N/A try {
841N/A mf = new MessageFile(msgFile);
841N/A } catch (IOException e) {
841N/A error("problem reading message file: " + e);
841N/A return false;
841N/A }
841N/A
841N/A Map<String, Set<String>> msgInfo = runExamples(examplesDir, verbose);
841N/A
841N/A if (ensureNewlines)
841N/A ensureNewlines(mf);
841N/A
841N/A if (fixIndent)
841N/A fixIndent(mf);
841N/A
841N/A if (sort)
841N/A sort(mf, true);
841N/A
841N/A for (Map.Entry<String, Set<String>> e: msgInfo.entrySet()) {
841N/A String k = e.getKey();
841N/A Set<String> suggestions = e.getValue();
841N/A MessageFile.Message m = mf.messages.get(k);
841N/A if (m == null) {
841N/A error("Can't find message for " + k + " in message file");
841N/A continue;
841N/A }
841N/A
841N/A MessageFile.Info info = m.getInfo();
841N/A Set<Integer> placeholders = m.getPlaceholders();
841N/A MessageFile.Info suggestedInfo = new MessageFile.Info(suggestions);
841N/A suggestedInfo.markUnused(placeholders);
841N/A
841N/A if (!info.isEmpty()) {
841N/A if (info.contains(suggestedInfo))
841N/A continue;
841N/A if (!replace) {
841N/A if (info.fields.size() != suggestedInfo.fields.size())
841N/A error("Cannot merge info for " + k);
841N/A else
841N/A suggestedInfo.merge(info);
841N/A }
841N/A }
841N/A
841N/A if (outFile == null) {
841N/A System.err.println("suggest for " + k);
841N/A System.err.println(suggestedInfo.toComment());
841N/A } else
841N/A m.setInfo(suggestedInfo);
841N/A }
841N/A
841N/A if (check)
841N/A check(mf, notYetFile);
841N/A
841N/A try {
841N/A if (outFile != null)
841N/A mf.write(outFile);
841N/A } catch (IOException e) {
841N/A error("problem writing file: " + e);
841N/A return false;
841N/A }
841N/A
841N/A return (errors == 0);
841N/A }
841N/A
841N/A void check(MessageFile mf, File notYetFile) {
841N/A Set<String> notYetList = null;
841N/A for (Map.Entry<String, MessageFile.Message> e: mf.messages.entrySet()) {
841N/A String key = e.getKey();
841N/A MessageFile.Message m = e.getValue();
841N/A if (m.needInfo() && m.getInfo().isEmpty()) {
841N/A if (notYetList == null)
841N/A notYetList = getNotYetList(notYetFile);
841N/A if (notYetList.contains(key))
841N/A System.err.println("Warning: no info for " + key);
841N/A else
841N/A error("no info for " + key);
841N/A }
841N/A }
841N/A
841N/A }
841N/A
841N/A void ensureNewlines(MessageFile mf) {
841N/A for (MessageFile.Message m: mf.messages.values()) {
841N/A MessageFile.Line l = m.firstLine;
841N/A while (l.text.endsWith("\\"))
841N/A l = l.next;
841N/A if (l.next != null && !l.next.text.isEmpty())
841N/A l.insertAfter("");
841N/A }
841N/A }
841N/A
841N/A void fixIndent(MessageFile mf) {
841N/A for (MessageFile.Message m: mf.messages.values()) {
841N/A MessageFile.Line l = m.firstLine;
841N/A while (l.text.endsWith("\\") && l.next != null) {
841N/A if (!l.next.text.matches("^ \\S.*"))
841N/A l.next.text = " " + l.next.text.trim();
841N/A l = l.next;
841N/A }
841N/A }
841N/A }
841N/A
841N/A void sort(MessageFile mf, boolean includePrecedingNewlines) {
841N/A for (MessageFile.Message m: mf.messages.values()) {
841N/A for (MessageFile.Line l: m.getLines(includePrecedingNewlines)) {
841N/A l.remove();
841N/A mf.lastLine.insertAfter(l);
841N/A }
841N/A }
841N/A }
841N/A
841N/A Map<String, Set<String>> runExamples(File examplesDir, boolean verbose) {
841N/A Map<String, Set<String>> map = new TreeMap<String, Set<String>>();
841N/A for (Example e: getExamples(examplesDir)) {
841N/A StringWriter sw = new StringWriter();
841N/A PrintWriter pw = new PrintWriter(sw);
841N/A e.run(pw, true, verbose);
841N/A pw.close();
841N/A String[] lines = sw.toString().split("\n");
841N/A for (String line: lines) {
841N/A if (!line.startsWith("compiler."))
841N/A continue;
841N/A int colon = line.indexOf(":");
841N/A if (colon == -1)
841N/A continue;
841N/A String key = line.substring(0, colon);
841N/A StringBuilder sb = new StringBuilder();
841N/A sb.append("# ");
841N/A int i = 0;
841N/A String[] descs = line.substring(colon + 1).split(", *");
841N/A for (String desc: descs) {
841N/A if (i > 0) sb.append(", ");
841N/A sb.append(i++);
841N/A sb.append(": ");
841N/A sb.append(desc.trim());
841N/A }
841N/A Set<String> set = map.get(key);
841N/A if (set == null)
841N/A map.put(key, set = new TreeSet<String>());
841N/A set.add(sb.toString());
841N/A }
841N/A }
841N/A
841N/A return map;
841N/A }
841N/A
841N/A /**
841N/A * Get the complete set of examples to be checked.
841N/A */
841N/A Set<Example> getExamples(File examplesDir) {
841N/A Set<Example> results = new TreeSet<Example>();
841N/A for (File f: examplesDir.listFiles()) {
841N/A if (isValidExample(f))
841N/A results.add(new Example(f));
841N/A }
841N/A return results;
841N/A }
841N/A
841N/A boolean isValidExample(File f) {
841N/A return (f.isDirectory() && (!jtreg || f.list().length > 0)) ||
841N/A (f.isFile() && f.getName().endsWith(".java"));
841N/A }
841N/A
841N/A /**
841N/A * Get the contents of the "not-yet" list.
841N/A */
841N/A Set<String> getNotYetList(File file) {
841N/A Set<String> results = new TreeSet<String>();
841N/A try {
841N/A String[] lines = read(file).split("[\r\n]");
841N/A for (String line: lines) {
841N/A int hash = line.indexOf("#");
841N/A if (hash != -1)
841N/A line = line.substring(0, hash).trim();
841N/A if (line.matches("[A-Za-z0-9-_.]+"))
841N/A results.add(line);
841N/A }
841N/A } catch (IOException e) {
841N/A throw new Error(e);
841N/A }
841N/A return results;
841N/A }
841N/A
841N/A /**
841N/A * Read the contents of a file.
841N/A */
841N/A String read(File f) throws IOException {
841N/A byte[] bytes = new byte[(int) f.length()];
841N/A DataInputStream in = new DataInputStream(new FileInputStream(f));
841N/A try {
841N/A in.readFully(bytes);
841N/A } finally {
841N/A in.close();
841N/A }
841N/A return new String(bytes);
841N/A }
841N/A
841N/A /**
841N/A * Report an error.
841N/A */
841N/A void error(String msg) {
841N/A System.err.println("Error: " + msg);
841N/A errors++;
841N/A }
841N/A
841N/A static boolean jtreg;
841N/A
841N/A int errors;
841N/A
841N/A /**
841N/A * Clean the contents of a directory.
841N/A */
841N/A static boolean clean(File dir) {
841N/A boolean ok = true;
841N/A for (File f: dir.listFiles()) {
841N/A if (f.isDirectory())
841N/A ok &= clean(f);
841N/A ok &= f.delete();
841N/A }
841N/A return ok;
841N/A }
841N/A
841N/A}
841N/A
841N/A