mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 15:19:59 +07:00
[eel] generalize all eel result types into a single EelResult
Motivation: 1. Allows removing identical "unwrap" functions for each result type 2. Makes it easier to add helper functions GitOrigin-RevId: fd05408f6c756b3220120c87c8738df45573b008
This commit is contained in:
committed by
intellij-monorepo-bot
parent
775a1655e0
commit
ad808e267e
@@ -17,7 +17,7 @@ interface EelExecApi {
|
||||
*
|
||||
* See [executeProcessBuilder]
|
||||
*/
|
||||
suspend fun execute(builder: ExecuteProcessBuilder): ExecuteProcessResult
|
||||
suspend fun execute(builder: ExecuteProcessBuilder): EelResult<EelProcess, ExecuteProcessError>
|
||||
|
||||
/** Docs: [executeProcessBuilder] */
|
||||
interface ExecuteProcessBuilder {
|
||||
@@ -63,9 +63,9 @@ interface EelExecApi {
|
||||
*/
|
||||
suspend fun fetchLoginShellEnvVariables(): Map<String, String>
|
||||
|
||||
sealed interface ExecuteProcessResult {
|
||||
class Success(val process: EelProcess) : ExecuteProcessResult
|
||||
data class Failure(val errno: Int, val message: String) : ExecuteProcessResult
|
||||
interface ExecuteProcessError {
|
||||
val errno: Int
|
||||
val message: String
|
||||
}
|
||||
|
||||
/** [echo] must be true in general and must be false when the user is asked for a password. */
|
||||
@@ -73,7 +73,7 @@ interface EelExecApi {
|
||||
}
|
||||
|
||||
/** Docs: [EelExecApi.executeProcessBuilder] */
|
||||
suspend fun EelExecApi.executeProcess(exe: String, vararg args: String): EelExecApi.ExecuteProcessResult =
|
||||
suspend fun EelExecApi.executeProcess(exe: String, vararg args: String): EelResult<EelProcess, EelExecApi.ExecuteProcessError> =
|
||||
execute(EelExecApi.executeProcessBuilder(exe).args(listOf(*args)))
|
||||
|
||||
/** Docs: [EelExecApi.executeProcessBuilder] */
|
||||
|
||||
22
platform/eel/src/com/intellij/platform/eel/EelResult.kt
Normal file
22
platform/eel/src/com/intellij/platform/eel/EelResult.kt
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.eel
|
||||
|
||||
sealed interface EelResult<out P, out E> {
|
||||
interface Ok<out P, out E> : EelResult<P, E> {
|
||||
val value: P
|
||||
}
|
||||
|
||||
interface Error<out P, out E> : EelResult<P, E> {
|
||||
val error: E
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <T, E> EelResult<T, E>.getOrThrow(action: (E) -> Nothing = { throw RuntimeException(it.toString()) }): T = when (this) {
|
||||
is EelResult.Ok -> this.value
|
||||
is EelResult.Error -> action(this.error)
|
||||
}
|
||||
|
||||
fun <T, E> EelResult<T, E>.getOrNull(): T? = when (this) {
|
||||
is EelResult.Ok -> this.value
|
||||
is EelResult.Error -> null
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
package com.intellij.platform.eel
|
||||
|
||||
import com.intellij.platform.eel.EelTunnelsApi.Connection
|
||||
import com.intellij.platform.eel.impl.IpProtocolPreferenceImpl
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.channels.ReceiveChannel
|
||||
import kotlinx.coroutines.channels.SendChannel
|
||||
@@ -36,7 +35,7 @@ sealed interface EelTunnelsApi {
|
||||
*
|
||||
* One should not forget to invoke [Connection.close] when the connection is not needed.
|
||||
*/
|
||||
suspend fun getConnectionToRemotePort(address: HostAddress): EelNetworkResult<Connection, EelConnectionError>
|
||||
suspend fun getConnectionToRemotePort(address: HostAddress): EelResult<Connection, EelConnectionError>
|
||||
|
||||
/**
|
||||
* Creates a builder for address on the remote host.
|
||||
@@ -204,7 +203,7 @@ sealed interface EelTunnelsApi {
|
||||
*
|
||||
* One should not forget to invoke [Connection.close] when the connection is not needed.
|
||||
*/
|
||||
suspend fun getAcceptorForRemotePort(address: HostAddress): EelNetworkResult<ConnectionAcceptor, EelConnectionError>
|
||||
suspend fun getAcceptorForRemotePort(address: HostAddress): EelResult<ConnectionAcceptor, EelConnectionError>
|
||||
|
||||
/**
|
||||
* This is a representation of a remote server bound to [boundAddress].
|
||||
@@ -311,8 +310,8 @@ suspend fun <T> EelTunnelsApi.withConnectionToRemotePort(
|
||||
action: suspend CoroutineScope.(Connection) -> T,
|
||||
): T =
|
||||
when (val connectionResult = getConnectionToRemotePort(hostAddress)) {
|
||||
is EelNetworkResult.Error -> errorHandler(connectionResult.error)
|
||||
is EelNetworkResult.Ok -> closeWithExceptionHandling({ action(connectionResult.value) }, { connectionResult.value.close() })
|
||||
is EelResult.Error -> errorHandler(connectionResult.error)
|
||||
is EelResult.Ok -> closeWithExceptionHandling({ action(connectionResult.value) }, { connectionResult.value.close() })
|
||||
}
|
||||
|
||||
private suspend fun <T> closeWithExceptionHandling(action: suspend CoroutineScope.() -> T, close: suspend () -> Unit): T {
|
||||
@@ -360,8 +359,8 @@ suspend fun <T> EelTunnelsApi.withAcceptorForRemotePort(
|
||||
action: suspend CoroutineScope.(EelTunnelsApi.ConnectionAcceptor) -> T,
|
||||
): T =
|
||||
when (val connectionResult = getAcceptorForRemotePort(hostAddress)) {
|
||||
is EelNetworkResult.Error -> errorHandler(connectionResult.error)
|
||||
is EelNetworkResult.Ok -> closeWithExceptionHandling({ action(connectionResult.value) }, { connectionResult.value.close() })
|
||||
is EelResult.Error -> errorHandler(connectionResult.error)
|
||||
is EelResult.Ok -> closeWithExceptionHandling({ action(connectionResult.value) }, { connectionResult.value.close() })
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -369,25 +368,6 @@ suspend fun <T> EelTunnelsApi.withAcceptorForRemotePort(
|
||||
*/
|
||||
sealed interface EelNetworkError
|
||||
|
||||
/**
|
||||
* Represents a result of a network operation
|
||||
*/
|
||||
sealed interface EelNetworkResult<out T, out E : EelNetworkError> {
|
||||
/**
|
||||
* Used when a network operation completed successfully
|
||||
*/
|
||||
interface Ok<out T> : EelNetworkResult<T, Nothing> {
|
||||
val value: T
|
||||
}
|
||||
|
||||
/**
|
||||
* Used when a network operation completed with an error
|
||||
*/
|
||||
interface Error<out E : EelNetworkError> : EelNetworkResult<Nothing, E> {
|
||||
val error: E
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An error that can happen during the creation of a connection to a remote server
|
||||
*/
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.eel.fs
|
||||
|
||||
import com.intellij.platform.eel.EelResult
|
||||
import com.intellij.platform.eel.EelUserInfo
|
||||
import com.intellij.platform.eel.EelUserPosixInfo
|
||||
import com.intellij.platform.eel.EelUserWindowsInfo
|
||||
import com.intellij.platform.eel.fs.EelFileSystemApi.StatError
|
||||
import com.intellij.platform.eel.path.EelPath
|
||||
import com.intellij.platform.eel.path.EelPathResult
|
||||
import com.intellij.platform.eel.path.EelPathError
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
fun EelFileSystemApi.getPath(string: String, vararg other: String): EelPathResult<out EelPath.Absolute> {
|
||||
fun EelFileSystemApi.getPath(string: String, vararg other: String): EelResult<out EelPath.Absolute, EelPathError> {
|
||||
return EelPath.Absolute.build(listOf(string, *other), when (this) {
|
||||
is EelFileSystemPosixApi -> EelPath.Absolute.OS.UNIX
|
||||
is EelFileSystemWindowsApi -> EelPath.Absolute.OS.WINDOWS
|
||||
@@ -37,7 +38,7 @@ interface EelFileSystemApi {
|
||||
/**
|
||||
* Returns names of files in a directory. If [path] is a symlink, it will be resolved, but no symlinks are resolved among children.
|
||||
*/
|
||||
suspend fun listDirectory(path: EelPath.Absolute): EelFsResult<
|
||||
suspend fun listDirectory(path: EelPath.Absolute): EelResult<
|
||||
Collection<String>,
|
||||
ListDirectoryError>
|
||||
|
||||
@@ -52,7 +53,7 @@ interface EelFileSystemApi {
|
||||
suspend fun listDirectoryWithAttrs(
|
||||
path: EelPath.Absolute,
|
||||
symlinkPolicy: SymlinkPolicy,
|
||||
): EelFsResult<
|
||||
): EelResult<
|
||||
Collection<Pair<String, EelFileInfo>>,
|
||||
ListDirectoryError>
|
||||
|
||||
@@ -67,7 +68,7 @@ interface EelFileSystemApi {
|
||||
/**
|
||||
* Resolves all symlinks in the path. Corresponds to realpath(3) on Unix and GetFinalPathNameByHandle on Windows.
|
||||
*/
|
||||
suspend fun canonicalize(path: EelPath.Absolute): EelFsResult<
|
||||
suspend fun canonicalize(path: EelPath.Absolute): EelResult<
|
||||
EelPath.Absolute,
|
||||
CanonicalizeError>
|
||||
|
||||
@@ -82,7 +83,7 @@ interface EelFileSystemApi {
|
||||
/**
|
||||
* Similar to stat(2) and lstat(2). [symlinkPolicy] has an impact only on [EelFileInfo.type] if [path] points on a symlink.
|
||||
*/
|
||||
suspend fun stat(path: EelPath.Absolute, symlinkPolicy: SymlinkPolicy): EelFsResult<EelFileInfo, StatError>
|
||||
suspend fun stat(path: EelPath.Absolute, symlinkPolicy: SymlinkPolicy): EelResult<EelFileInfo, StatError>
|
||||
|
||||
/**
|
||||
* Defines the behavior of FS operations on symbolic links
|
||||
@@ -118,7 +119,7 @@ interface EelFileSystemApi {
|
||||
* On Unix return true if both paths have the same inode.
|
||||
* On Windows some heuristics are used, for more details see https://docs.rs/same-file/1.0.6/same_file/
|
||||
*/
|
||||
suspend fun sameFile(source: EelPath.Absolute, target: EelPath.Absolute): EelFsResult<
|
||||
suspend fun sameFile(source: EelPath.Absolute, target: EelPath.Absolute): EelResult<
|
||||
Boolean,
|
||||
SameFileError>
|
||||
|
||||
@@ -133,7 +134,7 @@ interface EelFileSystemApi {
|
||||
/**
|
||||
* Opens the file only for reading
|
||||
*/
|
||||
suspend fun openForReading(path: EelPath.Absolute): EelFsResult<
|
||||
suspend fun openForReading(path: EelPath.Absolute): EelResult<
|
||||
EelOpenedFile.Reader,
|
||||
FileReaderError>
|
||||
|
||||
@@ -151,7 +152,7 @@ interface EelFileSystemApi {
|
||||
*/
|
||||
suspend fun openForWriting(
|
||||
options: WriteOptions,
|
||||
): EelFsResult<
|
||||
): EelResult<
|
||||
EelOpenedFile.Writer,
|
||||
FileWriterError>
|
||||
|
||||
@@ -193,7 +194,7 @@ interface EelFileSystemApi {
|
||||
interface Other : FileWriterError, EelFsError.Other
|
||||
}
|
||||
|
||||
suspend fun openForReadingAndWriting(options: WriteOptions): EelFsResult<EelOpenedFile.ReaderWriter, FileWriterError>
|
||||
suspend fun openForReadingAndWriting(options: WriteOptions): EelResult<EelOpenedFile.ReaderWriter, FileWriterError>
|
||||
|
||||
@Throws(DeleteException::class)
|
||||
suspend fun delete(path: EelPath.Absolute, removeContent: Boolean)
|
||||
@@ -297,7 +298,7 @@ sealed interface EelOpenedFile {
|
||||
: CloseException(where, additionalMessage), EelFsError.Other
|
||||
}
|
||||
|
||||
suspend fun tell(): EelFsResult<
|
||||
suspend fun tell(): EelResult<
|
||||
Long,
|
||||
TellError>
|
||||
|
||||
@@ -305,7 +306,7 @@ sealed interface EelOpenedFile {
|
||||
interface Other : TellError, EelFsError.Other
|
||||
}
|
||||
|
||||
suspend fun seek(offset: Long, whence: SeekWhence): EelFsResult<
|
||||
suspend fun seek(offset: Long, whence: SeekWhence): EelResult<
|
||||
Long,
|
||||
SeekError>
|
||||
|
||||
@@ -325,7 +326,7 @@ sealed interface EelOpenedFile {
|
||||
* Sometimes, the files are inaccessible via [EelFileSystemApi.stat] -- for example, if they are deleted.
|
||||
* In this case, one can get the information about the opened file with the use of this function.
|
||||
*/
|
||||
suspend fun stat(): EelFsResult<EelFileInfo, StatError>
|
||||
suspend fun stat(): EelResult<EelFileInfo, StatError>
|
||||
|
||||
|
||||
interface Reader : EelOpenedFile {
|
||||
@@ -341,7 +342,7 @@ sealed interface EelOpenedFile {
|
||||
*
|
||||
* The implementation MAY read less data than the capacity of the buffer even if it's possible to read the whole requested buffer.
|
||||
*/
|
||||
suspend fun read(buf: ByteBuffer): EelFsResult<ReadResult, ReadError>
|
||||
suspend fun read(buf: ByteBuffer): EelResult<ReadResult, ReadError>
|
||||
|
||||
/**
|
||||
* Reads data from the position [offset] of the file.
|
||||
@@ -350,7 +351,7 @@ sealed interface EelOpenedFile {
|
||||
*
|
||||
* The implementation MAY read less than [offset] bytes even if it's possible to read the whole requested buffer.
|
||||
*/
|
||||
suspend fun read(buf: ByteBuffer, offset: Long): EelFsResult<ReadResult, ReadError>
|
||||
suspend fun read(buf: ByteBuffer, offset: Long): EelResult<ReadResult, ReadError>
|
||||
|
||||
sealed interface ReadResult {
|
||||
interface EOF : ReadResult
|
||||
@@ -372,7 +373,7 @@ sealed interface EelOpenedFile {
|
||||
*
|
||||
* The implementation MAY write the part of the [buf] even if it's possible to write the whole buffer.
|
||||
*/
|
||||
suspend fun write(buf: ByteBuffer): EelFsResult<
|
||||
suspend fun write(buf: ByteBuffer): EelResult<
|
||||
Int,
|
||||
WriteError>
|
||||
|
||||
@@ -381,7 +382,7 @@ sealed interface EelOpenedFile {
|
||||
*
|
||||
* The implementation MAY write the part of the [buf] even if it's possible to write the whole buffer.
|
||||
*/
|
||||
suspend fun write(buf: ByteBuffer, pos: Long): EelFsResult<
|
||||
suspend fun write(buf: ByteBuffer, pos: Long): EelResult<
|
||||
Int,
|
||||
WriteError>
|
||||
|
||||
@@ -459,11 +460,11 @@ interface EelFileSystemPosixApi : EelFileSystemApi {
|
||||
override suspend fun listDirectoryWithAttrs(
|
||||
path: EelPath.Absolute,
|
||||
symlinkPolicy: EelFileSystemApi.SymlinkPolicy,
|
||||
): EelFsResult<
|
||||
): EelResult<
|
||||
Collection<Pair<String, EelPosixFileInfo>>,
|
||||
EelFileSystemApi.ListDirectoryError>
|
||||
|
||||
override suspend fun stat(path: EelPath.Absolute, symlinkPolicy: EelFileSystemApi.SymlinkPolicy): EelFsResult<
|
||||
override suspend fun stat(path: EelPath.Absolute, symlinkPolicy: EelFileSystemApi.SymlinkPolicy): EelResult<
|
||||
EelPosixFileInfo,
|
||||
StatError>
|
||||
|
||||
@@ -528,11 +529,11 @@ interface EelFileSystemWindowsApi : EelFileSystemApi {
|
||||
override suspend fun listDirectoryWithAttrs(
|
||||
path: EelPath.Absolute,
|
||||
symlinkPolicy: EelFileSystemApi.SymlinkPolicy,
|
||||
): EelFsResult<
|
||||
): EelResult<
|
||||
Collection<Pair<String, EelWindowsFileInfo>>,
|
||||
EelFileSystemApi.ListDirectoryError>
|
||||
|
||||
override suspend fun stat(path: EelPath.Absolute, symlinkPolicy: EelFileSystemApi.SymlinkPolicy): EelFsResult<
|
||||
override suspend fun stat(path: EelPath.Absolute, symlinkPolicy: EelFileSystemApi.SymlinkPolicy): EelResult<
|
||||
EelWindowsFileInfo,
|
||||
StatError>
|
||||
}
|
||||
@@ -5,19 +5,6 @@ import com.intellij.platform.eel.path.EelPath
|
||||
import org.jetbrains.annotations.Nls
|
||||
import java.io.IOException
|
||||
|
||||
/**
|
||||
* [T] should not be `Unit`, throw a subclass of [EelFsIOException] in such cases instead.
|
||||
*/
|
||||
sealed interface EelFsResult<out T, E : EelFsError> {
|
||||
interface Ok<out T, E : EelFsError> : EelFsResult<T, E> {
|
||||
val value: T
|
||||
}
|
||||
|
||||
interface Error<T, E : EelFsError> : EelFsResult<T, E> {
|
||||
val error: E
|
||||
}
|
||||
}
|
||||
|
||||
sealed interface EelFsError {
|
||||
val where: EelPath.Absolute
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.eel.path
|
||||
|
||||
import com.intellij.platform.eel.path.EelPathResult.Err
|
||||
import com.intellij.platform.eel.path.EelPathResult.Ok
|
||||
import com.intellij.platform.eel.EelResult
|
||||
|
||||
internal class ArrayListEelAbsolutePath private constructor(
|
||||
private val _root: Root,
|
||||
@@ -34,7 +33,7 @@ internal class ArrayListEelAbsolutePath private constructor(
|
||||
root.fileName == other.root.fileName &&
|
||||
(0..<other.nameCount).all { getName(it) == other.getName(it) }
|
||||
|
||||
override fun normalize(): EelPathResult<out EelPath.Absolute> {
|
||||
override fun normalize(): EelResult<out EelPath.Absolute, EelPathError> {
|
||||
val result = mutableListOf<String>()
|
||||
for (part in parts) {
|
||||
when (part) {
|
||||
@@ -42,7 +41,7 @@ internal class ArrayListEelAbsolutePath private constructor(
|
||||
|
||||
".." ->
|
||||
if (result.isEmpty())
|
||||
return Err(toString(), "Traversing beyond the root")
|
||||
return ErrorResult(Err(toString(), "Traversing beyond the root"))
|
||||
else
|
||||
result.dropLast(1)
|
||||
|
||||
@@ -50,28 +49,28 @@ internal class ArrayListEelAbsolutePath private constructor(
|
||||
result += part
|
||||
}
|
||||
}
|
||||
return Ok(ArrayListEelAbsolutePath(_root, result))
|
||||
return OkResult(ArrayListEelAbsolutePath(_root, result))
|
||||
}
|
||||
|
||||
override fun resolve(other: EelPath.Relative): EelPathResult<out EelPath.Absolute> {
|
||||
override fun resolve(other: EelPath.Relative): EelResult<out EelPath.Absolute, EelPathError> {
|
||||
val result = parts.toMutableList()
|
||||
for (index in 0..<other.nameCount) {
|
||||
val name = other.getName(index).fileName
|
||||
if (name.isNotEmpty()) {
|
||||
val error = checkFileName(name)
|
||||
if (error != null) return Err(other.toString(), error)
|
||||
if (error != null) return ErrorResult(Err(other.toString(), error))
|
||||
result += name
|
||||
}
|
||||
}
|
||||
return Ok(ArrayListEelAbsolutePath(_root, result))
|
||||
return OkResult(ArrayListEelAbsolutePath(_root, result))
|
||||
}
|
||||
|
||||
override fun getChild(name: String): EelPathResult<out EelPath.Absolute> {
|
||||
override fun getChild(name: String): EelResult<out EelPath.Absolute, EelPathError> {
|
||||
val error = checkFileName(name)
|
||||
return if (error == null)
|
||||
Ok(ArrayListEelAbsolutePath(_root, parts + name))
|
||||
OkResult(ArrayListEelAbsolutePath(_root, parts + name))
|
||||
else
|
||||
Err(name, error)
|
||||
ErrorResult(Err(name, error))
|
||||
}
|
||||
|
||||
override fun scan(): Sequence<EelPath.Absolute> =
|
||||
@@ -131,9 +130,9 @@ internal class ArrayListEelAbsolutePath private constructor(
|
||||
return nameCount - other.nameCount
|
||||
}
|
||||
|
||||
override fun relativize(other: EelPath.Absolute): EelPathResult<out EelPath.Relative> {
|
||||
override fun relativize(other: EelPath.Absolute): EelResult<out EelPath.Relative, EelPathError> {
|
||||
if (root != other.root) {
|
||||
return Err(other.root.toString(), "The other path has a different root")
|
||||
return ErrorResult(Err(other.root.toString(), "The other path has a different root"))
|
||||
}
|
||||
|
||||
var firstDifferenceIndex = 0
|
||||
@@ -171,7 +170,7 @@ internal class ArrayListEelAbsolutePath private constructor(
|
||||
})
|
||||
|
||||
companion object {
|
||||
fun build(parts: List<String>, os: EelPath.Absolute.OS?): EelPathResult<out EelPath.Absolute> {
|
||||
fun build(parts: List<String>, os: EelPath.Absolute.OS?): EelResult<out EelPath.Absolute, EelPathError> {
|
||||
require(parts.isNotEmpty()) { "Can't build an absolute path from no path parts" }
|
||||
|
||||
val windowsRoot = when (os) {
|
||||
@@ -190,44 +189,44 @@ internal class ArrayListEelAbsolutePath private constructor(
|
||||
else parts
|
||||
for (part in parts) {
|
||||
val error = checkFileName(part, isWindows = false)
|
||||
if (error != null) return Err(part, error)
|
||||
if (error != null) return ErrorResult(Err(part, error))
|
||||
}
|
||||
return Ok(ArrayListEelAbsolutePath(Root.Unix, parts))
|
||||
return OkResult(ArrayListEelAbsolutePath(Root.Unix, parts))
|
||||
}
|
||||
|
||||
is Ok -> {
|
||||
is EelResult.Ok -> {
|
||||
@Suppress("NAME_SHADOWING") val parts = parts.drop(1)
|
||||
for (part in parts) {
|
||||
val error = checkFileName(part, isWindows = true)
|
||||
if (error != null) return Err(part, error)
|
||||
if (error != null) return ErrorResult(Err(part, error))
|
||||
}
|
||||
return Ok(ArrayListEelAbsolutePath(windowsRoot.path._root, parts))
|
||||
return OkResult(ArrayListEelAbsolutePath(windowsRoot.value._root, parts))
|
||||
}
|
||||
|
||||
is Err -> return windowsRoot
|
||||
is EelResult.Error -> return windowsRoot
|
||||
}
|
||||
}
|
||||
|
||||
fun parse(raw: String, os: EelPath.Absolute.OS?): EelPathResult<ArrayListEelAbsolutePath> =
|
||||
fun parse(raw: String, os: EelPath.Absolute.OS?): EelResult<ArrayListEelAbsolutePath, EelPathError> =
|
||||
when (os) {
|
||||
EelPath.Absolute.OS.WINDOWS ->
|
||||
findAbsoluteUncPath(raw)
|
||||
?: findAbsoluteTraditionalDosPath(raw)
|
||||
?: reportError(raw)
|
||||
?: ErrorResult(createErr(raw))
|
||||
|
||||
EelPath.Absolute.OS.UNIX ->
|
||||
findAbsoluteUnixPath(raw)
|
||||
?: reportError(raw)
|
||||
?: ErrorResult(createErr(raw))
|
||||
|
||||
null ->
|
||||
findAbsoluteUncPath(raw)
|
||||
?: findAbsoluteTraditionalDosPath(raw)
|
||||
?: findAbsoluteUnixPath(raw)
|
||||
?: reportError(raw)
|
||||
?: ErrorResult(createErr(raw))
|
||||
}
|
||||
|
||||
/** https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats#unc-paths */
|
||||
private fun findAbsoluteUncPath(raw: String): EelPathResult<ArrayListEelAbsolutePath>? {
|
||||
private fun findAbsoluteUncPath(raw: String): EelResult<ArrayListEelAbsolutePath, EelPathError>? {
|
||||
if (raw.length < 3) return null
|
||||
if (raw.getOrNull(0) != raw.getOrNull(1)) return null
|
||||
|
||||
@@ -239,12 +238,12 @@ internal class ArrayListEelAbsolutePath private constructor(
|
||||
|
||||
run {
|
||||
val error = checkFileName(raw.substring(2, index), isWindows = true)
|
||||
if (error != null) return Err(raw, "Incorrect server name in UNC path")
|
||||
if (error != null) return ErrorResult(Err(raw, "Incorrect server name in UNC path"))
|
||||
}
|
||||
|
||||
val shareNameStart = index
|
||||
|
||||
if (++index == raw.length) return Err(raw, "Empty share name in UNC path")
|
||||
if (++index == raw.length) return ErrorResult(Err(raw, "Empty share name in UNC path"))
|
||||
|
||||
// Skipping the server/host name.
|
||||
while (raw[index] !in "/\\") {
|
||||
@@ -253,7 +252,7 @@ internal class ArrayListEelAbsolutePath private constructor(
|
||||
|
||||
run {
|
||||
val error = checkFileName(raw.substring(shareNameStart, index), isWindows = true)
|
||||
if (error != null) return Err(raw, "Incorrect share name in UNC path")
|
||||
if (error != null) return ErrorResult(Err(raw, "Incorrect share name in UNC path"))
|
||||
}
|
||||
|
||||
val parts = raw.substring(index)
|
||||
@@ -263,14 +262,14 @@ internal class ArrayListEelAbsolutePath private constructor(
|
||||
|
||||
for (part in parts) {
|
||||
val error = checkFileName(part, isWindows = true)
|
||||
if (error != null) return Err(raw, error)
|
||||
if (error != null) return ErrorResult(Err(raw, error))
|
||||
}
|
||||
|
||||
return Ok(ArrayListEelAbsolutePath(Root.Windows(raw.substring(0, index).replace("/", "\\")), parts))
|
||||
return OkResult(ArrayListEelAbsolutePath(Root.Windows(raw.substring(0, index).replace("/", "\\")), parts))
|
||||
}
|
||||
|
||||
/** https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats#traditional-dos-paths */
|
||||
private fun findAbsoluteTraditionalDosPath(raw: String): EelPathResult<ArrayListEelAbsolutePath>? {
|
||||
private fun findAbsoluteTraditionalDosPath(raw: String): EelResult<ArrayListEelAbsolutePath, EelPathError>? {
|
||||
if (raw.length < 3) return null
|
||||
if (!raw[0].isLetter()) return null
|
||||
if (raw[1] != ':') return null
|
||||
@@ -283,13 +282,13 @@ internal class ArrayListEelAbsolutePath private constructor(
|
||||
|
||||
for (part in parts) {
|
||||
val error = checkFileName(part, isWindows = true)
|
||||
if (error != null) return Err(raw, error)
|
||||
if (error != null) return ErrorResult(Err(raw, error))
|
||||
}
|
||||
|
||||
return Ok(ArrayListEelAbsolutePath(Root.Windows(raw.substring(0, 3)), parts))
|
||||
return OkResult(ArrayListEelAbsolutePath(Root.Windows(raw.substring(0, 3)), parts))
|
||||
}
|
||||
|
||||
private fun findAbsoluteUnixPath(raw: String): EelPathResult<ArrayListEelAbsolutePath>? {
|
||||
private fun findAbsoluteUnixPath(raw: String): EelResult<ArrayListEelAbsolutePath, EelPathError>? {
|
||||
if (raw.getOrNull(0) != '/') return null
|
||||
|
||||
val parts = raw
|
||||
@@ -299,13 +298,13 @@ internal class ArrayListEelAbsolutePath private constructor(
|
||||
|
||||
for (part in parts) {
|
||||
val error = checkFileName(part, isWindows = false)
|
||||
if (error != null) return Err(raw, error)
|
||||
if (error != null) return ErrorResult(Err(raw, error))
|
||||
}
|
||||
|
||||
return Ok(ArrayListEelAbsolutePath(Root.Unix, parts))
|
||||
return OkResult(ArrayListEelAbsolutePath(Root.Unix, parts))
|
||||
}
|
||||
|
||||
private fun reportError(raw: String): Err<ArrayListEelAbsolutePath> =
|
||||
private fun createErr(raw: String): Err =
|
||||
Err(
|
||||
raw = raw,
|
||||
reason = run {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.eel.path
|
||||
|
||||
import com.intellij.platform.eel.EelResult
|
||||
|
||||
internal class ArrayListEelRelativePath private constructor(
|
||||
private val parts: List<String>,
|
||||
) : EelPath.Relative {
|
||||
@@ -24,7 +26,7 @@ internal class ArrayListEelRelativePath private constructor(
|
||||
return true
|
||||
}
|
||||
|
||||
override fun resolve(other: EelPath.Relative): EelPathResult<ArrayListEelRelativePath> {
|
||||
override fun resolve(other: EelPath.Relative): EelResult<ArrayListEelRelativePath, EelPathError> {
|
||||
val result = mutableListOf<String>()
|
||||
result += parts
|
||||
if (other != EMPTY) {
|
||||
@@ -33,14 +35,14 @@ internal class ArrayListEelRelativePath private constructor(
|
||||
result += fileName
|
||||
}
|
||||
}
|
||||
return Ok(ArrayListEelRelativePath(result))
|
||||
return OkResult(ArrayListEelRelativePath(result))
|
||||
}
|
||||
|
||||
override fun getChild(name: String): EelPathResult<ArrayListEelRelativePath> =
|
||||
override fun getChild(name: String): EelResult<ArrayListEelRelativePath, EelPathError> =
|
||||
when {
|
||||
name.isEmpty() -> Err(name, "Empty child name is not allowed")
|
||||
"/" in name -> Err(name, "Invalid symbol in child name: /")
|
||||
else -> Ok(ArrayListEelRelativePath(parts + name))
|
||||
name.isEmpty() -> ErrorResult(Err(name, "Empty child name is not allowed"))
|
||||
"/" in name -> ErrorResult(Err(name, "Invalid symbol in child name: /"))
|
||||
else -> OkResult(ArrayListEelRelativePath(parts + name))
|
||||
}
|
||||
|
||||
override fun compareTo(other: EelPath.Relative): Int {
|
||||
@@ -108,22 +110,22 @@ internal class ArrayListEelRelativePath private constructor(
|
||||
val EMPTY = ArrayListEelRelativePath(listOf())
|
||||
private val REGEX = Regex("""[/\\]""")
|
||||
|
||||
fun parse(raw: String): EelPathResult<ArrayListEelRelativePath> =
|
||||
fun parse(raw: String): EelResult<ArrayListEelRelativePath, EelPathError> =
|
||||
build(raw.splitToSequence(REGEX).filter(String::isNotEmpty).iterator())
|
||||
|
||||
fun build(parts: List<String>): EelPathResult<ArrayListEelRelativePath> =
|
||||
fun build(parts: List<String>): EelResult<ArrayListEelRelativePath, EelPathError> =
|
||||
build(parts.iterator())
|
||||
|
||||
private fun build(parts: Iterator<String>): EelPathResult<ArrayListEelRelativePath> {
|
||||
private fun build(parts: Iterator<String>): EelResult<ArrayListEelRelativePath, EelPathError> {
|
||||
// Not optimal, but DRY.
|
||||
var result = ArrayListEelRelativePath(listOf())
|
||||
for (part in parts) {
|
||||
result = when (val r = result.getChild(part)) {
|
||||
is EelPathResult.Ok -> r.path
|
||||
is EelPathResult.Err -> return r
|
||||
is EelResult.Ok -> r.value
|
||||
is EelResult.Error -> return r
|
||||
}
|
||||
}
|
||||
return Ok(result)
|
||||
return OkResult(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,17 +2,14 @@
|
||||
package com.intellij.platform.eel.path
|
||||
|
||||
import com.intellij.platform.eel.EelPlatform
|
||||
import com.intellij.platform.eel.EelResult
|
||||
import com.intellij.platform.eel.getOrThrow
|
||||
import com.intellij.platform.eel.path.EelPath.Absolute.OS
|
||||
import java.nio.file.InvalidPathException
|
||||
|
||||
sealed interface EelPathResult<P : EelPath> {
|
||||
interface Ok<P : EelPath> : EelPathResult<P> {
|
||||
val path: P
|
||||
}
|
||||
interface Err<P : EelPath> : EelPathResult<P> {
|
||||
val raw: String
|
||||
val reason: String
|
||||
}
|
||||
interface EelPathError {
|
||||
val raw: String
|
||||
val reason: String
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -26,10 +23,10 @@ sealed interface EelPathResult<P : EelPath> {
|
||||
sealed interface EelPath {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun parse(raw: String, os: OS?): EelPathResult<out EelPath> =
|
||||
fun parse(raw: String, os: OS?): EelResult<out EelPath, EelPathError> =
|
||||
when (val absoluteResult = Absolute.parse(raw, os)) {
|
||||
is EelPathResult.Ok -> absoluteResult
|
||||
is EelPathResult.Err -> Relative.parse(raw)
|
||||
is EelResult.Ok -> absoluteResult
|
||||
is EelResult.Error -> Relative.parse(raw)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +99,7 @@ sealed interface EelPath {
|
||||
* // TODO Wouldn't it be better to return different types for relative and absolute paths?
|
||||
* It should fail in cases like Absolute("/").resolve(Relative("..")).
|
||||
*/
|
||||
fun resolve(other: Relative): EelPathResult<out EelPath>
|
||||
fun resolve(other: Relative): EelResult<out EelPath, EelPathError>
|
||||
|
||||
/**
|
||||
* ```kotlin
|
||||
@@ -114,28 +111,28 @@ sealed interface EelPath {
|
||||
* IjentRelativePath.parse("abc", false).getChild("") == Err(...)
|
||||
* ```
|
||||
*/
|
||||
fun getChild(name: String): EelPathResult<out EelPath>
|
||||
fun getChild(name: String): EelResult<out EelPath, EelPathError>
|
||||
|
||||
override fun toString(): String
|
||||
|
||||
interface Relative : EelPath, Comparable<Relative> {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun parse(raw: String): EelPathResult<out Relative> =
|
||||
fun parse(raw: String): EelResult<out Relative, EelPathError> =
|
||||
ArrayListEelRelativePath.parse(raw)
|
||||
|
||||
/**
|
||||
* The parts of the path must not contain / or \.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun build(vararg parts: String): EelPathResult<out Relative> =
|
||||
fun build(vararg parts: String): EelResult<out Relative, EelPathError> =
|
||||
build(listOf(*parts))
|
||||
|
||||
/**
|
||||
* The parts of the path must not contain / or \.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun build(parts: List<String>): EelPathResult<out Relative> =
|
||||
fun build(parts: List<String>): EelResult<out Relative, EelPathError> =
|
||||
ArrayListEelRelativePath.build(parts)
|
||||
|
||||
@JvmField
|
||||
@@ -147,9 +144,9 @@ sealed interface EelPath {
|
||||
/** See [java.nio.file.Path.startsWith] */
|
||||
fun startsWith(other: Relative): Boolean
|
||||
|
||||
override fun resolve(other: Relative): EelPathResult<out Relative>
|
||||
override fun resolve(other: Relative): EelResult<out Relative, EelPathError>
|
||||
|
||||
override fun getChild(name: String): EelPathResult<out Relative>
|
||||
override fun getChild(name: String): EelResult<out Relative, EelPathError>
|
||||
|
||||
override fun compareTo(other: Relative): Int
|
||||
|
||||
@@ -177,15 +174,15 @@ sealed interface EelPath {
|
||||
interface Absolute : EelPath, Comparable<Absolute> {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun parse(raw: String, os: OS?): EelPathResult<out Absolute> =
|
||||
fun parse(raw: String, os: OS?): EelResult<out Absolute, EelPathError> =
|
||||
ArrayListEelAbsolutePath.parse(raw, os)
|
||||
|
||||
@JvmStatic
|
||||
fun build(vararg parts: String): EelPathResult<out Absolute> =
|
||||
fun build(vararg parts: String): EelResult<out Absolute, EelPathError> =
|
||||
build(listOf(*parts), null)
|
||||
|
||||
@JvmStatic
|
||||
fun build(parts: List<String>, os: OS?): EelPathResult<out Absolute> =
|
||||
fun build(parts: List<String>, os: OS?): EelResult<out Absolute, EelPathError> =
|
||||
ArrayListEelAbsolutePath.build(parts, os)
|
||||
}
|
||||
|
||||
@@ -204,10 +201,10 @@ sealed interface EelPath {
|
||||
fun startsWith(other: Absolute): Boolean
|
||||
|
||||
/** See [java.nio.file.Path.normalize] */
|
||||
fun normalize(): EelPathResult<out Absolute>
|
||||
fun normalize(): EelResult<out Absolute, EelPathError>
|
||||
|
||||
/** See [java.nio.file.Path.resolve] */
|
||||
override fun resolve(other: Relative): EelPathResult<out Absolute>
|
||||
override fun resolve(other: Relative): EelResult<out Absolute, EelPathError>
|
||||
|
||||
/**
|
||||
* See [java.nio.file.Path.relativize].
|
||||
@@ -217,9 +214,9 @@ sealed interface EelPath {
|
||||
* == IjentPathAbsolute.parse("..\..\oops", isWindows = true)
|
||||
* ```
|
||||
*/
|
||||
fun relativize(other: Absolute): EelPathResult<out Relative>
|
||||
fun relativize(other: Absolute): EelResult<out Relative, EelPathError>
|
||||
|
||||
override fun getChild(name: String): EelPathResult<out Absolute>
|
||||
override fun getChild(name: String): EelResult<out Absolute, EelPathError>
|
||||
|
||||
fun scan(): Sequence<Absolute>
|
||||
|
||||
@@ -232,11 +229,7 @@ sealed interface EelPath {
|
||||
}
|
||||
|
||||
@Throws(InvalidPathException::class)
|
||||
fun <P : EelPath> EelPathResult<P>.getOrThrow(): P =
|
||||
when (this) {
|
||||
is EelPathResult.Ok -> path
|
||||
is EelPathResult.Err -> throw InvalidPathException(raw, reason)
|
||||
}
|
||||
fun <P : EelPath, E : EelPathError> EelResult<P, E>.getOrThrow(): P = getOrThrow { throw InvalidPathException(it.raw, it.reason) }
|
||||
|
||||
val EelPlatform.pathOs: OS
|
||||
get() = when (this) {
|
||||
|
||||
@@ -2,5 +2,8 @@
|
||||
@file:JvmName("EelPathResultImpl")
|
||||
package com.intellij.platform.eel.path
|
||||
|
||||
internal data class Ok<P : EelPath>(override val path: P) : EelPathResult.Ok<P>
|
||||
internal data class Err<P : EelPath>(override val raw: String, override val reason: String) : EelPathResult.Err<P>
|
||||
import com.intellij.platform.eel.EelResult
|
||||
|
||||
internal data class OkResult<P : EelPath>(override val value: P) : EelResult.Ok<P, EelPathError>
|
||||
internal data class ErrorResult<P : EelPath>(override val error: EelPathError) : EelResult.Error<P, EelPathError>
|
||||
internal data class Err(override val raw: String, override val reason: String) : EelPathError
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.eel.path
|
||||
|
||||
import com.intellij.platform.eel.EelResult
|
||||
import io.kotest.matchers.shouldBe
|
||||
import io.kotest.matchers.types.shouldBeInstanceOf
|
||||
import org.junit.jupiter.api.DynamicTest
|
||||
@@ -36,8 +37,8 @@ class EelAbsolutePathTest {
|
||||
add(dynamicTest(rawPath) {
|
||||
val eelPath = EelPath.Absolute
|
||||
.parse(rawPath, null)
|
||||
.shouldBeInstanceOf<EelPathResult.Ok<EelPath.Absolute>>()
|
||||
.path
|
||||
.shouldBeInstanceOf<EelResult.Ok<EelPath.Absolute, EelPathError>>()
|
||||
.value
|
||||
eelPath.toString() shouldBe rawPath
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
package com.intellij.platform.eel.impl.local
|
||||
|
||||
import com.intellij.platform.eel.EelExecApi
|
||||
import com.intellij.platform.eel.EelProcess
|
||||
import com.intellij.platform.eel.EelResult
|
||||
import com.intellij.platform.eel.provider.EelProcessResultImpl
|
||||
import com.pty4j.PtyProcessBuilder
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import java.io.File
|
||||
@@ -9,7 +12,7 @@ import java.io.IOException
|
||||
|
||||
@ApiStatus.Internal
|
||||
class EelLocalExecApi : EelExecApi {
|
||||
override suspend fun execute(builder: EelExecApi.ExecuteProcessBuilder): EelExecApi.ExecuteProcessResult {
|
||||
override suspend fun execute(builder: EelExecApi.ExecuteProcessBuilder): EelResult<EelProcess, EelExecApi.ExecuteProcessError> {
|
||||
val args = builder.args.toTypedArray()
|
||||
val pty = builder.pty
|
||||
|
||||
@@ -35,9 +38,9 @@ class EelLocalExecApi : EelExecApi {
|
||||
}
|
||||
}
|
||||
catch (e: IOException) {
|
||||
return EelExecApi.ExecuteProcessResult.Failure(-1, e.toString())
|
||||
return EelProcessResultImpl.createErrorResult(-1, e.toString())
|
||||
}
|
||||
return EelExecApi.ExecuteProcessResult.Success(process)
|
||||
return EelProcessResultImpl.createOkResult(process)
|
||||
}
|
||||
|
||||
override suspend fun fetchLoginShellEnvVariables(): Map<String, String> = System.getenv()
|
||||
|
||||
@@ -7,14 +7,14 @@ import com.intellij.platform.eel.fs.EelFileSystemPosixApi
|
||||
import com.intellij.platform.eel.fs.EelFileSystemWindowsApi
|
||||
import com.intellij.platform.eel.fs.getPath
|
||||
import com.intellij.platform.eel.path.EelPath
|
||||
import com.intellij.platform.eel.path.getOrThrow
|
||||
import com.intellij.platform.eel.provider.EelUserPosixInfoImpl
|
||||
import com.intellij.platform.eel.provider.EelUserWindowsInfoImpl
|
||||
import com.intellij.platform.eel.provider.utils.unwrap
|
||||
import java.nio.file.Path
|
||||
|
||||
internal class LocalEelPathMapper(private val eelApi: EelApi) : EelPathMapper {
|
||||
override fun getOriginalPath(path: Path): EelPath.Absolute {
|
||||
return eelApi.fs.getPath(path.toString()).unwrap()
|
||||
return eelApi.fs.getPath(path.toString()).getOrThrow()
|
||||
}
|
||||
|
||||
override fun toNioPath(path: EelPath.Absolute): Path {
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.eel.provider
|
||||
|
||||
import com.intellij.platform.eel.EelResult
|
||||
import com.intellij.platform.eel.fs.EelFileSystemApi
|
||||
import com.intellij.platform.eel.fs.EelFsError
|
||||
import com.intellij.platform.eel.fs.EelFsResult
|
||||
import com.intellij.platform.eel.fs.EelOpenedFile
|
||||
import com.intellij.platform.eel.path.EelPath
|
||||
|
||||
@Suppress("unused") // Usages are to be implemented later.
|
||||
object EelFsResultImpl {
|
||||
data class Ok<T, E : EelFsError>(override val value: T) : EelFsResult.Ok<T, E>
|
||||
data class Error<T, E : EelFsError>(override val error: E) : EelFsResult.Error<T, E>
|
||||
data class Ok<T, E : EelFsError>(override val value: T) : EelResult.Ok<T, E>
|
||||
data class Error<T, E : EelFsError>(override val error: E) : EelResult.Error<T, E>
|
||||
|
||||
data class BytesReadImpl(override val bytesRead: Int) : EelOpenedFile.Reader.ReadResult.Bytes
|
||||
data object EOFImpl : EelOpenedFile.Reader.ReadResult.EOF
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.eel.provider
|
||||
|
||||
import com.intellij.platform.eel.EelExecApi
|
||||
import com.intellij.platform.eel.EelProcess
|
||||
import com.intellij.platform.eel.EelResult
|
||||
import org.jetbrains.annotations.ApiStatus.Internal
|
||||
|
||||
@Internal
|
||||
object EelProcessResultImpl {
|
||||
private data class Ok(override val value: EelProcess) : EelResult.Ok<EelProcess, EelExecApi.ExecuteProcessError>
|
||||
private data class Error(override val error: EelExecApi.ExecuteProcessError) : EelResult.Error<EelProcess, EelExecApi.ExecuteProcessError>
|
||||
private data class ExecuteProcessError(override val errno: Int, override val message: String) : EelExecApi.ExecuteProcessError
|
||||
|
||||
fun createOkResult(process: EelProcess): EelResult.Ok<EelProcess, EelExecApi.ExecuteProcessError> = Ok(process)
|
||||
fun createErrorResult(errno: Int, message: String): EelResult.Error<EelProcess, EelExecApi.ExecuteProcessError> = Error(ExecuteProcessError(errno, message))
|
||||
}
|
||||
@@ -4,14 +4,6 @@ package com.intellij.platform.eel.provider.utils
|
||||
import com.intellij.openapi.progress.runBlockingMaybeCancellable
|
||||
import com.intellij.platform.eel.fs.EelFileSystemApi
|
||||
import com.intellij.platform.eel.path.EelPath
|
||||
import com.intellij.platform.eel.path.EelPathResult
|
||||
|
||||
fun <T : EelPath> EelPathResult<T>.unwrap(): T {
|
||||
return when (this) {
|
||||
is EelPathResult.Ok -> path
|
||||
is EelPathResult.Err -> throw RuntimeException(reason)
|
||||
}
|
||||
}
|
||||
|
||||
fun EelFileSystemApi.userHomeBlocking(): EelPath.Absolute? {
|
||||
return runBlockingMaybeCancellable {
|
||||
|
||||
@@ -5,27 +5,13 @@ import com.intellij.execution.process.ProcessOutput
|
||||
import com.intellij.platform.eel.*
|
||||
import com.intellij.platform.eel.fs.getPath
|
||||
import com.intellij.platform.eel.path.EelPath
|
||||
import com.intellij.platform.eel.path.getOrThrow
|
||||
import com.intellij.util.io.computeDetached
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.channels.consumeEach
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.IOException
|
||||
|
||||
/**
|
||||
* Unwraps the `ExecuteProcessResult` instance, returning the underlying `EelProcess` if the result is a success,
|
||||
* or throws an `IOException` if the result is a failure.
|
||||
*
|
||||
* @throws IOException if the `ExecuteProcessResult` is `Failure`.
|
||||
* @return the `EelProcess` if the `ExecuteProcessResult` is `Success`.
|
||||
*/
|
||||
fun EelExecApi.ExecuteProcessResult.unwrap(): EelProcess {
|
||||
return when (this) {
|
||||
is EelExecApi.ExecuteProcessResult.Success -> process
|
||||
is EelExecApi.ExecuteProcessResult.Failure -> throw RuntimeException(toString())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that awaits the completion of an [EelProcess] and retrieves its execution result,
|
||||
@@ -92,13 +78,13 @@ suspend fun EelApi.where(exe: String): EelPath.Absolute? {
|
||||
else -> throw IllegalArgumentException("Unsupported OS: $this")
|
||||
}
|
||||
|
||||
val result = exec.executeProcess(tool, exe).unwrap().awaitProcessResult()
|
||||
val result = exec.executeProcess(tool, exe).getOrThrow().awaitProcessResult()
|
||||
|
||||
if (result.exitCode != 0) {
|
||||
// TODO: log error?/throw Exception?
|
||||
return null
|
||||
}
|
||||
else {
|
||||
return fs.getPath(result.stdout).unwrap()
|
||||
return fs.getPath(result.stdout).getOrThrow()
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.openapi.diagnostic.runAndLogException
|
||||
import com.intellij.openapi.project.DumbAwareAction
|
||||
import com.intellij.openapi.ui.Messages
|
||||
import com.intellij.platform.eel.EelExecApi
|
||||
import com.intellij.platform.eel.EelResult
|
||||
import com.intellij.platform.eel.executeProcess
|
||||
import com.intellij.platform.ide.progress.ModalTaskOwner
|
||||
import com.intellij.platform.ide.progress.TaskCancellation
|
||||
@@ -77,8 +77,8 @@ abstract class AbstractIjentVerificationAction : DumbAwareAction() {
|
||||
|
||||
launch {
|
||||
val process = when (val p = ijent.exec.executeProcess("uname", "-a")) {
|
||||
is EelExecApi.ExecuteProcessResult.Failure -> error(p)
|
||||
is EelExecApi.ExecuteProcessResult.Success -> p.process
|
||||
is EelResult.Error -> error(p)
|
||||
is EelResult.Ok -> p.value
|
||||
}
|
||||
val stdout = ByteArrayOutputStream()
|
||||
process.stdout.consumeEach(stdout::write)
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.ijent.community.impl
|
||||
|
||||
import com.intellij.platform.eel.EelResult
|
||||
import com.intellij.platform.eel.EelUserPosixInfo
|
||||
import com.intellij.platform.eel.fs.*
|
||||
import com.intellij.platform.eel.fs.EelFileSystemApi
|
||||
import com.intellij.platform.eel.fs.EelFileSystemPosixApi
|
||||
import com.intellij.platform.eel.fs.EelOpenedFile
|
||||
import com.intellij.platform.eel.fs.EelPosixFileInfo
|
||||
import com.intellij.platform.eel.path.EelPath
|
||||
import com.intellij.platform.ijent.IjentApi
|
||||
import com.intellij.platform.ijent.IjentPosixApi
|
||||
@@ -104,7 +108,7 @@ private class IjentFailSafeFileSystemPosixApiImpl(
|
||||
|
||||
override suspend fun listDirectory(
|
||||
path: EelPath.Absolute,
|
||||
): EelFsResult<Collection<String>, EelFileSystemApi.ListDirectoryError> =
|
||||
): EelResult<Collection<String>, EelFileSystemApi.ListDirectoryError> =
|
||||
holder.withDelegateRetrying {
|
||||
listDirectory(path)
|
||||
}
|
||||
@@ -121,7 +125,7 @@ private class IjentFailSafeFileSystemPosixApiImpl(
|
||||
override suspend fun listDirectoryWithAttrs(
|
||||
path: EelPath.Absolute,
|
||||
symlinkPolicy: EelFileSystemApi.SymlinkPolicy,
|
||||
): EelFsResult<Collection<Pair<String, EelPosixFileInfo>>, EelFileSystemApi.ListDirectoryError> {
|
||||
): EelResult<Collection<Pair<String, EelPosixFileInfo>>, EelFileSystemApi.ListDirectoryError> {
|
||||
return holder.withDelegateRetrying {
|
||||
listDirectoryWithAttrs(path, symlinkPolicy)
|
||||
}
|
||||
@@ -129,7 +133,7 @@ private class IjentFailSafeFileSystemPosixApiImpl(
|
||||
|
||||
override suspend fun canonicalize(
|
||||
path: EelPath.Absolute,
|
||||
): EelFsResult<EelPath.Absolute, EelFileSystemApi.CanonicalizeError> =
|
||||
): EelResult<EelPath.Absolute, EelFileSystemApi.CanonicalizeError> =
|
||||
holder.withDelegateRetrying {
|
||||
canonicalize(path)
|
||||
}
|
||||
@@ -137,7 +141,7 @@ private class IjentFailSafeFileSystemPosixApiImpl(
|
||||
override suspend fun stat(
|
||||
path: EelPath.Absolute,
|
||||
symlinkPolicy: EelFileSystemApi.SymlinkPolicy,
|
||||
): EelFsResult<EelPosixFileInfo, EelFileSystemApi.StatError> =
|
||||
): EelResult<EelPosixFileInfo, EelFileSystemApi.StatError> =
|
||||
holder.withDelegateRetrying {
|
||||
stat(path, symlinkPolicy)
|
||||
}
|
||||
@@ -145,28 +149,28 @@ private class IjentFailSafeFileSystemPosixApiImpl(
|
||||
override suspend fun sameFile(
|
||||
source: EelPath.Absolute,
|
||||
target: EelPath.Absolute,
|
||||
): EelFsResult<Boolean, EelFileSystemApi.SameFileError> =
|
||||
): EelResult<Boolean, EelFileSystemApi.SameFileError> =
|
||||
holder.withDelegateRetrying {
|
||||
sameFile(source, target)
|
||||
}
|
||||
|
||||
override suspend fun openForReading(
|
||||
path: EelPath.Absolute,
|
||||
): EelFsResult<EelOpenedFile.Reader, EelFileSystemApi.FileReaderError> =
|
||||
): EelResult<EelOpenedFile.Reader, EelFileSystemApi.FileReaderError> =
|
||||
holder.withDelegateRetrying {
|
||||
openForReading(path)
|
||||
}
|
||||
|
||||
override suspend fun openForWriting(
|
||||
options: EelFileSystemApi.WriteOptions,
|
||||
): EelFsResult<EelOpenedFile.Writer, EelFileSystemApi.FileWriterError> =
|
||||
): EelResult<EelOpenedFile.Writer, EelFileSystemApi.FileWriterError> =
|
||||
holder.withDelegateRetrying {
|
||||
openForWriting(options)
|
||||
}
|
||||
|
||||
override suspend fun openForReadingAndWriting(
|
||||
options: EelFileSystemApi.WriteOptions,
|
||||
): EelFsResult<EelOpenedFile.ReaderWriter, EelFileSystemApi.FileWriterError> =
|
||||
): EelResult<EelOpenedFile.ReaderWriter, EelFileSystemApi.FileWriterError> =
|
||||
holder.withDelegateRetrying {
|
||||
openForReadingAndWriting(options)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,9 @@ package com.intellij.platform.ijent.community.impl.nio
|
||||
|
||||
import com.intellij.platform.eel.path.EelPath
|
||||
import com.intellij.platform.eel.path.getOrThrow
|
||||
import com.intellij.platform.ijent.fs.*
|
||||
import com.intellij.platform.ijent.fs.IjentFileSystemApi
|
||||
import com.intellij.platform.ijent.fs.IjentFileSystemPosixApi
|
||||
import com.intellij.platform.ijent.fs.IjentFileSystemWindowsApi
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import java.net.URI
|
||||
import java.nio.file.FileStore
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
package com.intellij.platform.ijent.community.impl.nio
|
||||
|
||||
import com.intellij.platform.eel.EelResult
|
||||
import com.intellij.platform.eel.fs.EelFileSystemApi
|
||||
import com.intellij.platform.eel.fs.EelFsError
|
||||
import com.intellij.platform.eel.fs.EelFsResult
|
||||
import com.intellij.platform.eel.fs.EelOpenedFile
|
||||
import com.intellij.platform.eel.path.EelPath
|
||||
import com.intellij.platform.eel.path.getOrThrow
|
||||
@@ -13,16 +13,15 @@ import com.intellij.util.text.nullize
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import java.io.IOException
|
||||
import java.nio.file.*
|
||||
import kotlin.Throws
|
||||
import kotlin.coroutines.Continuation
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.startCoroutine
|
||||
|
||||
@Throws(FileSystemException::class)
|
||||
internal fun <T, E : EelFsError> EelFsResult<T, E>.getOrThrowFileSystemException(): T =
|
||||
internal fun <T, E : EelFsError> EelResult<T, E>.getOrThrowFileSystemException(): T =
|
||||
when (this) {
|
||||
is EelFsResult.Ok -> value
|
||||
is EelFsResult.Error -> error.throwFileSystemException()
|
||||
is EelResult.Ok -> value
|
||||
is EelResult.Error -> error.throwFileSystemException()
|
||||
}
|
||||
|
||||
// TODO There's java.nio.file.FileSystemLoopException, so ELOOP should be added to all error codes for a decent support of all exceptions.
|
||||
|
||||
@@ -4,9 +4,10 @@ package com.intellij.execution.eel
|
||||
import com.intellij.execution.ijent.nio.IjentEphemeralRootAwarePath
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.platform.eel.*
|
||||
import com.intellij.platform.eel.EelExecApi.ExecuteProcessError
|
||||
import com.intellij.platform.eel.fs.getPath
|
||||
import com.intellij.platform.eel.path.EelPath
|
||||
import com.intellij.platform.eel.provider.utils.unwrap
|
||||
import com.intellij.platform.eel.path.getOrThrow
|
||||
import org.jetbrains.annotations.ApiStatus.Internal
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.pathString
|
||||
@@ -47,7 +48,7 @@ private class EelEphemeralRootAwareMapper(
|
||||
) : EelPathMapper {
|
||||
override fun getOriginalPath(path: Path): EelPath.Absolute? {
|
||||
return if (path is IjentEphemeralRootAwarePath) {
|
||||
eelApi.fs.getPath(path.originalPath.toString()).unwrap()
|
||||
eelApi.fs.getPath(path.originalPath.toString()).getOrThrow()
|
||||
}
|
||||
else {
|
||||
null
|
||||
@@ -72,7 +73,7 @@ private class EelExecApiWithNormalization(
|
||||
private val original: EelExecApi,
|
||||
private val normalize: (EelExecApi.ExecuteProcessBuilder) -> EelExecApi.ExecuteProcessBuilder,
|
||||
) : EelExecApi by original {
|
||||
override suspend fun execute(builder: EelExecApi.ExecuteProcessBuilder): EelExecApi.ExecuteProcessResult {
|
||||
override suspend fun execute(builder: EelExecApi.ExecuteProcessBuilder): EelResult<EelProcess, ExecuteProcessError> {
|
||||
return original.execute(normalize(builder))
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.platform.eel.EelExecApi
|
||||
import com.intellij.platform.eel.EelExecApi.Arguments.executeProcessBuilder
|
||||
import com.intellij.platform.eel.EelResult
|
||||
import com.intellij.platform.ijent.IjentChildProcess
|
||||
import com.intellij.util.concurrency.annotations.RequiresBackgroundThread
|
||||
import com.intellij.util.concurrency.annotations.RequiresBlockingContext
|
||||
@@ -136,13 +137,13 @@ fun runProcessBlocking(
|
||||
.pty(pty)
|
||||
.workingDirectory(workingDirectory)
|
||||
)) {
|
||||
is EelExecApi.ExecuteProcessResult.Success ->
|
||||
(processResult.process as IjentChildProcess).toProcess(
|
||||
is EelResult.Ok ->
|
||||
(processResult.value as IjentChildProcess).toProcess(
|
||||
coroutineScope = scope,
|
||||
isPty = pty != null,
|
||||
redirectStderr = processBuilder.redirectErrorStream(),
|
||||
)
|
||||
is EelExecApi.ExecuteProcessResult.Failure -> throw IOException(processResult.message)
|
||||
is EelResult.Error -> throw IOException(processResult.error.message)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.intellij.openapi.util.SystemInfoRt
|
||||
import com.intellij.platform.eel.EelExecApi
|
||||
import com.intellij.platform.eel.EelExecApi.Pty
|
||||
import com.intellij.platform.eel.EelProcess
|
||||
import com.intellij.platform.eel.EelResult
|
||||
import com.intellij.platform.eel.impl.local.EelLocalExecApi
|
||||
import com.intellij.testFramework.UsefulTestCase.IS_UNDER_TEAMCITY
|
||||
import com.intellij.testFramework.common.timeoutRunBlocking
|
||||
@@ -90,9 +91,9 @@ class EelLocalExecApiTest {
|
||||
PTYManagement.PTY_RESIZE_LATER -> Pty(PTY_COLS - 1, PTY_ROWS - 1, true) // wrong tty size: will resize in the test
|
||||
})
|
||||
when (val r = EelLocalExecApi().execute(builder)) {
|
||||
is EelExecApi.ExecuteProcessResult.Failure -> Assertions.fail(r.message)
|
||||
is EelExecApi.ExecuteProcessResult.Success -> {
|
||||
val process = r.process
|
||||
is EelResult.Error -> Assertions.fail(r.error.message)
|
||||
is EelResult.Ok -> {
|
||||
val process = r.value
|
||||
|
||||
// Resize tty
|
||||
when (ptyManagement) {
|
||||
|
||||
@@ -14,9 +14,9 @@ import com.intellij.openapi.util.Computable
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.openapi.util.use
|
||||
import com.intellij.platform.eel.EelExecApi
|
||||
import com.intellij.platform.eel.EelPlatform
|
||||
import com.intellij.platform.eel.EelUserPosixInfo
|
||||
import com.intellij.platform.eel.*
|
||||
import com.intellij.platform.eel.EelExecApi.ExecuteProcessError
|
||||
import com.intellij.platform.eel.provider.EelProcessResultImpl
|
||||
import com.intellij.platform.ijent.IjentExecApi
|
||||
import com.intellij.platform.ijent.IjentPosixApi
|
||||
import com.intellij.platform.ijent.IjentProcessInfo
|
||||
@@ -501,7 +501,7 @@ class WSLDistributionTest {
|
||||
val err = shouldThrow<ProcessNotCreatedException> {
|
||||
sourceCommandLine.createProcess()
|
||||
}
|
||||
err.message should be(executeResultMock.message)
|
||||
err.message should be(executeResultMock.error.message)
|
||||
}
|
||||
adapter
|
||||
}
|
||||
@@ -532,7 +532,7 @@ private class MockIjentApi(private val adapter: GeneralCommandLine, val rootUser
|
||||
private class MockIjentExecApi(private val adapter: GeneralCommandLine, private val rootUser: Boolean) : IjentExecApi {
|
||||
|
||||
|
||||
override suspend fun execute(builder: EelExecApi.ExecuteProcessBuilder): EelExecApi.ExecuteProcessResult = executeResultMock.also {
|
||||
override suspend fun execute(builder: EelExecApi.ExecuteProcessBuilder): EelResult<EelProcess, ExecuteProcessError> = executeResultMock.also {
|
||||
adapter.exePath = builder.exe
|
||||
if (rootUser) {
|
||||
adapter.putUserData(TEST_ROOT_USER_SET, true)
|
||||
@@ -549,7 +549,7 @@ private val TEST_ROOT_USER_SET by lazy { Key.create<Boolean>("TEST_ROOT_USER_SET
|
||||
|
||||
|
||||
private val executeResultMock by lazy {
|
||||
EelExecApi.ExecuteProcessResult.Failure(errno = 12345, message = "mock result ${Ksuid.generate()}")
|
||||
EelProcessResultImpl.createErrorResult(errno = 12345, message = "mock result ${Ksuid.generate()}")
|
||||
}
|
||||
|
||||
private class WslTestStrategyExtension
|
||||
|
||||
Reference in New Issue
Block a user