Skip to content

Commit 205ab5e

Browse files
authored
Merge pull request #35 from QuantStack/fileType
Update `getFileType` function
2 parents c4dee63 + ef702d0 commit 205ab5e

File tree

2 files changed

+112
-90
lines changed

2 files changed

+112
-90
lines changed

src/s3.ts

Lines changed: 86 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ export const listS3Contents = async (
8383
registeredFileTypes: IRegisteredFileTypes,
8484
path?: string
8585
): Promise<Contents.IModel> => {
86+
let isFile: boolean = false;
8687
const fileList: IContentsList = {};
8788
const prefix = path ? PathExt.join(root, path) : root;
8889

@@ -106,14 +107,16 @@ export const listS3Contents = async (
106107
c.Key !== path + '/' &&
107108
c.Key !== root + '/' + path + '/'
108109
) {
109-
const fileName = c
110-
.Key!.replace(
111-
(root ? root + '/' : '') + (path ? path + '/' : ''),
112-
''
113-
)
114-
.split('/')[0];
110+
let fileName = c.Key!.replace(
111+
(root ? root + '/' : '') + (path ? path + '/' : ''),
112+
''
113+
);
114+
const isDir: boolean =
115+
fileName === fileName.split('/')[0] ? false : true;
116+
fileName = fileName.split('/')[0];
115117
const [fileType, fileMimeType, fileFormat] = Private.getFileType(
116118
PathExt.extname(PathExt.basename(fileName)),
119+
isDir,
117120
registeredFileTypes
118121
);
119122

@@ -131,25 +134,37 @@ export const listS3Contents = async (
131134
};
132135
}
133136
});
137+
} else {
138+
isFile = true;
139+
data = await getS3FileContents(
140+
s3Client,
141+
bucketName,
142+
root,
143+
path!,
144+
registeredFileTypes
145+
);
134146
}
147+
135148
if (isTruncated) {
136149
isTruncated = IsTruncated;
137150
}
138151
command.input.ContinuationToken = NextContinuationToken;
139152
}
140153

141-
data = {
142-
name: path ? PathExt.basename(path) : bucketName,
143-
path: path ? path + '/' : bucketName,
144-
last_modified: '',
145-
created: '',
146-
content: Object.values(fileList),
147-
format: 'json',
148-
mimetype: '',
149-
size: undefined,
150-
writable: true,
151-
type: 'directory'
152-
};
154+
if (isFile === false) {
155+
data = {
156+
name: path ? PathExt.basename(path) : bucketName,
157+
path: path ? path + '/' : bucketName,
158+
last_modified: '',
159+
created: '',
160+
content: Object.values(fileList),
161+
format: 'json',
162+
mimetype: '',
163+
size: undefined,
164+
writable: true,
165+
type: 'directory'
166+
};
167+
}
153168

154169
return data;
155170
};
@@ -184,6 +199,7 @@ export const getS3FileContents = async (
184199
const date: string = response.LastModified!.toISOString();
185200
const [fileType, fileMimeType, fileFormat] = Private.getFileType(
186201
PathExt.extname(PathExt.basename(path)),
202+
false,
187203
registeredFileTypes
188204
);
189205

@@ -243,12 +259,14 @@ export const createS3Object = async (
243259
path: string,
244260
body: string | Blob,
245261
registeredFileTypes: IRegisteredFileTypes,
262+
isDir: boolean,
246263
options?: Partial<Contents.IModel>
247264
): Promise<Contents.IModel> => {
248265
path = PathExt.join(root, path);
249266

250267
const [fileType, fileMimeType, fileFormat] = Private.getFileType(
251268
PathExt.extname(PathExt.basename(name)),
269+
isDir,
252270
registeredFileTypes
253271
);
254272

@@ -386,6 +404,7 @@ export const checkS3Object = async (
386404
* @param oldLocalPath: The old path of the object.
387405
* @param newLocalPath: The new path of the object.
388406
* @param newFileName: The new object name.
407+
* @param isDir: Whether the object is a directory or a file.
389408
* @param registeredFileTypes: The list containing all registered file types.
390409
*
391410
* @returns A promise which resolves with the new object contents model.
@@ -397,13 +416,12 @@ export const renameS3Objects = async (
397416
oldLocalPath: string,
398417
newLocalPath: string,
399418
newFileName: string,
419+
isDir: boolean,
400420
registeredFileTypes: IRegisteredFileTypes
401421
): Promise<Contents.IModel> => {
402422
newLocalPath = PathExt.join(root, newLocalPath);
403423
oldLocalPath = PathExt.join(root, oldLocalPath);
404424

405-
const isDir: boolean = await isDirectory(s3Client, bucketName, oldLocalPath);
406-
407425
if (isDir) {
408426
newLocalPath = newLocalPath.substring(0, newLocalPath.length - 1);
409427
}
@@ -412,6 +430,7 @@ export const renameS3Objects = async (
412430

413431
const [fileType, fileMimeType, fileFormat] = Private.getFileType(
414432
PathExt.extname(PathExt.basename(newFileName)),
433+
isDir,
415434
registeredFileTypes
416435
);
417436

@@ -560,29 +579,45 @@ export const copyS3Objects = async (
560579

561580
const [fileType, fileMimeType, fileFormat] = Private.getFileType(
562581
PathExt.extname(PathExt.basename(name)),
582+
isDir,
563583
registeredFileTypes
564584
);
565585

566-
// retrieve information of new file
567-
const newFileContents = await s3Client.send(
568-
new GetObjectCommand({
569-
Bucket: newBucketName ?? bucketName,
570-
Key: name + (suffix ? suffix : '')
571-
})
572-
);
586+
try {
587+
const newFileContents = await s3Client.send(
588+
new GetObjectCommand({
589+
Bucket: newBucketName ?? bucketName,
590+
Key: name + (suffix ? suffix : '')
591+
})
592+
);
573593

574-
data = {
575-
name: PathExt.basename(name),
576-
path: name,
577-
last_modified: newFileContents.LastModified!.toISOString(),
578-
created: new Date().toISOString(),
579-
content: await newFileContents.Body!.transformToString(),
580-
format: fileFormat as Contents.FileFormat,
581-
mimetype: fileMimeType,
582-
size: newFileContents.ContentLength!,
583-
writable: true,
584-
type: fileType
585-
};
594+
data = {
595+
name: PathExt.basename(name),
596+
path: name,
597+
last_modified: newFileContents.LastModified!.toISOString(),
598+
created: new Date().toISOString(),
599+
content: await newFileContents.Body!.transformToString(),
600+
format: fileFormat as Contents.FileFormat,
601+
mimetype: fileMimeType,
602+
size: newFileContents.ContentLength!,
603+
writable: true,
604+
type: fileType
605+
};
606+
} catch {
607+
// object directory itself doesn't exist
608+
data = {
609+
name: PathExt.basename(name),
610+
path: name,
611+
last_modified: new Date().toISOString(),
612+
created: new Date().toISOString(),
613+
content: [],
614+
format: fileFormat as Contents.FileFormat,
615+
mimetype: fileMimeType,
616+
size: 0,
617+
writable: true,
618+
type: fileType
619+
};
620+
}
586621

587622
return data;
588623
};
@@ -655,7 +690,8 @@ export async function isDirectory(
655690
// listing contents given a path, to check if it is a directory
656691
const command = new ListObjectsV2Command({
657692
Bucket: bucketName,
658-
Prefix: objectPath + '/'
693+
Prefix:
694+
objectPath[objectPath.length - 1] === '/' ? objectPath : objectPath + '/'
659695
});
660696

661697
const { Contents } = await s3Client.send(command);
@@ -669,18 +705,22 @@ export async function isDirectory(
669705
namespace Private {
670706
/**
671707
* Helping function to define file type, mimetype and format based on file extension.
672-
* @param extension file extension (e.g.: txt, ipynb, csv)
673-
* @returns
708+
* @param extension: File extension (e.g.: txt, ipynb, csv)
709+
* @param isDir: Boolean showing if the object is a directory or a file
710+
* @param registeredFileTypes: The list containing all registered file types.
711+
* @returns The object type, mimetype and format.
674712
*/
675713
export function getFileType(
676714
extension: string,
715+
isDir: boolean,
677716
registeredFileTypes: IRegisteredFileTypes
678717
) {
679-
let fileType: string = 'text';
680-
let fileMimetype: string = 'text/plain';
681-
let fileFormat: string = 'text';
718+
let fileType: string = isDir === false ? 'text' : 'directory';
719+
let fileMimetype: string =
720+
isDir === false ? 'text/plain' : 'text/directory';
721+
let fileFormat: string = isDir === false ? 'text' : 'json';
682722

683-
if (registeredFileTypes[extension]) {
723+
if (isDir === false && registeredFileTypes[extension]) {
684724
fileType = registeredFileTypes[extension].fileType;
685725
fileMimetype = registeredFileTypes[extension].fileMimeTypes[0];
686726
fileFormat = registeredFileTypes[extension].fileFormat;

src/s3contents.ts

Lines changed: 26 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import {
1919
renameS3Objects,
2020
listS3Contents,
2121
IRegisteredFileTypes,
22-
getS3FileContents,
2322
isDirectory
2423
} from './s3';
2524

@@ -278,38 +277,14 @@ export class Drive implements Contents.IDrive {
278277
this._isRootFormatted = true;
279278
}
280279

281-
// getting the list of files from the root
282-
if (!path) {
283-
data = await listS3Contents(
284-
this._s3Client,
285-
this._name,
286-
this._root,
287-
this._registeredFileTypes
288-
);
289-
} else {
290-
const currentPath = PathExt.basename(path);
291-
292-
// listing contents of a folder
293-
if (PathExt.extname(currentPath) === '') {
294-
data = await listS3Contents(
295-
this._s3Client,
296-
this._name,
297-
this.root,
298-
this.registeredFileTypes,
299-
path
300-
);
301-
}
302-
// getting the contents of a specific file
303-
else {
304-
data = await getS3FileContents(
305-
this._s3Client,
306-
this._name,
307-
this._root,
308-
path,
309-
this.registeredFileTypes
310-
);
311-
}
312-
}
280+
// listing the contents of a directory or retriving the contents of a file
281+
data = await listS3Contents(
282+
this._s3Client,
283+
this._name,
284+
this.root,
285+
this.registeredFileTypes,
286+
path
287+
);
313288

314289
Contents.validateContentsModel(data);
315290
return data;
@@ -345,7 +320,8 @@ export class Drive implements Contents.IDrive {
345320
name,
346321
options.path ? PathExt.join(options.path, name) : name,
347322
'', // create new file with empty body,
348-
this.registeredFileTypes
323+
this.registeredFileTypes,
324+
options.type === 'directory' ? true : false
349325
);
350326
} else {
351327
console.warn('Type of new element is undefined');
@@ -447,10 +423,15 @@ export class Drive implements Contents.IDrive {
447423
options: Contents.ICreateOptions = {}
448424
): Promise<Contents.IModel> {
449425
let newFileName = PathExt.basename(newLocalPath);
426+
const isDir: boolean = await isDirectory(
427+
this._s3Client,
428+
this._name,
429+
oldLocalPath
430+
);
450431

451432
try {
452433
await checkS3Object(this._s3Client, this._name, this._root, newLocalPath);
453-
newFileName = await this.incrementName(newLocalPath, this._name);
434+
newFileName = await this.incrementName(newLocalPath, this._name, isDir);
454435
} catch (error) {
455436
// HEAD request failed for this file name, continue, as name doesn't already exist.
456437
} finally {
@@ -461,6 +442,7 @@ export class Drive implements Contents.IDrive {
461442
oldLocalPath,
462443
newLocalPath,
463444
newFileName,
445+
isDir,
464446
this._registeredFileTypes
465447
);
466448
}
@@ -481,19 +463,14 @@ export class Drive implements Contents.IDrive {
481463
*
482464
* @param bucketName - The name of the bucket where content is moved.
483465
*
484-
* @param root - The root of the bucket, if it exists.
466+
* @param isDir - Whether the object is a directory or a file.
485467
*/
486-
async incrementName(localPath: string, bucketName: string) {
487-
const isDir: boolean = await isDirectory(
488-
this._s3Client,
489-
bucketName,
490-
localPath
491-
);
468+
async incrementName(localPath: string, bucketName: string, isDir: boolean) {
492469
let fileExtension: string = '';
493470
let originalName: string = '';
494471

495472
// check if we are dealing with a directory
496-
if (isDir) {
473+
if (isDir === true) {
497474
localPath = localPath.substring(0, localPath.length - 1);
498475
originalName = PathExt.basename(localPath);
499476
}
@@ -549,6 +526,7 @@ export class Drive implements Contents.IDrive {
549526
localPath,
550527
options.content,
551528
this._registeredFileTypes,
529+
true,
552530
options
553531
);
554532

@@ -594,7 +572,11 @@ export class Drive implements Contents.IDrive {
594572
(isDir ? '/' : '');
595573

596574
// getting incremented name of Copy in case of duplicates
597-
const incrementedName = await this.incrementName(newFilePath, bucketName);
575+
const incrementedName = await this.incrementName(
576+
newFilePath,
577+
bucketName,
578+
isDir
579+
);
598580

599581
return incrementedName;
600582
}

0 commit comments

Comments
 (0)