1313from rich .console import Console
1414from rich .panel import Panel
1515from rich .table import Table
16+ from rich .prompt import Prompt
1617
1718from StreamingCommunity .Upload .version import __author__ , __title__
1819
20+
1921# Variable
2022max_timeout = 15
2123console = Console ()
2224local_path = os .path .join ("." )
25+ REQUIRED_PROJECT_FILES = {"update.py" , "Video" }
26+ PROJECT_MARKER_FILE = "update.py"
27+
28+
29+ def verify_project_directory (directory : str ) -> bool :
30+ """
31+ Verify that we're in the correct project directory by checking for required files.
32+
33+ Parameters:
34+ - directory (str): The path to verify
35+
36+ Returns:
37+ - bool: True if this appears to be the correct project directory
38+ """
39+ if not os .path .isdir (directory ):
40+ console .print (f"[red]Error: '{ directory } ' is not a valid directory." )
41+ return False
42+
43+ marker_path = os .path .join (directory , PROJECT_MARKER_FILE )
44+ if not os .path .exists (marker_path ):
45+ console .print (f"[red]Safety check failed: '{ PROJECT_MARKER_FILE } ' not found in { os .path .abspath (directory )} " )
46+ console .print ("[yellow]Please ensure you're running this script from the project root directory." )
47+ return False
48+
49+ return True
50+
51+
52+ def dry_run_deletion (directory : str , keep_folder : str , keep_file : str ) -> list :
53+ """
54+ Simulate what would be deleted without actually deleting anything.
55+
56+ Parameters:
57+ - directory (str): The path to the directory
58+ - keep_folder (str): The name of the folder to keep
59+ - keep_file (str): The name of the file to keep
60+
61+ Returns:
62+ - list: Items that would be deleted
63+ """
64+ if not os .path .exists (directory ) or not os .path .isdir (directory ):
65+ return []
66+
67+ skip_folders = {keep_folder , ".git" }
68+ skip_files = {keep_file }
69+ items_to_delete = []
70+
71+ for item in os .listdir (directory ):
72+ if item in skip_folders or item in skip_files :
73+ continue
74+
75+ item_path = os .path .join (directory , item )
76+ item_type = "directory" if os .path .isdir (item_path ) else "file"
77+ items_to_delete .append ((item , item_type , item_path ))
78+
79+ return items_to_delete
2380
2481
2582def move_content (source : str , destination : str ):
@@ -44,39 +101,45 @@ def move_content(source: str, destination: str):
44101 shutil .move (source_path , destination_path )
45102
46103
47- def keep_specific_items (directory : str , keep_folder : str , keep_file : str ):
104+ def keep_specific_items (directory : str , keep_folder : str , keep_file : str , dry_run : bool = False ):
48105 """
49- Deletes all items in the given directory except for the specified folder,
50- the specified file, and the '.git' directory.
106+ Deletes all items in the given directory except for the specified folder, the specified file, and the '.git' directory.
51107
52108 Parameters:
53109 - directory (str): The path to the directory.
54110 - keep_folder (str): The name of the folder to keep.
55111 - keep_file (str): The name of the file to keep.
112+ - dry_run (bool): If True, only show what would be deleted without deleting.
56113 """
57- if not os .path .exists (directory ) or not os .path .isdir (directory ):
58- console .print (f"[red]Error: '{ directory } ' is not a valid directory." )
59- return
114+ if not verify_project_directory (directory ):
115+ return False
60116
61- # Define folders and files to skip
62117 skip_folders = {keep_folder , ".git" }
63118 skip_files = {keep_file }
64119
65- # Iterate through items in the directory
66120 for item in os .listdir (directory ):
67121 if item in skip_folders or item in skip_files :
68122 continue
69123
70124 item_path = os .path .join (directory , item )
71125 try :
72- if os .path .isdir (item_path ):
73- shutil .rmtree (item_path )
74- console .log (f"[green]Removed directory: { item_path } " )
75- elif os .path .isfile (item_path ):
76- os .remove (item_path )
77- console .log (f"[green]Removed file: { item_path } " )
126+ if dry_run :
127+ item_type = "directory" if os .path .isdir (item_path ) else "file"
128+ console .log (f"[yellow][DRY RUN] Would remove { item_type } : { item_path } " )
129+
130+ else :
131+ if os .path .isdir (item_path ):
132+ shutil .rmtree (item_path )
133+ console .log (f"[green]Removed directory: { item_path } " )
134+
135+ elif os .path .isfile (item_path ):
136+ os .remove (item_path )
137+ console .log (f"[green]Removed file: { item_path } " )
138+
78139 except Exception as e :
79140 console .log (f"[yellow]Skipping { item_path } due to error: { e } " )
141+
142+ return True
80143
81144
82145def print_commit_info (commit_info : dict ):
@@ -177,41 +240,100 @@ def download_and_extract_latest_commit():
177240 console .print (f"[red]An unexpected error occurred: { e } " )
178241
179242
180- def main_upload (auto_confirm = None ):
243+ def main_upload (auto_confirm = None , dry_run = False ):
181244 """
182- Main function to upload the latest commit of a GitHub repository.
245+ Main function to update to the latest commit of a GitHub repository with safety checks.
246+
247+ Parameters:
248+ - auto_confirm (str or None): 'y', 'n', or None for interactive prompt
249+ - dry_run (bool): If True, only show what would be deleted
183250 """
184-
251+
252+ # Verify we're in the correct project directory
253+ if not verify_project_directory ("." ):
254+ console .print ("[red]Aborted: Cannot verify project directory. Refusing to proceed." )
255+ return
256+
257+ current_dir = os .path .abspath ("." )
258+ console .print (f"[cyan]Project directory: { current_dir } " )
259+
260+ # Show what will be deleted
261+ items_to_delete = dry_run_deletion ("." , "Video" , "upload.py" )
262+
263+ if items_to_delete :
264+ console .print ("\n [bold yellow]Files and folders that will be deleted:" )
265+ for item_name , item_type , item_path in items_to_delete :
266+ console .print (f" [red]• { item_type } : { item_name } " )
267+ console .print ()
268+
269+ # First confirmation: Basic yes/no
185270 if auto_confirm is None :
186- # fallback al prompt interattivo
187- from rich .prompt import Prompt
188271 cmd_insert = Prompt .ask (
189- "[bold red]Are you sure you want to delete all files? (Only 'Video' folder and 'update_version .py' will remain) " ,
272+ "[bold red]Are you sure you want to delete all files except 'Video' folder and 'upload .py'? " ,
190273 choices = ['y' , 'n' ],
191- default = 'y ' ,
274+ default = 'n ' ,
192275 show_choices = True
193276 )
277+
194278 else :
195279 cmd_insert = auto_confirm
196280
197- if cmd_insert .lower ().strip () in ('y' , 'yes' ):
198- console .print ("[red]Deleting all files except 'Video' folder and 'update_version.py'..." )
199- keep_specific_items ("." , "Video" , "upload.py" )
281+ if cmd_insert .lower ().strip () not in ('y' , 'yes' ):
282+ console .print ("[yellow]Operation cancelled." )
283+ return
284+
285+ # Second confirmation: Require explicit phrase
286+ console .print ("\n [bold red]WARNING: This action cannot be undone!" )
287+ confirmation_phrase = "DELETE MY FILES"
288+ user_input = Prompt .ask (
289+ f"[bold red]Type '{ confirmation_phrase } ' to confirm deletion" ,
290+ default = ""
291+ )
292+
293+ if user_input .strip () != confirmation_phrase :
294+ console .print ("[yellow]Confirmation phrase incorrect. Operation cancelled." )
295+ return
296+
297+ # Perform dry run first
298+ if dry_run :
299+ console .print ("\n [bold cyan]DRY RUN MODE - No files will be deleted" )
300+ keep_specific_items ("." , "Video" , "upload.py" , dry_run = True )
301+ return
302+
303+ # Perform actual deletion
304+ console .print ("[red]Deleting all files except 'Video' folder and 'upload.py'..." )
305+ if keep_specific_items ("." , "Video" , "upload.py" ):
200306 download_and_extract_latest_commit ()
201307 else :
202- console .print ("[red]Operation cancelled ." )
308+ console .print ("[red]Deletion aborted due to safety check failure ." )
203309
204310
205311if __name__ == "__main__" :
206- parser = argparse .ArgumentParser (description = "Upload the latest commit of a GitHub repository." )
312+ parser = argparse .ArgumentParser (
313+ description = "Safely update to the latest commit of a GitHub repository." ,
314+ epilog = "SAFETY: This script will only work from the project root directory."
315+ )
316+ parser .add_argument (
317+ "--dry-run" ,
318+ action = "store_true" ,
319+ help = "Show what would be deleted without actually deleting anything."
320+ )
207321 group = parser .add_mutually_exclusive_group ()
208- group .add_argument ("-y" , "--yes" , action = "store_true" , help = "Automatically confirm deletion." )
209- group .add_argument ("-n" , "--no" , action = "store_true" , help = "Automatically cancel deletion." )
322+ group .add_argument (
323+ "-y" , "--yes" ,
324+ action = "store_true" ,
325+ help = "Skip first confirmation (you'll still need to type the confirmation phrase)."
326+ )
327+ group .add_argument (
328+ "-n" , "--no" ,
329+ action = "store_true" ,
330+ help = "Automatically cancel without prompting."
331+ )
210332 args = parser .parse_args ()
211333
212- if args .yes :
213- main_upload ("y" )
214- elif args .no :
334+ if args .no :
215335 main_upload ("n" )
336+ elif args .yes :
337+ main_upload ("y" , dry_run = args .dry_run )
216338 else :
217- main_upload ()
339+ main_upload (dry_run = args . dry_run )
0 commit comments