Skip to content

Instantly share code, notes, and snippets.

@me-suzy
Created June 11, 2026 16:52
Show Gist options
  • Select an option

  • Save me-suzy/087308407af30aba34073cc122dfc752 to your computer and use it in GitHub Desktop.

Select an option

Save me-suzy/087308407af30aba34073cc122dfc752 to your computer and use it in GitHub Desktop.
adauga-folder-in-repository V.2.py
# -*- coding: utf-8 -*-
"""
adauga-folder-in-repository.py
Adauga toate fisierele dintr-un folder local intr-un repository de pe GitHub.
Flux:
Fereastra 1 -> intreaba in ce repo de pe GitHub sa adaugi fisierele (URL repo).
Fereastra 2 -> intreaba calea folderului local pe care vrei sa-l copiezi in repo,
cu un checkbox: "Copiaza si subfolderele" (recursiv) sau doar fisierele din folder.
Apoi: cloneaza repo-ul, copiaza fisierele, face commit si push.
Necesita: git instalat si configurat (cu credentiale/token pentru push).
"""
import os
import sys
import shutil
import tempfile
import subprocess
import time
import queue
import threading
import tkinter as tk
from tkinter import ttk, filedialog, messagebox, scrolledtext
DIRECTOARE_EXCLUSE = {"__pycache__", "logs", ".git"}
FISIERE_EXCLUSE = {"parent.lock", ".git"}
# ----------------------------------------------------------------------------
# FEREASTRA 1: alegerea repo-ului de pe GitHub
# ----------------------------------------------------------------------------
def cere_repo():
"""Afiseaza prima fereastra si intoarce URL-ul repo-ului ales (sau None)."""
rezultat = {"url": None}
win = tk.Tk()
win.title("Pasul 1/2 - Alege repository-ul GitHub")
win.geometry("680x230")
win.resizable(False, False)
tk.Label(
win,
text="In ce repository de pe GitHub vrei sa adaugi fisierele?",
font=("Segoe UI", 11, "bold"),
).pack(pady=(18, 4))
tk.Label(
win,
text="Lipeste aici URL-ul complet al repo-ului (ex: https://github.com/me-suzy/NumeRepo)",
font=("Segoe UI", 9),
fg="#555",
).pack(pady=(0, 8))
entry = tk.Entry(win, width=80, font=("Consolas", 10))
entry.pack(pady=6, padx=20)
entry.insert(0, "https://github.com/me-suzy/")
entry.focus_set()
def confirma():
url = entry.get().strip()
if not url:
messagebox.showwarning("Atentie", "Trebuie sa introduci un URL de repository.")
return
if "github.com" not in url:
if not messagebox.askyesno(
"Confirmare",
"URL-ul nu pare a fi de pe github.com.\nVrei sa continui oricum?",
):
return
rezultat["url"] = url
win.destroy()
btn = tk.Frame(win)
btn.pack(pady=18)
tk.Button(btn, text="Continua ->", width=16, command=confirma,
bg="#2e7d32", fg="white", font=("Segoe UI", 10, "bold")).pack(side="left", padx=6)
tk.Button(btn, text="Anuleaza", width=12, command=win.destroy).pack(side="left", padx=6)
win.bind("<Return>", lambda e: confirma())
win.mainloop()
return rezultat["url"]
# ----------------------------------------------------------------------------
# FEREASTRA 2: alegerea folderului local + checkbox subfoldere
# ----------------------------------------------------------------------------
def cere_folder():
"""Afiseaza a doua fereastra si intoarce (cale_folder, include_subfoldere) sau (None, None)."""
rezultat = {"folder": None, "recursiv": None}
win = tk.Tk()
win.title("Pasul 2/2 - Alege folderul de copiat")
win.geometry("680x260")
win.resizable(False, False)
tk.Label(
win,
text="Ce folder local vrei sa copiezi complet in repo?",
font=("Segoe UI", 11, "bold"),
).pack(pady=(18, 8))
rand = tk.Frame(win)
rand.pack(pady=6, padx=20, fill="x")
entry = tk.Entry(rand, width=62, font=("Consolas", 10))
entry.pack(side="left", fill="x", expand=True)
entry.insert(0, r"d:\TEST\arcanum_capture\\")
def rasfoieste():
cale = filedialog.askdirectory(title="Alege folderul de copiat")
if cale:
entry.delete(0, tk.END)
entry.insert(0, cale)
tk.Button(rand, text="Rasfoieste...", command=rasfoieste).pack(side="left", padx=(8, 0))
var_recursiv = tk.BooleanVar(value=True)
tk.Checkbutton(
win,
text="Copiaza si subfolderele (recursiv), nu doar fisierele din folder",
variable=var_recursiv,
font=("Segoe UI", 10),
).pack(pady=(14, 4), anchor="w", padx=22)
def confirma():
folder = entry.get().strip().strip('"')
if not folder:
messagebox.showwarning("Atentie", "Trebuie sa alegi un folder.")
return
if not os.path.isdir(folder):
messagebox.showerror("Eroare", f"Folderul nu exista:\n{folder}")
return
rezultat["folder"] = folder
rezultat["recursiv"] = var_recursiv.get()
win.destroy()
btn = tk.Frame(win)
btn.pack(pady=18)
tk.Button(btn, text="Adauga in repo ->", width=18, command=confirma,
bg="#2e7d32", fg="white", font=("Segoe UI", 10, "bold")).pack(side="left", padx=6)
tk.Button(btn, text="Anuleaza", width=12, command=win.destroy).pack(side="left", padx=6)
win.bind("<Return>", lambda e: confirma())
win.mainloop()
return rezultat["folder"], rezultat["recursiv"]
# ----------------------------------------------------------------------------
# FEREASTRA 3: log / progres
# ----------------------------------------------------------------------------
class FereastraLog:
def __init__(self):
self.win = tk.Tk()
self.win.title("Adaugare fisiere in repository - progres")
self.win.geometry("900x560")
self.win.protocol("WM_DELETE_WINDOW", self._inchide)
self._terminat = False
self.status = tk.StringVar(value="Pregatire...")
tk.Label(
self.win, textvariable=self.status, anchor="w", font=("Segoe UI", 9)
).pack(fill="x", padx=8, pady=(8, 2))
self.progress = ttk.Progressbar(
self.win, orient="horizontal", mode="determinate", maximum=100
)
self.progress.pack(fill="x", padx=8, pady=(0, 6))
self.txt = scrolledtext.ScrolledText(self.win, font=("Consolas", 9), wrap="word")
self.txt.pack(fill="both", expand=True, padx=8, pady=(0, 8))
self.btn = tk.Button(self.win, text="Inchide", width=14,
command=self._inchide, state="disabled")
self.btn.pack(pady=(0, 10))
self.win.update()
def _inchide(self):
if self._terminat:
self.win.destroy()
def log(self, mesaj):
self.txt.insert(tk.END, mesaj + "\n")
self.txt.see(tk.END)
self.win.update()
def seteaza_progres(self, curent, total, mesaj):
self.progress.stop()
self.progress.configure(mode="determinate", maximum=100)
procent = (curent * 100 / total) if total else 0
self.progress["value"] = procent
self.status.set(mesaj)
self.win.update_idletasks()
def incepe_asteptare(self, mesaj):
self.progress.stop()
self.progress.configure(mode="indeterminate")
self.progress.start(12)
self.status.set(mesaj)
self.win.update()
def actualizeaza_asteptare(self, mesaj):
self.status.set(mesaj)
self.win.update()
def opreste_asteptare(self):
self.progress.stop()
self.progress.configure(mode="determinate", maximum=100)
self.progress["value"] = 0
self.win.update_idletasks()
def gata(self):
self._terminat = True
self.progress.stop()
self.progress.configure(mode="determinate", maximum=100)
self.progress["value"] = 100
self.status.set("Operatie terminata. Poti inchide fereastra.")
self.btn.config(state="normal")
self.win.mainloop()
# ----------------------------------------------------------------------------
# Operatii git + copiere
# ----------------------------------------------------------------------------
def ruleaza(comanda, cwd, log, actualizeaza_ui=None, mesaj_asteptare=None):
"""Ruleaza o comanda fara sa blocheze fereastra si trimite output-ul in log."""
log("> " + " ".join(comanda))
proc = subprocess.Popen(
comanda, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
text=True, encoding="utf-8", errors="replace",
)
linii = queue.Queue()
citire_terminata = threading.Event()
def citeste_output():
try:
for linie in proc.stdout:
linii.put(linie.rstrip())
finally:
citire_terminata.set()
threading.Thread(target=citeste_output, daemon=True).start()
inceput = time.monotonic()
ultima_actualizare = 0.0
while proc.poll() is None or not citire_terminata.is_set() or not linii.empty():
for _ in range(100):
try:
log(linii.get_nowait())
except queue.Empty:
break
acum = time.monotonic()
if actualizeaza_ui and acum - ultima_actualizare >= 0.2:
secunde = int(acum - inceput)
minute, secunde = divmod(secunde, 60)
text = mesaj_asteptare or "Comanda Git ruleaza"
actualizeaza_ui(f"{text} - timp scurs {minute:02d}:{secunde:02d}")
ultima_actualizare = acum
if proc.poll() is None:
time.sleep(0.05)
while not linii.empty():
log(linii.get_nowait())
return proc.returncode
def ruleaza_cu_fereastra(comanda, cwd, log_win, log, mesaj):
"""Ruleaza o comanda Git mentinand activa fereastra de progres."""
log_win.incepe_asteptare(mesaj)
try:
return ruleaza(
comanda,
cwd,
log,
actualizeaza_ui=log_win.actualizeaza_asteptare,
mesaj_asteptare=mesaj,
)
finally:
log_win.opreste_asteptare()
def formateaza_marime(numar_octeti):
"""Formateaza o dimensiune in octeti intr-un text usor de citit."""
valoare = float(numar_octeti)
for unitate in ("B", "KB", "MB", "GB", "TB"):
if valoare < 1024 or unitate == "TB":
return f"{valoare:.1f} {unitate}"
valoare /= 1024
def iter_fisiere(sursa, recursiv):
"""Genereaza (cale completa, cale relativa, dimensiune), cu excluderi."""
if recursiv:
for radacina, directoare, fisiere in os.walk(sursa):
directoare[:] = [
nume for nume in directoare
if nume.casefold() not in DIRECTOARE_EXCLUSE
]
for f in fisiere:
if f.casefold() in FISIERE_EXCLUSE:
continue
cale = os.path.join(radacina, f)
try:
marime = os.path.getsize(cale)
except (FileNotFoundError, PermissionError):
# Firefox poate sterge/bloca fisierele cache chiar in timpul scanarii.
continue
yield cale, os.path.relpath(cale, sursa), marime
else:
for nume in os.listdir(sursa):
cale = os.path.join(sursa, nume)
if os.path.isfile(cale) and nume.casefold() not in FISIERE_EXCLUSE:
try:
marime = os.path.getsize(cale)
except (FileNotFoundError, PermissionError):
continue
yield cale, nume, marime
def copiaza_fisiere(sursa, destinatie, recursiv, log, progres):
"""Copiaza continutul folderului sursa in destinatie si afiseaza progres."""
log("Scanez fisierele care trebuie copiate...")
fisiere = list(iter_fisiere(sursa, recursiv))
total_fisiere = len(fisiere)
total_octeti = sum(marime for _cale, _rel, marime in fisiere)
log(
f"De copiat: {total_fisiere} fisiere, "
f"{formateaza_marime(total_octeti)}."
)
if recursiv:
log("Exclud directoarele: __pycache__, Logs, .git (oriunde apar).")
log("Exclud fisierele: parent.lock, .git.")
log("Fisierele existente in repository vor fi suprascrise.")
if total_fisiere == 0:
return 0
inceput = time.monotonic()
ultima_actualizare = 0.0
octeti_copiati = 0
fisiere_copiate = 0
fisiere_suprascrise = 0
fisiere_sarite = []
for index, (cale_sursa, cale_relativa, marime) in enumerate(fisiere, start=1):
cale_destinatie = os.path.join(destinatie, cale_relativa)
os.makedirs(os.path.dirname(cale_destinatie), exist_ok=True)
exista_deja = os.path.exists(cale_destinatie)
if exista_deja:
try:
os.chmod(cale_destinatie, 0o666)
except OSError:
pass
eroare = None
for incercare in range(3):
try:
shutil.copy2(cale_sursa, cale_destinatie)
eroare = None
break
except OSError as exc:
eroare = exc
if incercare < 2:
time.sleep(0.15)
if eroare is None:
fisiere_copiate += 1
if exista_deja:
fisiere_suprascrise += 1
octeti_copiati += marime
else:
fisiere_sarite.append((cale_relativa, str(eroare)))
acum = time.monotonic()
if acum - ultima_actualizare >= 0.5 or index == total_fisiere:
durata = max(acum - inceput, 0.001)
viteza = octeti_copiati / durata
mesaj = (
f"Procesez {index}/{total_fisiere} | copiate {fisiere_copiate} | "
f"suprascrise {fisiere_suprascrise} | "
f"sarite {len(fisiere_sarite)} | "
f"{formateaza_marime(octeti_copiati)}/"
f"{formateaza_marime(total_octeti)} | "
f"{formateaza_marime(viteza)}/s | {cale_relativa}"
)
progres(index, total_fisiere, mesaj)
log(
f" {index}/{total_fisiere} procesate, "
f"{fisiere_copiate} copiate, "
f"{fisiere_suprascrise} suprascrise, "
f"{len(fisiere_sarite)} sarite, "
f"{formateaza_marime(octeti_copiati)}..."
)
ultima_actualizare = acum
if fisiere_sarite:
log(
f"AVERTISMENT: {len(fisiere_sarite)} fisiere au disparut sau au fost "
"blocate in timpul copierii. Operatia continua."
)
for cale_relativa, eroare in fisiere_sarite[:20]:
log(f" SARIT: {cale_relativa} ({eroare})")
if len(fisiere_sarite) > 20:
log(f" ... si inca {len(fisiere_sarite) - 20} fisiere sarite.")
log(
f"Copiate {fisiere_copiate} fisiere, {formateaza_marime(octeti_copiati)} "
f"({'cu subfoldere' if recursiv else 'doar fisierele din folder'})."
)
log(f"Fisiere existente suprascrise: {fisiere_suprascrise}.")
return fisiere_copiate
def proceseaza(repo_url, folder, recursiv):
log_win = FereastraLog()
L = log_win.log
L("=" * 60)
L(f"Repository : {repo_url}")
L(f"Folder : {folder}")
L(f"Recursiv : {'DA (cu subfoldere)' if recursiv else 'NU (doar fisierele)'}")
L("=" * 60)
# verifica git
if shutil.which("git") is None:
L("EROARE: git nu este instalat sau nu este in PATH.")
log_win.gata()
return
temp = tempfile.mkdtemp(prefix="repo_upload_")
nume_repo = repo_url.rstrip("/").split("/")[-1].replace(".git", "")
clona = os.path.join(temp, nume_repo or "repo")
try:
L("\n[1/5] Clonez repository-ul...")
if ruleaza_cu_fereastra(
["git", "clone", "--progress", repo_url, clona],
temp, log_win, L, "Clonez repository-ul"
) != 0:
L("\nEROARE la clonare. Verifica URL-ul si accesul (token/credentiale).")
return
L("\n[2/5] Copiez fisierele in repository...")
nr = copiaza_fisiere(
folder, clona, recursiv, L, log_win.seteaza_progres
)
if nr == 0:
L("Nu am gasit fisiere de copiat. Ma opresc.")
return
L("\n[3/5] git add ...")
L(
f"Git indexeaza {nr} fisiere. La volume mari poate dura mai multe "
"minute; bara miscatoare si timpul scurs arata ca operatia continua."
)
comanda_add = [
"git",
"-c", "core.autocrlf=false",
"-c", "core.safecrlf=false",
"add", "-f", "-A",
]
if ruleaza_cu_fereastra(
comanda_add,
clona, log_win, L,
f"NU este blocat: Git indexeaza {nr} fisiere (git add)"
) != 0:
L("\nEROARE la git add. Verifica mesajul de mai sus.")
return
# verifica daca exista modificari
cod_modificari = ruleaza_cu_fereastra(
["git", "diff", "--cached", "--quiet", "--exit-code"],
clona, log_win, L, "Verific modificarile pregatite"
)
if cod_modificari == 0:
L("\nNu exista modificari noi fata de repo (fisierele exista deja identice).")
return
if cod_modificari != 1:
L("\nEROARE la verificarea modificarilor Git.")
return
L("\n[4/5] git commit ...")
mesaj = f"Adauga fisiere din folderul {os.path.basename(folder.rstrip(os.sep))}"
if ruleaza_cu_fereastra(
["git", "commit", "-m", mesaj],
clona, log_win, L, "Creez commit-ul"
) != 0:
L("\nEROARE la commit. Verifica numele/emailul Git si mesajul de mai sus.")
return
L("\n[5/5] git push ...")
if ruleaza_cu_fereastra(
["git", "push", "--progress"],
clona, log_win, L, "Trimit fisierele pe GitHub (git push)"
) != 0:
L("\nEROARE la push. Verifica autentificarea GitHub (token / git credential manager).")
return
L("\n" + "=" * 60)
L("GATA! Fisierele au fost adaugate si trimise pe GitHub.")
L(repo_url)
L("=" * 60)
except Exception as exc:
L("\n" + "=" * 60)
L("EROARE: operatia nu a putut fi terminata.")
L(str(exc))
L("=" * 60)
finally:
# curata folderul temporar
log_win.status.set("Curat folderul temporar...")
log_win.win.update_idletasks()
try:
shutil.rmtree(temp, ignore_errors=True)
except Exception:
pass
log_win.gata()
# ----------------------------------------------------------------------------
def main():
repo_url = cere_repo()
if not repo_url:
return
folder, recursiv = cere_folder()
if not folder:
return
proceseaza(repo_url, folder, recursiv)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment