Install a plugin from a local directory.
(
source_path: Path,
plugins_dir: Path,
editable: bool = False,
)
| 238 | |
| 239 | |
| 240 | def install_local_plugin( |
| 241 | source_path: Path, |
| 242 | plugins_dir: Path, |
| 243 | editable: bool = False, |
| 244 | ) -> None: |
| 245 | """Install a plugin from a local directory.""" |
| 246 | source_path = source_path.expanduser().resolve() |
| 247 | plugins_dir = plugins_dir.resolve() |
| 248 | |
| 249 | if not source_path.exists() or not source_path.is_dir(): |
| 250 | raise click.ClickException(f"Local plugin path does not exist: {source_path}") |
| 251 | |
| 252 | metadata = load_yaml_metadata(source_path) |
| 253 | plugin_name = metadata.get("name") |
| 254 | if not isinstance(plugin_name, str) or not plugin_name.strip(): |
| 255 | raise click.ClickException( |
| 256 | f"Local plugin {source_path} must contain metadata.yaml with a valid name" |
| 257 | ) |
| 258 | plugin_name = _validate_plugin_dir_name(plugin_name, source_path) |
| 259 | |
| 260 | target_path = plugins_dir / plugin_name |
| 261 | if target_path.exists(): |
| 262 | raise click.ClickException(f"Plugin {plugin_name} already exists") |
| 263 | |
| 264 | try: |
| 265 | plugins_dir.mkdir(parents=True, exist_ok=True) |
| 266 | if editable: |
| 267 | try: |
| 268 | target_path.symlink_to(source_path, target_is_directory=True) |
| 269 | except OSError as e: |
| 270 | raise click.ClickException( |
| 271 | f"Failed to create symlink for editable install: {e}. " |
| 272 | "On Windows, you may need to run as Administrator or enable Developer Mode." |
| 273 | ) from e |
| 274 | else: |
| 275 | _copy_local_plugin(source_path, plugins_dir, target_path) |
| 276 | click.echo(f"Plugin {plugin_name} installed successfully from {source_path}") |
| 277 | except FileExistsError: |
| 278 | raise click.ClickException(f"Plugin {plugin_name} already exists") from None |
| 279 | except click.ClickException: |
| 280 | raise |
| 281 | except Exception as e: |
| 282 | if editable and target_path.is_symlink(): |
| 283 | _cleanup_local_plugin_target(target_path) |
| 284 | raise click.ClickException( |
| 285 | f"Error installing local plugin {plugin_name}: {e}" |
| 286 | ) from e |
| 287 | |
| 288 | |
| 289 | def manage_plugin( |
no test coverage detected