/* * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions.
*/
/** * A task to configure and run the jar file utility.
*/ publicclass JarTask extends AbstractTask<JarTask> { private Path jar; private Manifest manifest; private String classpath; private String mainClass; private Path baseDir; private List<Path> paths; private Set<FileObject> fileObjects;
/** * Creates a task to write jar files, using API mode. * @param toolBox the {@code ToolBox} to use
*/ public JarTask(ToolBox toolBox) { super(toolBox, Task.Mode.API);
paths = Collections.emptyList();
fileObjects = new LinkedHashSet<>();
}
/** * Creates a JarTask for use with a given jar file. * @param toolBox the {@code ToolBox} to use * @param path the file
*/ public JarTask(ToolBox toolBox, String path) { this(toolBox);
jar = Paths.get(path);
}
/** * Creates a JarTask for use with a given jar file. * @param toolBox the {@code ToolBox} to use * @param path the file
*/ public JarTask(ToolBox toolBox, Path path) { this(toolBox);
jar = path;
}
/** * Sets a manifest for the jar file. * @param manifest the manifest * @return this task object
*/ public JarTask manifest(Manifest manifest) { this.manifest = manifest; returnthis;
}
/** * Sets a manifest for the jar file. * @param manifest a string containing the contents of the manifest * @return this task object * @throws IOException if there is a problem creating the manifest
*/ public JarTask manifest(String manifest) throws IOException { this.manifest = new Manifest(new ByteArrayInputStream(manifest.getBytes())); returnthis;
}
/** * Sets the classpath to be written to the {@code Class-Path} * entry in the manifest. * @param classpath the classpath * @return this task object
*/ public JarTask classpath(String classpath) { this.classpath = classpath; returnthis;
}
/** * Sets the class to be written to the {@code Main-Class} * entry in the manifest.. * @param mainClass the name of the main class * @return this task object
*/ public JarTask mainClass(String mainClass) { this.mainClass = mainClass; returnthis;
}
/** * Sets the base directory for files to be written into the jar file. * @param baseDir the base directory * @return this task object
*/ public JarTask baseDir(String baseDir) { this.baseDir = Paths.get(baseDir); returnthis;
}
/** * Sets the base directory for files to be written into the jar file. * @param baseDir the base directory * @return this task object
*/ public JarTask baseDir(Path baseDir) { this.baseDir = baseDir; returnthis;
}
/** * Sets the files to be written into the jar file. * @param files the files * @return this task object
*/ public JarTask files(String... files) { this.paths = Stream.of(files)
.map(file -> Paths.get(file))
.collect(Collectors.toList()); returnthis;
}
/** * Adds a set of file objects to be written into the jar file, by copying them * from a Location in a JavaFileManager. * The file objects to be written are specified by a series of paths; * each path can be in one of the following forms: * <ul> * <li>The name of a class. For example, java.lang.Object. * In this case, the corresponding .class file will be written to the jar file. * <li>the name of a package followed by {@code .*}. For example, {@code java.lang.*}. * In this case, all the class files in the specified package will be written to * the jar file. * <li>the name of a package followed by {@code .**}. For example, {@code java.lang.**}. * In this case, all the class files in the specified package, and any subpackages * will be written to the jar file. * </ul> * * @param fm the file manager in which to find the file objects * @param l the location in which to find the file objects * @param paths the paths specifying the file objects to be copied * @return this task object * @throws IOException if errors occur while determining the set of file objects
*/ public JarTask files(JavaFileManager fm, JavaFileManager.Location l, String... paths) throws IOException { for (String p : paths) { if (p.endsWith(".**"))
addPackage(fm, l, p.substring(0, p.length() - 3), true); elseif (p.endsWith(".*"))
addPackage(fm, l, p.substring(0, p.length() - 2), false); else
addFile(fm, l, p);
} returnthis;
}
/** * Provides limited jar command-like functionality. * The supported commands are: * <ul> * <li> jar cf jarfile -C dir files... * <li> jar cfm jarfile manifestfile -C dir files... * </ul> * Any values specified by other configuration methods will be ignored. * @param args arguments in the style of those for the jar command * @return a Result object containing the results of running the task
*/ public Task.Result run(String... args) { if (args.length < 2) thrownew IllegalArgumentException();
ListIterator<String> iter = Arrays.asList(args).listIterator();
String first = iter.next(); switch (first) { case"cf":
jar = Paths.get(iter.next()); break; case"cfm":
jar = Paths.get(iter.next()); try (InputStream in = Files.newInputStream(Paths.get(iter.next()))) {
manifest = new Manifest(in);
} catch (IOException e) { thrownew IOError(e);
} break;
}
if (iter.hasNext()) { if (iter.next().equals("-C"))
baseDir = Paths.get(iter.next()); else
iter.previous();
}
paths = new ArrayList<>(); while (iter.hasNext())
paths.add(Paths.get(iter.next()));
return run();
}
/** * {@inheritDoc} * @return the name "jar"
*/
@Override public String name() { return"jar";
}
/** * Creates a jar file with the arguments as currently configured. * @return a Result object indicating the outcome of the compilation * and the content of any output written to stdout, stderr, or the * main stream by the compiler. * @throws TaskError if the outcome of the task is not as expected.
*/
@Override public Task.Result run() {
Manifest m = (manifest == null) ? new Manifest() : manifest;
Attributes mainAttrs = m.getMainAttributes(); if (mainClass != null)
mainAttrs.put(Attributes.Name.MAIN_CLASS, mainClass); if (classpath != null)
mainAttrs.put(Attributes.Name.CLASS_PATH, classpath);
AbstractTask.StreamOutput sysOut = new AbstractTask.StreamOutput(System.out, System::setOut);
AbstractTask.StreamOutput sysErr = new AbstractTask.StreamOutput(System.err, System::setErr);
Map<Task.OutputKind, String> outputMap = new HashMap<>();
privatevoid writeFiles(JarOutputStream jos) throws IOException {
Path base = (baseDir == null) ? currDir : baseDir; for (Path path : paths) {
Files.walkFileTree(base.resolve(path), new SimpleFileVisitor<Path>() {
@Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { try {
String p = base.relativize(file)
.normalize()
.toString()
.replace(File.separatorChar, '/');
JarEntry e = new JarEntry(p);
jos.putNextEntry(e); try {
jos.write(Files.readAllBytes(file));
} finally {
jos.closeEntry();
} return FileVisitResult.CONTINUE;
} catch (IOException e) {
error("Exception while adding " + file + " to jar file", e); return FileVisitResult.TERMINATE;
}
}
});
}
}
privatevoid writeFileObjects(JarOutputStream jos) throws IOException { for (FileObject fo : fileObjects) {
String p = guessPath(fo);
JarEntry e = new JarEntry(p);
jos.putNextEntry(e); try { byte[] buf = newbyte[1024]; try (BufferedInputStream in = new BufferedInputStream(fo.openInputStream())) { int n; while ((n = in.read(buf)) > 0)
jos.write(buf, 0, n);
} catch (IOException ex) {
error("Exception while adding " + fo.getName() + " to jar file", ex);
}
} finally {
jos.closeEntry();
}
}
}
/* * A jar: URL is of the form jar:URL!/<entry> where URL is a URL for the .jar file itself. * In Symbol files (i.e. ct.sym) the underlying entry is prefixed META-INF/sym/<base>.
*/ privatefinal Pattern jarEntry = Pattern.compile(".*!/(?:META-INF/sym/[^/]+/)?(.*)");
/* * A jrt: URL is of the form jrt:/<module>/<package>/<file>
*/ privatefinal Pattern jrtEntry = Pattern.compile("/([^/]+)/(.*)");
/* * A file: URL is of the form file:/path/to/{modules,patches}/<module>/<package>/<file>
*/ privatefinal Pattern fileEntry = Pattern.compile(".*/(?:modules|patches)/([^/]+)/(.*)");
private String guessPath(FileObject fo) {
URI u = fo.toUri(); switch (u.getScheme()) { case"jar": {
Matcher m = jarEntry.matcher(u.getSchemeSpecificPart()); if (m.matches()) { return m.group(1);
} break;
} case"jrt": {
Matcher m = jrtEntry.matcher(u.getSchemeSpecificPart()); if (m.matches()) { return m.group(2);
} break;
} case"file": {
Matcher m = fileEntry.matcher(u.getSchemeSpecificPart()); if (m.matches()) { return m.group(2);
} break;
}
} thrownew IllegalArgumentException(fo.getName() + "--" + fo.toUri());
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.