@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 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
- const plans = files.map((localFile) => {
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
- return {
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
- const summary = createSummary('upload', false, results, startedAt, {
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
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@struggler/cli",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "CLI to Upload vite packaged files to Qiniu Cloud OSS.",
5
5
  "main": "index.js",
6
6
  "scripts": {