src/share/classes/sun/module/tools/JRepo.java
Print this page
@@ -43,18 +43,19 @@
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.Comparator;
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 java.util.Set;
+import java.util.TreeSet;
import sun.module.repository.RepositoryConfig;
import sun.security.action.GetPropertyAction;
import sun.tools.jar.CommandLine;
/**
@@ -112,19 +113,20 @@
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();
+ /** Causes an individual command to print help and exit. */
+ private static final Flag helpFlag = new Flag('h');
/** Contains the flags that are common to all commands. */
private static final HashMap<Character, Flag> commonFlags = new HashMap<Character, Flag>();
static {
repositoryFlag.register(commonFlags);
verboseFlag.register(commonFlags);
+ helpFlag.register(commonFlags);
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
pw.printf(MAIFormat, "Name", "Version"); // XXX i18n
maiHeading = sw.toString();
@@ -142,14 +144,16 @@
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 DependenciesCommand().register(commands);
new InstallCommand().register(commands);
+ new HelpCommand().register(commands);
+ new ListCommand().register(commands);
new UninstallCommand().register(commands);
- new DependenciesCommand().register(commands);
+ new ValidateCommand().register(commands);
}
}
reset();
}
@@ -168,10 +172,15 @@
if (DEBUG && cmd != null) debug("running " + cmd);
if (cmd == null) {
return false;
}
+ if (helpFlag.isEnabled()) {
+ cmd.usageError(msg);
+ return true;
+ }
+
Repository repo = null;
try {
repo = getRepository();
repo.shutdownOnExit(true);
} catch (IOException ex) {
@@ -223,10 +232,11 @@
private void reset() {
moduleName = null;
parentFlag.reset();
repositoryFlag.reset();
verboseFlag.reset();
+ helpFlag.reset();
for (Command cmd : commands.values()) {
cmd.reset();
}
}
@@ -262,44 +272,37 @@
return null;
}
try {
int numFlags = cmd.parseFlags(args, commonFlags);
+ if (helpFlag.isEnabled()) {
+ return cmd;
+ }
+
args = Arrays.copyOfRange(args, numFlags + 1, args.length);
try {
if (cmd.parseArgs(args, msg)) {
return cmd;
} else {
- usageError();
+ cmd.usageError(msg);
return null;
}
} catch (ArrayIndexOutOfBoundsException e) {
usageError();
}
} catch (IllegalArgumentException ex) {
msg.error(ex.getMessage());
- usageError();
+ cmd.usageError(msg);
return null;
}
return cmd;
}
/** Returns a user-grokkable description of the repository. */
private static String getRepositoryText(Repository repo) {
String rc;
-/* URI u = repo.getSourceLocation();
- if (u == null) {
- rc = "Bootstrap repository";
- } else {
- try {
- rc = "Repository " + u.toURL().toExternalForm();
- } catch (MalformedURLException ex) {
- rc = "Repository unknown";
- }
- }
- */
rc = "[" + repo.toString() + "]";
return rc;
}
@@ -331,13 +334,10 @@
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
pw.printf(MDFormat, md.getName(), md.getVersion());
if (verboseFlag.isEnabled()) {
pw.printf(MDFormatVerbose,
-// md.getRepository() == Repository.getBootstrapRepository()
-// ? "bootstrap"
-// : md.getRepository().getSourceLocation().toString());
md.getRepository().getName());
}
return sw.toString();
}
@@ -430,47 +430,10 @@
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.
*/
@@ -502,11 +465,11 @@
/**
* Parse the Flags for this command.
* @return number of flags found.
* @throws IllegalArgumentException if an invalid flag is given.
*/
- int parseFlags(String[] args, Map<Character, Flag> flags) {
+/* int parseFlags(String[] args, Map<Character, Flag> flags) {
int rc = 0;
int i = 0;
while (i < args.length) {
String s = args[i];
if (s.length() == 2 && s.charAt(0) == '-') {
@@ -517,21 +480,57 @@
rc += numConsumed; // Increases only when the arg is a flag.
} else {
throw new IllegalArgumentException("unrecognized flag: " // XXX i18n
+ args[i]);
}
+ } if (s.charAt(0) == '-') {
+ throw new IllegalArgumentException("invalid flag: " // XXX i18n
+ + args[i]);
} else {
i++;
}
}
return rc;
}
+*/
+ int parseFlags(String[] args, Map<Character, Flag> flags) {
+ int rc = 0;
+ int i = 0;
+ while (i < args.length) {
+ String s = args[i];
+ if (s.charAt(0) == '-') {
+ if (s.length() == 2) {
+ Flag f = flags.get(s.charAt(1));
+ 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: " // XXX i18n
+ + args[i]);
+ }
+ } else {
+ throw new IllegalArgumentException("invalid flag: " // XXX i18n
+ + args[i]);
+ }
+ } else {
+ i++;
+ }
+ }
+ return rc;
+ }
/** Represents the actual behavior of the command. */
abstract boolean run(Repository repo, Messenger msg);
- /** Returns a usage string describing this command, or null if the
+ /** Prints command-specific usage message. */
+ void usageError(Messenger msg) {
+ msg.error("Synopsis for " + name + ": \n" + usage());
+ }
+
+ /**
+ *Returns a usage string describing this command, or null if the
* command is a synonym for another command.
*/
abstract String usage();
@Override
@@ -580,17 +579,15 @@
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);
@@ -609,13 +606,11 @@
}
if (args.length > 2) {
return false;
}
- if (DEBUG) debug("name: " + name + " ver: " + version
- + " plat: " + bindingFlag.getPlatform()
- + " arch: " + bindingFlag.getArch());
+ if (DEBUG) debug("name: " + name + " ver: " + version);
return true;
}
boolean run(Repository repo, Messenger msg) {
boolean rc = true;
@@ -622,33 +617,30 @@
if (name != null) {
VersionConstraint vc = (version == null
? VersionConstraint.DEFAULT
: version.toVersionConstraint());
printHeader(name, vc);
- rc = depend(repo, name, vc,
- bindingFlag.getPlatform(), bindingFlag.getArch());
+ rc = depend(repo, name, vc);
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());
+ rc &= depend(repo, maiName, vc);
printTrailer("\n");
}
}
return rc;
}
- boolean depend(Repository repo, String name, VersionConstraint constraint,
- String platform, String arch) {
+ boolean depend(Repository repo, String name, VersionConstraint constraint) {
ImportTraverser traverser = new ImportTraverser();
ImportTraverser.Visitor visitor = new ImportVisitor(traverser, msg);
try {
- traverser.traverse(visitor, repo, name, constraint, platform, arch);
+ traverser.traverse(visitor, repo, name, constraint);
if (traverser.traversedAny()) {
return true;
}
if (verboseFlag.isEnabled()) {
msg.error("Cannot find module " + name + " in " // XXX i18n
@@ -675,12 +667,12 @@
msg.print(s);
}
}
String usage() {
- return "dependencies [-v] [-r repositoryLocation] [-b platform-arch]"// XXX i18n
- + " [moduleName [moduleVersion] ]\n"
+ // XXX i18n
+ return "dependencies [-v] [-r repositoryLocation] [moduleName [moduleVersion] ]\n"
+ " Lists all modules on which identified modules depend.\n"
+ " If no moduleName is given, lists dependencies of all"
+ " module archives in the repository\n"
+ " which are instantiable on the current platform.";
}
@@ -734,18 +726,59 @@
void printModule(Module m) {
msg.println(indent + getMText(m));
}
}
+
+ /** Prints help. */
+ private class HelpCommand extends Command {
+ HelpCommand() {
+ super("help");
+ }
+
+ boolean parseArgs(String[] args, Messenger msg) {
+ return true;
+ }
+
+ boolean run(Repository repo, Messenger msg) {
+ JRepo.this.usageError(msg);
+ return true;
+ }
+
+ String usage() {
+ return "help\n Prints brief help text for all commands.\n"
+ + " Each command allows a -h option which gives help for that command.";
+ }
+ }
+
+
/** Installs a JAM into a repository. */
private class InstallCommand extends Command {
+ @SuppressWarnings("unchecked")
+ private final Map<Character, Flag> myFlags = (Map<Character, Flag>) commonFlags.clone();
+
+ /** When used, prevents checking of installed module's dependencies. */
+ private Flag quickInstallFlag = new Flag('q');
+
private String jamName;
InstallCommand() {
super("install");
+ quickInstallFlag.register(myFlags);
}
+ @Override
+ void reset() {
+ jamName = null;
+ quickInstallFlag.reset();
+ }
+
+ @Override
+ int parseFlags(String[] args, Map<Character, Flag> flags) {
+ return super.parseFlags(args, myFlags);
+ }
+
boolean parseArgs(String[] args, Messenger msg) {
boolean rc = false;
if (!parentFlag.isEnabled()
&& repositoryFlag.getLocation() != null
&& args.length == 1) {
@@ -778,11 +811,31 @@
try {
ModuleArchiveInfo mai = repo.install(new URL(jamURL).toURI());
if (verboseFlag.isEnabled()) {
msg.println("Installed " + jamName + ": " + getMAIText(mai));
}
+ if (!quickInstallFlag.isEnabled()) {
+ ModuleDefinition md = repo.find(
+ mai.getName(), mai.getVersion().toVersionConstraint());
+ if (md == null) {
+ msg.error("Warning: " + jamName
+ + " was installed but cannot be found");
+ } else {
+ try {
+ Module m = md.getModuleInstance();
+ } catch (ModuleInitializationException ex) {
+ msg.error("Cannot install " + ex.getMessage());
+ if (!repo.uninstall(mai)) {
+ msg.error("Could not uninstall " + mai);
+ }
+ return false;
+ }
+ }
+ }
return true;
+ } catch (IllegalStateException ex) {
+ msg.error("Cannot install " + jamName + ": " + ex.getMessage());
} catch (URISyntaxException ex) {
msg.error("Cannot install " + jamName + ": no such file, or malformed URI");
} catch (MalformedURLException ex) {
msg.error("Cannot install " + jamName + ": no such file, or malformed URL");
} catch (IOException ex) {
@@ -791,12 +844,12 @@
}
return false;
}
String usage() {
- return "install [-v] -r repositoryLocation jamFile | jamURL\n" // XXX i18n
- + " installs a module into a repository";
+ return "install [-v] [-q] -r repositoryLocation jamFile | jamURL\n" // XXX i18n
+ + " Installs a module into a repository.";
}
}
/** Uninstalls a module from a repository. */
private class UninstallCommand extends Command {
@@ -914,11 +967,11 @@
}
String usage() {
return "uninstall [-v] [-f | -i] -r repositoryLocation moduleName"// XXX i18n
+ " [moduleVersion] [modulePlatformBinding]\n"
- + " removes a module from a repository, along with associated files.";
+ + " 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) {
boolean rc = false;
@@ -1025,10 +1078,64 @@
}
return s;
}
}
+ /** Provides a way to sort ModuleArchiveInfo instances. */
+ static class MAIComparator implements Comparator<ModuleArchiveInfo> {
+ private static final MAIComparator instance = new MAIComparator();
+
+ private MAIComparator() { }
+
+ static MAIComparator getInstance() {
+ return instance;
+ }
+
+ public int compare(ModuleArchiveInfo o1, ModuleArchiveInfo o2) {
+ int rc = o1.getName().compareTo(o2.getName());
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = o1.getVersion().compareTo(o2.getVersion());
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = compareStrings(o1.getPlatform(), o2.getPlatform());
+ if (rc != 0) {
+ return rc;
+ }
+
+ return compareStrings(o1.getArch(), o2.getArch());
+ }
+
+ // Compare two Strings. If neither is null, compare them
+ // lexicographically. If both are null, return 0. If the first is
+ // null, return -1; else 1.
+ private int compareStrings(String s1, String s2) {
+ int rc = 0;
+ if (s2 != null && s2 != null) {
+ rc = s1.compareTo(s2);
+ if (rc != 0) {
+ return rc;
+ }
+ }
+ if (s1 == null) {
+ return -1;
+ } else if (s2 == null) {
+ return 1;
+ }
+ return 0;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return this == o;
+ }
+ }
+
/** Prints information about modules found in repositories. */
private class ListCommand extends Command {
@SuppressWarnings("unchecked")
private final Map<Character, Flag> myFlags = (Map<Character, Flag>) commonFlags.clone();
@@ -1073,12 +1180,13 @@
}
return found;
}
String usage() {
- return "list [-v] [-p] [-r repositoryLocation] moduleName\n"// XXX i18n
- + " lists the modules in the repository";
+ return "list [-v] [-p] [-r repositoryLocation] [moduleName]\n"// XXX i18n
+ + " Lists the modules in the repository that match the given name.\n"
+ + " If no moduleName is given, lists all modules in the repository.";
}
class ListRepositoryVisitor extends RepositoryVisitor {
private boolean found = false;
@@ -1089,11 +1197,14 @@
List<ModuleArchiveInfo> maiList = repo.list();
if (maiList.size() == 0 && verboseFlag.isEnabled()) {
msg.println(getRepositoryText(repo));
msg.println(" empty");
} else {
- for (ModuleArchiveInfo mai : repo.list()) {
+ TreeSet<ModuleArchiveInfo> sorted =
+ new TreeSet<ModuleArchiveInfo>(MAIComparator.getInstance());
+ sorted.addAll(repo.list());
+ for (ModuleArchiveInfo mai : sorted) {
if (moduleName == null || mai.getName().startsWith(moduleName)) {
if (!printedHeader) {
msg.println(getRepositoryText(repo));
msg.println(verboseFlag.isEnabled() ? maiHeadingVerbose : maiHeading);
printedHeader = true;
@@ -1104,6 +1215,117 @@
}
}
}
}
}
+
+ /** Runs shallow and/or deep validation on one or more modules. */
+ class ValidateCommand extends Command {
+ @SuppressWarnings("unchecked")
+ private final Map<Character, Flag> myFlags = (Map<Character, Flag>) commonFlags.clone();
+
+ /** Indicates that deep validation should be run. */
+ private Flag deepValidateFlag = new Flag('d');
+
+ private String name;
+ private Version version;
+
+ ValidateCommand() {
+ super("validate");
+ deepValidateFlag.register(myFlags);
+ }
+
+ @Override
+ void reset() {
+ deepValidateFlag.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);
+ return true;
+ }
+
+ boolean run(Repository repo, Messenger msg) {
+ boolean rc = true;
+ if (name != null) {
+ VersionConstraint vc = (version == null
+ ? VersionConstraint.DEFAULT
+ : version.toVersionConstraint());
+
+ List<ModuleDefinition> mdList = repo.find(Query.module(name, vc));
+ if (mdList.size() == 1) {
+ rc = validate(mdList.get(0), msg);
+ } else {
+ throw new IllegalArgumentException(
+ "more than one matching module found for name=" + name
+ + " version=" + vc);
+ }
+ } else {
+ for (ModuleDefinition md : repo.findAll()) {
+ rc &= validate(md, msg);
+ }
+ }
+ return rc;
+ }
+
+ /** @return true if the module passes validation validation. */
+ boolean validate(ModuleDefinition md, Messenger msg) {
+ boolean rc = false;
+ try {
+ Module m = md.getModuleInstance();
+ if (deepValidateFlag.isEnabled()) {
+ if (m.supportsDeepValidation()) {
+ try {
+ m.deepValidate();
+ if (verboseFlag.isEnabled()) {
+ msg.println(
+ "Module " + m + " passed deep validation"); // XXX i18n
+ }
+ rc = true;
+ } catch (ModuleInitializationException ex) {
+ msg.error(
+ "Module " + m + " failed deep validation"); // XXX i18n
+ }
+ }
+ } else {
+ // Module was instantiated => passed shallow validation
+ if (verboseFlag.isEnabled()) {
+ msg.println(
+ "Module " + m + " passed shallow validation"); // XXX i18n
+ }
+ rc = true;
+ }
+ } catch (ModuleInitializationException ex) {
+ msg.error("Could not initialize module for " + md // XXX i18n
+ + ": " + ex.getMessage());
+ }
+ return rc;
+ }
+
+ String usage() {
+ // XXX i18n
+ return "validate [-v] [-d] [-r repositoryLocation] [moduleName [moduleVersion] ]\n"
+ + " Runs deep validation on the identified modules.\n"
+ + " If no moduleName is given, validates all module"
+ + " archives in the repository.\n";
+ }
+ }
}