src/share/classes/sun/module/tools/JRepo.java

Print this page

        

@@ -28,26 +28,31 @@
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStreamReader;
+import java.io.OutputStream;
 import java.io.PrintStream;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.module.*;
+import java.module.annotation.ImportPolicyClass;
 import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.text.DateFormat;
 import java.util.Arrays;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-import sun.module.JamUtils;
+import java.util.Set;
 import sun.module.repository.RepositoryConfig;
 import sun.security.action.GetPropertyAction;
 import sun.tools.jar.CommandLine;
 
 /**

@@ -75,16 +80,22 @@
     private static final Map<String, Command> commands = new LinkedHashMap<String, Command>();
 
     /** Usage message created from each command's usage. */
     private static String usage = null;
 
-    /** Format for module name & version. */
+    /** Format for ModuleArchiveInfo name & version. */
     private static final String MAIFormat = "%-20s %-20s";
 
-    /** Format for additional/verbose module information. */
+    /** Format for additional/verbose ModuleArchiveInfo details. */
     private static final String MAIFormatVerbose = " %-9s %-7s %-17s %s";
 
+    /** Format for ModuleDefinition name & version. */
+    private static final String MDFormat = "%s-%s";
+
+    /** Format for additional/verbose ModuleDefinition details. */
+    private static final String MDFormatVerbose = " %s";
+
     /** String containing column headings for name & version. */
     private static final String maiHeading;
 
     /** String containing column headings for additional/verbose module information. */
     private static final String maiHeadingVerbose;

@@ -96,10 +107,16 @@
     private static final Flag verboseFlag = new Flag('v');
 
     /** Location of repository; if not given uses system repository. */
     private static final RepositoryFlag repositoryFlag = new RepositoryFlag();
 
+    /** Indicates dependencies command should display info on core modules. */
+    private static final Flag javaseFlag = new Flag('j');
+
+    /** Provides way to specify platform binding fo dependencies command. */
+    private static final BindingFlag bindingFlag = new BindingFlag();
+
     /** Contains the flags that are common to all commands. */
     private static final HashMap<Character, Flag> commonFlags = new HashMap<Character, Flag>();
 
     static {
         repositoryFlag.register(commonFlags);

@@ -115,17 +132,22 @@
         pw.printf(MAIFormat, "Name", "Version"); // XXX i18n
         pw.printf(MAIFormatVerbose, "Platform", "Arch", "Modified", "Filename"); // XXX i18n
         maiHeadingVerbose = sw.toString();
     }
 
+    public JRepo(OutputStream out, OutputStream err, BufferedReader reader) {
+        this(new PrintStream(out), new PrintStream(err), reader);
+    }
+
     public JRepo(PrintStream out, PrintStream err, BufferedReader reader) {
         msg = new Messenger("jrepo", out, err, reader);
         synchronized(commands) {
             if (commands.isEmpty()) {
                 new ListCommand().register(commands);
                 new InstallCommand().register(commands);
                 new UninstallCommand().register(commands);
+                new DependenciesCommand().register(commands);
             }
         }
         reset();
     }
 

@@ -185,11 +207,12 @@
                     rc = Modules.newLocalRepository(
                         RepositoryConfig.getSystemRepository(),
                         "jrepo",
                         f.getCanonicalFile());
                 } else {
-                    throw new IOException("Cannot access repository at " + repositoryLocation);
+                    throw new IOException("Cannot access repository at " // XXX i18n
+                                          + repositoryLocation); 
                 }
             }
         }
         return rc;
     }

@@ -258,22 +281,22 @@
         return cmd;
     }
 
 
     /** Returns a user-grokkable description of the repository. */
-    private String getRepositoryText(Repository repo) {
+    private static String getRepositoryText(Repository repo) {
         String rc;
         URL u = repo.getSourceLocation();
         if (u == null) {
             rc = "Bootstrap repository";
         } else {
-            rc = "Repository " + u.toExternalForm();
+                        rc = "Repository '" + repo.getName() + "' at " + u.toExternalForm();
         }
         return rc;
     }
 
-    private String getMAIText(ModuleArchiveInfo mai) {
+    private static String getMAIText(ModuleArchiveInfo mai) {
         StringWriter sw = new StringWriter();
         PrintWriter pw = new PrintWriter(sw);
         pw.printf(MAIFormat, mai.getName(), mai.getVersion());
         if (verboseFlag.isEnabled()) {
             long t = mai.getLastModified();

@@ -289,18 +312,34 @@
                 );
         }
         return sw.toString();
     }
 
+    private static String getMText(Module m) {
+        return getMDText(m.getModuleDefinition());
+    }
+    
+    private static String getMDText(ModuleDefinition md) {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        pw.printf(MDFormat, md.getName(), md.getVersion());
+        if (verboseFlag.isEnabled()) {
+            URL srcLoc = md.getRepository().getSourceLocation();
+            pw.printf(MDFormatVerbose,
+                      srcLoc == null ? "bootstrap" : srcLoc.toString());
+        }
+        return sw.toString();
+    }
+
     void usageError() {
         usageError(msg);
     }
 
     static void usageError(Messenger msg) {
         if (usage == null) {
             StringBuilder ub = new StringBuilder(
-                "Usage: jrepo <command>\nwhere <command> includes:");
+                "Usage: jrepo <command>\nwhere <command> includes:"); // XXX i18n
             for (Command c : commands.values()) {
                 String u = c.usage();
                 if (u != null) {
                     ub.append("\n    ").append(c.usage());
                 }

@@ -311,11 +350,11 @@
     }
 
     /**
      * Represents a flag given on the command line.  Flags always are 2
      * characters long, and start with a '-'.  They can have additional
-     * associated arguments (cf RepositoryFlag).
+     * associated arguments (cf {@link #RepositoryFlag}).
      */
     private static class Flag {
         private final char name;
 
         private boolean enabled = false;

@@ -334,11 +373,11 @@
         char getName() {
             return name;
         }
 
         /** @return the number of arguments consumed by this Flag. */
-        int set(String[] args, int pos) {
+        int set(String[] args, int pos) throws IllegalArgumentException {
             enabled = true;
             return 1;
         }
 
         void reset() {

@@ -359,26 +398,65 @@
 
         RepositoryFlag() {
             super('r');
         }
 
-        int set(String[] args, int pos) {
+        @Override
+        int set(String[] args, int pos) throws IllegalArgumentException {
             int rc = super.set(args, pos);
             location = args[pos + 1];
             return rc + 1;
         }
 
         String getLocation() {
             return location;
         }
 
+        @Override
         void reset() {
             super.reset();
             location = null;
         }
     }
 
+    private static class BindingFlag extends Flag {
+        String platform;
+        String arch;
+
+        BindingFlag() {
+            super('b');
+        }
+
+        @Override
+        int set(String[] args, int pos) throws IllegalArgumentException {
+            int rc = super.set(args, pos);
+            String[] binding = args[pos + 1].split("-");
+            if (binding.length != 2) {
+                throw new IllegalArgumentException(
+                    "Must 2 and only 2 elements for platform-arch");
+            }
+            platform = binding[0];
+            arch = binding[1];
+            return rc + 1;
+        }
+
+        String getPlatform() {
+            return platform;
+        }
+
+        String getArch() {
+            return arch;
+        }
+
+        @Override
+        void reset() {
+            super.reset();
+            platform = null;
+            arch = null;
+        }
+    }
+
     /*
      * Command types: An abstract base class, plus one concrete class for
      * each Command.
      */
 

@@ -422,11 +500,12 @@
                     if (f != null) {
                         int numConsumed = f.set(args, i);
                         i += numConsumed;  // Increases at each iteration.
                         rc += numConsumed; // Increases only when the arg is a flag.
                     } else {
-                        throw new IllegalArgumentException("unrecognized flag: " + args[i]);
+                        throw new IllegalArgumentException("unrecognized flag: " // XXX i18n
+                                                           + args[i]);
                     }
                 } else {
                     i++;
                 }
             }

@@ -439,10 +518,11 @@
         /** Returns a usage string describing this command, or null if the
          * command is a synonym for another command.
          */
         abstract String usage();
 
+        @Override
         public String toString() { return name; }
 
         /**
          * RepositoryVisitor types walk a parent chain of repositories, invoking
          * {@code doit} in each one.  The abstract base class provides the recursion;

@@ -451,13 +531,13 @@
          * and the system repository is last.
          */
         abstract class RepositoryVisitor {
             abstract void doit(Repository repo, Messenger msg);
 
-            void doBefore(Messenger msg) { }
+            void preVisit(Messenger msg) { }
 
-            void doAfter(Messenger msg) { }
+            void postVisit(Messenger msg) { }
 
             final void run(Repository repo, Messenger msg) {
                 visit(repo, msg);
             }
 

@@ -464,17 +544,183 @@
             private final void visit(Repository repo, Messenger msg) {
                 Repository parent = parentFlag.isEnabled() ? repo.getParent() : null;
                 if (parent != null) {
                     visit(parent, msg);
                 }
-                doBefore(msg);
+                preVisit(msg);
                 doit(repo, msg);
-                doAfter(msg);
+                postVisit(msg);
             }
         }
     }
 
+
+    /** Lists dependencies of a module. */
+    private class DependenciesCommand extends Command {
+        @SuppressWarnings("unchecked")
+        private final Map<Character, Flag> myFlags = (Map<Character, Flag>) commonFlags.clone();
+
+        private String name;
+        private Version version;
+
+        // For printing module name, version.
+        private String moduleString;
+
+        DependenciesCommand() {
+            super("dependencies");
+            javaseFlag.register(myFlags);
+            bindingFlag.register(myFlags);
+        }
+
+        @Override
+        void reset() {
+            javaseFlag.reset();
+            bindingFlag.reset();
+        }
+        
+        @Override
+        int parseFlags(String[] args, Map<Character, Flag> flags) {
+            return super.parseFlags(args, myFlags);
+        }
+
+        boolean parseArgs(String[] args, Messenger msg) {
+            if (args.length > 0) {
+                name = args[0];
+            }
+            if (args.length > 1) {
+                try {
+                    version = Version.valueOf(args[1]);
+                } catch (IllegalArgumentException ex) {
+                    return false;
+                }
+            }
+            if (args.length > 2) {
+                return false;
+            }
+            
+            if (DEBUG) debug("name: " + name + " ver: " + version
+                             + " plat: " + bindingFlag.getPlatform()
+                             + " arch: " + bindingFlag.getArch());
+            return true;
+        }
+
+        boolean run(Repository repo, Messenger msg) {
+            boolean rc = true;
+            if (name != null) {
+                VersionConstraint vc = (version == null
+                                        ? VersionConstraint.DEFAULT
+                                        : version.toVersionConstraint());
+                printHeader(name, vc);
+                rc = depend(repo, name, vc,
+                            bindingFlag.getPlatform(), bindingFlag.getArch());
+                printTrailer(null);
+            } else {
+                for (ModuleArchiveInfo mai : repo.list()) {
+                    reset();
+                    String maiName = mai.getName();
+                    VersionConstraint vc = mai.getVersion().toVersionConstraint();
+                    printHeader(maiName, vc);
+                    rc &= depend(repo, maiName, vc,
+                                 mai.getPlatform(), mai.getArch());
+                    printTrailer("\n");
+                }
+            }
+            return rc;
+        }
+
+        boolean depend(Repository repo, String name, VersionConstraint constraint,
+                       String platform, String arch) {
+            ImportTraverser iv = new JRepoImportTraverser(msg);
+            try {
+                iv.visit(repo, name, constraint, platform, arch);
+                for (Module dep : iv) {
+                    // If any modules were found, traversal was successful
+                    return true;
+                }
+                if (verboseFlag.isEnabled()) {
+                    msg.error("Cannot find module " + name + " in " // XXX i18n
+                              + getRepositoryText(repo));
+                }
+                return false;
+            } catch (ModuleInitializationException ex) {
+                msg.error("Cannot instantiate module for " + name // XXX i18n
+                          + ": " + ex);
+                return false;
+            }
+        }
+
+        
+        void printHeader(String name, VersionConstraint vc) {
+            if (verboseFlag.isEnabled()) {
+                msg.println("Dependencies for " // XXXi18n
+                            + name + "-" + vc + ":");
+            }
+        }
+
+        void printTrailer(String s) {
+            if (verboseFlag.isEnabled()) {
+                msg.print(s);
+            }
+        }
+        
+        // TBD support platform binding.  Ideally, want to allow specifying
+        // version, or binding, or both.
+        String usage() {
+            return "dependencies [-v] [-r repositoryLocation] [-b platform-arch]"// XXX i18n
+                + " [moduleName [moduleVersion] ]\n"
+                + "        Lists all modules on which identified modules depend.\n"
+                + "        If no moduleName is given, lists dependencies of all"
+                + " modules in the repository.";
+        }
+    }
+            
+
+    private static class JRepoImportTraverser extends ImportTraverser {
+        private final Messenger msg;
+        
+        private String indent = "";
+
+        JRepoImportTraverser(Messenger msg) {
+            this.msg = msg;
+        }
+
+        @Override
+        protected void init(Module m) {
+            printModule(m);
+        }
+
+        @Override
+        protected boolean preVisit(Module m) {
+            if (javaseFlag.isEnabled() == false
+                && "java.se".equals(m.getModuleDefinition().getName())) {
+                return false;
+            } else {
+                indent += "    ";
+                return true;
+            }
+        }
+
+        @Override
+        protected void visit(Module m) {
+            printModule(m);
+        }
+
+        @Override
+        protected void postVisit(Module m) {
+            if (javaseFlag.isEnabled() == false
+                && "java.se".equals(m.getModuleDefinition().getName())) {
+                // empty
+            } else {
+                indent = indent.substring(4);
+            }
+        }
+
+        void printModule(Module m) {
+            msg.println(indent + getMText(m));
+        }
+    }
+
     /** Installs a JAM into a repository. */
     private class InstallCommand extends Command {
         private String jamName;
 
         InstallCommand() {

@@ -526,11 +772,11 @@
             }
             return false;
         }
 
         String usage() {
-            return "install [-v] -r repositoryLocation jamFile | jamURL\n"
+            return "install [-v] -r repositoryLocation jamFile | jamURL\n" // XXX i18n
                 +  "        installs a module into a repository";
         }
     }
 
     /** Uninstalls a module from a repository. */

@@ -552,17 +798,19 @@
             super("uninstall");
             forceFlag.register(myFlags);
             interactiveFlag.register(myFlags);
         }
 
+        @Override
         void reset() {
             version = null;
             platformBinding = null;
             forceFlag.reset();
             interactiveFlag.reset();
         }
 
+        @Override
         int parseFlags(String[] args, Map<Character, Flag> flags) {
             return super.parseFlags(args, myFlags);
         }
 
         boolean parseArgs(String[] args, Messenger msg) {

@@ -645,11 +893,12 @@
             }
             return rc;
         }
 
         String usage() {
-            return "uninstall [-v] [-f | -i] -r repositoryLocation moduleName [moduleVersion] [modulePlatformBinding]\n"
+            return "uninstall [-v] [-f | -i] -r repositoryLocation moduleName"// XXX i18n
+                + " [moduleVersion] [modulePlatformBinding]\n"
                 +  "        removes a module from a repository, along with associated files.";
         }
 
         /** Uninstall the ModuleArchiveInfo from the Repository. */
         private boolean uninstall(Repository repo, ModuleArchiveInfo mai, Messenger msg) {

@@ -657,13 +906,13 @@
             if (DEBUG) debug("Uninstalling " + getMAIText(mai));
             try {
                 rc = repo.uninstall(mai);
                 if (verboseFlag.isEnabled()) {
                     if (rc) {
-                        msg.println("Uninstalled " + getMAIText(mai));
+                        msg.println("Uninstalled " + getMAIText(mai)); // XXX i18n
                     } else {
-                        msg.error("Failed to uninstall " + getMAIText(mai));
+                        msg.error("Failed to uninstall " + getMAIText(mai)); // XXX i18n
                     }
                 }
             } catch (Exception ex) {
                 msg.error("Exception while uninstalling " + getInfo()
                           + ": " + ex.getMessage());

@@ -767,14 +1016,16 @@
         ListCommand() {
             super("list");
             parentFlag.register(myFlags);
         }
 
+        @Override
         void reset() {
             parentFlag.reset();
         }
 
+        @Override
         int parseFlags(String[] args, Map<Character, Flag> flags) {
             return super.parseFlags(args, myFlags);
         }
 
         boolean parseArgs(String[] args, Messenger msg){

@@ -793,20 +1044,23 @@
             ListRepositoryVisitor visitor = new ListRepositoryVisitor();
             visitor.run(repo, msg);
             boolean found = visitor.wasFound();
             if (verboseFlag.isEnabled() && !found) {
                 if (moduleName != null) {
-                    msg.error("Could not find module name starting with '" + moduleName + "'");
+                    msg.error("Could not find module name starting with '"// 
+                                                                          // XXX i18n
+                              + moduleName + "'");
                 } else {
-                    msg.error("Could not find any modules");
+                    msg.error("Could not find any modules"); // XXX i18n
                 }
             }
             return found;
         }
 
         String usage() {
-            return "list [-v] [-p] [-r repositoryLocation] moduleName\n"
+            return "list [-v] [-p] [-r repositoryLocation] moduleName\n"// 
+                                                                        // XXX i18n
                 +  "        lists the modules in the repository";
         }
 
         class ListRepositoryVisitor extends RepositoryVisitor {
             private boolean found = false;

@@ -813,10 +1067,15 @@
 
             boolean wasFound() { return found; }
 
             void doit(Repository repo, Messenger msg) {
                 boolean printedHeader = false;
+                List<ModuleArchiveInfo> maiList = repo.list();
+                if (maiList.size() == 0 && verboseFlag.isEnabled()) {
+                    msg.println(getRepositoryText(repo));
+                    msg.println("   empty");
+                } else {
                 for (ModuleArchiveInfo mai : repo.list()) {
                     if (moduleName == null || mai.getName().startsWith(moduleName)) {
                         if (!printedHeader) {
                             msg.println(getRepositoryText(repo));
                             msg.println(verboseFlag.isEnabled() ? maiHeadingVerbose : maiHeading);

@@ -824,9 +1083,10 @@
                         }
                         msg.println(getMAIText(mai));
                         found = true;
                     }
                 }
+                }
             }
         }
     }
 }