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;
}
}
+ }
}
}
}
}