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,
|
* This method creates (or overrides, if exists) the JMOD file,
|
||||||
* returning the output stream to write to 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);
|
OutputStream out = Files.newOutputStream(file);
|
||||||
BufferedOutputStream bos = new BufferedOutputStream(out);
|
BufferedOutputStream bos = new BufferedOutputStream(out);
|
||||||
return new JmodOutputStream(bos, date);
|
return new JmodOutputStream(bos, date, compressLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final ZipOutputStream zos;
|
private final ZipOutputStream zos;
|
||||||
private final LocalDateTime date;
|
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 = new ZipOutputStream(out);
|
||||||
|
this.zos.setLevel(compressLevel);
|
||||||
this.date = date;
|
this.date = date;
|
||||||
try {
|
try {
|
||||||
JmodFile.writeMagicNumber(out);
|
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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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.regex.PatternSyntaxException;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
import java.util.zip.Deflater;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipException;
|
import java.util.zip.ZipException;
|
||||||
import java.util.zip.ZipFile;
|
import java.util.zip.ZipFile;
|
||||||
@ -167,6 +168,7 @@ public class JmodTask {
|
|||||||
List<PathMatcher> excludes;
|
List<PathMatcher> excludes;
|
||||||
Path extractDir;
|
Path extractDir;
|
||||||
LocalDateTime date;
|
LocalDateTime date;
|
||||||
|
int compressLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Valid --date range
|
// Valid --date range
|
||||||
@ -438,7 +440,7 @@ public class JmodTask {
|
|||||||
Path target = options.jmodFile;
|
Path target = options.jmodFile;
|
||||||
Path tempTarget = jmodTempFilePath(target);
|
Path tempTarget = jmodTempFilePath(target);
|
||||||
try {
|
try {
|
||||||
try (JmodOutputStream jos = JmodOutputStream.newOutputStream(tempTarget, options.date)) {
|
try (JmodOutputStream jos = JmodOutputStream.newOutputStream(tempTarget, options.date, options.compressLevel)) {
|
||||||
jmod.write(jos);
|
jmod.write(jos);
|
||||||
}
|
}
|
||||||
Files.move(tempTarget, target);
|
Files.move(tempTarget, target);
|
||||||
@ -1024,7 +1026,7 @@ public class JmodTask {
|
|||||||
{
|
{
|
||||||
|
|
||||||
try (JmodFile jf = new JmodFile(target);
|
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 -> {
|
jf.stream().forEach(e -> {
|
||||||
try (InputStream in = jf.getInputStream(e.section(), e.name())) {
|
try (InputStream in = jf.getInputStream(e.section(), e.name())) {
|
||||||
@ -1179,6 +1181,33 @@ public class JmodTask {
|
|||||||
@Override public String valuePattern() { return "date"; }
|
@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
|
static class WarnIfResolvedReasonConverter
|
||||||
implements ValueConverter<ModuleResolution>
|
implements ValueConverter<ModuleResolution>
|
||||||
{
|
{
|
||||||
@ -1419,6 +1448,11 @@ public class JmodTask {
|
|||||||
.withRequiredArg()
|
.withRequiredArg()
|
||||||
.withValuesConvertedBy(new DateConverter());
|
.withValuesConvertedBy(new DateConverter());
|
||||||
|
|
||||||
|
OptionSpec<Integer> compress
|
||||||
|
= parser.accepts("compress", getMessage("main.opt.compress"))
|
||||||
|
.withRequiredArg()
|
||||||
|
.withValuesConvertedBy(new CompLevelConverter());
|
||||||
|
|
||||||
NonOptionArgumentSpec<String> nonOptions
|
NonOptionArgumentSpec<String> nonOptions
|
||||||
= parser.nonOptions();
|
= parser.nonOptions();
|
||||||
|
|
||||||
@ -1488,6 +1522,17 @@ public class JmodTask {
|
|||||||
throw new CommandException("err.modulepath.must.be.specified")
|
throw new CommandException("err.modulepath.must.be.specified")
|
||||||
.showUsage(true);
|
.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.mode.equals(Mode.HASH)) {
|
||||||
if (options.moduleFinder == null || options.modulesToHash == null)
|
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.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}
|
module.hashes.recorded=Hashes are recorded in module {0}
|
||||||
|
|
||||||
err.missing.mode=one of create, extract, list, describe, or hash must be specified
|
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.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.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.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.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.no.module.hashes=No hashes recorded: no module specified for hashing depends on {0}
|
||||||
warn.ignore.entry=ignoring entry {0}, in section {1}
|
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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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 {
|
static boolean compileModule(String name, Path dest) throws IOException {
|
||||||
|
Loading…
Reference in New Issue
Block a user