Skip to content

Commit eb6e791

Browse files
committed
Finish upload folder +tests(WIP)
1 parent 9be8327 commit eb6e791

9 files changed

Lines changed: 763 additions & 59 deletions

File tree

src/commands/upload-folder.ts

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { CLIUtils } from '../utils/cli.utils';
33
import { AuthService } from '../services/auth.service';
44
import { UploadService } from '../services/network/upload/upload.service';
55
import { ValidationService } from '../services/validation.service';
6+
import { ConfigService } from '../services/config.service';
67

78
export default class UploadFolder extends Command {
89
static readonly args = {};
@@ -32,8 +33,45 @@ export default class UploadFolder extends Command {
3233
if (!doesDirectoryExist) {
3334
throw new Error(`The provided folder path is not a valid directory: ${flags['folder']}`);
3435
}
35-
throw new Error('Not implemented yet');
36-
//return await UploadService.instance.uploadFolder();
36+
37+
// If destinationFolderUuid is empty from flags&prompt, means we should use RootFolderUuid
38+
const destinationFolderUuid =
39+
(await CLIUtils.getDestinationFolderUuid({
40+
destinationFolderUuidFlag: flags['destination'],
41+
destinationFlagName: UploadFolder.flags['destination'].name,
42+
nonInteractive: flags['non-interactive'],
43+
reporter: this.log.bind(this),
44+
})) ?? user.rootFolderId;
45+
46+
const progressBar = CLIUtils.progress(
47+
{
48+
format: 'Uploading folder [{bar}] {percentage}%',
49+
linewrap: true,
50+
},
51+
flags['json'],
52+
);
53+
progressBar?.start(100, 0);
54+
const { data, error } = await UploadService.instance.uploadFolderHandler({
55+
localPath: flags['folder'],
56+
destinationFolderUuid,
57+
loginUserDetails: user,
58+
jsonFlag: flags['json'],
59+
onProgress: (progress) => {
60+
progressBar?.update(progress.percentage);
61+
},
62+
});
63+
64+
progressBar?.update(100);
65+
progressBar?.stop();
66+
67+
if (error) {
68+
throw error;
69+
}
70+
71+
const driveUrl = ConfigService.instance.get('DRIVE_WEB_URL');
72+
const folderUrl = `${driveUrl}/folder/${data.rootFolderId}`;
73+
const message = `Folder uploaded in ${data.uploadTimeMs}ms, view it at ${folderUrl} (${data.totalBytes} bytes)`;
74+
CLIUtils.success(this.log.bind(this), message);
3775
};
3876

3977
public catch = async (error: Error) => {
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { promises } from 'fs';
2+
import { basename, dirname, join, relative, parse } from 'path';
3+
import { FileSystemNode, ScanResult } from './local-filesystem.types';
4+
import { logger } from '../../utils/logger.utils';
5+
6+
export class LocalFilesystemService {
7+
static readonly instance = new LocalFilesystemService();
8+
9+
async scanLocalDirectory(path: string): Promise<ScanResult> {
10+
const folders: FileSystemNode[] = [];
11+
const files: FileSystemNode[] = [];
12+
13+
const parentPath = dirname(path);
14+
const totalBytes = await this.scanRecursive(path, parentPath, folders, files);
15+
return {
16+
folders,
17+
files,
18+
totalItems: folders.length + files.length,
19+
totalBytes,
20+
};
21+
}
22+
async scanRecursive(
23+
currentPath: string,
24+
parentPath: string,
25+
folders: FileSystemNode[],
26+
files: FileSystemNode[],
27+
): Promise<number> {
28+
try {
29+
const stats = await promises.stat(currentPath);
30+
const relativePath = relative(parentPath, currentPath);
31+
32+
if (stats.isFile()) {
33+
const fileInfo = parse(currentPath);
34+
files.push({
35+
type: 'file',
36+
name: fileInfo.name,
37+
absolutePath: currentPath,
38+
relativePath,
39+
size: stats.size,
40+
});
41+
return stats.size;
42+
}
43+
44+
if (stats.isDirectory()) {
45+
folders.push({
46+
type: 'folder',
47+
name: basename(currentPath),
48+
absolutePath: currentPath,
49+
relativePath,
50+
size: 0,
51+
});
52+
const entries = await promises.readdir(currentPath, { withFileTypes: true });
53+
const validEntries = entries.filter((e) => !e.isSymbolicLink());
54+
const bytesArray = await Promise.all(
55+
validEntries.map((e) => this.scanRecursive(join(currentPath, e.name), parentPath, folders, files)),
56+
);
57+
58+
return bytesArray.reduce((sum, bytes) => sum + bytes, 0);
59+
}
60+
61+
return 0;
62+
} catch (error: unknown) {
63+
logger.warn(`Error scanning path ${currentPath}: ${(error as Error).message} - skipping...`);
64+
return 0;
65+
}
66+
}
67+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
export interface FileSystemNode {
2+
type: 'file' | 'folder';
3+
name: string;
4+
size: number;
5+
absolutePath: string;
6+
relativePath: string;
7+
}
8+
9+
export interface ScanResult {
10+
folders: FileSystemNode[];
11+
files: FileSystemNode[];
12+
totalItems: number;
13+
totalBytes: number;
14+
}

0 commit comments

Comments
 (0)