multitool 0.7.2__tar.gz → 0.8.0__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.
- {multitool-0.7.2 → multitool-0.8.0}/PKG-INFO +63 -13
- {multitool-0.7.2 → multitool-0.8.0}/README.rst +61 -12
- {multitool-0.7.2 → multitool-0.8.0}/multitool/__init__.py +1 -1
- {multitool-0.7.2 → multitool-0.8.0}/multitool/plugins/commands.py +195 -20
- {multitool-0.7.2 → multitool-0.8.0}/multitool.egg-info/PKG-INFO +63 -13
- {multitool-0.7.2 → multitool-0.8.0}/multitool.egg-info/requires.txt +1 -0
- {multitool-0.7.2 → multitool-0.8.0}/pyproject.toml +3 -2
- {multitool-0.7.2 → multitool-0.8.0}/LICENSE +0 -0
- {multitool-0.7.2 → multitool-0.8.0}/multitool/__main__.py +0 -0
- {multitool-0.7.2 → multitool-0.8.0}/multitool/cls.py +0 -0
- {multitool-0.7.2 → multitool-0.8.0}/multitool/console.py +0 -0
- {multitool-0.7.2 → multitool-0.8.0}/multitool/exceptions.py +0 -0
- {multitool-0.7.2 → multitool-0.8.0}/multitool/plugins/__init__.py +0 -0
- {multitool-0.7.2 → multitool-0.8.0}/multitool/silent.py +0 -0
- {multitool-0.7.2 → multitool-0.8.0}/multitool/utils.py +0 -0
- {multitool-0.7.2 → multitool-0.8.0}/multitool/utils_init.py +0 -0
- {multitool-0.7.2 → multitool-0.8.0}/multitool/verbose.py +0 -0
- {multitool-0.7.2 → multitool-0.8.0}/multitool.egg-info/SOURCES.txt +0 -0
- {multitool-0.7.2 → multitool-0.8.0}/multitool.egg-info/dependency_links.txt +0 -0
- {multitool-0.7.2 → multitool-0.8.0}/multitool.egg-info/entry_points.txt +0 -0
- {multitool-0.7.2 → multitool-0.8.0}/multitool.egg-info/top_level.txt +0 -0
- {multitool-0.7.2 → multitool-0.8.0}/setup.cfg +0 -0
- {multitool-0.7.2 → multitool-0.8.0}/tests/__init__.py +0 -0
- {multitool-0.7.2 → multitool-0.8.0}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: multitool
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: Create and run plugin-based command-line tools.
|
|
5
5
|
Author-email: Matthew Delotavo <matthew.t.delotavo@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -19,6 +19,7 @@ Requires-Dist: click>=8.1.3
|
|
|
19
19
|
Requires-Dist: click-aliases>=1.0.1
|
|
20
20
|
Requires-Dist: click-option-group>=0.5.5
|
|
21
21
|
Requires-Dist: GitPython>=3.1.30
|
|
22
|
+
Requires-Dist: packaging>=26.2
|
|
22
23
|
Dynamic: license-file
|
|
23
24
|
|
|
24
25
|
multitool
|
|
@@ -51,8 +52,7 @@ Run the example command::
|
|
|
51
52
|
-vv \
|
|
52
53
|
--enabled \
|
|
53
54
|
--tag alpha \
|
|
54
|
-
--tag beta
|
|
55
|
-
--output result.json
|
|
55
|
+
--tag beta
|
|
56
56
|
|
|
57
57
|
Edit the generated source code::
|
|
58
58
|
|
|
@@ -147,10 +147,18 @@ Configuring
|
|
|
147
147
|
|
|
148
148
|
Configure plugin repositories with::
|
|
149
149
|
|
|
150
|
-
multitool plugins configure
|
|
150
|
+
multitool plugins configure
|
|
151
|
+
|
|
152
|
+
This opens your editor to modify the plugin configuration. After saving your
|
|
153
|
+
changes, apply them with::
|
|
154
|
+
|
|
155
|
+
multitool plugins update
|
|
156
|
+
|
|
157
|
+
To automatically apply the configuration changes after saving and closing the
|
|
158
|
+
file (install new plugins, update existing plugins, and prune removed plugins),
|
|
159
|
+
use::
|
|
151
160
|
|
|
152
|
-
|
|
153
|
-
don't want changes applied automatically.
|
|
161
|
+
multitool plugins configure -a
|
|
154
162
|
|
|
155
163
|
Example configuration::
|
|
156
164
|
|
|
@@ -172,11 +180,11 @@ Install the example plugins::
|
|
|
172
180
|
echo -e '[sources]\nmdelotavo-multitool-plugins = https://github.com/mdelotavo/multitool-plugins.git' >> ~/.multitool/plugins/config
|
|
173
181
|
|
|
174
182
|
multitool plugins update
|
|
183
|
+
|
|
175
184
|
multitool plugins show
|
|
176
185
|
multitool plugins show -n mdelotavo-multitool-plugins
|
|
177
186
|
multitool plugins show -n mdelotavo-multitool-plugins --show-commit-only
|
|
178
187
|
multitool plugins show -n mdelotavo-multitool-plugins --show-dependencies-only
|
|
179
|
-
pip3 install $(multitool plugins show -n mdelotavo-multitool-plugins --show-dependencies-only)
|
|
180
188
|
|
|
181
189
|
multitool run examples -h
|
|
182
190
|
|
|
@@ -184,10 +192,57 @@ Install the example plugins::
|
|
|
184
192
|
Updating
|
|
185
193
|
^^^^^^^^
|
|
186
194
|
|
|
187
|
-
Install new plugins
|
|
195
|
+
Install new plugins, update existing ones, and automatically install any Python
|
|
196
|
+
dependencies declared in the Requires field of the plugin's
|
|
197
|
+
multitool-info.json file::
|
|
188
198
|
|
|
189
199
|
multitool plugins update
|
|
190
200
|
|
|
201
|
+
Update a specific plugin only::
|
|
202
|
+
|
|
203
|
+
multitool plugins update -n PLUGIN_NAME
|
|
204
|
+
|
|
205
|
+
The Requires field is where a plugin declares the Python packages it
|
|
206
|
+
depends on. Any packages listed will be installed automatically when
|
|
207
|
+
multitool plugins update is run. For example::
|
|
208
|
+
|
|
209
|
+
{
|
|
210
|
+
"Homepage": "",
|
|
211
|
+
"Requires": "click>=8.1.3 click-aliases>=1.0.1 click-option-group>=0.5.5 GitPython>=3.1.30",
|
|
212
|
+
"Maintainer": "",
|
|
213
|
+
"Description-en": ""
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
If one or more dependencies could not be installed automatically, multitool
|
|
217
|
+
will report the failures and display the appropriate pip command to install
|
|
218
|
+
the remaining packages manually. For example::
|
|
219
|
+
|
|
220
|
+
Updating plugins
|
|
221
|
+
----------------
|
|
222
|
+
Updating mdelotavo-multitool-plugins... Done
|
|
223
|
+
Updating test... Skipped Git pull (not a Git repository)
|
|
224
|
+
|
|
225
|
+
Checking Python package dependencies
|
|
226
|
+
------------------------------------
|
|
227
|
+
Checked GitPython (GitPython>=3.1.30)... 3.1.50 installed
|
|
228
|
+
Installing asdfasdfasdf... Failed
|
|
229
|
+
Checked click-aliases (click-aliases>=1.0.1)... 1.0.1 installed
|
|
230
|
+
Checked click-option-group (click-option-group>=0.5.5)... 0.5.5 installed
|
|
231
|
+
Checked click (click>=8.1.3)... 8.1.8 installed
|
|
232
|
+
Installing qwerqwerqwer>=8.1.3... Failed
|
|
233
|
+
Checked tabulate (tabulate)... 0.9.0 installed
|
|
234
|
+
|
|
235
|
+
The following dependencies could not be installed automatically:
|
|
236
|
+
asdfasdfasdf
|
|
237
|
+
qwerqwerqwer>=8.1.3
|
|
238
|
+
|
|
239
|
+
Try installing them manually:
|
|
240
|
+
/usr/bin/python3 -m pip install asdfasdfasdf qwerqwerqwer>=8.1.3
|
|
241
|
+
|
|
242
|
+
You can also display a plugin's declared dependencies at any time::
|
|
243
|
+
|
|
244
|
+
multitool plugins show --name PLUGIN_NAME --show-dependencies-only
|
|
245
|
+
|
|
191
246
|
^^^^^^^
|
|
192
247
|
Pruning
|
|
193
248
|
^^^^^^^
|
|
@@ -209,11 +264,6 @@ Or inspect a specific repository::
|
|
|
209
264
|
multitool plugins show -n PLUGIN_NAME --show-commit-only
|
|
210
265
|
multitool plugins show -n PLUGIN_NAME --show-dependencies-only
|
|
211
266
|
|
|
212
|
-
If a plugin declares Python dependencies in ``multitool-info.json``, install
|
|
213
|
-
them with::
|
|
214
|
-
|
|
215
|
-
pip3 install $(multitool plugins show -n PLUGIN_NAME --show-dependencies-only)
|
|
216
|
-
|
|
217
267
|
---------------
|
|
218
268
|
Troubleshooting
|
|
219
269
|
---------------
|
|
@@ -28,8 +28,7 @@ Run the example command::
|
|
|
28
28
|
-vv \
|
|
29
29
|
--enabled \
|
|
30
30
|
--tag alpha \
|
|
31
|
-
--tag beta
|
|
32
|
-
--output result.json
|
|
31
|
+
--tag beta
|
|
33
32
|
|
|
34
33
|
Edit the generated source code::
|
|
35
34
|
|
|
@@ -124,10 +123,18 @@ Configuring
|
|
|
124
123
|
|
|
125
124
|
Configure plugin repositories with::
|
|
126
125
|
|
|
127
|
-
multitool plugins configure
|
|
126
|
+
multitool plugins configure
|
|
127
|
+
|
|
128
|
+
This opens your editor to modify the plugin configuration. After saving your
|
|
129
|
+
changes, apply them with::
|
|
130
|
+
|
|
131
|
+
multitool plugins update
|
|
132
|
+
|
|
133
|
+
To automatically apply the configuration changes after saving and closing the
|
|
134
|
+
file (install new plugins, update existing plugins, and prune removed plugins),
|
|
135
|
+
use::
|
|
128
136
|
|
|
129
|
-
|
|
130
|
-
don't want changes applied automatically.
|
|
137
|
+
multitool plugins configure -a
|
|
131
138
|
|
|
132
139
|
Example configuration::
|
|
133
140
|
|
|
@@ -149,11 +156,11 @@ Install the example plugins::
|
|
|
149
156
|
echo -e '[sources]\nmdelotavo-multitool-plugins = https://github.com/mdelotavo/multitool-plugins.git' >> ~/.multitool/plugins/config
|
|
150
157
|
|
|
151
158
|
multitool plugins update
|
|
159
|
+
|
|
152
160
|
multitool plugins show
|
|
153
161
|
multitool plugins show -n mdelotavo-multitool-plugins
|
|
154
162
|
multitool plugins show -n mdelotavo-multitool-plugins --show-commit-only
|
|
155
163
|
multitool plugins show -n mdelotavo-multitool-plugins --show-dependencies-only
|
|
156
|
-
pip3 install $(multitool plugins show -n mdelotavo-multitool-plugins --show-dependencies-only)
|
|
157
164
|
|
|
158
165
|
multitool run examples -h
|
|
159
166
|
|
|
@@ -161,10 +168,57 @@ Install the example plugins::
|
|
|
161
168
|
Updating
|
|
162
169
|
^^^^^^^^
|
|
163
170
|
|
|
164
|
-
Install new plugins
|
|
171
|
+
Install new plugins, update existing ones, and automatically install any Python
|
|
172
|
+
dependencies declared in the Requires field of the plugin's
|
|
173
|
+
multitool-info.json file::
|
|
165
174
|
|
|
166
175
|
multitool plugins update
|
|
167
176
|
|
|
177
|
+
Update a specific plugin only::
|
|
178
|
+
|
|
179
|
+
multitool plugins update -n PLUGIN_NAME
|
|
180
|
+
|
|
181
|
+
The Requires field is where a plugin declares the Python packages it
|
|
182
|
+
depends on. Any packages listed will be installed automatically when
|
|
183
|
+
multitool plugins update is run. For example::
|
|
184
|
+
|
|
185
|
+
{
|
|
186
|
+
"Homepage": "",
|
|
187
|
+
"Requires": "click>=8.1.3 click-aliases>=1.0.1 click-option-group>=0.5.5 GitPython>=3.1.30",
|
|
188
|
+
"Maintainer": "",
|
|
189
|
+
"Description-en": ""
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
If one or more dependencies could not be installed automatically, multitool
|
|
193
|
+
will report the failures and display the appropriate pip command to install
|
|
194
|
+
the remaining packages manually. For example::
|
|
195
|
+
|
|
196
|
+
Updating plugins
|
|
197
|
+
----------------
|
|
198
|
+
Updating mdelotavo-multitool-plugins... Done
|
|
199
|
+
Updating test... Skipped Git pull (not a Git repository)
|
|
200
|
+
|
|
201
|
+
Checking Python package dependencies
|
|
202
|
+
------------------------------------
|
|
203
|
+
Checked GitPython (GitPython>=3.1.30)... 3.1.50 installed
|
|
204
|
+
Installing asdfasdfasdf... Failed
|
|
205
|
+
Checked click-aliases (click-aliases>=1.0.1)... 1.0.1 installed
|
|
206
|
+
Checked click-option-group (click-option-group>=0.5.5)... 0.5.5 installed
|
|
207
|
+
Checked click (click>=8.1.3)... 8.1.8 installed
|
|
208
|
+
Installing qwerqwerqwer>=8.1.3... Failed
|
|
209
|
+
Checked tabulate (tabulate)... 0.9.0 installed
|
|
210
|
+
|
|
211
|
+
The following dependencies could not be installed automatically:
|
|
212
|
+
asdfasdfasdf
|
|
213
|
+
qwerqwerqwer>=8.1.3
|
|
214
|
+
|
|
215
|
+
Try installing them manually:
|
|
216
|
+
/usr/bin/python3 -m pip install asdfasdfasdf qwerqwerqwer>=8.1.3
|
|
217
|
+
|
|
218
|
+
You can also display a plugin's declared dependencies at any time::
|
|
219
|
+
|
|
220
|
+
multitool plugins show --name PLUGIN_NAME --show-dependencies-only
|
|
221
|
+
|
|
168
222
|
^^^^^^^
|
|
169
223
|
Pruning
|
|
170
224
|
^^^^^^^
|
|
@@ -186,11 +240,6 @@ Or inspect a specific repository::
|
|
|
186
240
|
multitool plugins show -n PLUGIN_NAME --show-commit-only
|
|
187
241
|
multitool plugins show -n PLUGIN_NAME --show-dependencies-only
|
|
188
242
|
|
|
189
|
-
If a plugin declares Python dependencies in ``multitool-info.json``, install
|
|
190
|
-
them with::
|
|
191
|
-
|
|
192
|
-
pip3 install $(multitool plugins show -n PLUGIN_NAME --show-dependencies-only)
|
|
193
|
-
|
|
194
243
|
---------------
|
|
195
244
|
Troubleshooting
|
|
196
245
|
---------------
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
APP = "multitool"
|
|
2
|
-
__version__ = "0.
|
|
2
|
+
__version__ = "0.8.0"
|
|
3
3
|
description = "Create and run plugin-based command-line tools."
|
|
4
4
|
long_description = ("Create and run plugin-based command-line tools by dynamically loading Click commands from local or Git-managed plugin repositories.")
|
|
5
5
|
|
|
@@ -4,6 +4,10 @@ import shutil
|
|
|
4
4
|
import stat
|
|
5
5
|
import sys
|
|
6
6
|
import uuid
|
|
7
|
+
import shutil
|
|
8
|
+
import subprocess
|
|
9
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
10
|
+
from packaging.requirements import Requirement
|
|
7
11
|
from pathlib import Path
|
|
8
12
|
|
|
9
13
|
import click
|
|
@@ -69,32 +73,173 @@ def clone():
|
|
|
69
73
|
console.echo(e)
|
|
70
74
|
|
|
71
75
|
|
|
72
|
-
def
|
|
76
|
+
def pip_command():
|
|
77
|
+
if sys.executable:
|
|
78
|
+
return [sys.executable, "-m", "pip"]
|
|
73
79
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
return
|
|
80
|
+
if shutil.which("pip"):
|
|
81
|
+
return ["pip"]
|
|
77
82
|
|
|
78
|
-
|
|
83
|
+
if shutil.which("pip3"):
|
|
84
|
+
return ["pip3"]
|
|
85
|
+
|
|
86
|
+
return None
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def package_installed(package):
|
|
90
|
+
try:
|
|
91
|
+
version(package)
|
|
92
|
+
return True
|
|
93
|
+
except PackageNotFoundError:
|
|
94
|
+
return False
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def parse_requires(info):
|
|
98
|
+
requires = info.get("Requires")
|
|
99
|
+
|
|
100
|
+
if not requires:
|
|
101
|
+
return []
|
|
102
|
+
|
|
103
|
+
if isinstance(requires, str):
|
|
104
|
+
return requires.split()
|
|
105
|
+
|
|
106
|
+
if isinstance(requires, (list, tuple, set)):
|
|
107
|
+
return [str(r).strip() for r in requires if str(r).strip()]
|
|
108
|
+
|
|
109
|
+
return []
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def package_status(requirement):
|
|
113
|
+
req = Requirement(requirement)
|
|
114
|
+
|
|
115
|
+
try:
|
|
116
|
+
installed = version(req.name)
|
|
117
|
+
except PackageNotFoundError:
|
|
118
|
+
return req, None, False
|
|
119
|
+
|
|
120
|
+
return req, installed, req.specifier.contains(installed, prereleases=True)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def install_plugin_dependencies(name=None):
|
|
124
|
+
cmd = pip_command()
|
|
125
|
+
|
|
126
|
+
if cmd is None:
|
|
127
|
+
console.echo("Unable to locate pip.")
|
|
128
|
+
return
|
|
129
|
+
|
|
130
|
+
required = set()
|
|
131
|
+
|
|
132
|
+
def add_dependencies(plugin_name):
|
|
133
|
+
info = plugin_info(plugin_name)
|
|
134
|
+
|
|
135
|
+
if info:
|
|
136
|
+
required.update(parse_requires(info))
|
|
137
|
+
|
|
138
|
+
if name:
|
|
139
|
+
path = Path(MULTITOOL_PLUGINS_DIRECTORY) / name
|
|
140
|
+
|
|
141
|
+
if not is_dir(path):
|
|
142
|
+
console.echo(f'Plugin "{name}" not found.')
|
|
143
|
+
sys.exit(1)
|
|
144
|
+
|
|
145
|
+
add_dependencies(name)
|
|
146
|
+
|
|
147
|
+
else:
|
|
148
|
+
|
|
149
|
+
def fn(path):
|
|
150
|
+
if is_dir(path):
|
|
151
|
+
add_dependencies(Path(path).stem)
|
|
152
|
+
|
|
153
|
+
for_each_file(
|
|
154
|
+
MULTITOOL_PLUGINS_DIRECTORY,
|
|
155
|
+
fn,
|
|
156
|
+
glob="[!.][!__]*",
|
|
157
|
+
)
|
|
79
158
|
|
|
80
|
-
|
|
159
|
+
failed = []
|
|
160
|
+
|
|
161
|
+
for requirement in sorted(required):
|
|
162
|
+
req, installed, satisfied = package_status(requirement)
|
|
163
|
+
|
|
164
|
+
if satisfied:
|
|
165
|
+
console.echo(f"Checked {req.name} ({requirement})... "
|
|
166
|
+
f"{installed} installed")
|
|
167
|
+
continue
|
|
168
|
+
|
|
169
|
+
if installed is None:
|
|
170
|
+
console.echo(
|
|
171
|
+
f"Installing {requirement}... ",
|
|
172
|
+
end="",
|
|
173
|
+
flush=True,
|
|
174
|
+
)
|
|
175
|
+
else:
|
|
176
|
+
console.echo(
|
|
177
|
+
f"Updating {req.name} ({installed} -> {requirement})... ",
|
|
178
|
+
end="",
|
|
179
|
+
flush=True,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
result = subprocess.run(
|
|
183
|
+
cmd + ["install", requirement],
|
|
184
|
+
stdout=subprocess.DEVNULL,
|
|
185
|
+
stderr=subprocess.DEVNULL,
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
if result.returncode == 0:
|
|
189
|
+
console.echo("Done")
|
|
190
|
+
else:
|
|
191
|
+
console.echo("Failed")
|
|
192
|
+
failed.append(requirement)
|
|
193
|
+
|
|
194
|
+
if failed:
|
|
195
|
+
console.echo()
|
|
196
|
+
console.echo("The following dependencies could not be installed automatically:")
|
|
197
|
+
|
|
198
|
+
for requirement in failed:
|
|
199
|
+
console.echo(f" {requirement}")
|
|
200
|
+
|
|
201
|
+
console.echo()
|
|
202
|
+
console.echo("Try installing them manually:")
|
|
203
|
+
console.echo(f" {' '.join(cmd)} install {' '.join(failed)}")
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def update_repos(name=None):
|
|
207
|
+
|
|
208
|
+
def update_repo(path):
|
|
209
|
+
plugin_name = Path(path).stem
|
|
210
|
+
|
|
211
|
+
console.echo(f"Updating {plugin_name}... ", end="", flush=True)
|
|
81
212
|
|
|
82
213
|
try:
|
|
83
|
-
repo = Repo(
|
|
214
|
+
repo = Repo(path)
|
|
84
215
|
|
|
85
216
|
if repo.bare:
|
|
86
|
-
console.echo("Skipped (bare repository)")
|
|
217
|
+
console.echo("Skipped Git pull (bare repository)")
|
|
87
218
|
return
|
|
88
219
|
|
|
89
220
|
if not repo.remotes:
|
|
90
|
-
console.echo("Skipped (Git repository has no remote)")
|
|
221
|
+
console.echo("Skipped Git pull (Git repository has no remote)")
|
|
91
222
|
return
|
|
92
223
|
|
|
93
224
|
repo.remotes["origin"].pull()
|
|
94
225
|
console.echo("Done")
|
|
95
226
|
|
|
96
227
|
except Exception:
|
|
97
|
-
console.echo("Skipped (not a Git repository)")
|
|
228
|
+
console.echo("Skipped Git pull (not a Git repository)")
|
|
229
|
+
|
|
230
|
+
if name:
|
|
231
|
+
path = Path(MULTITOOL_PLUGINS_DIRECTORY) / name
|
|
232
|
+
|
|
233
|
+
if not is_dir(path):
|
|
234
|
+
console.echo(f'Plugin "{name}" not found.')
|
|
235
|
+
sys.exit(1)
|
|
236
|
+
|
|
237
|
+
update_repo(path)
|
|
238
|
+
return
|
|
239
|
+
|
|
240
|
+
def fn(path):
|
|
241
|
+
if is_dir(path):
|
|
242
|
+
update_repo(path)
|
|
98
243
|
|
|
99
244
|
for_each_file(
|
|
100
245
|
MULTITOOL_PLUGINS_DIRECTORY,
|
|
@@ -181,10 +326,17 @@ def configure(silent, verbose, apply_changes):
|
|
|
181
326
|
@plugins.command()
|
|
182
327
|
@common_silent_options
|
|
183
328
|
@common_verbose_options
|
|
184
|
-
|
|
329
|
+
@click.option("-n", "--name")
|
|
330
|
+
def update(silent, verbose, name):
|
|
185
331
|
require_git()
|
|
186
332
|
clone()
|
|
187
|
-
|
|
333
|
+
console.echo("Updating plugins")
|
|
334
|
+
console.echo("----------------")
|
|
335
|
+
update_repos(name)
|
|
336
|
+
console.echo()
|
|
337
|
+
console.echo("Checking Python package dependencies")
|
|
338
|
+
console.echo("------------------------------------")
|
|
339
|
+
install_plugin_dependencies(name)
|
|
188
340
|
|
|
189
341
|
|
|
190
342
|
@plugins.command()
|
|
@@ -260,7 +412,36 @@ def prune(silent, verbose):
|
|
|
260
412
|
@common_silent_options
|
|
261
413
|
@common_verbose_options
|
|
262
414
|
@click.argument("name")
|
|
263
|
-
|
|
415
|
+
@click.option(
|
|
416
|
+
"--requires-format",
|
|
417
|
+
type=click.Choice(["array", "string"], case_sensitive=False),
|
|
418
|
+
default="string",
|
|
419
|
+
show_default=True,
|
|
420
|
+
help="Format to use for the Requires field.",
|
|
421
|
+
)
|
|
422
|
+
def new(silent, verbose, name, requires_format):
|
|
423
|
+
if requires_format == "array":
|
|
424
|
+
info = """{
|
|
425
|
+
"Homepage": "",
|
|
426
|
+
"Requires": [
|
|
427
|
+
"click>=8.1.3",
|
|
428
|
+
"click-aliases>=1.0.1",
|
|
429
|
+
"click-option-group>=0.5.5",
|
|
430
|
+
"GitPython>=3.1.30"
|
|
431
|
+
],
|
|
432
|
+
"Maintainer": "",
|
|
433
|
+
"Description-en": ""
|
|
434
|
+
}
|
|
435
|
+
"""
|
|
436
|
+
elif requires_format == "string":
|
|
437
|
+
info = """{
|
|
438
|
+
"Homepage": "",
|
|
439
|
+
"Requires": "click>=8.1.3 click-aliases>=1.0.1 click-option-group>=0.5.5 GitPython>=3.1.30",
|
|
440
|
+
"Maintainer": "",
|
|
441
|
+
"Description-en": ""
|
|
442
|
+
}
|
|
443
|
+
"""
|
|
444
|
+
|
|
264
445
|
init()
|
|
265
446
|
|
|
266
447
|
if not name.isidentifier():
|
|
@@ -381,13 +562,7 @@ def hello(
|
|
|
381
562
|
'''
|
|
382
563
|
)
|
|
383
564
|
|
|
384
|
-
(root / f"{APP}-info.json").write_text(
|
|
385
|
-
"Homepage": "",
|
|
386
|
-
"Requires": "click",
|
|
387
|
-
"Maintainer": "",
|
|
388
|
-
"Description-en": ""
|
|
389
|
-
}
|
|
390
|
-
""")
|
|
565
|
+
(root / f"{APP}-info.json").write_text(info)
|
|
391
566
|
|
|
392
567
|
touch(root / "README.md")
|
|
393
568
|
touch(root / "LICENSE")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: multitool
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: Create and run plugin-based command-line tools.
|
|
5
5
|
Author-email: Matthew Delotavo <matthew.t.delotavo@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -19,6 +19,7 @@ Requires-Dist: click>=8.1.3
|
|
|
19
19
|
Requires-Dist: click-aliases>=1.0.1
|
|
20
20
|
Requires-Dist: click-option-group>=0.5.5
|
|
21
21
|
Requires-Dist: GitPython>=3.1.30
|
|
22
|
+
Requires-Dist: packaging>=26.2
|
|
22
23
|
Dynamic: license-file
|
|
23
24
|
|
|
24
25
|
multitool
|
|
@@ -51,8 +52,7 @@ Run the example command::
|
|
|
51
52
|
-vv \
|
|
52
53
|
--enabled \
|
|
53
54
|
--tag alpha \
|
|
54
|
-
--tag beta
|
|
55
|
-
--output result.json
|
|
55
|
+
--tag beta
|
|
56
56
|
|
|
57
57
|
Edit the generated source code::
|
|
58
58
|
|
|
@@ -147,10 +147,18 @@ Configuring
|
|
|
147
147
|
|
|
148
148
|
Configure plugin repositories with::
|
|
149
149
|
|
|
150
|
-
multitool plugins configure
|
|
150
|
+
multitool plugins configure
|
|
151
|
+
|
|
152
|
+
This opens your editor to modify the plugin configuration. After saving your
|
|
153
|
+
changes, apply them with::
|
|
154
|
+
|
|
155
|
+
multitool plugins update
|
|
156
|
+
|
|
157
|
+
To automatically apply the configuration changes after saving and closing the
|
|
158
|
+
file (install new plugins, update existing plugins, and prune removed plugins),
|
|
159
|
+
use::
|
|
151
160
|
|
|
152
|
-
|
|
153
|
-
don't want changes applied automatically.
|
|
161
|
+
multitool plugins configure -a
|
|
154
162
|
|
|
155
163
|
Example configuration::
|
|
156
164
|
|
|
@@ -172,11 +180,11 @@ Install the example plugins::
|
|
|
172
180
|
echo -e '[sources]\nmdelotavo-multitool-plugins = https://github.com/mdelotavo/multitool-plugins.git' >> ~/.multitool/plugins/config
|
|
173
181
|
|
|
174
182
|
multitool plugins update
|
|
183
|
+
|
|
175
184
|
multitool plugins show
|
|
176
185
|
multitool plugins show -n mdelotavo-multitool-plugins
|
|
177
186
|
multitool plugins show -n mdelotavo-multitool-plugins --show-commit-only
|
|
178
187
|
multitool plugins show -n mdelotavo-multitool-plugins --show-dependencies-only
|
|
179
|
-
pip3 install $(multitool plugins show -n mdelotavo-multitool-plugins --show-dependencies-only)
|
|
180
188
|
|
|
181
189
|
multitool run examples -h
|
|
182
190
|
|
|
@@ -184,10 +192,57 @@ Install the example plugins::
|
|
|
184
192
|
Updating
|
|
185
193
|
^^^^^^^^
|
|
186
194
|
|
|
187
|
-
Install new plugins
|
|
195
|
+
Install new plugins, update existing ones, and automatically install any Python
|
|
196
|
+
dependencies declared in the Requires field of the plugin's
|
|
197
|
+
multitool-info.json file::
|
|
188
198
|
|
|
189
199
|
multitool plugins update
|
|
190
200
|
|
|
201
|
+
Update a specific plugin only::
|
|
202
|
+
|
|
203
|
+
multitool plugins update -n PLUGIN_NAME
|
|
204
|
+
|
|
205
|
+
The Requires field is where a plugin declares the Python packages it
|
|
206
|
+
depends on. Any packages listed will be installed automatically when
|
|
207
|
+
multitool plugins update is run. For example::
|
|
208
|
+
|
|
209
|
+
{
|
|
210
|
+
"Homepage": "",
|
|
211
|
+
"Requires": "click>=8.1.3 click-aliases>=1.0.1 click-option-group>=0.5.5 GitPython>=3.1.30",
|
|
212
|
+
"Maintainer": "",
|
|
213
|
+
"Description-en": ""
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
If one or more dependencies could not be installed automatically, multitool
|
|
217
|
+
will report the failures and display the appropriate pip command to install
|
|
218
|
+
the remaining packages manually. For example::
|
|
219
|
+
|
|
220
|
+
Updating plugins
|
|
221
|
+
----------------
|
|
222
|
+
Updating mdelotavo-multitool-plugins... Done
|
|
223
|
+
Updating test... Skipped Git pull (not a Git repository)
|
|
224
|
+
|
|
225
|
+
Checking Python package dependencies
|
|
226
|
+
------------------------------------
|
|
227
|
+
Checked GitPython (GitPython>=3.1.30)... 3.1.50 installed
|
|
228
|
+
Installing asdfasdfasdf... Failed
|
|
229
|
+
Checked click-aliases (click-aliases>=1.0.1)... 1.0.1 installed
|
|
230
|
+
Checked click-option-group (click-option-group>=0.5.5)... 0.5.5 installed
|
|
231
|
+
Checked click (click>=8.1.3)... 8.1.8 installed
|
|
232
|
+
Installing qwerqwerqwer>=8.1.3... Failed
|
|
233
|
+
Checked tabulate (tabulate)... 0.9.0 installed
|
|
234
|
+
|
|
235
|
+
The following dependencies could not be installed automatically:
|
|
236
|
+
asdfasdfasdf
|
|
237
|
+
qwerqwerqwer>=8.1.3
|
|
238
|
+
|
|
239
|
+
Try installing them manually:
|
|
240
|
+
/usr/bin/python3 -m pip install asdfasdfasdf qwerqwerqwer>=8.1.3
|
|
241
|
+
|
|
242
|
+
You can also display a plugin's declared dependencies at any time::
|
|
243
|
+
|
|
244
|
+
multitool plugins show --name PLUGIN_NAME --show-dependencies-only
|
|
245
|
+
|
|
191
246
|
^^^^^^^
|
|
192
247
|
Pruning
|
|
193
248
|
^^^^^^^
|
|
@@ -209,11 +264,6 @@ Or inspect a specific repository::
|
|
|
209
264
|
multitool plugins show -n PLUGIN_NAME --show-commit-only
|
|
210
265
|
multitool plugins show -n PLUGIN_NAME --show-dependencies-only
|
|
211
266
|
|
|
212
|
-
If a plugin declares Python dependencies in ``multitool-info.json``, install
|
|
213
|
-
them with::
|
|
214
|
-
|
|
215
|
-
pip3 install $(multitool plugins show -n PLUGIN_NAME --show-dependencies-only)
|
|
216
|
-
|
|
217
267
|
---------------
|
|
218
268
|
Troubleshooting
|
|
219
269
|
---------------
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "multitool"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.8.0"
|
|
8
8
|
description = "Create and run plugin-based command-line tools."
|
|
9
9
|
readme = { file = "README.rst", content-type = "text/x-rst" }
|
|
10
10
|
requires-python = ">=3.7"
|
|
@@ -28,7 +28,8 @@ dependencies = [
|
|
|
28
28
|
"click>=8.1.3",
|
|
29
29
|
"click-aliases>=1.0.1",
|
|
30
30
|
"click-option-group>=0.5.5",
|
|
31
|
-
"GitPython>=3.1.30"
|
|
31
|
+
"GitPython>=3.1.30",
|
|
32
|
+
"packaging>=26.2"
|
|
32
33
|
]
|
|
33
34
|
|
|
34
35
|
[project.urls]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|