1
1
import { Contents , ServerConnection } from '@jupyterlab/services' ;
2
2
3
+ import { PathExt } from '@jupyterlab/coreutils' ;
4
+
3
5
import { ISignal , Signal } from '@lumino/signaling' ;
4
6
7
+ async function toArray < T > (
8
+ asyncIterator : AsyncIterableIterator < T >
9
+ ) : Promise < T [ ] > {
10
+ const arr = [ ] ;
11
+
12
+ for await ( const i of asyncIterator ) {
13
+ arr . push ( i ) ;
14
+ }
15
+
16
+ return arr ;
17
+ }
18
+
5
19
export class FileSystemDrive implements Contents . IDrive {
6
20
get isDisposed ( ) : boolean {
7
21
return this . _isDisposed ;
@@ -36,7 +50,7 @@ export class FileSystemDrive implements Contents.IDrive {
36
50
}
37
51
38
52
async get (
39
- localPath : string ,
53
+ path : string ,
40
54
options ?: Contents . IFetchOptions
41
55
) : Promise < Contents . IModel > {
42
56
const root = this . _rootHandle ;
@@ -55,12 +69,33 @@ export class FileSystemDrive implements Contents.IDrive {
55
69
} ;
56
70
}
57
71
72
+ let parentHandle = root ;
73
+ // If requesting a file/directory that is not under root, we need the right directory handle
74
+ for ( const subPath of path . split ( '/' ) . slice ( 0 , - 1 ) ) {
75
+ parentHandle = await parentHandle . getDirectoryHandle ( subPath ) ;
76
+ }
77
+
78
+ const parentPath = PathExt . dirname ( path ) ;
79
+ const localPath = PathExt . basename ( path ) ;
80
+
81
+ let localHandle : FileSystemDirectoryHandle | FileSystemFileHandle ;
82
+
83
+ const currentContent = await toArray ( parentHandle . values ( ) ) ;
84
+
58
85
if ( localPath ) {
59
- const handle = await root . getFileHandle ( localPath ) ;
60
- const file = await handle . getFile ( ) ;
86
+ localHandle = currentContent . filter (
87
+ element => element . name === localPath
88
+ ) [ 0 ] ;
89
+ } else {
90
+ localHandle = parentHandle ;
91
+ }
92
+
93
+ if ( localHandle . kind === 'file' ) {
94
+ const file = await localHandle . getFile ( ) ;
95
+
61
96
return {
62
97
name : file . name ,
63
- path : file . name ,
98
+ path : PathExt . join ( parentPath , localPath ) ,
64
99
created : new Date ( file . lastModified ) . toISOString ( ) ,
65
100
last_modified : new Date ( file . lastModified ) . toISOString ( ) ,
66
101
format : 'text' ,
@@ -69,72 +104,71 @@ export class FileSystemDrive implements Contents.IDrive {
69
104
type : 'file' ,
70
105
mimetype : 'text/plain'
71
106
} ;
72
- }
73
-
74
- const content : Contents . IModel [ ] = [ ] ;
75
-
76
- for await ( const value of root . values ( ) ) {
77
- if ( value . kind === ' file' ) {
78
- const file = await value . getFile ( ) ;
79
- content . push ( {
80
- name : file . name ,
81
- path : file . name ,
82
- created : new Date ( file . lastModified ) . toISOString ( ) ,
83
- last_modified : new Date ( file . lastModified ) . toISOString ( ) ,
84
- format : ' text' ,
85
- content : await file . text ( ) ,
86
- writable : true ,
87
- type : 'file' ,
88
- mimetype : 'text/plain'
89
- } ) ;
90
- } else {
91
- content . push ( {
92
- name : value . name ,
93
- path : value . name ,
94
- created : new Date ( ) . toISOString ( ) ,
95
- last_modified : new Date ( ) . toISOString ( ) ,
96
- format : 'json' ,
97
- content : null ,
98
- writable : true ,
99
- type : 'directory' ,
100
- mimetype : 'application/json'
101
- } ) ;
107
+ } else {
108
+ const content : Contents . IModel [ ] = [ ] ;
109
+
110
+ for await ( const value of localHandle . values ( ) ) {
111
+ if ( value . kind === 'file' ) {
112
+ const file = await value . getFile ( ) ;
113
+ content . push ( {
114
+ name : file . name ,
115
+ path : PathExt . join ( parentPath , localPath , file . name ) ,
116
+ created : new Date ( file . lastModified ) . toISOString ( ) ,
117
+ last_modified : new Date ( file . lastModified ) . toISOString ( ) ,
118
+ format : 'text' ,
119
+ content : await file . text ( ) ,
120
+ writable : true ,
121
+ type : 'file' ,
122
+ mimetype : 'text/plain'
123
+ } ) ;
124
+ } else {
125
+ content . push ( {
126
+ name : value . name ,
127
+ path : PathExt . join ( parentPath , localPath , value . name ) ,
128
+ created : '' ,
129
+ last_modified : '' ,
130
+ format : 'json' ,
131
+ content : null ,
132
+ writable : true ,
133
+ type : 'directory' ,
134
+ mimetype : 'application/json'
135
+ } ) ;
136
+ }
102
137
}
103
- }
104
138
105
- const date = new Date ( ) ;
106
- return {
107
- name : 'root' ,
108
- path : '' ,
109
- last_modified : date . toISOString ( ) ,
110
- created : date . toISOString ( ) ,
111
- format : 'json' ,
112
- mimetype : 'application/json' ,
113
- content ,
114
- size : undefined ,
115
- writable : true ,
116
- type : 'directory'
117
- } ;
139
+ return {
140
+ name : PathExt . basename ( parentPath ) ,
141
+ path : PathExt . join ( parentPath , localPath ) ,
142
+ last_modified : '' ,
143
+ created : '' ,
144
+ format : 'json' ,
145
+ mimetype : 'application/ json' ,
146
+ content ,
147
+ size : undefined ,
148
+ writable : true ,
149
+ type : 'directory'
150
+ } ;
151
+ }
118
152
}
119
153
120
- getDownloadUrl ( localPath : string ) : Promise < string > {
154
+ getDownloadUrl ( path : string ) : Promise < string > {
121
155
throw new Error ( 'Method not implemented.' ) ;
122
156
}
123
157
124
158
newUntitled ( options ?: Contents . ICreateOptions ) : Promise < Contents . IModel > {
125
159
throw new Error ( 'Method not implemented.' ) ;
126
160
}
127
161
128
- delete ( localPath : string ) : Promise < void > {
162
+ delete ( path : string ) : Promise < void > {
129
163
throw new Error ( 'Method not implemented.' ) ;
130
164
}
131
165
132
- rename ( oldLocalPath : string , newLocalPath : string ) : Promise < Contents . IModel > {
166
+ rename ( oldPath : string , newPath : string ) : Promise < Contents . IModel > {
133
167
throw new Error ( 'Method not implemented.' ) ;
134
168
}
135
169
136
170
async save (
137
- localPath : string ,
171
+ path : string ,
138
172
options ?: Partial < Contents . IModel >
139
173
) : Promise < Contents . IModel > {
140
174
const root = this . _rootHandle ;
@@ -143,7 +177,13 @@ export class FileSystemDrive implements Contents.IDrive {
143
177
throw new Error ( 'No root file handle' ) ;
144
178
}
145
179
146
- const handle = await root . getFileHandle ( localPath ) ;
180
+ let parentHandle = root ;
181
+ // If saving a file that is not under root, we need the right directory handle
182
+ for ( const subPath of path . split ( '/' ) . slice ( 0 , - 1 ) ) {
183
+ parentHandle = await parentHandle . getDirectoryHandle ( subPath ) ;
184
+ }
185
+
186
+ const handle = await parentHandle . getFileHandle ( PathExt . basename ( path ) ) ;
147
187
const writable = await handle . createWritable ( { } ) ;
148
188
149
189
const format = options ?. format ;
@@ -155,25 +195,21 @@ export class FileSystemDrive implements Contents.IDrive {
155
195
await writable . write ( content ) ;
156
196
}
157
197
await writable . close ( ) ;
158
- return this . get ( localPath ) ;
198
+ return this . get ( path ) ;
159
199
}
160
200
161
- copy ( localPath : string , toLocalDir : string ) : Promise < Contents . IModel > {
201
+ copy ( path : string , toLocalDir : string ) : Promise < Contents . IModel > {
162
202
throw new Error ( 'Method not implemented.' ) ;
163
203
}
164
204
165
- async createCheckpoint (
166
- localPath : string
167
- ) : Promise < Contents . ICheckpointModel > {
205
+ async createCheckpoint ( path : string ) : Promise < Contents . ICheckpointModel > {
168
206
return {
169
207
id : 'test' ,
170
208
last_modified : new Date ( ) . toISOString ( )
171
209
} ;
172
210
}
173
211
174
- async listCheckpoints (
175
- localPath : string
176
- ) : Promise < Contents . ICheckpointModel [ ] > {
212
+ async listCheckpoints ( path : string ) : Promise < Contents . ICheckpointModel [ ] > {
177
213
return [
178
214
{
179
215
id : 'test' ,
@@ -182,11 +218,11 @@ export class FileSystemDrive implements Contents.IDrive {
182
218
] ;
183
219
}
184
220
185
- restoreCheckpoint ( localPath : string , checkpointID : string ) : Promise < void > {
221
+ restoreCheckpoint ( path : string , checkpointID : string ) : Promise < void > {
186
222
return Promise . resolve ( void 0 ) ;
187
223
}
188
224
189
- deleteCheckpoint ( localPath : string , checkpointID : string ) : Promise < void > {
225
+ deleteCheckpoint ( path : string , checkpointID : string ) : Promise < void > {
190
226
return Promise . resolve ( void 0 ) ;
191
227
}
192
228
0 commit comments