Skip to content

Commit f56691e

Browse files
committed
[ADD, REFACTOR] refactor cli modules, adjust template metadata injection logic
1 parent eaf88cb commit f56691e

File tree

19 files changed

+459
-250
lines changed

19 files changed

+459
-250
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# test workspace
2+
tests/temp_test_workspace/
3+
14
.pdm-python
25
### VisualStudioCode template
36
.vscode/*

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ repos:
2828

2929
- id: test
3030
name: test
31-
entry: bash scripts/fetch-and-test.sh
31+
entry: bash scripts/test.sh
3232
language: system
3333
pass_filenames: false
3434

File renamed without changes.

scripts/test.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/usr/bin/env bash
2+
3+
set -e
4+
set -x
5+
6+
pytest

src/fastapi_fastkit/backend.py

Lines changed: 0 additions & 167 deletions
This file was deleted.

src/fastapi_fastkit/backend/__init__.py

Whitespace-only changes.

src/fastapi_fastkit/backend/main.py

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
# --------------------------------------------------------------------------
2+
# The Module defines backend operations for FastAPI-fastkit CLI.
3+
#
4+
# @author bnbong bbbong9@gmail.com
5+
# --------------------------------------------------------------------------
6+
import os
7+
import subprocess
8+
9+
from fastapi_fastkit import console
10+
from fastapi_fastkit.core.exceptions import BackendExceptions, TemplateExceptions
11+
from fastapi_fastkit.core.settings import settings
12+
from fastapi_fastkit.utils.main import print_error, print_info, print_success
13+
14+
15+
def find_template_core_modules(project_dir: str) -> dict[str, str]:
16+
"""
17+
Find core module files in the template project structure.
18+
Returns a dictionary with paths to main.py, setup.py, and config files.
19+
"""
20+
core_modules = {"main": "", "setup": "", "config": ""}
21+
template_config = settings.TEMPLATE_PATHS["config"]
22+
23+
# Find main.py
24+
for path in settings.TEMPLATE_PATHS["main"]:
25+
full_path = os.path.join(project_dir, path)
26+
if os.path.exists(full_path):
27+
core_modules["main"] = full_path
28+
break
29+
30+
# Find setup.py
31+
for path in settings.TEMPLATE_PATHS["setup"]:
32+
full_path = os.path.join(project_dir, path)
33+
if os.path.exists(full_path):
34+
core_modules["setup"] = full_path
35+
break
36+
37+
# Find config files (settings.py or config.py)
38+
if isinstance(template_config, dict):
39+
for config_file in template_config.get("files", []):
40+
for base_path in template_config.get("paths", []):
41+
full_path = os.path.join(project_dir, base_path, config_file)
42+
if os.path.exists(full_path):
43+
core_modules["config"] = full_path
44+
break
45+
if core_modules["config"]:
46+
break
47+
48+
return core_modules
49+
50+
51+
def inject_project_metadata(
52+
target_dir: str,
53+
project_name: str,
54+
author: str,
55+
author_email: str,
56+
description: str,
57+
) -> None:
58+
"""
59+
Inject project metadata into template files after template conversion.
60+
"""
61+
try:
62+
core_modules = find_template_core_modules(target_dir)
63+
64+
# Inject metadata to main.py
65+
if core_modules["main"]:
66+
with open(core_modules["main"], "r+") as f:
67+
content = f.read()
68+
content = content.replace("app_title", f'"{project_name}"')
69+
content = content.replace("app_description", f'"{description}"')
70+
f.seek(0)
71+
f.write(content)
72+
f.truncate()
73+
74+
# Inject metadata to setup.py
75+
if core_modules["setup"]:
76+
with open(core_modules["setup"], "r+") as f:
77+
content = f.read()
78+
content = content.replace("<project_name>", project_name, 1)
79+
content = content.replace("<description>", description, 1)
80+
content = content.replace("<author>", author, 1)
81+
content = content.replace("<author_email>", author_email, 1)
82+
f.seek(0)
83+
f.write(content)
84+
f.truncate()
85+
86+
# Inject metadata to config files
87+
if core_modules["config"]:
88+
with open(core_modules["config"], "r+") as f:
89+
content = f.read()
90+
content = content.replace("<project_name>", project_name)
91+
content = content.replace("<description>", description)
92+
f.seek(0)
93+
f.write(content)
94+
f.truncate()
95+
96+
except Exception as e:
97+
print_error(f"Error during metadata injection: {e}")
98+
raise TemplateExceptions("Failed to inject metadata")
99+
100+
101+
def create_venv(project_dir: str) -> str:
102+
"""Create a virtual environment."""
103+
try:
104+
with console.status("[bold green]Setting up project environment..."):
105+
console.print("[yellow]Creating virtual environment...[/yellow]")
106+
venv_path = os.path.join(project_dir, ".venv")
107+
subprocess.run(["python", "-m", "venv", venv_path], check=True)
108+
109+
if os.name == "nt":
110+
activate_venv = f" {os.path.join(venv_path, 'Scripts', 'activate.bat')}"
111+
else:
112+
activate_venv = f" source {os.path.join(venv_path, 'bin', 'activate')}"
113+
print_info(
114+
"venv created at "
115+
+ venv_path
116+
+ "\nTo activate the virtual environment, run:\n\n"
117+
+ activate_venv,
118+
)
119+
return venv_path
120+
121+
except Exception as e:
122+
print_error(f"Error during venv creation: {e}")
123+
raise BackendExceptions("Failed to create venv")
124+
125+
126+
def install_dependencies(project_dir: str, venv_path: str) -> None:
127+
"""Install project dependencies in the virtual environment."""
128+
try:
129+
if os.name == "nt": # Windows
130+
pip_path = os.path.join(venv_path, "Scripts", "pip")
131+
else: # Linux/Mac
132+
pip_path = os.path.join(venv_path, "bin", "pip")
133+
134+
with console.status("[bold green]Installing dependencies..."):
135+
subprocess.run(
136+
[pip_path, "install", "-r", "requirements.txt"],
137+
cwd=project_dir,
138+
check=True,
139+
)
140+
141+
except Exception as e:
142+
print_error(f"Error during dependency installation: {e}")
143+
raise BackendExceptions("Failed to install dependencies")
144+
145+
146+
# TODO : modify this function
147+
# def read_template_stack() -> Union[list, None]:
148+
# pass

0 commit comments

Comments
 (0)