Skip to content

Commit 7ff9d5a

Browse files
authored
refactor: update template handling to support new directory structure - Remove backward compatibility code - Add support for common + template-specific/default templates - Update read_template function to handle template_id parameter - Clean up imports and formatting (#700)
1 parent 2253446 commit 7ff9d5a

14 files changed

+196
-40
lines changed

preswald/cli.py

Lines changed: 93 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
import json
12
import os
23
import sys
34
import tempfile
5+
from pathlib import Path
46

57
import click
68

@@ -24,15 +26,80 @@ def cli():
2426
pass
2527

2628

29+
def get_available_templates():
30+
"""Get available templates from templates.json"""
31+
try:
32+
templates_path = Path(__file__).parent / "templates" / "templates.json"
33+
with open(templates_path) as f:
34+
return json.load(f)["templates"]
35+
except Exception:
36+
return []
37+
38+
39+
def copy_template_files(template_dir, target_dir, project_slug):
40+
"""Copy files from template directory to target directory, handling special cases."""
41+
import shutil
42+
43+
# Ensure data directory exists
44+
os.makedirs(os.path.join(target_dir, "data"), exist_ok=True)
45+
46+
# First copy common files
47+
common_dir = Path(__file__).parent / "templates" / "common"
48+
if common_dir.exists():
49+
for file_path in common_dir.glob("**/*"):
50+
if file_path.is_file():
51+
rel_path = file_path.relative_to(common_dir)
52+
# Remove .template extension from the target filename
53+
target_filename = str(rel_path).replace(".template", "")
54+
target_path = os.path.join(target_dir, target_filename)
55+
os.makedirs(os.path.dirname(target_path), exist_ok=True)
56+
shutil.copy2(file_path, target_path)
57+
58+
# Then copy template-specific files
59+
for file_path in template_dir.glob("**/*"):
60+
if file_path.is_file():
61+
rel_path = file_path.relative_to(template_dir)
62+
# Remove .template extension from the target filename
63+
target_filename = str(rel_path).replace(".template", "")
64+
65+
# Handle special cases for data files
66+
if target_filename == "sample.csv":
67+
target_path = os.path.join(target_dir, "data", "sample.csv")
68+
else:
69+
target_path = os.path.join(target_dir, target_filename)
70+
71+
os.makedirs(os.path.dirname(target_path), exist_ok=True)
72+
shutil.copy2(file_path, target_path)
73+
74+
# Update preswald.toml with project slug if it exists
75+
if target_filename == "preswald.toml":
76+
with open(target_path) as f:
77+
content = f.read()
78+
content = content.replace(
79+
'slug = "preswald-project"', f'slug = "{project_slug}"'
80+
)
81+
with open(target_path, "w") as f:
82+
f.write(content)
83+
84+
2785
@cli.command()
2886
@click.argument("name", default="preswald_project")
29-
def init(name):
87+
@click.option(
88+
"--template",
89+
"-t",
90+
help="Template ID to use for initialization",
91+
type=click.Choice(
92+
[t["id"] for t in get_available_templates()], case_sensitive=False
93+
),
94+
)
95+
def init(name, template):
3096
"""
3197
Initialize a new Preswald project.
3298
3399
This creates a directory with boilerplate files like `hello.py` and `preswald.toml`.
100+
If a template is specified, it will use the template's files instead of the default ones.
34101
"""
35-
from preswald.utils import generate_slug, read_template
102+
from preswald.utils import generate_slug
36103

37104
try:
38105
os.makedirs(name, exist_ok=True)
@@ -53,34 +120,36 @@ def init(name):
53120
with as_file(files("preswald").joinpath("static/logo.png")) as path:
54121
shutil.copy2(path, os.path.join(name, "images", "logo.png"))
55122

56-
file_templates = {
57-
"hello.py": "hello.py",
58-
"preswald.toml": "preswald.toml",
59-
"secrets.toml": "secrets.toml",
60-
".gitignore": "gitignore",
61-
"pyproject.toml": "pyproject.toml",
62-
"data/sample.csv": "sample.csv",
63-
}
64-
65-
for file_name, template_name in file_templates.items():
66-
content = read_template(template_name)
67-
68-
# Replace the default slug in preswald.toml with the generated one
69-
if file_name == "preswald.toml":
70-
content = content.replace(
71-
'slug = "preswald-project"', f'slug = "{project_slug}"'
72-
)
123+
if template:
124+
# Initialize from template
125+
template_dir = Path(__file__).parent / "templates" / template
126+
if not template_dir.exists():
127+
click.echo(f"Error: Template directory not found for '{template}' ❌")
128+
return
129+
else:
130+
# Use default template
131+
template_dir = Path(__file__).parent / "templates" / "default"
132+
if not template_dir.exists():
133+
click.echo("Error: Default template directory not found ❌")
134+
return
73135

74-
with open(os.path.join(name, file_name), "w") as f:
75-
f.write(content)
136+
# Copy template files
137+
copy_template_files(template_dir, name, project_slug)
76138

77139
# Track initialization
78140
telemetry.track_command(
79-
"init", {"project_name": name, "project_slug": project_slug}
141+
"init",
142+
{
143+
"project_name": name,
144+
"project_slug": project_slug,
145+
"template": template or "default",
146+
},
80147
)
81148

82149
click.echo(f"Initialized a new Preswald project in '{name}/' 🎉!")
83150
click.echo(f"Project slug: {project_slug}")
151+
if template:
152+
click.echo(f"Using template: {template}")
84153
except Exception as e:
85154
click.echo(f"Error initializing project: {e} ❌")
86155

@@ -182,7 +251,7 @@ def run(port, log_level, disable_new_tab):
182251
default=None,
183252
help="Set the logging level (overrides config file)",
184253
)
185-
def deploy(script, target, port, log_level, github, api_key): # noqa: C901
254+
def deploy(script, target, port, log_level, github, api_key):
186255
"""
187256
Deploy your Preswald app.
188257
@@ -325,6 +394,7 @@ def stop(target):
325394
except Exception:
326395
sys.exit(1)
327396

397+
328398
@cli.command()
329399
@click.pass_context
330400
def tutorial(ctx):

0 commit comments

Comments
 (0)