Skip to content

Commit ee2dc57

Browse files
authored
Project manager API for basic file system operations (#9245)
close #9173 Changelog: - add: `--filesystem-list {path}` cli parameter that list files, directories and projects - add: `--filesystem-create-directory {path}` cli parameter that creates a specified directory - add: `--filesystem-delete-directory {path}` cli parameter that deletes a specified directory - add: `--filesystem-move-from {path}` ` --filesystem-move-to {path}` cli parameters to move specified filesystem object
1 parent f80dd9f commit ee2dc57

22 files changed

+1093
-15
lines changed

docs/language-server/protocol-project-manager.md

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ transport formats, please look [here](./protocol-architecture.md).
2424
- [`ProgressUnit`](#progressunit)
2525
- [`EngineVersion`](#engineversion)
2626
- [`RunningState`](#runningstate)
27+
- [`FileSystemEntry`](#filesystementry)
28+
- [`Attributes`](#attributes)
29+
- [`UTCDateTime`](#utcdatetime)
30+
- [File System Management Operations](#file-system-management-operations)
31+
- [List Directories](#list-directories)
32+
- [Create Directory](#create-directory)
33+
- [Delete Directory](#delete-directory)
34+
- [Move File Or Directory](#move-file-or-directory)
2735
- [Project Management Operations](#project-management-operations)
2836
- [`project/open`](#projectopen)
2937
- [`project/close`](#projectclose)
@@ -187,6 +195,149 @@ interface RunningStatus {
187195
}
188196
```
189197

198+
### `FileSystemEntry`
199+
200+
A directory entry in the fileystem operations.
201+
202+
#### Format
203+
204+
```typescript
205+
type FileSystemEntry = FileEntry | DirectoryEntry | ProjectEntry;
206+
207+
interface FileEntry {
208+
path: string;
209+
attributes: Attributes;
210+
}
211+
212+
interface DirectoryEntry {
213+
path: string;
214+
attributes: Attributes;
215+
}
216+
217+
interface ProjectEntry {
218+
path: string;
219+
attributes: Attributes;
220+
metadata: ProjectMetadata;
221+
}
222+
```
223+
224+
### `Attributes`
225+
226+
Basic attributes of a filesystem entry.
227+
228+
#### Format
229+
230+
```typescript
231+
interface Attributes {
232+
creationTime: UTCDateTime;
233+
lastAccessTime: UTCDateTime;
234+
lastModifiedTime: UTCDateTime;
235+
byteSize: number;
236+
}
237+
```
238+
239+
### `UTCDateTime`
240+
241+
Time in UTC time zone represented as ISO-8601 string.
242+
243+
#### Format
244+
245+
```typescript
246+
type UTCDateTime = string;
247+
```
248+
249+
## File System Management Operations
250+
251+
The project-manager binary provides Cli interface to do basic filesystem
252+
operations.
253+
254+
### List Directories
255+
256+
List directory returning information about filesystem entries together with the
257+
project metadata if the listed directory contains a project.
258+
259+
#### Parameters
260+
261+
```typescript
262+
project-manager --filesystem-list {path}
263+
```
264+
265+
#### Result
266+
267+
```typescript
268+
{
269+
entries: FileSystemEntry[];
270+
}
271+
```
272+
273+
#### Errors
274+
275+
- [`ProjectDataStoreError`](#projectdatastoreerror) to signal problems with
276+
underlying data store.
277+
278+
### Create Directory
279+
280+
Create directory with the specified path.
281+
282+
#### Parameters
283+
284+
```typescript
285+
project-manager --filesystem-create-directory {path}
286+
```
287+
288+
### Result
289+
290+
```typescript
291+
null;
292+
```
293+
294+
#### Errors
295+
296+
- [`ProjectDataStoreError`](#projectdatastoreerror) to signal problems with
297+
underlying data store.
298+
299+
### Delete Directory
300+
301+
Deletes directory with the specified path.
302+
303+
#### Parameters
304+
305+
```typescript
306+
project-manager --filesystem-delete-directory {path}
307+
```
308+
309+
### Result
310+
311+
```typescript
312+
null;
313+
```
314+
315+
#### Errors
316+
317+
- [`ProjectDataStoreError`](#projectdatastoreerror) to signal problems with
318+
underlying data store.
319+
320+
### Move File Or Directory
321+
322+
Moves file or directory from target path to the destination path.
323+
324+
#### Parameters
325+
326+
```typescript
327+
project-manager --filesystem-move-from {path} --filesystem-move-to {path}
328+
```
329+
330+
### Result
331+
332+
```typescript
333+
null;
334+
```
335+
336+
#### Errors
337+
338+
- [`ProjectDataStoreError`](#projectdatastoreerror) to signal problems with
339+
underlying data store.
340+
190341
## Project Management Operations
191342

192343
The primary responsibility of the project managers is to allow users to manage

lib/scala/project-manager/src/main/scala/org/enso/projectmanager/boot/Cli.scala

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ object Cli {
1717
val PROJECTS_DIRECTORY = "projects-directory"
1818
val PROJECT_LIST = "project-list"
1919

20+
val FILESYSTEM_LIST = "filesystem-list"
21+
val FILESYSTEM_CREATE_DIRECTORY = "filesystem-create-directory"
22+
val FILESYSTEM_DELETE_DIRECTORY = "filesystem-delete-directory"
23+
val FILESYSTEM_MOVE_FROM = "filesystem-move-from"
24+
val FILESYSTEM_MOVE_TO = "filesystem-move-to"
25+
2026
object option {
2127

2228
val help: cli.Option = cli.Option
@@ -82,6 +88,46 @@ object Cli {
8288
.longOpt(PROJECT_LIST)
8389
.desc("List user projects.")
8490
.build()
91+
92+
val filesystemList: cli.Option = cli.Option.builder
93+
.hasArg(true)
94+
.numberOfArgs(1)
95+
.argName("path")
96+
.longOpt(FILESYSTEM_LIST)
97+
.desc("List directory.")
98+
.build()
99+
100+
val filesystemCreateDirectory: cli.Option = cli.Option.builder
101+
.hasArg(true)
102+
.numberOfArgs(1)
103+
.argName("path")
104+
.longOpt(FILESYSTEM_CREATE_DIRECTORY)
105+
.desc("Create directory.")
106+
.build()
107+
108+
val filesystemDeleteDirectory: cli.Option = cli.Option.builder
109+
.hasArg(true)
110+
.numberOfArgs(1)
111+
.argName("path")
112+
.longOpt(FILESYSTEM_DELETE_DIRECTORY)
113+
.desc("Delete directory.")
114+
.build()
115+
116+
val filesystemMoveFrom: cli.Option = cli.Option.builder
117+
.hasArg(true)
118+
.numberOfArgs(1)
119+
.argName("path")
120+
.longOpt(FILESYSTEM_MOVE_FROM)
121+
.desc("Move directory. Target.")
122+
.build()
123+
124+
val filesystemMoveTo: cli.Option = cli.Option.builder
125+
.hasArg(true)
126+
.numberOfArgs(1)
127+
.argName("path")
128+
.longOpt(FILESYSTEM_MOVE_TO)
129+
.desc("Move directory. Destination.")
130+
.build()
85131
}
86132

87133
val options: cli.Options =
@@ -95,6 +141,11 @@ object Cli {
95141
.addOption(option.profilingTime)
96142
.addOption(option.projectsDirectory)
97143
.addOption(option.projectList)
144+
.addOption(option.filesystemList)
145+
.addOption(option.filesystemCreateDirectory)
146+
.addOption(option.filesystemDeleteDirectory)
147+
.addOption(option.filesystemMoveFrom)
148+
.addOption(option.filesystemMoveTo)
98149

99150
/** Parse the command line options. */
100151
def parse(args: Array[String]): Either[String, cli.CommandLine] = {

lib/scala/project-manager/src/main/scala/org/enso/projectmanager/boot/ProjectManager.scala

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ import org.enso.projectmanager.boot.Globals.{
99
FailureExitCode,
1010
SuccessExitCode
1111
}
12+
import org.enso.projectmanager.boot.command.filesystem.{
13+
FileSystemCreateDirectoryCommand,
14+
FileSystemDeleteDirectoryCommand,
15+
FileSystemListCommand,
16+
FileSystemMoveDirectoryCommand
17+
}
1218
import org.enso.projectmanager.boot.command.{CommandHandler, ProjectListCommand}
1319
import org.enso.projectmanager.boot.configuration.{
1420
MainProcessConfig,
@@ -209,6 +215,39 @@ object ProjectManager extends ZIOAppDefault with LazyLogging {
209215
ZIO.succeed(SuccessExitCode)
210216
} else if (options.hasOption(Cli.VERSION_OPTION)) {
211217
displayVersion(options.hasOption(Cli.JSON_OPTION))
218+
} else if (options.hasOption(Cli.FILESYSTEM_LIST)) {
219+
val directory = Paths.get(options.getOptionValue(Cli.FILESYSTEM_LIST))
220+
val fileSystemListCommand =
221+
FileSystemListCommand[ZIO[ZAny, +*, +*]](config, directory.toFile)
222+
commandHandler.printJson(fileSystemListCommand.run)
223+
} else if (options.hasOption(Cli.FILESYSTEM_CREATE_DIRECTORY)) {
224+
val directory =
225+
Paths.get(options.getOptionValue(Cli.FILESYSTEM_CREATE_DIRECTORY))
226+
val fileSystemCreateDirectoryCommand =
227+
FileSystemCreateDirectoryCommand[ZIO[ZAny, +*, +*]](
228+
config,
229+
directory.toFile
230+
)
231+
commandHandler.printJson(fileSystemCreateDirectoryCommand.run)
232+
} else if (options.hasOption(Cli.FILESYSTEM_DELETE_DIRECTORY)) {
233+
val directory =
234+
Paths.get(options.getOptionValue(Cli.FILESYSTEM_DELETE_DIRECTORY))
235+
val fileSystemDeleteDirectoryCommand =
236+
FileSystemDeleteDirectoryCommand[ZIO[ZAny, +*, +*]](
237+
config,
238+
directory.toFile
239+
)
240+
commandHandler.printJson(fileSystemDeleteDirectoryCommand.run)
241+
} else if (options.hasOption(Cli.FILESYSTEM_MOVE_FROM)) {
242+
val from = Paths.get(options.getOptionValue(Cli.FILESYSTEM_MOVE_FROM))
243+
val to = Paths.get(options.getOptionValue(Cli.FILESYSTEM_MOVE_TO))
244+
val fileSystemMoveDirectoryCommand =
245+
FileSystemMoveDirectoryCommand[ZIO[ZAny, +*, +*]](
246+
config,
247+
from.toFile,
248+
to.toFile
249+
)
250+
commandHandler.printJson(fileSystemMoveDirectoryCommand.run)
212251
} else if (options.hasOption(Cli.PROJECT_LIST)) {
213252
val projectsPathOpt =
214253
Option(options.getOptionValue(Cli.PROJECTS_DIRECTORY))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package org.enso.projectmanager.boot.command.filesystem
2+
3+
import org.enso.projectmanager.boot.configuration.ProjectManagerConfig
4+
import org.enso.projectmanager.control.core.{Applicative, CovariantFlatMap}
5+
import org.enso.projectmanager.control.core.syntax._
6+
import org.enso.projectmanager.control.effect.{ErrorChannel, Sync}
7+
import org.enso.projectmanager.infrastructure.file.BlockingFileSystem
8+
import org.enso.projectmanager.infrastructure.random.SystemGenerator
9+
import org.enso.projectmanager.infrastructure.repository.ProjectFileRepositoryFactory
10+
import org.enso.projectmanager.infrastructure.time.RealClock
11+
import org.enso.projectmanager.protocol.FileSystemManagementApi.FileSystemCreateDirectory
12+
import org.enso.projectmanager.service.filesystem.{
13+
FileSystemService,
14+
FileSystemServiceApi,
15+
FileSystemServiceFailure
16+
}
17+
18+
import java.io.File
19+
20+
final class FileSystemCreateDirectoryCommand[F[+_, +_]: CovariantFlatMap](
21+
service: FileSystemServiceApi[F],
22+
path: File
23+
) {
24+
25+
def run: F[FileSystemServiceFailure, FileSystemCreateDirectory.Result] =
26+
service.createDirectory(path).map(_ => FileSystemCreateDirectory.Result)
27+
}
28+
29+
object FileSystemCreateDirectoryCommand {
30+
31+
def apply[F[+_, +_]: Applicative: CovariantFlatMap: ErrorChannel: Sync](
32+
config: ProjectManagerConfig,
33+
path: File
34+
): FileSystemCreateDirectoryCommand[F] = {
35+
val clock = new RealClock[F]
36+
val fileSystem = new BlockingFileSystem[F](config.timeout.ioTimeout)
37+
val gen = new SystemGenerator[F]
38+
val projectRepositoryFactory = new ProjectFileRepositoryFactory[F](
39+
config.storage,
40+
clock,
41+
fileSystem,
42+
gen
43+
)
44+
45+
val service = new FileSystemService[F](fileSystem, projectRepositoryFactory)
46+
47+
new FileSystemCreateDirectoryCommand[F](service, path)
48+
}
49+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package org.enso.projectmanager.boot.command.filesystem
2+
3+
import org.enso.projectmanager.boot.configuration.ProjectManagerConfig
4+
import org.enso.projectmanager.control.core.syntax._
5+
import org.enso.projectmanager.control.core.{Applicative, CovariantFlatMap}
6+
import org.enso.projectmanager.control.effect.{ErrorChannel, Sync}
7+
import org.enso.projectmanager.infrastructure.file.BlockingFileSystem
8+
import org.enso.projectmanager.infrastructure.random.SystemGenerator
9+
import org.enso.projectmanager.infrastructure.repository.ProjectFileRepositoryFactory
10+
import org.enso.projectmanager.infrastructure.time.RealClock
11+
import org.enso.projectmanager.protocol.FileSystemManagementApi.FileSystemDeleteDirectory
12+
import org.enso.projectmanager.service.filesystem.{
13+
FileSystemService,
14+
FileSystemServiceApi,
15+
FileSystemServiceFailure
16+
}
17+
18+
import java.io.File
19+
20+
final class FileSystemDeleteDirectoryCommand[F[+_, +_]: CovariantFlatMap](
21+
service: FileSystemServiceApi[F],
22+
path: File
23+
) {
24+
25+
def run: F[FileSystemServiceFailure, FileSystemDeleteDirectory.Result] =
26+
service.deleteDirectory(path).map(_ => FileSystemDeleteDirectory.Result)
27+
}
28+
29+
object FileSystemDeleteDirectoryCommand {
30+
31+
def apply[F[+_, +_]: Applicative: CovariantFlatMap: ErrorChannel: Sync](
32+
config: ProjectManagerConfig,
33+
path: File
34+
): FileSystemDeleteDirectoryCommand[F] = {
35+
val clock = new RealClock[F]
36+
val fileSystem = new BlockingFileSystem[F](config.timeout.ioTimeout)
37+
val gen = new SystemGenerator[F]
38+
val projectRepositoryFactory = new ProjectFileRepositoryFactory[F](
39+
config.storage,
40+
clock,
41+
fileSystem,
42+
gen
43+
)
44+
45+
val service = new FileSystemService[F](fileSystem, projectRepositoryFactory)
46+
47+
new FileSystemDeleteDirectoryCommand[F](service, path)
48+
}
49+
}

0 commit comments

Comments
 (0)