@@ -30,6 +30,33 @@ def __init__(self, parser):
3030 choices = ['console' , 'file' ], default = 'file' , help = 'Output mode' )
3131 parser .set_defaults (func = self .execute )
3232
33+ def _parse_template_vars (self , vars_str ):
34+ """Parse a comma-separated KEY=VALUE string into a dict safely.
35+ - Ignores empty tokens and trailing commas
36+ - Supports values containing '=' by splitting only on the first '='
37+ - Logs and skips malformed entries without raising
38+ """
39+ result = {}
40+ if not vars_str :
41+ return result
42+ # Normalize by removing accidental leading/trailing commas and whitespace
43+ tokens = [t .strip () for t in vars_str .strip (', ' ).split (',' )]
44+ for token in tokens :
45+ if not token :
46+ continue
47+ if '=' not in token :
48+ # Skip malformed item but warn
49+ self .logger .warning (f"Skipping malformed template var (no '='): '{ token } '" )
50+ continue
51+ key , value = token .split ('=' , 1 )
52+ key = key .strip ()
53+ value = value
54+ if not key :
55+ self .logger .warning (f"Skipping template var with empty key: '{ token } '" )
56+ continue
57+ result [key ] = value
58+ return result
59+
3360 def _deep_merge_dicts (self , dict1 , dict2 ):
3461 """
3562 Deep merge two dictionaries, with dict2 values overriding dict1 values.
@@ -146,7 +173,8 @@ def _create_structure(self, args, mappings=None, summary=None, print_summary=Tru
146173 if config is None :
147174 return summary if summary is not None else None
148175
149- template_vars = dict (item .split ('=' ) for item in args .vars .split (',' )) if args .vars else None
176+ # Safely parse template variables
177+ template_vars = self ._parse_template_vars (args .vars ) if getattr (args , 'vars' , None ) else {}
150178 config_structure = config .get ('files' , config .get ('structure' , []))
151179 config_folders = config .get ('folders' , [])
152180 config_variables = config .get ('variables' , [])
@@ -301,8 +329,18 @@ def _create_structure(self, args, mappings=None, summary=None, print_summary=Tru
301329 merged_vars = "," .join (
302330 [f"{ k } ={ v } " for k , v in rendered_with .items ()])
303331
304- if args .vars :
305- merged_vars = args .vars + "," + merged_vars
332+ # Merge parent args.vars safely without introducing trailing commas
333+ if getattr (args , 'vars' , None ):
334+ parts = []
335+ parent_vars = args .vars .strip ().strip (',' )
336+ if parent_vars :
337+ parts .append (parent_vars )
338+ if merged_vars :
339+ parts .append (merged_vars )
340+ merged_vars = "," .join (parts )
341+
342+ # If nothing to merge, keep None to avoid accidental truthiness with empty string
343+ merged_vars = merged_vars if merged_vars else None
306344
307345 if isinstance (content ['struct' ], str ):
308346 self ._create_structure ({
@@ -345,8 +383,8 @@ def _create_structure(self, args, mappings=None, summary=None, print_summary=Tru
345383 self .logger .info (f" ✅ Created: { summary ['created' ]} " )
346384 self .logger .info (f" ✅ Updated: { summary ['updated' ]} " )
347385 self .logger .info (f" 📝 Appended: { summary ['appended' ]} " )
348- self .logger .info (f" ⏭️ Skipped: { summary ['skipped' ]} " )
349- self .logger .info (f" 🗄️ Backed up: { summary ['backed_up' ]} " )
386+ self .logger .info (f" ⏭️ Skipped: { summary ['skipped' ]} " )
387+ self .logger .info (f" 🗄️ Backed up: { summary ['backed_up' ]} " )
350388 self .logger .info (f" 🔁 Renamed: { summary ['renamed' ]} " )
351389 self .logger .info (f" 📁 Folders created: { summary ['folders' ]} " )
352390 if args .dry_run :
0 commit comments