8293499: Provide jmod --compress option

Reviewed-by: alanb, mchung, jpai, redestad
This commit is contained in:
Aleksey Shipilev 2022-09-19 06:19:53 +00:00
parent 26e08cf3d0
commit 43f7f47ae0
4 changed files with 154 additions and 7 deletions

View File

@ -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);

View File

@ -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)

View File

@ -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}

View File

@ -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 {