@struggler/cli 1.0.5 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/command/upload.js +46 -7
- package/index.js +1 -1
- package/lib/cache.js +37 -0
- package/lib/config.js +13 -0
- package/lib/i18n.js +2 -0
- package/package.json +1 -1
package/command/upload.js
CHANGED
|
@@ -2,7 +2,7 @@ var qiniu = require("qiniu");
|
|
|
2
2
|
|
|
3
3
|
var qiniuPrefix = require("../lib/prefix")
|
|
4
4
|
|
|
5
|
-
let { getQiniuConfig, getDir } = require('../lib/config')
|
|
5
|
+
let { getQiniuConfig, getDir, getCachePath } = require('../lib/config')
|
|
6
6
|
let { getJsonData } = require('../lib/files')
|
|
7
7
|
const { createIgnoreMatcher } = require('../lib/ignore');
|
|
8
8
|
const {
|
|
@@ -16,6 +16,7 @@ const {
|
|
|
16
16
|
toRemoteKey,
|
|
17
17
|
} = require('../lib/deploy');
|
|
18
18
|
const { printMessage } = require('../lib/output');
|
|
19
|
+
const { computeFileMd5, readCache, writeCache, isCacheHit, updateCacheEntry } = require('../lib/cache');
|
|
19
20
|
|
|
20
21
|
async function main(options, runtime = {}) {
|
|
21
22
|
const qiniuConfig = getJsonData(getQiniuConfig(options))
|
|
@@ -25,20 +26,39 @@ async function main(options, runtime = {}) {
|
|
|
25
26
|
const ignoreMatcher = createIgnoreMatcher(dir, options);
|
|
26
27
|
const excludedPatterns = runtime.excludePatterns || ignoreMatcher.patterns;
|
|
27
28
|
const files = runtime.files || await collectDeployFiles(dir, options);
|
|
28
|
-
|
|
29
|
+
|
|
30
|
+
const useCache = !options.noCache;
|
|
31
|
+
const cachePath = getCachePath(options);
|
|
32
|
+
const cache = useCache ? readCache(cachePath) : {};
|
|
33
|
+
|
|
34
|
+
const plans = [];
|
|
35
|
+
const skippedPlans = [];
|
|
36
|
+
|
|
37
|
+
for (const localFile of files) {
|
|
29
38
|
const key = toRemoteKey(prefix, dir, localFile);
|
|
30
|
-
|
|
39
|
+
const plan = {
|
|
31
40
|
localFile,
|
|
32
41
|
key,
|
|
33
42
|
target: `${qiniuConfig.domain || ''}${key}`,
|
|
34
43
|
};
|
|
35
|
-
|
|
44
|
+
|
|
45
|
+
if (useCache && !options.dryRun) {
|
|
46
|
+
const md5 = computeFileMd5(localFile);
|
|
47
|
+
plan.localMd5 = md5;
|
|
48
|
+
if (isCacheHit(cache, key, md5)) {
|
|
49
|
+
skippedPlans.push(plan);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
plans.push(plan);
|
|
55
|
+
}
|
|
36
56
|
|
|
37
57
|
if (options.dryRun) {
|
|
38
58
|
if (!runtime.suppressOutput) {
|
|
39
|
-
logPlan('upload', plans, options);
|
|
59
|
+
logPlan('upload', [...plans, ...skippedPlans], options);
|
|
40
60
|
}
|
|
41
|
-
const summary = createSummary('upload', true, plans.map((plan) => ({
|
|
61
|
+
const summary = createSummary('upload', true, [...plans, ...skippedPlans].map((plan) => ({
|
|
42
62
|
ok: true,
|
|
43
63
|
localFile: plan.localFile,
|
|
44
64
|
key: plan.key,
|
|
@@ -47,6 +67,7 @@ async function main(options, runtime = {}) {
|
|
|
47
67
|
prefix,
|
|
48
68
|
concurrency: normalizeConcurrency(options.concurrency),
|
|
49
69
|
excludedPatterns,
|
|
70
|
+
skippedCount: 0,
|
|
50
71
|
});
|
|
51
72
|
return runtime.suppressOutput ? summary : finalizeOutput(summary, options, runtime.manifestExtra);
|
|
52
73
|
}
|
|
@@ -108,6 +129,9 @@ async function main(options, runtime = {}) {
|
|
|
108
129
|
if (!runtime.suppressOutput) {
|
|
109
130
|
printMessage(options, `[uploaded] ${plan.localFile} -> ${plan.target}`);
|
|
110
131
|
}
|
|
132
|
+
if (useCache && plan.localMd5) {
|
|
133
|
+
updateCacheEntry(cache, plan.key, plan.localMd5, response.hash);
|
|
134
|
+
}
|
|
111
135
|
return {
|
|
112
136
|
ok: true,
|
|
113
137
|
localFile: plan.localFile,
|
|
@@ -126,10 +150,25 @@ async function main(options, runtime = {}) {
|
|
|
126
150
|
}
|
|
127
151
|
});
|
|
128
152
|
|
|
129
|
-
|
|
153
|
+
if (useCache) {
|
|
154
|
+
writeCache(cachePath, cache);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const skippedResults = skippedPlans.map((plan) => ({
|
|
158
|
+
ok: true,
|
|
159
|
+
skipped: true,
|
|
160
|
+
localFile: plan.localFile,
|
|
161
|
+
key: plan.key,
|
|
162
|
+
target: plan.target,
|
|
163
|
+
}));
|
|
164
|
+
|
|
165
|
+
const allResults = [...results, ...skippedResults];
|
|
166
|
+
|
|
167
|
+
const summary = createSummary('upload', false, allResults, startedAt, {
|
|
130
168
|
prefix,
|
|
131
169
|
concurrency: normalizeConcurrency(options.concurrency),
|
|
132
170
|
excludedPatterns,
|
|
171
|
+
skippedCount: skippedPlans.length,
|
|
133
172
|
});
|
|
134
173
|
const finalSummary = runtime.suppressOutput ? summary : finalizeOutput(summary, options, runtime.manifestExtra);
|
|
135
174
|
if (finalSummary.failedCount > 0) {
|
package/index.js
CHANGED
|
@@ -60,7 +60,7 @@ program.configureHelp({
|
|
|
60
60
|
},
|
|
61
61
|
})
|
|
62
62
|
|
|
63
|
-
program.name("struggler-cli").description(locale.appDescription).version(packageJson.version, "-v, --version", locale.options.version).helpOption("-h, --help", locale.options.help).option("-c, --config <path>", locale.options.config, "./command/qiniu.json").option("-d, --dir <path>", locale.options.dir, "./dist").option("--dry-run", locale.options.dryRun).option("--concurrency <number>", locale.options.concurrency, "5").option("--exclude <pattern>", locale.options.exclude).option("--ignore-file <path>", locale.options.ignoreFile, ".strugglerignore").option("--manifest <path>", locale.options.manifest).option("--json", locale.options.json).option("--skip-init", locale.options.skipInit).option("--skip-refresh", locale.options.skipRefresh).option("--lang <lang>", locale.options.lang, lang)
|
|
63
|
+
program.name("struggler-cli").description(locale.appDescription).version(packageJson.version, "-v, --version", locale.options.version).helpOption("-h, --help", locale.options.help).option("-c, --config <path>", locale.options.config, "./command/qiniu.json").option("-d, --dir <path>", locale.options.dir, "./dist").option("--dry-run", locale.options.dryRun).option("--concurrency <number>", locale.options.concurrency, "5").option("--exclude <pattern>", locale.options.exclude).option("--ignore-file <path>", locale.options.ignoreFile, ".strugglerignore").option("--manifest <path>", locale.options.manifest).option("--json", locale.options.json).option("--skip-init", locale.options.skipInit).option("--skip-refresh", locale.options.skipRefresh).option("--no-cache", locale.options.noCache).option("--lang <lang>", locale.options.lang, lang)
|
|
64
64
|
|
|
65
65
|
program
|
|
66
66
|
.command("init")
|
package/lib/cache.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const crypto = require('crypto');
|
|
3
|
+
const { getJsonData, setSyncJsonData } = require('./files');
|
|
4
|
+
|
|
5
|
+
function computeFileMd5(filePath) {
|
|
6
|
+
const content = fs.readFileSync(filePath);
|
|
7
|
+
return crypto.createHash('md5').update(content).digest('hex');
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function readCache(cachePath) {
|
|
11
|
+
return getJsonData(cachePath);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function writeCache(cachePath, cache) {
|
|
15
|
+
setSyncJsonData(cachePath, cache);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function isCacheHit(cache, relativeKey, localMd5) {
|
|
19
|
+
const entry = cache[relativeKey];
|
|
20
|
+
return entry && entry.localMd5 === localMd5;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function updateCacheEntry(cache, relativeKey, localMd5, qiniuHash) {
|
|
24
|
+
cache[relativeKey] = {
|
|
25
|
+
localMd5,
|
|
26
|
+
qiniuHash,
|
|
27
|
+
uploadedAt: new Date().toISOString(),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
module.exports = {
|
|
32
|
+
computeFileMd5,
|
|
33
|
+
readCache,
|
|
34
|
+
writeCache,
|
|
35
|
+
isCacheHit,
|
|
36
|
+
updateCacheEntry,
|
|
37
|
+
};
|
package/lib/config.js
CHANGED
|
@@ -2,6 +2,7 @@ let path = require('path')
|
|
|
2
2
|
|
|
3
3
|
const DEFAULT_QINIU_CONFIG = './command/qiniu.json';
|
|
4
4
|
const DEFAULT_CONFIG = './command/config.json';
|
|
5
|
+
const DEFAULT_CACHE = './command/upload-cache.json';
|
|
5
6
|
|
|
6
7
|
function resolveFromCwd(targetPath) {
|
|
7
8
|
return path.resolve(process.cwd(), targetPath);
|
|
@@ -20,6 +21,15 @@ function getConfigPath(options = {}) {
|
|
|
20
21
|
return path.join(path.dirname(qiniuConfigPath), 'config.json');
|
|
21
22
|
}
|
|
22
23
|
|
|
24
|
+
function getCachePath(options = {}) {
|
|
25
|
+
if (!options.config) {
|
|
26
|
+
return resolveFromCwd(DEFAULT_CACHE);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const qiniuConfigPath = getQiniuConfigPath(options);
|
|
30
|
+
return path.join(path.dirname(qiniuConfigPath), 'upload-cache.json');
|
|
31
|
+
}
|
|
32
|
+
|
|
23
33
|
module.exports = {
|
|
24
34
|
getConfig: (options) => {
|
|
25
35
|
return getConfigPath(options)
|
|
@@ -27,6 +37,9 @@ module.exports = {
|
|
|
27
37
|
getQiniuConfig: (options) => {
|
|
28
38
|
return getQiniuConfigPath(options)
|
|
29
39
|
},
|
|
40
|
+
getCachePath: (options) => {
|
|
41
|
+
return getCachePath(options)
|
|
42
|
+
},
|
|
30
43
|
getDir: (options) => {
|
|
31
44
|
return resolveFromCwd(options.dir || './dist')
|
|
32
45
|
},
|
package/lib/i18n.js
CHANGED
|
@@ -13,6 +13,7 @@ const LANGUAGES = {
|
|
|
13
13
|
json: '输出机器可读的 JSON 结果。',
|
|
14
14
|
skipInit: '在 deploy 时跳过 init 步骤。',
|
|
15
15
|
skipRefresh: '在 deploy 时跳过 refresh 步骤。',
|
|
16
|
+
noCache: '禁用上传缓存,强制重新上传所有文件。',
|
|
16
17
|
lang: '切换菜单语言,可选 zh / en。',
|
|
17
18
|
help: '显示帮助信息。',
|
|
18
19
|
},
|
|
@@ -51,6 +52,7 @@ const LANGUAGES = {
|
|
|
51
52
|
json: 'Print machine-readable JSON output.',
|
|
52
53
|
skipInit: 'Skip init during deploy.',
|
|
53
54
|
skipRefresh: 'Skip refresh during deploy.',
|
|
55
|
+
noCache: 'Disable upload cache and force re-upload all files.',
|
|
54
56
|
lang: 'Switch menu language, supported values: zh / en.',
|
|
55
57
|
help: 'Display help information.',
|
|
56
58
|
},
|