import tkinter as tk from tkinter import filedialog, messagebox from tkinter import ttk import shutil import os import json from ftplib import FTP class BackupApp: def __init__(self, root): self.root = root self.root.title("Programme de Backup") self.root.iconbitmap("backup.ico") self.source_paths = [] self.destination_path = tk.StringVar() self.ftp_server = tk.StringVar() self.ftp_user = tk.StringVar() self.ftp_pass = tk.StringVar() self.ftp_remote_dir = tk.StringVar() self.backup_type = tk.StringVar(value="local") self.create_widgets() self.load_paths() def create_widgets(self): tk.Label(self.root, text="Source:").grid(row=0, column=0, padx=10, pady=10) self.source_listbox = tk.Listbox(self.root, selectmode=tk.MULTIPLE, height=10, width=50) self.source_listbox.grid(row=0, column=1, rowspan=2, padx=10, pady=10) tk.Button(self.root, text="Ajouter Dossier", command=self.browse_source).grid(row=0, column=2, padx=10, pady=10) tk.Button(self.root, text="Supprimer Dossier", command=self.remove_selected_sources).grid(row=1, column=2, padx=10, pady=10) tk.Label(self.root, text="Destination:").grid(row=2, column=0, padx=10, pady=10) tk.Entry(self.root, textvariable=self.destination_path).grid(row=2, column=1, padx=10, pady=10) tk.Button(self.root, text="Parcourir", command=self.browse_destination).grid(row=2, column=2, padx=10, pady=10) tk.Label(self.root, text="Type de Sauvegarde:").grid(row=3, column=0, padx=10, pady=10) tk.Radiobutton(self.root, text="Local", variable=self.backup_type, value="local").grid(row=3, column=1, padx=10, pady=10) tk.Radiobutton(self.root, text="FTP", variable=self.backup_type, value="ftp").grid(row=3, column=2, padx=10, pady=10) tk.Label(self.root, text="Serveur FTP:").grid(row=4, column=0, padx=10, pady=10) tk.Entry(self.root, textvariable=self.ftp_server).grid(row=4, column=1, padx=10, pady=10) tk.Label(self.root, text="Utilisateur FTP:").grid(row=5, column=0, padx=10, pady=10) tk.Entry(self.root, textvariable=self.ftp_user).grid(row=5, column=1, padx=10, pady=10) tk.Label(self.root, text="Mot de passe FTP:").grid(row=6, column=0, padx=10, pady=10) tk.Entry(self.root, textvariable=self.ftp_pass, show="*").grid(row=6, column=1, padx=10, pady=10) tk.Label(self.root, text="Répertoire Distant:").grid(row=7, column=0, padx=10, pady=10) tk.Entry(self.root, textvariable=self.ftp_remote_dir).grid(row=7, column=1, padx=10, pady=10) tk.Button(self.root, text="Démarrer Backup", command=self.start_backup).grid(row=8, column=1, padx=10, pady=10) self.progress = ttk.Progressbar(self.root, orient="horizontal", length=400, mode="determinate") self.progress.grid(row=9, column=0, columnspan=3, padx=10, pady=10) def browse_source(self): sources = filedialog.askdirectory(mustexist=True) if sources: self.source_paths.append(sources) self.source_listbox.insert(tk.END, sources) self.save_paths() def browse_destination(self): destination = filedialog.askdirectory(mustexist=True) if destination: self.destination_path.set(destination) self.save_paths() def remove_selected_sources(self): selected_indices = self.source_listbox.curselection() selected_paths = [self.source_listbox.get(i) for i in selected_indices] for path in selected_paths: self.source_paths.remove(path) for i in selected_indices[::-1]: self.source_listbox.delete(i) self.save_paths() def start_backup(self): destination = self.destination_path.get() if not self.source_paths or (self.backup_type.get() == "local" and not destination): messagebox.showerror("Erreur", "Veuillez sélectionner les répertoires source et destination.") return total_files = sum([len(files) for source in self.source_paths for _, _, files in os.walk(source)]) self.progress["maximum"] = total_files self.progress["value"] = 0 try: if self.backup_type.get() == "local": for source in self.source_paths: self.incremental_backup(source, destination) elif self.backup_type.get() == "ftp": ftp_server = self.ftp_server.get() ftp_user = self.ftp_user.get() ftp_pass = self.ftp_pass.get() ftp_remote_dir = self.ftp_remote_dir.get() if not ftp_server or not ftp_user or not ftp_pass or not ftp_remote_dir: messagebox.showerror("Erreur", "Veuillez entrer les informations FTP et le répertoire distant.") return for source in self.source_paths: self.ftp_backup(source, ftp_server, ftp_user, ftp_pass, ftp_remote_dir) messagebox.showinfo("Succès", "Sauvegarde terminée avec succès.") except Exception as e: messagebox.showerror("Erreur", f"Une erreur est survenue: {e}") def incremental_backup(self, source, destination): for root, dirs, files in os.walk(source): relative_path = os.path.relpath(root, source) dest_dir = os.path.join(destination, os.path.basename(source), relative_path) if not os.path.exists(dest_dir): os.makedirs(dest_dir) for file in files: source_file = os.path.join(root, file) dest_file = os.path.join(dest_dir, file) if not os.path.exists(dest_file) or os.path.getmtime(source_file) > os.path.getmtime(dest_file): shutil.copy2(source_file, dest_file) self.progress["value"] += 1 self.root.update_idletasks() def ftp_backup(self, source, ftp_server, ftp_user, ftp_pass, ftp_remote_dir): ftp = FTP(ftp_server) ftp.login(user=ftp_user, passwd=ftp_pass) ftp.set_pasv(True) # Forcer le mode passif ftp.cwd('/') # Créer le répertoire distant s'il n'existe pas try: ftp.mkd(ftp_remote_dir) except Exception as e: if not str(e).startswith('550'): raise ftp.cwd(ftp_remote_dir) for root, dirs, files in os.walk(source): relative_path = os.path.relpath(root, source).replace("\\", "/") for dir in dirs: dir_path = os.path.join(relative_path, dir).replace("\\", "/") try: ftp.mkd(dir_path) except Exception as e: if str(e).startswith('550'): pass else: raise for file in files: file_path = os.path.join(root, file).replace("\\", "/") with open(file_path, 'rb') as f: ftp.storbinary("STOR {}".format(os.path.join(relative_path, file).replace('\\', '/')), f) self.progress["value"] += 1 self.root.update_idletasks() ftp.quit() def save_paths(self): data = { "source_paths": self.source_paths, "destination_path": self.destination_path.get(), "ftp_server": self.ftp_server.get(), "ftp_user": self.ftp_user.get(), "ftp_pass": self.ftp_pass.get(), "ftp_remote_dir": self.ftp_remote_dir.get(), "backup_type": self.backup_type.get() } with open("paths.json", "w") as file: json.dump(data, file) def load_paths(self): if os.path.exists("paths.json"): with open("paths.json", "r") as file: data = json.load(file) self.source_paths = data.get("source_paths", []) self.destination_path.set(data.get("destination_path", "")) self.ftp_server.set(data.get("ftp_server", "")) self.ftp_user.set(data.get("ftp_user", "")) self.ftp_pass.set(data.get("ftp_pass", "")) self.ftp_remote_dir.set(data.get("ftp_remote_dir", "")) self.backup_type.set(data.get("backup_type", "local")) for path in self.source_paths: self.source_listbox.insert(tk.END, path) if __name__ == "__main__": root = tk.Tk() app = BackupApp(root) root.mainloop()