1
+ import json
1
2
import os
2
3
import sys
3
4
import tempfile
5
+ from pathlib import Path
4
6
5
7
import click
6
8
@@ -24,15 +26,80 @@ def cli():
24
26
pass
25
27
26
28
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
+
27
85
@cli .command ()
28
86
@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 ):
30
96
"""
31
97
Initialize a new Preswald project.
32
98
33
99
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.
34
101
"""
35
- from preswald .utils import generate_slug , read_template
102
+ from preswald .utils import generate_slug
36
103
37
104
try :
38
105
os .makedirs (name , exist_ok = True )
@@ -53,34 +120,36 @@ def init(name):
53
120
with as_file (files ("preswald" ).joinpath ("static/logo.png" )) as path :
54
121
shutil .copy2 (path , os .path .join (name , "images" , "logo.png" ))
55
122
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
73
135
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 )
76
138
77
139
# Track initialization
78
140
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
+ },
80
147
)
81
148
82
149
click .echo (f"Initialized a new Preswald project in '{ name } /' 🎉!" )
83
150
click .echo (f"Project slug: { project_slug } " )
151
+ if template :
152
+ click .echo (f"Using template: { template } " )
84
153
except Exception as e :
85
154
click .echo (f"Error initializing project: { e } ❌" )
86
155
@@ -182,7 +251,7 @@ def run(port, log_level, disable_new_tab):
182
251
default = None ,
183
252
help = "Set the logging level (overrides config file)" ,
184
253
)
185
- def deploy (script , target , port , log_level , github , api_key ): # noqa: C901
254
+ def deploy (script , target , port , log_level , github , api_key ):
186
255
"""
187
256
Deploy your Preswald app.
188
257
@@ -325,6 +394,7 @@ def stop(target):
325
394
except Exception :
326
395
sys .exit (1 )
327
396
397
+
328
398
@cli .command ()
329
399
@click .pass_context
330
400
def tutorial (ctx ):
0 commit comments