Im trying to make a backup utility tool in python where the user can backup either folder or file but not both. The folder can backup folders but for the file, it does not backup the file. It will only produce a log file which state the starting time of backup process and the end time of backup process
import tkinter as tk
import tkinter.ttk as ttk
from tkinter import filedialog, messagebox
import shutil
import os
import time
import zipfile
def backup():
source_folders = source_folder_text.get('1.0', 'end').strip().split('\n')
dest_folder = dest_folder_text.get('1.0', 'end').strip()
if not source_folders:
messagebox.showerror('Error', 'Please specify at least one source folder.')
return
if not dest_folder:
messagebox.showerror('Error', 'Please specify a destination folder.')
return
is_file_selected = False
is_folder_selected = False
for source_folder in source_folders:
if os.path.isfile(source_folder):
is_file_selected = True
elif os.path.isdir(source_folder):
is_folder_selected = True
if is_file_selected and is_folder_selected:
messagebox.showerror('Error', 'Please select either files or folders for backup, not both.')
return
try:
if not os.path.exists(dest_folder):
os.makedirs(dest_folder)
timestamp = time.strftime('%Y%m%d-%H%M%S')
backup_folder = os.path.join(dest_folder, f'backup-{timestamp}')
if not os.path.exists(backup_folder):
os.makedirs(backup_folder)
log_file = os.path.join(backup_folder, 'backup.log')
with open(log_file, 'w') as f:
f.write(f'Backup started at {time.strftime("%Y-%m-%d %H:%M:%S")}\n')
total_files = 0
for source_folder in source_folders:
for root, dirs, files in os.walk(source_folder):
total_files += len(files)
progress_window = tk.Toplevel()
progress_window.title('Backup Progress')
progress_label = tk.Label(progress_window, text='Backing up files...')
progress_label.pack()
progress_bar = tk.ttk.Progressbar(progress_window, orient='horizontal', length=300, mode='determinate', maximum=total_files)
progress_bar.pack()
current_file = 0
for source_folder in source_folders:
for root, dirs, files in os.walk(source_folder):
for file in files:
source_file = os.path.join(root, file)
dest_file = os.path.join(backup_folder, os.path.relpath(source_file, source_folder))
dest_dir = os.path.dirname(dest_file)
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
if os.path.exists(dest_file) and os.path.getmtime(dest_file) >= os.path.getmtime(source_file):
# skip if destination file already exists and is newer than source file
with open(log_file, 'a') as f:
f.write(f'[SKIP] {source_file} (already exists)\n')
else:
shutil.copy2(source_file, dest_file)
with open(log_file, 'a') as f:
f.write(f'[COPY] {source_file} to {dest_file}\n')
current_file += 1
progress_bar['value'] = current_file
progress_label.config(text=f'Backing up {source_file}...')
progress_window.update()
with open(log_file, 'a') as f:
f.write(f'Backup completed at {time.strftime("%Y-%m-%d %H:%M:%S")}\n')
if compress_var.get():
progress_label.config(text='Compressing backup files...')
zip_file = os.path.join(dest_folder, f'backup-{timestamp}.zip')
with zipfile.ZipFile(zip_file, 'w', zipfile.ZIP_DEFLATED) as zipf:
for root, dirs, files in os.walk(backup_folder):
for file in files:
zipf.write(os.path.join(root, file), os.path.relpath(os.path.join(root, file), backup_folder))
shutil.rmtree(backup_folder)
messagebox.showinfo('Success', 'Backup completed successfully.')
clear()
except Exception as e:
with open(log_file, 'a') as f:
f.write(f'[ERROR] An error occurred during backup: {str(e)}\n')
messagebox.showerror('Error', f'An error occurred during backup:\n{str(e)}')
def browse_source_folder():
folder = filedialog.askdirectory()
if folder:
source_folder_text.insert('end', folder + '\n')
def browse_source_file():
file = filedialog.askopenfilename()
if file:
source_folder_text.insert('end', file + '\n')
def browse_dest_folder():
folder = filedialog.askdirectory()
if folder:
dest_folder_text.delete('1.0', 'end')
dest_folder_text.insert('1.0', folder)
def clear():
source_folder_text.delete('1.0', 'end')
dest_folder_text.delete('1.0', 'end')
compress_var.set(False)
# Create the main window
root = tk.Tk()
root.title('Backup Tool')
root.geometry('820x400')
root.config(bg='#FFFFFF')
# Create the source folder section
source_folder_label = tk.Label(root, text='Source folders or files:', font=('Helvetica', 12, 'bold'), bg='#FFFFFF')
source_folder_label.pack(pady=10)
source_folder_text = tk.Text(root, height=5)
source_folder_text.pack()
select_folder_or_file_label = tk.Label(root, text='Select either a folder or a file for backup, but not both.', font=('TkDefaultFont', 10), fg='red', bg='#FFFFFF')
select_folder_or_file_label.pack(pady=5)
source_folder_button_frame = tk.Frame(root, bg='#FFFFFF')
source_folder_button_frame.pack(pady=5)
browse_source_folder_button = tk.Button(source_folder_button_frame, text='Browse Folder', command=browse_source_folder, font=('Helvetica', 10))
browse_source_folder_button.pack(side='left', padx=10)
browse_source_file_button = tk.Button(source_folder_button_frame, text='Browse File', command=browse_source_file, font=('Helvetica', 10))
browse_source_file_button.pack(side='left')
# Create the destination folder section
dest_folder_frame = tk.Frame(root, bg='#FFFFFF')
dest_folder_frame.pack(pady=10)
dest_folder_label = tk.Label(dest_folder_frame, text='Destination folder:', font=('Helvetica', 12, 'bold'), bg='#FFFFFF')
dest_folder_label.pack(side='left', padx=10)
dest_folder_text = tk.Text(dest_folder_frame, height=1, font=('Helvetica', 10))
dest_folder_text.pack(side='left')
browse_dest_folder_button = tk.Button(dest_folder_frame, text='Browse', command=browse_dest_folder, font=('Helvetica', 10))
browse_dest_folder_button.pack(side='left', padx=10)
# Create the backup and compression section
compress_checkbox_frame = tk.Frame(root, bg='#FFFFFF')
compress_checkbox_frame.pack(pady=10)
compress_var = tk.BooleanVar()
compress_checkbox = tk.Checkbutton(compress_checkbox_frame, text='Compress backup files', variable=compress_var, bg='#FFFFFF')
compress_checkbox.pack(side='left', padx=10)
clear_button = tk.Button(compress_checkbox_frame, text='Clear', command=clear, font=('Helvetica', 10))
clear_button.pack(side='left')
backup_button = tk.Button(root, text='Backup', command=backup, font=('Helvetica', 12, 'bold'))
backup_button.pack(pady=10)
# Start the main event loop
root.mainloop()
I tried modify it but im stuck
The reason why only your folders get backed up, but not you files is because of this line for root, dirs, files in os.walk(source_folder)
when you back up. This works as expected when source_folder
is a folder, but when source_folder
is a file, os.walk
doesn't return anything for you to loop over.
So what you should do is perform a check if you are backing up files or folders. You can do this by using your is_file_selected
and is_folder selected
. Then the code you have now for backing up your folders goes under is_folder_selected
, and for when files are selected you may simply just loop over them.
# Check if we are backing up files or folders
if is_folders_selected:
for source_folder in source_folders:
for root, dirs, files in os.walk(source_folder):
for file in files:
# The same code as before
# ...
if is_files_selected:
for source_file in source_folders:
# Then use almost the same code as in folders