batch-exec-cli 1.2.2 → 1.3.0

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/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  ## 功能特性
6
6
 
7
- - 🚀 高效遍历目标目录的所有直接子目录
7
+ - 🚀 高效遍历目标目录的所有直接子目录, 默认并行执行
8
8
  - 📁 支持绝对路径和相对路径
9
9
  - 🚫 可配置忽略目录(支持 `.gitignore` 风格的模式匹配)
10
10
  - 📊 提供执行摘要和失败目录列表
@@ -64,6 +64,7 @@ batch-exec ./repos ls -la
64
64
  | `-s, --skip <文件>` | | 指定忽略文件路径(默认:`./.batchexecignore`) |
65
65
  | `-v, --verbose` | | 显示详细输出 |
66
66
  | `--no-progress` | | 禁用进度条显示 |
67
+ | `--no-parallel` | | 禁用并行执行, 按顺序执行 |
67
68
  | `-h, --help` | | 显示帮助信息 |
68
69
 
69
70
  ### 使用自定义忽略文件
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "batch-exec-cli",
3
- "version": "1.2.2",
4
- "description": "Efficiently iterate through directories and execute commands with progress display",
3
+ "version": "1.3.0",
4
+ "description": "Efficiently iterate through directories and execute commands with progress display and parallel execution",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
7
7
  "bin": {
package/src/cli.js CHANGED
@@ -10,7 +10,7 @@ $.verbose = false;
10
10
 
11
11
  async function main() {
12
12
  const argv = minimist(process.argv.slice(2), {
13
- boolean: ['v', 'verbose', 'h', 'help', 'no-progress'],
13
+ boolean: ['v', 'verbose', 'h', 'help', 'no-progress', 'no-parallel'],
14
14
  string: ['s', 'skip'],
15
15
  alias: {
16
16
  s: 'skip',
@@ -45,6 +45,7 @@ async function main() {
45
45
  console.log(bold('\n🚀 Batch Executor\n'));
46
46
  console.log(`Target directory: ${cyan(targetDir)}`);
47
47
  console.log(`Command: ${yellow(command)} ${args.join(' ')}`);
48
+ console.log(`Parallel mode: ${argv.parallel === false ? red('Disabled') : green('Enabled')}`);
48
49
  if (skipPaths.length > 0) {
49
50
  console.log(`Skipping directories: ${gray(skipPaths.join(', '))}`);
50
51
  }
@@ -55,7 +56,8 @@ async function main() {
55
56
  const results = await batchExecute(targetDir, command, args, {
56
57
  skipPaths,
57
58
  verbose: argv.verbose,
58
- showProgress: argv.progress !== false
59
+ showProgress: argv.progress !== false,
60
+ parallel: argv.parallel !== false
59
61
  });
60
62
 
61
63
  printSummary(results);
@@ -67,7 +69,7 @@ async function main() {
67
69
 
68
70
  function printHelp() {
69
71
  console.log(`
70
- ${bold('Batch Executor')} ${dim('v1.1.0')}
72
+ ${bold('Batch Executor')} ${dim('v1.3.0')}
71
73
 
72
74
  ${cyan('Usage:')} batch-exec [options] <directory> <command> [args...]
73
75
 
@@ -82,12 +84,14 @@ ${magenta('Options:')}
82
84
  -s, --skip <file> Ignore file path (default: ./.batchexecignore)
83
85
  -v, --verbose Show verbose output
84
86
  --no-progress Disable progress bar
87
+ --no-parallel Disable parallel execution (use sequential mode)
85
88
  -h, --help Show this help message
86
89
 
87
90
  ${green('Examples:')}
88
91
  ${green('batch-exec')} ./my-projects git pull
89
92
  ${green('batch-exec')} ./my-projects npm update lodash -S
90
93
  ${green('batch-exec')} --skip ./custom-ignore.txt ./repos ls -la
94
+ ${green('batch-exec')} --no-parallel ./my-projects npm install
91
95
  `);
92
96
  }
93
97
 
package/src/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import path from 'path';
2
- import { $, cd } from 'zx';
2
+ import { $, within, cd } from 'zx';
3
3
  import { parseIgnoreFile } from './ignoreParser.js';
4
4
  import { listDirectSubdirectories } from './directoryLister.js';
5
5
  import { cyan, red, ProgressBar, clearLine } from './utils/colors.js';
@@ -7,8 +7,55 @@ import { cyan, red, ProgressBar, clearLine } from './utils/colors.js';
7
7
  export { parseIgnoreFile };
8
8
  export { listDirectSubdirectories };
9
9
 
10
+ async function executeInDirectory(subdirPath, command, args, verbose) {
11
+ try {
12
+ if (verbose) {
13
+ console.log(`=== Executing in: ${cyan(subdirPath)} ===`);
14
+ }
15
+
16
+ let result;
17
+
18
+ await within(async () => {
19
+ cd(subdirPath);
20
+ if (verbose) {
21
+ result = await $`${command} ${args}`;
22
+ } else {
23
+ result = await $`${command} ${args}`.quiet();
24
+ }
25
+ if (verbose) {
26
+ console.log(`${cyan(subdirPath)}: `, result.stdout);
27
+ if (result.stderr) {
28
+ console.error(`${cyan(subdirPath)}: `, result.stderr);
29
+ }
30
+ }
31
+ });
32
+
33
+ return {
34
+ success: true,
35
+ stdout: result.stdout,
36
+ stderr: result.stderr
37
+ };
38
+ } catch (error) {
39
+ if (verbose) {
40
+ console.error(red(`Error in ${cyan(subdirPath)}: ${error.message}`));
41
+ if (error.stdout) {
42
+ console.log(`${cyan(subdirPath)}: `, error.stdout);
43
+ }
44
+ if (error.stderr) {
45
+ console.error(`${cyan(subdirPath)}: `, error.stderr);
46
+ }
47
+ }
48
+ return {
49
+ success: false,
50
+ error: error.message,
51
+ stdout: error.stdout || '',
52
+ stderr: error.stderr || ''
53
+ };
54
+ }
55
+ }
56
+
10
57
  export async function batchExecute(targetDir, command, args, options = {}) {
11
- const { skipPaths = [], verbose = false, showProgress = true } = options;
58
+ const { skipPaths = [], verbose = false, showProgress = true, parallel = true } = options;
12
59
 
13
60
  const absoluteTargetDir = path.resolve(targetDir);
14
61
 
@@ -22,60 +69,54 @@ export async function batchExecute(targetDir, command, args, options = {}) {
22
69
  progressBar.start();
23
70
  }
24
71
 
25
- for (let i = 0; i < subdirs.length; i++) {
26
- const subdir = subdirs[i];
27
- const subdirPath = path.join(absoluteTargetDir, subdir);
72
+ if (parallel) {
73
+ const promises = subdirs.map(async (subdir, index) => {
74
+ const subdirPath = path.join(absoluteTargetDir, subdir);
75
+ const result = await executeInDirectory(subdirPath, command, args, verbose);
28
76
 
29
- try {
30
- if (verbose) {
31
- console.log(`=== Executing in: ${cyan(subdirPath)} ===`);
77
+ if (progressBar) {
78
+ progressBar.increment();
32
79
  }
33
80
 
34
- let result;
81
+ return { directory: subdir, ...result };
82
+ });
35
83
 
36
- cd(subdirPath);
84
+ const resolvedResults = await Promise.all(promises);
37
85
 
38
- if (verbose) {
39
- result = await $`${command} ${args}`;
40
- } else {
41
- result = await $`${command} ${args}`.quiet();
42
- }
43
-
44
- results.push({
45
- directory: subdir,
46
- success: true,
47
- stdout: result.stdout,
48
- stderr: result.stderr
49
- });
50
-
51
- if (verbose) {
52
- console.log(result.stdout);
53
- if (result.stderr) {
54
- console.error(result.stderr);
55
- }
56
- }
57
- } catch (error) {
58
- results.push({
59
- directory: subdir,
60
- success: false,
61
- error: error.message,
62
- stdout: error.stdout || '',
63
- stderr: error.stderr || ''
64
- });
65
-
66
- if (verbose) {
67
- console.error(red(`Error in ${cyan(subdir)}: ${error.message}`));
68
- if (error.stdout) {
69
- console.log(error.stdout);
70
- }
71
- if (error.stderr) {
72
- console.error(error.stderr);
73
- }
86
+ for (const subdir of subdirs) {
87
+ const result = resolvedResults.find(r => r.directory === subdir);
88
+ if (result) {
89
+ results.push(result);
74
90
  }
75
91
  }
76
-
77
- if (progressBar) {
78
- progressBar.update(i + 1);
92
+ } else {
93
+ for (let i = 0; i < subdirs.length; i++) {
94
+ const subdir = subdirs[i];
95
+ const subdirPath = path.join(absoluteTargetDir, subdir);
96
+ const result = await executeInDirectory(subdirPath, command, args, verbose);
97
+
98
+ results.push({ directory: subdir, ...result });
99
+
100
+ // if (verbose) {
101
+ // if (result.success) {
102
+ // console.log(result.stdout);
103
+ // if (result.stderr) {
104
+ // console.error(result.stderr);
105
+ // }
106
+ // } else {
107
+ // console.error(red(`Error in ${cyan(subdir)}: ${result.error}`));
108
+ // if (result.stdout) {
109
+ // console.log(result.stdout);
110
+ // }
111
+ // if (result.stderr) {
112
+ // console.error(result.stderr);
113
+ // }
114
+ // }
115
+ // }
116
+
117
+ if (progressBar) {
118
+ progressBar.update(i + 1);
119
+ }
79
120
  }
80
121
  }
81
122