devit-cli 0.1.3__tar.gz → 0.1.5__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.
- {devit_cli-0.1.3/devit_cli.egg-info → devit_cli-0.1.5}/PKG-INFO +1 -1
- {devit_cli-0.1.3 → devit_cli-0.1.5/devit_cli.egg-info}/PKG-INFO +1 -1
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/__init__.py +1 -1
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/commands/archive.py +35 -27
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/commands/env.py +24 -16
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/commands/find.py +20 -4
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/commands/init.py +30 -8
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/commands/run.py +8 -1
- {devit_cli-0.1.3 → devit_cli-0.1.5}/pyproject.toml +1 -1
- {devit_cli-0.1.3 → devit_cli-0.1.5}/LICENSE +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/README.md +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/_devkit_entry.py +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devit_cli.egg-info/SOURCES.txt +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devit_cli.egg-info/dependency_links.txt +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devit_cli.egg-info/entry_points.txt +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devit_cli.egg-info/requires.txt +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devit_cli.egg-info/top_level.txt +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/commands/__init__.py +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/commands/clean.py +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/commands/info.py +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/main.py +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/aws/.gitignore +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/aws/README.md +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/aws/requirements.txt +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/aws/scripts/__init__.py +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/aws/scripts/ec2.py +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/aws/scripts/main.py +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/aws/scripts/s3.py +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/aws/tests/test_scripts.py +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/django/.gitignore +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/django/README.md +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/django/apps/__init__.py +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/django/apps/core/__init__.py +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/django/apps/core/apps.py +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/django/apps/core/urls.py +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/django/apps/core/views.py +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/django/manage.py +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/django/requirements.txt +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/django/{{module_name}}/__init__.py +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/django/{{module_name}}/settings.py +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/django/{{module_name}}/urls.py +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/django/{{module_name}}/wsgi.py +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/fastapi/.gitignore +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/fastapi/README.md +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/fastapi/app/__init__.py +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/fastapi/app/routers/__init__.py +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/fastapi/app/routers/health.py +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/fastapi/main.py +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/fastapi/requirements.txt +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/fastapi/tests/test_api.py +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/package/.gitignore +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/package/README.md +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/package/pyproject.toml +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/package/tests/test_core.py +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/package/{{module_name}}/__init__.py +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/package/{{module_name}}/core.py +0 -0
- {devit_cli-0.1.3 → devit_cli-0.1.5}/setup.cfg +0 -0
|
@@ -79,20 +79,24 @@ def zip_cmd(output, sources, level, exclude):
|
|
|
79
79
|
|
|
80
80
|
compress = zipfile.ZIP_DEFLATED if level > 0 else zipfile.ZIP_STORED
|
|
81
81
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
82
|
+
try:
|
|
83
|
+
with Progress(
|
|
84
|
+
TextColumn("[bold blue]{task.description}"),
|
|
85
|
+
BarColumn(),
|
|
86
|
+
TaskProgressColumn(),
|
|
87
|
+
FileSizeColumn(),
|
|
88
|
+
TransferSpeedColumn(),
|
|
89
|
+
TimeRemainingColumn(),
|
|
90
|
+
console=console,
|
|
91
|
+
) as progress:
|
|
92
|
+
task = progress.add_task("Compressing", total=total_size)
|
|
93
|
+
with zipfile.ZipFile(out_path, "w", compression=compress, compresslevel=level) as zf:
|
|
94
|
+
for fpath, arc_name in all_files:
|
|
95
|
+
zf.write(fpath, arc_name)
|
|
96
|
+
progress.advance(task, fpath.stat().st_size)
|
|
97
|
+
except OSError as e:
|
|
98
|
+
console.print(f"[red]✗[/red] Failed to create archive: {e}")
|
|
99
|
+
raise click.Abort()
|
|
96
100
|
|
|
97
101
|
final_size = out_path.stat().st_size
|
|
98
102
|
ratio = (1 - final_size / total_size) * 100 if total_size else 0
|
|
@@ -149,18 +153,22 @@ def unzip_cmd(archive, destination, list_only):
|
|
|
149
153
|
dest.mkdir(parents=True, exist_ok=True)
|
|
150
154
|
total_size = sum(m.file_size for m in members if not m.is_dir())
|
|
151
155
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
156
|
+
try:
|
|
157
|
+
with Progress(
|
|
158
|
+
TextColumn("[bold blue]{task.description}"),
|
|
159
|
+
BarColumn(),
|
|
160
|
+
TaskProgressColumn(),
|
|
161
|
+
FileSizeColumn(),
|
|
162
|
+
TimeRemainingColumn(),
|
|
163
|
+
console=console,
|
|
164
|
+
) as progress:
|
|
165
|
+
task = progress.add_task("Extracting", total=total_size)
|
|
166
|
+
for member in members:
|
|
167
|
+
zf.extract(member, dest)
|
|
168
|
+
if not member.is_dir():
|
|
169
|
+
progress.advance(task, member.file_size)
|
|
170
|
+
except OSError as e:
|
|
171
|
+
console.print(f"[red]✗[/red] Extraction failed: {e}")
|
|
172
|
+
raise click.Abort()
|
|
165
173
|
|
|
166
174
|
console.print(f"[green]✔[/green] Extracted [bold]{len(members)}[/bold] items to [cyan]{dest}[/cyan]")
|
|
@@ -14,7 +14,11 @@ console = Console()
|
|
|
14
14
|
def _load_dotenv(path: Path) -> dict[str, str]:
|
|
15
15
|
"""Parse a .env file into a dict."""
|
|
16
16
|
result = {}
|
|
17
|
-
|
|
17
|
+
try:
|
|
18
|
+
content = path.read_text(encoding="utf-8")
|
|
19
|
+
except OSError as e:
|
|
20
|
+
raise click.ClickException(f"Cannot read {path}: {e}")
|
|
21
|
+
for line in content.splitlines():
|
|
18
22
|
line = line.strip()
|
|
19
23
|
if not line or line.startswith("#"):
|
|
20
24
|
continue
|
|
@@ -93,21 +97,25 @@ def env_export(output, filter_str, fmt):
|
|
|
93
97
|
|
|
94
98
|
out = Path(output)
|
|
95
99
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
100
|
+
try:
|
|
101
|
+
if fmt == "dotenv":
|
|
102
|
+
lines = [f'{k}="{v}"' for k, v in sorted(vars_dict.items())]
|
|
103
|
+
out.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
|
104
|
+
elif fmt == "json":
|
|
105
|
+
out.write_text(json.dumps(vars_dict, indent=2), encoding="utf-8")
|
|
106
|
+
elif fmt == "shell":
|
|
107
|
+
lines = [f"export {k}={json.dumps(v)}" for k, v in sorted(vars_dict.items())]
|
|
108
|
+
out.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
|
109
|
+
elif fmt == "powershell":
|
|
110
|
+
lines = [f'$env:{k} = {json.dumps(v)}' for k, v in sorted(vars_dict.items())]
|
|
111
|
+
out.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
|
112
|
+
elif fmt == "cmd":
|
|
113
|
+
# Values with special CMD characters are quoted; newlines replaced with space
|
|
114
|
+
lines = [f"set {k}={v.replace(chr(10), ' ')}" for k, v in sorted(vars_dict.items())]
|
|
115
|
+
out.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
|
116
|
+
except OSError as e:
|
|
117
|
+
console.print(f"[red]✗[/red] Cannot write to [bold]{out}[/bold]: {e}")
|
|
118
|
+
raise SystemExit(1)
|
|
111
119
|
|
|
112
120
|
console.print(f"[green]✔[/green] Exported [bold]{len(vars_dict)}[/bold] variables to [cyan]{out}[/cyan]")
|
|
113
121
|
|
|
@@ -60,10 +60,26 @@ def find(pattern, search_dir, ext, min_size, max_size, newer_than, older_than, l
|
|
|
60
60
|
devkit find --dirs-only "src"
|
|
61
61
|
"""
|
|
62
62
|
root = Path(search_dir).resolve()
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
try:
|
|
64
|
+
min_bytes = _parse_size(min_size) if min_size else None
|
|
65
|
+
except (ValueError, TypeError):
|
|
66
|
+
console.print(f"[red]✗[/red] Invalid --min-size value: [bold]{min_size}[/bold] (example: 10kb, 2mb)")
|
|
67
|
+
raise SystemExit(1)
|
|
68
|
+
try:
|
|
69
|
+
max_bytes = _parse_size(max_size) if max_size else None
|
|
70
|
+
except (ValueError, TypeError):
|
|
71
|
+
console.print(f"[red]✗[/red] Invalid --max-size value: [bold]{max_size}[/bold] (example: 10kb, 2mb)")
|
|
72
|
+
raise SystemExit(1)
|
|
73
|
+
try:
|
|
74
|
+
newer_cutoff = (datetime.now() - timedelta(days=int(newer_than))).timestamp() if newer_than else None
|
|
75
|
+
except (ValueError, TypeError):
|
|
76
|
+
console.print(f"[red]✗[/red] --newer-than must be a whole number of days, got: [bold]{newer_than}[/bold]")
|
|
77
|
+
raise SystemExit(1)
|
|
78
|
+
try:
|
|
79
|
+
older_cutoff = (datetime.now() - timedelta(days=int(older_than))).timestamp() if older_than else None
|
|
80
|
+
except (ValueError, TypeError):
|
|
81
|
+
console.print(f"[red]✗[/red] --older-than must be a whole number of days, got: [bold]{older_than}[/bold]")
|
|
82
|
+
raise SystemExit(1)
|
|
67
83
|
|
|
68
84
|
table = Table(title=f"Search: [cyan]{pattern}[/cyan] in [dim]{root}[/dim]",
|
|
69
85
|
show_lines=False, expand=False)
|
|
@@ -50,7 +50,11 @@ def _create_venv(project_dir: Path, python_version: str) -> None:
|
|
|
50
50
|
"""Create a native venv inside project_dir."""
|
|
51
51
|
with Progress(SpinnerColumn(), TextColumn("[bold green]Creating venv..."), transient=True) as p:
|
|
52
52
|
p.add_task("")
|
|
53
|
-
|
|
53
|
+
try:
|
|
54
|
+
_run([sys.executable, "-m", "venv", ".venv"], cwd=project_dir)
|
|
55
|
+
except subprocess.CalledProcessError as e:
|
|
56
|
+
console.print(f"[red]✗[/red] Failed to create virtual environment.\n [dim]{e}[/dim]")
|
|
57
|
+
raise click.Abort()
|
|
54
58
|
console.print("[green]✔[/green] Virtual environment created at [cyan].venv/[/cyan]")
|
|
55
59
|
|
|
56
60
|
|
|
@@ -62,7 +66,11 @@ def _create_conda_env(project_dir: Path, name: str, python_version: str) -> None
|
|
|
62
66
|
return
|
|
63
67
|
with Progress(SpinnerColumn(), TextColumn(f"[bold green]Creating conda env '{name}'..."), transient=True) as p:
|
|
64
68
|
p.add_task("")
|
|
65
|
-
|
|
69
|
+
try:
|
|
70
|
+
_run([conda_bin, "create", "-n", name, f"python={python_version}", "-y"])
|
|
71
|
+
except subprocess.CalledProcessError as e:
|
|
72
|
+
console.print(f"[red]✗[/red] Failed to create conda environment.\n [dim]{e}[/dim]")
|
|
73
|
+
raise click.Abort()
|
|
66
74
|
console.print(f"[green]✔[/green] Conda environment [cyan]{name}[/cyan] created.")
|
|
67
75
|
|
|
68
76
|
|
|
@@ -276,10 +284,16 @@ def _copy_template(template_name: str, dest: Path, context: dict) -> None:
|
|
|
276
284
|
if src.is_dir():
|
|
277
285
|
dst.mkdir(parents=True, exist_ok=True)
|
|
278
286
|
else:
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
287
|
+
try:
|
|
288
|
+
text = src.read_text(encoding="utf-8")
|
|
289
|
+
for key, val in context.items():
|
|
290
|
+
text = text.replace("{{" + key + "}}", val)
|
|
291
|
+
_write_file(dst, text)
|
|
292
|
+
except (UnicodeDecodeError, ValueError):
|
|
293
|
+
# Binary file (e.g. .pyc, images) — copy as-is
|
|
294
|
+
import shutil as _shutil
|
|
295
|
+
dst.parent.mkdir(parents=True, exist_ok=True)
|
|
296
|
+
_shutil.copy2(src, dst)
|
|
283
297
|
|
|
284
298
|
|
|
285
299
|
# ---------------------------------------------------------------------------
|
|
@@ -405,7 +419,11 @@ def init(project_name, project_type, env_type, python_version, target_dir, yes):
|
|
|
405
419
|
if not overwrite:
|
|
406
420
|
raise click.Abort()
|
|
407
421
|
else:
|
|
408
|
-
|
|
422
|
+
try:
|
|
423
|
+
project_dir.mkdir(parents=True)
|
|
424
|
+
except PermissionError:
|
|
425
|
+
console.print(f"[red]✗[/red] Permission denied: cannot create [cyan]{project_dir}[/cyan]")
|
|
426
|
+
raise click.Abort()
|
|
409
427
|
|
|
410
428
|
# --- scaffold ---
|
|
411
429
|
ctx = {
|
|
@@ -423,7 +441,11 @@ def init(project_name, project_type, env_type, python_version, target_dir, yes):
|
|
|
423
441
|
py_path = env_decision["python_path"]
|
|
424
442
|
with Progress(SpinnerColumn(), TextColumn("[bold green]Creating .venv..."), transient=True) as p:
|
|
425
443
|
p.add_task("")
|
|
426
|
-
|
|
444
|
+
try:
|
|
445
|
+
_run([py_path, "-m", "venv", ".venv"], cwd=project_dir)
|
|
446
|
+
except subprocess.CalledProcessError as e:
|
|
447
|
+
console.print(f"[red]✗[/red] Failed to create virtual environment.\n [dim]{e}[/dim]")
|
|
448
|
+
raise click.Abort()
|
|
427
449
|
console.print("[green]✔[/green] Virtual environment created at [cyan].venv/[/cyan]")
|
|
428
450
|
elif kind == "conda_new":
|
|
429
451
|
_create_conda_env(project_dir, project_name, python_version)
|
|
@@ -104,7 +104,14 @@ def _run_cmd(cmd: list[str], cwd: Path) -> None:
|
|
|
104
104
|
f" Make sure [cyan]{exe}[/cyan] is installed and on your PATH."
|
|
105
105
|
)
|
|
106
106
|
raise SystemExit(1)
|
|
107
|
-
|
|
107
|
+
try:
|
|
108
|
+
result = subprocess.run(cmd, cwd=cwd)
|
|
109
|
+
except FileNotFoundError:
|
|
110
|
+
console.print(
|
|
111
|
+
f"[red]Command not found:[/red] [bold]{cmd[0]}[/bold]\n"
|
|
112
|
+
f" Make sure [cyan]{cmd[0]}[/cyan] is installed and on your PATH."
|
|
113
|
+
)
|
|
114
|
+
raise SystemExit(1)
|
|
108
115
|
if result.returncode != 0:
|
|
109
116
|
raise SystemExit(result.returncode)
|
|
110
117
|
|
|
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
|
{devit_cli-0.1.3 → devit_cli-0.1.5}/devkit_cli/templates/package/{{module_name}}/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|