mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-CR-12256 client should not close input stream
This commit is contained in:
@@ -2,10 +2,19 @@
|
||||
<item name='java.nio.file.FileSystem java.nio.file.Path getPath(java.lang.String, java.lang.String...)'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
<item name='java.nio.file.Files byte[] readAllBytes(java.nio.file.Path)'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
<item name='java.nio.file.Files java.io.InputStream newInputStream(java.nio.file.Path, java.nio.file.OpenOption...)'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
<item name='java.nio.file.Files java.nio.channels.SeekableByteChannel newByteChannel(java.nio.file.Path, java.nio.file.OpenOption...)'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
<item name='java.nio.file.Path java.nio.file.Path getParent()'>
|
||||
<annotation name='org.jetbrains.annotations.Nullable'/>
|
||||
</item>
|
||||
<item name='java.nio.file.Path java.nio.file.Path resolve(java.lang.String)'>
|
||||
<annotation name='org.jetbrains.annotations.NotNull'/>
|
||||
</item>
|
||||
</root>
|
||||
@@ -259,11 +259,9 @@ class SchemeManagerImpl<T : Scheme, E : ExternalizableScheme>(val fileSpec: Stri
|
||||
if (provider != null && provider.enabled) {
|
||||
provider.processChildren(fileSpec, roamingType, { canRead(it) }) { name, input, readOnly ->
|
||||
catchAndLog(name) {
|
||||
input.use {
|
||||
val scheme = loadScheme(name, it, true)
|
||||
if (readOnly && scheme != null) {
|
||||
readOnlyExternalizableSchemes.put(scheme.name, scheme)
|
||||
}
|
||||
val scheme = loadScheme(name, input, true)
|
||||
if (readOnly && scheme != null) {
|
||||
readOnlyExternalizableSchemes.put(scheme.name, scheme)
|
||||
}
|
||||
}
|
||||
true
|
||||
@@ -277,7 +275,7 @@ class SchemeManagerImpl<T : Scheme, E : ExternalizableScheme>(val fileSpec: Stri
|
||||
}
|
||||
|
||||
catchAndLog(file.fileName.toString()) { filename ->
|
||||
file.inputStream()?.use { loadScheme(filename, it, true) }
|
||||
file.inputStream().use { loadScheme(filename, it, true) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,10 +20,10 @@ import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream
|
||||
import java.io.InputStream
|
||||
|
||||
interface StreamProvider {
|
||||
open val enabled: Boolean
|
||||
val enabled: Boolean
|
||||
get() = true
|
||||
|
||||
open fun isApplicable(fileSpec: String, roamingType: RoamingType = RoamingType.DEFAULT): Boolean = true
|
||||
fun isApplicable(fileSpec: String, roamingType: RoamingType = RoamingType.DEFAULT): Boolean = true
|
||||
|
||||
/**
|
||||
* @param fileSpec
|
||||
@@ -34,9 +34,6 @@ interface StreamProvider {
|
||||
|
||||
fun read(fileSpec: String, roamingType: RoamingType = RoamingType.DEFAULT): InputStream?
|
||||
|
||||
/**
|
||||
* You must close passed input stream.
|
||||
*/
|
||||
fun processChildren(path: String, roamingType: RoamingType, filter: (name: String) -> Boolean, processor: (name: String, input: InputStream, readOnly: Boolean) -> Boolean)
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,53 +1,48 @@
|
||||
package com.intellij.configurationStore
|
||||
|
||||
import com.intellij.openapi.components.RoamingType
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.util.SmartList
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import com.intellij.util.*
|
||||
import java.io.InputStream
|
||||
import java.nio.file.NoSuchFileException
|
||||
import java.nio.file.Path
|
||||
|
||||
class MockStreamProvider(private val myBaseDir: File) : StreamProvider {
|
||||
class MockStreamProvider(private val dir: Path) : StreamProvider {
|
||||
override fun write(fileSpec: String, content: ByteArray, size: Int, roamingType: RoamingType) {
|
||||
FileUtil.writeToFile(File(myBaseDir, fileSpec), content, 0, size)
|
||||
dir.resolve(fileSpec).write(content, 0, size)
|
||||
}
|
||||
|
||||
override fun read(fileSpec: String, roamingType: RoamingType): InputStream? {
|
||||
val file = File(myBaseDir, fileSpec)
|
||||
//noinspection IOResourceOpenedButNotSafelyClosed
|
||||
return if (file.exists()) FileInputStream(file) else null
|
||||
val file = dir.resolve(fileSpec)
|
||||
try {
|
||||
return file.inputStream()
|
||||
}
|
||||
catch (e: NoSuchFileException) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
private fun listSubFiles(fileSpec: String, roamingType: RoamingType): Collection<String> {
|
||||
if (roamingType !== RoamingType.DEFAULT) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
val files = File(myBaseDir, fileSpec).listFiles() ?: return emptyList()
|
||||
val names = SmartList<String>()
|
||||
for (file in files) {
|
||||
names.add(file.name)
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
/**
|
||||
* You must close passed input stream.
|
||||
*/
|
||||
override fun processChildren(path: String, roamingType: RoamingType, filter: (name: String) -> Boolean, processor: (name: String, input: InputStream, readOnly: Boolean) -> Boolean) {
|
||||
for (name in listSubFiles(path, roamingType)) {
|
||||
if (!filter(name)) {
|
||||
continue
|
||||
}
|
||||
dir.resolve(path).directoryStreamIfExists({ filter(it.fileName.toString()) }) {
|
||||
for (file in it) {
|
||||
val attributes = file.basicAttributesIfExists()
|
||||
if (attributes == null || attributes.isDirectory || file.isHidden()) {
|
||||
continue
|
||||
}
|
||||
|
||||
val input = read("$path/$name", roamingType)
|
||||
if (input != null && !processor(name, input, false)) {
|
||||
break
|
||||
// we ignore empty files as well - delete if corrupted
|
||||
if (attributes.size() == 0L) {
|
||||
file.delete()
|
||||
continue
|
||||
}
|
||||
|
||||
if (!file.inputStream().use { processor(file.fileName.toString(), it, false) }) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun delete(fileSpec: String, roamingType: RoamingType) {
|
||||
FileUtil.delete(File(myBaseDir, fileSpec))
|
||||
dir.resolve(fileSpec).delete()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,7 +324,7 @@ internal class SchemeManagerTest {
|
||||
}
|
||||
|
||||
private fun createAndLoad(): SchemeManagerImpl<TestScheme, TestScheme> {
|
||||
val schemesManager = SchemeManagerImpl<TestScheme, TestScheme>(FILE_SPEC, TestSchemesProcessor(), MockStreamProvider(remoteBaseDir!!.toFile()), localBaseDir!!)
|
||||
val schemesManager = SchemeManagerImpl<TestScheme, TestScheme>(FILE_SPEC, TestSchemesProcessor(), MockStreamProvider(remoteBaseDir!!), localBaseDir!!)
|
||||
schemesManager.loadSchemes()
|
||||
return schemesManager
|
||||
}
|
||||
|
||||
@@ -21,13 +21,15 @@ import com.intellij.openapi.vfs.VfsUtil
|
||||
import org.jetbrains.io.readCharSequence
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import java.nio.file.*
|
||||
import java.nio.file.attribute.BasicFileAttributes
|
||||
import java.nio.file.attribute.FileTime
|
||||
|
||||
fun Path.exists() = Files.exists(this)
|
||||
|
||||
fun Path.createDirectories() = Files.createDirectories(this)
|
||||
fun Path.createDirectories(): Path = Files.createDirectories(this)
|
||||
|
||||
/**
|
||||
* Opposite to Java, parent directories will be created
|
||||
@@ -37,7 +39,7 @@ fun Path.outputStream(): OutputStream {
|
||||
return Files.newOutputStream(this)
|
||||
}
|
||||
|
||||
fun Path.inputStream() = Files.newInputStream(this)
|
||||
fun Path.inputStream(): InputStream = Files.newInputStream(this)
|
||||
|
||||
/**
|
||||
* Opposite to Java, parent directories will be created
|
||||
@@ -71,7 +73,7 @@ fun Path.deleteRecursively(): Path = if (exists()) Files.walkFileTree (this, obj
|
||||
}
|
||||
}) else this
|
||||
|
||||
fun Path.lastModified() = Files.getLastModifiedTime(this)
|
||||
fun Path.lastModified(): FileTime = Files.getLastModifiedTime(this)
|
||||
|
||||
val Path.systemIndependentPath: String
|
||||
get() = toString().replace(File.separatorChar, '/')
|
||||
@@ -79,9 +81,9 @@ val Path.systemIndependentPath: String
|
||||
val Path.parentSystemIndependentPath: String
|
||||
get() = parent!!.toString().replace(File.separatorChar, '/')
|
||||
|
||||
fun Path.readBytes() = Files.readAllBytes(this)
|
||||
fun Path.readBytes(): ByteArray = Files.readAllBytes(this)
|
||||
|
||||
fun Path.readText() = readBytes().toString(Charsets.UTF_8)
|
||||
fun Path.readText(): String = readBytes().toString(Charsets.UTF_8)
|
||||
|
||||
fun Path.readChars() = inputStream().reader().readCharSequence(size().toInt())
|
||||
|
||||
@@ -103,25 +105,24 @@ fun Path.write(data: String): Path {
|
||||
|
||||
fun Path.size() = Files.size(this)
|
||||
|
||||
fun Path.sizeOrNull(): Long {
|
||||
val attributes: BasicFileAttributes
|
||||
fun Path.basicAttributesIfExists(): BasicFileAttributes? {
|
||||
try {
|
||||
attributes = Files.readAttributes(this, BasicFileAttributes::class.java)
|
||||
return Files.readAttributes(this, BasicFileAttributes::class.java)
|
||||
}
|
||||
catch (ignored: IOException) {
|
||||
return -1
|
||||
catch (ignored: NoSuchFileException) {
|
||||
return null
|
||||
}
|
||||
|
||||
return attributes.size()
|
||||
}
|
||||
|
||||
fun Path.sizeOrNull() = basicAttributesIfExists()?.size() ?: -1
|
||||
|
||||
fun Path.isHidden() = Files.isHidden(this)
|
||||
|
||||
fun Path.isDirectory() = Files.isDirectory(this)
|
||||
|
||||
fun Path.isFile() = Files.isRegularFile(this)
|
||||
|
||||
fun Path.move(target: Path) = Files.move(this, target)
|
||||
fun Path.move(target: Path): Path = Files.move(this, target)
|
||||
|
||||
/**
|
||||
* Opposite to Java, parent directories will be created
|
||||
@@ -152,7 +153,7 @@ inline fun <R> Path.directoryStreamIfExists(task: (stream: DirectoryStream<Path>
|
||||
|
||||
inline fun <R> Path.directoryStreamIfExists(noinline filter: ((path: Path) -> Boolean), task: (stream: DirectoryStream<Path>) -> R): R? {
|
||||
try {
|
||||
return Files.newDirectoryStream(this, { filter.invoke(it) }).use(task)
|
||||
return Files.newDirectoryStream(this, filter).use(task)
|
||||
}
|
||||
catch (ignored: NoSuchFileException) {
|
||||
}
|
||||
|
||||
@@ -26,9 +26,11 @@ import com.intellij.openapi.vfs.CharsetToolkit
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.testFramework.LightVirtualFile
|
||||
import com.intellij.util.*
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.attribute.BasicFileAttributes
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.read
|
||||
import kotlin.concurrent.write
|
||||
@@ -37,28 +39,35 @@ abstract class BaseRepositoryManager(protected val dir: Path) : RepositoryManage
|
||||
protected val lock: ReentrantReadWriteLock = ReentrantReadWriteLock()
|
||||
|
||||
override fun processChildren(path: String, filter: (name: String) -> Boolean, processor: (name: String, inputStream: InputStream) -> Boolean) {
|
||||
dir.resolve(path).directoryStreamIfExists {
|
||||
dir.resolve(path).directoryStreamIfExists({ filter(it.fileName.toString()) }) {
|
||||
for (file in it) {
|
||||
if (file.isDirectory() || file.isHidden()) {
|
||||
continue;
|
||||
val attributes: BasicFileAttributes?
|
||||
try {
|
||||
attributes = file.basicAttributesIfExists()
|
||||
}
|
||||
catch (e: IOException) {
|
||||
LOG.warn(e)
|
||||
continue
|
||||
}
|
||||
|
||||
if (attributes == null || attributes.isDirectory || file.isHidden()) {
|
||||
continue
|
||||
}
|
||||
|
||||
// we ignore empty files as well - delete if corrupted
|
||||
if (file.size() == 0L) {
|
||||
if (file.exists()) {
|
||||
try {
|
||||
LOG.warn("File $path is empty (length 0), will be removed")
|
||||
delete(file, path)
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.error(e)
|
||||
}
|
||||
if (attributes.size() == 0L) {
|
||||
try {
|
||||
LOG.warn("File $path is empty (length 0), will be removed")
|
||||
delete(file, path)
|
||||
}
|
||||
continue;
|
||||
catch (e: Exception) {
|
||||
LOG.error(e)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if (!processor(file.fileName.toString(), file.inputStream())) {
|
||||
break;
|
||||
if (!file.inputStream().use { processor(file.fileName.toString(), it) }) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ class IcsManager(dir: Path) {
|
||||
}
|
||||
}
|
||||
|
||||
val settingsFile = dir.resolve("config.json")
|
||||
val settingsFile: Path = dir.resolve("config.json")
|
||||
|
||||
val settings: IcsSettings
|
||||
val repositoryManager: RepositoryManager = GitRepositoryManager(credentialsStore, dir.resolve("repository"))
|
||||
@@ -190,10 +190,10 @@ class IcsManager(dir: Path) {
|
||||
|
||||
// first of all we must load read-only schemes - scheme could be overridden if bundled or read-only, so, such schemes must be loaded first
|
||||
for (repository in readOnlySourcesManager.repositories) {
|
||||
repository.processChildren(fullPath, filter, { name, input -> processor(name, input, true) })
|
||||
repository.processChildren(fullPath, filter) { name, input -> processor(name, input, true) }
|
||||
}
|
||||
|
||||
repositoryManager.processChildren(fullPath, filter, { name, input -> processor(name, input, false) })
|
||||
repositoryManager.processChildren(fullPath, filter) { name, input -> processor(name, input, false) }
|
||||
}
|
||||
|
||||
override fun write(fileSpec: String, content: ByteArray, size: Int, roamingType: RoamingType) {
|
||||
|
||||
@@ -97,7 +97,7 @@ fun createBareRepository(dir: Path): Repository {
|
||||
return repository
|
||||
}
|
||||
|
||||
fun createRepository(dir: Path): Repository {
|
||||
fun createGitRepository(dir: Path): Repository {
|
||||
val repository = FileRepositoryBuilder().setWorkTree(dir.toFile()).build()
|
||||
repository.create()
|
||||
return repository
|
||||
@@ -250,8 +250,8 @@ fun Repository.processChildren(path: String, filter: ((name: String) -> Boolean)
|
||||
continue
|
||||
}
|
||||
|
||||
if (!processor(fileName, objectLoader.openStream())) {
|
||||
break;
|
||||
if (!objectLoader.openStream().use { processor(fileName, it) }) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -317,7 +317,7 @@ private class InputStreamWrapper(private val delegate: InputStream, private val
|
||||
delegate.close()
|
||||
}
|
||||
finally {
|
||||
reader.close();
|
||||
reader.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,10 +21,10 @@ import org.eclipse.jgit.lib.Repository
|
||||
import org.jetbrains.jgit.dirCache.AddLoadedFile
|
||||
import org.jetbrains.jgit.dirCache.edit
|
||||
import org.jetbrains.settingsRepository.IcsManager
|
||||
import org.jetbrains.settingsRepository.git.createGitRepository
|
||||
import org.junit.Rule
|
||||
import java.nio.file.FileSystem
|
||||
import java.nio.file.Path
|
||||
import org.jetbrains.settingsRepository.git.createRepository as createGitRepository
|
||||
|
||||
fun Repository.add(path: String, data: String) = add(path, data.toByteArray())
|
||||
|
||||
|
||||
Reference in New Issue
Block a user