mirror of
https://github.com/enso-org/enso.git
synced 2024-12-23 08:53:31 +03:00
Add attributes to filesystem events (#8767)
close #8200 Changelog: - add: `attributes` field to the file event notification
This commit is contained in:
parent
04b0d266e8
commit
51540e2eb2
@ -2350,6 +2350,7 @@ of the (possibly multiple) content roots.
|
||||
interface FileEventNotification {
|
||||
path: Path;
|
||||
kind: FileEventKind;
|
||||
attributes?: FileAttributes;
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -8,8 +8,13 @@ import org.enso.filewatcher.Watcher
|
||||
*
|
||||
* @param path path to the file system object
|
||||
* @param kind type of file system event
|
||||
* @param attributes the file attributes
|
||||
*/
|
||||
case class FileEvent(path: Path, kind: FileEventKind)
|
||||
case class FileEvent(
|
||||
path: Path,
|
||||
kind: FileEventKind,
|
||||
attributes: Either[FileSystemFailure, FileAttributes]
|
||||
)
|
||||
|
||||
object FileEvent {
|
||||
|
||||
@ -18,21 +23,27 @@ object FileEvent {
|
||||
* @param root a project root
|
||||
* @param base a watched path
|
||||
* @param event a file system event
|
||||
* @param attributes a file attributes
|
||||
* @return file event
|
||||
*/
|
||||
def fromWatcherEvent(
|
||||
root: File,
|
||||
base: Path,
|
||||
event: Watcher.WatcherEvent
|
||||
): FileEvent =
|
||||
event: Watcher.WatcherEvent,
|
||||
attributes: Either[FileSystemFailure, FileSystemApi.Attributes]
|
||||
): FileEvent = {
|
||||
val eventPath = Path.getRelativePath(root, base, event.path)
|
||||
FileEvent(
|
||||
Path.getRelativePath(root, base, event.path),
|
||||
FileEventKind(event.eventType)
|
||||
eventPath,
|
||||
FileEventKind(event.eventType),
|
||||
attributes.map(
|
||||
FileAttributes.fromFileSystemAttributes(root, eventPath, _)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Type of a file event.
|
||||
*/
|
||||
/** Type of a file event. */
|
||||
sealed trait FileEventKind extends EnumEntry
|
||||
|
||||
object FileEventKind extends Enum[FileEventKind] with CirceEnum[FileEventKind] {
|
||||
|
@ -183,7 +183,11 @@ object FileManagerApi {
|
||||
|
||||
case object EventFile extends Method("file/event") {
|
||||
|
||||
case class Params(path: Path, kind: FileEventKind)
|
||||
case class Params(
|
||||
path: Path,
|
||||
kind: FileEventKind,
|
||||
attributes: Option[FileAttributes]
|
||||
)
|
||||
|
||||
implicit val hasParams: HasParams.Aux[this.type, EventFile.Params] =
|
||||
new HasParams[this.type] {
|
||||
|
@ -140,7 +140,17 @@ final class PathWatcher(
|
||||
|
||||
case e: Watcher.WatcherEvent =>
|
||||
restartCounter.reset()
|
||||
val event = FileEvent.fromWatcherEvent(root, base, e)
|
||||
|
||||
val fileInfo =
|
||||
if (e.eventType == Watcher.EventTypeDelete) ZIO.fail(FileNotFound)
|
||||
else fs.info(e.path.toFile)
|
||||
|
||||
exec
|
||||
.exec(fileInfo)
|
||||
.map(FileEvent.fromWatcherEvent(root, base, e, _))
|
||||
.pipeTo(self)
|
||||
|
||||
case event: FileEvent =>
|
||||
clients.foreach(_ ! FileEventResult(event))
|
||||
context.system.eventStream.publish(event)
|
||||
|
||||
|
@ -354,13 +354,16 @@ class JsonConnectionController(
|
||||
FileModifiedOnDisk.Params(path)
|
||||
)
|
||||
|
||||
case TextProtocol.FileEvent(path, event) =>
|
||||
webActor ! Notification(EventFile, EventFile.Params(path, event))
|
||||
case TextProtocol.FileEvent(path, event, attributes) =>
|
||||
webActor ! Notification(
|
||||
EventFile,
|
||||
EventFile.Params(path, event, attributes)
|
||||
)
|
||||
|
||||
case PathWatcherProtocol.FileEventResult(event) =>
|
||||
webActor ! Notification(
|
||||
EventFile,
|
||||
EventFile.Params(event.path, event.kind)
|
||||
EventFile.Params(event.path, event.kind, event.attributes.toOption)
|
||||
)
|
||||
|
||||
case ContextRegistryProtocol
|
||||
|
@ -215,7 +215,7 @@ class BufferRegistry(
|
||||
registry
|
||||
)
|
||||
|
||||
case msg @ FileEvent(path, kind) =>
|
||||
case msg @ FileEvent(path, kind, _) =>
|
||||
if (kind == FileEventKind.Added || kind == FileEventKind.Modified) {
|
||||
registry.get(path).foreach { buffer =>
|
||||
buffer ! msg
|
||||
|
@ -324,81 +324,37 @@ class CollaborativeBuffer(
|
||||
)
|
||||
)
|
||||
|
||||
case FileEvent(path, _) =>
|
||||
fileManager ! FileManagerProtocol.InfoFile(path)
|
||||
val timeoutCancellable = context.system.scheduler.scheduleOnce(
|
||||
timingsConfig.requestTimeout,
|
||||
self,
|
||||
IOTimeout
|
||||
)
|
||||
context.become(
|
||||
waitingOnFileEventContent(
|
||||
path,
|
||||
buffer,
|
||||
timeoutCancellable,
|
||||
clients,
|
||||
lockHolder,
|
||||
autoSave
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
private def waitingOnFileEventContent(
|
||||
path: Path,
|
||||
buffer: Buffer,
|
||||
timeoutCancellable: Cancellable,
|
||||
clients: Map[ClientId, JsonSession],
|
||||
lockHolder: Option[JsonSession],
|
||||
autoSave: Map[ClientId, (ContentVersion, Cancellable)]
|
||||
): Receive = {
|
||||
case FileManagerProtocol.InfoFileResult(Right(attrs)) =>
|
||||
timeoutCancellable.cancel()
|
||||
val newBuffer = buffer.fileWithMetadata.lastModifiedTime.map {
|
||||
bufferLastModifiedTime =>
|
||||
if (attrs.lastModifiedTime.isAfter(bufferLastModifiedTime)) {
|
||||
clients.values.foreach {
|
||||
_.rpcController ! FileModifiedOnDisk(path)
|
||||
}
|
||||
buffer
|
||||
.withLastModifiedTime(attrs.lastModifiedTime)
|
||||
.withModifiedOnDisk()
|
||||
} else {
|
||||
buffer
|
||||
case FileEvent(path, _, attributes) =>
|
||||
attributes match {
|
||||
case Right(attrs) =>
|
||||
val newBuffer = buffer.fileWithMetadata.lastModifiedTime.map {
|
||||
bufferLastModifiedTime =>
|
||||
if (attrs.lastModifiedTime.isAfter(bufferLastModifiedTime)) {
|
||||
clients.values.foreach {
|
||||
_.rpcController ! FileModifiedOnDisk(path)
|
||||
}
|
||||
buffer
|
||||
.withLastModifiedTime(attrs.lastModifiedTime)
|
||||
.withModifiedOnDisk()
|
||||
} else {
|
||||
buffer
|
||||
}
|
||||
}
|
||||
context.become(
|
||||
collaborativeEditing(
|
||||
newBuffer.getOrElse(buffer),
|
||||
clients,
|
||||
lockHolder,
|
||||
autoSave
|
||||
)
|
||||
)
|
||||
case Left(failure) =>
|
||||
logger.error(
|
||||
"Failed to read file attributes for [{}]. {}",
|
||||
path,
|
||||
failure
|
||||
)
|
||||
}
|
||||
unstashAll()
|
||||
context.become(
|
||||
collaborativeEditing(
|
||||
newBuffer.getOrElse(buffer),
|
||||
clients,
|
||||
lockHolder,
|
||||
autoSave
|
||||
)
|
||||
)
|
||||
|
||||
case FileManagerProtocol.InfoFileResult(Left(err)) =>
|
||||
timeoutCancellable.cancel()
|
||||
logger.error("Failed to read file attributes for [{}]. {}", path, err)
|
||||
unstashAll()
|
||||
context.become(
|
||||
collaborativeEditing(buffer, clients, lockHolder, autoSave)
|
||||
)
|
||||
|
||||
case Status.Failure(ex) =>
|
||||
logger.error("Failed to read file attributes for [{}].", path, ex)
|
||||
unstashAll()
|
||||
context.become(
|
||||
collaborativeEditing(buffer, clients, lockHolder, autoSave)
|
||||
)
|
||||
|
||||
case IOTimeout =>
|
||||
unstashAll()
|
||||
context.become(
|
||||
collaborativeEditing(buffer, clients, lockHolder, autoSave)
|
||||
)
|
||||
|
||||
case _ => stash()
|
||||
}
|
||||
|
||||
private def waitingOnReloadedContent(
|
||||
@ -444,7 +400,11 @@ class CollaborativeBuffer(
|
||||
|
||||
case FileManagerProtocol.ReadFileWithAttributesResult(Left(FileNotFound)) =>
|
||||
clients.values.foreach {
|
||||
_.rpcController ! TextProtocol.FileEvent(path, FileEventKind.Removed)
|
||||
_.rpcController ! TextProtocol.FileEvent(
|
||||
path,
|
||||
FileEventKind.Removed,
|
||||
None
|
||||
)
|
||||
}
|
||||
replyTo ! ReloadedBuffer(path)
|
||||
timeoutCancellable.cancel()
|
||||
|
@ -2,6 +2,7 @@ package org.enso.languageserver.text
|
||||
|
||||
import org.enso.languageserver.data.{CapabilityRegistration, ClientId}
|
||||
import org.enso.languageserver.filemanager.{
|
||||
FileAttributes,
|
||||
FileEventKind,
|
||||
FileSystemFailure,
|
||||
Path
|
||||
@ -151,8 +152,14 @@ object TextProtocol {
|
||||
* a file event after reloading the buffer to sync with file system
|
||||
*
|
||||
* @param path path to the file
|
||||
* @param kind file event kind
|
||||
* @param attributes file attributes
|
||||
*/
|
||||
case class FileEvent(path: Path, event: FileEventKind)
|
||||
case class FileEvent(
|
||||
path: Path,
|
||||
kind: FileEventKind,
|
||||
attributes: Option[FileAttributes]
|
||||
)
|
||||
|
||||
/** Requests the language server to save a file on behalf of a given user.
|
||||
*
|
||||
|
@ -84,7 +84,7 @@ class ReceivesTreeUpdatesHandlerTest
|
||||
// create file
|
||||
val path = Paths.get(testContentRoot.file.toString, "oneone.txt")
|
||||
Files.createFile(path)
|
||||
client1.expectJson(json"""
|
||||
client1.fuzzyExpectJson(json"""
|
||||
{ "jsonrpc": "2.0",
|
||||
"method": "file/event",
|
||||
"params": {
|
||||
@ -92,11 +92,12 @@ class ReceivesTreeUpdatesHandlerTest
|
||||
"rootId": $testContentRootId,
|
||||
"segments": [ "oneone.txt" ]
|
||||
},
|
||||
"kind": "Added"
|
||||
"kind": "Added",
|
||||
"attributes": "*"
|
||||
}
|
||||
}
|
||||
""")
|
||||
client2.expectJson(json"""
|
||||
client2.fuzzyExpectJson(json"""
|
||||
{ "jsonrpc": "2.0",
|
||||
"method": "file/event",
|
||||
"params": {
|
||||
@ -104,14 +105,15 @@ class ReceivesTreeUpdatesHandlerTest
|
||||
"rootId": $testContentRootId,
|
||||
"segments": [ "oneone.txt" ]
|
||||
},
|
||||
"kind": "Added"
|
||||
"kind": "Added",
|
||||
"attributes": "*"
|
||||
}
|
||||
}
|
||||
""")
|
||||
|
||||
// update file
|
||||
Files.write(path, "Hello".getBytes())
|
||||
client1.expectJson(json"""
|
||||
client1.fuzzyExpectJson(json"""
|
||||
{ "jsonrpc": "2.0",
|
||||
"method": "file/event",
|
||||
"params": {
|
||||
@ -119,11 +121,12 @@ class ReceivesTreeUpdatesHandlerTest
|
||||
"rootId": $testContentRootId,
|
||||
"segments": [ "oneone.txt" ]
|
||||
},
|
||||
"kind": "Modified"
|
||||
"kind": "Modified",
|
||||
"attributes": "*"
|
||||
}
|
||||
}
|
||||
""")
|
||||
client2.expectJson(json"""
|
||||
client2.fuzzyExpectJson(json"""
|
||||
{ "jsonrpc": "2.0",
|
||||
"method": "file/event",
|
||||
"params": {
|
||||
@ -131,7 +134,8 @@ class ReceivesTreeUpdatesHandlerTest
|
||||
"rootId": $testContentRootId,
|
||||
"segments": [ "oneone.txt" ]
|
||||
},
|
||||
"kind": "Modified"
|
||||
"kind": "Modified",
|
||||
"attributes": "*"
|
||||
}
|
||||
}
|
||||
""")
|
||||
@ -150,7 +154,8 @@ class ReceivesTreeUpdatesHandlerTest
|
||||
"rootId": $testContentRootId,
|
||||
"segments": [ "oneone.txt" ]
|
||||
},
|
||||
"kind": "Removed"
|
||||
"kind": "Removed",
|
||||
"attributes": null
|
||||
}
|
||||
}
|
||||
""")
|
||||
|
@ -1324,7 +1324,8 @@ class VcsManagerTest
|
||||
$testBarFileName
|
||||
]
|
||||
},
|
||||
"kind" : "Removed"
|
||||
"kind" : "Removed",
|
||||
"attributes" : null
|
||||
}
|
||||
}
|
||||
"""
|
||||
@ -1354,7 +1355,8 @@ class VcsManagerTest
|
||||
$testBarFileName
|
||||
]
|
||||
},
|
||||
"kind" : "Removed"
|
||||
"kind" : "Removed",
|
||||
"attributes" : null
|
||||
}
|
||||
}
|
||||
""")
|
||||
|
Loading…
Reference in New Issue
Block a user