pacman-apt-wrapper 0.1.0__py3-none-any.whl
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.
- pacman_apt/__init__.py +4 -0
- pacman_apt/cli.py +152 -0
- pacman_apt_wrapper-0.1.0.dist-info/METADATA +102 -0
- pacman_apt_wrapper-0.1.0.dist-info/RECORD +8 -0
- pacman_apt_wrapper-0.1.0.dist-info/WHEEL +5 -0
- pacman_apt_wrapper-0.1.0.dist-info/entry_points.txt +3 -0
- pacman_apt_wrapper-0.1.0.dist-info/licenses/LICENSE +21 -0
- pacman_apt_wrapper-0.1.0.dist-info/top_level.txt +1 -0
pacman_apt/__init__.py
ADDED
pacman_apt/cli.py
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
pacman (Debian/Ubuntu wrapper)
|
|
4
|
+
|
|
5
|
+
Implements a small subset of pacman-style flags by translating to:
|
|
6
|
+
- apt-get (stable scripting)
|
|
7
|
+
- apt-cache (search/show)
|
|
8
|
+
- dpkg-query (installed list)
|
|
9
|
+
|
|
10
|
+
Supported:
|
|
11
|
+
pacman -Syu
|
|
12
|
+
pacman -S <pkg...>
|
|
13
|
+
pacman -R <pkg...>
|
|
14
|
+
pacman -Rns <pkg...>
|
|
15
|
+
pacman -Ss <query...>
|
|
16
|
+
pacman -Qi <pkg...>
|
|
17
|
+
pacman -Q
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import os
|
|
23
|
+
import shlex
|
|
24
|
+
import shutil
|
|
25
|
+
import subprocess
|
|
26
|
+
import sys
|
|
27
|
+
from typing import List, Tuple
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def die(msg: str, code: int = 2) -> None:
|
|
31
|
+
print(f"error: {msg}", file=sys.stderr)
|
|
32
|
+
raise SystemExit(code)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def ensure_tools() -> None:
|
|
36
|
+
for tool in ("apt-get", "apt-cache", "dpkg-query"):
|
|
37
|
+
if shutil.which(tool) is None:
|
|
38
|
+
die(f"Required tool not found in PATH: {tool}")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def split_args(argv: List[str]) -> Tuple[List[str], List[str]]:
|
|
42
|
+
flags: List[str] = []
|
|
43
|
+
rest: List[str] = []
|
|
44
|
+
for arg in argv:
|
|
45
|
+
if arg.startswith("-") and len(arg) > 1:
|
|
46
|
+
flags.append(arg)
|
|
47
|
+
else:
|
|
48
|
+
rest.append(arg)
|
|
49
|
+
return flags, rest
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def has_flag(flags: List[str], needle: str) -> bool:
|
|
53
|
+
# Pacman combines flags like -Syu
|
|
54
|
+
for flag in flags:
|
|
55
|
+
if flag.startswith("--"):
|
|
56
|
+
continue
|
|
57
|
+
if needle in flag[1:]:
|
|
58
|
+
return True
|
|
59
|
+
return False
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def as_root(cmd: List[str]) -> List[str]:
|
|
63
|
+
# Auto-sudo for operations that modify the system
|
|
64
|
+
if os.geteuid() == 0:
|
|
65
|
+
return cmd
|
|
66
|
+
if shutil.which("sudo") is None:
|
|
67
|
+
die("This operation requires root, and sudo is not available.")
|
|
68
|
+
return ["sudo", "--"] + cmd
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def run(cmd: List[str]) -> int:
|
|
72
|
+
print("+ " + " ".join(shlex.quote(c) for c in cmd))
|
|
73
|
+
process = subprocess.run(cmd, check=False)
|
|
74
|
+
return int(process.returncode)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def main(argv: List[str] | None = None) -> int:
|
|
78
|
+
ensure_tools()
|
|
79
|
+
|
|
80
|
+
if argv is None:
|
|
81
|
+
argv = sys.argv[1:]
|
|
82
|
+
|
|
83
|
+
if not argv or argv[0] in ("-h", "--help"):
|
|
84
|
+
print(
|
|
85
|
+
"pacman (Debian/Ubuntu wrapper)\n\n"
|
|
86
|
+
"Examples:\n\n"
|
|
87
|
+
" pacman -Syu\n\n"
|
|
88
|
+
" pacman -S htop curl\n\n"
|
|
89
|
+
" pacman -R htop\n\n"
|
|
90
|
+
" pacman -Rns htop\n\n"
|
|
91
|
+
" pacman -Ss nginx\n\n"
|
|
92
|
+
" pacman -Qi nginx\n\n"
|
|
93
|
+
" pacman -Q\n"
|
|
94
|
+
)
|
|
95
|
+
return 0
|
|
96
|
+
|
|
97
|
+
flags, args = split_args(argv)
|
|
98
|
+
|
|
99
|
+
# pacman -Syu
|
|
100
|
+
if has_flag(flags, "S") and has_flag(flags, "y") and has_flag(flags, "u"):
|
|
101
|
+
cmds = [
|
|
102
|
+
as_root(["apt-get", "update"]),
|
|
103
|
+
as_root(["apt-get", "dist-upgrade", "-y"]),
|
|
104
|
+
]
|
|
105
|
+
for cmd in cmds:
|
|
106
|
+
rc = run(cmd)
|
|
107
|
+
if rc != 0:
|
|
108
|
+
return rc
|
|
109
|
+
return 0
|
|
110
|
+
|
|
111
|
+
# pacman -S <pkgs...>
|
|
112
|
+
if has_flag(flags, "S") and args and not has_flag(flags, "u"):
|
|
113
|
+
return run(as_root(["apt-get", "install", "-y"] + args))
|
|
114
|
+
|
|
115
|
+
# pacman -R / -Rns <pkgs...>
|
|
116
|
+
if has_flag(flags, "R") and args:
|
|
117
|
+
purge = has_flag(flags, "n") and has_flag(flags, "s")
|
|
118
|
+
if purge:
|
|
119
|
+
# purge + autoremove --purge to mimic "remove + deps + config"
|
|
120
|
+
rc = run(as_root(["apt-get", "purge", "-y"] + args))
|
|
121
|
+
if rc != 0:
|
|
122
|
+
return rc
|
|
123
|
+
return run(as_root(["apt-get", "autoremove", "--purge", "-y"]))
|
|
124
|
+
return run(as_root(["apt-get", "remove", "-y"] + args))
|
|
125
|
+
|
|
126
|
+
# pacman -Ss <query...>
|
|
127
|
+
if has_flag(flags, "Ss"):
|
|
128
|
+
if not args:
|
|
129
|
+
die("Search requires a query (e.g. pacman -Ss nginx)")
|
|
130
|
+
return run(["apt-cache", "search"] + args)
|
|
131
|
+
|
|
132
|
+
# pacman -Qi <pkg...>
|
|
133
|
+
if has_flag(flags, "Qi"):
|
|
134
|
+
if not args:
|
|
135
|
+
die("Info requires package name(s) (e.g. pacman -Qi nginx)")
|
|
136
|
+
# apt-cache show shows package metadata (not strictly installed-state)
|
|
137
|
+
for pkg in args:
|
|
138
|
+
rc = run(["apt-cache", "show", pkg])
|
|
139
|
+
if rc != 0:
|
|
140
|
+
return rc
|
|
141
|
+
return 0
|
|
142
|
+
|
|
143
|
+
# pacman -Q (list installed)
|
|
144
|
+
if has_flag(flags, "Q") and not args:
|
|
145
|
+
return run(["dpkg-query", "-W", "-f=${binary:Package}\t${Version}\\n"])
|
|
146
|
+
|
|
147
|
+
die(f"Unsupported flags/args: flags={flags!r} args={args!r}")
|
|
148
|
+
return 2
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
if __name__ == "__main__":
|
|
152
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pacman-apt-wrapper
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Pacman-style wrapper for apt-get/apt-cache/dpkg-query
|
|
5
|
+
Author: Pacman Apt Wrapper Contributors
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/networkluki/pacman-apt-wrapper
|
|
8
|
+
Project-URL: Source, https://github.com/networkluki/pacman-apt-wrapper
|
|
9
|
+
Project-URL: Issues, https://github.com/networkluki/pacman-apt-wrapper/issues
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: System Administrators
|
|
13
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Topic :: System :: Software Distribution
|
|
16
|
+
Classifier: Topic :: System :: Systems Administration
|
|
17
|
+
Requires-Python: >=3.9
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
# pacman-apt (A pacman-like CLI compatibility layer for linux systems)
|
|
23
|
+
|
|
24
|
+
## Abstract
|
|
25
|
+
`pacman-apt` provides a small subset of Arch Linux `pacman`-style commands on
|
|
26
|
+
linux system by translating them into native `apt-get` / `apt-cache` / `dpkg-query`
|
|
27
|
+
invocations. The goal is consistent operator muscle-memory across distributions,
|
|
28
|
+
not to replace the underlying package manager.
|
|
29
|
+
|
|
30
|
+
## Motivation
|
|
31
|
+
Operators and developers frequently work across multiple Linux distributions.
|
|
32
|
+
Command surface area differences (e.g. `pacman -Syu` vs `apt update && apt upgrade`)
|
|
33
|
+
increase cognitive load and can lead to mistakes during routine maintenance.
|
|
34
|
+
|
|
35
|
+
This project reduces that friction by offering a minimal, explicit translation layer.
|
|
36
|
+
|
|
37
|
+
## Scope
|
|
38
|
+
### Goals
|
|
39
|
+
- Provide a pacman-like UX for common workflows on linux system:
|
|
40
|
+
- `-Syu`, `-S`, `-R`, `-Rns`, `-Ss`, `-Qi`, `-Q`
|
|
41
|
+
- Prefer stable, script-friendly Debian tooling (`apt-get`, `apt-cache`, `dpkg-query`)
|
|
42
|
+
- Transparent execution: print commands before running them
|
|
43
|
+
|
|
44
|
+
### Non-goals
|
|
45
|
+
- Not a package manager: no repository handling, no dependency resolution
|
|
46
|
+
- Not a full `pacman` implementation
|
|
47
|
+
- Not intended for Arch Linux (where `pacman` already exists)
|
|
48
|
+
|
|
49
|
+
## Design Overview
|
|
50
|
+
`pacman-apt` parses a small flag subset and maps it to linux tooling:
|
|
51
|
+
|
|
52
|
+
| pacman-style | linux backend |
|
|
53
|
+
|---|---|
|
|
54
|
+
| `pacman -Syu` | `apt-get update && apt-get dist-upgrade -y` |
|
|
55
|
+
| `pacman -S <pkg...>` | `apt-get install -y <pkg...>` |
|
|
56
|
+
| `pacman -R <pkg...>` | `apt-get remove -y <pkg...>` |
|
|
57
|
+
| `pacman -Rns <pkg...>` | `apt-get purge -y <pkg...> && apt-get autoremove --purge -y` |
|
|
58
|
+
| `pacman -Ss <query>` | `apt-cache search <query>` |
|
|
59
|
+
| `pacman -Qi <pkg>` | `apt-cache show <pkg>` (metadata; see Limitations) |
|
|
60
|
+
| `pacman -Q` | `dpkg-query -W -f='${binary:Package}\t${Version}\n'` |
|
|
61
|
+
|
|
62
|
+
For design rationale, see `docs/design.md`.
|
|
63
|
+
|
|
64
|
+
## Security Model
|
|
65
|
+
- No `shell=True`; all subprocess calls use explicit argument arrays
|
|
66
|
+
- Conservative privilege handling (uses `sudo` when not root)
|
|
67
|
+
- Commands are echoed before execution for auditability
|
|
68
|
+
|
|
69
|
+
See `docs/security.md` for the threat model and assumptions.
|
|
70
|
+
|
|
71
|
+
## Compatibility
|
|
72
|
+
- Debian: stable
|
|
73
|
+
- Ubuntu: LTS
|
|
74
|
+
|
|
75
|
+
(Exact versions may vary; see `docs/compatibility.md`.)
|
|
76
|
+
|
|
77
|
+
## Installation
|
|
78
|
+
### Install with pip
|
|
79
|
+
From a local checkout:
|
|
80
|
+
```bash
|
|
81
|
+
python -m pip install .
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
For development, use an editable install:
|
|
85
|
+
```bash
|
|
86
|
+
python -m pip install -e .
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Both pip installs create these commands in the active Python environment:
|
|
90
|
+
- `pacman`
|
|
91
|
+
- `pacman-apt`
|
|
92
|
+
|
|
93
|
+
If your Python environment's script directory is not on `PATH`, run the module
|
|
94
|
+
entrypoint directly instead:
|
|
95
|
+
```bash
|
|
96
|
+
python -m pacman_apt.cli --help
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Manual (single-file)
|
|
100
|
+
```bash
|
|
101
|
+
sudo install -m 0755 pacman /usr/local/bin/pacman
|
|
102
|
+
```
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
pacman_apt/__init__.py,sha256=v294TQ2wKz2ZTu26y88JsVzaBDyC8lMY7xRAVjFeTj0,97
|
|
2
|
+
pacman_apt/cli.py,sha256=EdmD9FHGEmKrIGGfJ_SV6P20SF6VYPPjijSvhUS1W6s,4196
|
|
3
|
+
pacman_apt_wrapper-0.1.0.dist-info/licenses/LICENSE,sha256=aed4jZQzr-SCuFQaEH3Q7Er_4-rv1bNyEqlHrX1diPw,1077
|
|
4
|
+
pacman_apt_wrapper-0.1.0.dist-info/METADATA,sha256=jbl2Uv1ALfWi5_RGM93vnye_GsP4ta8SFj9ie2QcSOc,3584
|
|
5
|
+
pacman_apt_wrapper-0.1.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
|
|
6
|
+
pacman_apt_wrapper-0.1.0.dist-info/entry_points.txt,sha256=KGcWQ_BS9BbqyNOeut10bZbUOjJtdFsr4RPC_2qriHE,80
|
|
7
|
+
pacman_apt_wrapper-0.1.0.dist-info/top_level.txt,sha256=8E1uAgoVKo0-tlNxt1g9Np8K1PGWkr8IuW-T30UleSU,11
|
|
8
|
+
pacman_apt_wrapper-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Luki Hackwell ( NL )
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pacman_apt
|