Skip to content

Commit

Permalink
Allow project manager to write files (#9483)
Browse files Browse the repository at this point in the history
close #9360

Changelog:
- add: `--filesystem-write-path {path}` command allowing to write bytes from stdin to the provided path
  • Loading branch information
4e6 committed Mar 21, 2024
1 parent df3faf6 commit aff7fb8
Show file tree
Hide file tree
Showing 11 changed files with 177 additions and 6 deletions.
22 changes: 22 additions & 0 deletions docs/language-server/protocol-project-manager.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ transport formats, please look [here](./protocol-architecture.md).
- [Create Directory](#create-directory)
- [Delete Directory](#delete-directory)
- [Move File Or Directory](#move-file-or-directory)
- [Write to File](#write-to-file)
- [Project Management Operations](#project-management-operations)
- [`project/open`](#projectopen)
- [`project/close`](#projectclose)
Expand Down Expand Up @@ -335,6 +336,27 @@ null;

#### Errors

- [`ProjectDataStoreError`](#projectdatastoreerror) to signal problems with
underlying data store.

### Write to File

Writes bytes from stdin to the provided path.

#### Parameters

```typescript
echo 'Hello World!' | project-manager --filesystem-write-path {path}
```

### Result

```typescript
null;
```

#### Errors

- [`ProjectDataStoreError`](#projectdatastoreerror) to signal problems with
underlying data store.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ object Cli {
val FILESYSTEM_DELETE = "filesystem-delete"
val FILESYSTEM_MOVE_FROM = "filesystem-move-from"
val FILESYSTEM_MOVE_TO = "filesystem-move-to"
val FILESYSTEM_WRITE_PATH = "filesystem-write-path"

object option {

Expand Down Expand Up @@ -128,6 +129,14 @@ object Cli {
.longOpt(FILESYSTEM_MOVE_TO)
.desc("Move directory. Destination.")
.build()

val filesystemWritePath: cli.Option = cli.Option.builder
.hasArg(true)
.numberOfArgs(1)
.argName("path")
.longOpt(FILESYSTEM_WRITE_PATH)
.desc("Write data from stdin to the provided file")
.build()
}

val options: cli.Options =
Expand All @@ -146,6 +155,7 @@ object Cli {
.addOption(option.filesystemDelete)
.addOption(option.filesystemMoveFrom)
.addOption(option.filesystemMoveTo)
.addOption(option.filesystemWritePath)

/** Parse the command line options. */
def parse(args: Array[String]): Either[String, cli.CommandLine] = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import org.enso.projectmanager.boot.command.filesystem.{
FileSystemCreateDirectoryCommand,
FileSystemDeleteCommand,
FileSystemListCommand,
FileSystemMoveDirectoryCommand
FileSystemMoveDirectoryCommand,
FileSystemWritePathCommand
}
import org.enso.projectmanager.boot.command.{CommandHandler, ProjectListCommand}
import org.enso.projectmanager.boot.configuration.{
Expand Down Expand Up @@ -245,6 +246,14 @@ object ProjectManager extends ZIOAppDefault with LazyLogging {
to.toFile
)
commandHandler.printJson(fileSystemMoveDirectoryCommand.run)
} else if (options.hasOption(Cli.FILESYSTEM_WRITE_PATH)) {
val path = Paths.get(options.getOptionValue(Cli.FILESYSTEM_WRITE_PATH))
val fileSystemMoveDirectoryCommand =
FileSystemWritePathCommand[ZIO[ZAny, +*, +*]](
config,
path.toFile
)
commandHandler.printJson(fileSystemMoveDirectoryCommand.run)
} else if (options.hasOption(Cli.PROJECT_LIST)) {
val projectsPathOpt =
Option(options.getOptionValue(Cli.PROJECTS_DIRECTORY))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package org.enso.projectmanager.boot.command.filesystem

import org.enso.projectmanager.boot.configuration.ProjectManagerConfig
import org.enso.projectmanager.control.core.syntax._
import org.enso.projectmanager.control.core.{Applicative, CovariantFlatMap}
import org.enso.projectmanager.control.effect.{ErrorChannel, Sync}
import org.enso.projectmanager.infrastructure.file.BlockingFileSystem
import org.enso.projectmanager.infrastructure.random.SystemGenerator
import org.enso.projectmanager.infrastructure.repository.ProjectFileRepositoryFactory
import org.enso.projectmanager.infrastructure.time.RealClock
import org.enso.projectmanager.protocol.FileSystemManagementApi.FileSystemWritePath
import org.enso.projectmanager.service.filesystem.{
FileSystemService,
FileSystemServiceApi,
FileSystemServiceFailure
}

import java.io.{File, InputStream}

final class FileSystemWritePathCommand[F[+_, +_]: CovariantFlatMap](
service: FileSystemServiceApi[F],
path: File,
data: InputStream
) {

def run: F[FileSystemServiceFailure, FileSystemWritePath.Result] =
service.write(path, data).map(_ => FileSystemWritePath.Result)
}

object FileSystemWritePathCommand {

def apply[F[+_, +_]: Applicative: CovariantFlatMap: ErrorChannel: Sync](
config: ProjectManagerConfig,
path: File
): FileSystemWritePathCommand[F] = {
val clock = new RealClock[F]
val fileSystem = new BlockingFileSystem[F](config.timeout.ioTimeout)
val gen = new SystemGenerator[F]
val projectRepositoryFactory = new ProjectFileRepositoryFactory[F](
config.storage,
clock,
fileSystem,
gen
)

val service = new FileSystemService[F](fileSystem, projectRepositoryFactory)

new FileSystemWritePathCommand[F](service, path, System.in)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package org.enso.projectmanager.infrastructure.file
import java.io.{File, FileNotFoundException}
import java.io.{File, FileNotFoundException, InputStream}
import java.nio.file.{
AccessDeniedException,
NoSuchFileException,
Expand Down Expand Up @@ -33,6 +33,18 @@ class BlockingFileSystem[F[+_, +_]: Sync: ErrorChannel](
.mapError(toFsFailure)
.timeoutFail(OperationTimeout)(ioTimeout)

/** Writes binary content to a file.
*
* @param file path to the file
* @param contents a textual contents of the file
* @return either [[FileSystemFailure]] or Unit
*/
def writeFile(file: File, contents: InputStream): F[FileSystemFailure, Unit] =
Sync[F]
.blockingOp { FileUtils.copyInputStreamToFile(contents, file) }
.mapError(toFsFailure)
.timeoutFail(OperationTimeout)(ioTimeout)

/** Writes textual content to a file.
*
* @param file path to the file
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.enso.projectmanager.infrastructure.file

import java.io.File
import java.io.{File, InputStream}

/** Represents abstraction for filesystem operations.
*
Expand All @@ -15,6 +15,14 @@ trait FileSystem[F[+_, +_]] {
*/
def readFile(file: File): F[FileSystemFailure, String]

/** Writes binary content to a file.
*
* @param file path to the file
* @param contents a contents of the file
* @return either [[FileSystemFailure]] or Unit
*/
def writeFile(file: File, contents: InputStream): F[FileSystemFailure, Unit]

/** Writes textual content to a file.
*
* @param file path to the file
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,23 @@ object FileSystemManagementApi {
type Result = Unused.type
}
}

case object FileSystemWritePath extends Method("filesystem/writePath") {

case class Params(path: File)

type Result = Unused.type
val Result = Unused

implicit val hasParams
: HasParams.Aux[this.type, FileSystemWritePath.Params] =
new HasParams[this.type] {
type Params = FileSystemWritePath.Params
}

implicit val hasResult: HasResult.Aux[this.type, Unused.type] =
new HasResult[this.type] {
type Result = Unused.type
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ object JsonRpc {
.registerRequest(FileSystemCreateDirectory)
.registerRequest(FileSystemDeleteDirectory)
.registerRequest(FileSystemMoveDirectory)
.registerRequest(FileSystemWritePath)
.finalized()

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import org.enso.projectmanager.control.effect.syntax._
import org.enso.projectmanager.infrastructure.repository.ProjectRepositoryFactory
import org.enso.projectmanager.service.ProjectService

import java.io.File
import java.io.{File, InputStream}
import java.nio.file.Files
import java.nio.file.attribute.BasicFileAttributes

Expand Down Expand Up @@ -56,6 +56,17 @@ class FileSystemService[F[+_, +_]: Applicative: CovariantFlatMap: ErrorChannel](
.move(from, to)
.mapError(_ => FileSystemServiceFailure.FileSystem("Failed to move path"))

/** @inheritdoc */
override def write(
path: File,
contents: InputStream
): F[FileSystemServiceFailure, Unit] =
fileSystem
.writeFile(path, contents)
.mapError(_ =>
FileSystemServiceFailure.FileSystem("Failed to write path")
)

private def toFileSystemEntry(
path: File
): F[FileSystemServiceFailure, Option[FileSystemEntry]] = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.enso.projectmanager.service.filesystem

import java.io.File
import java.io.{File, InputStream}

trait FileSystemServiceApi[F[+_, +_]] {

Expand Down Expand Up @@ -29,4 +29,11 @@ trait FileSystemServiceApi[F[+_, +_]] {
* @param to the destination path
*/
def move(from: File, to: File): F[FileSystemServiceFailure, Unit]

/** Writes a file
*
* @param path the file path to write
* @param bytes the file contents
*/
def write(path: File, in: InputStream): F[FileSystemServiceFailure, Unit]
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import org.enso.semver.SemVer
import org.scalatest.EitherValues
import zio.{ZAny, ZIO}

import java.io.File
import java.io.{ByteArrayInputStream, File}
import java.nio.charset.StandardCharsets
import java.nio.file.Files
import java.nio.file.attribute.BasicFileAttributes

Expand Down Expand Up @@ -182,5 +183,26 @@ class FileSystemServiceSpec
FileUtils.deleteQuietly(targetPath)
}

"write path" in {
val testDir = testStorageConfig.userProjectsPath

val fileName = "filesystem_test_write_path.txt"
val filePath = new File(testDir, fileName)
val contents = "Hello World!"

fileSystemService
.write(
filePath,
new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8))
)
.unsafeRunSync()

val bytes = Files.readAllBytes(filePath.toPath)
new String(bytes, StandardCharsets.UTF_8) shouldEqual contents

// cleanup
FileUtils.deleteQuietly(filePath)
}

}
}

0 comments on commit aff7fb8

Please sign in to comment.