cleanup [platform]: Drop File in ZipHandlerBase and use `Path instead.

`File` doesn't work well with Docker and other eel-based FSs

GitOrigin-RevId: f5a20547920d852bcf7b41f90e2c45efdba039b7
This commit is contained in:
Ilya.Kazakevich
2026-01-04 19:08:54 +00:00
committed by intellij-monorepo-bot
parent 5cb0c58a86
commit c255059f81
14 changed files with 57 additions and 123 deletions
@@ -176,7 +176,7 @@ public final class PackageFileWorker {
private static JBZipFile getOrCreateZipFile(File archiveFile) throws IOException {
FileUtil.createIfDoesntExist(archiveFile);
try {
return new JBZipFile(archiveFile);
return new JBZipFile(archiveFile.toPath(), false);
}
catch (IllegalArgumentException e) {
throw new IOException(e);
@@ -7,22 +7,22 @@ import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
@ApiStatus.Internal
public final class JBZipFileWrapper implements GenericZipFile {
final class JBZipFileWrapper implements GenericZipFile {
private final JBZipFile myZipFile;
public JBZipFileWrapper(File file) throws IOException {
JBZipFileWrapper(@NotNull Path file) throws IOException {
myZipFile = new JBZipFile(file, true);
}
@Override
public @Nullable GenericZipEntry getEntry(@NotNull String entryName) throws IOException {
public @Nullable GenericZipEntry getEntry(@NotNull String entryName) {
JBZipEntry entry = myZipFile.getEntry(entryName);
return entry != null ? new EntryWrapper(entry) : null;
}
@@ -42,7 +42,7 @@ public final class JBZipFileWrapper implements GenericZipFile {
myZipFile.close();
}
private static class EntryWrapper implements GenericZipEntry {
private static final class EntryWrapper implements GenericZipEntry {
private final JBZipEntry myEntry;
EntryWrapper(JBZipEntry entry) { myEntry = entry; }
@@ -15,15 +15,15 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@ApiStatus.Internal
public final class JavaZipFileWrapper implements GenericZipFile {
final class JavaZipFileWrapper implements GenericZipFile {
private final ZipFile myZipFile;
public JavaZipFileWrapper(File file) throws IOException {
JavaZipFileWrapper(File file) throws IOException {
myZipFile = new ZipFile(file);
}
@Override
public GenericZipEntry getEntry(@NotNull String entryName) throws IOException {
public GenericZipEntry getEntry(@NotNull String entryName) {
ZipEntry entry = myZipFile.getEntry(entryName);
return entry != null ? new EntryWrapper(entry, myZipFile) : null;
}
@@ -44,7 +44,7 @@ public final class JavaZipFileWrapper implements GenericZipFile {
myZipFile.close();
}
private static class EntryWrapper implements GenericZipFile.GenericZipEntry {
private static final class EntryWrapper implements GenericZipFile.GenericZipEntry {
private final ZipEntry myEntry;
private final ZipFile myFile;
@@ -30,7 +30,7 @@ public abstract class ZipHandlerBase extends ArchiveHandler {
@ApiStatus.Internal
public static @NotNull GenericZipFile getZipFileWrapper(@NotNull Path file) throws IOException {
GenericZipFile wrapper = isFileLocal(file) ? new JavaZipFileWrapper(file.toFile()) : new JBZipFileWrapper(file.toFile());
GenericZipFile wrapper = isFileLocal(file) ? new JavaZipFileWrapper(file.toFile()) : new JBZipFileWrapper(file);
if (LOG.isTraceEnabled()) {
LOG.trace("Using " + wrapper.getClass().getName() + " to open " + file);
}
@@ -325,25 +325,25 @@ public class JarFileSystemTest extends BareTestFixtureTestCase {
var jar = IoTestUtil.createTestJar(
tempDir.newFile("p.jar"),
"file1.txt", "my_content", "file2.dat", "my_content"
);
var jarRoot = JarFileSystem.getInstance().getJarRootForLocalFile(LocalFileSystem.getInstance().refreshAndFindFileByIoFile(jar));
).toPath();
var jarRoot = JarFileSystem.getInstance().getJarRootForLocalFile(LocalFileSystem.getInstance().refreshAndFindFileByNioFile(jar));
var file1Txt = jarRoot.findChild("file1.txt");
var file2Dat = jarRoot.findChild("file2.dat");
assertEquals(file1Txt.getTimeStamp(), file2Dat.getTimeStamp());
try (var it = new JBZipFile(jar)) {
try (var it = new JBZipFile(jar, false)) {
it.getOrCreateEntry(file1Txt.getName()).setData("my_new_content".getBytes(StandardCharsets.UTF_8));
}
// LFS invalidates JarFS caches
LocalFileSystem.getInstance().refreshNioFiles(List.of(jar.toPath()), false, true, null);
LocalFileSystem.getInstance().refreshNioFiles(List.of(jar), false, true, null);
assertNotEquals(file1Txt.getTimeStamp(), file2Dat.getTimeStamp());
try (var it = new JBZipFile(jar)) {
try (var it = new JBZipFile(jar, false)) {
it.getOrCreateEntry(file2Dat.getName()).setData("my_new_content".getBytes(StandardCharsets.UTF_8));
}
// LFS invalidates JarFS caches
LocalFileSystem.getInstance().refreshNioFiles(List.of(jar.toPath()), false, true, null);
LocalFileSystem.getInstance().refreshNioFiles(List.of(jar), false, true, null);
assertEquals(file1Txt.getTimeStamp(), file2Dat.getTimeStamp());
});
}
@@ -229,7 +229,7 @@ class VfsEventsTest : BareTestFixtureTestCase() {
private fun createJar(directory: Path): Path {
val jarPath = directory.resolve("Test.jar")
JBZipFile(jarPath.toFile()).use {
JBZipFile(jarPath, false).use {
it.getOrCreateEntry("awesome.txt").setData("Hello!".toByteArray(Charsets.UTF_8), 666L)
it.getOrCreateEntry("readme.txt").setData("Read it!".toByteArray(Charsets.UTF_8), 777L)
}
@@ -251,7 +251,7 @@ class VfsEventsTest : BareTestFixtureTestCase() {
private fun modifyJar(jarPath: Path) {
assertTrue { Files.exists(jarPath) }
JBZipFile(jarPath.toFile()).use {
JBZipFile(jarPath, false).use {
// modify
it.getOrCreateEntry("awesome.txt").setData("Hello_modified!".toByteArray(Charsets.UTF_8), 666L)
// add
@@ -134,13 +134,13 @@ public final class WorkingContextManager {
private JBZipFile getTasksArchive(String postfix) {
File file = getArchiveFile(postfix);
try {
return new JBZipFile(file);
return new JBZipFile(file.toPath(), false);
}
catch (IOException e) {
file.delete();
JBZipFile zipFile = null;
try {
zipFile = new JBZipFile(file);
zipFile = new JBZipFile(file.toPath(), false);
Notifications.Bus.notify(new Notification("Tasks", TaskBundle.message("notification.title.context.data.corrupted"),
TaskBundle.message("notification.content.context.information.history", myProject.getName()), NotificationType.ERROR), myProject);
}
-18
View File
@@ -4636,24 +4636,6 @@ com.intellij.util.io.zip.JBZipExtraField
- a:getLocalFileDataLength():com.intellij.util.io.zip.ZipShort
- a:parseFromCentralDirectoryData(B[],I,I):V
- a:parseFromLocalFileData(B[],I,I):V
c:com.intellij.util.io.zip.JBZipFile
- java.io.Closeable
- <init>(java.io.File):V
- <init>(java.io.File,java.lang.String):V
- <init>(java.io.File,java.nio.charset.Charset):V
- <init>(java.io.File,java.nio.charset.Charset,Z):V
- <init>(java.io.File,java.nio.charset.Charset,Z,com.intellij.util.ThreeState):V
- <init>(java.io.File,Z):V
- <init>(java.lang.String):V
- <init>(java.lang.String,java.lang.String):V
- <init>(java.nio.channels.SeekableByteChannel,java.nio.charset.Charset,Z,com.intellij.util.ThreeState):V
- close():V
- eraseEntry(com.intellij.util.io.zip.JBZipEntry):V
- gc():V
- getEncoding():java.nio.charset.Charset
- getEntries():java.util.List
- getEntry(java.lang.String):com.intellij.util.io.zip.JBZipEntry
- getOrCreateEntry(java.lang.String):com.intellij.util.io.zip.JBZipEntry
f:com.intellij.util.io.zip.Zip64ExtraField
- com.intellij.util.io.zip.JBZipExtraField
- <init>(com.intellij.util.io.zip.ZipUInt64,com.intellij.util.io.zip.ZipUInt64,com.intellij.util.io.zip.ZipUInt64):V
+11 -1
View File
@@ -544,12 +544,22 @@ com.intellij.util.io.storage.RecordIdIterator
- a:hasNextId():Z
- a:nextId():I
- a:validId():Z
c:com.intellij.util.io.zip.JBZipFile
f:com.intellij.util.io.zip.JBZipFile
- java.io.Closeable
- <init>(java.io.File):V
- <init>(java.nio.channels.SeekableByteChannel,java.nio.charset.Charset,Z,com.intellij.util.ThreeState):V
- <init>(java.nio.file.Path):V
- <init>(java.nio.file.Path,java.nio.charset.Charset):V
- <init>(java.nio.file.Path,java.nio.charset.Charset,Z):V
- <init>(java.nio.file.Path,java.nio.charset.Charset,Z,com.intellij.util.ThreeState):V
- <init>(java.nio.file.Path,Z):V
- close():V
- eraseEntry(com.intellij.util.io.zip.JBZipEntry):V
- gc():V
- getEncoding():java.nio.charset.Charset
- getEntries():java.util.List
- getEntry(java.lang.String):com.intellij.util.io.zip.JBZipEntry
- getOrCreateEntry(java.lang.String):com.intellij.util.io.zip.JBZipEntry
com.intellij.util.keyFMap.KeyFMap
- sf:EMPTY_MAP:com.intellij.util.keyFMap.KeyFMap
- a:equalsByReference(com.intellij.util.keyFMap.KeyFMap):Z
@@ -4,6 +4,7 @@ package com.intellij.util.io.zip;
import com.intellij.util.ArrayUtilRt;
import com.intellij.util.ThreeState;
import com.intellij.util.containers.ContainerUtil;
import kotlin.DeprecationLevel;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
@@ -57,7 +58,7 @@ import static java.nio.file.StandardOpenOption.*;
* </ul>
* </p>
*/
public class JBZipFile implements Closeable {
public final class JBZipFile implements Closeable {
static final int SHORT = 2;
static final int WORD = 4;
static final int DWORD = 8;
@@ -105,26 +106,18 @@ public class JBZipFile implements Closeable {
this(file, DEFAULT_CHARSET);
}
/** @deprecated the constructor has dubious default value of the {@code readonly} parameter */
/** @deprecated Use {@link #JBZipFile(Path, boolean)} */
@Deprecated
@ApiStatus.ScheduledForRemoval
@SuppressWarnings({"IO_FILE_USAGE", "UnnecessaryFullyQualifiedName"})
@kotlin.Deprecated(message = "Use Path instead", level = DeprecationLevel.ERROR)
public JBZipFile(java.io.File f) throws IOException {
this(f, DEFAULT_CHARSET);
this(f.toPath());
}
/**
* Opens the given file for reading, assuming the platform's native encoding for file names.
*
* @param name name of the archive.
* @throws IOException if an error occurs while reading the file.
*/
public JBZipFile(String name) throws IOException {
this(Paths.get(name), DEFAULT_CHARSET);
}
/**
* Opens the given file for reading, assuming the platform's native encoding for file names.
* Opens the given file for reading (or writing if readonly=false), assuming the platform's native encoding for file names.
*
* @param file file of the archive.
* @param readonly true to open file as readonly
@@ -134,32 +127,6 @@ public class JBZipFile implements Closeable {
this(file, DEFAULT_CHARSET, readonly);
}
@ApiStatus.Obsolete
@SuppressWarnings({"IO_FILE_USAGE", "UnnecessaryFullyQualifiedName"})
public JBZipFile(@NotNull java.io.File f, boolean readonly) throws IOException {
this(f, DEFAULT_CHARSET, readonly);
}
/**
* Opens the given file for reading, assuming the specified encoding for file names.
*
* @param name name of the archive.
* @param encoding the encoding to use for file names
* @throws IOException if an error occurs while reading the file.
*/
@ApiStatus.Obsolete
public JBZipFile(String name, @NotNull String encoding) throws IOException {
this(Paths.get(name), Charset.forName(encoding));
}
/** @deprecated the constructor has dubious default value of the {@code readonly} parameter */
@Deprecated
@ApiStatus.ScheduledForRemoval
@SuppressWarnings({"IO_FILE_USAGE", "UnnecessaryFullyQualifiedName"})
public JBZipFile(java.io.File f, @NotNull String encoding) throws IOException {
this(f, Charset.forName(encoding));
}
/**
* Opens the given file for reading, assuming the specified encoding for file names.
*
@@ -171,16 +138,8 @@ public class JBZipFile implements Closeable {
this(file, encoding, true);
}
/** @deprecated the constructor has dubious default value of the {@code readonly} parameter */
@Deprecated
@ApiStatus.ScheduledForRemoval
@SuppressWarnings({"IO_FILE_USAGE", "UnnecessaryFullyQualifiedName"})
public JBZipFile(java.io.File f, @NotNull Charset encoding) throws IOException {
this(f, encoding, false);
}
/**
* Opens the given file for reading, assuming the specified encoding for file names.
* Opens the given file for reading (or writing if readonly=false), assuming the specified encoding for file names.
*
* @param file the archive.
* @param encoding the encoding to use for file names
@@ -191,18 +150,6 @@ public class JBZipFile implements Closeable {
this(file, encoding, readonly, ThreeState.NO);
}
@ApiStatus.Obsolete
@SuppressWarnings({"IO_FILE_USAGE", "UnnecessaryFullyQualifiedName"})
public JBZipFile(@NotNull java.io.File f, @NotNull Charset encoding, boolean readonly) throws IOException {
this(f, encoding, readonly, ThreeState.NO);
}
@ApiStatus.Obsolete
@SuppressWarnings({"IO_FILE_USAGE", "UnnecessaryFullyQualifiedName"})
public JBZipFile(@NotNull java.io.File f, @NotNull Charset encoding, boolean readonly, @NotNull ThreeState isZip64) throws IOException {
this(openChannel(f, readonly), encoding, readonly, isZip64);
}
public JBZipFile(@NotNull Path file, @NotNull Charset encoding, boolean readonly, @NotNull ThreeState isZip64) throws IOException {
this(openChannel(file, readonly), encoding, readonly, isZip64);
}
@@ -215,7 +162,8 @@ public class JBZipFile implements Closeable {
* @param readonly true to open file as readonly
* @throws IOException if an error occurs while reading the file.
*/
public JBZipFile(@NotNull SeekableByteChannel channel, @NotNull Charset encoding, boolean readonly, @NotNull ThreeState isZip64) throws IOException {
public JBZipFile(@NotNull SeekableByteChannel channel, @NotNull Charset encoding, boolean readonly, @NotNull ThreeState isZip64)
throws IOException {
myEncoding = encoding;
myIsReadonly = readonly;
long channelSize = channel.size();
@@ -242,11 +190,6 @@ public class JBZipFile implements Closeable {
}
}
@SuppressWarnings({"IO_FILE_USAGE", "UnnecessaryFullyQualifiedName"})
private static SeekableByteChannel openChannel(java.io.File file, boolean isReadonly) throws IOException {
return openChannel(file.toPath(), isReadonly);
}
private static SeekableByteChannel openChannel(Path path, boolean isReadonly) throws IOException {
return Files.newByteChannel(path, isReadonly ? EnumSet.of(READ) : EnumSet.of(READ, WRITE, CREATE));
}
@@ -303,7 +246,7 @@ public class JBZipFile implements Closeable {
*
* @param name name of the entry.
* @return the ZipEntry corresponding to the given name - or
* {@code null} if not present.
* {@code null} if not present.
*/
public JBZipEntry getEntry(String name) {
return nameMap.get(name);
@@ -358,7 +301,7 @@ public class JBZipFile implements Closeable {
*/
ByteBuffer centralDirectoryCached = ByteBuffer.allocate(
Math.min((int)(getSize() - myArchive.position()),
// Sometimes the size of the central directory may be significant -- up to 3 megabytes.
// Sometimes the size of the central directory may be significant -- up to 3 megabytes.
64 * 1024) // seems enough
);
// we must fill the buffer before the loop starts
@@ -664,7 +607,7 @@ public class JBZipFile implements Closeable {
}
myArchive.position(myArchive.position() + ZIP64_EOCD_CFD_LOCATOR_OFFSET
- WORD /* signature has already been read */);
- WORD /* signature has already been read */);
long value = ZipUInt64.getLongValue(readBytes(DWORD));
currentCfdOffset = value;
myArchive.position(value);
@@ -698,9 +641,9 @@ public class JBZipFile implements Closeable {
*/
static final long LFH_OFFSET_FOR_FILENAME_LENGTH =
LFH_OFFSET_FOR_CRC
/* crc-32 */ + WORD
/* compressed size */ + WORD
/* uncompressed size */ + WORD;
/* crc-32 */ + WORD
/* compressed size */ + WORD
/* uncompressed size */ + WORD;
/**
* Retrieve a String from the given bytes using the encoding set
@@ -38,7 +38,7 @@ public class UpdateableZipTest extends TestCase {
@NotNull
@Override
protected JBZipFile createZip() throws IOException {
return new JBZipFile(zipFile, StandardCharsets.UTF_8, false, ThreeState.YES);
return new JBZipFile(zipFile.toPath(), StandardCharsets.UTF_8, false, ThreeState.YES);
}
@Override
@@ -47,14 +47,14 @@ public class UpdateableZipTest extends TestCase {
}
public void testBigZip() throws Exception {
File zipFile = FileUtil.createTempFile("big-test", ".zip");
var zipFile = FileUtil.createTempFile("big-test", ".zip").toPath();
String expectedEntryText = "first";
// add entries up to 6 GB (more than 4 GB - 1 byte)
int i = 0;
try (ZipArchiveOutputStream zos = new ZipArchiveOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile)))) {
try (ZipArchiveOutputStream zos = new ZipArchiveOutputStream(new BufferedOutputStream(Files.newOutputStream(zipFile)))) {
modifyArchive(zos);
while (Files.size(zipFile.toPath()) <= 6 * 1024 * 1024) {
while (Files.size(zipFile) <= 6 * 1024 * 1024) {
appendEntry(zos, "/entry" + i++, expectedEntryText.getBytes(StandardCharsets.UTF_8));
}
}
@@ -108,7 +108,7 @@ public class UpdateableZipTest extends TestCase {
@NotNull
protected JBZipFile createZip() throws IOException {
return new JBZipFile(zipFile);
return new JBZipFile(zipFile.toPath(), false);
}
public void testRead() throws Exception {
@@ -18,7 +18,7 @@ public final class JarUtils {
public static @Nullable Properties loadProperties(@NotNull Path file, @NotNull String entryName) {
if (Files.isReadable(file)) {
try {
try (JBZipFile zipFile = new JBZipFile(file.toFile(), true)) {
try (JBZipFile zipFile = new JBZipFile(file, true)) {
JBZipEntry entry = zipFile.getEntry(entryName);
if (entry != null) {
Properties properties = new Properties();
@@ -38,7 +38,7 @@ public final class JarUtils {
public static String getJarAttribute(Path file, String entryName, Attributes.Name attribute) {
if (Files.isReadable(file)) {
try (
JBZipFile zipFile = new JBZipFile(file.toFile(), true)
JBZipFile zipFile = new JBZipFile(file, true)
) {
for (JBZipEntry entry : zipFile.getEntries()) {
if ("META-INF/MANIFEST.MF".equals(entry.getName())) {
@@ -12,7 +12,6 @@ import com.intellij.tools.ide.util.common.logOutput
import com.intellij.util.ThreeState
import com.intellij.util.io.zip.JBZipFile
import org.kodein.di.instance
import java.io.File
import java.nio.charset.StandardCharsets
import java.nio.file.Path
import kotlin.io.path.*
@@ -34,7 +33,7 @@ data class RemoteArchiveProjectInfo(
private val description: String = "",
) : ProjectInfoSpec {
private fun getTopMostFolderFromZip(zipFile: File): String = JBZipFile(zipFile, StandardCharsets.UTF_8, false, ThreeState.UNSURE).entries.first().name.split("/").first()
private fun getTopMostFolderFromZip(zipFile: Path): String = JBZipFile(zipFile, StandardCharsets.UTF_8, false, ThreeState.UNSURE).entries.first().name.split("/").first()
@OptIn(ExperimentalPathApi::class)
override fun downloadAndUnpackProject(): Path {
@@ -51,7 +50,7 @@ data class RemoteArchiveProjectInfo(
throw SetupException("Failed to download the project")
}
val projectHome = (projectsUnpacked / getTopMostFolderFromZip(zipFile.toFile())).let(projectHomeRelativePath)
val projectHome = (projectsUnpacked / getTopMostFolderFromZip(zipFile)).let(projectHomeRelativePath)
if (!isReusable) {
val isDeleted = projectHome.deleteRecursivelyQuietly()
@@ -84,7 +84,7 @@ object FileSystem {
val symlinks = mutableListOf<SymlinkInfo>()
JBZipFile(zipFile.toFile(), StandardCharsets.UTF_8, false, ThreeState.UNSURE).use { zip ->
JBZipFile(zipFile, StandardCharsets.UTF_8, false, ThreeState.UNSURE).use { zip ->
for (entry in zip.entries) {
if (entry.isDirectory) {
val dir = targetDir.resolve(entry.name)