Skip to content
This repository was archived by the owner on May 6, 2025. It is now read-only.

Commit ddf542d

Browse files
committed
storage support
1 parent 5776a54 commit ddf542d

26 files changed

Lines changed: 912 additions & 116 deletions

lib/commands/env/index.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ commander_1.default
3333
item.Status === 'NORMAL' ? '正常' : '不可用'
3434
]);
3535
utils_1.printCliTable(head, tableData);
36-
const unavalibleEnv = data.find(item => item.Status === 'UNAVAILABLE');
37-
if (unavalibleEnv) {
38-
logger_1.warnLog(`您的环境中存在不可用的环境:[${unavalibleEnv.EnvId}],请留意!`);
36+
const unavailableEnv = data.find(item => item.Status === 'UNAVAILABLE');
37+
if (unavailableEnv) {
38+
logger_1.warnLog(`您的环境中存在不可用的环境:[${unavailableEnv.EnvId}],请留意!`);
3939
}
4040
});
4141
async function checkEnvAvailability(envId) {

lib/commands/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ require("./logout");
66
require("./env");
77
require("./functions");
88
require("./server");
9+
require("./storage");

lib/commands/storage.js

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
"use strict";
2+
var __importDefault = (this && this.__importDefault) || function (mod) {
3+
return (mod && mod.__esModule) ? mod : { "default": mod };
4+
};
5+
Object.defineProperty(exports, "__esModule", { value: true });
6+
const fs_1 = __importDefault(require("fs"));
7+
const path_1 = __importDefault(require("path"));
8+
const commander_1 = __importDefault(require("commander"));
9+
const manager_node_1 = __importDefault(require("@cloudbase/manager-node"));
10+
const utils_1 = require("../utils");
11+
const error_1 = require("../error");
12+
const logger_1 = require("../logger");
13+
const utils_2 = require("../utils");
14+
async function getStorageService(envId) {
15+
const { secretId, secretKey, token } = await utils_1.getCredential();
16+
const app = new manager_node_1.default({
17+
secretId,
18+
secretKey,
19+
token,
20+
envId
21+
});
22+
return app.storage;
23+
}
24+
commander_1.default
25+
.command('storage:upload <localPath> <cloudPath> [envId]')
26+
.description('上传文件/文件夹')
27+
.action(async function (localPath, cloudPath, envId, options) {
28+
const { configFile } = options.parent;
29+
const assignEnvId = await utils_1.getEnvId(envId, configFile);
30+
const storageService = await getStorageService(assignEnvId);
31+
const resolveLocalPath = path_1.default.resolve(localPath);
32+
if (!fs_1.default.existsSync(resolveLocalPath)) {
33+
throw new error_1.CloudBaseError('文件未找到!');
34+
}
35+
const isDir = fs_1.default.statSync(resolveLocalPath).isDirectory();
36+
let cancelLoading = utils_1.loading('上传文件中');
37+
if (isDir) {
38+
await storageService.uploadDirectory(resolveLocalPath, cloudPath);
39+
}
40+
else {
41+
await storageService.uploadFile(resolveLocalPath, cloudPath);
42+
}
43+
cancelLoading();
44+
logger_1.successLog('上传文件成功!');
45+
});
46+
commander_1.default
47+
.command('storage:download <cloudPath> <localPath> [envId]')
48+
.option('-d, --dir', '下载目标是否为文件夹')
49+
.description('下载文件/文件夹,文件夹需指定 --dir 选项')
50+
.action(async function (cloudPath, localPath, envId, options) {
51+
const { configFile } = options.parent;
52+
const assignEnvId = await utils_1.getEnvId(envId, configFile);
53+
const storageService = await getStorageService(assignEnvId);
54+
const resolveLocalPath = path_1.default.resolve(localPath);
55+
const { dir } = options;
56+
if (dir && !fs_1.default.existsSync(resolveLocalPath)) {
57+
throw new error_1.CloudBaseError('存储文件夹不存在!');
58+
}
59+
let cancelLoading = utils_1.loading('下载文件中');
60+
if (dir) {
61+
await storageService.downloadDirectory(cloudPath, resolveLocalPath);
62+
}
63+
else {
64+
await storageService.downloadFile(cloudPath, resolveLocalPath);
65+
}
66+
cancelLoading();
67+
logger_1.successLog('下载文件成功!');
68+
});
69+
commander_1.default
70+
.command('storage:delete <cloudPath> [envId]')
71+
.option('-d, --dir', '下载目标是否为文件夹')
72+
.description('删除文件/文件夹,文件夹需指定 --dir 选项')
73+
.action(async function (cloudPath, envId, options) {
74+
const { configFile } = options.parent;
75+
const assignEnvId = await utils_1.getEnvId(envId, configFile);
76+
const storageService = await getStorageService(assignEnvId);
77+
const { dir } = options;
78+
if (dir) {
79+
await storageService.deleteDirectory(cloudPath);
80+
}
81+
else {
82+
await storageService.deleteFile([cloudPath]);
83+
}
84+
logger_1.successLog('删除文件成功!');
85+
});
86+
commander_1.default
87+
.command('storage:list <cloudPath> [envId]')
88+
.option('--max', '传输数据的最大条数')
89+
.option('--markder', '起始路径名,后(不含)按照 UTF-8 字典序返回条目')
90+
.description('获取文件夹中的文件列表')
91+
.action(async function (cloudPath, envId, options) {
92+
const { configFile } = options.parent;
93+
const assignEnvId = await utils_1.getEnvId(envId, configFile);
94+
const storageService = await getStorageService(assignEnvId);
95+
const list = await storageService.listDirectoryFiles(cloudPath);
96+
const head = ['序号', 'Key', 'LastModified', 'ETag', 'Size(B)'];
97+
const notDir = item => !(Number(item.Size) === 0 && /\/$/g.test(item.Key));
98+
const tableData = list
99+
.filter(notDir)
100+
.map((item, index) => [
101+
index + 1,
102+
item.Key,
103+
utils_2.formatDate(item.LastModified, 'yyyy-MM-dd hh:mm:ss'),
104+
item.ETag,
105+
String(item.Size)
106+
]);
107+
utils_2.printCliTable(head, tableData);
108+
});
109+
commander_1.default
110+
.command('storage:url <cloudPath> [envId]')
111+
.description('获取文件临时访问地址')
112+
.action(async function (cloudPath, envId, options) {
113+
const { configFile } = options.parent;
114+
const assignEnvId = await utils_1.getEnvId(envId, configFile);
115+
const storageService = await getStorageService(assignEnvId);
116+
const fileList = await storageService.getTemporaryUrl([cloudPath]);
117+
const { url } = fileList[0];
118+
logger_1.successLog(`文件临时访问地址:${url}`);
119+
});
120+
commander_1.default
121+
.command('storage:detail <cloudPath> [envId]')
122+
.description('获取文件信息')
123+
.action(async function (cloudPath, envId, options) {
124+
const { configFile } = options.parent;
125+
const assignEnvId = await utils_1.getEnvId(envId, configFile);
126+
const storageService = await getStorageService(assignEnvId);
127+
const fileInfo = await storageService.getFileInfo(cloudPath);
128+
const date = utils_2.formatDate(fileInfo.Date, 'yyyy-MM-dd hh:mm:ss');
129+
const logInfo = `文件大小:${fileInfo.Size}\n文件类型:${fileInfo.Type}\n修改日期:${date}\nETag:${fileInfo.ETag}
130+
`;
131+
console.log(logInfo);
132+
});
133+
commander_1.default
134+
.command('storage:get-acl [envId]')
135+
.description('获取文件存储权限信息')
136+
.action(async function (envId, options) {
137+
const { configFile } = options.parent;
138+
const assignEnvId = await utils_1.getEnvId(envId, configFile);
139+
const storageService = await getStorageService(assignEnvId);
140+
const acl = await storageService.getStorageAcl();
141+
console.log(acl);
142+
});
143+
commander_1.default
144+
.command('storage:set-acl <acl> [envId]')
145+
.description('设置文件存储权限信息')
146+
.action(async function (acl, envId, options) {
147+
const validAcl = ['READONLY', 'PRIVATE', 'ADMINWRITE', 'ADMINONLY'];
148+
if (!validAcl.includes(acl)) {
149+
throw new error_1.CloudBaseError('非法的权限值,仅支持:READONLY, PRIVATE, ADMINWRITE, ADMINONLY');
150+
}
151+
const { configFile } = options.parent;
152+
const assignEnvId = await utils_1.getEnvId(envId, configFile);
153+
const storageService = await getStorageService(assignEnvId);
154+
await storageService.setStorageAcl(acl);
155+
});

lib/utils/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ exports.guid6 = uuid_1.guid6;
2828
__export(require("./qcloud-request"));
2929
__export(require("./http-request"));
3030
__export(require("./output"));
31+
__export(require("./time"));
3132
async function zipDir(dirPath, outputPath) {
3233
return new Promise((resolve, reject) => {
3334
const output = fs_1.default.createWriteStream(outputPath);

lib/utils/time.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
"use strict";
2+
Object.defineProperty(exports, "__esModule", { value: true });
3+
function formatDate(date, fmt) {
4+
if (date instanceof Date === false) {
5+
date = new Date(date);
6+
}
7+
if (/(y+)/.test(fmt)) {
8+
fmt = fmt.replace(RegExp.$1, String(date.getFullYear()).substr(4 - RegExp.$1.length));
9+
}
10+
let expMap = {
11+
'M+': date.getMonth() + 1,
12+
'd+': date.getDate(),
13+
'h+': date.getHours(),
14+
'm+': date.getMinutes(),
15+
's+': date.getSeconds(),
16+
S: date.getMilliseconds()
17+
};
18+
for (let exp in expMap) {
19+
if (new RegExp('(' + exp + ')').test(fmt)) {
20+
fmt = fmt.replace(RegExp.$1, RegExp.$1.length == 1
21+
? expMap[exp]
22+
: ('00' + expMap[exp]).substr(String(expMap[exp]).length));
23+
}
24+
}
25+
return fmt;
26+
}
27+
exports.formatDate = formatDate;

0 commit comments

Comments
 (0)