1818 is_regular_file , read_file_content )
1919from apigee .verbose import common_verbose_options
2020
21+ # ---- Global Variables ----
2122is_git_installed = False
2223plugins_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
2529try :
2630 from git import Repo
27-
2831 is_git_installed = True
2932except 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 )
145188def plugins ():
146189 pass
@@ -157,12 +200,12 @@ def plugins():
157200 show_default = True ,
158201)
159202def 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
175218def 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
238271def 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