multiCMD 1.16__tar.gz → 1.17__tar.gz
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.
- {multicmd-1.16 → multicmd-1.17}/PKG-INFO +190 -189
- {multicmd-1.16 → multicmd-1.17}/README.md +0 -0
- {multicmd-1.16 → multicmd-1.17}/multiCMD.egg-info/PKG-INFO +190 -189
- {multicmd-1.16 → multicmd-1.17}/multiCMD.egg-info/SOURCES.txt +0 -1
- {multicmd-1.16 → multicmd-1.17}/multiCMD.py +7 -2
- {multicmd-1.16 → multicmd-1.17}/setup.cfg +4 -4
- {multicmd-1.16 → multicmd-1.17}/setup.py +1 -0
- multicmd-1.16/LICENSE +0 -674
- {multicmd-1.16 → multicmd-1.17}/multiCMD.egg-info/dependency_links.txt +0 -0
- {multicmd-1.16 → multicmd-1.17}/multiCMD.egg-info/entry_points.txt +0 -0
- {multicmd-1.16 → multicmd-1.17}/multiCMD.egg-info/requires.txt +0 -0
- {multicmd-1.16 → multicmd-1.17}/multiCMD.egg-info/top_level.txt +0 -0
@@ -1,189 +1,190 @@
|
|
1
|
-
Metadata-Version: 2.2
|
2
|
-
Name: multiCMD
|
3
|
-
Version: 1.
|
4
|
-
Summary: Run commands simultaneously
|
5
|
-
Home-page: https://github.com/yufei-pan/multiCMD
|
6
|
-
Author: Yufei Pan
|
7
|
-
Author-email: pan@zopyr.us
|
8
|
-
|
9
|
-
Classifier:
|
10
|
-
Classifier:
|
11
|
-
Classifier: Operating System ::
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
Requires-Dist: argparse
|
16
|
-
Dynamic: author
|
17
|
-
Dynamic: author-email
|
18
|
-
Dynamic: classifier
|
19
|
-
Dynamic: description
|
20
|
-
Dynamic: description-content-type
|
21
|
-
Dynamic: home-page
|
22
|
-
Dynamic:
|
23
|
-
Dynamic: requires-
|
24
|
-
Dynamic:
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
-
|
79
|
-
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
self.
|
187
|
-
self.
|
188
|
-
self.
|
189
|
-
|
1
|
+
Metadata-Version: 2.2
|
2
|
+
Name: multiCMD
|
3
|
+
Version: 1.17
|
4
|
+
Summary: Run commands simultaneously
|
5
|
+
Home-page: https://github.com/yufei-pan/multiCMD
|
6
|
+
Author: Yufei Pan
|
7
|
+
Author-email: pan@zopyr.us
|
8
|
+
License: GPLv3+
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
10
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
11
|
+
Classifier: Operating System :: POSIX :: Linux
|
12
|
+
Classifier: Operating System :: Microsoft :: Windows
|
13
|
+
Requires-Python: >=3.6
|
14
|
+
Description-Content-Type: text/markdown
|
15
|
+
Requires-Dist: argparse
|
16
|
+
Dynamic: author
|
17
|
+
Dynamic: author-email
|
18
|
+
Dynamic: classifier
|
19
|
+
Dynamic: description
|
20
|
+
Dynamic: description-content-type
|
21
|
+
Dynamic: home-page
|
22
|
+
Dynamic: license
|
23
|
+
Dynamic: requires-dist
|
24
|
+
Dynamic: requires-python
|
25
|
+
Dynamic: summary
|
26
|
+
|
27
|
+
# multiCMD
|
28
|
+
A simple script that is able to issue multiple commands and execute them at the same time locally.
|
29
|
+
|
30
|
+
multiCMD can display realtime-ish outputs in color if running multiple commands at the same time.
|
31
|
+
|
32
|
+
Can be used in bash scripts for automation actions.
|
33
|
+
|
34
|
+
Also able to be imported and act as a wrapper for subprocess.
|
35
|
+
|
36
|
+
Use return_object=True with run_commands or run_command to get the Task Object (definition below)
|
37
|
+
|
38
|
+
Use quiet=True and wait_for_return=False to create a daemon thread that async updates the return list / objects when return comes
|
39
|
+
|
40
|
+
For each process, it will initialize a thread if using -m/--max_threads > 1
|
41
|
+
|
42
|
+
For each thread, it will use subprocess lib to open a process for the command task
|
43
|
+
|
44
|
+
And it will open two sub threads for processing input and output for the task.
|
45
|
+
|
46
|
+
They input / output threads will be non-blocking.
|
47
|
+
|
48
|
+
Thus using -t/--timeout will work more reliably.
|
49
|
+
|
50
|
+
Note: timeout specifies how many seconds multiCMD will kill the command if NO COMMITTED OUTPUT was detected from the program for this long.
|
51
|
+
|
52
|
+
An output line is considered committed if steram hanlder encounters a '\n' or '\r' character.
|
53
|
+
|
54
|
+
|
55
|
+
Install via
|
56
|
+
```bash
|
57
|
+
pip install multiCMD
|
58
|
+
```
|
59
|
+
|
60
|
+
multiCMD will be available as
|
61
|
+
```bash
|
62
|
+
mcmd
|
63
|
+
multiCMD
|
64
|
+
multicmd
|
65
|
+
```
|
66
|
+
|
67
|
+
|
68
|
+
```bash
|
69
|
+
$ mcmd -h
|
70
|
+
usage: mcmd [-h] [-t timeout] [-m max_threads] [-q] [-V] command [command ...]
|
71
|
+
|
72
|
+
Run multiple commands in parallel
|
73
|
+
|
74
|
+
positional arguments:
|
75
|
+
command commands to run
|
76
|
+
|
77
|
+
options:
|
78
|
+
-h, --help show this help message and exit
|
79
|
+
-p, --parse Parse ranged input and expand them into multiple commands
|
80
|
+
-t timeout, --timeout timeout
|
81
|
+
timeout for each command
|
82
|
+
-m max_threads, --max_threads max_threads
|
83
|
+
maximum number of threads to use
|
84
|
+
-q, --quiet quiet mode
|
85
|
+
-V, --version show program's version number and exit
|
86
|
+
```
|
87
|
+
|
88
|
+
```python
|
89
|
+
def run_commands(commands, timeout=0,max_threads=1,quiet=False,dry_run=False,with_stdErr=False,
|
90
|
+
return_code_only=False,return_object=False, parse = False, wait_for_return = True):
|
91
|
+
'''
|
92
|
+
Run multiple commands in parallel
|
93
|
+
|
94
|
+
@params:
|
95
|
+
commands: A list of commands to run ( list[str] | list[list[str]] )
|
96
|
+
timeout: The timeout for each command
|
97
|
+
max_threads: The maximum number of threads to use
|
98
|
+
quiet: Whether to suppress output
|
99
|
+
dry_run: Whether to simulate running the commands
|
100
|
+
with_stdErr: Whether to append the standard error output to the standard output
|
101
|
+
return_code_only: Whether to return only the return code
|
102
|
+
return_object: Whether to return the Task object
|
103
|
+
parse: Whether to parse ranged input
|
104
|
+
wait_for_return: Whether to wait for the return of the commands
|
105
|
+
|
106
|
+
@returns:
|
107
|
+
list: The output of the commands ( list[None] | list[int] | list[list[str]] | list[Task] )
|
108
|
+
'''
|
109
|
+
def run_command(command, timeout=0,max_threads=1,quiet=False,dry_run=False,with_stdErr=False,
|
110
|
+
return_code_only=False,return_object=False,wait_for_return=True):
|
111
|
+
'''
|
112
|
+
Run a command
|
113
|
+
|
114
|
+
@params:
|
115
|
+
command: The command to run
|
116
|
+
timeout: The timeout for the command
|
117
|
+
max_threads: The maximum number of threads to use
|
118
|
+
quiet: Whether to suppress output
|
119
|
+
dry_run: Whether to simulate running the command
|
120
|
+
with_stdErr: Whether to append the standard error output to the standard output
|
121
|
+
return_code_only: Whether to return only the return code
|
122
|
+
return_object: Whether to return the Task object
|
123
|
+
wait_for_return: Whether to wait for the return of the command
|
124
|
+
|
125
|
+
@returns:
|
126
|
+
None | int | list[str] | Task: The output of the command
|
127
|
+
'''
|
128
|
+
def join_threads(threads=__running_threads,timeout=None):
|
129
|
+
'''
|
130
|
+
Join threads
|
131
|
+
|
132
|
+
@params:
|
133
|
+
threads: The threads to join
|
134
|
+
timeout: The timeout
|
135
|
+
|
136
|
+
@returns:
|
137
|
+
None
|
138
|
+
'''
|
139
|
+
def input_with_timeout_and_countdown(timeout, prompt='Please enter your selection'):
|
140
|
+
"""
|
141
|
+
Read an input from the user with a timeout and a countdown.
|
142
|
+
|
143
|
+
@params:
|
144
|
+
timeout: The timeout in seconds
|
145
|
+
prompt: The prompt to display to the user
|
146
|
+
|
147
|
+
@returns:
|
148
|
+
str: The input from the user or None if no input was received
|
149
|
+
|
150
|
+
"""
|
151
|
+
def print_progress_bar(iteration, total, prefix='', suffix=''):
|
152
|
+
'''
|
153
|
+
Call in a loop to create terminal progress bar
|
154
|
+
@params:
|
155
|
+
iteration - Required : current iteration (Int)
|
156
|
+
total - Required : total iterations (Int)
|
157
|
+
prefix - Optional : prefix string (Str)
|
158
|
+
suffix - Optional : suffix string (Str)
|
159
|
+
|
160
|
+
@returns:
|
161
|
+
None
|
162
|
+
'''
|
163
|
+
def get_terminal_size():
|
164
|
+
'''
|
165
|
+
Get the terminal size
|
166
|
+
|
167
|
+
@params:
|
168
|
+
None
|
169
|
+
|
170
|
+
@returns:
|
171
|
+
(int,int): the number of columns and rows of the terminal
|
172
|
+
'''
|
173
|
+
def int_to_color(n, brightness_threshold=500):
|
174
|
+
'''
|
175
|
+
Convert an integer to a color
|
176
|
+
|
177
|
+
@params:
|
178
|
+
n: The integer
|
179
|
+
brightness_threshold: The brightness threshold
|
180
|
+
|
181
|
+
@returns:
|
182
|
+
(int,int,int): The RGB color
|
183
|
+
'''
|
184
|
+
class Task:
|
185
|
+
def __init__(self, command):
|
186
|
+
self.command = command
|
187
|
+
self.returncode = None
|
188
|
+
self.stdout = []
|
189
|
+
self.stderr = []
|
190
|
+
```
|
File without changes
|