< prev index next >

make/src/classes/build/tools/module/GenModuleInfoSource.java

Print this page

        

@@ -23,29 +23,31 @@
  * questions.
  */
 package build.tools.module;
 
 import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
- * A build tool to extend the module-info.java in the source tree
- * for platform-specific exports, uses, and provides and write
- * to the specified output file.
+ * A build tool to extend the module-info.java in the source tree for
+ * platform-specific exports, uses, and provides and write to the specified
+ * output file. Injecting platform-specific requires is not supported.
  *
- * GenModulesList build tool currently generates the modules.list from
- * the module-info.java from the source tree that will be used for
- * the make target and dependences.
- *
- * The build currently invokes gensrc-$MODULE.gmk after modules.list
- * is generated.  Hence, platform-specific requires is not supported.
+ * The extra exports, uses, provides can be specified in module-info.java.extra
+ * files and GenModuleInfoSource will be invoked for each module that has
+ * module-info.java.extra in the source directory.
  */
 public class GenModuleInfoSource {
     private final static String USAGE =
         "Usage: GenModuleInfoSource [option] -o <output file> <module-info-java>\n" +
         "Options are:\n" +

@@ -55,21 +57,36 @@
         "  -provides <service>/<provider-impl-classname>\n";
 
     public static void main(String... args) throws Exception {
         Path outfile = null;
         Path moduleInfoJava = null;
-        Map<String, Set<String>> options = new HashMap<>();
+        GenModuleInfoSource genModuleInfo = new GenModuleInfoSource();
 
         // validate input arguments
         for (int i = 0; i < args.length; i++){
             String option = args[i];
             if (option.startsWith("-")) {
                 String arg = args[++i];
-                if (option.equals("-exports") ||
-                        option.equals("-uses") ||
-                        option.equals("-provides")) {
-                    options.computeIfAbsent(option, _k -> new HashSet<>()).add(arg);
+                if (option.equals("-exports")) {
+                    int index = arg.indexOf('/');
+                        if (index > 0) {
+                            String pn = arg.substring(0, index);
+                            String mn = arg.substring(index + 1, arg.length());
+                            genModuleInfo.exportTo(pn, mn);
+                        } else {
+                            genModuleInfo.export(arg);
+                        }
+                } else if (option.equals("-uses")) {
+                    genModuleInfo.use(arg);
+                } else if (option.equals("-provides")) {
+                        int index = arg.indexOf('/');
+                        if (index <= 0) {
+                            throw new IllegalArgumentException("invalid -provide argument: " + arg);
+                        }
+                        String service = arg.substring(0, index);
+                        String impl = arg.substring(index + 1, arg.length());
+                        genModuleInfo.provide(service, impl);
                 } else if (option.equals("-o")) {
                     outfile = Paths.get(arg);
                 } else {
                     throw new IllegalArgumentException("invalid option: " + option);
                 }

@@ -85,50 +102,145 @@
 
         if (moduleInfoJava == null || outfile == null) {
             System.err.println(USAGE);
             System.exit(-1);
         }
-        // read module-info.java
-        Module.Builder builder = ModuleInfoReader.builder(moduleInfoJava);
-        augment(builder, options);
 
         // generate new module-info.java
-        Module module = builder.build();
+        genModuleInfo.generate(moduleInfoJava, outfile);
+    }
+
+    private final Set<String> exports = new HashSet<>();
+    private final Map<String, Set<String>> exportsTo = new HashMap<>();
+    private final Set<String> uses = new HashSet<>();
+    private final Map<String, Set<String>> provides = new HashMap<>();
+    GenModuleInfoSource() {
+    }
+
+    private void export(String p) {
+        Objects.requireNonNull(p);
+        if (exports.contains(p) || exportsTo.containsKey(p)) {
+            throw new RuntimeException("duplicated exports: " + p);
+        }
+        exports.add(p);
+    }
+    private void exportTo(String p, String mn) {
+        Objects.requireNonNull(p);
+        Objects.requireNonNull(mn);
+        if (exports.contains(p)) {
+            throw new RuntimeException("unqualified exports already exists: " + p);
+        }
+        exportsTo.computeIfAbsent(p, _k -> new HashSet<>()).add(mn);
+    }
+
+    private void use(String service) {
+        uses.add(service);
+    }
+
+    private void provide(String s, String impl) {
+        provides.computeIfAbsent(s, _k -> new HashSet<>()).add(impl);
+    }
+
+    private void generate(Path sourcefile, Path outfile) throws IOException {
         Path parent = outfile.getParent();
         if (parent != null)
             Files.createDirectories(parent);
 
-        try (BufferedWriter writer = Files.newBufferedWriter(outfile)) {
-            writer.write(module.toString());
+        List<String> lines = Files.readAllLines(sourcefile);
+        try (BufferedWriter bw = Files.newBufferedWriter(outfile);
+             PrintWriter writer = new PrintWriter(bw)) {
+            int lineNumber = 0;
+            for (String l : lines) {
+                lineNumber++;
+                String[] s = l.trim().split("\\s+");
+                String keyword = s[0].trim();
+                int nextIndex = keyword.length();
+                String exp = null;
+                int n = l.length();
+                switch (keyword) {
+                    case "exports":
+                        boolean inExportsTo = false;
+                        // assume package name immediately after exports
+                        exp = s[1].trim();
+                        if (s.length >= 3) {
+                            nextIndex = l.indexOf(exp, nextIndex) + exp.length();
+                            if (s[2].trim().equals("to")) {
+                                inExportsTo = true;
+                                n = l.indexOf("to", nextIndex) + "to".length();
+                            } else {
+                                throw new RuntimeException(sourcefile + ", line " +
+                                    lineNumber + ", is malformed: " + s[2]);
         }
     }
 
-    private static void augment(Module.Builder builder, Map<String, Set<String>> options) {
-        for (String opt : options.keySet()) {
-            if (opt.equals("-exports")) {
-                for (String arg : options.get(opt)) {
-                    int index = arg.indexOf('/');
-                    if (index > 0) {
-                        String pn = arg.substring(0, index);
-                        String mn = arg.substring(index + 1, arg.length());
-                        builder.exportTo(pn, mn);
+                        // inject the extra targets after "to"
+                        if (inExportsTo) {
+                            writer.println(injectExportTargets(exp, l, n));
                     } else {
-                        builder.export(arg);
+                            writer.println(l);
                     }
+                        break;
+                    case "to":
+                        if (exp == null) {
+                            throw new RuntimeException(sourcefile + ", line " +
+                                lineNumber + ", is malformed");
+                        }
+                        n = l.indexOf("to", nextIndex) + "to".length();
+                        writer.println(injectExportTargets(exp, l, n));
+                        break;
+                    case "}":
+                        doAugments(writer);
+                        // fall through
+                    default:
+                        writer.println(l);
+                        // reset exports
+                        exp = null;
                 }
-            } else if (opt.equals("-uses")) {
-                options.get(opt).stream()
-                        .forEach(builder::use);
-            } else if (opt.equals("-provides")) {
-                for (String arg : options.get(opt)) {
-                    int index = arg.indexOf('/');
-                    if (index <= 0) {
-                        throw new IllegalArgumentException("invalid -provide argument: " + arg);
                     }
-                    String service = arg.substring(0, index);
-                    String impl = arg.substring(index + 1, arg.length());
-                    builder.provide(service, impl);
                 }
             }
+
+    private String injectExportTargets(String pn, String exp, int pos) {
+        Set<String> targets = exportsTo.remove(pn);
+        if (targets != null) {
+            StringBuilder sb = new StringBuilder();
+            // inject the extra targets after the given pos
+            sb.append(exp.substring(0, pos))
+              .append(targets.stream()
+                             .collect(Collectors.joining(", ", " ", ",")))
+              .append(" /* injected */");
+            if (pos < exp.length()) {
+                // print the remaining statement followed "to"
+                sb.append(exp.substring(pos+1, exp.length()));
+            }
+            return sb.toString();
+        } else {
+            return exp;
         }
     }
+
+    private void doAugments(PrintWriter writer) {
+        if ((exports.size() + exportsTo.size() + uses.size() + provides.size()) == 0)
+            return;
+
+        writer.println("    // augmented from module-info.java.extra");
+        exports.stream()
+            .sorted()
+            .forEach(e -> writer.format("    exports %s;%n", e));
+        // remaining injected qualified exports
+        exportsTo.entrySet().stream()
+            .sorted(Map.Entry.comparingByKey())
+            .map(e -> String.format("    exports %s to%n%s;", e.getKey(),
+                                    e.getValue().stream().sorted()
+                                        .map(mn -> String.format("        %s", mn))
+                                        .collect(Collectors.joining(",\n"))))
+            .forEach(writer::println);
+        uses.stream().sorted()
+            .forEach(s -> writer.format("    uses %s;%n", s));
+        provides.entrySet().stream()
+            .sorted(Map.Entry.comparingByKey())
+            .flatMap(e -> e.getValue().stream().sorted()
+                           .map(impl -> String.format("    provides %s with %s;",
+                                                      e.getKey(), impl)))
+            .forEach(writer::println);
+    }
 }
< prev index next >