usecli 0.1.36__tar.gz → 0.1.38__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.
- {usecli-0.1.36 → usecli-0.1.38}/PKG-INFO +1 -1
- {usecli-0.1.36 → usecli-0.1.38}/pyproject.toml +1 -1
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/commands/init_command.py +29 -19
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/config/colors.py +78 -15
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/shared/config/manager.py +105 -19
- {usecli-0.1.36/src/usecli/cli → usecli-0.1.38/src/usecli}/usecli.config.toml +3 -3
- {usecli-0.1.36 → usecli-0.1.38}/LICENSE +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/README.md +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/__init__.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/__init__.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/commands/README.md +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/commands/__init__.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/commands/custom/README.md +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/commands/custom/__init__.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/commands/defaults/__init__.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/commands/defaults/base/__init__.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/commands/defaults/base/about_command.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/commands/defaults/base/help_command.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/commands/defaults/base/inspire_command.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/commands/defaults/base/internal/__init__.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/commands/defaults/base/internal/fzf_command.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/commands/defaults/core/__init__.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/commands/defaults/core/utils.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/commands/defaults/make/__init__.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/commands/defaults/make/make_command.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/commands/defaults/make/make_theme_command.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/config/__init__.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/core/__init__.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/core/base_command.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/core/error/__init__.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/core/error/handler.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/core/error/utils.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/core/exceptions/__init__.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/core/exceptions/base.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/core/exceptions/config.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/core/exceptions/usage.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/core/exceptions/validation.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/core/skill_generator.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/core/ui/__init__.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/core/ui/list.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/core/ui/title.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/core/validators/__init__.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/core/validators/network.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/core/validators/numeric.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/core/validators/path.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/core/validators/string.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/services/__init__.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/services/command_service.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/templates/command.py.j2 +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/templates/theme.toml.j2 +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/templates/usecli.config.toml.j2 +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/themes/ayu_dark.toml +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/themes/catppuccin_frappe.toml +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/themes/catppuccin_latte.toml +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/themes/catppuccin_macchiato.toml +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/themes/catppuccin_mocha.toml +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/themes/default.toml +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/themes/dracula.toml +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/themes/gruvbox_dark.toml +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/themes/nord.toml +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/themes/tokyo_night.toml +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/utils/__init__.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/utils/interactive/__init__.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/utils/interactive/terminal_menu.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/menu.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/params.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/shared/__init__.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/shared/config/__init__.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/shared/config/globals.py +0 -0
- {usecli-0.1.36 → usecli-0.1.38}/src/usecli/ui.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "usecli"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.38"
|
|
4
4
|
description = "A powerful Python CLI framework for building beautiful, developer-friendly command-line tools."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [{ name = "Edward Boswell", email = "thememium@gmail.com" }]
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import os
|
|
5
6
|
import re
|
|
6
7
|
import shutil
|
|
7
8
|
import subprocess
|
|
@@ -504,7 +505,11 @@ include = ["{root_package}*"]
|
|
|
504
505
|
cwd = Path.cwd()
|
|
505
506
|
config_manager = ConfigManager(start_dir=cwd)
|
|
506
507
|
project_root = config_manager.get_project_root()
|
|
507
|
-
pyproject_path =
|
|
508
|
+
pyproject_path = (
|
|
509
|
+
config_manager.pyproject_path
|
|
510
|
+
if config_manager.pyproject_path.exists()
|
|
511
|
+
else project_root / "pyproject.toml"
|
|
512
|
+
)
|
|
508
513
|
|
|
509
514
|
console.print()
|
|
510
515
|
existing_command_name = self._get_existing_usecli_script_name(pyproject_path)
|
|
@@ -651,24 +656,6 @@ include = ["{root_package}*"]
|
|
|
651
656
|
f"[{COLOR.WARNING}]Default theme already exists:[/{COLOR.WARNING}] {theme_template_path}"
|
|
652
657
|
)
|
|
653
658
|
|
|
654
|
-
# Load the template
|
|
655
|
-
template_path = (
|
|
656
|
-
Path(__file__).parent.parent / "templates" / "usecli.config.toml.j2"
|
|
657
|
-
)
|
|
658
|
-
template_content = template_path.read_text()
|
|
659
|
-
template = Template(template_content)
|
|
660
|
-
|
|
661
|
-
# Render the config
|
|
662
|
-
config_content = template.render(
|
|
663
|
-
title=title,
|
|
664
|
-
description=description,
|
|
665
|
-
commands_dir=commands_dir,
|
|
666
|
-
templates_dir=templates_dir,
|
|
667
|
-
themes_dir=themes_dir,
|
|
668
|
-
title_font=title_font,
|
|
669
|
-
theme=theme,
|
|
670
|
-
)
|
|
671
|
-
|
|
672
659
|
scripts_status: str | None = None
|
|
673
660
|
usecli_config_status: str | None = None
|
|
674
661
|
|
|
@@ -744,6 +731,29 @@ include = ["{root_package}*"]
|
|
|
744
731
|
if replace_existing:
|
|
745
732
|
config_path = existing_config
|
|
746
733
|
|
|
734
|
+
config_dir = config_path.parent
|
|
735
|
+
config_commands_dir = os.path.relpath(commands_path, start=config_dir)
|
|
736
|
+
config_templates_dir = os.path.relpath(templates_path, start=config_dir)
|
|
737
|
+
config_themes_dir = os.path.relpath(themes_path, start=config_dir)
|
|
738
|
+
|
|
739
|
+
# Load the template
|
|
740
|
+
template_path = (
|
|
741
|
+
Path(__file__).parent.parent / "templates" / "usecli.config.toml.j2"
|
|
742
|
+
)
|
|
743
|
+
template_content = template_path.read_text()
|
|
744
|
+
template = Template(template_content)
|
|
745
|
+
|
|
746
|
+
# Render the config
|
|
747
|
+
config_content = template.render(
|
|
748
|
+
title=title,
|
|
749
|
+
description=description,
|
|
750
|
+
commands_dir=config_commands_dir,
|
|
751
|
+
templates_dir=config_templates_dir,
|
|
752
|
+
themes_dir=config_themes_dir,
|
|
753
|
+
title_font=title_font,
|
|
754
|
+
theme=theme,
|
|
755
|
+
)
|
|
756
|
+
|
|
747
757
|
usecli_config_status = self._write_usecli_config(
|
|
748
758
|
config_path, config_content, force
|
|
749
759
|
)
|
|
@@ -11,7 +11,9 @@ Usage:
|
|
|
11
11
|
|
|
12
12
|
from __future__ import annotations
|
|
13
13
|
|
|
14
|
+
import importlib.metadata
|
|
14
15
|
import importlib.util
|
|
16
|
+
import os
|
|
15
17
|
import sys
|
|
16
18
|
from pathlib import Path
|
|
17
19
|
from typing import Any, Callable, Final, final
|
|
@@ -26,7 +28,15 @@ PYPROJECT_TOML = "pyproject.toml"
|
|
|
26
28
|
USECLI_CONFIG_TOML = "usecli.config.toml"
|
|
27
29
|
DEFAULT_THEME_NAME = "default"
|
|
28
30
|
THEMES_DIR = Path(__file__).resolve().parent.parent / "themes"
|
|
29
|
-
|
|
31
|
+
_SKIP_DIRS = {
|
|
32
|
+
".venv",
|
|
33
|
+
"venv",
|
|
34
|
+
"site-packages",
|
|
35
|
+
"dist-packages",
|
|
36
|
+
"__pypackages__",
|
|
37
|
+
"pipx",
|
|
38
|
+
"venvs",
|
|
39
|
+
}
|
|
30
40
|
DEFAULT_THEME_COLORS: dict[str, str] = {
|
|
31
41
|
"primary": "#60D7FF",
|
|
32
42
|
"secondary": "#5EFF87",
|
|
@@ -61,7 +71,7 @@ def _find_usecli_config_path(
|
|
|
61
71
|
candidates = [
|
|
62
72
|
path
|
|
63
73
|
for path in candidates
|
|
64
|
-
if not any(part in
|
|
74
|
+
if not any(part in _SKIP_DIRS for part in path.parts)
|
|
65
75
|
]
|
|
66
76
|
if not candidates:
|
|
67
77
|
return None
|
|
@@ -106,8 +116,64 @@ def _find_usecli_config_in_package() -> Path | None:
|
|
|
106
116
|
return None
|
|
107
117
|
|
|
108
118
|
|
|
119
|
+
def _find_usecli_config_in_named_package(package_name: str) -> Path | None:
|
|
120
|
+
if not package_name:
|
|
121
|
+
return None
|
|
122
|
+
spec = importlib.util.find_spec(package_name)
|
|
123
|
+
if spec is None or not spec.submodule_search_locations:
|
|
124
|
+
return None
|
|
125
|
+
for location in spec.submodule_search_locations:
|
|
126
|
+
package_root = Path(location)
|
|
127
|
+
if not package_root.exists() or not package_root.is_dir():
|
|
128
|
+
continue
|
|
129
|
+
candidates = [
|
|
130
|
+
path for path in package_root.rglob(USECLI_CONFIG_TOML) if path.exists()
|
|
131
|
+
]
|
|
132
|
+
if candidates:
|
|
133
|
+
candidates.sort(key=lambda path: (len(path.parts), str(path)))
|
|
134
|
+
return candidates[0]
|
|
135
|
+
return None
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _find_usecli_config_for_console_script() -> Path | None:
|
|
139
|
+
command_name = os.path.basename(sys.argv[0]) if sys.argv else ""
|
|
140
|
+
if not command_name:
|
|
141
|
+
return None
|
|
142
|
+
try:
|
|
143
|
+
distributions = importlib.metadata.distributions()
|
|
144
|
+
except Exception:
|
|
145
|
+
return None
|
|
146
|
+
for dist in distributions:
|
|
147
|
+
try:
|
|
148
|
+
entry_points = dist.entry_points
|
|
149
|
+
except Exception:
|
|
150
|
+
continue
|
|
151
|
+
for entry_point in entry_points:
|
|
152
|
+
if entry_point.group != "console_scripts":
|
|
153
|
+
continue
|
|
154
|
+
if entry_point.name != command_name:
|
|
155
|
+
continue
|
|
156
|
+
metadata = dist.metadata
|
|
157
|
+
dist_name = ""
|
|
158
|
+
if "Name" in metadata:
|
|
159
|
+
dist_name = metadata["Name"]
|
|
160
|
+
elif "name" in metadata:
|
|
161
|
+
dist_name = metadata["name"]
|
|
162
|
+
candidates: list[str] = []
|
|
163
|
+
if dist_name:
|
|
164
|
+
candidates.append(dist_name)
|
|
165
|
+
normalized = dist_name.replace("-", "_")
|
|
166
|
+
if normalized not in candidates:
|
|
167
|
+
candidates.append(normalized)
|
|
168
|
+
for package_name in candidates:
|
|
169
|
+
match = _find_usecli_config_in_named_package(package_name)
|
|
170
|
+
if match:
|
|
171
|
+
return match
|
|
172
|
+
return None
|
|
173
|
+
|
|
174
|
+
|
|
109
175
|
def _is_preferred_package_path(path: Path) -> bool:
|
|
110
|
-
return any(part in
|
|
176
|
+
return any(part in _SKIP_DIRS for part in path.parts)
|
|
111
177
|
|
|
112
178
|
|
|
113
179
|
def _is_within_usecli_package(start_dir: Path) -> bool:
|
|
@@ -132,10 +198,6 @@ def _find_project_root(start_dir: Path | None = None) -> Path | None:
|
|
|
132
198
|
current = start_dir.resolve()
|
|
133
199
|
git_root: Path | None = None
|
|
134
200
|
|
|
135
|
-
package_match = _find_usecli_config_in_package()
|
|
136
|
-
if package_match and _is_preferred_package_path(package_match):
|
|
137
|
-
return package_match.parent
|
|
138
|
-
|
|
139
201
|
while True:
|
|
140
202
|
pyproject_path = current / PYPROJECT_TOML
|
|
141
203
|
if pyproject_path.exists():
|
|
@@ -156,12 +218,14 @@ def _find_project_root(start_dir: Path | None = None) -> Path | None:
|
|
|
156
218
|
current = parent
|
|
157
219
|
|
|
158
220
|
search_root = git_root or start_dir.resolve()
|
|
159
|
-
config_match = _find_usecli_config_path(
|
|
160
|
-
search_root, start_dir, skip_venv=_is_within_usecli_package(start_dir)
|
|
161
|
-
)
|
|
221
|
+
config_match = _find_usecli_config_path(search_root, start_dir, skip_venv=True)
|
|
162
222
|
if config_match:
|
|
163
223
|
return config_match.parent
|
|
164
224
|
|
|
225
|
+
console_match = _find_usecli_config_for_console_script()
|
|
226
|
+
if console_match:
|
|
227
|
+
return console_match.parent
|
|
228
|
+
|
|
165
229
|
package_match = _find_usecli_config_in_package()
|
|
166
230
|
if package_match:
|
|
167
231
|
return package_match.parent
|
|
@@ -173,18 +237,17 @@ def _load_usecli_config(project_root: Path | None) -> dict[str, Any]:
|
|
|
173
237
|
if project_root is None:
|
|
174
238
|
return {}
|
|
175
239
|
|
|
176
|
-
package_match = _find_usecli_config_in_package()
|
|
177
|
-
if package_match and _is_preferred_package_path(package_match):
|
|
178
|
-
return _load_usecli_config_file(package_match)
|
|
179
|
-
|
|
180
240
|
config_path = project_root / USECLI_CONFIG_TOML
|
|
181
241
|
if not config_path.exists():
|
|
182
242
|
config_path = _find_usecli_config_path(
|
|
183
243
|
project_root,
|
|
184
244
|
project_root,
|
|
185
|
-
skip_venv=
|
|
245
|
+
skip_venv=True,
|
|
186
246
|
)
|
|
187
247
|
if not config_path or not config_path.exists():
|
|
248
|
+
console_match = _find_usecli_config_for_console_script()
|
|
249
|
+
if console_match:
|
|
250
|
+
return _load_usecli_config_file(console_match)
|
|
188
251
|
package_match = _find_usecli_config_in_package()
|
|
189
252
|
if package_match:
|
|
190
253
|
config_path = package_match
|
|
@@ -5,7 +5,9 @@ Handles loading and accessing configuration from project-level files.
|
|
|
5
5
|
|
|
6
6
|
from __future__ import annotations
|
|
7
7
|
|
|
8
|
+
import importlib.metadata
|
|
8
9
|
import importlib.util
|
|
10
|
+
import os
|
|
9
11
|
import sys
|
|
10
12
|
from pathlib import Path
|
|
11
13
|
from typing import Any
|
|
@@ -59,8 +61,15 @@ def _dedupe_items(items: list[str]) -> list[str]:
|
|
|
59
61
|
class ConfigManager:
|
|
60
62
|
"""Manages useCli configuration from project-level files."""
|
|
61
63
|
|
|
62
|
-
_SKIP_DIRS = {
|
|
63
|
-
|
|
64
|
+
_SKIP_DIRS = {
|
|
65
|
+
".venv",
|
|
66
|
+
"venv",
|
|
67
|
+
"site-packages",
|
|
68
|
+
"dist-packages",
|
|
69
|
+
"__pypackages__",
|
|
70
|
+
"pipx",
|
|
71
|
+
"venvs",
|
|
72
|
+
}
|
|
64
73
|
|
|
65
74
|
DEFAULT_CONFIG: dict[str, Any] = {
|
|
66
75
|
"title": "usecli",
|
|
@@ -109,8 +118,25 @@ class ConfigManager:
|
|
|
109
118
|
self.usecli_config_path: Path = usecli_config_path
|
|
110
119
|
self.start_dir: Path = start_dir
|
|
111
120
|
detected_root = find_project_root(start_dir)
|
|
112
|
-
if
|
|
113
|
-
|
|
121
|
+
if self.usecli_config_path.exists():
|
|
122
|
+
config_parent = self.usecli_config_path.parent
|
|
123
|
+
if detected_root is None:
|
|
124
|
+
detected_root = config_parent
|
|
125
|
+
else:
|
|
126
|
+
root_config = detected_root / USECLI_CONFIG_TOML
|
|
127
|
+
if self.usecli_config_path.resolve() != root_config.resolve():
|
|
128
|
+
detected_root = config_parent
|
|
129
|
+
else:
|
|
130
|
+
try:
|
|
131
|
+
self.usecli_config_path.relative_to(detected_root)
|
|
132
|
+
except ValueError:
|
|
133
|
+
detected_root = config_parent
|
|
134
|
+
else:
|
|
135
|
+
if any(
|
|
136
|
+
part in self._SKIP_DIRS
|
|
137
|
+
for part in self.usecli_config_path.parts
|
|
138
|
+
):
|
|
139
|
+
detected_root = config_parent
|
|
114
140
|
self.project_root: Path = (detected_root or start_dir).resolve()
|
|
115
141
|
self._config: dict[str, Any] = {}
|
|
116
142
|
self._overrides: dict[str, Any] = {}
|
|
@@ -170,10 +196,6 @@ class ConfigManager:
|
|
|
170
196
|
def _find_usecli_config(cls, start_dir: Path) -> Path | None:
|
|
171
197
|
current = start_dir.resolve()
|
|
172
198
|
|
|
173
|
-
package_match = cls._find_usecli_config_in_package()
|
|
174
|
-
if package_match and cls._is_preferred_package_path(package_match):
|
|
175
|
-
return package_match
|
|
176
|
-
|
|
177
199
|
while True:
|
|
178
200
|
config_path = current / USECLI_CONFIG_TOML
|
|
179
201
|
if config_path.exists():
|
|
@@ -184,17 +206,24 @@ class ConfigManager:
|
|
|
184
206
|
break
|
|
185
207
|
current = parent
|
|
186
208
|
|
|
187
|
-
in_usecli_package = cls._is_within_usecli_package(start_dir)
|
|
188
|
-
if in_usecli_package and package_match:
|
|
189
|
-
return package_match
|
|
190
|
-
|
|
191
209
|
search_root = find_project_root(start_dir) or start_dir.resolve()
|
|
192
210
|
recursive_match = cls._find_usecli_config_in_tree(
|
|
193
|
-
search_root, start_dir, skip_venv=
|
|
211
|
+
search_root, start_dir, skip_venv=True
|
|
194
212
|
)
|
|
195
213
|
if recursive_match:
|
|
196
214
|
return recursive_match
|
|
197
215
|
|
|
216
|
+
console_match = cls._find_usecli_config_for_console_script()
|
|
217
|
+
if console_match:
|
|
218
|
+
return console_match
|
|
219
|
+
|
|
220
|
+
if not cls._is_within_usecli_package(start_dir):
|
|
221
|
+
return None
|
|
222
|
+
|
|
223
|
+
package_match = cls._find_usecli_config_in_package()
|
|
224
|
+
if package_match:
|
|
225
|
+
return package_match
|
|
226
|
+
|
|
198
227
|
return cls._find_usecli_config_on_sys_path()
|
|
199
228
|
|
|
200
229
|
@staticmethod
|
|
@@ -253,9 +282,65 @@ class ConfigManager:
|
|
|
253
282
|
return candidates[0]
|
|
254
283
|
return None
|
|
255
284
|
|
|
285
|
+
@classmethod
|
|
286
|
+
def _find_usecli_config_in_named_package(cls, package_name: str) -> Path | None:
|
|
287
|
+
if not package_name:
|
|
288
|
+
return None
|
|
289
|
+
spec = importlib.util.find_spec(package_name)
|
|
290
|
+
if spec is None or not spec.submodule_search_locations:
|
|
291
|
+
return None
|
|
292
|
+
for location in spec.submodule_search_locations:
|
|
293
|
+
package_root = Path(location)
|
|
294
|
+
if not package_root.exists() or not package_root.is_dir():
|
|
295
|
+
continue
|
|
296
|
+
candidates = [
|
|
297
|
+
path for path in package_root.rglob(USECLI_CONFIG_TOML) if path.exists()
|
|
298
|
+
]
|
|
299
|
+
if candidates:
|
|
300
|
+
candidates.sort(key=lambda path: (len(path.parts), str(path)))
|
|
301
|
+
return candidates[0]
|
|
302
|
+
return None
|
|
303
|
+
|
|
304
|
+
@classmethod
|
|
305
|
+
def _find_usecli_config_for_console_script(cls) -> Path | None:
|
|
306
|
+
command_name = os.path.basename(sys.argv[0]) if sys.argv else ""
|
|
307
|
+
if not command_name:
|
|
308
|
+
return None
|
|
309
|
+
try:
|
|
310
|
+
distributions = importlib.metadata.distributions()
|
|
311
|
+
except Exception:
|
|
312
|
+
return None
|
|
313
|
+
for dist in distributions:
|
|
314
|
+
try:
|
|
315
|
+
entry_points = dist.entry_points
|
|
316
|
+
except Exception:
|
|
317
|
+
continue
|
|
318
|
+
for entry_point in entry_points:
|
|
319
|
+
if entry_point.group != "console_scripts":
|
|
320
|
+
continue
|
|
321
|
+
if entry_point.name != command_name:
|
|
322
|
+
continue
|
|
323
|
+
metadata = dist.metadata
|
|
324
|
+
dist_name = ""
|
|
325
|
+
if "Name" in metadata:
|
|
326
|
+
dist_name = metadata["Name"]
|
|
327
|
+
elif "name" in metadata:
|
|
328
|
+
dist_name = metadata["name"]
|
|
329
|
+
candidates = []
|
|
330
|
+
if dist_name:
|
|
331
|
+
candidates.append(dist_name)
|
|
332
|
+
normalized = dist_name.replace("-", "_")
|
|
333
|
+
if normalized not in candidates:
|
|
334
|
+
candidates.append(normalized)
|
|
335
|
+
for package_name in candidates:
|
|
336
|
+
match = cls._find_usecli_config_in_named_package(package_name)
|
|
337
|
+
if match:
|
|
338
|
+
return match
|
|
339
|
+
return None
|
|
340
|
+
|
|
256
341
|
@staticmethod
|
|
257
342
|
def _is_preferred_package_path(path: Path) -> bool:
|
|
258
|
-
return any(part in ConfigManager.
|
|
343
|
+
return any(part in ConfigManager._SKIP_DIRS for part in path.parts)
|
|
259
344
|
|
|
260
345
|
@staticmethod
|
|
261
346
|
def _is_within_usecli_package(start_dir: Path) -> bool:
|
|
@@ -433,10 +518,6 @@ def find_project_root(start_dir: Path | None = None) -> Path | None:
|
|
|
433
518
|
|
|
434
519
|
current = start_dir.resolve()
|
|
435
520
|
|
|
436
|
-
package_match = ConfigManager._find_usecli_config_in_package()
|
|
437
|
-
if package_match and ConfigManager._is_preferred_package_path(package_match):
|
|
438
|
-
return package_match.parent
|
|
439
|
-
|
|
440
521
|
git_root: Path | None = None
|
|
441
522
|
while True:
|
|
442
523
|
pyproject_path = current / PYPROJECT_TOML
|
|
@@ -461,11 +542,16 @@ def find_project_root(start_dir: Path | None = None) -> Path | None:
|
|
|
461
542
|
config_match = ConfigManager._find_usecli_config_in_tree(
|
|
462
543
|
search_root,
|
|
463
544
|
start_dir,
|
|
464
|
-
skip_venv=
|
|
545
|
+
skip_venv=True,
|
|
465
546
|
)
|
|
466
547
|
if config_match:
|
|
467
548
|
return config_match.parent
|
|
468
549
|
|
|
550
|
+
if ConfigManager._is_within_usecli_package(start_dir):
|
|
551
|
+
package_match = ConfigManager._find_usecli_config_in_package()
|
|
552
|
+
if package_match:
|
|
553
|
+
return package_match.parent
|
|
554
|
+
|
|
469
555
|
return git_root
|
|
470
556
|
|
|
471
557
|
|
|
@@ -3,9 +3,9 @@ title = "usecli"
|
|
|
3
3
|
title_file = ""
|
|
4
4
|
title_font = "ansi_shadow"
|
|
5
5
|
description = "A custom CLI tool"
|
|
6
|
-
commands_dir = "
|
|
7
|
-
templates_dir = "
|
|
8
|
-
themes_dir = "
|
|
6
|
+
commands_dir = "cli/commands/custom"
|
|
7
|
+
templates_dir = "cli/templates"
|
|
8
|
+
themes_dir = "cli/themes"
|
|
9
9
|
theme = "default"
|
|
10
10
|
hide_init = false
|
|
11
11
|
hide_inspire = false
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{usecli-0.1.36 → usecli-0.1.38}/src/usecli/cli/commands/defaults/base/internal/fzf_command.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|