omnipkg 1.0.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.
- omnipkg-1.0.0/LICENSE +21 -0
- omnipkg-1.0.0/MANIFEST.in +3 -0
- omnipkg-1.0.0/PKG-INFO +125 -0
- omnipkg-1.0.0/README.md +104 -0
- omnipkg-1.0.0/omnipkg/__init__.py +0 -0
- omnipkg-1.0.0/omnipkg/__main__.py +6 -0
- omnipkg-1.0.0/omnipkg/activator.py +70 -0
- omnipkg-1.0.0/omnipkg/cli.py +133 -0
- omnipkg-1.0.0/omnipkg/core.py +1054 -0
- omnipkg-1.0.0/omnipkg/demo.py +263 -0
- omnipkg-1.0.0/omnipkg/loader.py +106 -0
- omnipkg-1.0.0/omnipkg/package_meta_builder.py +611 -0
- omnipkg-1.0.0/omnipkg/stress_test.py +133 -0
- omnipkg-1.0.0/omnipkg.egg-info/PKG-INFO +125 -0
- omnipkg-1.0.0/omnipkg.egg-info/SOURCES.txt +20 -0
- omnipkg-1.0.0/omnipkg.egg-info/dependency_links.txt +1 -0
- omnipkg-1.0.0/omnipkg.egg-info/entry_points.txt +2 -0
- omnipkg-1.0.0/omnipkg.egg-info/requires.txt +3 -0
- omnipkg-1.0.0/omnipkg.egg-info/top_level.txt +1 -0
- omnipkg-1.0.0/pyproject.toml +36 -0
- omnipkg-1.0.0/requirements.txt +6 -0
- omnipkg-1.0.0/setup.cfg +4 -0
omnipkg-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Copyright (c) 2025 1minds3t
|
|
2
|
+
|
|
3
|
+
This file is part of `omnipkg`.
|
|
4
|
+
|
|
5
|
+
omnipkg is free software: you can redistribute it and/or modify
|
|
6
|
+
it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
(at your option) any later version.
|
|
9
|
+
|
|
10
|
+
omnipkg is distributed in the hope that it will be useful,
|
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
GNU Affero General Public License for more details.
|
|
14
|
+
|
|
15
|
+
You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
along with omnipkg. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
For commercial licensing options or general inquiries, contact:
|
|
21
|
+
๐ง omnipkg@proton.me
|
omnipkg-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: omnipkg
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: The Intelligent Python Dependency Resolver
|
|
5
|
+
Author-email: minds3t <omnipkg@proton.me>
|
|
6
|
+
License: AGPL-3.0-or-later
|
|
7
|
+
Project-URL: Homepage, https://github.com/1minds3t/omnipkg
|
|
8
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: GNU Affero General Public License v3
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
14
|
+
Requires-Python: >=3.11
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: redis
|
|
18
|
+
Requires-Dist: packaging
|
|
19
|
+
Requires-Dist: requests
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
# omnipkg: The Intelligent Python Package Manager
|
|
26
|
+
> One environment. Infinite versions. Zero conflicts.
|
|
27
|
+
|
|
28
|
+
<p align="center">
|
|
29
|
+
<a href="https://github.com/omnipkg/omnipkg/actions/workflows/test.yml">
|
|
30
|
+
<img src="https://img.shields.io/github/actions/workflow/status/omnipkg/omnipkg/test.yml?branch=main" alt="Build Status">
|
|
31
|
+
</a>
|
|
32
|
+
<a href="https://pypi.org/project/omnipkg/">
|
|
33
|
+
<img src="https://img.shields.io/pypi/v/omnipkg.svg" alt="PyPI version">
|
|
34
|
+
</a>
|
|
35
|
+
<a href="https://www.gnu.org/licenses/agpl-3.0">
|
|
36
|
+
<img src="https://img.shields.io/badge/License-AGPLv3-red.svg" alt="License: AGPLv3">
|
|
37
|
+
</a>
|
|
38
|
+
<a href="https://github.com/omnipkg/omnipkg/actions/workflows/security_audit.yml">
|
|
39
|
+
<img src="https://img.shields.io/github/actions/workflow/status/omnipkg/omnipkg/security_audit.yml?branch=main" alt="Security Audit">
|
|
40
|
+
</a>
|
|
41
|
+
</p>
|
|
42
|
+
|
|
43
|
+
[](https://github.com/1minds3t/omnipkg/actions/workflows/security_audit.yml)
|
|
44
|
+
[](https://github.com/1minds3t/omnipkg/actions/workflows/publish.yml)
|
|
45
|
+
[](https://pypi.org/project/omnipkg/)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
`omnipkg` lets you install *any version* of *any package* without breaking your environment, downgrading dependencies, or needing Conda, Docker, or `pipx`. **Dependency hell? Obliterated.**
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
## See It to Believe It (30 Second Demo)
|
|
54
|
+
|
|
55
|
+
<!-- A GIF is the best format for this. It shows the tool in action without taking up a ton of space. -->
|
|
56
|
+

|
|
57
|
+
*This shows `omnipkg install old-package`, downgrade protection activating, and `omnipkg status` confirming both versions coexist.*
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## ๐ Features
|
|
62
|
+
|
|
63
|
+
- ๐ก๏ธ **Downgrade Protection**: Stops `pip` from nuking your environment by isolating conflicting versions into protected "bubbles."
|
|
64
|
+
- ๐พ **Intelligent Deduplication**: Saves up to 60% disk space on bubbled packages while keeping native C extensions stable.
|
|
65
|
+
- ๐ง **Redis-Backed Knowledge Base**: Lightning-fast lookups for all package versions, dependencies, and security info.
|
|
66
|
+
- ๐ **Runtime Version Switching**: Activate any bubbled package version on the fly, even within the same script.
|
|
67
|
+
- ๐งช **Battle-Tested**: Proven to handle massive environments (520+ packages, 95+ bubbles, 15.4GB+) without flinching.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## How Is This Possible?
|
|
72
|
+
|
|
73
|
+
When a downgrade is detected, `omnipkg` performs surgery:
|
|
74
|
+
1. **Intercepts** the request.
|
|
75
|
+
2. **Installs** the conflicting version and its entire dependency tree into a temporary, isolated location.
|
|
76
|
+
3. **Creates** a space-efficient, deduplicated "bubble" in `.omnipkg_versions`.
|
|
77
|
+
4. **Restores** the original package in your main environment.
|
|
78
|
+
|
|
79
|
+
The result: a perfectly stable global environment, with every version you've ever needed on standby.
|
|
80
|
+
|
|
81
|
+
<details>
|
|
82
|
+
<summary><strong>๐ฌ Click for a Real-World Example: Downgrading PyTorch</strong></summary>
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# User wants to install an older torch version
|
|
86
|
+
$ omnipkg install torch==2.7.0
|
|
87
|
+
|
|
88
|
+
# ... (omnipkg detects the downgrade) ...
|
|
89
|
+
๐ก๏ธ DOWNGRADE PROTECTION ACTIVATED!
|
|
90
|
+
-> Fixing downgrade: torch from v2.7.1 to v2.7.0
|
|
91
|
+
๐ซง Creating isolated bubble for torch v2.7.0
|
|
92
|
+
โ
Success: Dependencies resolved via PyPI API.
|
|
93
|
+
๐งน Creating deduplicated bubble...
|
|
94
|
+
โ ๏ธ Disabling deduplication for native package: torch
|
|
95
|
+
โ
Bubble created: 16241 files copied, 3211 deduplicated.
|
|
96
|
+
๐ Space efficiency: 16.5% saved.
|
|
97
|
+
๐ Restoring โtorchโ to safe version v2.7.1 in main environmentโฆ
|
|
98
|
+
|
|
99
|
+
โ
Environment protection complete!
|
|
100
|
+
```
|
|
101
|
+
</details>
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Why Other Tools Fail
|
|
106
|
+
|
|
107
|
+
| Tool | The Task: `install old-conflicting-package` | Result |
|
|
108
|
+
|---------------|---------------------------------------------|---------------------------------------|
|
|
109
|
+
| `pip` | โ | `ERROR: Cannot uninstall...` |
|
|
110
|
+
| `conda` | โณ | `Solving environment...` (for hours) |
|
|
111
|
+
| `poetry` | ๐ฅ | `SolverProblemError` |
|
|
112
|
+
| `uv` | ๐ซ | `No solution found for the request` |
|
|
113
|
+
| **`omnipkg`** | โ
| **`DOWNGRADE PROTECTION ACTIVATED!`** |
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## ๐ Licensing
|
|
118
|
+
|
|
119
|
+
`omnipkg` is available under a dual-license model to suit different needs.
|
|
120
|
+
|
|
121
|
+
- **Community Edition (AGPLv3):** Perfect for individual developers, open-source projects, and academic use. If you use `omnipkg` in a project that is also open-source under a compatible license, you're good to go. The source code is available in this repository under the [GNU AGPLv3](LICENSE).
|
|
122
|
+
|
|
123
|
+
- **Commercial License:** Required for use in closed-source commercial software, proprietary systems, or for any organization that cannot comply with the terms of the AGPLv3. This license allows you to integrate `omnipkg` without the obligation to open-source your own code.
|
|
124
|
+
|
|
125
|
+
โ **To inquire about a commercial license, please contact:** [**omnipkg@proton.me**](mailto:omnipkg@proton.me)
|
omnipkg-1.0.0/README.md
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
|
|
2
|
+
---
|
|
3
|
+
|
|
4
|
+
# omnipkg: The Intelligent Python Package Manager
|
|
5
|
+
> One environment. Infinite versions. Zero conflicts.
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="https://github.com/omnipkg/omnipkg/actions/workflows/test.yml">
|
|
9
|
+
<img src="https://img.shields.io/github/actions/workflow/status/omnipkg/omnipkg/test.yml?branch=main" alt="Build Status">
|
|
10
|
+
</a>
|
|
11
|
+
<a href="https://pypi.org/project/omnipkg/">
|
|
12
|
+
<img src="https://img.shields.io/pypi/v/omnipkg.svg" alt="PyPI version">
|
|
13
|
+
</a>
|
|
14
|
+
<a href="https://www.gnu.org/licenses/agpl-3.0">
|
|
15
|
+
<img src="https://img.shields.io/badge/License-AGPLv3-red.svg" alt="License: AGPLv3">
|
|
16
|
+
</a>
|
|
17
|
+
<a href="https://github.com/omnipkg/omnipkg/actions/workflows/security_audit.yml">
|
|
18
|
+
<img src="https://img.shields.io/github/actions/workflow/status/omnipkg/omnipkg/security_audit.yml?branch=main" alt="Security Audit">
|
|
19
|
+
</a>
|
|
20
|
+
</p>
|
|
21
|
+
|
|
22
|
+
[](https://github.com/1minds3t/omnipkg/actions/workflows/security_audit.yml)
|
|
23
|
+
[](https://github.com/1minds3t/omnipkg/actions/workflows/publish.yml)
|
|
24
|
+
[](https://pypi.org/project/omnipkg/)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
`omnipkg` lets you install *any version* of *any package* without breaking your environment, downgrading dependencies, or needing Conda, Docker, or `pipx`. **Dependency hell? Obliterated.**
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
## See It to Believe It (30 Second Demo)
|
|
33
|
+
|
|
34
|
+
<!-- A GIF is the best format for this. It shows the tool in action without taking up a ton of space. -->
|
|
35
|
+

|
|
36
|
+
*This shows `omnipkg install old-package`, downgrade protection activating, and `omnipkg status` confirming both versions coexist.*
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## ๐ Features
|
|
41
|
+
|
|
42
|
+
- ๐ก๏ธ **Downgrade Protection**: Stops `pip` from nuking your environment by isolating conflicting versions into protected "bubbles."
|
|
43
|
+
- ๐พ **Intelligent Deduplication**: Saves up to 60% disk space on bubbled packages while keeping native C extensions stable.
|
|
44
|
+
- ๐ง **Redis-Backed Knowledge Base**: Lightning-fast lookups for all package versions, dependencies, and security info.
|
|
45
|
+
- ๐ **Runtime Version Switching**: Activate any bubbled package version on the fly, even within the same script.
|
|
46
|
+
- ๐งช **Battle-Tested**: Proven to handle massive environments (520+ packages, 95+ bubbles, 15.4GB+) without flinching.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## How Is This Possible?
|
|
51
|
+
|
|
52
|
+
When a downgrade is detected, `omnipkg` performs surgery:
|
|
53
|
+
1. **Intercepts** the request.
|
|
54
|
+
2. **Installs** the conflicting version and its entire dependency tree into a temporary, isolated location.
|
|
55
|
+
3. **Creates** a space-efficient, deduplicated "bubble" in `.omnipkg_versions`.
|
|
56
|
+
4. **Restores** the original package in your main environment.
|
|
57
|
+
|
|
58
|
+
The result: a perfectly stable global environment, with every version you've ever needed on standby.
|
|
59
|
+
|
|
60
|
+
<details>
|
|
61
|
+
<summary><strong>๐ฌ Click for a Real-World Example: Downgrading PyTorch</strong></summary>
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# User wants to install an older torch version
|
|
65
|
+
$ omnipkg install torch==2.7.0
|
|
66
|
+
|
|
67
|
+
# ... (omnipkg detects the downgrade) ...
|
|
68
|
+
๐ก๏ธ DOWNGRADE PROTECTION ACTIVATED!
|
|
69
|
+
-> Fixing downgrade: torch from v2.7.1 to v2.7.0
|
|
70
|
+
๐ซง Creating isolated bubble for torch v2.7.0
|
|
71
|
+
โ
Success: Dependencies resolved via PyPI API.
|
|
72
|
+
๐งน Creating deduplicated bubble...
|
|
73
|
+
โ ๏ธ Disabling deduplication for native package: torch
|
|
74
|
+
โ
Bubble created: 16241 files copied, 3211 deduplicated.
|
|
75
|
+
๐ Space efficiency: 16.5% saved.
|
|
76
|
+
๐ Restoring โtorchโ to safe version v2.7.1 in main environmentโฆ
|
|
77
|
+
|
|
78
|
+
โ
Environment protection complete!
|
|
79
|
+
```
|
|
80
|
+
</details>
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Why Other Tools Fail
|
|
85
|
+
|
|
86
|
+
| Tool | The Task: `install old-conflicting-package` | Result |
|
|
87
|
+
|---------------|---------------------------------------------|---------------------------------------|
|
|
88
|
+
| `pip` | โ | `ERROR: Cannot uninstall...` |
|
|
89
|
+
| `conda` | โณ | `Solving environment...` (for hours) |
|
|
90
|
+
| `poetry` | ๐ฅ | `SolverProblemError` |
|
|
91
|
+
| `uv` | ๐ซ | `No solution found for the request` |
|
|
92
|
+
| **`omnipkg`** | โ
| **`DOWNGRADE PROTECTION ACTIVATED!`** |
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## ๐ Licensing
|
|
97
|
+
|
|
98
|
+
`omnipkg` is available under a dual-license model to suit different needs.
|
|
99
|
+
|
|
100
|
+
- **Community Edition (AGPLv3):** Perfect for individual developers, open-source projects, and academic use. If you use `omnipkg` in a project that is also open-source under a compatible license, you're good to go. The source code is available in this repository under the [GNU AGPLv3](LICENSE).
|
|
101
|
+
|
|
102
|
+
- **Commercial License:** Required for use in closed-source commercial software, proprietary systems, or for any organization that cannot comply with the terms of the AGPLv3. This license allows you to integrate `omnipkg` without the obligation to open-source your own code.
|
|
103
|
+
|
|
104
|
+
โ **To inquire about a commercial license, please contact:** [**omnipkg@proton.me**](mailto:omnipkg@proton.me)
|
|
File without changes
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import os
|
|
3
|
+
import importlib.util
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from omnipkg.core import ConfigManager
|
|
6
|
+
|
|
7
|
+
def get_config():
|
|
8
|
+
"""Load config using ConfigManager"""
|
|
9
|
+
config_manager = ConfigManager()
|
|
10
|
+
return config_manager.config
|
|
11
|
+
|
|
12
|
+
def get_multiversion_base():
|
|
13
|
+
"""Get base path from config with fallbacks"""
|
|
14
|
+
try:
|
|
15
|
+
config = get_config()
|
|
16
|
+
base = config.get("multiversion_base")
|
|
17
|
+
if base: return base
|
|
18
|
+
except Exception:
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
# Fallback to package-relative directory
|
|
22
|
+
return str(Path(__file__).parent.parent / ".omnipkg_versions")
|
|
23
|
+
|
|
24
|
+
class ImportHookManager:
|
|
25
|
+
def __init__(self, multiversion_base: str):
|
|
26
|
+
self.multiversion_base = Path(multiversion_base)
|
|
27
|
+
self.version_map = {}
|
|
28
|
+
self.load_version_map()
|
|
29
|
+
|
|
30
|
+
def load_version_map(self):
|
|
31
|
+
if not self.multiversion_base.exists(): return
|
|
32
|
+
for version_dir in self.multiversion_base.iterdir():
|
|
33
|
+
if version_dir.is_dir() and '-' in version_dir.name:
|
|
34
|
+
parts = version_dir.name.rsplit('-', 1)
|
|
35
|
+
if len(parts) == 2:
|
|
36
|
+
pkg_name, version = parts
|
|
37
|
+
if pkg_name not in self.version_map:
|
|
38
|
+
self.version_map[pkg_name] = {}
|
|
39
|
+
self.version_map[pkg_name][version] = str(version_dir)
|
|
40
|
+
|
|
41
|
+
def get_package_path(self, package_name: str, version: str):
|
|
42
|
+
return self.version_map.get(package_name.lower(), {}).get(version)
|
|
43
|
+
|
|
44
|
+
class MultiversionFinder:
|
|
45
|
+
def __init__(self, hook_manager: ImportHookManager):
|
|
46
|
+
self.hook_manager = hook_manager
|
|
47
|
+
|
|
48
|
+
def find_spec(self, fullname, path, target=None):
|
|
49
|
+
top_level = fullname.split('.')[0]
|
|
50
|
+
env_var_name = f"_omnipkg_ACTIVE_{top_level.upper().replace('-', '_')}"
|
|
51
|
+
activated_version = os.environ.get(env_var_name)
|
|
52
|
+
if activated_version:
|
|
53
|
+
pkg_path = self.hook_manager.get_package_path(top_level, activated_version)
|
|
54
|
+
if pkg_path:
|
|
55
|
+
module_path = Path(pkg_path) / top_level
|
|
56
|
+
if module_path.is_dir() and (module_path / "__init__.py").exists():
|
|
57
|
+
return importlib.util.spec_from_file_location(
|
|
58
|
+
fullname,
|
|
59
|
+
str(module_path / "__init__.py"),
|
|
60
|
+
submodule_search_locations=[str(module_path)]
|
|
61
|
+
)
|
|
62
|
+
return None
|
|
63
|
+
|
|
64
|
+
# --- Global Singleton ---
|
|
65
|
+
_hook_manager = ImportHookManager(get_multiversion_base())
|
|
66
|
+
|
|
67
|
+
def install_hook():
|
|
68
|
+
"""Installs the omnipkg import hook if not already active"""
|
|
69
|
+
if not any(isinstance(finder, MultiversionFinder) for finder in sys.meta_path):
|
|
70
|
+
sys.meta_path.insert(0, MultiversionFinder(_hook_manager))
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
omnipkg CLI
|
|
4
|
+
"""
|
|
5
|
+
import sys
|
|
6
|
+
import argparse
|
|
7
|
+
from .core import omnipkg, ConfigManager
|
|
8
|
+
|
|
9
|
+
def print_header(title):
|
|
10
|
+
"""Prints a consistent, pretty header for CLI sections."""
|
|
11
|
+
print("\n" + "="*60)
|
|
12
|
+
print(f" ๐ {title}")
|
|
13
|
+
print("="*60)
|
|
14
|
+
|
|
15
|
+
import textwrap
|
|
16
|
+
|
|
17
|
+
def create_parser():
|
|
18
|
+
"""Creates and configures the argument parser."""
|
|
19
|
+
# This formatter_class is key to making our new help text look good.
|
|
20
|
+
# The epilog provides examples of the most important commands.
|
|
21
|
+
parser = argparse.ArgumentParser(
|
|
22
|
+
prog='omnipkg',
|
|
23
|
+
description='The intelligent Python package manager that solves dependency hell.',
|
|
24
|
+
formatter_class=argparse.RawTextHelpFormatter, # Prevents argparse from messing up our formatting
|
|
25
|
+
epilog=textwrap.dedent('''\
|
|
26
|
+
|
|
27
|
+
Common Commands:
|
|
28
|
+
omnipkg install <package> Install a package with downgrade protection.
|
|
29
|
+
omnipkg list See all installed packages and their health.
|
|
30
|
+
omnipkg status Check the health of your multi-version environment.
|
|
31
|
+
omnipkg info <package> Get a detailed dashboard for a specific package.
|
|
32
|
+
omnipkg demo Run the interactive showcase to see the magic.
|
|
33
|
+
''')
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
subparsers = parser.add_subparsers(dest='command', help='All available commands:', required=True)
|
|
37
|
+
|
|
38
|
+
install_parser = subparsers.add_parser('install', help='Install packages (with downgrade protection)')
|
|
39
|
+
install_parser.add_argument('packages', nargs='+', help='Packages to install (e.g., "requests==2.25.1")')
|
|
40
|
+
|
|
41
|
+
info_parser = subparsers.add_parser('info', help='Show detailed package information with interactive version selection')
|
|
42
|
+
info_parser.add_argument('package', help='Package name to inspect')
|
|
43
|
+
info_parser.add_argument('--version', default='active', help='Specific version to inspect')
|
|
44
|
+
|
|
45
|
+
list_parser = subparsers.add_parser('list', help='List installed packages')
|
|
46
|
+
list_parser.add_argument('filter', nargs='?', help='Optional filter pattern for package names')
|
|
47
|
+
|
|
48
|
+
status_parser = subparsers.add_parser('status', help='Show multi-version system status')
|
|
49
|
+
|
|
50
|
+
demo_parser = subparsers.add_parser('demo', help='Run the interactive, automated demo')
|
|
51
|
+
|
|
52
|
+
stress_parser = subparsers.add_parser('stress-test', help='Run the ultimate stress test with heavy-duty packages.')
|
|
53
|
+
|
|
54
|
+
reset_parser = subparsers.add_parser('reset', help='DELETE and rebuild the omnipkg knowledge base in Redis')
|
|
55
|
+
reset_parser.add_argument('--yes', '-y', action='store_true', help='Skip confirmation')
|
|
56
|
+
|
|
57
|
+
rebuild_parser = subparsers.add_parser('rebuild-kb', help='Force a full rebuild of the knowledge base without deleting')
|
|
58
|
+
rebuild_parser.add_argument('--force', '-f', action='store_true', help='Ignore cache and force re-processing of all metadata')
|
|
59
|
+
|
|
60
|
+
return parser
|
|
61
|
+
|
|
62
|
+
def main():
|
|
63
|
+
"""The main entry point for the CLI."""
|
|
64
|
+
|
|
65
|
+
# Handle the case where 'omnipkg' is run with no arguments
|
|
66
|
+
if len(sys.argv) == 1:
|
|
67
|
+
cm = ConfigManager()
|
|
68
|
+
if not cm.config_path.exists():
|
|
69
|
+
cm._first_time_setup()
|
|
70
|
+
print("\n" + "="*50)
|
|
71
|
+
print("๐ Welcome to omnipkg! Your setup is complete.")
|
|
72
|
+
print("To see the magic in action, we highly recommend running the demo:")
|
|
73
|
+
print("\n omnipkg demo\n")
|
|
74
|
+
print("="*50)
|
|
75
|
+
else:
|
|
76
|
+
print("๐ Welcome back to omnipkg!")
|
|
77
|
+
print(" Run `omnipkg status` to see your environment.")
|
|
78
|
+
print(" Run `omnipkg demo` for a showcase of features.")
|
|
79
|
+
print(" Run `omnipkg --help` for all commands.")
|
|
80
|
+
return 0
|
|
81
|
+
|
|
82
|
+
parser = create_parser()
|
|
83
|
+
args = parser.parse_args()
|
|
84
|
+
|
|
85
|
+
# First, create the config manager to load/create the config
|
|
86
|
+
cm = ConfigManager()
|
|
87
|
+
|
|
88
|
+
# Now, create the main instance, PASSING IN the loaded config
|
|
89
|
+
pkg_instance = omnipkg(cm.config)
|
|
90
|
+
|
|
91
|
+
try:
|
|
92
|
+
if args.command == 'install':
|
|
93
|
+
return pkg_instance.smart_install(args.packages)
|
|
94
|
+
elif args.command == 'info':
|
|
95
|
+
return pkg_instance.show_package_info(args.package, args.version)
|
|
96
|
+
elif args.command == 'list':
|
|
97
|
+
return pkg_instance.list_packages(args.filter)
|
|
98
|
+
elif args.command == 'status':
|
|
99
|
+
return pkg_instance.show_multiversion_status()
|
|
100
|
+
elif args.command == 'demo':
|
|
101
|
+
from .demo import run_demo
|
|
102
|
+
return run_demo()
|
|
103
|
+
elif args.command == 'stress-test':
|
|
104
|
+
from . import stress_test
|
|
105
|
+
print_header("omnipkg Ultimate Stress Test")
|
|
106
|
+
print("This test will install, bubble, and test multiple large scientific packages.")
|
|
107
|
+
print("\nโ ๏ธ This will download several hundred MB and may take several minutes.")
|
|
108
|
+
|
|
109
|
+
if input("\nProceed with the stress test? (y/n): ").lower() != 'y':
|
|
110
|
+
print("Stress test cancelled.")
|
|
111
|
+
return 0
|
|
112
|
+
|
|
113
|
+
stress_test.run()
|
|
114
|
+
return 0
|
|
115
|
+
elif args.command == 'reset':
|
|
116
|
+
return pkg_instance.reset_knowledge_base(force=args.yes)
|
|
117
|
+
elif args.command == 'rebuild-kb':
|
|
118
|
+
return pkg_instance.rebuild_knowledge_base(force=args.force)
|
|
119
|
+
else:
|
|
120
|
+
parser.print_help()
|
|
121
|
+
return 1
|
|
122
|
+
|
|
123
|
+
except KeyboardInterrupt:
|
|
124
|
+
print("\nโ Operation cancelled by user.")
|
|
125
|
+
return 1
|
|
126
|
+
except Exception as e:
|
|
127
|
+
print(f"\nโ An unexpected top-level error occurred: {e}")
|
|
128
|
+
import traceback
|
|
129
|
+
traceback.print_exc()
|
|
130
|
+
return 1
|
|
131
|
+
|
|
132
|
+
if __name__ == "__main__":
|
|
133
|
+
sys.exit(main())
|