swisscli 0.1.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.
@@ -0,0 +1,7 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *$py.class
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .venv/
@@ -0,0 +1,73 @@
1
+ # swisscli — AGENTS.md
2
+
3
+ ## Build, install, test
4
+
5
+ ```bash
6
+ pip install -e . # editable install
7
+ python -m build # sdist + wheel
8
+ python -m build && pip install dist/swisscli-0.1.0-py3-none-any.whl --force-reinstall
9
+ swisscli --help # verify
10
+ ```
11
+
12
+ No test framework, no lint, no typecheck — manual verification only.
13
+
14
+ ## Architecture
15
+
16
+ - **`cli.py`** — single Click command with `help_option_names=[]` and `ignore_unknown_options=True`. All args via `nargs=-1`. `--help`/`--version` handled in user code (lines 25-55), not by Click.
17
+ - **`plugin.py`** — `Plugin` ABC, `Subcommand` (prefix/suffix args), `ArgMapper` (flag aliases), `PluginRegistry` (singleton dict keyed by `name`).
18
+ - **`loader.py`** — `discover_plugins()` uses `pkgutil.walk_packages` over `swisscli.plugins`. Every subpackage is scanned. Any module with a top-level `plugin` attribute is registered.
19
+ - **`__init__.py`** — version from `importlib.metadata` with fallback to `"0.1.0"`.
20
+
21
+ ## Discovery & registration
22
+
23
+ - Plugin modules go under `src/swisscli/plugins/<category>/<tool>.py`.
24
+ - Every plugin module **must** export `plugin = ClassName()` at module level — this is the sole discovery contract.
25
+ - Categories are not hardcoded; they come from each plugin's `category` property.
26
+ - Existing categories: `web-cli` (curl, wget), `ssl` (openssl, ssh-keygen), `package` (apt, dnf, yum, dpkg, rpm).
27
+
28
+ ## Two plugin patterns
29
+
30
+ **Simple flag mapping** — override `arg_mapper` property, args pass through:
31
+ ```python
32
+ class CurlPlugin(Plugin):
33
+ name = "curl"
34
+ category = "web-cli"
35
+ @property
36
+ def arg_mapper(self):
37
+ return ArgMapper({"--insecure": "-k"})
38
+ plugin = CurlPlugin()
39
+ ```
40
+
41
+ **Subcommand-based** — override `subcommands` property. Each `Subcommand` has `prefix_args` (inserted between tool name and user args) and optional `suffix_args` / `arg_mapper`:
42
+ ```python
43
+ class OpenSslPlugin(Plugin):
44
+ name = "openssl"
45
+ category = "ssl"
46
+ @property
47
+ def subcommands(self):
48
+ return {
49
+ "show": Subcommand(
50
+ name="show", description="Show certificate details",
51
+ prefix_args=["x509", "-in"], suffix_args=["-text", "-noout"],
52
+ ),
53
+ }
54
+ plugin = OpenSslPlugin()
55
+ ```
56
+
57
+ ## Fallback
58
+
59
+ If `shutil.which(tool_name)` fails, `execute()` scans `PluginRegistry.all()` for another plugin in the **same `category`** that is available. First match wins (insertion order). Prints fallback notice to stderr.
60
+
61
+ Example: on Debian, `swisscli dnf install curl` → `'dnf' not found, falling back to 'apt'`.
62
+
63
+ ## Help system
64
+
65
+ - `swisscli --help` — tools grouped by category
66
+ - `swisscli <tool> --help` — subcommands + arg mappings
67
+ - `swisscli <tool> <subcommand> --help` — subcommand details + "Runs:" command preview
68
+ - `--help` is handled manually in `cli.py`, not by Click. Unknown options pass through silently.
69
+
70
+ ## Style
71
+
72
+ - No docstrings or comments in code.
73
+ - `from __future__ import annotations` at top of `plugin.py`.
@@ -0,0 +1,106 @@
1
+ Metadata-Version: 2.4
2
+ Name: swisscli
3
+ Version: 0.1.0
4
+ Summary: A plugin-based CLI wrapper ecosystem for common command-line tools
5
+ Project-URL: Homepage, https://github.com/yourusername/swisscli
6
+ Author-email: Your Name <you@example.com>
7
+ License: MIT
8
+ Requires-Python: >=3.9
9
+ Requires-Dist: click>=8.0
10
+ Description-Content-Type: text/markdown
11
+
12
+ # swisscli
13
+
14
+ A plugin-based CLI wrapper ecosystem for common command-line tools. swisscli wraps native tools like `curl`, `wget`, `openssl`, `ssh-keygen`, `apt`, `dnf`, `yum`, `dpkg`, and `rpm`, providing consistent argument naming, subcommand interfaces, and automatic fallback between tools in the same category.
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ git clone https://github.com/agonzalezrh/swisscli.git
20
+ cd swisscli
21
+ pip install .
22
+ ```
23
+
24
+ Or install directly:
25
+
26
+ ```bash
27
+ pip install swisscli
28
+ ```
29
+
30
+ ## Usage
31
+
32
+ ```bash
33
+ swisscli --help # list tools grouped by category
34
+ swisscli --version # show version
35
+ swisscli <tool> --help # tool-specific help
36
+ swisscli <tool> <subcommand> --help # subcommand details
37
+ swisscli <tool> [ARGS]... # run a tool
38
+ ```
39
+
40
+ ## Available tools
41
+
42
+ ### web-cli
43
+
44
+ | Tool | Description |
45
+ |------|-------------|
46
+ | `curl` | HTTP requests with long-flag aliases (`--insecure` → `-k`, `--silent` → `-s`, `--location` → `-L`, etc.) |
47
+ | `wget` | File downloads with long-flag aliases (`--insecure` → `--no-check-certificate`, `--quiet` → `-q`, etc.) |
48
+
49
+ ```bash
50
+ swisscli curl --insecure --location https://example.com
51
+ swisscli wget --output file.zip https://example.com/file.zip
52
+ ```
53
+
54
+ ### ssl
55
+
56
+ | Tool | Subcommands | Description |
57
+ |------|-------------|-------------|
58
+ | `openssl` | `show`, `generate` | OpenSSL certificate toolkit |
59
+ | `ssh-keygen` | `show`, `generate` | SSH key management tool |
60
+
61
+ ```bash
62
+ swisscli openssl show cert.pem
63
+ swisscli openssl generate --days 730 --out mycert.pem
64
+ swisscli ssh-keygen show ~/.ssh/id_rsa
65
+ swisscli ssh-keygen generate --type ed25519 --file mykey
66
+ ```
67
+
68
+ ### package
69
+
70
+ | Tool | Subcommands | Description |
71
+ |------|-------------|-------------|
72
+ | `apt` | `install`, `remove`, `search`, `list` | Debian/Ubuntu package manager |
73
+ | `dnf` | `install`, `remove`, `search`, `list` | RPM package manager (modern) |
74
+ | `yum` | `install`, `remove`, `search`, `list` | RPM package manager (legacy) |
75
+ | `dpkg` | `list`, `info`, `search`, `contents` | Debian low-level package manager |
76
+ | `rpm` | `list`, `info`, `search`, `files` | RPM low-level package manager |
77
+
78
+ ```bash
79
+ swisscli apt install curl
80
+ swisscli apt remove --purge firefox
81
+ swisscli apt search build-essential
82
+ swisscli dpkg list
83
+ swisscli dpkg info bash
84
+ swisscli rpm list
85
+ swisscli rpm files coreutils
86
+ ```
87
+
88
+ ## Fallback behavior
89
+
90
+ If a tool binary is not found on the system, swisscli automatically falls back to another tool in the same category. For example, running `swisscli dnf install curl` on a Debian system will fall back to `apt install curl`. The fallback notice is printed to stderr.
91
+
92
+ ## Adding your own plugin
93
+
94
+ Create a file at `src/swisscli/plugins/<category>/<tool>.py`. Define a `Plugin` subclass with a `name`, `description`, and `category`. Export a module-level `plugin = MyPlugin()` instance — auto-discovery picks it up on next run.
95
+
96
+ Two patterns:
97
+ - **Simple flag mapping** — override `arg_mapper` for long-flag aliases
98
+ - **Subcommand-based** — override `subcommands` dict with `Subcommand` objects (prefix args, suffix args, optional arg mapper)
99
+
100
+ ## Architecture
101
+
102
+ - **Plugin** — base class wrapping a CLI tool (argument mapping, execution, fallback)
103
+ - **ArgMapper** — translates user-friendly long flags to native tool flags
104
+ - **Subcommand** — defines prefix/suffix args injected between tool name and user args
105
+ - **PluginRegistry** — singleton registry discovered automatically via `pkgutil.walk_packages`
106
+ - **Categories** — plugins grouped by domain; fallback operates within the same category
@@ -0,0 +1,95 @@
1
+ # swisscli
2
+
3
+ A plugin-based CLI wrapper ecosystem for common command-line tools. swisscli wraps native tools like `curl`, `wget`, `openssl`, `ssh-keygen`, `apt`, `dnf`, `yum`, `dpkg`, and `rpm`, providing consistent argument naming, subcommand interfaces, and automatic fallback between tools in the same category.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ git clone https://github.com/agonzalezrh/swisscli.git
9
+ cd swisscli
10
+ pip install .
11
+ ```
12
+
13
+ Or install directly:
14
+
15
+ ```bash
16
+ pip install swisscli
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ ```bash
22
+ swisscli --help # list tools grouped by category
23
+ swisscli --version # show version
24
+ swisscli <tool> --help # tool-specific help
25
+ swisscli <tool> <subcommand> --help # subcommand details
26
+ swisscli <tool> [ARGS]... # run a tool
27
+ ```
28
+
29
+ ## Available tools
30
+
31
+ ### web-cli
32
+
33
+ | Tool | Description |
34
+ |------|-------------|
35
+ | `curl` | HTTP requests with long-flag aliases (`--insecure` → `-k`, `--silent` → `-s`, `--location` → `-L`, etc.) |
36
+ | `wget` | File downloads with long-flag aliases (`--insecure` → `--no-check-certificate`, `--quiet` → `-q`, etc.) |
37
+
38
+ ```bash
39
+ swisscli curl --insecure --location https://example.com
40
+ swisscli wget --output file.zip https://example.com/file.zip
41
+ ```
42
+
43
+ ### ssl
44
+
45
+ | Tool | Subcommands | Description |
46
+ |------|-------------|-------------|
47
+ | `openssl` | `show`, `generate` | OpenSSL certificate toolkit |
48
+ | `ssh-keygen` | `show`, `generate` | SSH key management tool |
49
+
50
+ ```bash
51
+ swisscli openssl show cert.pem
52
+ swisscli openssl generate --days 730 --out mycert.pem
53
+ swisscli ssh-keygen show ~/.ssh/id_rsa
54
+ swisscli ssh-keygen generate --type ed25519 --file mykey
55
+ ```
56
+
57
+ ### package
58
+
59
+ | Tool | Subcommands | Description |
60
+ |------|-------------|-------------|
61
+ | `apt` | `install`, `remove`, `search`, `list` | Debian/Ubuntu package manager |
62
+ | `dnf` | `install`, `remove`, `search`, `list` | RPM package manager (modern) |
63
+ | `yum` | `install`, `remove`, `search`, `list` | RPM package manager (legacy) |
64
+ | `dpkg` | `list`, `info`, `search`, `contents` | Debian low-level package manager |
65
+ | `rpm` | `list`, `info`, `search`, `files` | RPM low-level package manager |
66
+
67
+ ```bash
68
+ swisscli apt install curl
69
+ swisscli apt remove --purge firefox
70
+ swisscli apt search build-essential
71
+ swisscli dpkg list
72
+ swisscli dpkg info bash
73
+ swisscli rpm list
74
+ swisscli rpm files coreutils
75
+ ```
76
+
77
+ ## Fallback behavior
78
+
79
+ If a tool binary is not found on the system, swisscli automatically falls back to another tool in the same category. For example, running `swisscli dnf install curl` on a Debian system will fall back to `apt install curl`. The fallback notice is printed to stderr.
80
+
81
+ ## Adding your own plugin
82
+
83
+ Create a file at `src/swisscli/plugins/<category>/<tool>.py`. Define a `Plugin` subclass with a `name`, `description`, and `category`. Export a module-level `plugin = MyPlugin()` instance — auto-discovery picks it up on next run.
84
+
85
+ Two patterns:
86
+ - **Simple flag mapping** — override `arg_mapper` for long-flag aliases
87
+ - **Subcommand-based** — override `subcommands` dict with `Subcommand` objects (prefix args, suffix args, optional arg mapper)
88
+
89
+ ## Architecture
90
+
91
+ - **Plugin** — base class wrapping a CLI tool (argument mapping, execution, fallback)
92
+ - **ArgMapper** — translates user-friendly long flags to native tool flags
93
+ - **Subcommand** — defines prefix/suffix args injected between tool name and user args
94
+ - **PluginRegistry** — singleton registry discovered automatically via `pkgutil.walk_packages`
95
+ - **Categories** — plugins grouped by domain; fallback operates within the same category
@@ -0,0 +1,23 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "swisscli"
7
+ version = "0.1.0"
8
+ description = "A plugin-based CLI wrapper ecosystem for common command-line tools"
9
+ readme = "README.md"
10
+ license = {text = "MIT"}
11
+ authors = [
12
+ {name = "Your Name", email = "you@example.com"},
13
+ ]
14
+ requires-python = ">=3.9"
15
+ dependencies = [
16
+ "click>=8.0",
17
+ ]
18
+
19
+ [project.scripts]
20
+ swisscli = "swisscli.cli:main"
21
+
22
+ [project.urls]
23
+ Homepage = "https://github.com/yourusername/swisscli"
@@ -0,0 +1,5 @@
1
+ try:
2
+ from importlib.metadata import version as _version
3
+ __version__ = _version("swisscli")
4
+ except Exception:
5
+ __version__ = "0.1.0"
@@ -0,0 +1,4 @@
1
+ from .cli import main
2
+
3
+ if __name__ == "__main__":
4
+ main()
@@ -0,0 +1,74 @@
1
+ import sys
2
+
3
+ import click
4
+
5
+ from . import __version__
6
+ from .loader import discover_plugins
7
+ from .plugin import PluginRegistry
8
+
9
+
10
+ @click.command(context_settings=dict(
11
+ help_option_names=[],
12
+ ignore_unknown_options=True,
13
+ ))
14
+ @click.argument("args", nargs=-1)
15
+ def main(args):
16
+ """swisscli - CLI wrapper ecosystem."""
17
+
18
+ discover_plugins()
19
+
20
+ if not args:
21
+ click.echo("Usage: swisscli <tool> [ARGS]...")
22
+ click.echo(" swisscli --help")
23
+ sys.exit(1)
24
+
25
+ if args[0] in ("--help", "-h"):
26
+ _show_help()
27
+ return
28
+
29
+ if args[0] in ("--version", "-V"):
30
+ click.echo(f"swisscli version {__version__}")
31
+ return
32
+
33
+ tool = args[0]
34
+ tool_args = list(args[1:])
35
+
36
+ if tool_args and tool_args[0] in ("--help", "-h"):
37
+ plugin = PluginRegistry.get(tool)
38
+ if plugin:
39
+ click.echo(plugin.format_help())
40
+ else:
41
+ click.echo(f"Unknown tool: {tool}", err=True)
42
+ return
43
+
44
+ plugin = PluginRegistry.get(tool)
45
+ if plugin is None:
46
+ click.echo(f"Error: unknown tool '{tool}'", err=True)
47
+ click.echo("Run 'swisscli --help' for available tools.")
48
+ sys.exit(1)
49
+
50
+ if tool_args and tool_args[0] in plugin.subcommands:
51
+ sub_name = tool_args[0]
52
+ sub_args = tool_args[1:]
53
+ if sub_args and sub_args[0] in ("--help", "-h"):
54
+ click.echo(plugin.format_subcommand_help(plugin.subcommands[sub_name]))
55
+ return
56
+
57
+ sys.exit(plugin.execute(tool_args))
58
+
59
+
60
+ def _show_help():
61
+ by_category = PluginRegistry.by_category()
62
+
63
+ click.echo("Usage: swisscli <tool> [ARGS]...")
64
+ click.echo()
65
+ click.echo("Available tools:")
66
+ click.echo()
67
+ for category in sorted(by_category):
68
+ tools = by_category[category]
69
+ click.echo(f" {category}:")
70
+ for name in sorted(tools):
71
+ plugin = tools[name]
72
+ click.echo(f" {name:<12} {plugin.description}")
73
+ click.echo()
74
+ click.echo("Run 'swisscli <tool> --help' for tool-specific help.")
@@ -0,0 +1,30 @@
1
+ import importlib
2
+ import pkgutil
3
+ import warnings
4
+
5
+ from .plugin import PluginRegistry
6
+
7
+
8
+ def _import_module(modname: str):
9
+ try:
10
+ return importlib.import_module(modname)
11
+ except Exception as exc:
12
+ warnings.warn(f"Failed to load plugin module '{modname}': {exc}")
13
+ return None
14
+
15
+
16
+ def discover_plugins() -> None:
17
+ import swisscli.plugins as plugins_pkg
18
+
19
+ prefix = plugins_pkg.__name__ + "."
20
+ seen = set()
21
+
22
+ for importer, modname, ispkg in pkgutil.walk_packages(
23
+ plugins_pkg.__path__, prefix=prefix
24
+ ):
25
+ if ispkg or modname in seen:
26
+ continue
27
+ seen.add(modname)
28
+ mod = _import_module(modname)
29
+ if mod is not None and hasattr(mod, "plugin"):
30
+ PluginRegistry.register(mod.plugin)
@@ -0,0 +1,160 @@
1
+ from __future__ import annotations
2
+
3
+ import shutil
4
+ import subprocess
5
+ import sys
6
+ from abc import ABC, abstractmethod
7
+ from typing import Dict, List, Optional
8
+
9
+ import click
10
+
11
+
12
+ class ArgMapper:
13
+ def __init__(self, mapping: Dict[str, str]):
14
+ self._mapping = mapping
15
+
16
+ def translate(self, args: List[str]) -> List[str]:
17
+ result = []
18
+ for arg in args:
19
+ result.append(self._mapping.get(arg, arg))
20
+ return result
21
+
22
+
23
+ class Subcommand:
24
+ def __init__(
25
+ self,
26
+ name: str,
27
+ description: str,
28
+ prefix_args: Optional[List[str]] = None,
29
+ suffix_args: Optional[List[str]] = None,
30
+ arg_mapper: Optional[ArgMapper] = None,
31
+ ):
32
+ self.name = name
33
+ self.description = description
34
+ self.prefix_args = prefix_args or []
35
+ self.suffix_args = suffix_args or []
36
+ self.arg_mapper = arg_mapper
37
+
38
+ def translate_args(self, args: List[str]) -> List[str]:
39
+ if self.arg_mapper:
40
+ return self.arg_mapper.translate(args)
41
+ return list(args)
42
+
43
+ def build_command(self, tool_name: str, args: List[str]) -> List[str]:
44
+ return [tool_name, *self.prefix_args, *self.translate_args(args), *self.suffix_args]
45
+
46
+
47
+ class Plugin(ABC):
48
+
49
+ @property
50
+ @abstractmethod
51
+ def name(self) -> str:
52
+ ...
53
+
54
+ @property
55
+ @abstractmethod
56
+ def description(self) -> str:
57
+ ...
58
+
59
+ @property
60
+ def category(self) -> str:
61
+ return "general"
62
+
63
+ @property
64
+ def arg_mapper(self) -> Optional[ArgMapper]:
65
+ return None
66
+
67
+ @property
68
+ def subcommands(self) -> Dict[str, Subcommand]:
69
+ return {}
70
+
71
+ def translate_args(self, args: List[str]) -> List[str]:
72
+ if self.arg_mapper:
73
+ return self.arg_mapper.translate(args)
74
+ return list(args)
75
+
76
+ def build_command(self, args: List[str]) -> List[str]:
77
+ return [self.name, *self.translate_args(args)]
78
+
79
+ def _is_available(self) -> bool:
80
+ return shutil.which(self.name) is not None
81
+
82
+ def _get_fallback(self) -> Optional[Plugin]:
83
+ for plugin in PluginRegistry.all().values():
84
+ if plugin is not self and plugin.category == self.category and plugin._is_available():
85
+ return plugin
86
+ return None
87
+
88
+ def execute(self, args: List[str]) -> int:
89
+ if not self._is_available():
90
+ fallback = self._get_fallback()
91
+ if fallback is not None:
92
+ click.echo(
93
+ f"'{self.name}' not found, falling back to '{fallback.name}'",
94
+ err=True,
95
+ )
96
+ return fallback.execute(args)
97
+ click.echo(
98
+ f"Error: '{self.name}' not found and no fallback available in category '{self.category}'.",
99
+ err=True,
100
+ )
101
+ return 1
102
+
103
+ if args and args[0] in self.subcommands:
104
+ sub = self.subcommands[args[0]]
105
+ cmd = sub.build_command(self.name, args[1:])
106
+ return subprocess.call(cmd)
107
+
108
+ cmd = self.build_command(args)
109
+ return subprocess.call(cmd)
110
+
111
+ def format_help(self) -> str:
112
+ lines = [f"{self.name}: {self.description}", ""]
113
+ if self.subcommands:
114
+ lines.append("Subcommands:")
115
+ for name, sub in self.subcommands.items():
116
+ lines.append(f" {name:<12} {sub.description}")
117
+ lines.append("")
118
+ if self.arg_mapper and self.arg_mapper._mapping:
119
+ lines.append("Argument mappings:")
120
+ for alias, native in self.arg_mapper._mapping.items():
121
+ lines.append(f" {alias} \u2192 {native}")
122
+ lines.append("")
123
+ lines.append(f"Category: {self.category}")
124
+ return "\n".join(lines)
125
+
126
+ def format_subcommand_help(self, sub: Subcommand) -> str:
127
+ lines = [f"{self.name} {sub.name}: {sub.description}", ""]
128
+ if sub.arg_mapper and sub.arg_mapper._mapping:
129
+ lines.append("Argument mappings:")
130
+ for alias, native in sub.arg_mapper._mapping.items():
131
+ lines.append(f" {alias} \u2192 {native}")
132
+ lines.append("")
133
+ lines.append(f"Runs: {' '.join(sub.build_command(self.name, ['<args>']))}")
134
+ return "\n".join(lines)
135
+
136
+
137
+ class PluginRegistry:
138
+ _plugins: Dict[str, Plugin] = {}
139
+
140
+ @classmethod
141
+ def register(cls, plugin: Plugin) -> None:
142
+ cls._plugins[plugin.name] = plugin
143
+
144
+ @classmethod
145
+ def get(cls, name: str) -> Optional[Plugin]:
146
+ return cls._plugins.get(name)
147
+
148
+ @classmethod
149
+ def all(cls) -> Dict[str, Plugin]:
150
+ return dict(cls._plugins)
151
+
152
+ @classmethod
153
+ def by_category(cls) -> Dict[str, Dict[str, Plugin]]:
154
+ result: Dict[str, Dict[str, Plugin]] = {}
155
+ for name, plugin in cls._plugins.items():
156
+ cat = plugin.category
157
+ if cat not in result:
158
+ result[cat] = {}
159
+ result[cat][name] = plugin
160
+ return result
File without changes
@@ -0,0 +1,47 @@
1
+ from swisscli.plugin import ArgMapper, Plugin, Subcommand
2
+
3
+
4
+ class AptPlugin(Plugin):
5
+ name = "apt"
6
+ description = "Debian/Ubuntu package manager"
7
+ category = "package"
8
+
9
+ @property
10
+ def subcommands(self):
11
+ return {
12
+ "install": Subcommand(
13
+ name="install",
14
+ description="Install packages",
15
+ prefix_args=["install"],
16
+ arg_mapper=ArgMapper({
17
+ "--yes": "-y",
18
+ "--assume-yes": "-y",
19
+ "--no-install-recommends": "--no-install-recommends",
20
+ "--reinstall": "--reinstall",
21
+ }),
22
+ ),
23
+ "remove": Subcommand(
24
+ name="remove",
25
+ description="Remove packages",
26
+ prefix_args=["remove"],
27
+ arg_mapper=ArgMapper({
28
+ "--yes": "-y",
29
+ "--assume-yes": "-y",
30
+ "--purge": "--purge",
31
+ "--autoremove": "--autoremove",
32
+ }),
33
+ ),
34
+ "search": Subcommand(
35
+ name="search",
36
+ description="Search for packages",
37
+ prefix_args=["search"],
38
+ ),
39
+ "list": Subcommand(
40
+ name="list",
41
+ description="List installed packages",
42
+ prefix_args=["list", "--installed"],
43
+ ),
44
+ }
45
+
46
+
47
+ plugin = AptPlugin()
@@ -0,0 +1,43 @@
1
+ from swisscli.plugin import ArgMapper, Plugin, Subcommand
2
+
3
+
4
+ class DnfPlugin(Plugin):
5
+ name = "dnf"
6
+ description = "RPM package manager (modern)"
7
+ category = "package"
8
+
9
+ @property
10
+ def subcommands(self):
11
+ return {
12
+ "install": Subcommand(
13
+ name="install",
14
+ description="Install packages",
15
+ prefix_args=["install"],
16
+ arg_mapper=ArgMapper({
17
+ "--yes": "-y",
18
+ "--assumeyes": "-y",
19
+ }),
20
+ ),
21
+ "remove": Subcommand(
22
+ name="remove",
23
+ description="Remove packages",
24
+ prefix_args=["remove"],
25
+ arg_mapper=ArgMapper({
26
+ "--yes": "-y",
27
+ "--assumeyes": "-y",
28
+ }),
29
+ ),
30
+ "search": Subcommand(
31
+ name="search",
32
+ description="Search for packages",
33
+ prefix_args=["search"],
34
+ ),
35
+ "list": Subcommand(
36
+ name="list",
37
+ description="List installed packages",
38
+ prefix_args=["list", "--installed"],
39
+ ),
40
+ }
41
+
42
+
43
+ plugin = DnfPlugin()
@@ -0,0 +1,35 @@
1
+ from swisscli.plugin import Plugin, Subcommand
2
+
3
+
4
+ class DpkgPlugin(Plugin):
5
+ name = "dpkg"
6
+ description = "Debian package manager (low-level)"
7
+ category = "package"
8
+
9
+ @property
10
+ def subcommands(self):
11
+ return {
12
+ "list": Subcommand(
13
+ name="list",
14
+ description="List installed packages",
15
+ prefix_args=["-l"],
16
+ ),
17
+ "info": Subcommand(
18
+ name="info",
19
+ description="Show package info",
20
+ prefix_args=["-s"],
21
+ ),
22
+ "search": Subcommand(
23
+ name="search",
24
+ description="Search which package owns a file",
25
+ prefix_args=["-S"],
26
+ ),
27
+ "contents": Subcommand(
28
+ name="contents",
29
+ description="List files installed by a package",
30
+ prefix_args=["-L"],
31
+ ),
32
+ }
33
+
34
+
35
+ plugin = DpkgPlugin()
@@ -0,0 +1,35 @@
1
+ from swisscli.plugin import Plugin, Subcommand
2
+
3
+
4
+ class RpmPlugin(Plugin):
5
+ name = "rpm"
6
+ description = "RPM package manager (low-level)"
7
+ category = "package"
8
+
9
+ @property
10
+ def subcommands(self):
11
+ return {
12
+ "list": Subcommand(
13
+ name="list",
14
+ description="List installed packages",
15
+ prefix_args=["-qa"],
16
+ ),
17
+ "info": Subcommand(
18
+ name="info",
19
+ description="Show package info",
20
+ prefix_args=["-qi"],
21
+ ),
22
+ "search": Subcommand(
23
+ name="search",
24
+ description="Search installed packages",
25
+ prefix_args=["-q"],
26
+ ),
27
+ "files": Subcommand(
28
+ name="files",
29
+ description="List files in a package",
30
+ prefix_args=["-ql"],
31
+ ),
32
+ }
33
+
34
+
35
+ plugin = RpmPlugin()
@@ -0,0 +1,43 @@
1
+ from swisscli.plugin import ArgMapper, Plugin, Subcommand
2
+
3
+
4
+ class YumPlugin(Plugin):
5
+ name = "yum"
6
+ description = "RPM package manager (legacy)"
7
+ category = "package"
8
+
9
+ @property
10
+ def subcommands(self):
11
+ return {
12
+ "install": Subcommand(
13
+ name="install",
14
+ description="Install packages",
15
+ prefix_args=["install"],
16
+ arg_mapper=ArgMapper({
17
+ "--yes": "-y",
18
+ "--assumeyes": "-y",
19
+ }),
20
+ ),
21
+ "remove": Subcommand(
22
+ name="remove",
23
+ description="Remove packages",
24
+ prefix_args=["remove"],
25
+ arg_mapper=ArgMapper({
26
+ "--yes": "-y",
27
+ "--assumeyes": "-y",
28
+ }),
29
+ ),
30
+ "search": Subcommand(
31
+ name="search",
32
+ description="Search for packages",
33
+ prefix_args=["search"],
34
+ ),
35
+ "list": Subcommand(
36
+ name="list",
37
+ description="List installed packages",
38
+ prefix_args=["list", "installed"],
39
+ ),
40
+ }
41
+
42
+
43
+ plugin = YumPlugin()
File without changes
@@ -0,0 +1,37 @@
1
+ from swisscli.plugin import ArgMapper, Plugin, Subcommand
2
+
3
+
4
+ class OpenSslPlugin(Plugin):
5
+ name = "openssl"
6
+ description = "OpenSSL certificate toolkit"
7
+ category = "ssl"
8
+
9
+ @property
10
+ def subcommands(self):
11
+ return {
12
+ "show": Subcommand(
13
+ name="show",
14
+ description="Show certificate details",
15
+ prefix_args=["x509", "-in"],
16
+ suffix_args=["-text", "-noout"],
17
+ ),
18
+ "generate": Subcommand(
19
+ name="generate",
20
+ description="Generate a self-signed certificate",
21
+ prefix_args=[
22
+ "req", "-x509", "-newkey", "rsa:4096",
23
+ "-keyout", "key.pem", "-out", "cert.pem",
24
+ "-days", "365", "-nodes",
25
+ "-subj", "/CN=SelfSigned",
26
+ ],
27
+ arg_mapper=ArgMapper({
28
+ "--days": "-days",
29
+ "--keyout": "-keyout",
30
+ "--out": "-out",
31
+ "--subj": "-subj",
32
+ }),
33
+ ),
34
+ }
35
+
36
+
37
+ plugin = OpenSslPlugin()
@@ -0,0 +1,31 @@
1
+ from swisscli.plugin import ArgMapper, Plugin, Subcommand
2
+
3
+
4
+ class SshKeygenPlugin(Plugin):
5
+ name = "ssh-keygen"
6
+ description = "SSH key management tool"
7
+ category = "ssl"
8
+
9
+ @property
10
+ def subcommands(self):
11
+ return {
12
+ "show": Subcommand(
13
+ name="show",
14
+ description="Show SSH key fingerprint",
15
+ prefix_args=["-l", "-f"],
16
+ ),
17
+ "generate": Subcommand(
18
+ name="generate",
19
+ description="Generate an SSH key pair",
20
+ prefix_args=["-t", "rsa", "-b", "4096", "-f", "key", "-N", ""],
21
+ arg_mapper=ArgMapper({
22
+ "--type": "-t",
23
+ "--bits": "-b",
24
+ "--file": "-f",
25
+ "--comment": "-C",
26
+ }),
27
+ ),
28
+ }
29
+
30
+
31
+ plugin = SshKeygenPlugin()
File without changes
@@ -0,0 +1,21 @@
1
+ from swisscli.plugin import ArgMapper, Plugin
2
+
3
+
4
+ class CurlPlugin(Plugin):
5
+ name = "curl"
6
+ description = "Wrapper around curl for HTTP requests"
7
+ category = "web-cli"
8
+
9
+ @property
10
+ def arg_mapper(self):
11
+ return ArgMapper({
12
+ "--insecure": "-k",
13
+ "--silent": "-s",
14
+ "--location": "-L",
15
+ "--output": "-o",
16
+ "--header": "-H",
17
+ "--data": "-d",
18
+ })
19
+
20
+
21
+ plugin = CurlPlugin()
@@ -0,0 +1,19 @@
1
+ from swisscli.plugin import ArgMapper, Plugin
2
+
3
+
4
+ class WgetPlugin(Plugin):
5
+ name = "wget"
6
+ description = "Wrapper around wget for downloading files"
7
+ category = "web-cli"
8
+
9
+ @property
10
+ def arg_mapper(self):
11
+ return ArgMapper({
12
+ "--insecure": "--no-check-certificate",
13
+ "--quiet": "-q",
14
+ "--output": "-O",
15
+ "--timeout": "-T",
16
+ })
17
+
18
+
19
+ plugin = WgetPlugin()