multitool 0.4.0__tar.gz → 0.5.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.
Files changed (25) hide show
  1. {multitool-0.4.0 → multitool-0.5.0}/LICENSE +0 -0
  2. {multitool-0.4.0 → multitool-0.5.0}/PKG-INFO +17 -9
  3. {multitool-0.4.0 → multitool-0.5.0}/README.rst +13 -8
  4. {multitool-0.4.0 → multitool-0.5.0}/multitool/__init__.py +1 -1
  5. {multitool-0.4.0 → multitool-0.5.0}/multitool/__main__.py +0 -0
  6. {multitool-0.4.0 → multitool-0.5.0}/multitool/cls.py +0 -0
  7. {multitool-0.4.0 → multitool-0.5.0}/multitool/console.py +0 -0
  8. {multitool-0.4.0 → multitool-0.5.0}/multitool/exceptions.py +0 -0
  9. {multitool-0.4.0 → multitool-0.5.0}/multitool/plugins/__init__.py +0 -0
  10. multitool-0.5.0/multitool/plugins/commands.py +266 -0
  11. {multitool-0.4.0 → multitool-0.5.0}/multitool/silent.py +0 -0
  12. {multitool-0.4.0 → multitool-0.5.0}/multitool/utils.py +0 -0
  13. {multitool-0.4.0 → multitool-0.5.0}/multitool/verbose.py +0 -0
  14. {multitool-0.4.0 → multitool-0.5.0}/multitool.egg-info/PKG-INFO +17 -9
  15. {multitool-0.4.0 → multitool-0.5.0}/multitool.egg-info/SOURCES.txt +0 -0
  16. {multitool-0.4.0 → multitool-0.5.0}/multitool.egg-info/dependency_links.txt +0 -0
  17. {multitool-0.4.0 → multitool-0.5.0}/multitool.egg-info/entry_points.txt +1 -0
  18. multitool-0.5.0/multitool.egg-info/requires.txt +4 -0
  19. {multitool-0.4.0 → multitool-0.5.0}/multitool.egg-info/top_level.txt +0 -0
  20. {multitool-0.4.0 → multitool-0.5.0}/setup.cfg +0 -0
  21. {multitool-0.4.0 → multitool-0.5.0}/setup.py +0 -7
  22. {multitool-0.4.0 → multitool-0.5.0}/tests/__init__.py +0 -0
  23. {multitool-0.4.0 → multitool-0.5.0}/tests/test_utils.py +0 -0
  24. multitool-0.4.0/multitool/plugins/commands.py +0 -229
  25. multitool-0.4.0/multitool.egg-info/requires.txt +0 -11
File without changes
@@ -1,11 +1,12 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: multitool
3
- Version: 0.4.0
3
+ Version: 0.5.0
4
4
  Summary: General-purpose command-line interface with plugins support
5
5
  Home-page: https://github.com/mdelotavo/multitool
6
6
  Author: Matthew Delotavo
7
7
  Author-email: matthew.t.delotavo@gmail.com
8
8
  License: MIT
9
+ Platform: UNKNOWN
9
10
  Classifier: Development Status :: 4 - Beta
10
11
  Classifier: Environment :: Console
11
12
  Classifier: Intended Audience :: Developers
@@ -24,9 +25,7 @@ Multitool is a general-purpose command-line interface with plugins support.
24
25
  Why does this exist?
25
26
  --------------------
26
27
 
27
- I built this tool so that I can quickly create and distribute command-line tools for consulting work and personal use.
28
-
29
- The plugins manager uses ``git`` to manage plugins installed from remote ``git`` repositories.
28
+ I built this tool so I can quickly create and distribute command-line tools for consulting work and personal use.
30
29
 
31
30
  -----
32
31
  Usage
@@ -48,9 +47,6 @@ Usage
48
47
  Commands:
49
48
  plugins Simple plugins manager for distributing commands.
50
49
 
51
- .. ..
52
- The plugins features are based off those found in the `apigeecli`_.
53
-
54
50
  ----------------
55
51
  Managing plugins
56
52
  ----------------
@@ -122,7 +118,7 @@ This will install and update plugins.
122
118
  Pruning
123
119
  ^^^^^^^
124
120
 
125
- If you specified the ``-a`` option when running ``multitool plugins configure`` then the removal of plugins will occur automatically.
121
+ If you remove plugins from the config file or comment them out, and you then specified the ``-a`` option when running ``multitool plugins configure`` then the removal of plugins will occur automatically.
126
122
  Otherwise you can run::
127
123
 
128
124
  multitool plugins prune
@@ -146,6 +142,17 @@ In order for this to work, the plugin needs to have the ``Requires`` key in the
146
142
 
147
143
  pip3 install $(multitool plugins show -n PLUGIN_NAME --show-dependencies-only)
148
144
 
145
+ ^^^^^^^^^^^^^^^
146
+ Troubleshooting
147
+ ^^^^^^^^^^^^^^^
148
+
149
+ If you encounter issues with plugins or commands, you can find more detailed debug information and error messages in the log file:
150
+ ::
151
+
152
+ ~/.multitool/multitool.log
153
+
154
+ Reviewing this file can help you diagnose installation problems, missing dependencies, or Git-related errors.
155
+
149
156
  .. ..
150
157
  ----------------------------
151
158
  Create a virtual environment
@@ -167,6 +174,7 @@ In order for this to work, the plugin needs to have the ``Requires`` key in the
167
174
  deactivate
168
175
 
169
176
  .. _`click`: https://click.palletsprojects.com/
170
- .. _`apigeecli`: https://pypi.org/project/apigeecli/
171
177
  .. _`multitool-plugins`: https://github.com/mdelotavo/multitool-plugins
172
178
  .. _`public plugins repository`: https://github.com/mdelotavo/multitool-plugins
179
+
180
+
@@ -7,9 +7,7 @@ Multitool is a general-purpose command-line interface with plugins support.
7
7
  Why does this exist?
8
8
  --------------------
9
9
 
10
- I built this tool so that I can quickly create and distribute command-line tools for consulting work and personal use.
11
-
12
- The plugins manager uses ``git`` to manage plugins installed from remote ``git`` repositories.
10
+ I built this tool so I can quickly create and distribute command-line tools for consulting work and personal use.
13
11
 
14
12
  -----
15
13
  Usage
@@ -31,9 +29,6 @@ Usage
31
29
  Commands:
32
30
  plugins Simple plugins manager for distributing commands.
33
31
 
34
- .. ..
35
- The plugins features are based off those found in the `apigeecli`_.
36
-
37
32
  ----------------
38
33
  Managing plugins
39
34
  ----------------
@@ -105,7 +100,7 @@ This will install and update plugins.
105
100
  Pruning
106
101
  ^^^^^^^
107
102
 
108
- If you specified the ``-a`` option when running ``multitool plugins configure`` then the removal of plugins will occur automatically.
103
+ If you remove plugins from the config file or comment them out, and you then specified the ``-a`` option when running ``multitool plugins configure`` then the removal of plugins will occur automatically.
109
104
  Otherwise you can run::
110
105
 
111
106
  multitool plugins prune
@@ -129,6 +124,17 @@ In order for this to work, the plugin needs to have the ``Requires`` key in the
129
124
 
130
125
  pip3 install $(multitool plugins show -n PLUGIN_NAME --show-dependencies-only)
131
126
 
127
+ ^^^^^^^^^^^^^^^
128
+ Troubleshooting
129
+ ^^^^^^^^^^^^^^^
130
+
131
+ If you encounter issues with plugins or commands, you can find more detailed debug information and error messages in the log file:
132
+ ::
133
+
134
+ ~/.multitool/multitool.log
135
+
136
+ Reviewing this file can help you diagnose installation problems, missing dependencies, or Git-related errors.
137
+
132
138
  .. ..
133
139
  ----------------------------
134
140
  Create a virtual environment
@@ -150,6 +156,5 @@ In order for this to work, the plugin needs to have the ``Requires`` key in the
150
156
  deactivate
151
157
 
152
158
  .. _`click`: https://click.palletsprojects.com/
153
- .. _`apigeecli`: https://pypi.org/project/apigeecli/
154
159
  .. _`multitool-plugins`: https://github.com/mdelotavo/multitool-plugins
155
160
  .. _`public plugins repository`: https://github.com/mdelotavo/multitool-plugins
@@ -1,5 +1,5 @@
1
1
  APP = 'multitool'
2
- __version__ = '0.4.0'
2
+ __version__ = '0.5.0'
3
3
  description = 'General-purpose command-line interface with plugins support'
4
4
  # long_description = 'General-purpose command-line interface with plugins support'
5
5
 
File without changes
@@ -0,0 +1,266 @@
1
+ import configparser
2
+ import os
3
+ import shutil
4
+ import stat
5
+ import sys
6
+ from os import path
7
+ from pathlib import Path
8
+
9
+ import click
10
+ from click_option_group import MutuallyExclusiveOptionGroup, optgroup
11
+
12
+ from multitool import (
13
+ APP,
14
+ MULTITOOL_PLUGINS_CONFIG_FILE,
15
+ MULTITOOL_PLUGINS_DIRECTORY,
16
+ MULTITOOL_PLUGINS_PATH,
17
+ console,
18
+ )
19
+ from multitool.silent import common_silent_options
20
+ from multitool.utils import (
21
+ is_directory,
22
+ is_regular_file,
23
+ create_directory,
24
+ read_file_content,
25
+ execute_function_on_directory_files,
26
+ create_empty_file,
27
+ )
28
+ from multitool.verbose import common_verbose_options
29
+
30
+
31
+ # ---- Global Variables ----
32
+ plugins_command_help = 'Simple plugins manager for distributing commands.'
33
+
34
+ # ---- Git Check ----
35
+ is_git_installed = False
36
+ try:
37
+ from git import Repo
38
+ is_git_installed = True
39
+ except ImportError:
40
+ plugins_command_help = (
41
+ "Simple plugins manager for distributing commands. "
42
+ "[Warning: Git must be installed to use plugin commands]"
43
+ )
44
+
45
+
46
+ # ---- Helper Classes ----
47
+ class FileUtils:
48
+ """Internal helper class for file/directory operations."""
49
+
50
+ @staticmethod
51
+ def chmod_directory(directory, mode):
52
+ """Recursively change permissions of a directory and its contents."""
53
+ for root, dirs, files in os.walk(directory):
54
+ for d in dirs:
55
+ os.chmod(path.join(root, d), mode)
56
+ for f in files:
57
+ os.chmod(path.join(root, f), mode)
58
+
59
+
60
+ class GitUtils:
61
+ """Internal helper class for Git operations."""
62
+
63
+ @staticmethod
64
+ def exit_if_not_installed():
65
+ if not is_git_installed:
66
+ sys.exit(0)
67
+
68
+
69
+ class PluginManager:
70
+ """Internal helper class for MULTITOOL plugin management."""
71
+
72
+ @staticmethod
73
+ def initialize_plugins():
74
+ create_directory(MULTITOOL_PLUGINS_DIRECTORY)
75
+ create_empty_file(MULTITOOL_PLUGINS_PATH)
76
+ create_empty_file(MULTITOOL_PLUGINS_CONFIG_FILE)
77
+
78
+ @staticmethod
79
+ def load_config(config_file=MULTITOOL_PLUGINS_CONFIG_FILE):
80
+ config = configparser.ConfigParser(allow_no_value=True)
81
+ config.read(config_file)
82
+ return config
83
+
84
+ @staticmethod
85
+ def clone_repositories(section="sources"):
86
+ PluginManager.initialize_plugins()
87
+ config = PluginManager.load_config()
88
+ if not config._sections:
89
+ return
90
+ sources = dict(config._sections[section])
91
+ for name, uri in sources.items():
92
+ dest = Path(MULTITOOL_PLUGINS_DIRECTORY) / name
93
+ if is_directory(dest):
94
+ continue
95
+ try:
96
+ console.echo(f"Installing {name}... ", line_ending="", should_flush=True)
97
+ Repo.clone_from(uri, dest)
98
+ console.echo("Done")
99
+ except Exception as e:
100
+ console.echo(e)
101
+
102
+ @staticmethod
103
+ def prune_unused_directories(section="sources"):
104
+ PluginManager.initialize_plugins()
105
+ config = PluginManager.load_config()
106
+ if not config._sections:
107
+ return
108
+ sources = dict(config._sections[section])
109
+
110
+ def _func(path_):
111
+ if not is_directory(path_):
112
+ return
113
+ name = Path(path_).stem
114
+ if name in sources:
115
+ return
116
+ console.echo(f"Removing {name}... ", line_ending="", should_flush=True)
117
+ plugin_directory = Path(MULTITOOL_PLUGINS_DIRECTORY) / name
118
+ try:
119
+ FileUtils.chmod_directory(str(Path(plugin_directory) / ".git"), stat.S_IRWXU)
120
+ shutil.rmtree(plugin_directory)
121
+ console.echo("Done")
122
+ except Exception as e:
123
+ console.echo(e)
124
+
125
+ return execute_function_on_directory_files(
126
+ MULTITOOL_PLUGINS_DIRECTORY, _func, glob="[!.][!__]*"
127
+ )
128
+
129
+ @staticmethod
130
+ def update_repositories():
131
+ def _func(path_):
132
+ if not is_directory(path_):
133
+ return
134
+ console.echo(f"Updating {Path(path_).stem}... ", line_ending="", should_flush=True)
135
+ repo = Repo(path_)
136
+ if repo.bare:
137
+ return
138
+ try:
139
+ repo.remotes["origin"].pull()
140
+ console.echo("Done")
141
+ except Exception as e:
142
+ console.echo(e)
143
+
144
+ return execute_function_on_directory_files(
145
+ MULTITOOL_PLUGINS_DIRECTORY, _func, glob="[!.][!__]*"
146
+ )
147
+
148
+ @staticmethod
149
+ def list_sources(section="sources"):
150
+ """Return a dictionary of plugin sources from config."""
151
+ config = PluginManager.load_config()
152
+ return dict(config._sections.get(section, {}))
153
+
154
+ @staticmethod
155
+ def get_plugin_info(name):
156
+ """Return the parsed plugin info JSON or None if file missing."""
157
+ info_file = Path(MULTITOOL_PLUGINS_DIRECTORY) / name / f"{APP}-info.json"
158
+ if not is_regular_file(info_file):
159
+ return None
160
+ return read_file_content(info_file, type="json")
161
+
162
+ @staticmethod
163
+ def print_latest_commit(name):
164
+ """Print the latest Git commit of a plugin repository."""
165
+ GitUtils.exit_if_not_installed()
166
+ repo = Repo(Path(MULTITOOL_PLUGINS_DIRECTORY) / name)
167
+ console.echo(repo.git.log(
168
+ "--pretty=format:%Cred%h%Creset -%C(yellow)%d%Creset %s "
169
+ "%Cgreen(%cr) %C(bold blue)<%an>%Creset", "-1"
170
+ ))
171
+
172
+ @staticmethod
173
+ def print_dependencies(plugins_info):
174
+ """Print the 'Requires' field from plugin info, if any."""
175
+ requires = plugins_info.get("Requires")
176
+ if requires:
177
+ console.echo(requires)
178
+
179
+ @staticmethod
180
+ def print_full_info(plugins_info):
181
+ """Print all key/value pairs from plugin info."""
182
+ for key, value in plugins_info.items():
183
+ console.echo(f"{key}: {value}")
184
+
185
+
186
+ # ---- CLI Commands ----
187
+ @click.group(help=plugins_command_help)
188
+ def plugins():
189
+ pass
190
+
191
+
192
+ @plugins.command(help="Edit config file manually.")
193
+ @common_silent_options
194
+ @common_verbose_options
195
+ @click.option(
196
+ "-a/-A",
197
+ "--apply-changes/--no-apply-changes",
198
+ default=False,
199
+ help="Install plugins from new sources after exiting the editor.",
200
+ show_default=True,
201
+ )
202
+ def configure(silent, verbose, apply_changes):
203
+ GitUtils.exit_if_not_installed()
204
+ PluginManager.initialize_plugins()
205
+ click.edit(filename=MULTITOOL_PLUGINS_CONFIG_FILE)
206
+ if apply_changes:
207
+ PluginManager.clone_repositories()
208
+ PluginManager.prune_unused_directories()
209
+ else:
210
+ console.echo(f"\n Run `{APP} plugins update` to apply any changes,")
211
+ console.echo(f" or rerun `{APP} plugins configure` with `-a`")
212
+ console.echo(" to apply changes automatically.\n")
213
+
214
+
215
+ @plugins.command(help="Update or install plugins.")
216
+ @common_silent_options
217
+ @common_verbose_options
218
+ def update(silent, verbose, section="sources"):
219
+ GitUtils.exit_if_not_installed()
220
+ PluginManager.clone_repositories()
221
+ PluginManager.update_repositories()
222
+
223
+
224
+ @plugins.command(help="Show plugins information.")
225
+ @common_silent_options
226
+ @common_verbose_options
227
+ @click.option("-n", "--name", help="Name of the plugins package")
228
+ @optgroup.group("Filter options", cls=MutuallyExclusiveOptionGroup, help="The filter options")
229
+ @optgroup.option(
230
+ "--show-commit-only/--no-show-commit-only",
231
+ default=False,
232
+ help="Only print latest Git commit log",
233
+ )
234
+ @optgroup.option(
235
+ "--show-dependencies-only/--no-show-dependencies-only",
236
+ default=False,
237
+ help="Only print list of required packages",
238
+ )
239
+ def show(silent, verbose, name, section="sources", show_commit_only=False, show_dependencies_only=False):
240
+ """Show plugins sources, info, commits, or dependencies based on options."""
241
+
242
+ if not name:
243
+ # List all plugin sources
244
+ sources = PluginManager.list_sources(section)
245
+ for plugin_name, uri in sources.items():
246
+ console.echo(f"{plugin_name}: {uri}")
247
+ return
248
+
249
+ plugins_info = PluginManager.get_plugin_info(name)
250
+ if not plugins_info:
251
+ return
252
+
253
+ if show_commit_only:
254
+ PluginManager.print_latest_commit(name)
255
+ elif show_dependencies_only:
256
+ PluginManager.print_dependencies(plugins_info)
257
+ else:
258
+ PluginManager.print_full_info(plugins_info)
259
+
260
+
261
+ @plugins.command(help="Prune plugins with removed sources.")
262
+ @common_silent_options
263
+ @common_verbose_options
264
+ def prune(silent, verbose, section="sources"):
265
+ GitUtils.exit_if_not_installed()
266
+ PluginManager.prune_unused_directories()
File without changes
File without changes
@@ -1,11 +1,12 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: multitool
3
- Version: 0.4.0
3
+ Version: 0.5.0
4
4
  Summary: General-purpose command-line interface with plugins support
5
5
  Home-page: https://github.com/mdelotavo/multitool
6
6
  Author: Matthew Delotavo
7
7
  Author-email: matthew.t.delotavo@gmail.com
8
8
  License: MIT
9
+ Platform: UNKNOWN
9
10
  Classifier: Development Status :: 4 - Beta
10
11
  Classifier: Environment :: Console
11
12
  Classifier: Intended Audience :: Developers
@@ -24,9 +25,7 @@ Multitool is a general-purpose command-line interface with plugins support.
24
25
  Why does this exist?
25
26
  --------------------
26
27
 
27
- I built this tool so that I can quickly create and distribute command-line tools for consulting work and personal use.
28
-
29
- The plugins manager uses ``git`` to manage plugins installed from remote ``git`` repositories.
28
+ I built this tool so I can quickly create and distribute command-line tools for consulting work and personal use.
30
29
 
31
30
  -----
32
31
  Usage
@@ -48,9 +47,6 @@ Usage
48
47
  Commands:
49
48
  plugins Simple plugins manager for distributing commands.
50
49
 
51
- .. ..
52
- The plugins features are based off those found in the `apigeecli`_.
53
-
54
50
  ----------------
55
51
  Managing plugins
56
52
  ----------------
@@ -122,7 +118,7 @@ This will install and update plugins.
122
118
  Pruning
123
119
  ^^^^^^^
124
120
 
125
- If you specified the ``-a`` option when running ``multitool plugins configure`` then the removal of plugins will occur automatically.
121
+ If you remove plugins from the config file or comment them out, and you then specified the ``-a`` option when running ``multitool plugins configure`` then the removal of plugins will occur automatically.
126
122
  Otherwise you can run::
127
123
 
128
124
  multitool plugins prune
@@ -146,6 +142,17 @@ In order for this to work, the plugin needs to have the ``Requires`` key in the
146
142
 
147
143
  pip3 install $(multitool plugins show -n PLUGIN_NAME --show-dependencies-only)
148
144
 
145
+ ^^^^^^^^^^^^^^^
146
+ Troubleshooting
147
+ ^^^^^^^^^^^^^^^
148
+
149
+ If you encounter issues with plugins or commands, you can find more detailed debug information and error messages in the log file:
150
+ ::
151
+
152
+ ~/.multitool/multitool.log
153
+
154
+ Reviewing this file can help you diagnose installation problems, missing dependencies, or Git-related errors.
155
+
149
156
  .. ..
150
157
  ----------------------------
151
158
  Create a virtual environment
@@ -167,6 +174,7 @@ In order for this to work, the plugin needs to have the ``Requires`` key in the
167
174
  deactivate
168
175
 
169
176
  .. _`click`: https://click.palletsprojects.com/
170
- .. _`apigeecli`: https://pypi.org/project/apigeecli/
171
177
  .. _`multitool-plugins`: https://github.com/mdelotavo/multitool-plugins
172
178
  .. _`public plugins repository`: https://github.com/mdelotavo/multitool-plugins
179
+
180
+
@@ -1,2 +1,3 @@
1
1
  [console_scripts]
2
2
  multitool = multitool.__main__:main
3
+
@@ -0,0 +1,4 @@
1
+ click-aliases>=1.0.1
2
+ click-option-group>=0.5.5
3
+ click>=8.1.3
4
+ gitpython>=3.1.30
File without changes
@@ -31,16 +31,9 @@ SETUP_ARGS = dict(
31
31
  ]
32
32
  },
33
33
  install_requires = [
34
- 'requests>=2.28.1',
35
34
  'click>=8.1.3',
36
35
  'click-aliases>=1.0.1',
37
36
  'click-option-group>=0.5.5',
38
- 'colorama>=0.4.6',
39
- 'pyotp>=2.8.0',
40
- 'tqdm>=4.64.1',
41
- 'tabulate>=0.9.0',
42
- 'pyjwt>=2.6.0',
43
- 'python-gnupg>=0.4.9',
44
37
  'gitpython>=3.1.30'
45
38
  ],
46
39
  python_requires=">=3.7",
File without changes
File without changes
@@ -1,229 +0,0 @@
1
- import configparser
2
- import os
3
- import shutil
4
- import stat
5
- import sys
6
- from os import path
7
- from pathlib import Path
8
-
9
- import click
10
- from click_option_group import MutuallyExclusiveOptionGroup, optgroup
11
-
12
- from multitool import (MULTITOOL_PLUGINS_CONFIG_FILE,
13
- MULTITOOL_PLUGINS_DIRECTORY, MULTITOOL_PLUGINS_PATH,
14
- console)
15
- from multitool.silent import common_silent_options
16
- from multitool.utils import (is_directory, is_regular_file, create_directory, read_file_content,
17
- execute_function_on_directory_files, create_empty_file)
18
- from multitool.verbose import common_verbose_options
19
-
20
- is_git_installed = False
21
- plugins_command_help = 'Simple plugins manager for distributing commands.'
22
-
23
- try:
24
- from git import Repo
25
-
26
- is_git_installed = True
27
- except ImportError:
28
- plugins_command_help = '[Git not found! Please install Git first.] Simple plugins manager for distributing commands. This command requires Git to be installed.'
29
-
30
-
31
- def chmod_directory(directory, mode):
32
- """
33
- Recursively changes the permissions of a directory and its contents.
34
-
35
- Reference: https://stackoverflow.com/a/58878271
36
-
37
- Args:
38
- directory (str): Path to the directory.
39
- mode (int): Permissions to be set (e.g., 0o0700).
40
-
41
- """
42
- for root, dirs, files in os.walk(directory):
43
- for dir in dirs:
44
- os.chmod(path.join(root, dir), mode)
45
- for file in files:
46
- os.chmod(path.join(root, file), mode)
47
-
48
-
49
- def clone_plugin_repositories(section="sources"):
50
- initialize_MULTITOOL_plugins()
51
- config = load_plugin_config()
52
- if not config._sections:
53
- return
54
- sources = dict(config._sections[section])
55
- for name, uri in sources.items():
56
- dest = Path(MULTITOOL_PLUGINS_DIRECTORY) / name
57
- if is_directory(dest):
58
- continue
59
- try:
60
- console.echo(f"Installing {name}... ", line_ending="", should_flush=True)
61
- Repo.clone_from(uri, dest)
62
- console.echo("Done")
63
- except Exception as e:
64
- console.echo(e)
65
-
66
-
67
- def exit_quietly_if_git_not_installed():
68
- if not is_git_installed:
69
- sys.exit(0)
70
-
71
-
72
- def initialize_and_save_plugin_config():
73
- initialize_MULTITOOL_plugins()
74
- config = load_plugin_config()
75
- if not config._sections:
76
- return
77
-
78
-
79
- def initialize_MULTITOOL_plugins():
80
- create_directory(MULTITOOL_PLUGINS_DIRECTORY)
81
- create_empty_file(MULTITOOL_PLUGINS_PATH)
82
- create_empty_file(MULTITOOL_PLUGINS_CONFIG_FILE)
83
-
84
-
85
- def load_plugin_config(config_file=MULTITOOL_PLUGINS_CONFIG_FILE):
86
- config = configparser.ConfigParser(allow_no_value=True)
87
- config.read(config_file)
88
- return config
89
-
90
-
91
- def prune_unused_plugin_directories(section="sources"):
92
- initialize_MULTITOOL_plugins()
93
- config = load_plugin_config()
94
- if not config._sections:
95
- return
96
- sources = dict(config._sections[section])
97
-
98
- def _func(path):
99
- if not is_directory(path):
100
- return
101
- name = Path(path).stem
102
- if name in sources:
103
- return
104
- console.echo(f"Removing {name}... ", line_ending="", should_flush=True)
105
- plugin_directory = Path(MULTITOOL_PLUGINS_DIRECTORY) / name
106
- try:
107
- chmod_directory(str(Path(plugin_directory) / ".git"), stat.S_IRWXU)
108
- shutil.rmtree(plugin_directory)
109
- console.echo("Done")
110
- except Exception as e:
111
- console.echo(e)
112
-
113
- return execute_function_on_directory_files(MULTITOOL_PLUGINS_DIRECTORY, _func, glob="[!.][!__]*")
114
-
115
-
116
- def update_plugin_repositories():
117
- def _func(path):
118
- if not is_directory(path):
119
- return
120
- console.echo(f"Updating {Path(path).stem}... ", line_ending="", should_flush=True)
121
- repo = Repo(path)
122
- if repo.bare:
123
- return
124
- try:
125
- repo.remotes["origin"].pull()
126
- console.echo("Done")
127
- except Exception as e:
128
- console.echo(e)
129
-
130
- return execute_function_on_directory_files(MULTITOOL_PLUGINS_DIRECTORY, _func, glob="[!.][!__]*")
131
-
132
-
133
- @click.group(help=plugins_command_help)
134
- def plugins():
135
- pass
136
-
137
-
138
- @plugins.command(help="Edit config file manually.")
139
- @common_silent_options
140
- @common_verbose_options
141
- @click.option(
142
- "-a/-A",
143
- "--apply-changes/--no-apply-changes",
144
- default=False,
145
- help="Install plugins from new sources after exiting the editor.",
146
- show_default=True,
147
- )
148
- def configure(silent, verbose, apply_changes):
149
- exit_quietly_if_git_not_installed()
150
- initialize_MULTITOOL_plugins()
151
- click.edit(filename=MULTITOOL_PLUGINS_CONFIG_FILE)
152
- if apply_changes:
153
- clone_plugin_repositories()
154
- prune_unused_plugin_directories()
155
- else:
156
- console.echo("\n Run `apigee plugins update` to apply any changes,")
157
- console.echo(" or rerun `apigee plugins configure` with `-a`")
158
- console.echo(" to apply changes automatically.\n")
159
-
160
-
161
- @plugins.command(help="Update or install plugins.")
162
- @common_silent_options
163
- @common_verbose_options
164
- def update(silent, verbose, section="sources"):
165
- exit_quietly_if_git_not_installed()
166
- clone_plugin_repositories()
167
- update_plugin_repositories()
168
-
169
-
170
- @plugins.command(help="Show plugins information.")
171
- @common_silent_options
172
- @common_verbose_options
173
- @click.option("-n", "--name", help="name of the plugins package")
174
- @optgroup.group(
175
- "Filter options", cls=MutuallyExclusiveOptionGroup, help="The filter options"
176
- )
177
- @optgroup.option(
178
- "--show-commit-only/--no-show-commit-only",
179
- default=False,
180
- help="only print latest Git commit log",
181
- )
182
- @optgroup.option(
183
- "--show-dependencies-only/--no-show-dependencies-only",
184
- default=False,
185
- help="only print list of required packages",
186
- )
187
- def show(
188
- silent,
189
- verbose,
190
- name,
191
- section="sources",
192
- show_commit_only=False,
193
- show_dependencies_only=False,
194
- ):
195
- if not name:
196
- config = load_plugin_config()
197
- if not config._sections:
198
- return
199
- sources = dict(config._sections[section])
200
- for name, uri in sources.items():
201
- console.echo(f"{name}: {uri}")
202
- return
203
- plugins_info_file = Path(MULTITOOL_PLUGINS_DIRECTORY) / name / "apigee-cli.info"
204
- if not is_regular_file(plugins_info_file):
205
- return
206
- plugins_info = read_file_content(plugins_info_file, type="json")
207
- if show_commit_only:
208
- exit_quietly_if_git_not_installed()
209
- console.echo(
210
- Repo(Path(MULTITOOL_PLUGINS_DIRECTORY) / name).git.log(
211
- "--pretty=format:%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset",
212
- "-1",
213
- )
214
- )
215
- return
216
- if show_dependencies_only:
217
- if plugins_info.get("Requires"):
218
- console.echo(plugins_info.get("Requires"))
219
- return
220
- for k, v in plugins_info.items():
221
- console.echo(f"{k}: {v}")
222
-
223
-
224
- @plugins.command(help="Prune plugins with removed sources.")
225
- @common_silent_options
226
- @common_verbose_options
227
- def prune(silent, verbose, section="sources"):
228
- exit_quietly_if_git_not_installed()
229
- prune_unused_plugin_directories()
@@ -1,11 +0,0 @@
1
- requests>=2.28.1
2
- click>=8.1.3
3
- click-aliases>=1.0.1
4
- click-option-group>=0.5.5
5
- colorama>=0.4.6
6
- pyotp>=2.8.0
7
- tqdm>=4.64.1
8
- tabulate>=0.9.0
9
- pyjwt>=2.6.0
10
- python-gnupg>=0.4.9
11
- gitpython>=3.1.30