diff --git a/lib/annotations/jdk/java/nio/file/annotations.xml b/lib/annotations/jdk/java/nio/file/annotations.xml index 4fc7d46c809e..c2ec872789fd 100644 --- a/lib/annotations/jdk/java/nio/file/annotations.xml +++ b/lib/annotations/jdk/java/nio/file/annotations.xml @@ -2,10 +2,19 @@ + + + + + + + + + \ No newline at end of file diff --git a/platform/configuration-store-impl/src/SchemeManagerImpl.kt b/platform/configuration-store-impl/src/SchemeManagerImpl.kt index 50bd63a3c070..0150bc6c4795 100644 --- a/platform/configuration-store-impl/src/SchemeManagerImpl.kt +++ b/platform/configuration-store-impl/src/SchemeManagerImpl.kt @@ -259,11 +259,9 @@ class SchemeManagerImpl(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(val fileSpec: Stri } catchAndLog(file.fileName.toString()) { filename -> - file.inputStream()?.use { loadScheme(filename, it, true) } + file.inputStream().use { loadScheme(filename, it, true) } } } } diff --git a/platform/configuration-store-impl/src/StreamProvider.kt b/platform/configuration-store-impl/src/StreamProvider.kt index 315947532141..9e7498560603 100644 --- a/platform/configuration-store-impl/src/StreamProvider.kt +++ b/platform/configuration-store-impl/src/StreamProvider.kt @@ -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) /** diff --git a/platform/configuration-store-impl/testSrc/MockStreamProvider.kt b/platform/configuration-store-impl/testSrc/MockStreamProvider.kt index 1385da123485..86e1b8a6ce29 100644 --- a/platform/configuration-store-impl/testSrc/MockStreamProvider.kt +++ b/platform/configuration-store-impl/testSrc/MockStreamProvider.kt @@ -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 { - if (roamingType !== RoamingType.DEFAULT) { - return emptyList() - } - - val files = File(myBaseDir, fileSpec).listFiles() ?: return emptyList() - val names = SmartList() - 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() } } diff --git a/platform/configuration-store-impl/testSrc/SchemeManagerTest.kt b/platform/configuration-store-impl/testSrc/SchemeManagerTest.kt index e96c81ac3a66..0d09b11659f3 100644 --- a/platform/configuration-store-impl/testSrc/SchemeManagerTest.kt +++ b/platform/configuration-store-impl/testSrc/SchemeManagerTest.kt @@ -324,7 +324,7 @@ internal class SchemeManagerTest { } private fun createAndLoad(): SchemeManagerImpl { - val schemesManager = SchemeManagerImpl(FILE_SPEC, TestSchemesProcessor(), MockStreamProvider(remoteBaseDir!!.toFile()), localBaseDir!!) + val schemesManager = SchemeManagerImpl(FILE_SPEC, TestSchemesProcessor(), MockStreamProvider(remoteBaseDir!!), localBaseDir!!) schemesManager.loadSchemes() return schemesManager } diff --git a/platform/platform-impl/src/com/intellij/util/path.kt b/platform/platform-impl/src/com/intellij/util/path.kt index d4eabb06655a..7754685b073d 100644 --- a/platform/platform-impl/src/com/intellij/util/path.kt +++ b/platform/platform-impl/src/com/intellij/util/path.kt @@ -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 Path.directoryStreamIfExists(task: (stream: DirectoryStream inline fun Path.directoryStreamIfExists(noinline filter: ((path: Path) -> Boolean), task: (stream: DirectoryStream) -> R): R? { try { - return Files.newDirectoryStream(this, { filter.invoke(it) }).use(task) + return Files.newDirectoryStream(this, filter).use(task) } catch (ignored: NoSuchFileException) { } diff --git a/plugins/settings-repository/src/BaseRepositoryManager.kt b/plugins/settings-repository/src/BaseRepositoryManager.kt index 35029871070e..2ad42794a09f 100644 --- a/plugins/settings-repository/src/BaseRepositoryManager.kt +++ b/plugins/settings-repository/src/BaseRepositoryManager.kt @@ -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 } } } diff --git a/plugins/settings-repository/src/IcsManager.kt b/plugins/settings-repository/src/IcsManager.kt index 568156f900d7..b866eee4aee6 100644 --- a/plugins/settings-repository/src/IcsManager.kt +++ b/plugins/settings-repository/src/IcsManager.kt @@ -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) { diff --git a/plugins/settings-repository/src/git/GitEx.kt b/plugins/settings-repository/src/git/GitEx.kt index 1cf2be1881da..572154756f8f 100644 --- a/plugins/settings-repository/src/git/GitEx.kt +++ b/plugins/settings-repository/src/git/GitEx.kt @@ -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() } } } diff --git a/plugins/settings-repository/testSrc/IcsTestCase.kt b/plugins/settings-repository/testSrc/IcsTestCase.kt index ef614ec565b8..fd53c86f356f 100644 --- a/plugins/settings-repository/testSrc/IcsTestCase.kt +++ b/plugins/settings-repository/testSrc/IcsTestCase.kt @@ -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())