Skip to content

Commit 10483cd

Browse files
committed
Refactor plugins, helpers, show(), and Git warning
1 parent e988002 commit 10483cd

File tree

1 file changed

+174
-141
lines changed

1 file changed

+174
-141
lines changed

apigee/plugins/commands.py

Lines changed: 174 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -18,129 +18,172 @@
1818
is_regular_file, read_file_content)
1919
from apigee.verbose import common_verbose_options
2020

21+
# ---- Global Variables ----
2122
is_git_installed = False
2223
plugins_command_help = (
23-
"[Experimental] Simple plugins manager for distributing commands.")
24+
"Originally meant to help Darumatic clients automate Apigee and API-related "
25+
"tasks, but available for anyone to use. Refer to "
26+
"https://github.com/mdelotavo/apigee-cli-plugins to learn how."
27+
)
2428

2529
try:
2630
from git import Repo
27-
2831
is_git_installed = True
2932
except ImportError:
30-
plugins_command_help = "[Unavailable - Git not found] Simple plugins manager for distributing commands."
31-
32-
33-
def chmod_directory(directory, mode):
34-
"""
35-
Recursively changes the permissions of a directory and its contents.
36-
37-
Reference: https://stackoverflow.com/a/58878271
38-
39-
Args:
40-
directory (str): Path to the directory.
41-
mode (int): Permissions to be set (e.g., 0o0700).
33+
plugins_command_help = (
34+
"Simple plugins manager for distributing commands. "
35+
"[Warning: Git must be installed to use plugin commands]")
4236

43-
"""
44-
for root, dirs, files in os.walk(directory):
45-
for dir in dirs:
46-
os.chmod(path.join(root, dir), mode)
47-
for file in files:
48-
os.chmod(path.join(root, file), mode)
4937

38+
# ---- Helper Classes ----
39+
class FileUtils:
40+
"""Internal helper class for file/directory operations."""
5041

51-
def clone_plugin_repositories(section="sources"):
52-
initialize_apigee_cli_plugins()
53-
config = load_plugin_config()
54-
if not config._sections:
55-
return
56-
sources = dict(config._sections[section])
57-
for name, uri in sources.items():
58-
dest = Path(APIGEE_CLI_PLUGINS_DIRECTORY) / name
59-
if is_directory(dest):
60-
continue
61-
try:
62-
console.echo(f"Installing {name}... ",
63-
line_ending="",
64-
should_flush=True)
65-
Repo.clone_from(uri, dest)
66-
console.echo("Done")
67-
except Exception as e:
68-
console.echo(e)
42+
@staticmethod
43+
def chmod_directory(directory, mode):
44+
"""Recursively change permissions of a directory and its contents."""
45+
for root, dirs, files in os.walk(directory):
46+
for d in dirs:
47+
os.chmod(path.join(root, d), mode)
48+
for f in files:
49+
os.chmod(path.join(root, f), mode)
6950

7051

71-
def exit_quietly_if_git_not_installed():
72-
if not is_git_installed:
73-
sys.exit(0)
52+
class GitUtils:
53+
"""Internal helper class for Git operations."""
7454

75-
76-
def initialize_and_save_plugin_config():
77-
initialize_apigee_cli_plugins()
78-
config = load_plugin_config()
79-
if not config._sections:
80-
return
55+
@staticmethod
56+
def exit_if_not_installed():
57+
if not is_git_installed:
58+
sys.exit(0)
8159

8260

83-
def initialize_apigee_cli_plugins():
84-
create_directory(APIGEE_CLI_PLUGINS_DIRECTORY)
85-
create_empty_file(APIGEE_CLI_PLUGINS_PATH)
86-
create_empty_file(APIGEE_CLI_PLUGINS_CONFIG_FILE)
61+
class PluginManager:
62+
"""Internal helper class for Apigee CLI plugin management."""
8763

64+
@staticmethod
65+
def initialize_plugins():
66+
create_directory(APIGEE_CLI_PLUGINS_DIRECTORY)
67+
create_empty_file(APIGEE_CLI_PLUGINS_PATH)
68+
create_empty_file(APIGEE_CLI_PLUGINS_CONFIG_FILE)
8869

89-
def load_plugin_config(config_file=APIGEE_CLI_PLUGINS_CONFIG_FILE):
90-
config = configparser.ConfigParser(allow_no_value=True)
91-
config.read(config_file)
92-
return config
70+
@staticmethod
71+
def load_config(config_file=APIGEE_CLI_PLUGINS_CONFIG_FILE):
72+
config = configparser.ConfigParser(allow_no_value=True)
73+
config.read(config_file)
74+
return config
9375

94-
95-
def prune_unused_plugin_directories(section="sources"):
96-
initialize_apigee_cli_plugins()
97-
config = load_plugin_config()
98-
if not config._sections:
99-
return
100-
sources = dict(config._sections[section])
101-
102-
def _func(path):
103-
if not is_directory(path):
76+
@staticmethod
77+
def clone_repositories(section="sources"):
78+
PluginManager.initialize_plugins()
79+
config = PluginManager.load_config()
80+
if not config._sections:
10481
return
105-
name = Path(path).stem
106-
if name in sources:
82+
sources = dict(config._sections[section])
83+
for name, uri in sources.items():
84+
dest = Path(APIGEE_CLI_PLUGINS_DIRECTORY) / name
85+
if is_directory(dest):
86+
continue
87+
try:
88+
console.echo(f"Installing {name}... ",
89+
line_ending="",
90+
should_flush=True)
91+
Repo.clone_from(uri, dest)
92+
console.echo("Done")
93+
except Exception as e:
94+
console.echo(e)
95+
96+
@staticmethod
97+
def prune_unused_directories(section="sources"):
98+
PluginManager.initialize_plugins()
99+
config = PluginManager.load_config()
100+
if not config._sections:
107101
return
108-
console.echo(f"Removing {name}... ", line_ending="", should_flush=True)
109-
plugin_directory = Path(APIGEE_CLI_PLUGINS_DIRECTORY) / name
110-
try:
111-
chmod_directory(str(Path(plugin_directory) / ".git"), stat.S_IRWXU)
112-
shutil.rmtree(plugin_directory)
113-
console.echo("Done")
114-
except Exception as e:
115-
console.echo(e)
116-
117-
return execute_function_on_directory_files(APIGEE_CLI_PLUGINS_DIRECTORY,
118-
_func,
119-
glob="[!.][!__]*")
120-
102+
sources = dict(config._sections[section])
121103

122-
def update_plugin_repositories():
104+
def _func(path_):
105+
if not is_directory(path_):
106+
return
107+
name = Path(path_).stem
108+
if name in sources:
109+
return
110+
console.echo(f"Removing {name}... ",
111+
line_ending="",
112+
should_flush=True)
113+
plugin_directory = Path(APIGEE_CLI_PLUGINS_DIRECTORY) / name
114+
try:
115+
FileUtils.chmod_directory(str(Path(plugin_directory) / ".git"),
116+
stat.S_IRWXU)
117+
shutil.rmtree(plugin_directory)
118+
console.echo("Done")
119+
except Exception as e:
120+
console.echo(e)
121+
122+
return execute_function_on_directory_files(APIGEE_CLI_PLUGINS_DIRECTORY,
123+
_func,
124+
glob="[!.][!__]*")
125+
126+
@staticmethod
127+
def update_repositories():
128+
129+
def _func(path_):
130+
if not is_directory(path_):
131+
return
132+
console.echo(f"Updating {Path(path_).stem}... ",
133+
line_ending="",
134+
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(APIGEE_CLI_PLUGINS_DIRECTORY,
145+
_func,
146+
glob="[!.][!__]*")
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(APIGEE_CLI_PLUGINS_DIRECTORY) / name / "apigee-cli.info"
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(APIGEE_CLI_PLUGINS_DIRECTORY) / name)
167+
console.echo(
168+
repo.git.log(
169+
"--pretty=format:%Cred%h%Creset -%C(yellow)%d%Creset %s "
170+
"%Cgreen(%cr) %C(bold blue)<%an>%Creset", "-1"))
123171

124-
def _func(path):
125-
if not is_directory(path):
126-
return
127-
console.echo(f"Updating {Path(path).stem}... ",
128-
line_ending="",
129-
should_flush=True)
130-
repo = Repo(path)
131-
if repo.bare:
132-
return
133-
try:
134-
repo.remotes["origin"].pull()
135-
console.echo("Done")
136-
except Exception as e:
137-
console.echo(e)
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)
138178

139-
return execute_function_on_directory_files(APIGEE_CLI_PLUGINS_DIRECTORY,
140-
_func,
141-
glob="[!.][!__]*")
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}")
142184

143185

186+
# ---- CLI Commands ----
144187
@click.group(help=plugins_command_help)
145188
def plugins():
146189
pass
@@ -157,12 +200,12 @@ def plugins():
157200
show_default=True,
158201
)
159202
def configure(silent, verbose, apply_changes):
160-
exit_quietly_if_git_not_installed()
161-
initialize_apigee_cli_plugins()
203+
GitUtils.exit_if_not_installed()
204+
PluginManager.initialize_plugins()
162205
click.edit(filename=APIGEE_CLI_PLUGINS_CONFIG_FILE)
163206
if apply_changes:
164-
clone_plugin_repositories()
165-
prune_unused_plugin_directories()
207+
PluginManager.clone_repositories()
208+
PluginManager.prune_unused_directories()
166209
else:
167210
console.echo("\n Run `apigee plugins update` to apply any changes,")
168211
console.echo(" or rerun `apigee plugins configure` with `-a`")
@@ -173,68 +216,58 @@ def configure(silent, verbose, apply_changes):
173216
@common_silent_options
174217
@common_verbose_options
175218
def update(silent, verbose, section="sources"):
176-
exit_quietly_if_git_not_installed()
177-
clone_plugin_repositories()
178-
update_plugin_repositories()
219+
GitUtils.exit_if_not_installed()
220+
PluginManager.clone_repositories()
221+
PluginManager.update_repositories()
179222

180223

181224
@plugins.command(help="Show plugins information.")
182225
@common_silent_options
183226
@common_verbose_options
184-
@click.option("-n", "--name", help="name of the plugins package")
227+
@click.option("-n", "--name", help="Name of the plugins package")
185228
@optgroup.group("Filter options",
186229
cls=MutuallyExclusiveOptionGroup,
187230
help="The filter options")
188231
@optgroup.option(
189232
"--show-commit-only/--no-show-commit-only",
190233
default=False,
191-
help="only print latest Git commit log",
234+
help="Only print latest Git commit log",
192235
)
193236
@optgroup.option(
194237
"--show-dependencies-only/--no-show-dependencies-only",
195238
default=False,
196-
help="only print list of required packages",
239+
help="Only print list of required packages",
197240
)
198-
def show(
199-
silent,
200-
verbose,
201-
name,
202-
section="sources",
203-
show_commit_only=False,
204-
show_dependencies_only=False,
205-
):
241+
def show(silent,
242+
verbose,
243+
name,
244+
section="sources",
245+
show_commit_only=False,
246+
show_dependencies_only=False):
247+
"""Show plugins sources, info, commits, or dependencies based on options."""
248+
206249
if not name:
207-
config = load_plugin_config()
208-
if not config._sections:
209-
return
210-
sources = dict(config._sections[section])
211-
for name, uri in sources.items():
212-
console.echo(f"{name}: {uri}")
250+
# List all plugin sources
251+
sources = PluginManager.list_sources(section)
252+
for plugin_name, uri in sources.items():
253+
console.echo(f"{plugin_name}: {uri}")
213254
return
214-
plugins_info_file = Path(
215-
APIGEE_CLI_PLUGINS_DIRECTORY) / name / "apigee-cli.info"
216-
if not is_regular_file(plugins_info_file):
255+
256+
plugins_info = PluginManager.get_plugin_info(name)
257+
if not plugins_info:
217258
return
218-
plugins_info = read_file_content(plugins_info_file, type="json")
259+
219260
if show_commit_only:
220-
exit_quietly_if_git_not_installed()
221-
console.echo(
222-
Repo(Path(APIGEE_CLI_PLUGINS_DIRECTORY) / name).git.log(
223-
"--pretty=format:%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset",
224-
"-1",
225-
))
226-
return
227-
if show_dependencies_only:
228-
if plugins_info.get("Requires"):
229-
console.echo(plugins_info.get("Requires"))
230-
return
231-
for k, v in plugins_info.items():
232-
console.echo(f"{k}: {v}")
261+
PluginManager.print_latest_commit(name)
262+
elif show_dependencies_only:
263+
PluginManager.print_dependencies(plugins_info)
264+
else:
265+
PluginManager.print_full_info(plugins_info)
233266

234267

235268
@plugins.command(help="Prune plugins with removed sources.")
236269
@common_silent_options
237270
@common_verbose_options
238271
def prune(silent, verbose, section="sources"):
239-
exit_quietly_if_git_not_installed()
240-
prune_unused_plugin_directories()
272+
GitUtils.exit_if_not_installed()
273+
PluginManager.prune_unused_directories()

0 commit comments

Comments
 (0)