8293499: Provide jmod --compress option
Reviewed-by: alanb, mchung, jpai, redestad
This commit is contained in:
parent
26e08cf3d0
commit
43f7f47ae0
@ -55,16 +55,17 @@ class JmodOutputStream extends OutputStream implements AutoCloseable {
|
||||
* This method creates (or overrides, if exists) the JMOD file,
|
||||
* returning the output stream to write to the JMOD file.
|
||||
*/
|
||||
static JmodOutputStream newOutputStream(Path file, LocalDateTime date) throws IOException {
|
||||
static JmodOutputStream newOutputStream(Path file, LocalDateTime date, int compressLevel) throws IOException {
|
||||
OutputStream out = Files.newOutputStream(file);
|
||||
BufferedOutputStream bos = new BufferedOutputStream(out);
|
||||
return new JmodOutputStream(bos, date);
|
||||
return new JmodOutputStream(bos, date, compressLevel);
|
||||
}
|
||||
|
||||
private final ZipOutputStream zos;
|
||||
private final LocalDateTime date;
|
||||
private JmodOutputStream(OutputStream out, LocalDateTime date) {
|
||||
private JmodOutputStream(OutputStream out, LocalDateTime date, int compressLevel) {
|
||||
this.zos = new ZipOutputStream(out);
|
||||
this.zos.setLevel(compressLevel);
|
||||
this.date = date;
|
||||
try {
|
||||
JmodFile.writeMagicNumber(out);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2022, 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
|
||||
@ -60,6 +60,7 @@ import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.Deflater;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipException;
|
||||
import java.util.zip.ZipFile;
|
||||
@ -167,6 +168,7 @@ public class JmodTask {
|
||||
List<PathMatcher> excludes;
|
||||
Path extractDir;
|
||||
LocalDateTime date;
|
||||
int compressLevel;
|
||||
}
|
||||
|
||||
// Valid --date range
|
||||
@ -438,7 +440,7 @@ public class JmodTask {
|
||||
Path target = options.jmodFile;
|
||||
Path tempTarget = jmodTempFilePath(target);
|
||||
try {
|
||||
try (JmodOutputStream jos = JmodOutputStream.newOutputStream(tempTarget, options.date)) {
|
||||
try (JmodOutputStream jos = JmodOutputStream.newOutputStream(tempTarget, options.date, options.compressLevel)) {
|
||||
jmod.write(jos);
|
||||
}
|
||||
Files.move(tempTarget, target);
|
||||
@ -1024,7 +1026,7 @@ public class JmodTask {
|
||||
{
|
||||
|
||||
try (JmodFile jf = new JmodFile(target);
|
||||
JmodOutputStream jos = JmodOutputStream.newOutputStream(tempTarget, options.date))
|
||||
JmodOutputStream jos = JmodOutputStream.newOutputStream(tempTarget, options.date, options.compressLevel))
|
||||
{
|
||||
jf.stream().forEach(e -> {
|
||||
try (InputStream in = jf.getInputStream(e.section(), e.name())) {
|
||||
@ -1179,6 +1181,33 @@ public class JmodTask {
|
||||
@Override public String valuePattern() { return "date"; }
|
||||
}
|
||||
|
||||
static class CompLevelConverter implements ValueConverter<Integer> {
|
||||
@Override
|
||||
public Integer convert(String value) {
|
||||
int idx = value.indexOf("-");
|
||||
int lastIdx = value.lastIndexOf("-");
|
||||
if (idx == -1 || idx != lastIdx) {
|
||||
throw new CommandException("err.compress.incorrect", value);
|
||||
}
|
||||
if (!value.substring(0, idx).equals("zip")) {
|
||||
throw new CommandException("err.compress.incorrect", value);
|
||||
}
|
||||
try {
|
||||
int level = Integer.parseInt(value.substring(idx + 1));
|
||||
if (level < 0 || level > 9) {
|
||||
throw new CommandException("err.compress.incorrect", value);
|
||||
}
|
||||
return level;
|
||||
} catch (NumberFormatException x) {
|
||||
throw new CommandException("err.compress.incorrect", value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public Class<Integer> valueType() { return Integer.class; }
|
||||
|
||||
@Override public String valuePattern() { return "compress"; }
|
||||
}
|
||||
|
||||
static class WarnIfResolvedReasonConverter
|
||||
implements ValueConverter<ModuleResolution>
|
||||
{
|
||||
@ -1419,6 +1448,11 @@ public class JmodTask {
|
||||
.withRequiredArg()
|
||||
.withValuesConvertedBy(new DateConverter());
|
||||
|
||||
OptionSpec<Integer> compress
|
||||
= parser.accepts("compress", getMessage("main.opt.compress"))
|
||||
.withRequiredArg()
|
||||
.withValuesConvertedBy(new CompLevelConverter());
|
||||
|
||||
NonOptionArgumentSpec<String> nonOptions
|
||||
= parser.nonOptions();
|
||||
|
||||
@ -1488,6 +1522,17 @@ public class JmodTask {
|
||||
throw new CommandException("err.modulepath.must.be.specified")
|
||||
.showUsage(true);
|
||||
}
|
||||
if (opts.has(compress)) {
|
||||
if (!options.mode.equals(Mode.CREATE)) {
|
||||
throw new CommandException("err.compress.wrong.mode")
|
||||
.showUsage(true);
|
||||
}
|
||||
options.compressLevel = getLastElement(opts.valuesOf(compress));
|
||||
} else {
|
||||
// Default to the default from zlib. Hard-coded here to avoid accidental
|
||||
// compression level change if zlib ever changes the default.
|
||||
options.compressLevel = 6;
|
||||
}
|
||||
|
||||
if (options.mode.equals(Mode.HASH)) {
|
||||
if (options.moduleFinder == null || options.modulesToHash == null)
|
||||
|
@ -82,6 +82,10 @@ main.opt.date=Date and time for the timestamps of entries, specified in ISO-8601
|
||||
|
||||
main.opt.cmdfile=Read options from the specified file
|
||||
|
||||
main.opt.compress=Compression to use when creating the JMOD archive.\
|
||||
\ Accepted values are: zip-[0-9], where zip-0 provides no compression, and zip-9\
|
||||
\ provides the best compression. Default is zip-6.
|
||||
|
||||
module.hashes.recorded=Hashes are recorded in module {0}
|
||||
|
||||
err.missing.mode=one of create, extract, list, describe, or hash must be specified
|
||||
@ -113,6 +117,8 @@ err.module.resolution.fail=Resolution failed: {0}
|
||||
err.no.moduleToHash=No hashes recorded: no module matching {0} found to record hashes
|
||||
err.invalid.date=--date {0} is not a valid ISO-8601 extended offset date-time with optional time-zone format: {1}
|
||||
err.date.out.of.range=--date {0} is out of the valid range 1980-01-01T00:00:02Z to 2099-12-31T23:59:59Z
|
||||
err.compress.incorrect=--compress value is invalid: {0}
|
||||
err.compress.wrong.mode=--compress is only accepted with create mode
|
||||
warn.invalid.arg=Invalid classname or pathname not exist: {0}
|
||||
warn.no.module.hashes=No hashes recorded: no module specified for hashing depends on {0}
|
||||
warn.ignore.entry=ignoring entry {0}, in section {1}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2022, 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
|
||||
@ -739,6 +739,101 @@ public class JmodTest {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompressionLevel() throws IOException {
|
||||
String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();
|
||||
Path jmod = MODS_DIR.resolve("foo.jmod");
|
||||
FileUtils.deleteFileIfExistsWithRetry(jmod);
|
||||
|
||||
jmod("create",
|
||||
"--class-path", cp,
|
||||
"--compress", "zip-0",
|
||||
jmod.toString())
|
||||
.assertSuccess();
|
||||
|
||||
jmod("list",
|
||||
"--compress", "zip-0",
|
||||
jmod.toString())
|
||||
.assertFailure()
|
||||
.resultChecker(r -> {
|
||||
assertTrue(r.output.contains("--compress is only accepted with create mode"), "Error message printed");
|
||||
});
|
||||
|
||||
FileUtils.deleteFileIfExistsWithRetry(jmod);
|
||||
|
||||
jmod("create",
|
||||
"--class-path", cp,
|
||||
"--compress", "zip-9",
|
||||
jmod.toString())
|
||||
.assertSuccess();
|
||||
|
||||
FileUtils.deleteFileIfExistsWithRetry(jmod);
|
||||
|
||||
jmod("create",
|
||||
"--class-path", cp,
|
||||
"--compress", "zip--1",
|
||||
jmod.toString())
|
||||
.assertFailure()
|
||||
.resultChecker(r -> {
|
||||
assertTrue(r.output.contains("--compress value is invalid"), "Error message printed");
|
||||
});
|
||||
|
||||
FileUtils.deleteFileIfExistsWithRetry(jmod);
|
||||
|
||||
jmod("create",
|
||||
"--class-path", cp,
|
||||
"--compress", "zip-1-something",
|
||||
jmod.toString())
|
||||
.assertFailure()
|
||||
.resultChecker(r -> {
|
||||
assertTrue(r.output.contains("--compress value is invalid"), "Error message printed");
|
||||
});
|
||||
|
||||
FileUtils.deleteFileIfExistsWithRetry(jmod);
|
||||
|
||||
jmod("create",
|
||||
"--class-path", cp,
|
||||
"--compress", "zip-10",
|
||||
jmod.toString())
|
||||
.assertFailure()
|
||||
.resultChecker(r -> {
|
||||
assertTrue(r.output.contains("--compress value is invalid"), "Error message printed");
|
||||
});
|
||||
|
||||
FileUtils.deleteFileIfExistsWithRetry(jmod);
|
||||
|
||||
jmod("create",
|
||||
"--class-path", cp,
|
||||
"--compress", "zip-",
|
||||
jmod.toString())
|
||||
.assertFailure()
|
||||
.resultChecker(r -> {
|
||||
assertTrue(r.output.contains("--compress value is invalid"), "Error message printed");
|
||||
});
|
||||
|
||||
FileUtils.deleteFileIfExistsWithRetry(jmod);
|
||||
|
||||
jmod("create",
|
||||
"--class-path", cp,
|
||||
"--compress", "test",
|
||||
jmod.toString())
|
||||
.assertFailure()
|
||||
.resultChecker(r -> {
|
||||
assertTrue(r.output.contains("--compress value is invalid"), "Error message printed");
|
||||
});
|
||||
|
||||
FileUtils.deleteFileIfExistsWithRetry(jmod);
|
||||
|
||||
jmod("create",
|
||||
"--class-path", cp,
|
||||
"--compress", "test-0",
|
||||
jmod.toString())
|
||||
.assertFailure()
|
||||
.resultChecker(r -> {
|
||||
assertTrue(r.output.contains("--compress value is invalid"), "Error message printed");
|
||||
});
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
static boolean compileModule(String name, Path dest) throws IOException {
|
||||
|
Loading…
Reference in New Issue
Block a user