diff --git a/.fyt/HEAD b/.fyt/HEAD new file mode 100644 index 0000000..b93d09e --- /dev/null +++ b/.fyt/HEAD @@ -0,0 +1 @@ +ref: refs/heads/test \ No newline at end of file diff --git a/.fyt/index b/.fyt/index new file mode 100644 index 0000000..3f6f397 --- /dev/null +++ b/.fyt/index @@ -0,0 +1 @@ +{"Launching.md": "8a34efceef0ac0a1d28f6ecd6b787faa858fc371"} \ No newline at end of file diff --git a/.fyt/objects/blob/69bce968f88ac26eaa0ebf28d84639b42a4471d7 b/.fyt/objects/blob/69bce968f88ac26eaa0ebf28d84639b42a4471d7 new file mode 100644 index 0000000..0ff4ccd --- /dev/null +++ b/.fyt/objects/blob/69bce968f88ac26eaa0ebf28d84639b42a4471d7 @@ -0,0 +1 @@ +Ceci est un fichier de text \ No newline at end of file diff --git a/.fyt/objects/blob/8a34efceef0ac0a1d28f6ecd6b787faa858fc371 b/.fyt/objects/blob/8a34efceef0ac0a1d28f6ecd6b787faa858fc371 new file mode 100644 index 0000000..85f30c0 --- /dev/null +++ b/.fyt/objects/blob/8a34efceef0ac0a1d28f6ecd6b787faa858fc371 @@ -0,0 +1,14 @@ +## Prérequis + +- Assurez-vous d'avoir Python 3 installé : + ```bash + python --version + ``` + +## Lancement du script + +Pour exécuter le script, utilisez la commande suivante : +```bash +python terminal.py [arguments] +``` +Remplacez `[arguments]` par les paramètres nécessaires selon l'utilisation du script. diff --git a/.fyt/objects/blob/bc9b311544d0687f60b2a17b1d2055e8c631ea73 b/.fyt/objects/blob/bc9b311544d0687f60b2a17b1d2055e8c631ea73 new file mode 100644 index 0000000..bc21a2d --- /dev/null +++ b/.fyt/objects/blob/bc9b311544d0687f60b2a17b1d2055e8c631ea73 @@ -0,0 +1,55 @@ +# **Comment lancer le script** +--- +## Cas de script Bash +**Rendre le fichier script exécutable** +```bash +chmod +x my_hash_object.sh #Rend le script exécutable +``` + +**Lancer le fichier avec un argument** +```bash +./my_hash_object.sh mon_fichier.txt +``` + +## Cas de script Python (notre cas) + +```bash +python3 --version # Vérifie que Python 3 est installé + +python3 git_hash_object.py mon_fichier.txt +``` +--- +**ou alors** +## Pour le script Bash +Place-le dans un dossier de ton PATH (par exemple ~/bin/). + +Ou utilise un alias dans ton ```.bashrc :``` + +```bash +alias git-hash-object="$HOME/path/to/my_hash_object.sh" +``` +### Pour le script Python +Rends-le exécutable : + +```bash +chmod +x git_hash_object.py +``` +Ajoute un shebang (première ligne du script) : + +```python +#!/usr/bin/env python3 +``` +Déplace-le dans un dossier du PATH ou utilise un alias : + +```bash +alias git-hash-object="python3 $HOME/path/to/git_hash_object.py" +``` +### Vérification avec Git +Compare le résultat avec la commande réelle de Git : + +```bash +git hash-object test.txt +``` + +[extrait de deepseek](https://chat.deepseek.com/a/chat/s/00c34d42-1c8e-4fcf-8f1a-a551c10f2804) +Ces étapes peuvent varier entre les utilisateurs de windows et de MacOS \ No newline at end of file diff --git a/.fyt/objects/commit/9c4b60dfe9f0b12263841644845dc8fc2d32bc5a b/.fyt/objects/commit/9c4b60dfe9f0b12263841644845dc8fc2d32bc5a new file mode 100644 index 0000000..ff3a3ba --- /dev/null +++ b/.fyt/objects/commit/9c4b60dfe9f0b12263841644845dc8fc2d32bc5a @@ -0,0 +1 @@ +{"tree": "2340a8db5d75bd52c074df36bd760aa1531b81be", "message": "bonjour", "date": "2025-07-02T16:21:34.769908"} \ No newline at end of file diff --git a/.fyt/objects/commit/d167f8150b32689b88347ca2b4ad552757bbaa1d b/.fyt/objects/commit/d167f8150b32689b88347ca2b4ad552757bbaa1d new file mode 100644 index 0000000..3f12680 --- /dev/null +++ b/.fyt/objects/commit/d167f8150b32689b88347ca2b4ad552757bbaa1d @@ -0,0 +1 @@ +{"tree": "ae91d2597f41e32b3246644d0da6002b7459efc1", "message": "bonjour", "date": "2025-07-16T15:00:53.235825"} \ No newline at end of file diff --git a/.fyt/objects/commit/d52abe7ef4782155953505139bb08ccf597be44e b/.fyt/objects/commit/d52abe7ef4782155953505139bb08ccf597be44e new file mode 100644 index 0000000..008c27e --- /dev/null +++ b/.fyt/objects/commit/d52abe7ef4782155953505139bb08ccf597be44e @@ -0,0 +1 @@ +{"tree": "ae91d2597f41e32b3246644d0da6002b7459efc1", "message": "bonjour", "date": "2025-07-16T15:11:14.809683"} \ No newline at end of file diff --git a/.fyt/objects/tree/2340a8db5d75bd52c074df36bd760aa1531b81be b/.fyt/objects/tree/2340a8db5d75bd52c074df36bd760aa1531b81be new file mode 100644 index 0000000..0004334 --- /dev/null +++ b/.fyt/objects/tree/2340a8db5d75bd52c074df36bd760aa1531b81be @@ -0,0 +1 @@ +{"files": [["test\\fichier.txt", "69bce968f88ac26eaa0ebf28d84639b42a4471d7"], ["launching.md", "bc9b311544d0687f60b2a17b1d2055e8c631ea73"]]} \ No newline at end of file diff --git a/.fyt/objects/tree/ae91d2597f41e32b3246644d0da6002b7459efc1 b/.fyt/objects/tree/ae91d2597f41e32b3246644d0da6002b7459efc1 new file mode 100644 index 0000000..1df9ce7 --- /dev/null +++ b/.fyt/objects/tree/ae91d2597f41e32b3246644d0da6002b7459efc1 @@ -0,0 +1 @@ +{"files": [["Launching.md", "8a34efceef0ac0a1d28f6ecd6b787faa858fc371"]]} \ No newline at end of file diff --git a/.fyt/refs/heads/main b/.fyt/refs/heads/main new file mode 100644 index 0000000..0e9fa5b --- /dev/null +++ b/.fyt/refs/heads/main @@ -0,0 +1 @@ +d167f8150b32689b88347ca2b4ad552757bbaa1d \ No newline at end of file diff --git a/.fyt/refs/heads/test b/.fyt/refs/heads/test new file mode 100644 index 0000000..33b14af --- /dev/null +++ b/.fyt/refs/heads/test @@ -0,0 +1 @@ +d52abe7ef4782155953505139bb08ccf597be44e \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..afe4e93 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*/__pycache__/ +*/*.pyc \ No newline at end of file diff --git a/Launching.md b/Launching.md new file mode 100644 index 0000000..85f30c0 --- /dev/null +++ b/Launching.md @@ -0,0 +1,14 @@ +## Prérequis + +- Assurez-vous d'avoir Python 3 installé : + ```bash + python --version + ``` + +## Lancement du script + +Pour exécuter le script, utilisez la commande suivante : +```bash +python terminal.py [arguments] +``` +Remplacez `[arguments]` par les paramètres nécessaires selon l'utilisation du script. diff --git a/Objects/__pycache__/commit.cpython-313.pyc b/Objects/__pycache__/commit.cpython-313.pyc new file mode 100644 index 0000000..3c83f58 Binary files /dev/null and b/Objects/__pycache__/commit.cpython-313.pyc differ diff --git a/Objects/__pycache__/o_commit.cpython-313.pyc b/Objects/__pycache__/o_commit.cpython-313.pyc new file mode 100644 index 0000000..e13a11f Binary files /dev/null and b/Objects/__pycache__/o_commit.cpython-313.pyc differ diff --git a/Objects/__pycache__/o_tree.cpython-313.pyc b/Objects/__pycache__/o_tree.cpython-313.pyc new file mode 100644 index 0000000..20319b0 Binary files /dev/null and b/Objects/__pycache__/o_tree.cpython-313.pyc differ diff --git a/Objects/__pycache__/tree.cpython-313.pyc b/Objects/__pycache__/tree.cpython-313.pyc new file mode 100644 index 0000000..00ebdac Binary files /dev/null and b/Objects/__pycache__/tree.cpython-313.pyc differ diff --git a/Objects/o_blob.py b/Objects/o_blob.py new file mode 100644 index 0000000..a2b24e7 --- /dev/null +++ b/Objects/o_blob.py @@ -0,0 +1,7 @@ +class Blob: + def setBlob(self, sha1, donnees): + self.sha1 = sha1 + self.donnees = donnees + + def getBlobHash(self): + return self.sha1 \ No newline at end of file diff --git a/Objects/o_commit.py b/Objects/o_commit.py new file mode 100644 index 0000000..6d66197 --- /dev/null +++ b/Objects/o_commit.py @@ -0,0 +1,60 @@ +import hashlib +import datetime +import os +import json + +class Commit: + def setCommit(self, tree_sha1, message, parent_sha1=None): + # Construction du contenu du commit pour le hash + commit_content = f"tree {tree_sha1}\n" + commit_content += f"message {message}\n" + if parent_sha1: + commit_content += f"parent {parent_sha1}\n" + + commit_bytes = commit_content.encode("utf-8") + self.sha1 = hashlib.sha1(commit_bytes).hexdigest() + + # Préparation des données à sauvegarder au format JSON + commit_data = { + "tree": tree_sha1, + "message": message, + "date": datetime.datetime.now().isoformat() + } + if parent_sha1: + commit_data["parent"] = parent_sha1 + + dir_path = ".fyt/objects/commit" + file_path = os.path.join(dir_path, self.sha1) + if os.path.exists(file_path): + with open(file_path, "r") as f: + content = json.load(f) + self.ref = content.get("tree") + self.parent = content.get("parent") + self.date = datetime.datetime.fromisoformat(content.get("date")) + self.message = content.get("message") + print("Un commit identique existe déjà. Aucun nouveau commit créé.") + return + + self.ref = tree_sha1 + self.parent = parent_sha1 + self.date = datetime.datetime.fromisoformat(commit_data["date"]) + self.message = message + + os.makedirs(dir_path, exist_ok=True) + with open(file_path, "w") as f: + json.dump(commit_data, f) + + def getCommitHash(self): + return self.sha1 + + def getCommitDate(self): + return self.date + + def getCommitRef(self): + return self.ref + + def getCommitMessage(self): + return self.message + + def getCommitParent(self): + return self.parent \ No newline at end of file diff --git a/Objects/o_tree.py b/Objects/o_tree.py new file mode 100644 index 0000000..d44ea54 --- /dev/null +++ b/Objects/o_tree.py @@ -0,0 +1,31 @@ +import os +import json +import hashlib + +class Tree: + def setTree(self): + # Charge l'index pour obtenir les chemins d'origine et les hashes de blob + with open(".fyt/index", "r", encoding="utf-8") as idx_file: + index = json.load(idx_file) + + # Construit la liste des fichiers pour le tree + files = [[path, blob_hash] for path, blob_hash in index.items()] + + tree_data = {"files": files} + tree_json = json.dumps(tree_data).encode("utf-8") + self.sha1 = hashlib.sha1(tree_json).hexdigest() + self.files = files + + # Sauvegarde dans .fyt/objects/tree/ + dir_path = ".fyt/objects/tree/" + file_path = os.path.join(dir_path, self.sha1) + if os.path.exists(file_path): + print("Un tree identique existe déjà. Aucun nouveau tree créé.") + return + + os.makedirs(dir_path, exist_ok=True) + with open(file_path, "wb") as f: + f.write(tree_json) + + def getFiles(self): + return self.files \ No newline at end of file diff --git a/__pycache__/add.cpython-313.pyc b/__pycache__/add.cpython-313.pyc new file mode 100644 index 0000000..8bd393e Binary files /dev/null and b/__pycache__/add.cpython-313.pyc differ diff --git a/__pycache__/commit.cpython-313.pyc b/__pycache__/commit.cpython-313.pyc new file mode 100644 index 0000000..dae819b Binary files /dev/null and b/__pycache__/commit.cpython-313.pyc differ diff --git a/__pycache__/commit_tree.cpython-313.pyc b/__pycache__/commit_tree.cpython-313.pyc new file mode 100644 index 0000000..a54bd3b Binary files /dev/null and b/__pycache__/commit_tree.cpython-313.pyc differ diff --git a/__pycache__/init.cpython-313.pyc b/__pycache__/init.cpython-313.pyc new file mode 100644 index 0000000..ed7d357 Binary files /dev/null and b/__pycache__/init.cpython-313.pyc differ diff --git a/__pycache__/ls_files.cpython-313.pyc b/__pycache__/ls_files.cpython-313.pyc new file mode 100644 index 0000000..778cd7d Binary files /dev/null and b/__pycache__/ls_files.cpython-313.pyc differ diff --git a/__pycache__/write_tree.cpython-313.pyc b/__pycache__/write_tree.cpython-313.pyc new file mode 100644 index 0000000..6a27e61 Binary files /dev/null and b/__pycache__/write_tree.cpython-313.pyc differ diff --git a/functions/__pycache__/add.cpython-313.pyc b/functions/__pycache__/add.cpython-313.pyc new file mode 100644 index 0000000..a3d6157 Binary files /dev/null and b/functions/__pycache__/add.cpython-313.pyc differ diff --git a/functions/__pycache__/cat_file.cpython-313.pyc b/functions/__pycache__/cat_file.cpython-313.pyc new file mode 100644 index 0000000..4c75273 Binary files /dev/null and b/functions/__pycache__/cat_file.cpython-313.pyc differ diff --git a/functions/__pycache__/checkout.cpython-313.pyc b/functions/__pycache__/checkout.cpython-313.pyc new file mode 100644 index 0000000..d9633c7 Binary files /dev/null and b/functions/__pycache__/checkout.cpython-313.pyc differ diff --git a/functions/__pycache__/commit.cpython-313.pyc b/functions/__pycache__/commit.cpython-313.pyc new file mode 100644 index 0000000..b4fcd46 Binary files /dev/null and b/functions/__pycache__/commit.cpython-313.pyc differ diff --git a/functions/__pycache__/commit_tree.cpython-313.pyc b/functions/__pycache__/commit_tree.cpython-313.pyc new file mode 100644 index 0000000..442740d Binary files /dev/null and b/functions/__pycache__/commit_tree.cpython-313.pyc differ diff --git a/functions/__pycache__/init.cpython-313.pyc b/functions/__pycache__/init.cpython-313.pyc new file mode 100644 index 0000000..3e56c81 Binary files /dev/null and b/functions/__pycache__/init.cpython-313.pyc differ diff --git a/functions/__pycache__/log.cpython-313.pyc b/functions/__pycache__/log.cpython-313.pyc new file mode 100644 index 0000000..2d90304 Binary files /dev/null and b/functions/__pycache__/log.cpython-313.pyc differ diff --git a/functions/__pycache__/ls_files.cpython-313.pyc b/functions/__pycache__/ls_files.cpython-313.pyc new file mode 100644 index 0000000..fb78a4c Binary files /dev/null and b/functions/__pycache__/ls_files.cpython-313.pyc differ diff --git a/functions/__pycache__/ls_tree.cpython-313.pyc b/functions/__pycache__/ls_tree.cpython-313.pyc new file mode 100644 index 0000000..b046426 Binary files /dev/null and b/functions/__pycache__/ls_tree.cpython-313.pyc differ diff --git a/functions/__pycache__/reset.cpython-313.pyc b/functions/__pycache__/reset.cpython-313.pyc new file mode 100644 index 0000000..dcafd69 Binary files /dev/null and b/functions/__pycache__/reset.cpython-313.pyc differ diff --git a/functions/__pycache__/rev_parse.cpython-313.pyc b/functions/__pycache__/rev_parse.cpython-313.pyc new file mode 100644 index 0000000..abb28d7 Binary files /dev/null and b/functions/__pycache__/rev_parse.cpython-313.pyc differ diff --git a/functions/__pycache__/show_ref.cpython-313.pyc b/functions/__pycache__/show_ref.cpython-313.pyc new file mode 100644 index 0000000..441a9eb Binary files /dev/null and b/functions/__pycache__/show_ref.cpython-313.pyc differ diff --git a/functions/__pycache__/write_tree.cpython-313.pyc b/functions/__pycache__/write_tree.cpython-313.pyc new file mode 100644 index 0000000..edea5c4 Binary files /dev/null and b/functions/__pycache__/write_tree.cpython-313.pyc differ diff --git a/functions/add.py b/functions/add.py new file mode 100644 index 0000000..10af4b4 --- /dev/null +++ b/functions/add.py @@ -0,0 +1,85 @@ +import os +import json +import hashlib + +def add_file(file_path): + with open(file_path, "rb") as f: + content = f.read() + blob_hash = hashlib.sha1(content).hexdigest() + blob_dir = ".fyt/objects/blob" + os.makedirs(blob_dir, exist_ok=True) + blob_path = os.path.join(blob_dir, blob_hash) + + with open(blob_path, "wb") as f: + f.write(content) + + update_index(file_path, blob_hash) + print(f"Fichier '{file_path}' ajouté (Blob: {blob_hash})") + +def update_index(file_path, blob_hash): + index_path = ".fyt/index" + if os.path.exists(index_path): + with open(index_path, "r") as f: + content = f.read().strip() + if content: + index = json.loads(content) + else: + index = {} + else: + index = {} + + rel_path = os.path.relpath(file_path, os.getcwd()) + file_stat = os.stat(file_path) + + index[rel_path] = blob_hash + # Sauvegarder l'index + with open(index_path, "w") as f: + json.dump(index, f) + + +def status_all(): + index_path = ".fyt/index" + project_root = os.path.join(os.getcwd(), "projet-test") + + if os.path.exists(index_path): + with open(index_path, "r") as f: + content = f.read().strip() + if content: + index = json.loads(content) + else: + index = {} + else: + index = {} + + tracked_files = set(index.keys()) + working_dir_files = set() + + for root, dirs, files in os.walk(project_root): + # Exclure les dossiers cachés et __pycache__ + rel_root = os.path.relpath(root, project_root) + if rel_root == ".fyt" or rel_root.startswith(".fyt" + os.sep): + continue + if rel_root.startswith(".git") or rel_root.startswith("__pycache__") or rel_root.startswith("Objects" + os.sep + "__pycache__"): + continue + # Exclure tous les dossiers cachés + dirs[:] = [d for d in dirs if not d.startswith('.') and d != '__pycache__'] + for file in files: + if file.startswith('.') or file.endswith('.pyc'): + continue + path = os.path.join(root, file) + rel_path = os.path.relpath(path, os.getcwd()) # rel_path par rapport à la racine du projet global + working_dir_files.add(rel_path) + + with open(path, "rb") as f: + content = f.read() + current_hash = hashlib.sha1(content).hexdigest() + + if rel_path not in index: + print(f"{rel_path}: nouveau fichier non suivi") + elif index[rel_path] != current_hash: + print(f"{rel_path}: modifié") + else: + print(f"{rel_path}: inchangé") + + for tracked in tracked_files - working_dir_files: + print(f"{tracked}: supprimé") diff --git a/functions/cat_file.py b/functions/cat_file.py new file mode 100644 index 0000000..4882182 --- /dev/null +++ b/functions/cat_file.py @@ -0,0 +1,44 @@ +import os +import json + +def cat_file(t, prettier, hash_id): + # Recherche dans les dossiers d'objets possibles + object_dirs = [ + ".fyt/objects/blob", + ".fyt/objects/tree", + ".fyt/objects/commit" + ] + found = False + for obj_dir in object_dirs: + file_path = os.path.join(obj_dir, hash_id) + if os.path.exists(file_path): + found = True + # Affiche le type si demandé + if t: + if "blob" in obj_dir: + print("blob") + elif "tree" in obj_dir: + print("tree") + elif "commit" in obj_dir: + print("commit") + else: + print("unknown") + # Affiche le contenu si demandé + if prettier: + with open(file_path, "rb") as f: + try: + content = f.read().decode("utf-8") + # Si c'est du JSON, affiche joliment + try: + data = json.loads(content) + print(json.dumps(data, indent=2, ensure_ascii=False)) + except Exception: + print(content) + except Exception: + print(f"[binaire] {hash_id}") + # Affiche le hash si demandé + if not t and not prettier: + print("Il faut choisir une option pour afficher le contenu ou le type de l'objet.") + break + if not found: + print(f"Objet {hash_id} introuvable.") \ No newline at end of file diff --git a/functions/checkout.py b/functions/checkout.py new file mode 100644 index 0000000..ce123f8 --- /dev/null +++ b/functions/checkout.py @@ -0,0 +1,75 @@ +import os +import json +import sys + +def checkout(b, branch_or_sha): + # Vérifier le dépôt + if not os.path.exists('.fyt'): + print("Aucun dépôt Fyt trouvé.") + return + + ref = branch_or_sha + # Création d'une nouvelle branche si -b + if b: + # HEAD doit pointer sur le commit courant + with open('.fyt/HEAD', 'r') as f: + current_ref = f.read().strip() + if current_ref.startswith('ref:'): + current_ref = current_ref.split(' ')[1] + current_commit_file = os.path.join('.fyt', current_ref) + with open(current_commit_file, 'r') as f: + current_commit_sha = f.readlines()[-1].split()[0] + else: + current_commit_sha = current_ref + # Créer la branche + ref_path = os.path.join('.fyt', 'refs', 'heads', ref) + with open(ref_path, 'w') as f: + f.write(current_commit_sha) + print(f"Branche '{ref}' créée sur {current_commit_sha}.") + # HEAD sur la nouvelle branche + with open('.fyt/HEAD', 'w') as f: + f.write(f"ref: refs/heads/{ref}") + commit_sha = current_commit_sha + else: + # Changement de branche ou commit + ref_path = os.path.join('.fyt', 'refs', 'heads', ref) + if os.path.exists(ref_path): + with open(ref_path, 'r') as f: + commit_sha = f.read().strip() + with open('.fyt/HEAD', 'w') as f: + f.write(f"ref: refs/heads/{ref}") + else: + commit_sha = ref + with open('.fyt/HEAD', 'w') as f: + f.write(commit_sha) + + # Charger le commit + commit_path = os.path.join('.fyt', 'commits', commit_sha) + if not os.path.exists(commit_path): + print(f"Commit {commit_sha} introuvable.") + return + with open(commit_path, 'r') as f: + commit_data = json.load(f) + + # Restaurer les fichiers du commit avec gestion des conflits + for file_path, blob_sha in commit_data.items(): + blob_path = os.path.join('.fyt', 'objects', 'blob', blob_sha) + if not os.path.exists(blob_path): + print(f"Blob {blob_sha} manquant pour {file_path}.") + continue + # Vérifier les conflits + if os.path.exists(file_path): + with open(file_path, 'rb') as f: + current_content = f.read() + with open(blob_path, 'rb') as f: + new_content = f.read() + if current_content != new_content: + print(f"Conflit: {file_path} modifié localement. Non écrasé.") + continue + # Créer les dossiers si besoin + os.makedirs(os.path.dirname(file_path), exist_ok=True) + with open(blob_path, 'rb') as blob_file: + content = blob_file.read() + with open(file_path, 'wb') as out_file: + out_file.write(content) + print(f"Checkout terminé sur {branch_or_sha}.") diff --git a/functions/commit.py b/functions/commit.py new file mode 100644 index 0000000..e973393 --- /dev/null +++ b/functions/commit.py @@ -0,0 +1,53 @@ +import os +import json +import hashlib +import datetime + +def commit_changes(message): + index_path = ".fyt/index" + if not os.path.exists(index_path): + print("Rien à commit. Utilisez 'add' avant.") + return + + # Charger l'index + with open(index_path, "r") as f: + index = json.load(f) + # Créer un Tree (simplifié) + tree_data = {"files": list(index.items())} # En vrai, on stocke une structure de dossiers/fichiers + tree_json = json.dumps(tree_data).encode() + tree_hash = hashlib.sha1(tree_json).hexdigest() + + os.makedirs(".fyt/objects/tree", exist_ok=True) + + with open(f".fyt/objects/tree/{tree_hash}", "wb") as f: + f.write(tree_json) + + # Créer un Commit + commit_data = { + "tree": tree_hash, + "message": message, + "date": datetime.datetime.now().isoformat(), + } + commit_json = json.dumps(commit_data).encode() + commit_hash = hashlib.sha1(commit_json).hexdigest() + + os.makedirs(".fyt/objects/commit", exist_ok=True) + + with open(f".fyt/objects/commit/{commit_hash}", "wb") as f: + f.write(commit_json) + + # Mettre à jour la référence (branche courante) + with open(".fyt/HEAD", "r") as f: + ref = f.read().strip() + if ref.startswith("ref:"): + ref_path = os.path.join(".fyt", ref.split(" ", 1)[1]) + with open(ref_path, "w") as f: + f.write(commit_hash) + else: + # HEAD détaché, écriture directe + with open(".fyt/HEAD", "w") as f: + f.write(commit_hash) + + print(f"Commit [{commit_hash[:6]}]: {message}") + + # git status \ No newline at end of file diff --git a/functions/commit_tree.py b/functions/commit_tree.py new file mode 100644 index 0000000..3358f6a --- /dev/null +++ b/functions/commit_tree.py @@ -0,0 +1,5 @@ +from Objects.o_commit import Commit + +def commit_tree(tree_sha, message, parent_sha=None): + commit = Commit() + commit.setCommit(tree_sha, message, parent_sha) \ No newline at end of file diff --git a/functions/hash.py b/functions/hash.py new file mode 100644 index 0000000..252fd96 --- /dev/null +++ b/functions/hash.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +import sys +import hashlib + +def git_hash_object(file_path): + try: + # 1. Vérifier que le fichier existe + with open(file_path, 'rb') as f: + content = f.read() + + # 2. Construire l'en-tête du blob Git + header = f"blob {len(content)}\0".encode('utf-8') + blob_data = header + content + + # 3. Calculer le SHA-1 + sha1 = hashlib.sha1(blob_data).hexdigest() + + # 4. Afficher le hash + print(sha1) + + except FileNotFoundError: + print("Error: File does not exist or is a directory", file=sys.stderr) + sys.exit(1) + +if __name__ == "__main__": + if len(sys.argv) != 2: + print(f"Usage: {sys.argv[0]} ", file=sys.stderr) + sys.exit(1) + + git_hash_object(sys.argv[1]) diff --git a/functions/init.py b/functions/init.py new file mode 100644 index 0000000..a36204b --- /dev/null +++ b/functions/init.py @@ -0,0 +1,8 @@ +import os + +def init_repo(): + os.makedirs(".fyt/objects", exist_ok=True) + os.makedirs(".fyt/refs/heads", exist_ok=True) + with open(".fyt/HEAD", "w") as f: + f.write("ref: refs/heads/main\n") + print("Dépôt initialisé.\nVous êtes dans la branche 'main'.") \ No newline at end of file diff --git a/functions/log.py b/functions/log.py new file mode 100644 index 0000000..a48697a --- /dev/null +++ b/functions/log.py @@ -0,0 +1,24 @@ +import os + +def log(): + if not os.path.exists('.fyt'): + print("Aucun dépôt Fyt trouvé dans le répertoire actuel.") + return + + with open('.fyt/HEAD', 'r') as head_file: + ref = head_file.read().strip() + + if ref.startswith('ref:'): + ref = ref.split(' ')[1] + + commit_file = os.path.join('.fyt', ref) + + if not os.path.exists(commit_file): + print("Aucun commit trouvé.") + return + + with open(commit_file, 'r') as file: + commits = file.readlines() + + for commit in commits: + print(commit.strip()) \ No newline at end of file diff --git a/functions/ls_files.py b/functions/ls_files.py new file mode 100644 index 0000000..cbdbb8d --- /dev/null +++ b/functions/ls_files.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +import os +import sys +import json + +def find_fyt_dir(path): + prev = None + while path != prev: + dot = os.path.join(path, ".fyt") + if os.path.isdir(dot): + return dot + prev, path = path, os.path.dirname(path) + sys.exit("Erreur : pas de dépôt .fyt ici.") + +def ls_files(): + fytdir = find_fyt_dir(os.getcwd()) + idx = os.path.join(fytdir, "index") + if not os.path.exists(idx): + sys.exit("") # index inexistant → rien à lister + with open(idx, "r", encoding="utf-8") as f: + content = f.read().strip() + if content: + index_data = json.loads(content) + else: + index_data = {} + print( "l'index est vide, rien à lister") + for file_path in index_data.keys(): + print(file_path) + +if __name__ == "__main__": + ls_files() \ No newline at end of file diff --git a/functions/ls_tree.py b/functions/ls_tree.py new file mode 100644 index 0000000..8d70963 --- /dev/null +++ b/functions/ls_tree.py @@ -0,0 +1,33 @@ +import sys +import os +import json + +def find_fyt_dir(path): + prev = None + while path != prev: + dot = os.path.join(path, ".fyt") + if os.path.isdir(dot): + return dot + prev, path = path, os.path.dirname(path) + sys.exit("Erreur : pas de dépôt .fyt ici.") + +def ls_tree(tree_sha): + fytdir = find_fyt_dir(os.getcwd()) + tree_path = os.path.join(fytdir, "objects", "tree", tree_sha) + if not os.path.exists(tree_path): + sys.exit(f"Erreur : tree {tree_sha} introuvable.") + with open(tree_path, "r", encoding="utf-8") as f: + content = f.read().strip() + if not content: + print("Tree vide.") + return + + tree_data = json.loads(content) + if isinstance(tree_data, dict) and "files" in tree_data: + for file_path, sha in tree_data["files"]: + print(f"100644 blob {sha}\t{file_path}") + else: + print("Format de tree inattendu :\n" + str(tree_data)) + +if __name__ == "__main__": + ls_tree(sys.argv[1]) \ No newline at end of file diff --git a/functions/reset.py b/functions/reset.py new file mode 100644 index 0000000..24e39b2 --- /dev/null +++ b/functions/reset.py @@ -0,0 +1,28 @@ +import os + +def reset(soft=None, mixed=None, hard=None): + if soft: + os.remove(".fyt/HEAD") + print("Réinitialisation en mode 'soft'. Les commits sont enlevés mais l'index et le répertoire de travail sont conservés.") + # Logique pour la réinitialisation soft + elif mixed: + if os.path.exists(".fyt/HEAD"): + os.remove(".fyt/HEAD") + with open(".fyt/index", "w") as f: + pass + print("Réinitialisation en mode 'mixed'. L'index est réinitialisé mais le répertoire de travail est conservé.") + # Logique pour la réinitialisation mixed + elif hard: + if os.path.exists(".fyt/HEAD"): + os.remove(".fyt/HEAD") + with open(".fyt/index", "w") as f: + pass + for root, dirs, files in os.walk("test/"): + for file in files: + file_path = os.path.join(root, file) + if ".fyt" not in file_path: + os.remove(file_path) + print("Réinitialisation en mode 'hard'. L'index et le répertoire de travail sont réinitialisés.") + # Logique pour la réinitialisation hard + else: + print("Aucun mode de réinitialisation spécifié. Veuillez utiliser -soft, -mixed ou -hard.") \ No newline at end of file diff --git a/functions/rev_parse.py b/functions/rev_parse.py new file mode 100644 index 0000000..f558ca6 --- /dev/null +++ b/functions/rev_parse.py @@ -0,0 +1,74 @@ +import json +import os + +def rev_parse(ref): + # 1. HEAD (fichier spécial) + if ref == "HEAD" and os.path.exists(".fyt/HEAD"): + with open(".fyt/HEAD", "r") as f: + head_content = f.read().strip() + if head_content.startswith("ref:"): + # Résout la ref HEAD récursivement + ref_path = head_content.split(":", 1)[1].strip() + # Enlève le préfixe "refs/" si présent pour matcher les branches + if ref_path.startswith("refs/"): + ref_path = ref_path[5:] + return rev_parse(ref_path) + else: + print(head_content) + return + + # 2. refs (branche ou tag, y compris sous-dossiers) + refs_root = ".fyt/refs" + if os.path.exists(refs_root): + for root, _, files in os.walk(refs_root): + for file in files: + abs_path = os.path.join(root, file) + rel_path = os.path.relpath(abs_path, refs_root).replace("\\", "/") + if ref == file or ref == rel_path: + with open(abs_path, "r") as f: + print(f.read().strip()) + return + + # 3. objets (commit/tree/blob) et recherche par préfixe + object_dirs = [ + ".fyt/objects/commit", + ".fyt/objects/tree", + ".fyt/objects/blob" + ] + possible_matches = [] + for obj_dir in object_dirs: + if os.path.exists(obj_dir): + for fname in os.listdir(obj_dir): + if fname == ref: + print(fname) + return + if fname.startswith(ref): + possible_matches.append(fname) + if len(possible_matches) == 1: + print(possible_matches[0]) + return + elif len(possible_matches) > 1: + print(f"Plusieurs objets correspondent au préfixe : {ref}") + return + + # 4. index (blobs) + index_path = ".fyt/index" + if os.path.exists(index_path): + with open(index_path, "r", encoding="utf-8") as f: + index = json.load(f) + if ref in index: + print(index[ref]) + return + for blob_hash in index.values(): + if ref == blob_hash: + print(blob_hash) + return + matches = [blob_hash for blob_hash in index.values() if blob_hash.startswith(ref)] + if len(matches) == 1: + print(matches[0]) + return + elif len(matches) > 1: + print(f"Plusieurs objets correspondent au préfixe : {ref}") + return + + print(f"Référence inconnue : {ref}") \ No newline at end of file diff --git a/functions/rm.py b/functions/rm.py new file mode 100644 index 0000000..1655e64 --- /dev/null +++ b/functions/rm.py @@ -0,0 +1,33 @@ +import os +import json + +def remove_from_index(file_path, index_dir=".git"): + index_path = os.path.join(index_dir, "index") + + if not os.path.exists(index_path): + return + + try: + with open(index_path, "r") as f: + index = json.load(f) + except json.JSONDecodeError: + index = {} + + rel_path = os.path.relpath(file_path, os.getcwd()) + + if rel_path in index: + del index[rel_path] + with open(index_path, "w") as f: + json.dump(index, f, indent=2) + +def fyt_rm(file_path, index_dir=".git"): + if os.path.exists(file_path): + os.remove(file_path) + print(f"{file_path} supprimé du disque.") + else: + print(f"Fichier introuvable : {file_path}") + return + + # Supprime le fichier de l'index + remove_from_index(file_path, index_dir) + print(f"{file_path} supprimé de l'index.") diff --git a/functions/show_ref.py b/functions/show_ref.py new file mode 100644 index 0000000..014fe9f --- /dev/null +++ b/functions/show_ref.py @@ -0,0 +1,12 @@ +import json +import os + +def show_ref(): + index_path = ".fyt/index" + if not os.path.exists(index_path): + print("Aucune référence trouvée.") + return + with open(index_path, "r", encoding="utf-8") as f: + index = json.load(f) + for ref, hash_value in index.items(): + print(f"{ref}: {hash_value}") \ No newline at end of file diff --git a/functions/write_tree.py b/functions/write_tree.py new file mode 100644 index 0000000..cf054ca --- /dev/null +++ b/functions/write_tree.py @@ -0,0 +1,6 @@ +from Objects.o_tree import Tree +import os + +def write_tree(): + tree = Tree() + tree.setTree() \ No newline at end of file diff --git a/github_workflow.md b/github_workflow.md deleted file mode 100644 index a4577bd..0000000 --- a/github_workflow.md +++ /dev/null @@ -1,42 +0,0 @@ -# 🚀 Workflow GitHub d'Équipe - -## 1. Mettre à jour la branche locale principale -```bash -git checkout main -git pull origin main -``` - -## 2. Créer une branche de fonctionnalité -Nom convention : `feat/nom-de-la-feature` -```bash -git checkout -b feat/nom-de-la-feature -``` - -## 3. Développer la feature -- Faire des commits atomiques et clairs : - ```bash - git add . - git commit -m "message explicite" - ``` -- Pousser régulièrement : - ```bash - git push -u origin feat/nom-de-la-feature - ``` - -## 4. Créer une Pull Request (PR) -- Vers `main` (ou `dev` selon organisation) -- Remplir la description (ce qui a été fait, pourquoi, etc.) -- Ajouter les reviewers - -## 5. Code Review par un·e autre membre -- Si changements demandés : retourner à l’étape 3 - -## 6. Merge après validation -- Merge via GitHub (squash ou rebase selon convention) -- Supprimer la branche distante si terminé - -## 7. Rebaser régulièrement en cas de longue PR *(optionnel mais recommandé)* -```bash -git fetch origin -git rebase origin/main -``` diff --git a/projet-test/dsjhf.py b/projet-test/dsjhf.py new file mode 100644 index 0000000..e69de29 diff --git a/projet-test/fichier.txt b/projet-test/fichier.txt new file mode 100644 index 0000000..e69de29 diff --git a/terminal.py b/terminal.py new file mode 100755 index 0000000..cba6c31 --- /dev/null +++ b/terminal.py @@ -0,0 +1,122 @@ +import argparse + +from functions.add import add_file, status_all +from functions.commit import commit_changes +from functions.cat_file import cat_file +from functions.checkout import checkout +from functions.commit_tree import commit_tree +from functions.init import init_repo +from functions.log import log +from functions.ls_files import ls_files +from functions.ls_tree import ls_tree +from functions.reset import reset +from functions.rev_parse import rev_parse +from functions.rm import fyt_rm +from functions.show_ref import show_ref +from functions.write_tree import write_tree + + +parser = argparse.ArgumentParser() +subparsers = parser.add_subparsers(dest="command") + +# git add +parser_add = subparsers.add_parser("add", help="Ajoute un fichier à l'index") +parser_add.add_argument("file", help="Fichier à ajouter") + +# git cat-file -t -p +cat_file_parser = subparsers.add_parser("cat-file", help="Crée un tree à partir de l'index") +cat_file_parser.add_argument("-t", action="store_true", help="Affiche le type de l'objet") +cat_file_parser.add_argument("-p", action="store_true", help="Affiche le contenu de l'objet") +cat_file_parser.add_argument("hash", help="Affiche l'ID de l'objet") + +# git checkout -b +checkout_parser = subparsers.add_parser("checkout", help="Change de branche") +checkout_parser.add_argument("-b", action="store_true", help="Crée une nouvelle branche") +checkout_parser.add_argument("branch", help="Branche à laquelle se déplacer") + +# git commit -m "message" +parser_commit = subparsers.add_parser("commit", help="Crée un commit") +parser_commit.add_argument("-m", "--message", required=True, help="Message du commit") + +# git commit-tree -m "message" [-p ] +commit_tree_parser = subparsers.add_parser("commit-tree", help="Crée un commit à partir d'un tree existant") +commit_tree_parser.add_argument("tree_sha", help="SHA1 du tree à committer") +commit_tree_parser.add_argument("-m", required=True, help="message du commit") +commit_tree_parser.add_argument("-p", help="SHA1 du commit parent (optionnel)") + +# git init +subparsers.add_parser("init", help="Initialise un dépôt") + +# git log +subparsers.add_parser("log", help="Affiche l'historique des commits") + +# git ls-files +subparsers.add_parser("ls-files", help="Liste les fichiers dans l'index") + +# git ls-tree +tree_parser = subparsers.add_parser("ls-tree", help="Liste les fichiers dans un tree") +tree_parser.add_argument("tree_sha", help="SHA1 du tree à lister") + +# git reset -soft -mixed -hard +parser_reset = subparsers.add_parser("reset", help="Réinitialise l'index et le répertoire de travail") +parser_reset.add_argument("-soft", action="store_true", help="Enlève les commits mais garde l'index et le répertoire de travail") +parser_reset.add_argument("-mixed", action="store_true", help="Réinitialise l\'index mais pas le répertoire de travail") +parser_reset.add_argument("-hard", action="store_true", help="Réinitialise l'index et le répertoire de travail") + +# git rev-parse +parser_rev_parse = subparsers.add_parser("rev-parse", help="Convertit une référence Git en SHA1") +parser_rev_parse.add_argument("ref", help="Référence Git à convertir en SHA1") + +# git status-all +status_parser = subparsers.add_parser("status-all", help="Affiche le statut de tous les fichiers") + +#git show-ref +subparsers.add_parser("show-ref", help="Affiche les références du dépôt") + +# git write-tree +subparsers.add_parser("write-tree", help="Crée un tree à partir de l'index") + +# git remove +parser_remove = subparsers.add_parser("remove", help="Supprime un fichier du répertoire de travail") +parser_remove.add_argument("file", help="Fichier à supprimer") + + +args = parser.parse_args() + + +if args.command == "add": + add_file(args.file) +elif args.command == "commit": + commit_changes(args.message) +elif args.command == "cat-file": + cat_file(args.t, args.p, args.hash) +elif args.command == "checkout": + checkout(args.b, args.branch) +elif args.command == "commit-tree": + commit_tree(args.tree_sha, args.m, args.p) +elif args.command == "init": + init_repo() +elif args.command == "log": + log() +elif args.command == "ls-files": + ls_files() +elif args.command == "ls-tree": + ls_tree(args.tree_sha) +elif args.command == "reset": + reset(args.soft, args.mixed, args.hard) +elif args.command == "rev-parse": + rev_parse(args.ref) +elif args.command == "status-all": + status_all() +elif args.command == "show-ref": + show_ref() +elif args.command == "write-tree": + write_tree() +elif args.command == "rm": + if args.file: + fyt_rm(args.file) + else: + print("Erreur : vous devez fournir un nom de fichier.") + +else: + parser.print_help() \ No newline at end of file