11import os
22import re
33import shutil
4+ import subprocess
45from pathlib import Path
56
6- from click import ClickException , UsageError , command , echo , option
7-
8-
9- @command ()
10- @option ("--name" , required = True , help = "Project new name" )
11- @option ("--description" , required = True , help = "Project short description" )
12- @option ("--author" , required = True , help = "Author name" )
13- @option ("--email" , required = True , help = "Author email" )
14- @option ("--github" , required = True , help = "GitHub username" )
7+ from click import ClickException , UsageError , command , confirm , echo , option , secho
8+
9+
10+ def _get_git_config (key : str ) -> str :
11+ try :
12+ return subprocess .check_output (["/usr/bin/git" , "config" , key ], text = True ).strip () # noqa: S603
13+ except (subprocess .CalledProcessError , FileNotFoundError ):
14+ return ""
15+
16+
17+ def _get_default_github () -> str :
18+ # Try git config first
19+ username = _get_git_config ("github.user" ) or _get_git_config ("user.name" )
20+ if username and re .match (r"^[a-zA-Z0-9-]+$" , username ):
21+ return username
22+
23+ # Try to extract from remote URL
24+ try :
25+ url = subprocess .check_output ( # noqa: S603
26+ ["/usr/bin/git" , "remote" , "get-url" , "origin" ], text = True
27+ ).strip ()
28+ if "github.com" in url :
29+ if url .startswith ("https" ):
30+ return url .split ("/" )[- 2 ]
31+ if url .startswith ("git@" ):
32+ return url .split (":" )[- 1 ].split ("/" )[0 ]
33+ except (subprocess .CalledProcessError , FileNotFoundError ):
34+ pass
35+
36+ return ""
37+
38+
39+ @command (context_settings = {"help_option_names" : ["-h" , "--help" ]})
40+ @option (
41+ "--name" ,
42+ prompt = "Project name" ,
43+ default = lambda : Path .cwd ().name ,
44+ help = "Project new name" ,
45+ )
46+ @option (
47+ "--description" ,
48+ prompt = "Project description" ,
49+ default = "A Python project" ,
50+ help = "Project short description" ,
51+ )
52+ @option (
53+ "--author" ,
54+ prompt = "Author name" ,
55+ default = lambda : _get_git_config ("user.name" ),
56+ help = "Author name" ,
57+ )
58+ @option (
59+ "--email" ,
60+ prompt = "Author email" ,
61+ default = lambda : _get_git_config ("user.email" ),
62+ help = "Author email" ,
63+ )
64+ @option (
65+ "--github" ,
66+ prompt = "GitHub username" ,
67+ default = _get_default_github ,
68+ help = "GitHub username" ,
69+ )
1570def main (name : str , description : str , author : str , email : str , github : str ):
1671 # Validate inputs to prevent configuration injection
1772 for label , value in [
@@ -49,11 +104,23 @@ def toml_escape(s: str) -> str:
49104
50105 source = name .replace ("-" , "_" ).lower ()
51106
52- echo (f"Initializing project '{ name } ' (source: '{ source } ')..." )
107+ echo (f"\n Project Configuration:" )
108+ echo (f" Name: { name } " )
109+ echo (f" Source: { source } " )
110+ echo (f" Description: { description } " )
111+ echo (f" Author: { author } <{ email } >" )
112+ echo (f" GitHub: { github } \n " )
113+
114+ if not confirm ("Do you want to proceed with these settings?" , default = True ):
115+ secho ("Aborted! ❌" , fg = "red" )
116+ return
117+
118+ secho (f"\n Initializing project '{ name } '... 🚀" , fg = "green" , bold = True )
53119
54120 # 1. Rename project directory
55121 if os .path .isdir ("project" ):
56122 shutil .move ("project" , source )
123+ secho (f"Renamed 'project' directory to '{ source } '" , fg = "blue" )
57124 elif not os .path .isdir (source ):
58125 raise ClickException (f"Error: Neither 'project' nor '{ source } ' directory found." )
59126
@@ -75,16 +142,16 @@ def toml_escape(s: str) -> str:
75142 for filepath , pattern , replacement in replacements :
76143 path = Path (filepath )
77144 if not path .exists ():
78- echo (f"Warning: File { filepath } not found, skipping." )
145+ secho (f" Warning: File { filepath } not found, skipping. ⚠️" , fg = "yellow " )
79146 continue
80147
81148 content = path .read_text ()
82149 # Use a lambda for replacement to avoid regex backreference injection
83150 new_content = re .sub (pattern , lambda _ : replacement , content , flags = re .MULTILINE )
84151 path .write_text (new_content )
85- echo (f"Updated { filepath } " )
152+ secho (f" Updated { filepath } ✅" , fg = "blue " )
86153
87- echo ( "Project initialization complete." )
154+ secho ( " \n Project initialization complete! ✨" , fg = "green" , bold = True )
88155
89156
90157if __name__ == "__main__" :
0 commit comments