From 6ba6844900377706118ce288669fdf69f6c8f196 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Wed, 5 Jan 2022 22:53:10 +0200 Subject: [PATCH 01/73] The project's initial commit --- .gitignore | 1 + .idea/.gitignore | 3 + .idea/.name | 1 + .../inspectionProfiles/profiles_settings.xml | 6 + .idea/misc.xml | 4 + .idea/modules.xml | 9 + .idea/vcs.xml | 7 + .idea/wit_project.iml | 9 + add_171.py | 74 ++++ branch_req.txt | 23 ++ checkout.py | 335 +++++++++++++++ commit.py | 140 +++++++ init.py | 22 + status.py | 225 ++++++++++ wit.py | 384 ++++++++++++++++++ wit_checks.py | 315 ++++++++++++++ 16 files changed, 1558 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/.name create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 .idea/wit_project.iml create mode 100644 add_171.py create mode 100644 branch_req.txt create mode 100644 checkout.py create mode 100644 commit.py create mode 100644 init.py create mode 100644 status.py create mode 100644 wit.py create mode 100644 wit_checks.py diff --git a/.gitignore b/.gitignore index b6e4761..dce79fc 100644 --- a/.gitignore +++ b/.gitignore @@ -127,3 +127,4 @@ dmypy.json # Pyre type checker .pyre/ +.wit diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..3e4e48b --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +.gitignore \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..d56657a --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..f21131b --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..288b36b --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/wit_project.iml b/.idea/wit_project.iml new file mode 100644 index 0000000..7b9db73 --- /dev/null +++ b/.idea/wit_project.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/add_171.py b/add_171.py new file mode 100644 index 0000000..a75d30b --- /dev/null +++ b/add_171.py @@ -0,0 +1,74 @@ +# upload 171 + +import os +from pathlib import Path +import shutil +import sys +from typing import Union + + +def init() -> None: + cwd = os.getcwd() + wit_path = os.path.join(cwd, '.wit') + os.mkdir(wit_path) + os.mkdir(os.path.join(wit_path, 'images')) + os.mkdir(os.path.join(wit_path, 'staging_area')) + + +def add(path_to_add: str) -> None: + file = Path(os.path.abspath(path_to_add)) + directory_with_wit = get_directory_with_wit(file) + if not directory_with_wit: + raise WitError("<.wit> file not found") + destination = directory_with_wit.joinpath('.wit', 'staging_area') + directories_to_copy = file.relative_to(directory_with_wit).parts[:-1] + for dir_name in directories_to_copy: + dirs = os.listdir(destination) + destination = destination.joinpath(dir_name) + if dir_name not in dirs: + destination.mkdir() + save_the_copy(destination, file) + + +def save_the_copy(destination: Path, file: Path) -> None: + if file.is_file(): + shutil.copy2(file, destination) + else: + destination_of_folder_if_doesnt_exists = destination.joinpath(file.name) + if destination_of_folder_if_doesnt_exists.exists(): + shutil.rmtree(destination_of_folder_if_doesnt_exists) + shutil.copytree(file, destination_of_folder_if_doesnt_exists) + + +def get_directory_with_wit(file: Path) -> Union[Path, bool]: + for parent in file.parents: + dir_lst = os.listdir(parent) + if '.wit' in dir_lst: # and os.path.isdir(os.path.abspath('.wit')): > never True. also with iterdir. why? + return parent + return False + + +class WitError(Exception): + pass + + +def is_init_status_command_correct(argv: list[str]) -> bool: + return len(argv) == 2 + + +def is_add_or_commit_command_correct(argv: list[str]) -> bool: + return len(argv) == 3 + + +if sys.argv[1] == 'init': + if is_init_status_command_correct(sys.argv): + init() + else: + print(fr"Usage: python {sys.argv[0]} init") + + +elif sys.argv[1] == 'add': + if is_add_or_commit_command_correct(sys.argv): + add(sys.argv[2]) + else: + print(fr"Usage: python {sys.argv[0]} add ") diff --git a/branch_req.txt b/branch_req.txt new file mode 100644 index 0000000..651b06b --- /dev/null +++ b/branch_req.txt @@ -0,0 +1,23 @@ +V +בעת הרצת הפקודה python path/to/wit.py branch NAME, צרו שורה חדשה ב־references.txt. השורה תראה כך: NAME=COMMIT_ID, +כאשר במקום NAME יופיע שמו של ה־branch, ובמקום COMMIT_ID יופיע מספרו של ה־commit שבו נמצא ה־HEAD בעת הרצת הפקודה. + +V +בעת הרצת פקודת checkout, יעודכן בקובץ בשם activated.txt שנמצא ישירות תחת התיקייה .wit, שמו של ה־branch שנמצא במצב “פעיל” בעת ביצוע הפקודה. זה יהיה כל תוכנו של הקובץ, +ולכן אפשר להרגיש בנוח לדרוס אותו. + +בעת הרצת פקודת commit, יתעדכן (כרגיל) ה־HEAD כך שיצביע ל־commit החדש שנוצר. +לפני עדכון ה־HEAD, בדקו אם ה־branch שנמצא במצב “פעיל” מצביע לאותו מקום שבו נמצא ה־HEAD. +אם כן, עדכנו את references.txt כך שה־branch יצביע למספר ה־commit החדש שנוצר. + +שינויים שצריך לעשות: + +V +בניגוד למה שנכתב ביום 2, בעת פקודת commit, התווית master כבר לא תתקדם כל פעם שהיא וה־HEAD נמצאים באותו מקום. כדי שתתקדם, היא חייבת שהתנאי המדובר יתקיים וגם שהענף יהיה “מופעל”. +הענף master “מופעל” והתווית תתקדם רק אם ה־checkout האחרון שהתבצע היה python wit.py checkout master. + +V +בעת הרצת הפקודה init, יווצר קובץ חדש בשם activated.txt שבו ירשם master. + +V +פקודת ה־checkout כעת צריכה להיות מסוגלת לקבל אחת משתי האפשרויות: או commit id, או שם של branch. diff --git a/checkout.py b/checkout.py new file mode 100644 index 0000000..8cf3efe --- /dev/null +++ b/checkout.py @@ -0,0 +1,335 @@ +# upload 174 +import datetime +import filecmp +import os +from pathlib import Path +import random +import shutil +import sys +from typing import Any, Generator, Optional, Union + + +def init() -> None: + cwd = os.getcwd() + wit_path = os.path.join(cwd, '.wit') + os.mkdir(wit_path) + os.mkdir(os.path.join(wit_path, 'images')) + os.mkdir(os.path.join(wit_path, 'staging_area')) + + +def add(path_to_add: str) -> None: + file_to_add = Path(os.path.abspath(path_to_add)) + repository = get_directory_with_wit(file_to_add) + if not repository: + raise WitError("<.wit> file not found") + destination = repository.joinpath('.wit', 'staging_area') + directories_to_copy = file_to_add.relative_to(repository).parts[:-1] + for dir_name in directories_to_copy: + dirs = os.listdir(destination) + destination = destination.joinpath(dir_name) + if dir_name not in dirs: + destination.mkdir() + save_the_copy(destination, file_to_add) + + +def save_the_copy(destination: Path, file: Path) -> None: + if file.is_file(): + shutil.copy2(file, destination) + else: + destination_of_folder_if_doesnt_exists = destination.joinpath(file.name) + if destination_of_folder_if_doesnt_exists.exists(): + shutil.rmtree(destination_of_folder_if_doesnt_exists) + shutil.copytree(file, destination_of_folder_if_doesnt_exists) + + +def get_directory_with_wit(file: Path) -> Optional[Path]: + for parent in file.parents: + dir_lst = os.listdir(parent) + if '.wit' in dir_lst: + return parent + return None + + +def commit(message: str) -> None: + dir_with_wit = get_directory_with_wit(Path.cwd()) + if not dir_with_wit: + raise WitError("<.wit> file not found") + images_path = dir_with_wit.joinpath('.wit', 'images') + path_of_new_folder = create_commit_folder(images_path) + create_commit_txt_file(dir_with_wit, images_path, path_of_new_folder, message) + save_files(dir_with_wit, path_of_new_folder) + commit_id = os.path.basename(path_of_new_folder) + write_references(commit_id, dir_with_wit) + + +def create_commit_folder(images_path: Path) -> str: + folder_name = create_commit_name() + path_of_new_folder = os.path.join(images_path, folder_name) + os.mkdir(path_of_new_folder) + return path_of_new_folder + + +def create_commit_name(): + length = 20 + chars = '1234567890abcdef' + folder_name = ''.join(random.choices(chars, k=length)) + return folder_name + + +def create_commit_txt_file(dir_with_wit: Path, images_path: Path, path_of_new_folder: str, message: str) -> None: + parent_head = get_parent_head(dir_with_wit) + txt_file = images_path.joinpath(Path(path_of_new_folder).name + '.txt') + txt_file.write_text( + f'parent = {parent_head if parent_head else None}\n' + f'date = {datetime.datetime.now().strftime("%c")}\n' + f'message = {message}' + ) + + +def get_parent_head(dir_with_wit: Path) -> str: + wit_folder = dir_with_wit.joinpath('.wit') # repository + r'\.wit' + references_file = wit_folder.joinpath('references.txt') + if references_file.exists(): + ref_path = wit_folder.joinpath('references.txt') + with ref_path.open() as f_h: + references_content = f_h.readlines() + head_line = references_content[0].split('=') + return head_line[1].strip() + return '' + + +def save_files(dir_with_wit: Path, path_of_new_folder: str) -> None: + staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') + for item in os.listdir(staging_area_path): + src = os.path.join(staging_area_path, item) + dst = os.path.join(path_of_new_folder, item) + if os.path.isfile(src): + shutil.copy2(src, dst) + else: + shutil.copytree(src, dst) + + +def write_references(commit_id: str, dir_with_wit: Path) -> None: + wit_folder = dir_with_wit.joinpath('.wit') + ref_file = wit_folder.joinpath('references.txt') + new_master = commit_id + if ref_file.exists(): + new_master = get_new_master(dir_with_wit, ref_file, commit_id) + ref_file.write_text(f'HEAD={commit_id}\nMASTER={new_master}') + + +def get_new_master(dir_with_wit: Path, ref_file: Path, commit_id: str) -> str: + old_head_id = get_parent_head(dir_with_wit) + old_master_id = get_master_commit_id(ref_file) + if old_head_id == old_master_id: + return commit_id + else: + return old_master_id + + +def status() -> None: + repository = get_directory_with_wit(Path.cwd()) + if not repository: + raise WitError("<.wit> file not found") + commit_id = get_parent_head(repository) + files_added_since_last_commit = get_files_added_since_last_commit(commit_id, repository) + files_changed_since_last_commit = get_files_changed_since_last_commit(commit_id, repository) + files_in_staging_area_that_dont_match_original = get_files_in_staging_area_that_dont_match_original(repository) + files_not_in_staging_area = get_files_not_in_staging_area(repository) + print( + f"Commit id: {commit_id}\n" + f"Changes to be committed: {(list(files_added_since_last_commit) + list(files_changed_since_last_commit))}\n" + f"Changes not staged for commit: {list(files_in_staging_area_that_dont_match_original)}\n" + f"Untracked files: {list(files_not_in_staging_area)}" + ) + + +def get_files_added_since_last_commit(commit_id: str, repository: Path) -> Generator[Any, Any, None]: + commit_path = os.path.join(repository, '.wit', 'images', commit_id) + staging_area_path = os.path.join(repository, '.wit', 'staging_area') + all_files_in_stagind_area_and_sub = get_files_of_dir_and_subdirs(staging_area_path) + all_files_in_commit_and_sub_dirs = get_files_of_dir_and_subdirs(commit_path) + for file in all_files_in_stagind_area_and_sub: + if file not in all_files_in_commit_and_sub_dirs: + yield file + + +def get_files_changed_since_last_commit(commit_id: str, repository: Path) -> Generator[str, Any, None]: + commit_path = os.path.join(repository, '.wit', 'images', commit_id) + staging_area_path = os.path.join(repository, '.wit', 'staging_area') + all_files_in_commit_and_sub = get_all_files_in_dir_and_subs(commit_path) + all_files_in_staging_area_and_sub = get_all_files_in_dir_and_subs(staging_area_path) + yield from get_names_of_changed_files( + all_files_in_commit_and_sub, all_files_in_staging_area_and_sub, commit_path, staging_area_path + ) + + +def get_names_of_changed_files( + all_files_in_commit_and_sub: Generator[Union[bytes, str], Any, None], + all_files_in_staging_area_and_sub: Generator[Union[bytes, str], Any, None], + commit_path: Union[str, Path], + staging_area_path: Union[str, Path] +) -> Generator[str, Any, None]: + for s_file in all_files_in_staging_area_and_sub: + for c_file in all_files_in_commit_and_sub: + if Path(s_file).relative_to(staging_area_path) == Path(c_file).relative_to(commit_path): + if not filecmp.cmp(s_file, c_file): + yield Path(s_file).name + + +def get_all_files_in_dir_and_subs(commit_path: str) -> Generator[Union[bytes, str], Any, None]: + for (root, dirs, files) in os.walk(commit_path, topdown=True): + for file in files: + yield os.path.join(root, file) + + +def get_files_in_staging_area_that_dont_match_original(repository: Path) -> Generator[str, Any, None]: + staging_area_path = os.path.join(repository, '.wit', 'staging_area') + all_files_in_repository_and_sub_dirs = get_all_files_and_dirs_in_repository(repository) + all_files_in_staging_area_and_sub = get_all_files_in_dir_and_subs(staging_area_path) + yield from get_names_of_changed_files( + all_files_in_staging_area_and_sub, all_files_in_repository_and_sub_dirs, staging_area_path, repository + ) + + +def get_all_files_and_dirs_in_repository(repository: Path) -> Generator[Union[bytes, str], Any, None]: + for (root, dirs, files) in os.walk(repository, topdown=True): + if '.wit' not in Path(root).parts: + for file in files: + yield os.path.join(root, file) + + +def get_files_not_in_staging_area(repository: Path) -> Generator[Any, Any, None]: + staging_area_path = os.path.join(repository, '.wit', 'staging_area') + files_names_in_repository_and_sub_dirs = get_files_names_of_repository_and_subs(repository) + all_files_in_staging_area_and_sub_dirs = get_files_of_dir_and_subdirs(staging_area_path) + for file in files_names_in_repository_and_sub_dirs: + if file not in all_files_in_staging_area_and_sub_dirs: + yield file + + +def get_files_names_of_repository_and_subs(repository: Path): + for (root, dirs, files) in os.walk(repository, topdown=True): + if '.wit' not in Path(root).parts: + for file in files: + yield file + + +def get_files_of_dir_and_subdirs(file_path: str) -> Generator[Any, Any, None]: + for (root, dirs, files) in os.walk(file_path, topdown=True): + for file in files: + yield file + + +def checkout(commit_id: str) -> None: + repository = get_directory_with_wit(Path.cwd()) + if not repository: + raise WitError("<.wit> file not found") + references_file = repository.joinpath('.wit', 'references.txt') + if commit_id == 'master': + commit_id = get_master_commit_id(references_file) + last_commit_id = get_parent_head(repository) + if ( + list(get_files_added_since_last_commit(last_commit_id, repository)) + or list(get_files_changed_since_last_commit(last_commit_id, repository)) + or list(get_files_in_staging_area_that_dont_match_original(repository)) + ): + raise FilesDoesntMatchError("There are files added or changed after last commit") + change_files_in_main_folder(repository, commit_id) + change_head_in_references_file(commit_id, references_file) + change_staging_area_folder(repository, commit_id) + + +def change_head_in_references_file(commit_id: str, references_file: Path) -> None: + with references_file.open() as file: + master_line = file.readlines()[1] + references_file.write_text(f'HEAD={commit_id}\n{master_line}') + + +def get_master_commit_id(references_file: Path) -> str: + with references_file.open() as file: + references_content = file.readlines() + master_line = references_content[-1].split('=') + commit_id = master_line[-1].strip() + return commit_id + + +def change_files_in_main_folder(repository: Path, commit_id: str) -> None: + commit_path = os.path.join(repository, '.wit', 'images', commit_id) + # all_files_in_repository_and_sub_dirs = get_all_files_and_dirs_in_repository(repository) + all_files_in_repository_and_sub_dirs = [] + for (root, dirs, files) in os.walk(repository, topdown=True): + if '.wit' not in Path(root).parts: + for file in files: + all_files_in_repository_and_sub_dirs.append(os.path.join(root, file)) + # all_files_in_commit_and_sub_dirs = get_files_of_dir_and_subdirs(commit_path) # didn't work with the functions + all_files_in_commit_and_sub_dirs = [] + for (root, dirs, files) in os.walk(commit_path, topdown=True): + for file in files: + all_files_in_commit_and_sub_dirs.append(os.path.join(root, file)) + for c_file in all_files_in_commit_and_sub_dirs: + for r_file in all_files_in_repository_and_sub_dirs: + if Path(r_file).relative_to(repository) == Path(c_file).relative_to(commit_path): + shutil.copy2(c_file, r_file) + + +def change_staging_area_folder(dir_with_wit: Path, commit_id: str): + staging_area_path = dir_with_wit.joinpath('.wit', 'staging_area') + commit_path = dir_with_wit.joinpath('.wit', 'images', commit_id) + for file_or_dir in staging_area_path.iterdir(): + if file_or_dir.is_file(): + file_or_dir.unlink() + else: + shutil.rmtree(file_or_dir) + for file in commit_path.iterdir(): + rel_path = Path(file).relative_to(commit_path) + if file.is_file(): + shutil.copy2(file, staging_area_path.joinpath(rel_path)) + else: + shutil.copytree(file, staging_area_path.joinpath(rel_path)) + + +class WitError(Exception): + pass + + +class FilesDoesntMatchError(Exception): + pass + + +def is_command_correct(argv: list[str]) -> bool: + if argv[1] in ['init', 'status']: + return len(argv) == 2 + else: + return len(argv) == 3 + + +if sys.argv[1] == 'init': + if is_command_correct(sys.argv): + init() + else: + print(fr"Usage: python {sys.argv[0]} init") + +elif sys.argv[1] == 'add': + if is_command_correct(sys.argv): + add(sys.argv[2]) + else: + print(fr"Usage: python {sys.argv[0]} add ") + +elif sys.argv[1] == 'commit': + if is_command_correct(sys.argv): + commit(sys.argv[2]) + else: + print(fr"Usage: python {sys.argv[0]} commit MESSAGE") + +elif sys.argv[1] == 'status': + if is_command_correct(sys.argv): + status() + else: + print(fr"Usage: python {sys.argv[0]} status") + +elif sys.argv[1] == 'checkout': + if is_command_correct(sys.argv): + checkout(sys.argv[2]) + else: + print(fr"Usage: python {sys.argv[0]} checkout ") diff --git a/commit.py b/commit.py new file mode 100644 index 0000000..c429d77 --- /dev/null +++ b/commit.py @@ -0,0 +1,140 @@ +# upload 172 +import datetime +import os +from pathlib import Path +import random +import shutil +import sys +from typing import Union + + +def init() -> None: + cwd = os.getcwd() + wit_path = os.path.join(cwd, '.wit') + os.mkdir(wit_path) + os.mkdir(os.path.join(wit_path, 'images')) + os.mkdir(os.path.join(wit_path, 'staging_area')) + + +def add(path_to_add: str) -> None: + file = Path(os.path.abspath(path_to_add)) + directory_with_wit = get_directory_with_wit(file) + if not directory_with_wit: + raise WitError("<.wit> file not found") + destination = directory_with_wit.joinpath('.wit', 'staging_area') + directories_to_copy = file.relative_to(directory_with_wit).parts[:-1] + for dir_name in directories_to_copy: + dirs = os.listdir(destination) + destination = destination.joinpath(dir_name) + if dir_name not in dirs: + destination.mkdir() + save_the_copy(destination, file) + + +def save_the_copy(destination: Path, file: Path) -> None: + if file.is_file(): + shutil.copy2(file, destination) + else: + destination_of_folder_if_doesnt_exists = destination.joinpath(file.name) + if destination_of_folder_if_doesnt_exists.exists(): + shutil.rmtree(destination_of_folder_if_doesnt_exists) + shutil.copytree(file, destination_of_folder_if_doesnt_exists) + + +def get_directory_with_wit(file: Path) -> Union[Path, bool]: + for parent in file.parents: + dir_lst = os.listdir(parent) + if '.wit' in dir_lst: # and os.path.isdir(os.path.abspath('.wit')): > never True. also with iterdir. why? + return parent + return False + + +def commit(message: str) -> None: + dir_with_wit = get_directory_with_wit(Path.cwd()) + if not dir_with_wit: + raise WitError("<.wit> file not found") + images_path = dir_with_wit.joinpath('.wit', 'images') + path_of_new_folder = create_commit_folder(images_path) + create_commit_txt_file(dir_with_wit, images_path, path_of_new_folder, message) + save_files(dir_with_wit, path_of_new_folder) + commit_id = os.path.basename(path_of_new_folder) + write_references(commit_id, dir_with_wit) + + +def create_commit_folder(images_path: Path) -> str: + length = 20 + chars = '1234567890abcdef' + folder_name = ''.join(random.choice(chars) for _ in range(length)) + path_of_new_folder = os.path.join(images_path, folder_name) + os.mkdir(path_of_new_folder) + return path_of_new_folder + + +def create_commit_txt_file(dir_with_wit: Path, images_path: Path, path_of_new_folder: str, message: str) -> None: + parent_head = get_parent_head(dir_with_wit) + txt_file = images_path.joinpath(Path(path_of_new_folder).name + '.txt') + txt_file.write_text( + f'parent = {parent_head if parent_head else None}\n' + f'date = {datetime.datetime.now().strftime("%c")}\n' + f'message = {message}' + ) + + +def get_parent_head(dir_with_wit: Path) -> str: + wit_folder = dir_with_wit.joinpath('.wit') # repository + r'\.wit' + if 'references.txt' in os.listdir(wit_folder): + ref_path = wit_folder.joinpath('references.txt') + with ref_path.open() as f_h: + references_file = f_h.readlines() + return references_file[0][5:].strip() + return '' + + +def save_files(dir_with_wit: Path, path_of_new_folder: str) -> None: + staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') + for item in os.listdir(staging_area_path): + src = os.path.join(staging_area_path, item) + dst = os.path.join(path_of_new_folder, item) + if os.path.isfile(src): + shutil.copy2(src, dst) + else: + shutil.copytree(src, dst) + + +def write_references(commit_id: str, dir_with_wit: Path) -> None: + wit_folder = dir_with_wit.joinpath('.wit') + ref_file = wit_folder.joinpath('references.txt') + ref_file.write_text(f'HEAD={commit_id}\nMASTER={commit_id}\n') + + +class WitError(Exception): + pass + + +def is_init_status_command_correct(argv: list[str]) -> bool: + return len(argv) == 2 + + +def is_add_or_commit_command_correct(argv: list[str]) -> bool: + return len(argv) == 3 + + +if sys.argv[1] == 'init': + if is_init_status_command_correct(sys.argv): + init() + else: + print(fr"Usage: python {sys.argv[0]} init") + + +elif sys.argv[1] == 'add': + if is_add_or_commit_command_correct(sys.argv): + add(sys.argv[2]) + else: + print(fr"Usage: python {sys.argv[0]} add ") + + +elif sys.argv[1] == 'commit': + if is_add_or_commit_command_correct(sys.argv): + commit(sys.argv[2]) + else: + print(fr"Usage: python {sys.argv[0]} commit MESSAGE") diff --git a/init.py b/init.py new file mode 100644 index 0000000..7f91f61 --- /dev/null +++ b/init.py @@ -0,0 +1,22 @@ +# upload 170 +import os +import sys + + +def init(): + cwd = os.getcwd() + wit_path = os.path.join(cwd, '.wit') + os.mkdir(wit_path) + os.mkdir(os.path.join(wit_path, 'images')) + os.mkdir(os.path.join(wit_path, 'staging_area')) + + +def is_init_command_correct(argv): + return len(argv) == 2 + + +if sys.argv[1] == 'init': + if is_init_command_correct(sys.argv): + init() + else: + print(r"Usage: python C:\Users\israe\PycharmProjects\wit_project\wit.py init") diff --git a/status.py b/status.py new file mode 100644 index 0000000..30a8671 --- /dev/null +++ b/status.py @@ -0,0 +1,225 @@ +# upload 173 +import datetime +from filecmp import dircmp +import os +from pathlib import Path +import random +import shutil +import sys +from typing import Iterator, Optional, Union + + +def init() -> None: + cwd = os.getcwd() + wit_path = os.path.join(cwd, '.wit') + os.mkdir(wit_path) + os.mkdir(os.path.join(wit_path, 'images')) + os.mkdir(os.path.join(wit_path, 'staging_area')) + + +def add(path_to_add: str) -> None: + file = Path(os.path.abspath(path_to_add)) + directory_with_wit = get_directory_with_wit(file) + if not directory_with_wit: + raise WitError("<.wit> file not found") + destination = directory_with_wit.joinpath('.wit', 'staging_area') + directories_to_copy = file.relative_to(directory_with_wit).parts[:-1] + for dir_name in directories_to_copy: + dirs = os.listdir(destination) + destination = destination.joinpath(dir_name) + if dir_name not in dirs: + destination.mkdir() + save_the_copy(destination, file) + + +def save_the_copy(destination: Path, file: Path) -> None: + if file.is_file(): + shutil.copy2(file, destination) + else: + destination_of_folder_if_doesnt_exists = destination.joinpath(file.name) + if destination_of_folder_if_doesnt_exists.exists(): + shutil.rmtree(destination_of_folder_if_doesnt_exists) + shutil.copytree(file, destination_of_folder_if_doesnt_exists) + + +# get the repository if exists, else- None. +def get_directory_with_wit(file: Path) -> Optional[Path]: + parents = file.parents + for p in parents: + wit = Path.joinpath(p, '.wit') + if wit.is_dir(): + return p + return None + + +def commit(message: str) -> None: + dir_with_wit = get_directory_with_wit(Path.cwd()) + if not dir_with_wit: + raise WitError("<.wit> file not found") + images_path = dir_with_wit.joinpath('.wit', 'images') + path_of_new_folder = create_commit_folder(images_path) + create_commit_txt_file(dir_with_wit, images_path, path_of_new_folder, message) + save_files(dir_with_wit, path_of_new_folder) + commit_id = os.path.basename(path_of_new_folder) + write_references(commit_id, dir_with_wit) + + +def create_commit_folder(images_path: Path) -> str: + length = 20 + chars = '1234567890abcdef' + folder_name = ''.join(random.choice(chars) for _ in range(length)) + path_of_new_folder = os.path.join(images_path, folder_name) + os.mkdir(path_of_new_folder) + return path_of_new_folder + + +def create_commit_txt_file(dir_with_wit: Path, images_path: Path, path_of_new_folder: str, message: str) -> None: + parent_head = get_parent_head(dir_with_wit) + txt_file = images_path.joinpath(Path(path_of_new_folder).name + '.txt') + txt_file.write_text( + f'parent = {parent_head if parent_head else None}\n' + f'date = {datetime.datetime.now().strftime("%c")}\n' + f'message = {message}' + ) + + +# if references file exists- return the HEAD, else- return ''. +def get_parent_head(dir_with_wit: Path) -> str: + wit_folder = dir_with_wit.joinpath('.wit') + references_file = wit_folder.joinpath('references.txt') + if references_file.exists(): + ref_path = wit_folder.joinpath('references.txt') + with ref_path.open() as f_h: + references_content = f_h.readlines() + head_line = references_content[0].split('=') + return head_line[1].strip() + return '' + + +def save_files(dir_with_wit: Path, path_of_new_folder: str) -> None: + staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') + for item in os.listdir(staging_area_path): + src = os.path.join(staging_area_path, item) + dst = os.path.join(path_of_new_folder, item) + if os.path.isfile(src): + shutil.copy2(src, dst) + else: + shutil.copytree(src, dst) + + +def write_references(commit_id: str, dir_with_wit: Path) -> None: + wit_folder = dir_with_wit.joinpath('.wit') + ref_file = wit_folder.joinpath('references.txt') + ref_file.write_text(f'HEAD={commit_id}\nMASTER={commit_id}\n') + + +def status() -> None: + repository = get_directory_with_wit(Path.cwd()) + if not repository: + raise WitError("<.wit> file not found") + commit_id = get_parent_head(repository) + commit_path = os.path.join(repository, '.wit', 'images', commit_id) + staging_area_path = os.path.join(repository, '.wit', 'staging_area') + changes_to_be_committed = list(get_changes_to_be_committed(commit_path, staging_area_path)) + changes_not_staged_for_commit = list(get_changes_not_staged_for_commit(repository, staging_area_path)) + untracked_files = list(get_untracked_files(repository, staging_area_path)) + print( + f"Commit id: {commit_id}\n" + f"Changes to be committed: {changes_to_be_committed}\n" + f"Changes not staged for commit: {changes_not_staged_for_commit}\n" + f"Untracked files: {untracked_files}" + ) + + +def get_all_files_in_directory_and_subs(directory: Union[Path, str], start_path: Union[Path, str]) -> Iterator[str]: + for (root, dirs, files) in os.walk(directory, topdown=True): + for file in files: + file_path = os.path.join(root, file) + rel = os.path.relpath(file_path, start=start_path) + yield rel + + +def get_changes_to_be_committed(commit_path: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: + cmp = dircmp(commit_path, staging_area_path) + yield from get_new_and_changed_files(cmp, staging_area_path) + for d, d_cmp in cmp.subdirs.items(): + yield from get_new_and_changed_files(d_cmp, os.path.join(staging_area_path, d)) + + +def get_new_and_changed_files(cmp: dircmp[Union[str, bytes]], staging_area_path: Union[Path, str]) -> Iterator[str]: + yield from get_new_files_added(cmp, staging_area_path) + yield from get_changed_files(cmp, staging_area_path) + + +def get_changed_files(cmp: dircmp[Union[str, bytes]], staging_area_path) -> Iterator[str]: + diff_files = cmp.diff_files + start_path = os.path.join(get_directory_with_wit(Path.cwd()), '.wit', 'staging_area') + for diff in diff_files: + file_path = os.path.join(staging_area_path, diff) + + rel = os.path.relpath(file_path, start=start_path) + yield rel + + +def get_new_files_added(cmp: dircmp[Union[str, bytes]], staging_area_path: Union[Path, str]) -> Iterator[str]: + new_files_added = cmp.right_only + start_path = get_directory_with_wit(Path.cwd()) + for f in new_files_added: + f_path = os.path.join(staging_area_path, f) + if os.path.isfile(f_path): + yield f + else: + yield from get_all_files_in_directory_and_subs(f_path, start_path) + + +def get_changes_not_staged_for_commit( + repository: Union[Path, str], staging_area_path: Union[Path, str] +) -> Iterator[str]: + cmp = dircmp(repository, staging_area_path) + yield from get_changed_files(cmp, staging_area_path) + for common_dir in cmp.common_dirs: + path_in_repository = os.path.join(repository, common_dir) + path_in_staging_area = os.path.join(staging_area_path, common_dir) + yield from get_changes_not_staged_for_commit(path_in_repository, path_in_staging_area) + + +def get_untracked_files(repository: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: + cmp = dircmp(staging_area_path, repository, ignore=['.wit']) + yield from get_new_files_added(cmp, repository) # + + +class WitError(Exception): + pass + + +def is_init_status_command_correct(argv: list[str]) -> bool: + return len(argv) == 2 + + +def is_add_or_commit_command_correct(argv: list[str]) -> bool: + return len(argv) == 3 + + +if sys.argv[1] == 'init': + if is_init_status_command_correct(sys.argv): + init() + else: + print(fr"Usage: python {sys.argv[0]} init") + +elif sys.argv[1] == 'add': + if is_add_or_commit_command_correct(sys.argv): + add(sys.argv[2]) + else: + print(fr"Usage: python {sys.argv[0]} add ") + +elif sys.argv[1] == 'commit': + if is_add_or_commit_command_correct(sys.argv): + commit(sys.argv[2]) + else: + print(fr"Usage: python {sys.argv[0]} commit MESSAGE") + +elif sys.argv[1] == 'status': + if is_init_status_command_correct(sys.argv): + status() + else: + print(fr"Usage: python {sys.argv[0]} status") diff --git a/wit.py b/wit.py new file mode 100644 index 0000000..bb702b3 --- /dev/null +++ b/wit.py @@ -0,0 +1,384 @@ +# upload 176 +import datetime +import filecmp +import os +from pathlib import Path +import random +import shutil +import sys +from typing import Any, Generator, Optional, Union + + +def init() -> None: + cwd = os.getcwd() + wit_path = os.path.join(cwd, '.wit') + os.mkdir(wit_path) + os.mkdir(os.path.join(wit_path, 'images')) + os.mkdir(os.path.join(wit_path, 'staging_area')) + activated_path = os.path.join(wit_path, 'activated.txt') + Path(activated_path).write_text('master') + + +def add(path_to_add: str) -> None: + file_to_add = Path(os.path.abspath(path_to_add)) + repository = get_directory_with_wit(file_to_add) + if not repository: + raise WitError("<.wit> file not found") + destination = repository.joinpath('.wit', 'staging_area') + directories_to_copy = file_to_add.relative_to(repository).parts[:-1] + for dir_name in directories_to_copy: + dirs = os.listdir(destination) + destination = destination.joinpath(dir_name) + if dir_name not in dirs: + destination.mkdir() + save_the_copy(destination, file_to_add) + + +def save_the_copy(destination: Path, file: Path) -> None: + if file.is_file(): + shutil.copy2(file, destination) + else: + destination_of_folder_if_doesnt_exists = destination.joinpath(file.name) + if destination_of_folder_if_doesnt_exists.exists(): + shutil.rmtree(destination_of_folder_if_doesnt_exists) + shutil.copytree(file, destination_of_folder_if_doesnt_exists) + + +def get_directory_with_wit(file: Path) -> Optional[Path]: + for parent in file.parents: + dir_lst = os.listdir(parent) + if '.wit' in dir_lst: + return parent + return None + + +def commit(message: str) -> None: + dir_with_wit = get_directory_with_wit(Path.cwd()) + if not dir_with_wit: + raise WitError("<.wit> file not found") + images_path = dir_with_wit.joinpath('.wit', 'images') + path_of_new_folder = create_commit_folder(images_path) + create_commit_txt_file(dir_with_wit, images_path, path_of_new_folder, message) + save_files(dir_with_wit, path_of_new_folder) + commit_id = os.path.basename(path_of_new_folder) + + write_references(commit_id, dir_with_wit) + + +def create_commit_folder(images_path: Path) -> str: + folder_name = create_commit_name() + path_of_new_folder = os.path.join(images_path, folder_name) + os.mkdir(path_of_new_folder) + return path_of_new_folder + + +def create_commit_name(): + length = 20 + chars = '1234567890abcdef' + folder_name = ''.join(random.choices(chars, k=length)) + return folder_name + + +def create_commit_txt_file(dir_with_wit: Path, images_path: Path, path_of_new_folder: str, message: str) -> None: + parent_head = get_parent_head(dir_with_wit) + txt_file = images_path.joinpath(Path(path_of_new_folder).name + '.txt') + txt_file.write_text( + f'parent = {parent_head if parent_head else None}\n' + f'date = {datetime.datetime.now().strftime("%c")}\n' + f'message = {message}' + ) + + +def get_parent_head(dir_with_wit: Path) -> str: + wit_folder = dir_with_wit.joinpath('.wit') + references_file = wit_folder.joinpath('references.txt') + if references_file.exists(): + ref_path = wit_folder.joinpath('references.txt') + with ref_path.open() as f_h: + references_content = f_h.readlines() + head_line = references_content[0].split('=') + return head_line[1].strip() + return '' + + +def save_files(dir_with_wit: Path, path_of_new_folder: str) -> None: + staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') + for item in os.listdir(staging_area_path): + src = os.path.join(staging_area_path, item) + dst = os.path.join(path_of_new_folder, item) + if os.path.isfile(src): + shutil.copy2(src, dst) + else: + shutil.copytree(src, dst) + + +# בעת הרצת פקודת commit, יתעדכן (כרגיל) ה־HEAD כך שיצביע ל־commit החדש שנוצר. +# לפני עדכון ה־HEAD, בדקו אם ה־branch שנמצא במצב “פעיל” מצביע לאותו מקום שבו נמצא ה־HEAD. +# אם כן, עדכנו את references.txt כך שה־branch יצביע למספר ה־commit החדש שנוצר. + +def write_references(commit_id: str, dir_with_wit: Path) -> None: + wit_folder = dir_with_wit.joinpath('.wit') + ref_file = wit_folder.joinpath('references.txt') + # new_branch_id = commit_id # new_master = commit_id + activated_path = wit_folder.joinpath('activated.txt') + activated_branch = activated_path.read_text() + new_content = '='.join((activated_branch, commit_id)) + if ref_file.exists(): + content = ref_file.read_text().split() + head_line = content[0] + head_id = head_line.split('=')[1] + branch_data = content[1:] + new_content = head_line + for line in branch_data: + name_and_id = line.split('=') + branch_name = name_and_id[0] + branch_id = name_and_id[1] + if branch_name == activated_branch: + if branch_id == head_id: + line = '='.join((branch_name, commit_id)) + new_content += line + ref_file.write_text(f'HEAD={commit_id}\n{new_content}') + + +def status() -> None: + repository = get_directory_with_wit(Path.cwd()) + if not repository: + raise WitError("<.wit> file not found") + commit_id = get_parent_head(repository) + files_added_since_last_commit = get_files_added_since_last_commit(commit_id, repository) + files_changed_since_last_commit = get_files_changed_since_last_commit(commit_id, repository) + files_in_staging_area_that_dont_match_original = get_files_in_staging_area_that_dont_match_original(repository) + files_not_in_staging_area = get_files_not_in_staging_area(repository) + print( + f"Commit id: {commit_id}\n" + f"Changes to be committed: {(list(files_added_since_last_commit) + list(files_changed_since_last_commit))}\n" + f"Changes not staged for commit: {list(files_in_staging_area_that_dont_match_original)}\n" + f"Untracked files: {list(files_not_in_staging_area)}" + ) + + +def get_files_added_since_last_commit(commit_id: str, repository: Path) -> Generator[Any, Any, None]: + commit_path = os.path.join(repository, '.wit', 'images', commit_id) + staging_area_path = os.path.join(repository, '.wit', 'staging_area') + all_files_in_stagind_area_and_sub = get_files_of_dir_and_subdirs(staging_area_path) + all_files_in_commit_and_sub_dirs = get_files_of_dir_and_subdirs(commit_path) + for file in all_files_in_stagind_area_and_sub: + if file not in all_files_in_commit_and_sub_dirs: + yield file + + +def get_files_changed_since_last_commit(commit_id: str, repository: Path) -> Generator[str, Any, None]: + commit_path = os.path.join(repository, '.wit', 'images', commit_id) + staging_area_path = os.path.join(repository, '.wit', 'staging_area') + all_files_in_commit_and_sub = get_all_files_in_dir_and_subs(commit_path) + all_files_in_staging_area_and_sub = get_all_files_in_dir_and_subs(staging_area_path) + yield from get_names_of_changed_files( + all_files_in_commit_and_sub, all_files_in_staging_area_and_sub, commit_path, staging_area_path + ) + + +def get_names_of_changed_files( + all_files_in_commit_and_sub: Generator[Union[bytes, str], Any, None], + all_files_in_staging_area_and_sub: Generator[Union[bytes, str], Any, None], + commit_path: Union[str, Path], + staging_area_path: Union[str, Path] +) -> Generator[str, Any, None]: + for s_file in all_files_in_staging_area_and_sub: + for c_file in all_files_in_commit_and_sub: + if Path(s_file).relative_to(staging_area_path) == Path(c_file).relative_to(commit_path): + if not filecmp.cmp(s_file, c_file): + yield Path(s_file).name + + +def get_all_files_in_dir_and_subs(commit_path: str) -> Generator[Union[bytes, str], Any, None]: + for (root, dirs, files) in os.walk(commit_path, topdown=True): + for file in files: + yield os.path.join(root, file) + + +def get_files_in_staging_area_that_dont_match_original(repository: Path) -> Generator[str, Any, None]: + staging_area_path = os.path.join(repository, '.wit', 'staging_area') + all_files_in_repository_and_sub_dirs = get_all_files_and_dirs_in_repository(repository) + all_files_in_staging_area_and_sub = get_all_files_in_dir_and_subs(staging_area_path) + yield from get_names_of_changed_files( + all_files_in_staging_area_and_sub, all_files_in_repository_and_sub_dirs, staging_area_path, repository + ) + + +def get_all_files_and_dirs_in_repository(repository: Path) -> Generator[Union[bytes, str], Any, None]: + for (root, dirs, files) in os.walk(repository, topdown=True): + if '.wit' not in Path(root).parts: + for file in files: + yield os.path.join(root, file) + + +def get_files_not_in_staging_area(repository: Path) -> Generator[Any, Any, None]: + staging_area_path = os.path.join(repository, '.wit', 'staging_area') + files_names_in_repository_and_sub_dirs = get_files_names_of_repository_and_subs(repository) + all_files_in_staging_area_and_sub_dirs = get_files_of_dir_and_subdirs(staging_area_path) + for file in files_names_in_repository_and_sub_dirs: + if file not in all_files_in_staging_area_and_sub_dirs: + yield file + + +def get_files_names_of_repository_and_subs(repository: Path): + for (root, dirs, files) in os.walk(repository, topdown=True): + if '.wit' not in Path(root).parts: + for file in files: + yield file + + +def get_files_of_dir_and_subdirs(file_path: str) -> Generator[Any, Any, None]: + for (root, dirs, files) in os.walk(file_path, topdown=True): + for file in files: + yield file + + +def checkout(commit_id_or_branch: str) -> None: + repository = get_directory_with_wit(Path.cwd()) + if not repository: + raise WitError("<.wit> file not found") + references_file = repository.joinpath('.wit', 'references.txt') + last_commit_id = get_parent_head(repository) + if ( + list(get_files_added_since_last_commit(last_commit_id, repository)) + or list(get_files_changed_since_last_commit(last_commit_id, repository)) + or list(get_files_in_staging_area_that_dont_match_original(repository)) + ): + raise FilesDoesntMatchError("There are files added or changed after last commit") + commit_id = get_commit_id_of_branch(commit_id_or_branch, references_file) + print(commit_id) + change_files_in_main_folder(repository, commit_id) + change_head_in_references_file(commit_id, references_file) + change_staging_area_folder(repository, commit_id) + write_activated(commit_id, commit_id_or_branch, repository) # + + +def write_activated(commit_id: str, commit_id_or_branch: str, repository: Path) -> None: + activated_path = repository.joinpath('.wit', 'activated.txt') + Path(activated_path).write_text(commit_id_or_branch) + + +def get_commit_id_of_branch(commit_id_or_branch: str, references_file: Path) -> str: + with references_file.open() as file: + references_content = file.readlines() + branches_data = references_content[1:] + for branch_line in branches_data: + name_and_id = branch_line.split('=') + branch_name = name_and_id[0] + branch_id = name_and_id[1] + if branch_name == commit_id_or_branch: + return branch_id + return commit_id_or_branch + + +def change_head_in_references_file(commit_id: str, references_file: Path) -> None: + with references_file.open() as file: + branches = file.readlines()[1:] + branches_txt = ''.join(branches) + references_file.write_text(f'HEAD={commit_id}\n{branches_txt}') + + +def get_master_commit_id(references_file: Path) -> str: + with references_file.open() as file: + references_content = file.readlines() + master_line = references_content[1].split('=') + commit_id = master_line[-1].strip() + return commit_id + + +def change_files_in_main_folder(repository: Path, commit_id: str) -> None: + commit_path = os.path.join(repository, '.wit', 'images', commit_id) + # all_files_in_repository_and_sub_dirs = get_all_files_and_dirs_in_repository(repository) + all_files_in_repository_and_sub_dirs = [] + for (root, dirs, files) in os.walk(repository, topdown=True): + if '.wit' not in Path(root).parts: + for file in files: + all_files_in_repository_and_sub_dirs.append(os.path.join(root, file)) + # all_files_in_commit_and_sub_dirs = get_files_of_dir_and_subdirs(commit_path) # didn't work with the functions + all_files_in_commit_and_sub_dirs = [] + for (root, dirs, files) in os.walk(commit_path, topdown=True): + for file in files: + all_files_in_commit_and_sub_dirs.append(os.path.join(root, file)) + for c_file in all_files_in_commit_and_sub_dirs: + for r_file in all_files_in_repository_and_sub_dirs: + if Path(r_file).relative_to(repository) == Path(c_file).relative_to(commit_path): + shutil.copy2(c_file, r_file) + + +def change_staging_area_folder(dir_with_wit: Path, commit_id: str): + staging_area_path = dir_with_wit.joinpath('.wit', 'staging_area') + commit_path = dir_with_wit.joinpath('.wit', 'images', commit_id) + for file_or_dir in staging_area_path.iterdir(): + if file_or_dir.is_file(): + file_or_dir.unlink() + else: + shutil.rmtree(file_or_dir) + for file in commit_path.iterdir(): + rel_path = Path(file).relative_to(commit_path) + if file.is_file(): + shutil.copy2(file, staging_area_path.joinpath(rel_path)) + else: + shutil.copytree(file, staging_area_path.joinpath(rel_path)) + + +def branch(name: str) -> None: + repository = get_directory_with_wit(Path.cwd()) + if not repository: + raise WitError("<.wit> file not found") + references_file = repository.joinpath('.wit', 'references.txt') + commit_id = get_parent_head(repository) + with references_file.open('a') as ref_file: + ref_file.write(f'\n{name}={commit_id}') + + +class WitError(Exception): + pass + + +class FilesDoesntMatchError(Exception): + pass + + +def is_command_correct(argv: list[str]) -> bool: + if argv[1] in ['init', 'status']: + return len(argv) == 2 + else: + return len(argv) == 3 + + +if sys.argv[1] == 'init': + if is_command_correct(sys.argv): + init() + else: + print(fr"Usage: python {sys.argv[0]} init") + +elif sys.argv[1] == 'add': + if is_command_correct(sys.argv): + add(sys.argv[2]) + else: + print(fr"Usage: python {sys.argv[0]} add ") + +elif sys.argv[1] == 'commit': + if is_command_correct(sys.argv): + commit(sys.argv[2]) + else: + print(fr"Usage: python {sys.argv[0]} commit MESSAGE") + +elif sys.argv[1] == 'status': + if is_command_correct(sys.argv): + status() + else: + print(fr"Usage: python {sys.argv[0]} status") + +elif sys.argv[1] == 'checkout': + if is_command_correct(sys.argv): + checkout(sys.argv[2]) + else: + print(fr"Usage: python {sys.argv[0]} checkout ") + +elif sys.argv[1] == 'branch': + if is_command_correct(sys.argv): + branch(sys.argv[2]) + else: + print(fr"Usage: python {sys.argv[0]} branch ") diff --git a/wit_checks.py b/wit_checks.py new file mode 100644 index 0000000..25bc449 --- /dev/null +++ b/wit_checks.py @@ -0,0 +1,315 @@ +# upload 172 +import datetime +import filecmp +import os +from pathlib import Path +import random +import shutil +import sys +from typing import Union + + +def init() -> None: + cwd = os.getcwd() + wit_path = os.path.join(cwd, '.wit') + os.mkdir(wit_path) + os.mkdir(os.path.join(wit_path, 'images')) + os.mkdir(os.path.join(wit_path, 'staging_area')) + + +def add(path_to_add: str) -> None: + file = Path(os.path.abspath(path_to_add)) + directory_with_wit = get_directory_with_wit(file) + if not directory_with_wit: + raise WitError("<.wit> file not found") + destination = directory_with_wit.joinpath('.wit', 'staging_area') + directories_to_copy = file.relative_to(directory_with_wit).parts[:-1] + for dir_name in directories_to_copy: + dirs = os.listdir(destination) + destination = destination.joinpath(dir_name) + if dir_name not in dirs: + destination.mkdir() + save_the_copy(destination, file) + + +def save_the_copy(destination: Path, file: Path) -> None: + if file.is_file(): + shutil.copy2(file, destination) + else: + destination_of_folder_if_doesnt_exists = destination.joinpath(file.name) + if destination_of_folder_if_doesnt_exists.exists(): + shutil.rmtree(destination_of_folder_if_doesnt_exists) + shutil.copytree(file, destination_of_folder_if_doesnt_exists) + + +def get_directory_with_wit(file: Path) -> Union[Path, bool]: + for parent in file.parents: + dir_lst = os.listdir(parent) + if '.wit' in dir_lst: # and os.path.isdir(os.path.abspath('.wit')): > never True. also with iterdir. why? + return parent + return False + + +def commit(message: str) -> None: + dir_with_wit = get_directory_with_wit(Path.cwd()) + if not dir_with_wit: + raise WitError("<.wit> file not found") + images_path = dir_with_wit.joinpath('.wit', 'images') + path_of_new_folder = create_commit_folder(images_path) + create_commit_txt_file(dir_with_wit, images_path, path_of_new_folder, message) + save_files(dir_with_wit, path_of_new_folder) + commit_id = os.path.basename(path_of_new_folder) + write_references(commit_id, dir_with_wit) + + +def create_commit_folder(images_path: Path) -> str: + length = 20 + chars = '1234567890abcdef' + folder_name = ''.join(random.choice(chars) for _ in range(length)) + path_of_new_folder = os.path.join(images_path, folder_name) + os.mkdir(path_of_new_folder) + return path_of_new_folder + + +def create_commit_txt_file(dir_with_wit: Path, images_path: Path, path_of_new_folder: str, message: str) -> None: + parent_head = get_parent_head(dir_with_wit) + txt_file = images_path.joinpath(Path(path_of_new_folder).name + '.txt') + txt_file.write_text( + f'parent = {parent_head if parent_head else None}\n' + f'date = {datetime.datetime.now().strftime("%c")}\n' + f'message = {message}' + ) + + +def get_parent_head(dir_with_wit: Path) -> str: + wit_folder = dir_with_wit.joinpath('.wit') # repository + r'\.wit' + if 'references.txt' in os.listdir(wit_folder): + ref_path = wit_folder.joinpath('references.txt') + with ref_path.open() as f_h: + references_file = f_h.readlines() + return references_file[0][5:].strip() + return '' + + +def save_files(dir_with_wit: Path, path_of_new_folder: str) -> None: + staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') + for item in os.listdir(staging_area_path): + src = os.path.join(staging_area_path, item) + dst = os.path.join(path_of_new_folder, item) + if os.path.isfile(src): + shutil.copy2(src, dst) + else: + shutil.copytree(src, dst) # todo ?? + + +def write_references(commit_id: str, dir_with_wit: Path) -> None: + wit_folder = dir_with_wit.joinpath('.wit') + ref_file = wit_folder.joinpath('references.txt') + old_commit_id = get_parent_head(dir_with_wit) + print(old_commit_id) + master_id = get_master_commit_id(ref_file) + if old_commit_id == master_id: + ref_file.write_text(f'HEAD={commit_id}\nMASTER={commit_id}\n') + else: + ref_file.write_text(f'HEAD={commit_id}\nMASTER={master_id}\n') + + +########### + + +def status(): + dir_with_wit = get_directory_with_wit(Path.cwd()) + if not dir_with_wit: + raise WitError("<.wit> file not found") + commit_id = get_parent_head(dir_with_wit) + files_added_or_changed_since_last_commit = get_files_added_or_changed_since_last_commit(commit_id, dir_with_wit) + files_in_staging_area_that_dont_match_original = get_files_in_staging_area_that_dont_match_original(dir_with_wit) + files_not_in_staging_area = get_files_not_in_staging_area(dir_with_wit) + print( + f"Commit id: {commit_id}\n" + f"Changes to be committed: {[file for file in files_added_or_changed_since_last_commit if file]}\n" + f"Changes not staged for commit: {[file for file in files_in_staging_area_that_dont_match_original if file]}\n" + f"Untracked files: {[file for file in files_not_in_staging_area]}" + ) + + +def get_files_added_or_changed_since_last_commit(commit_id: str, dir_with_wit: Path) -> list[str]: + commit_path = os.path.join(dir_with_wit, '.wit', 'images', commit_id) + staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') + dir_cmp = filecmp.dircmp(a=commit_path, b=staging_area_path) + yield dir_cmp.right_only + yield dir_cmp.diff_files + # while dir_cmp.subdirs: + for sub in dir_cmp.subdirs.values(): + dir_cmp = sub + yield dir_cmp.right_only + yield dir_cmp.diff_files + # return dir_cmp.right_only + dir_cmp.diff_files + + +def get_files_in_staging_area_that_dont_match_original(dir_with_wit: Path) -> list[str]: + staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') + dir_cmp = filecmp.dircmp(a=dir_with_wit, b=staging_area_path) + yield dir_cmp.diff_files + # while dir_cmp.subdirs: + for sub in dir_cmp.subdirs.values(): + yield sub.diff_files + + +def get_files_not_in_staging_area(dir_with_wit: Path) -> list[str]: + staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') + dir_cmp = filecmp.dircmp(a=dir_with_wit, b=staging_area_path) + yield dir_cmp.left_only + for sub in dir_cmp.subdirs.values(): + yield sub.left_only + + +########## +# +# +# +# +# def status(): +# repository = get_directory_with_wit(Path.cwd()) +# if not repository: +# raise WitError("<.wit> file not found") +# commit_id = get_parent_head(repository) +# commit_path = os.path.join(repository, '.wit', 'images', commit_id) +# staging_area_path = os.path.join(repository, '.wit', 'staging_area') +# cmp = filecmp.dircmp(staging_area_path, commit_path) +# files_added_since_last_commit = [f for f in get_files_added_since_last_commit(cmp)] +# print(files_added_since_last_commit) +# +# +# +# # +# # files_in_staging_area_that_dont_match_original = get_files_in_staging_area_that_dont_match_original(repository) +# # files_not_in_staging_area = get_files_not_in_staging_area(repository) +# # print( +# # f"Commit id: {commit_id}\n" +# # f"Changes to be committed: {files_added_or_changed_since_last_commit}\n" +# # f"Changes not staged for commit: {[file for file in files_in_staging_area_that_dont_match_original if file]}\n" +# # f"Untracked files: {[file for file in files_not_in_staging_area]}" +# +# # ) +# +# +# def get_files_added_since_last_commit(cmp): +# # cmp = filecmp.dircmp(staging_area_path, commit_path) +# for name in cmp.left_only: +# yield name +# for sub_cmp in cmp.subdirs.values(): +# get_files_added_since_last_commit(sub_cmp) +# +# +# +# # for file_name in Path(staging_area_path).iterdir(): +# # if file_name.name not in [f.name for f in Path(commit_path).iterdir()]: +# # yield file_name.name +# # elif file_name.is_dir(): +# # path_in_staging_area = os.path.join(staging_area_path, file_name.name) +# # path_in_commit = os.path.join(commit_path, file_name.name) +# # get_files_changed_since_last_commit(path_in_commit, path_in_staging_area) +# # +# +# +# +# +# +# +# +# +# +# +# def get_files_changed_since_last_commit(staging_area_path: str, commit_path: str): +# pass +############ + + +def checkout(commit_id: str): + dir_with_wit = get_directory_with_wit(Path.cwd()) + if not dir_with_wit: + raise WitError("<.wit> file not found") + # if files_added_or_changed_since_last_commit or files_in_staging_area_that_dont_match_original: + # return False + references_file = dir_with_wit.joinpath('.wit', 'references.txt') + + if commit_id == 'master': + commit_id = get_master_commit_id(references_file) + change_files_in_main_folder(dir_with_wit, commit_id) + with references_file.open() as file: + master = file.readlines()[1] + references_file.write_text(f'HEAD={commit_id}\n{master}\n') + change_staging_area_folder(dir_with_wit, commit_id) + + +def get_master_commit_id(references_file): + with references_file.open() as file: + commit_id = file.readlines()[1][7:].strip() + return commit_id + + +def change_files_in_main_folder(dir_with_wit: Path, commit_id : str) -> None: + commit_path = os.path.join(dir_with_wit, '.wit', 'images', commit_id) + for item in os.listdir(commit_path): + src = os.path.join(commit_path, item) + dst = os.path.join(dir_with_wit, item) + if os.path.isfile(src): + shutil.copy2(src, dst) + elif os.path.exists(dst): + print("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") # todo how to replace if exists + else: + shutil.copytree(src, dst) + + +def change_staging_area_folder(dir_with_wit, commit_id): + staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') + commit_path = os.path.join(dir_with_wit, '.wit', 'images', commit_id) + shutil.rmtree(staging_area_path) + shutil.copytree(commit_path, staging_area_path) + + + + +class WitError(Exception): + pass + + +def is_init_status_command_correct(argv: list[str]) -> bool: + return len(argv) == 2 + + +def is_add_commit_checkout_command_correct(argv: list[str]) -> bool: + return len(argv) == 3 + + +if sys.argv[1] == 'init': + if is_init_status_command_correct(sys.argv): + init() + else: + print(fr"Usage: python {sys.argv[0]} init") + +elif sys.argv[1] == 'add': + if is_add_commit_checkout_command_correct(sys.argv): + add(sys.argv[2]) + else: + print(fr"Usage: python {sys.argv[0]} add ") + +elif sys.argv[1] == 'commit': + if is_add_commit_checkout_command_correct(sys.argv): + commit(sys.argv[2]) + else: + print(fr"Usage: python {sys.argv[0]} commit MESSAGE") + +elif sys.argv[1] == 'status': + if is_init_status_command_correct(sys.argv): + status() + else: + print(fr"Usage: python {sys.argv[0]} status") + +elif sys.argv[1] == 'checkout': + if is_add_commit_checkout_command_correct(sys.argv): + checkout(sys.argv[2]) + else: + print(fr"Usage: python {sys.argv[0]} checkout ") + From 0040983149a351094fbf0a94bbe68ab2dc2dfdba Mon Sep 17 00:00:00 2001 From: RuthMahallaMilano <97195051+RuthMahallaMilano@users.noreply.github.com> Date: Wed, 5 Jan 2022 23:56:10 +0200 Subject: [PATCH 02/73] Delete branch_req.txt delete txt --- branch_req.txt | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 branch_req.txt diff --git a/branch_req.txt b/branch_req.txt deleted file mode 100644 index 651b06b..0000000 --- a/branch_req.txt +++ /dev/null @@ -1,23 +0,0 @@ -V -בעת הרצת הפקודה python path/to/wit.py branch NAME, צרו שורה חדשה ב־references.txt. השורה תראה כך: NAME=COMMIT_ID, -כאשר במקום NAME יופיע שמו של ה־branch, ובמקום COMMIT_ID יופיע מספרו של ה־commit שבו נמצא ה־HEAD בעת הרצת הפקודה. - -V -בעת הרצת פקודת checkout, יעודכן בקובץ בשם activated.txt שנמצא ישירות תחת התיקייה .wit, שמו של ה־branch שנמצא במצב “פעיל” בעת ביצוע הפקודה. זה יהיה כל תוכנו של הקובץ, -ולכן אפשר להרגיש בנוח לדרוס אותו. - -בעת הרצת פקודת commit, יתעדכן (כרגיל) ה־HEAD כך שיצביע ל־commit החדש שנוצר. -לפני עדכון ה־HEAD, בדקו אם ה־branch שנמצא במצב “פעיל” מצביע לאותו מקום שבו נמצא ה־HEAD. -אם כן, עדכנו את references.txt כך שה־branch יצביע למספר ה־commit החדש שנוצר. - -שינויים שצריך לעשות: - -V -בניגוד למה שנכתב ביום 2, בעת פקודת commit, התווית master כבר לא תתקדם כל פעם שהיא וה־HEAD נמצאים באותו מקום. כדי שתתקדם, היא חייבת שהתנאי המדובר יתקיים וגם שהענף יהיה “מופעל”. -הענף master “מופעל” והתווית תתקדם רק אם ה־checkout האחרון שהתבצע היה python wit.py checkout master. - -V -בעת הרצת הפקודה init, יווצר קובץ חדש בשם activated.txt שבו ירשם master. - -V -פקודת ה־checkout כעת צריכה להיות מסוגלת לקבל אחת משתי האפשרויות: או commit id, או שם של branch. From 4633d2bb748d020d1dae74540c92b000aae2b45d Mon Sep 17 00:00:00 2001 From: RuthMahallaMilano <97195051+RuthMahallaMilano@users.noreply.github.com> Date: Wed, 5 Jan 2022 23:57:19 +0200 Subject: [PATCH 03/73] Delete wit_checks.py delete --- wit_checks.py | 315 -------------------------------------------------- 1 file changed, 315 deletions(-) delete mode 100644 wit_checks.py diff --git a/wit_checks.py b/wit_checks.py deleted file mode 100644 index 25bc449..0000000 --- a/wit_checks.py +++ /dev/null @@ -1,315 +0,0 @@ -# upload 172 -import datetime -import filecmp -import os -from pathlib import Path -import random -import shutil -import sys -from typing import Union - - -def init() -> None: - cwd = os.getcwd() - wit_path = os.path.join(cwd, '.wit') - os.mkdir(wit_path) - os.mkdir(os.path.join(wit_path, 'images')) - os.mkdir(os.path.join(wit_path, 'staging_area')) - - -def add(path_to_add: str) -> None: - file = Path(os.path.abspath(path_to_add)) - directory_with_wit = get_directory_with_wit(file) - if not directory_with_wit: - raise WitError("<.wit> file not found") - destination = directory_with_wit.joinpath('.wit', 'staging_area') - directories_to_copy = file.relative_to(directory_with_wit).parts[:-1] - for dir_name in directories_to_copy: - dirs = os.listdir(destination) - destination = destination.joinpath(dir_name) - if dir_name not in dirs: - destination.mkdir() - save_the_copy(destination, file) - - -def save_the_copy(destination: Path, file: Path) -> None: - if file.is_file(): - shutil.copy2(file, destination) - else: - destination_of_folder_if_doesnt_exists = destination.joinpath(file.name) - if destination_of_folder_if_doesnt_exists.exists(): - shutil.rmtree(destination_of_folder_if_doesnt_exists) - shutil.copytree(file, destination_of_folder_if_doesnt_exists) - - -def get_directory_with_wit(file: Path) -> Union[Path, bool]: - for parent in file.parents: - dir_lst = os.listdir(parent) - if '.wit' in dir_lst: # and os.path.isdir(os.path.abspath('.wit')): > never True. also with iterdir. why? - return parent - return False - - -def commit(message: str) -> None: - dir_with_wit = get_directory_with_wit(Path.cwd()) - if not dir_with_wit: - raise WitError("<.wit> file not found") - images_path = dir_with_wit.joinpath('.wit', 'images') - path_of_new_folder = create_commit_folder(images_path) - create_commit_txt_file(dir_with_wit, images_path, path_of_new_folder, message) - save_files(dir_with_wit, path_of_new_folder) - commit_id = os.path.basename(path_of_new_folder) - write_references(commit_id, dir_with_wit) - - -def create_commit_folder(images_path: Path) -> str: - length = 20 - chars = '1234567890abcdef' - folder_name = ''.join(random.choice(chars) for _ in range(length)) - path_of_new_folder = os.path.join(images_path, folder_name) - os.mkdir(path_of_new_folder) - return path_of_new_folder - - -def create_commit_txt_file(dir_with_wit: Path, images_path: Path, path_of_new_folder: str, message: str) -> None: - parent_head = get_parent_head(dir_with_wit) - txt_file = images_path.joinpath(Path(path_of_new_folder).name + '.txt') - txt_file.write_text( - f'parent = {parent_head if parent_head else None}\n' - f'date = {datetime.datetime.now().strftime("%c")}\n' - f'message = {message}' - ) - - -def get_parent_head(dir_with_wit: Path) -> str: - wit_folder = dir_with_wit.joinpath('.wit') # repository + r'\.wit' - if 'references.txt' in os.listdir(wit_folder): - ref_path = wit_folder.joinpath('references.txt') - with ref_path.open() as f_h: - references_file = f_h.readlines() - return references_file[0][5:].strip() - return '' - - -def save_files(dir_with_wit: Path, path_of_new_folder: str) -> None: - staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') - for item in os.listdir(staging_area_path): - src = os.path.join(staging_area_path, item) - dst = os.path.join(path_of_new_folder, item) - if os.path.isfile(src): - shutil.copy2(src, dst) - else: - shutil.copytree(src, dst) # todo ?? - - -def write_references(commit_id: str, dir_with_wit: Path) -> None: - wit_folder = dir_with_wit.joinpath('.wit') - ref_file = wit_folder.joinpath('references.txt') - old_commit_id = get_parent_head(dir_with_wit) - print(old_commit_id) - master_id = get_master_commit_id(ref_file) - if old_commit_id == master_id: - ref_file.write_text(f'HEAD={commit_id}\nMASTER={commit_id}\n') - else: - ref_file.write_text(f'HEAD={commit_id}\nMASTER={master_id}\n') - - -########### - - -def status(): - dir_with_wit = get_directory_with_wit(Path.cwd()) - if not dir_with_wit: - raise WitError("<.wit> file not found") - commit_id = get_parent_head(dir_with_wit) - files_added_or_changed_since_last_commit = get_files_added_or_changed_since_last_commit(commit_id, dir_with_wit) - files_in_staging_area_that_dont_match_original = get_files_in_staging_area_that_dont_match_original(dir_with_wit) - files_not_in_staging_area = get_files_not_in_staging_area(dir_with_wit) - print( - f"Commit id: {commit_id}\n" - f"Changes to be committed: {[file for file in files_added_or_changed_since_last_commit if file]}\n" - f"Changes not staged for commit: {[file for file in files_in_staging_area_that_dont_match_original if file]}\n" - f"Untracked files: {[file for file in files_not_in_staging_area]}" - ) - - -def get_files_added_or_changed_since_last_commit(commit_id: str, dir_with_wit: Path) -> list[str]: - commit_path = os.path.join(dir_with_wit, '.wit', 'images', commit_id) - staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') - dir_cmp = filecmp.dircmp(a=commit_path, b=staging_area_path) - yield dir_cmp.right_only - yield dir_cmp.diff_files - # while dir_cmp.subdirs: - for sub in dir_cmp.subdirs.values(): - dir_cmp = sub - yield dir_cmp.right_only - yield dir_cmp.diff_files - # return dir_cmp.right_only + dir_cmp.diff_files - - -def get_files_in_staging_area_that_dont_match_original(dir_with_wit: Path) -> list[str]: - staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') - dir_cmp = filecmp.dircmp(a=dir_with_wit, b=staging_area_path) - yield dir_cmp.diff_files - # while dir_cmp.subdirs: - for sub in dir_cmp.subdirs.values(): - yield sub.diff_files - - -def get_files_not_in_staging_area(dir_with_wit: Path) -> list[str]: - staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') - dir_cmp = filecmp.dircmp(a=dir_with_wit, b=staging_area_path) - yield dir_cmp.left_only - for sub in dir_cmp.subdirs.values(): - yield sub.left_only - - -########## -# -# -# -# -# def status(): -# repository = get_directory_with_wit(Path.cwd()) -# if not repository: -# raise WitError("<.wit> file not found") -# commit_id = get_parent_head(repository) -# commit_path = os.path.join(repository, '.wit', 'images', commit_id) -# staging_area_path = os.path.join(repository, '.wit', 'staging_area') -# cmp = filecmp.dircmp(staging_area_path, commit_path) -# files_added_since_last_commit = [f for f in get_files_added_since_last_commit(cmp)] -# print(files_added_since_last_commit) -# -# -# -# # -# # files_in_staging_area_that_dont_match_original = get_files_in_staging_area_that_dont_match_original(repository) -# # files_not_in_staging_area = get_files_not_in_staging_area(repository) -# # print( -# # f"Commit id: {commit_id}\n" -# # f"Changes to be committed: {files_added_or_changed_since_last_commit}\n" -# # f"Changes not staged for commit: {[file for file in files_in_staging_area_that_dont_match_original if file]}\n" -# # f"Untracked files: {[file for file in files_not_in_staging_area]}" -# -# # ) -# -# -# def get_files_added_since_last_commit(cmp): -# # cmp = filecmp.dircmp(staging_area_path, commit_path) -# for name in cmp.left_only: -# yield name -# for sub_cmp in cmp.subdirs.values(): -# get_files_added_since_last_commit(sub_cmp) -# -# -# -# # for file_name in Path(staging_area_path).iterdir(): -# # if file_name.name not in [f.name for f in Path(commit_path).iterdir()]: -# # yield file_name.name -# # elif file_name.is_dir(): -# # path_in_staging_area = os.path.join(staging_area_path, file_name.name) -# # path_in_commit = os.path.join(commit_path, file_name.name) -# # get_files_changed_since_last_commit(path_in_commit, path_in_staging_area) -# # -# -# -# -# -# -# -# -# -# -# -# def get_files_changed_since_last_commit(staging_area_path: str, commit_path: str): -# pass -############ - - -def checkout(commit_id: str): - dir_with_wit = get_directory_with_wit(Path.cwd()) - if not dir_with_wit: - raise WitError("<.wit> file not found") - # if files_added_or_changed_since_last_commit or files_in_staging_area_that_dont_match_original: - # return False - references_file = dir_with_wit.joinpath('.wit', 'references.txt') - - if commit_id == 'master': - commit_id = get_master_commit_id(references_file) - change_files_in_main_folder(dir_with_wit, commit_id) - with references_file.open() as file: - master = file.readlines()[1] - references_file.write_text(f'HEAD={commit_id}\n{master}\n') - change_staging_area_folder(dir_with_wit, commit_id) - - -def get_master_commit_id(references_file): - with references_file.open() as file: - commit_id = file.readlines()[1][7:].strip() - return commit_id - - -def change_files_in_main_folder(dir_with_wit: Path, commit_id : str) -> None: - commit_path = os.path.join(dir_with_wit, '.wit', 'images', commit_id) - for item in os.listdir(commit_path): - src = os.path.join(commit_path, item) - dst = os.path.join(dir_with_wit, item) - if os.path.isfile(src): - shutil.copy2(src, dst) - elif os.path.exists(dst): - print("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") # todo how to replace if exists - else: - shutil.copytree(src, dst) - - -def change_staging_area_folder(dir_with_wit, commit_id): - staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') - commit_path = os.path.join(dir_with_wit, '.wit', 'images', commit_id) - shutil.rmtree(staging_area_path) - shutil.copytree(commit_path, staging_area_path) - - - - -class WitError(Exception): - pass - - -def is_init_status_command_correct(argv: list[str]) -> bool: - return len(argv) == 2 - - -def is_add_commit_checkout_command_correct(argv: list[str]) -> bool: - return len(argv) == 3 - - -if sys.argv[1] == 'init': - if is_init_status_command_correct(sys.argv): - init() - else: - print(fr"Usage: python {sys.argv[0]} init") - -elif sys.argv[1] == 'add': - if is_add_commit_checkout_command_correct(sys.argv): - add(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} add ") - -elif sys.argv[1] == 'commit': - if is_add_commit_checkout_command_correct(sys.argv): - commit(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} commit MESSAGE") - -elif sys.argv[1] == 'status': - if is_init_status_command_correct(sys.argv): - status() - else: - print(fr"Usage: python {sys.argv[0]} status") - -elif sys.argv[1] == 'checkout': - if is_add_commit_checkout_command_correct(sys.argv): - checkout(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} checkout ") - From ff92db7e52c04013a32f7423dba1edf7366778df Mon Sep 17 00:00:00 2001 From: RuthMahallaMilano <97195051+RuthMahallaMilano@users.noreply.github.com> Date: Wed, 5 Jan 2022 23:58:17 +0200 Subject: [PATCH 04/73] Delete .gitignore --- .gitignore | 130 ----------------------------------------------------- 1 file changed, 130 deletions(-) delete mode 100644 .gitignore diff --git a/.gitignore b/.gitignore deleted file mode 100644 index dce79fc..0000000 --- a/.gitignore +++ /dev/null @@ -1,130 +0,0 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -pip-wheel-metadata/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.py,cover -.hypothesis/ -.pytest_cache/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 -db.sqlite3-journal - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -.python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - -# Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ -.wit From 56528cce6de160e85e043808410eb9f7e50d0a20 Mon Sep 17 00:00:00 2001 From: RuthMahallaMilano <97195051+RuthMahallaMilano@users.noreply.github.com> Date: Wed, 5 Jan 2022 23:58:24 +0200 Subject: [PATCH 05/73] Delete .name --- .idea/.name | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .idea/.name diff --git a/.idea/.name b/.idea/.name deleted file mode 100644 index 3e4e48b..0000000 --- a/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -.gitignore \ No newline at end of file From dc5a3f750d3da015641cca28ff3e795fa2ce98c2 Mon Sep 17 00:00:00 2001 From: RuthMahallaMilano <97195051+RuthMahallaMilano@users.noreply.github.com> Date: Thu, 6 Jan 2022 00:00:27 +0200 Subject: [PATCH 06/73] Delete .gitignore --- .idea/.gitignore | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 .idea/.gitignore diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 26d3352..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml From 9fd59ccaedd0a790782d19bff97d1f62c421d6a8 Mon Sep 17 00:00:00 2001 From: RuthMahallaMilano <97195051+RuthMahallaMilano@users.noreply.github.com> Date: Thu, 6 Jan 2022 00:00:54 +0200 Subject: [PATCH 07/73] Delete profiles_settings.xml --- .idea/inspectionProfiles/profiles_settings.xml | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 .idea/inspectionProfiles/profiles_settings.xml diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 105ce2d..0000000 --- a/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file From eb37fe1bab12e4bdc7f71a45c315a90cc3f6ce95 Mon Sep 17 00:00:00 2001 From: RuthMahallaMilano <97195051+RuthMahallaMilano@users.noreply.github.com> Date: Thu, 6 Jan 2022 00:01:23 +0200 Subject: [PATCH 08/73] Delete misc.xml --- .idea/misc.xml | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 .idea/misc.xml diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index d56657a..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file From 4bad3824d0eee461c5c4570115f50e864900405d Mon Sep 17 00:00:00 2001 From: RuthMahallaMilano <97195051+RuthMahallaMilano@users.noreply.github.com> Date: Thu, 6 Jan 2022 00:01:37 +0200 Subject: [PATCH 09/73] Delete add_171.py --- add_171.py | 74 ------------------------------------------------------ 1 file changed, 74 deletions(-) delete mode 100644 add_171.py diff --git a/add_171.py b/add_171.py deleted file mode 100644 index a75d30b..0000000 --- a/add_171.py +++ /dev/null @@ -1,74 +0,0 @@ -# upload 171 - -import os -from pathlib import Path -import shutil -import sys -from typing import Union - - -def init() -> None: - cwd = os.getcwd() - wit_path = os.path.join(cwd, '.wit') - os.mkdir(wit_path) - os.mkdir(os.path.join(wit_path, 'images')) - os.mkdir(os.path.join(wit_path, 'staging_area')) - - -def add(path_to_add: str) -> None: - file = Path(os.path.abspath(path_to_add)) - directory_with_wit = get_directory_with_wit(file) - if not directory_with_wit: - raise WitError("<.wit> file not found") - destination = directory_with_wit.joinpath('.wit', 'staging_area') - directories_to_copy = file.relative_to(directory_with_wit).parts[:-1] - for dir_name in directories_to_copy: - dirs = os.listdir(destination) - destination = destination.joinpath(dir_name) - if dir_name not in dirs: - destination.mkdir() - save_the_copy(destination, file) - - -def save_the_copy(destination: Path, file: Path) -> None: - if file.is_file(): - shutil.copy2(file, destination) - else: - destination_of_folder_if_doesnt_exists = destination.joinpath(file.name) - if destination_of_folder_if_doesnt_exists.exists(): - shutil.rmtree(destination_of_folder_if_doesnt_exists) - shutil.copytree(file, destination_of_folder_if_doesnt_exists) - - -def get_directory_with_wit(file: Path) -> Union[Path, bool]: - for parent in file.parents: - dir_lst = os.listdir(parent) - if '.wit' in dir_lst: # and os.path.isdir(os.path.abspath('.wit')): > never True. also with iterdir. why? - return parent - return False - - -class WitError(Exception): - pass - - -def is_init_status_command_correct(argv: list[str]) -> bool: - return len(argv) == 2 - - -def is_add_or_commit_command_correct(argv: list[str]) -> bool: - return len(argv) == 3 - - -if sys.argv[1] == 'init': - if is_init_status_command_correct(sys.argv): - init() - else: - print(fr"Usage: python {sys.argv[0]} init") - - -elif sys.argv[1] == 'add': - if is_add_or_commit_command_correct(sys.argv): - add(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} add ") From f57cc0188ddddd7f42c2e764311bd3ecbe80e8d8 Mon Sep 17 00:00:00 2001 From: RuthMahallaMilano <97195051+RuthMahallaMilano@users.noreply.github.com> Date: Thu, 6 Jan 2022 00:01:51 +0200 Subject: [PATCH 10/73] Delete wit_project.iml --- .idea/wit_project.iml | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 .idea/wit_project.iml diff --git a/.idea/wit_project.iml b/.idea/wit_project.iml deleted file mode 100644 index 7b9db73..0000000 --- a/.idea/wit_project.iml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file From 039dace8542244e6bab7b825dde508285415f26a Mon Sep 17 00:00:00 2001 From: RuthMahallaMilano <97195051+RuthMahallaMilano@users.noreply.github.com> Date: Thu, 6 Jan 2022 00:02:02 +0200 Subject: [PATCH 11/73] Delete vcs.xml --- .idea/vcs.xml | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 .idea/vcs.xml diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 288b36b..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file From f1cdbe826e0b4248945809aefdd8cec616fa91e2 Mon Sep 17 00:00:00 2001 From: RuthMahallaMilano <97195051+RuthMahallaMilano@users.noreply.github.com> Date: Thu, 6 Jan 2022 00:02:16 +0200 Subject: [PATCH 12/73] Delete modules.xml --- .idea/modules.xml | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 .idea/modules.xml diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index f21131b..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file From c207687c4d78642dca576788ab715789130f330d Mon Sep 17 00:00:00 2001 From: RuthMahallaMilano <97195051+RuthMahallaMilano@users.noreply.github.com> Date: Thu, 6 Jan 2022 00:02:50 +0200 Subject: [PATCH 13/73] Delete commit.py --- commit.py | 140 ------------------------------------------------------ 1 file changed, 140 deletions(-) delete mode 100644 commit.py diff --git a/commit.py b/commit.py deleted file mode 100644 index c429d77..0000000 --- a/commit.py +++ /dev/null @@ -1,140 +0,0 @@ -# upload 172 -import datetime -import os -from pathlib import Path -import random -import shutil -import sys -from typing import Union - - -def init() -> None: - cwd = os.getcwd() - wit_path = os.path.join(cwd, '.wit') - os.mkdir(wit_path) - os.mkdir(os.path.join(wit_path, 'images')) - os.mkdir(os.path.join(wit_path, 'staging_area')) - - -def add(path_to_add: str) -> None: - file = Path(os.path.abspath(path_to_add)) - directory_with_wit = get_directory_with_wit(file) - if not directory_with_wit: - raise WitError("<.wit> file not found") - destination = directory_with_wit.joinpath('.wit', 'staging_area') - directories_to_copy = file.relative_to(directory_with_wit).parts[:-1] - for dir_name in directories_to_copy: - dirs = os.listdir(destination) - destination = destination.joinpath(dir_name) - if dir_name not in dirs: - destination.mkdir() - save_the_copy(destination, file) - - -def save_the_copy(destination: Path, file: Path) -> None: - if file.is_file(): - shutil.copy2(file, destination) - else: - destination_of_folder_if_doesnt_exists = destination.joinpath(file.name) - if destination_of_folder_if_doesnt_exists.exists(): - shutil.rmtree(destination_of_folder_if_doesnt_exists) - shutil.copytree(file, destination_of_folder_if_doesnt_exists) - - -def get_directory_with_wit(file: Path) -> Union[Path, bool]: - for parent in file.parents: - dir_lst = os.listdir(parent) - if '.wit' in dir_lst: # and os.path.isdir(os.path.abspath('.wit')): > never True. also with iterdir. why? - return parent - return False - - -def commit(message: str) -> None: - dir_with_wit = get_directory_with_wit(Path.cwd()) - if not dir_with_wit: - raise WitError("<.wit> file not found") - images_path = dir_with_wit.joinpath('.wit', 'images') - path_of_new_folder = create_commit_folder(images_path) - create_commit_txt_file(dir_with_wit, images_path, path_of_new_folder, message) - save_files(dir_with_wit, path_of_new_folder) - commit_id = os.path.basename(path_of_new_folder) - write_references(commit_id, dir_with_wit) - - -def create_commit_folder(images_path: Path) -> str: - length = 20 - chars = '1234567890abcdef' - folder_name = ''.join(random.choice(chars) for _ in range(length)) - path_of_new_folder = os.path.join(images_path, folder_name) - os.mkdir(path_of_new_folder) - return path_of_new_folder - - -def create_commit_txt_file(dir_with_wit: Path, images_path: Path, path_of_new_folder: str, message: str) -> None: - parent_head = get_parent_head(dir_with_wit) - txt_file = images_path.joinpath(Path(path_of_new_folder).name + '.txt') - txt_file.write_text( - f'parent = {parent_head if parent_head else None}\n' - f'date = {datetime.datetime.now().strftime("%c")}\n' - f'message = {message}' - ) - - -def get_parent_head(dir_with_wit: Path) -> str: - wit_folder = dir_with_wit.joinpath('.wit') # repository + r'\.wit' - if 'references.txt' in os.listdir(wit_folder): - ref_path = wit_folder.joinpath('references.txt') - with ref_path.open() as f_h: - references_file = f_h.readlines() - return references_file[0][5:].strip() - return '' - - -def save_files(dir_with_wit: Path, path_of_new_folder: str) -> None: - staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') - for item in os.listdir(staging_area_path): - src = os.path.join(staging_area_path, item) - dst = os.path.join(path_of_new_folder, item) - if os.path.isfile(src): - shutil.copy2(src, dst) - else: - shutil.copytree(src, dst) - - -def write_references(commit_id: str, dir_with_wit: Path) -> None: - wit_folder = dir_with_wit.joinpath('.wit') - ref_file = wit_folder.joinpath('references.txt') - ref_file.write_text(f'HEAD={commit_id}\nMASTER={commit_id}\n') - - -class WitError(Exception): - pass - - -def is_init_status_command_correct(argv: list[str]) -> bool: - return len(argv) == 2 - - -def is_add_or_commit_command_correct(argv: list[str]) -> bool: - return len(argv) == 3 - - -if sys.argv[1] == 'init': - if is_init_status_command_correct(sys.argv): - init() - else: - print(fr"Usage: python {sys.argv[0]} init") - - -elif sys.argv[1] == 'add': - if is_add_or_commit_command_correct(sys.argv): - add(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} add ") - - -elif sys.argv[1] == 'commit': - if is_add_or_commit_command_correct(sys.argv): - commit(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} commit MESSAGE") From 36d1e90f1055803cbec9ea90e32ef1966af0957f Mon Sep 17 00:00:00 2001 From: RuthMahallaMilano <97195051+RuthMahallaMilano@users.noreply.github.com> Date: Thu, 6 Jan 2022 00:03:30 +0200 Subject: [PATCH 14/73] Delete checkout.py --- checkout.py | 335 ---------------------------------------------------- 1 file changed, 335 deletions(-) delete mode 100644 checkout.py diff --git a/checkout.py b/checkout.py deleted file mode 100644 index 8cf3efe..0000000 --- a/checkout.py +++ /dev/null @@ -1,335 +0,0 @@ -# upload 174 -import datetime -import filecmp -import os -from pathlib import Path -import random -import shutil -import sys -from typing import Any, Generator, Optional, Union - - -def init() -> None: - cwd = os.getcwd() - wit_path = os.path.join(cwd, '.wit') - os.mkdir(wit_path) - os.mkdir(os.path.join(wit_path, 'images')) - os.mkdir(os.path.join(wit_path, 'staging_area')) - - -def add(path_to_add: str) -> None: - file_to_add = Path(os.path.abspath(path_to_add)) - repository = get_directory_with_wit(file_to_add) - if not repository: - raise WitError("<.wit> file not found") - destination = repository.joinpath('.wit', 'staging_area') - directories_to_copy = file_to_add.relative_to(repository).parts[:-1] - for dir_name in directories_to_copy: - dirs = os.listdir(destination) - destination = destination.joinpath(dir_name) - if dir_name not in dirs: - destination.mkdir() - save_the_copy(destination, file_to_add) - - -def save_the_copy(destination: Path, file: Path) -> None: - if file.is_file(): - shutil.copy2(file, destination) - else: - destination_of_folder_if_doesnt_exists = destination.joinpath(file.name) - if destination_of_folder_if_doesnt_exists.exists(): - shutil.rmtree(destination_of_folder_if_doesnt_exists) - shutil.copytree(file, destination_of_folder_if_doesnt_exists) - - -def get_directory_with_wit(file: Path) -> Optional[Path]: - for parent in file.parents: - dir_lst = os.listdir(parent) - if '.wit' in dir_lst: - return parent - return None - - -def commit(message: str) -> None: - dir_with_wit = get_directory_with_wit(Path.cwd()) - if not dir_with_wit: - raise WitError("<.wit> file not found") - images_path = dir_with_wit.joinpath('.wit', 'images') - path_of_new_folder = create_commit_folder(images_path) - create_commit_txt_file(dir_with_wit, images_path, path_of_new_folder, message) - save_files(dir_with_wit, path_of_new_folder) - commit_id = os.path.basename(path_of_new_folder) - write_references(commit_id, dir_with_wit) - - -def create_commit_folder(images_path: Path) -> str: - folder_name = create_commit_name() - path_of_new_folder = os.path.join(images_path, folder_name) - os.mkdir(path_of_new_folder) - return path_of_new_folder - - -def create_commit_name(): - length = 20 - chars = '1234567890abcdef' - folder_name = ''.join(random.choices(chars, k=length)) - return folder_name - - -def create_commit_txt_file(dir_with_wit: Path, images_path: Path, path_of_new_folder: str, message: str) -> None: - parent_head = get_parent_head(dir_with_wit) - txt_file = images_path.joinpath(Path(path_of_new_folder).name + '.txt') - txt_file.write_text( - f'parent = {parent_head if parent_head else None}\n' - f'date = {datetime.datetime.now().strftime("%c")}\n' - f'message = {message}' - ) - - -def get_parent_head(dir_with_wit: Path) -> str: - wit_folder = dir_with_wit.joinpath('.wit') # repository + r'\.wit' - references_file = wit_folder.joinpath('references.txt') - if references_file.exists(): - ref_path = wit_folder.joinpath('references.txt') - with ref_path.open() as f_h: - references_content = f_h.readlines() - head_line = references_content[0].split('=') - return head_line[1].strip() - return '' - - -def save_files(dir_with_wit: Path, path_of_new_folder: str) -> None: - staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') - for item in os.listdir(staging_area_path): - src = os.path.join(staging_area_path, item) - dst = os.path.join(path_of_new_folder, item) - if os.path.isfile(src): - shutil.copy2(src, dst) - else: - shutil.copytree(src, dst) - - -def write_references(commit_id: str, dir_with_wit: Path) -> None: - wit_folder = dir_with_wit.joinpath('.wit') - ref_file = wit_folder.joinpath('references.txt') - new_master = commit_id - if ref_file.exists(): - new_master = get_new_master(dir_with_wit, ref_file, commit_id) - ref_file.write_text(f'HEAD={commit_id}\nMASTER={new_master}') - - -def get_new_master(dir_with_wit: Path, ref_file: Path, commit_id: str) -> str: - old_head_id = get_parent_head(dir_with_wit) - old_master_id = get_master_commit_id(ref_file) - if old_head_id == old_master_id: - return commit_id - else: - return old_master_id - - -def status() -> None: - repository = get_directory_with_wit(Path.cwd()) - if not repository: - raise WitError("<.wit> file not found") - commit_id = get_parent_head(repository) - files_added_since_last_commit = get_files_added_since_last_commit(commit_id, repository) - files_changed_since_last_commit = get_files_changed_since_last_commit(commit_id, repository) - files_in_staging_area_that_dont_match_original = get_files_in_staging_area_that_dont_match_original(repository) - files_not_in_staging_area = get_files_not_in_staging_area(repository) - print( - f"Commit id: {commit_id}\n" - f"Changes to be committed: {(list(files_added_since_last_commit) + list(files_changed_since_last_commit))}\n" - f"Changes not staged for commit: {list(files_in_staging_area_that_dont_match_original)}\n" - f"Untracked files: {list(files_not_in_staging_area)}" - ) - - -def get_files_added_since_last_commit(commit_id: str, repository: Path) -> Generator[Any, Any, None]: - commit_path = os.path.join(repository, '.wit', 'images', commit_id) - staging_area_path = os.path.join(repository, '.wit', 'staging_area') - all_files_in_stagind_area_and_sub = get_files_of_dir_and_subdirs(staging_area_path) - all_files_in_commit_and_sub_dirs = get_files_of_dir_and_subdirs(commit_path) - for file in all_files_in_stagind_area_and_sub: - if file not in all_files_in_commit_and_sub_dirs: - yield file - - -def get_files_changed_since_last_commit(commit_id: str, repository: Path) -> Generator[str, Any, None]: - commit_path = os.path.join(repository, '.wit', 'images', commit_id) - staging_area_path = os.path.join(repository, '.wit', 'staging_area') - all_files_in_commit_and_sub = get_all_files_in_dir_and_subs(commit_path) - all_files_in_staging_area_and_sub = get_all_files_in_dir_and_subs(staging_area_path) - yield from get_names_of_changed_files( - all_files_in_commit_and_sub, all_files_in_staging_area_and_sub, commit_path, staging_area_path - ) - - -def get_names_of_changed_files( - all_files_in_commit_and_sub: Generator[Union[bytes, str], Any, None], - all_files_in_staging_area_and_sub: Generator[Union[bytes, str], Any, None], - commit_path: Union[str, Path], - staging_area_path: Union[str, Path] -) -> Generator[str, Any, None]: - for s_file in all_files_in_staging_area_and_sub: - for c_file in all_files_in_commit_and_sub: - if Path(s_file).relative_to(staging_area_path) == Path(c_file).relative_to(commit_path): - if not filecmp.cmp(s_file, c_file): - yield Path(s_file).name - - -def get_all_files_in_dir_and_subs(commit_path: str) -> Generator[Union[bytes, str], Any, None]: - for (root, dirs, files) in os.walk(commit_path, topdown=True): - for file in files: - yield os.path.join(root, file) - - -def get_files_in_staging_area_that_dont_match_original(repository: Path) -> Generator[str, Any, None]: - staging_area_path = os.path.join(repository, '.wit', 'staging_area') - all_files_in_repository_and_sub_dirs = get_all_files_and_dirs_in_repository(repository) - all_files_in_staging_area_and_sub = get_all_files_in_dir_and_subs(staging_area_path) - yield from get_names_of_changed_files( - all_files_in_staging_area_and_sub, all_files_in_repository_and_sub_dirs, staging_area_path, repository - ) - - -def get_all_files_and_dirs_in_repository(repository: Path) -> Generator[Union[bytes, str], Any, None]: - for (root, dirs, files) in os.walk(repository, topdown=True): - if '.wit' not in Path(root).parts: - for file in files: - yield os.path.join(root, file) - - -def get_files_not_in_staging_area(repository: Path) -> Generator[Any, Any, None]: - staging_area_path = os.path.join(repository, '.wit', 'staging_area') - files_names_in_repository_and_sub_dirs = get_files_names_of_repository_and_subs(repository) - all_files_in_staging_area_and_sub_dirs = get_files_of_dir_and_subdirs(staging_area_path) - for file in files_names_in_repository_and_sub_dirs: - if file not in all_files_in_staging_area_and_sub_dirs: - yield file - - -def get_files_names_of_repository_and_subs(repository: Path): - for (root, dirs, files) in os.walk(repository, topdown=True): - if '.wit' not in Path(root).parts: - for file in files: - yield file - - -def get_files_of_dir_and_subdirs(file_path: str) -> Generator[Any, Any, None]: - for (root, dirs, files) in os.walk(file_path, topdown=True): - for file in files: - yield file - - -def checkout(commit_id: str) -> None: - repository = get_directory_with_wit(Path.cwd()) - if not repository: - raise WitError("<.wit> file not found") - references_file = repository.joinpath('.wit', 'references.txt') - if commit_id == 'master': - commit_id = get_master_commit_id(references_file) - last_commit_id = get_parent_head(repository) - if ( - list(get_files_added_since_last_commit(last_commit_id, repository)) - or list(get_files_changed_since_last_commit(last_commit_id, repository)) - or list(get_files_in_staging_area_that_dont_match_original(repository)) - ): - raise FilesDoesntMatchError("There are files added or changed after last commit") - change_files_in_main_folder(repository, commit_id) - change_head_in_references_file(commit_id, references_file) - change_staging_area_folder(repository, commit_id) - - -def change_head_in_references_file(commit_id: str, references_file: Path) -> None: - with references_file.open() as file: - master_line = file.readlines()[1] - references_file.write_text(f'HEAD={commit_id}\n{master_line}') - - -def get_master_commit_id(references_file: Path) -> str: - with references_file.open() as file: - references_content = file.readlines() - master_line = references_content[-1].split('=') - commit_id = master_line[-1].strip() - return commit_id - - -def change_files_in_main_folder(repository: Path, commit_id: str) -> None: - commit_path = os.path.join(repository, '.wit', 'images', commit_id) - # all_files_in_repository_and_sub_dirs = get_all_files_and_dirs_in_repository(repository) - all_files_in_repository_and_sub_dirs = [] - for (root, dirs, files) in os.walk(repository, topdown=True): - if '.wit' not in Path(root).parts: - for file in files: - all_files_in_repository_and_sub_dirs.append(os.path.join(root, file)) - # all_files_in_commit_and_sub_dirs = get_files_of_dir_and_subdirs(commit_path) # didn't work with the functions - all_files_in_commit_and_sub_dirs = [] - for (root, dirs, files) in os.walk(commit_path, topdown=True): - for file in files: - all_files_in_commit_and_sub_dirs.append(os.path.join(root, file)) - for c_file in all_files_in_commit_and_sub_dirs: - for r_file in all_files_in_repository_and_sub_dirs: - if Path(r_file).relative_to(repository) == Path(c_file).relative_to(commit_path): - shutil.copy2(c_file, r_file) - - -def change_staging_area_folder(dir_with_wit: Path, commit_id: str): - staging_area_path = dir_with_wit.joinpath('.wit', 'staging_area') - commit_path = dir_with_wit.joinpath('.wit', 'images', commit_id) - for file_or_dir in staging_area_path.iterdir(): - if file_or_dir.is_file(): - file_or_dir.unlink() - else: - shutil.rmtree(file_or_dir) - for file in commit_path.iterdir(): - rel_path = Path(file).relative_to(commit_path) - if file.is_file(): - shutil.copy2(file, staging_area_path.joinpath(rel_path)) - else: - shutil.copytree(file, staging_area_path.joinpath(rel_path)) - - -class WitError(Exception): - pass - - -class FilesDoesntMatchError(Exception): - pass - - -def is_command_correct(argv: list[str]) -> bool: - if argv[1] in ['init', 'status']: - return len(argv) == 2 - else: - return len(argv) == 3 - - -if sys.argv[1] == 'init': - if is_command_correct(sys.argv): - init() - else: - print(fr"Usage: python {sys.argv[0]} init") - -elif sys.argv[1] == 'add': - if is_command_correct(sys.argv): - add(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} add ") - -elif sys.argv[1] == 'commit': - if is_command_correct(sys.argv): - commit(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} commit MESSAGE") - -elif sys.argv[1] == 'status': - if is_command_correct(sys.argv): - status() - else: - print(fr"Usage: python {sys.argv[0]} status") - -elif sys.argv[1] == 'checkout': - if is_command_correct(sys.argv): - checkout(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} checkout ") From 0b7910eda38a4b2577b49d4f9e1e18ea81cfe2b1 Mon Sep 17 00:00:00 2001 From: RuthMahallaMilano <97195051+RuthMahallaMilano@users.noreply.github.com> Date: Thu, 6 Jan 2022 00:03:46 +0200 Subject: [PATCH 15/73] Delete init.py --- init.py | 22 ---------------------- 1 file changed, 22 deletions(-) delete mode 100644 init.py diff --git a/init.py b/init.py deleted file mode 100644 index 7f91f61..0000000 --- a/init.py +++ /dev/null @@ -1,22 +0,0 @@ -# upload 170 -import os -import sys - - -def init(): - cwd = os.getcwd() - wit_path = os.path.join(cwd, '.wit') - os.mkdir(wit_path) - os.mkdir(os.path.join(wit_path, 'images')) - os.mkdir(os.path.join(wit_path, 'staging_area')) - - -def is_init_command_correct(argv): - return len(argv) == 2 - - -if sys.argv[1] == 'init': - if is_init_command_correct(sys.argv): - init() - else: - print(r"Usage: python C:\Users\israe\PycharmProjects\wit_project\wit.py init") From 559e3b13a1be9b2146c8795c3080cb2538dc03a6 Mon Sep 17 00:00:00 2001 From: RuthMahallaMilano <97195051+RuthMahallaMilano@users.noreply.github.com> Date: Thu, 6 Jan 2022 00:04:21 +0200 Subject: [PATCH 16/73] Delete wit.py --- wit.py | 384 --------------------------------------------------------- 1 file changed, 384 deletions(-) delete mode 100644 wit.py diff --git a/wit.py b/wit.py deleted file mode 100644 index bb702b3..0000000 --- a/wit.py +++ /dev/null @@ -1,384 +0,0 @@ -# upload 176 -import datetime -import filecmp -import os -from pathlib import Path -import random -import shutil -import sys -from typing import Any, Generator, Optional, Union - - -def init() -> None: - cwd = os.getcwd() - wit_path = os.path.join(cwd, '.wit') - os.mkdir(wit_path) - os.mkdir(os.path.join(wit_path, 'images')) - os.mkdir(os.path.join(wit_path, 'staging_area')) - activated_path = os.path.join(wit_path, 'activated.txt') - Path(activated_path).write_text('master') - - -def add(path_to_add: str) -> None: - file_to_add = Path(os.path.abspath(path_to_add)) - repository = get_directory_with_wit(file_to_add) - if not repository: - raise WitError("<.wit> file not found") - destination = repository.joinpath('.wit', 'staging_area') - directories_to_copy = file_to_add.relative_to(repository).parts[:-1] - for dir_name in directories_to_copy: - dirs = os.listdir(destination) - destination = destination.joinpath(dir_name) - if dir_name not in dirs: - destination.mkdir() - save_the_copy(destination, file_to_add) - - -def save_the_copy(destination: Path, file: Path) -> None: - if file.is_file(): - shutil.copy2(file, destination) - else: - destination_of_folder_if_doesnt_exists = destination.joinpath(file.name) - if destination_of_folder_if_doesnt_exists.exists(): - shutil.rmtree(destination_of_folder_if_doesnt_exists) - shutil.copytree(file, destination_of_folder_if_doesnt_exists) - - -def get_directory_with_wit(file: Path) -> Optional[Path]: - for parent in file.parents: - dir_lst = os.listdir(parent) - if '.wit' in dir_lst: - return parent - return None - - -def commit(message: str) -> None: - dir_with_wit = get_directory_with_wit(Path.cwd()) - if not dir_with_wit: - raise WitError("<.wit> file not found") - images_path = dir_with_wit.joinpath('.wit', 'images') - path_of_new_folder = create_commit_folder(images_path) - create_commit_txt_file(dir_with_wit, images_path, path_of_new_folder, message) - save_files(dir_with_wit, path_of_new_folder) - commit_id = os.path.basename(path_of_new_folder) - - write_references(commit_id, dir_with_wit) - - -def create_commit_folder(images_path: Path) -> str: - folder_name = create_commit_name() - path_of_new_folder = os.path.join(images_path, folder_name) - os.mkdir(path_of_new_folder) - return path_of_new_folder - - -def create_commit_name(): - length = 20 - chars = '1234567890abcdef' - folder_name = ''.join(random.choices(chars, k=length)) - return folder_name - - -def create_commit_txt_file(dir_with_wit: Path, images_path: Path, path_of_new_folder: str, message: str) -> None: - parent_head = get_parent_head(dir_with_wit) - txt_file = images_path.joinpath(Path(path_of_new_folder).name + '.txt') - txt_file.write_text( - f'parent = {parent_head if parent_head else None}\n' - f'date = {datetime.datetime.now().strftime("%c")}\n' - f'message = {message}' - ) - - -def get_parent_head(dir_with_wit: Path) -> str: - wit_folder = dir_with_wit.joinpath('.wit') - references_file = wit_folder.joinpath('references.txt') - if references_file.exists(): - ref_path = wit_folder.joinpath('references.txt') - with ref_path.open() as f_h: - references_content = f_h.readlines() - head_line = references_content[0].split('=') - return head_line[1].strip() - return '' - - -def save_files(dir_with_wit: Path, path_of_new_folder: str) -> None: - staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') - for item in os.listdir(staging_area_path): - src = os.path.join(staging_area_path, item) - dst = os.path.join(path_of_new_folder, item) - if os.path.isfile(src): - shutil.copy2(src, dst) - else: - shutil.copytree(src, dst) - - -# בעת הרצת פקודת commit, יתעדכן (כרגיל) ה־HEAD כך שיצביע ל־commit החדש שנוצר. -# לפני עדכון ה־HEAD, בדקו אם ה־branch שנמצא במצב “פעיל” מצביע לאותו מקום שבו נמצא ה־HEAD. -# אם כן, עדכנו את references.txt כך שה־branch יצביע למספר ה־commit החדש שנוצר. - -def write_references(commit_id: str, dir_with_wit: Path) -> None: - wit_folder = dir_with_wit.joinpath('.wit') - ref_file = wit_folder.joinpath('references.txt') - # new_branch_id = commit_id # new_master = commit_id - activated_path = wit_folder.joinpath('activated.txt') - activated_branch = activated_path.read_text() - new_content = '='.join((activated_branch, commit_id)) - if ref_file.exists(): - content = ref_file.read_text().split() - head_line = content[0] - head_id = head_line.split('=')[1] - branch_data = content[1:] - new_content = head_line - for line in branch_data: - name_and_id = line.split('=') - branch_name = name_and_id[0] - branch_id = name_and_id[1] - if branch_name == activated_branch: - if branch_id == head_id: - line = '='.join((branch_name, commit_id)) - new_content += line - ref_file.write_text(f'HEAD={commit_id}\n{new_content}') - - -def status() -> None: - repository = get_directory_with_wit(Path.cwd()) - if not repository: - raise WitError("<.wit> file not found") - commit_id = get_parent_head(repository) - files_added_since_last_commit = get_files_added_since_last_commit(commit_id, repository) - files_changed_since_last_commit = get_files_changed_since_last_commit(commit_id, repository) - files_in_staging_area_that_dont_match_original = get_files_in_staging_area_that_dont_match_original(repository) - files_not_in_staging_area = get_files_not_in_staging_area(repository) - print( - f"Commit id: {commit_id}\n" - f"Changes to be committed: {(list(files_added_since_last_commit) + list(files_changed_since_last_commit))}\n" - f"Changes not staged for commit: {list(files_in_staging_area_that_dont_match_original)}\n" - f"Untracked files: {list(files_not_in_staging_area)}" - ) - - -def get_files_added_since_last_commit(commit_id: str, repository: Path) -> Generator[Any, Any, None]: - commit_path = os.path.join(repository, '.wit', 'images', commit_id) - staging_area_path = os.path.join(repository, '.wit', 'staging_area') - all_files_in_stagind_area_and_sub = get_files_of_dir_and_subdirs(staging_area_path) - all_files_in_commit_and_sub_dirs = get_files_of_dir_and_subdirs(commit_path) - for file in all_files_in_stagind_area_and_sub: - if file not in all_files_in_commit_and_sub_dirs: - yield file - - -def get_files_changed_since_last_commit(commit_id: str, repository: Path) -> Generator[str, Any, None]: - commit_path = os.path.join(repository, '.wit', 'images', commit_id) - staging_area_path = os.path.join(repository, '.wit', 'staging_area') - all_files_in_commit_and_sub = get_all_files_in_dir_and_subs(commit_path) - all_files_in_staging_area_and_sub = get_all_files_in_dir_and_subs(staging_area_path) - yield from get_names_of_changed_files( - all_files_in_commit_and_sub, all_files_in_staging_area_and_sub, commit_path, staging_area_path - ) - - -def get_names_of_changed_files( - all_files_in_commit_and_sub: Generator[Union[bytes, str], Any, None], - all_files_in_staging_area_and_sub: Generator[Union[bytes, str], Any, None], - commit_path: Union[str, Path], - staging_area_path: Union[str, Path] -) -> Generator[str, Any, None]: - for s_file in all_files_in_staging_area_and_sub: - for c_file in all_files_in_commit_and_sub: - if Path(s_file).relative_to(staging_area_path) == Path(c_file).relative_to(commit_path): - if not filecmp.cmp(s_file, c_file): - yield Path(s_file).name - - -def get_all_files_in_dir_and_subs(commit_path: str) -> Generator[Union[bytes, str], Any, None]: - for (root, dirs, files) in os.walk(commit_path, topdown=True): - for file in files: - yield os.path.join(root, file) - - -def get_files_in_staging_area_that_dont_match_original(repository: Path) -> Generator[str, Any, None]: - staging_area_path = os.path.join(repository, '.wit', 'staging_area') - all_files_in_repository_and_sub_dirs = get_all_files_and_dirs_in_repository(repository) - all_files_in_staging_area_and_sub = get_all_files_in_dir_and_subs(staging_area_path) - yield from get_names_of_changed_files( - all_files_in_staging_area_and_sub, all_files_in_repository_and_sub_dirs, staging_area_path, repository - ) - - -def get_all_files_and_dirs_in_repository(repository: Path) -> Generator[Union[bytes, str], Any, None]: - for (root, dirs, files) in os.walk(repository, topdown=True): - if '.wit' not in Path(root).parts: - for file in files: - yield os.path.join(root, file) - - -def get_files_not_in_staging_area(repository: Path) -> Generator[Any, Any, None]: - staging_area_path = os.path.join(repository, '.wit', 'staging_area') - files_names_in_repository_and_sub_dirs = get_files_names_of_repository_and_subs(repository) - all_files_in_staging_area_and_sub_dirs = get_files_of_dir_and_subdirs(staging_area_path) - for file in files_names_in_repository_and_sub_dirs: - if file not in all_files_in_staging_area_and_sub_dirs: - yield file - - -def get_files_names_of_repository_and_subs(repository: Path): - for (root, dirs, files) in os.walk(repository, topdown=True): - if '.wit' not in Path(root).parts: - for file in files: - yield file - - -def get_files_of_dir_and_subdirs(file_path: str) -> Generator[Any, Any, None]: - for (root, dirs, files) in os.walk(file_path, topdown=True): - for file in files: - yield file - - -def checkout(commit_id_or_branch: str) -> None: - repository = get_directory_with_wit(Path.cwd()) - if not repository: - raise WitError("<.wit> file not found") - references_file = repository.joinpath('.wit', 'references.txt') - last_commit_id = get_parent_head(repository) - if ( - list(get_files_added_since_last_commit(last_commit_id, repository)) - or list(get_files_changed_since_last_commit(last_commit_id, repository)) - or list(get_files_in_staging_area_that_dont_match_original(repository)) - ): - raise FilesDoesntMatchError("There are files added or changed after last commit") - commit_id = get_commit_id_of_branch(commit_id_or_branch, references_file) - print(commit_id) - change_files_in_main_folder(repository, commit_id) - change_head_in_references_file(commit_id, references_file) - change_staging_area_folder(repository, commit_id) - write_activated(commit_id, commit_id_or_branch, repository) # - - -def write_activated(commit_id: str, commit_id_or_branch: str, repository: Path) -> None: - activated_path = repository.joinpath('.wit', 'activated.txt') - Path(activated_path).write_text(commit_id_or_branch) - - -def get_commit_id_of_branch(commit_id_or_branch: str, references_file: Path) -> str: - with references_file.open() as file: - references_content = file.readlines() - branches_data = references_content[1:] - for branch_line in branches_data: - name_and_id = branch_line.split('=') - branch_name = name_and_id[0] - branch_id = name_and_id[1] - if branch_name == commit_id_or_branch: - return branch_id - return commit_id_or_branch - - -def change_head_in_references_file(commit_id: str, references_file: Path) -> None: - with references_file.open() as file: - branches = file.readlines()[1:] - branches_txt = ''.join(branches) - references_file.write_text(f'HEAD={commit_id}\n{branches_txt}') - - -def get_master_commit_id(references_file: Path) -> str: - with references_file.open() as file: - references_content = file.readlines() - master_line = references_content[1].split('=') - commit_id = master_line[-1].strip() - return commit_id - - -def change_files_in_main_folder(repository: Path, commit_id: str) -> None: - commit_path = os.path.join(repository, '.wit', 'images', commit_id) - # all_files_in_repository_and_sub_dirs = get_all_files_and_dirs_in_repository(repository) - all_files_in_repository_and_sub_dirs = [] - for (root, dirs, files) in os.walk(repository, topdown=True): - if '.wit' not in Path(root).parts: - for file in files: - all_files_in_repository_and_sub_dirs.append(os.path.join(root, file)) - # all_files_in_commit_and_sub_dirs = get_files_of_dir_and_subdirs(commit_path) # didn't work with the functions - all_files_in_commit_and_sub_dirs = [] - for (root, dirs, files) in os.walk(commit_path, topdown=True): - for file in files: - all_files_in_commit_and_sub_dirs.append(os.path.join(root, file)) - for c_file in all_files_in_commit_and_sub_dirs: - for r_file in all_files_in_repository_and_sub_dirs: - if Path(r_file).relative_to(repository) == Path(c_file).relative_to(commit_path): - shutil.copy2(c_file, r_file) - - -def change_staging_area_folder(dir_with_wit: Path, commit_id: str): - staging_area_path = dir_with_wit.joinpath('.wit', 'staging_area') - commit_path = dir_with_wit.joinpath('.wit', 'images', commit_id) - for file_or_dir in staging_area_path.iterdir(): - if file_or_dir.is_file(): - file_or_dir.unlink() - else: - shutil.rmtree(file_or_dir) - for file in commit_path.iterdir(): - rel_path = Path(file).relative_to(commit_path) - if file.is_file(): - shutil.copy2(file, staging_area_path.joinpath(rel_path)) - else: - shutil.copytree(file, staging_area_path.joinpath(rel_path)) - - -def branch(name: str) -> None: - repository = get_directory_with_wit(Path.cwd()) - if not repository: - raise WitError("<.wit> file not found") - references_file = repository.joinpath('.wit', 'references.txt') - commit_id = get_parent_head(repository) - with references_file.open('a') as ref_file: - ref_file.write(f'\n{name}={commit_id}') - - -class WitError(Exception): - pass - - -class FilesDoesntMatchError(Exception): - pass - - -def is_command_correct(argv: list[str]) -> bool: - if argv[1] in ['init', 'status']: - return len(argv) == 2 - else: - return len(argv) == 3 - - -if sys.argv[1] == 'init': - if is_command_correct(sys.argv): - init() - else: - print(fr"Usage: python {sys.argv[0]} init") - -elif sys.argv[1] == 'add': - if is_command_correct(sys.argv): - add(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} add ") - -elif sys.argv[1] == 'commit': - if is_command_correct(sys.argv): - commit(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} commit MESSAGE") - -elif sys.argv[1] == 'status': - if is_command_correct(sys.argv): - status() - else: - print(fr"Usage: python {sys.argv[0]} status") - -elif sys.argv[1] == 'checkout': - if is_command_correct(sys.argv): - checkout(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} checkout ") - -elif sys.argv[1] == 'branch': - if is_command_correct(sys.argv): - branch(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} branch ") From 16a2ab05efeda942689a78967ac3af7bc572d4f6 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Sun, 9 Jan 2022 23:34:18 +0200 Subject: [PATCH 17/73] gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index dce79fc..f92b431 100644 --- a/.gitignore +++ b/.gitignore @@ -128,3 +128,4 @@ dmypy.json # Pyre type checker .pyre/ .wit +.idea From 37687c36c611fde2839654dbe6643e4dd63d7e17 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Mon, 10 Jan 2022 09:09:06 +0200 Subject: [PATCH 18/73] finish --- .idea/.name | 2 +- add_171.py => add.py | 0 branch.py | 384 +++++++++++++++++++++++++++++++++++++++++++ branch_req.txt | 23 --- checkout.py | 234 +++++++++++--------------- 5 files changed, 485 insertions(+), 158 deletions(-) rename add_171.py => add.py (100%) create mode 100644 branch.py delete mode 100644 branch_req.txt diff --git a/.idea/.name b/.idea/.name index 3e4e48b..4a32c97 100644 --- a/.idea/.name +++ b/.idea/.name @@ -1 +1 @@ -.gitignore \ No newline at end of file +init.py \ No newline at end of file diff --git a/add_171.py b/add.py similarity index 100% rename from add_171.py rename to add.py diff --git a/branch.py b/branch.py new file mode 100644 index 0000000..bb702b3 --- /dev/null +++ b/branch.py @@ -0,0 +1,384 @@ +# upload 176 +import datetime +import filecmp +import os +from pathlib import Path +import random +import shutil +import sys +from typing import Any, Generator, Optional, Union + + +def init() -> None: + cwd = os.getcwd() + wit_path = os.path.join(cwd, '.wit') + os.mkdir(wit_path) + os.mkdir(os.path.join(wit_path, 'images')) + os.mkdir(os.path.join(wit_path, 'staging_area')) + activated_path = os.path.join(wit_path, 'activated.txt') + Path(activated_path).write_text('master') + + +def add(path_to_add: str) -> None: + file_to_add = Path(os.path.abspath(path_to_add)) + repository = get_directory_with_wit(file_to_add) + if not repository: + raise WitError("<.wit> file not found") + destination = repository.joinpath('.wit', 'staging_area') + directories_to_copy = file_to_add.relative_to(repository).parts[:-1] + for dir_name in directories_to_copy: + dirs = os.listdir(destination) + destination = destination.joinpath(dir_name) + if dir_name not in dirs: + destination.mkdir() + save_the_copy(destination, file_to_add) + + +def save_the_copy(destination: Path, file: Path) -> None: + if file.is_file(): + shutil.copy2(file, destination) + else: + destination_of_folder_if_doesnt_exists = destination.joinpath(file.name) + if destination_of_folder_if_doesnt_exists.exists(): + shutil.rmtree(destination_of_folder_if_doesnt_exists) + shutil.copytree(file, destination_of_folder_if_doesnt_exists) + + +def get_directory_with_wit(file: Path) -> Optional[Path]: + for parent in file.parents: + dir_lst = os.listdir(parent) + if '.wit' in dir_lst: + return parent + return None + + +def commit(message: str) -> None: + dir_with_wit = get_directory_with_wit(Path.cwd()) + if not dir_with_wit: + raise WitError("<.wit> file not found") + images_path = dir_with_wit.joinpath('.wit', 'images') + path_of_new_folder = create_commit_folder(images_path) + create_commit_txt_file(dir_with_wit, images_path, path_of_new_folder, message) + save_files(dir_with_wit, path_of_new_folder) + commit_id = os.path.basename(path_of_new_folder) + + write_references(commit_id, dir_with_wit) + + +def create_commit_folder(images_path: Path) -> str: + folder_name = create_commit_name() + path_of_new_folder = os.path.join(images_path, folder_name) + os.mkdir(path_of_new_folder) + return path_of_new_folder + + +def create_commit_name(): + length = 20 + chars = '1234567890abcdef' + folder_name = ''.join(random.choices(chars, k=length)) + return folder_name + + +def create_commit_txt_file(dir_with_wit: Path, images_path: Path, path_of_new_folder: str, message: str) -> None: + parent_head = get_parent_head(dir_with_wit) + txt_file = images_path.joinpath(Path(path_of_new_folder).name + '.txt') + txt_file.write_text( + f'parent = {parent_head if parent_head else None}\n' + f'date = {datetime.datetime.now().strftime("%c")}\n' + f'message = {message}' + ) + + +def get_parent_head(dir_with_wit: Path) -> str: + wit_folder = dir_with_wit.joinpath('.wit') + references_file = wit_folder.joinpath('references.txt') + if references_file.exists(): + ref_path = wit_folder.joinpath('references.txt') + with ref_path.open() as f_h: + references_content = f_h.readlines() + head_line = references_content[0].split('=') + return head_line[1].strip() + return '' + + +def save_files(dir_with_wit: Path, path_of_new_folder: str) -> None: + staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') + for item in os.listdir(staging_area_path): + src = os.path.join(staging_area_path, item) + dst = os.path.join(path_of_new_folder, item) + if os.path.isfile(src): + shutil.copy2(src, dst) + else: + shutil.copytree(src, dst) + + +# בעת הרצת פקודת commit, יתעדכן (כרגיל) ה־HEAD כך שיצביע ל־commit החדש שנוצר. +# לפני עדכון ה־HEAD, בדקו אם ה־branch שנמצא במצב “פעיל” מצביע לאותו מקום שבו נמצא ה־HEAD. +# אם כן, עדכנו את references.txt כך שה־branch יצביע למספר ה־commit החדש שנוצר. + +def write_references(commit_id: str, dir_with_wit: Path) -> None: + wit_folder = dir_with_wit.joinpath('.wit') + ref_file = wit_folder.joinpath('references.txt') + # new_branch_id = commit_id # new_master = commit_id + activated_path = wit_folder.joinpath('activated.txt') + activated_branch = activated_path.read_text() + new_content = '='.join((activated_branch, commit_id)) + if ref_file.exists(): + content = ref_file.read_text().split() + head_line = content[0] + head_id = head_line.split('=')[1] + branch_data = content[1:] + new_content = head_line + for line in branch_data: + name_and_id = line.split('=') + branch_name = name_and_id[0] + branch_id = name_and_id[1] + if branch_name == activated_branch: + if branch_id == head_id: + line = '='.join((branch_name, commit_id)) + new_content += line + ref_file.write_text(f'HEAD={commit_id}\n{new_content}') + + +def status() -> None: + repository = get_directory_with_wit(Path.cwd()) + if not repository: + raise WitError("<.wit> file not found") + commit_id = get_parent_head(repository) + files_added_since_last_commit = get_files_added_since_last_commit(commit_id, repository) + files_changed_since_last_commit = get_files_changed_since_last_commit(commit_id, repository) + files_in_staging_area_that_dont_match_original = get_files_in_staging_area_that_dont_match_original(repository) + files_not_in_staging_area = get_files_not_in_staging_area(repository) + print( + f"Commit id: {commit_id}\n" + f"Changes to be committed: {(list(files_added_since_last_commit) + list(files_changed_since_last_commit))}\n" + f"Changes not staged for commit: {list(files_in_staging_area_that_dont_match_original)}\n" + f"Untracked files: {list(files_not_in_staging_area)}" + ) + + +def get_files_added_since_last_commit(commit_id: str, repository: Path) -> Generator[Any, Any, None]: + commit_path = os.path.join(repository, '.wit', 'images', commit_id) + staging_area_path = os.path.join(repository, '.wit', 'staging_area') + all_files_in_stagind_area_and_sub = get_files_of_dir_and_subdirs(staging_area_path) + all_files_in_commit_and_sub_dirs = get_files_of_dir_and_subdirs(commit_path) + for file in all_files_in_stagind_area_and_sub: + if file not in all_files_in_commit_and_sub_dirs: + yield file + + +def get_files_changed_since_last_commit(commit_id: str, repository: Path) -> Generator[str, Any, None]: + commit_path = os.path.join(repository, '.wit', 'images', commit_id) + staging_area_path = os.path.join(repository, '.wit', 'staging_area') + all_files_in_commit_and_sub = get_all_files_in_dir_and_subs(commit_path) + all_files_in_staging_area_and_sub = get_all_files_in_dir_and_subs(staging_area_path) + yield from get_names_of_changed_files( + all_files_in_commit_and_sub, all_files_in_staging_area_and_sub, commit_path, staging_area_path + ) + + +def get_names_of_changed_files( + all_files_in_commit_and_sub: Generator[Union[bytes, str], Any, None], + all_files_in_staging_area_and_sub: Generator[Union[bytes, str], Any, None], + commit_path: Union[str, Path], + staging_area_path: Union[str, Path] +) -> Generator[str, Any, None]: + for s_file in all_files_in_staging_area_and_sub: + for c_file in all_files_in_commit_and_sub: + if Path(s_file).relative_to(staging_area_path) == Path(c_file).relative_to(commit_path): + if not filecmp.cmp(s_file, c_file): + yield Path(s_file).name + + +def get_all_files_in_dir_and_subs(commit_path: str) -> Generator[Union[bytes, str], Any, None]: + for (root, dirs, files) in os.walk(commit_path, topdown=True): + for file in files: + yield os.path.join(root, file) + + +def get_files_in_staging_area_that_dont_match_original(repository: Path) -> Generator[str, Any, None]: + staging_area_path = os.path.join(repository, '.wit', 'staging_area') + all_files_in_repository_and_sub_dirs = get_all_files_and_dirs_in_repository(repository) + all_files_in_staging_area_and_sub = get_all_files_in_dir_and_subs(staging_area_path) + yield from get_names_of_changed_files( + all_files_in_staging_area_and_sub, all_files_in_repository_and_sub_dirs, staging_area_path, repository + ) + + +def get_all_files_and_dirs_in_repository(repository: Path) -> Generator[Union[bytes, str], Any, None]: + for (root, dirs, files) in os.walk(repository, topdown=True): + if '.wit' not in Path(root).parts: + for file in files: + yield os.path.join(root, file) + + +def get_files_not_in_staging_area(repository: Path) -> Generator[Any, Any, None]: + staging_area_path = os.path.join(repository, '.wit', 'staging_area') + files_names_in_repository_and_sub_dirs = get_files_names_of_repository_and_subs(repository) + all_files_in_staging_area_and_sub_dirs = get_files_of_dir_and_subdirs(staging_area_path) + for file in files_names_in_repository_and_sub_dirs: + if file not in all_files_in_staging_area_and_sub_dirs: + yield file + + +def get_files_names_of_repository_and_subs(repository: Path): + for (root, dirs, files) in os.walk(repository, topdown=True): + if '.wit' not in Path(root).parts: + for file in files: + yield file + + +def get_files_of_dir_and_subdirs(file_path: str) -> Generator[Any, Any, None]: + for (root, dirs, files) in os.walk(file_path, topdown=True): + for file in files: + yield file + + +def checkout(commit_id_or_branch: str) -> None: + repository = get_directory_with_wit(Path.cwd()) + if not repository: + raise WitError("<.wit> file not found") + references_file = repository.joinpath('.wit', 'references.txt') + last_commit_id = get_parent_head(repository) + if ( + list(get_files_added_since_last_commit(last_commit_id, repository)) + or list(get_files_changed_since_last_commit(last_commit_id, repository)) + or list(get_files_in_staging_area_that_dont_match_original(repository)) + ): + raise FilesDoesntMatchError("There are files added or changed after last commit") + commit_id = get_commit_id_of_branch(commit_id_or_branch, references_file) + print(commit_id) + change_files_in_main_folder(repository, commit_id) + change_head_in_references_file(commit_id, references_file) + change_staging_area_folder(repository, commit_id) + write_activated(commit_id, commit_id_or_branch, repository) # + + +def write_activated(commit_id: str, commit_id_or_branch: str, repository: Path) -> None: + activated_path = repository.joinpath('.wit', 'activated.txt') + Path(activated_path).write_text(commit_id_or_branch) + + +def get_commit_id_of_branch(commit_id_or_branch: str, references_file: Path) -> str: + with references_file.open() as file: + references_content = file.readlines() + branches_data = references_content[1:] + for branch_line in branches_data: + name_and_id = branch_line.split('=') + branch_name = name_and_id[0] + branch_id = name_and_id[1] + if branch_name == commit_id_or_branch: + return branch_id + return commit_id_or_branch + + +def change_head_in_references_file(commit_id: str, references_file: Path) -> None: + with references_file.open() as file: + branches = file.readlines()[1:] + branches_txt = ''.join(branches) + references_file.write_text(f'HEAD={commit_id}\n{branches_txt}') + + +def get_master_commit_id(references_file: Path) -> str: + with references_file.open() as file: + references_content = file.readlines() + master_line = references_content[1].split('=') + commit_id = master_line[-1].strip() + return commit_id + + +def change_files_in_main_folder(repository: Path, commit_id: str) -> None: + commit_path = os.path.join(repository, '.wit', 'images', commit_id) + # all_files_in_repository_and_sub_dirs = get_all_files_and_dirs_in_repository(repository) + all_files_in_repository_and_sub_dirs = [] + for (root, dirs, files) in os.walk(repository, topdown=True): + if '.wit' not in Path(root).parts: + for file in files: + all_files_in_repository_and_sub_dirs.append(os.path.join(root, file)) + # all_files_in_commit_and_sub_dirs = get_files_of_dir_and_subdirs(commit_path) # didn't work with the functions + all_files_in_commit_and_sub_dirs = [] + for (root, dirs, files) in os.walk(commit_path, topdown=True): + for file in files: + all_files_in_commit_and_sub_dirs.append(os.path.join(root, file)) + for c_file in all_files_in_commit_and_sub_dirs: + for r_file in all_files_in_repository_and_sub_dirs: + if Path(r_file).relative_to(repository) == Path(c_file).relative_to(commit_path): + shutil.copy2(c_file, r_file) + + +def change_staging_area_folder(dir_with_wit: Path, commit_id: str): + staging_area_path = dir_with_wit.joinpath('.wit', 'staging_area') + commit_path = dir_with_wit.joinpath('.wit', 'images', commit_id) + for file_or_dir in staging_area_path.iterdir(): + if file_or_dir.is_file(): + file_or_dir.unlink() + else: + shutil.rmtree(file_or_dir) + for file in commit_path.iterdir(): + rel_path = Path(file).relative_to(commit_path) + if file.is_file(): + shutil.copy2(file, staging_area_path.joinpath(rel_path)) + else: + shutil.copytree(file, staging_area_path.joinpath(rel_path)) + + +def branch(name: str) -> None: + repository = get_directory_with_wit(Path.cwd()) + if not repository: + raise WitError("<.wit> file not found") + references_file = repository.joinpath('.wit', 'references.txt') + commit_id = get_parent_head(repository) + with references_file.open('a') as ref_file: + ref_file.write(f'\n{name}={commit_id}') + + +class WitError(Exception): + pass + + +class FilesDoesntMatchError(Exception): + pass + + +def is_command_correct(argv: list[str]) -> bool: + if argv[1] in ['init', 'status']: + return len(argv) == 2 + else: + return len(argv) == 3 + + +if sys.argv[1] == 'init': + if is_command_correct(sys.argv): + init() + else: + print(fr"Usage: python {sys.argv[0]} init") + +elif sys.argv[1] == 'add': + if is_command_correct(sys.argv): + add(sys.argv[2]) + else: + print(fr"Usage: python {sys.argv[0]} add ") + +elif sys.argv[1] == 'commit': + if is_command_correct(sys.argv): + commit(sys.argv[2]) + else: + print(fr"Usage: python {sys.argv[0]} commit MESSAGE") + +elif sys.argv[1] == 'status': + if is_command_correct(sys.argv): + status() + else: + print(fr"Usage: python {sys.argv[0]} status") + +elif sys.argv[1] == 'checkout': + if is_command_correct(sys.argv): + checkout(sys.argv[2]) + else: + print(fr"Usage: python {sys.argv[0]} checkout ") + +elif sys.argv[1] == 'branch': + if is_command_correct(sys.argv): + branch(sys.argv[2]) + else: + print(fr"Usage: python {sys.argv[0]} branch ") diff --git a/branch_req.txt b/branch_req.txt deleted file mode 100644 index 651b06b..0000000 --- a/branch_req.txt +++ /dev/null @@ -1,23 +0,0 @@ -V -בעת הרצת הפקודה python path/to/wit.py branch NAME, צרו שורה חדשה ב־references.txt. השורה תראה כך: NAME=COMMIT_ID, -כאשר במקום NAME יופיע שמו של ה־branch, ובמקום COMMIT_ID יופיע מספרו של ה־commit שבו נמצא ה־HEAD בעת הרצת הפקודה. - -V -בעת הרצת פקודת checkout, יעודכן בקובץ בשם activated.txt שנמצא ישירות תחת התיקייה .wit, שמו של ה־branch שנמצא במצב “פעיל” בעת ביצוע הפקודה. זה יהיה כל תוכנו של הקובץ, -ולכן אפשר להרגיש בנוח לדרוס אותו. - -בעת הרצת פקודת commit, יתעדכן (כרגיל) ה־HEAD כך שיצביע ל־commit החדש שנוצר. -לפני עדכון ה־HEAD, בדקו אם ה־branch שנמצא במצב “פעיל” מצביע לאותו מקום שבו נמצא ה־HEAD. -אם כן, עדכנו את references.txt כך שה־branch יצביע למספר ה־commit החדש שנוצר. - -שינויים שצריך לעשות: - -V -בניגוד למה שנכתב ביום 2, בעת פקודת commit, התווית master כבר לא תתקדם כל פעם שהיא וה־HEAD נמצאים באותו מקום. כדי שתתקדם, היא חייבת שהתנאי המדובר יתקיים וגם שהענף יהיה “מופעל”. -הענף master “מופעל” והתווית תתקדם רק אם ה־checkout האחרון שהתבצע היה python wit.py checkout master. - -V -בעת הרצת הפקודה init, יווצר קובץ חדש בשם activated.txt שבו ירשם master. - -V -פקודת ה־checkout כעת צריכה להיות מסוגלת לקבל אחת משתי האפשרויות: או commit id, או שם של branch. diff --git a/checkout.py b/checkout.py index 8cf3efe..52f833f 100644 --- a/checkout.py +++ b/checkout.py @@ -1,12 +1,12 @@ # upload 174 import datetime -import filecmp +from filecmp import dircmp import os from pathlib import Path import random import shutil import sys -from typing import Any, Generator, Optional, Union +from typing import Optional, Union, Iterator def init() -> None: @@ -18,18 +18,18 @@ def init() -> None: def add(path_to_add: str) -> None: - file_to_add = Path(os.path.abspath(path_to_add)) - repository = get_directory_with_wit(file_to_add) - if not repository: + file = Path(os.path.abspath(path_to_add)) + directory_with_wit = get_directory_with_wit(file) + if not directory_with_wit: raise WitError("<.wit> file not found") - destination = repository.joinpath('.wit', 'staging_area') - directories_to_copy = file_to_add.relative_to(repository).parts[:-1] + destination = directory_with_wit.joinpath('.wit', 'staging_area') + directories_to_copy = file.relative_to(directory_with_wit).parts[:-1] for dir_name in directories_to_copy: dirs = os.listdir(destination) destination = destination.joinpath(dir_name) if dir_name not in dirs: destination.mkdir() - save_the_copy(destination, file_to_add) + save_the_copy(destination, file) def save_the_copy(destination: Path, file: Path) -> None: @@ -43,10 +43,11 @@ def save_the_copy(destination: Path, file: Path) -> None: def get_directory_with_wit(file: Path) -> Optional[Path]: - for parent in file.parents: - dir_lst = os.listdir(parent) - if '.wit' in dir_lst: - return parent + parents = file.parents + for p in parents: + wit = Path.joinpath(p, '.wit') + if wit.is_dir(): + return p return None @@ -63,16 +64,16 @@ def commit(message: str) -> None: def create_commit_folder(images_path: Path) -> str: - folder_name = create_commit_name() + folder_name = create_folder_name() path_of_new_folder = os.path.join(images_path, folder_name) os.mkdir(path_of_new_folder) return path_of_new_folder -def create_commit_name(): +def create_folder_name(): length = 20 chars = '1234567890abcdef' - folder_name = ''.join(random.choices(chars, k=length)) + folder_name = ''.join(random.choice(chars) for _ in range(length)) return folder_name @@ -87,7 +88,7 @@ def create_commit_txt_file(dir_with_wit: Path, images_path: Path, path_of_new_fo def get_parent_head(dir_with_wit: Path) -> str: - wit_folder = dir_with_wit.joinpath('.wit') # repository + r'\.wit' + wit_folder = dir_with_wit.joinpath('.wit') references_file = wit_folder.joinpath('references.txt') if references_file.exists(): ref_path = wit_folder.joinpath('references.txt') @@ -112,19 +113,7 @@ def save_files(dir_with_wit: Path, path_of_new_folder: str) -> None: def write_references(commit_id: str, dir_with_wit: Path) -> None: wit_folder = dir_with_wit.joinpath('.wit') ref_file = wit_folder.joinpath('references.txt') - new_master = commit_id - if ref_file.exists(): - new_master = get_new_master(dir_with_wit, ref_file, commit_id) - ref_file.write_text(f'HEAD={commit_id}\nMASTER={new_master}') - - -def get_new_master(dir_with_wit: Path, ref_file: Path, commit_id: str) -> str: - old_head_id = get_parent_head(dir_with_wit) - old_master_id = get_master_commit_id(ref_file) - if old_head_id == old_master_id: - return commit_id - else: - return old_master_id + ref_file.write_text(f'HEAD={commit_id}\nMASTER={commit_id}\n') def status() -> None: @@ -132,118 +121,105 @@ def status() -> None: if not repository: raise WitError("<.wit> file not found") commit_id = get_parent_head(repository) - files_added_since_last_commit = get_files_added_since_last_commit(commit_id, repository) - files_changed_since_last_commit = get_files_changed_since_last_commit(commit_id, repository) - files_in_staging_area_that_dont_match_original = get_files_in_staging_area_that_dont_match_original(repository) - files_not_in_staging_area = get_files_not_in_staging_area(repository) + commit_path = os.path.join(repository, '.wit', 'images', commit_id) + staging_area_path = os.path.join(repository, '.wit', 'staging_area') + changes_to_be_committed = list(get_changes_to_be_committed(commit_path, staging_area_path)) + changes_not_staged_for_commit = list(get_changes_not_staged_for_commit(repository, staging_area_path)) + untracked_files = list(get_untracked_files(repository, staging_area_path)) print( f"Commit id: {commit_id}\n" - f"Changes to be committed: {(list(files_added_since_last_commit) + list(files_changed_since_last_commit))}\n" - f"Changes not staged for commit: {list(files_in_staging_area_that_dont_match_original)}\n" - f"Untracked files: {list(files_not_in_staging_area)}" + f"Changes to be committed: {changes_to_be_committed}\n" + f"Changes not staged for commit: {changes_not_staged_for_commit}\n" + f"Untracked files: {untracked_files}" ) -def get_files_added_since_last_commit(commit_id: str, repository: Path) -> Generator[Any, Any, None]: - commit_path = os.path.join(repository, '.wit', 'images', commit_id) - staging_area_path = os.path.join(repository, '.wit', 'staging_area') - all_files_in_stagind_area_and_sub = get_files_of_dir_and_subdirs(staging_area_path) - all_files_in_commit_and_sub_dirs = get_files_of_dir_and_subdirs(commit_path) - for file in all_files_in_stagind_area_and_sub: - if file not in all_files_in_commit_and_sub_dirs: - yield file - - -def get_files_changed_since_last_commit(commit_id: str, repository: Path) -> Generator[str, Any, None]: - commit_path = os.path.join(repository, '.wit', 'images', commit_id) - staging_area_path = os.path.join(repository, '.wit', 'staging_area') - all_files_in_commit_and_sub = get_all_files_in_dir_and_subs(commit_path) - all_files_in_staging_area_and_sub = get_all_files_in_dir_and_subs(staging_area_path) - yield from get_names_of_changed_files( - all_files_in_commit_and_sub, all_files_in_staging_area_and_sub, commit_path, staging_area_path - ) - +def get_all_files_in_directory_and_subs(directory: Union[Path, str], start_path: Union[Path, str]) -> Iterator[str]: + for (root, dirs, files) in os.walk(directory, topdown=True): + for file in files: + file_path = os.path.join(root, file) + rel = os.path.relpath(file_path, start=start_path) + yield rel -def get_names_of_changed_files( - all_files_in_commit_and_sub: Generator[Union[bytes, str], Any, None], - all_files_in_staging_area_and_sub: Generator[Union[bytes, str], Any, None], - commit_path: Union[str, Path], - staging_area_path: Union[str, Path] -) -> Generator[str, Any, None]: - for s_file in all_files_in_staging_area_and_sub: - for c_file in all_files_in_commit_and_sub: - if Path(s_file).relative_to(staging_area_path) == Path(c_file).relative_to(commit_path): - if not filecmp.cmp(s_file, c_file): - yield Path(s_file).name +def get_changes_to_be_committed(commit_path: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: + cmp = dircmp(commit_path, staging_area_path) + yield from get_new_and_changed_files(cmp, staging_area_path) + for d, d_cmp in cmp.subdirs.items(): + yield from get_new_and_changed_files(d_cmp, os.path.join(staging_area_path, d)) -def get_all_files_in_dir_and_subs(commit_path: str) -> Generator[Union[bytes, str], Any, None]: - for (root, dirs, files) in os.walk(commit_path, topdown=True): - for file in files: - yield os.path.join(root, file) +def get_new_and_changed_files(cmp: dircmp[Union[str, bytes]], staging_area_path: Union[Path, str]) -> Iterator[str]: + yield from get_new_files_added(cmp, staging_area_path) + yield from get_changed_files(cmp, staging_area_path) -def get_files_in_staging_area_that_dont_match_original(repository: Path) -> Generator[str, Any, None]: - staging_area_path = os.path.join(repository, '.wit', 'staging_area') - all_files_in_repository_and_sub_dirs = get_all_files_and_dirs_in_repository(repository) - all_files_in_staging_area_and_sub = get_all_files_in_dir_and_subs(staging_area_path) - yield from get_names_of_changed_files( - all_files_in_staging_area_and_sub, all_files_in_repository_and_sub_dirs, staging_area_path, repository - ) +def get_changed_files(cmp: dircmp[Union[str, bytes]], staging_area_path) -> Iterator[str]: + diff_files = cmp.diff_files + start_path = os.path.join(get_directory_with_wit(Path.cwd()), '.wit', 'staging_area') + for diff in diff_files: + file_path = os.path.join(staging_area_path, diff) -def get_all_files_and_dirs_in_repository(repository: Path) -> Generator[Union[bytes, str], Any, None]: - for (root, dirs, files) in os.walk(repository, topdown=True): - if '.wit' not in Path(root).parts: - for file in files: - yield os.path.join(root, file) + rel = os.path.relpath(file_path, start=start_path) + yield rel -def get_files_not_in_staging_area(repository: Path) -> Generator[Any, Any, None]: - staging_area_path = os.path.join(repository, '.wit', 'staging_area') - files_names_in_repository_and_sub_dirs = get_files_names_of_repository_and_subs(repository) - all_files_in_staging_area_and_sub_dirs = get_files_of_dir_and_subdirs(staging_area_path) - for file in files_names_in_repository_and_sub_dirs: - if file not in all_files_in_staging_area_and_sub_dirs: - yield file +def get_new_files_added(cmp: dircmp[Union[str, bytes]], staging_area_path: Union[Path, str]) -> Iterator[str]: + new_files_added = cmp.right_only + start_path = staging_area_path + for f in new_files_added: + f_path = os.path.join(staging_area_path, f) + if os.path.isfile(f_path): + yield f + else: + yield from get_all_files_in_directory_and_subs(f_path, start_path) -def get_files_names_of_repository_and_subs(repository: Path): - for (root, dirs, files) in os.walk(repository, topdown=True): - if '.wit' not in Path(root).parts: - for file in files: - yield file +def get_changes_not_staged_for_commit( + repository: Union[Path, str], staging_area_path: Union[Path, str] +) -> Iterator[str]: + cmp = dircmp(repository, staging_area_path) + yield from get_changed_files(cmp, staging_area_path) + for common_dir in cmp.common_dirs: + path_in_repository = os.path.join(repository, common_dir) + path_in_staging_area = os.path.join(staging_area_path, common_dir) + yield from get_changes_not_staged_for_commit(path_in_repository, path_in_staging_area) -def get_files_of_dir_and_subdirs(file_path: str) -> Generator[Any, Any, None]: - for (root, dirs, files) in os.walk(file_path, topdown=True): - for file in files: - yield file +def get_untracked_files(repository: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: + cmp = dircmp(staging_area_path, repository, ignore=['.wit']) + yield from get_new_files_added(cmp, repository) + for common_dir in cmp.common_dirs: + path_in_repository = os.path.join(repository, common_dir) + path_in_staging_area = os.path.join(staging_area_path, common_dir) + yield from get_untracked_files(path_in_repository, path_in_staging_area) def checkout(commit_id: str) -> None: repository = get_directory_with_wit(Path.cwd()) + commit_path = os.path.join(repository, '.wit', 'images', commit_id) + staging_area_path = os.path.join(repository, '.wit', 'staging_area') + last_commit_id = get_parent_head(repository) + last_commit_path = os.path.join(repository, '.wit', 'images', last_commit_id) if not repository: raise WitError("<.wit> file not found") - references_file = repository.joinpath('.wit', 'references.txt') - if commit_id == 'master': - commit_id = get_master_commit_id(references_file) - last_commit_id = get_parent_head(repository) if ( - list(get_files_added_since_last_commit(last_commit_id, repository)) - or list(get_files_changed_since_last_commit(last_commit_id, repository)) - or list(get_files_in_staging_area_that_dont_match_original(repository)) + list(get_changes_to_be_committed(last_commit_path, staging_area_path)) + or list(get_changes_not_staged_for_commit(repository, staging_area_path)) ): raise FilesDoesntMatchError("There are files added or changed after last commit") - change_files_in_main_folder(repository, commit_id) + references_file = repository.joinpath('.wit', 'references.txt') + if commit_id == 'master': + commit_id = get_master_commit_id(references_file) + change_files_in_main_folder(commit_path, repository) change_head_in_references_file(commit_id, references_file) - change_staging_area_folder(repository, commit_id) + change_staging_area_folder(staging_area_path, commit_path) def change_head_in_references_file(commit_id: str, references_file: Path) -> None: with references_file.open() as file: - master_line = file.readlines()[1] - references_file.write_text(f'HEAD={commit_id}\n{master_line}') + content = file.readlines() + references_file.write_text(f'HEAD={commit_id}\n{content[1:]}') def get_master_commit_id(references_file: Path) -> str: @@ -254,39 +230,29 @@ def get_master_commit_id(references_file: Path) -> str: return commit_id -def change_files_in_main_folder(repository: Path, commit_id: str) -> None: - commit_path = os.path.join(repository, '.wit', 'images', commit_id) - # all_files_in_repository_and_sub_dirs = get_all_files_and_dirs_in_repository(repository) - all_files_in_repository_and_sub_dirs = [] - for (root, dirs, files) in os.walk(repository, topdown=True): - if '.wit' not in Path(root).parts: - for file in files: - all_files_in_repository_and_sub_dirs.append(os.path.join(root, file)) - # all_files_in_commit_and_sub_dirs = get_files_of_dir_and_subdirs(commit_path) # didn't work with the functions - all_files_in_commit_and_sub_dirs = [] - for (root, dirs, files) in os.walk(commit_path, topdown=True): - for file in files: - all_files_in_commit_and_sub_dirs.append(os.path.join(root, file)) - for c_file in all_files_in_commit_and_sub_dirs: - for r_file in all_files_in_repository_and_sub_dirs: - if Path(r_file).relative_to(repository) == Path(c_file).relative_to(commit_path): - shutil.copy2(c_file, r_file) +def change_files_in_main_folder(commit_path: str, repository: Path) -> None: + files_committed = get_all_files_in_directory_and_subs(commit_path, commit_path) + for committed_file in files_committed: + path_in_commit = os.path.join(commit_path, committed_file) + with open(path_in_commit, 'r') as committed_file_h: + content = committed_file_h.read() + path_in_repository = os.path.join(repository, committed_file) + with open(path_in_repository, "w") as original_file: + original_file.write(content) -def change_staging_area_folder(dir_with_wit: Path, commit_id: str): - staging_area_path = dir_with_wit.joinpath('.wit', 'staging_area') - commit_path = dir_with_wit.joinpath('.wit', 'images', commit_id) - for file_or_dir in staging_area_path.iterdir(): +def change_staging_area_folder(staging_area_path: str, commit_path: str): + for file_or_dir in Path(staging_area_path).iterdir(): if file_or_dir.is_file(): file_or_dir.unlink() else: shutil.rmtree(file_or_dir) - for file in commit_path.iterdir(): + for file in Path(commit_path).iterdir(): rel_path = Path(file).relative_to(commit_path) if file.is_file(): - shutil.copy2(file, staging_area_path.joinpath(rel_path)) + shutil.copy2(file, Path(staging_area_path).joinpath(rel_path)) else: - shutil.copytree(file, staging_area_path.joinpath(rel_path)) + shutil.copytree(file, Path(staging_area_path).joinpath(rel_path)) class WitError(Exception): @@ -298,7 +264,7 @@ class FilesDoesntMatchError(Exception): def is_command_correct(argv: list[str]) -> bool: - if argv[1] in ['init', 'status']: + if argv[1] in {'init', 'status'}: return len(argv) == 2 else: return len(argv) == 3 From 5140b924f320640951634bb93f20f34b6e7ab913 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Mon, 10 Jan 2022 09:52:55 +0200 Subject: [PATCH 19/73] finish branch --- branch.py | 221 ++++++++++++++++++++++------------------------------ checkout.py | 1 - wit.py | 5 +- 3 files changed, 97 insertions(+), 130 deletions(-) diff --git a/branch.py b/branch.py index bb702b3..cabb39e 100644 --- a/branch.py +++ b/branch.py @@ -1,12 +1,11 @@ -# upload 176 import datetime -import filecmp +from filecmp import dircmp import os from pathlib import Path import random import shutil import sys -from typing import Any, Generator, Optional, Union +from typing import Optional, Union, Iterator def init() -> None: @@ -66,13 +65,13 @@ def commit(message: str) -> None: def create_commit_folder(images_path: Path) -> str: - folder_name = create_commit_name() + folder_name = create_folder_name() path_of_new_folder = os.path.join(images_path, folder_name) os.mkdir(path_of_new_folder) return path_of_new_folder -def create_commit_name(): +def create_folder_name(): length = 20 chars = '1234567890abcdef' folder_name = ''.join(random.choices(chars, k=length)) @@ -112,14 +111,9 @@ def save_files(dir_with_wit: Path, path_of_new_folder: str) -> None: shutil.copytree(src, dst) -# בעת הרצת פקודת commit, יתעדכן (כרגיל) ה־HEAD כך שיצביע ל־commit החדש שנוצר. -# לפני עדכון ה־HEAD, בדקו אם ה־branch שנמצא במצב “פעיל” מצביע לאותו מקום שבו נמצא ה־HEAD. -# אם כן, עדכנו את references.txt כך שה־branch יצביע למספר ה־commit החדש שנוצר. - def write_references(commit_id: str, dir_with_wit: Path) -> None: wit_folder = dir_with_wit.joinpath('.wit') ref_file = wit_folder.joinpath('references.txt') - # new_branch_id = commit_id # new_master = commit_id activated_path = wit_folder.joinpath('activated.txt') activated_branch = activated_path.read_text() new_content = '='.join((activated_branch, commit_id)) @@ -127,9 +121,9 @@ def write_references(commit_id: str, dir_with_wit: Path) -> None: content = ref_file.read_text().split() head_line = content[0] head_id = head_line.split('=')[1] - branch_data = content[1:] + branches_data = content[1:] new_content = head_line - for line in branch_data: + for line in branches_data: name_and_id = line.split('=') branch_name = name_and_id[0] branch_id = name_and_id[1] @@ -145,118 +139,110 @@ def status() -> None: if not repository: raise WitError("<.wit> file not found") commit_id = get_parent_head(repository) - files_added_since_last_commit = get_files_added_since_last_commit(commit_id, repository) - files_changed_since_last_commit = get_files_changed_since_last_commit(commit_id, repository) - files_in_staging_area_that_dont_match_original = get_files_in_staging_area_that_dont_match_original(repository) - files_not_in_staging_area = get_files_not_in_staging_area(repository) - print( - f"Commit id: {commit_id}\n" - f"Changes to be committed: {(list(files_added_since_last_commit) + list(files_changed_since_last_commit))}\n" - f"Changes not staged for commit: {list(files_in_staging_area_that_dont_match_original)}\n" - f"Untracked files: {list(files_not_in_staging_area)}" - ) - - -def get_files_added_since_last_commit(commit_id: str, repository: Path) -> Generator[Any, Any, None]: - commit_path = os.path.join(repository, '.wit', 'images', commit_id) - staging_area_path = os.path.join(repository, '.wit', 'staging_area') - all_files_in_stagind_area_and_sub = get_files_of_dir_and_subdirs(staging_area_path) - all_files_in_commit_and_sub_dirs = get_files_of_dir_and_subdirs(commit_path) - for file in all_files_in_stagind_area_and_sub: - if file not in all_files_in_commit_and_sub_dirs: - yield file - - -def get_files_changed_since_last_commit(commit_id: str, repository: Path) -> Generator[str, Any, None]: commit_path = os.path.join(repository, '.wit', 'images', commit_id) staging_area_path = os.path.join(repository, '.wit', 'staging_area') - all_files_in_commit_and_sub = get_all_files_in_dir_and_subs(commit_path) - all_files_in_staging_area_and_sub = get_all_files_in_dir_and_subs(staging_area_path) - yield from get_names_of_changed_files( - all_files_in_commit_and_sub, all_files_in_staging_area_and_sub, commit_path, staging_area_path + changes_to_be_committed = list(get_changes_to_be_committed(commit_path, staging_area_path)) + changes_not_staged_for_commit = list(get_changes_not_staged_for_commit(repository, staging_area_path)) + untracked_files = list(get_untracked_files(repository, staging_area_path)) + print( + f"Commit id: {commit_id}\n" + f"Changes to be committed: {changes_to_be_committed}\n" + f"Changes not staged for commit: {changes_not_staged_for_commit}\n" + f"Untracked files: {untracked_files}" ) -def get_names_of_changed_files( - all_files_in_commit_and_sub: Generator[Union[bytes, str], Any, None], - all_files_in_staging_area_and_sub: Generator[Union[bytes, str], Any, None], - commit_path: Union[str, Path], - staging_area_path: Union[str, Path] -) -> Generator[str, Any, None]: - for s_file in all_files_in_staging_area_and_sub: - for c_file in all_files_in_commit_and_sub: - if Path(s_file).relative_to(staging_area_path) == Path(c_file).relative_to(commit_path): - if not filecmp.cmp(s_file, c_file): - yield Path(s_file).name +def get_all_files_in_directory_and_subs(directory: Union[Path, str], start_path: Union[Path, str]) -> Iterator[str]: + for (root, dirs, files) in os.walk(directory, topdown=True): + for file in files: + file_path = os.path.join(root, file) + rel = os.path.relpath(file_path, start=start_path) + yield rel -def get_all_files_in_dir_and_subs(commit_path: str) -> Generator[Union[bytes, str], Any, None]: - for (root, dirs, files) in os.walk(commit_path, topdown=True): - for file in files: - yield os.path.join(root, file) +def get_changes_to_be_committed(commit_path: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: + cmp = dircmp(commit_path, staging_area_path) + yield from get_new_and_changed_files(cmp, staging_area_path) + for d, d_cmp in cmp.subdirs.items(): + yield from get_new_and_changed_files(d_cmp, os.path.join(staging_area_path, d)) -def get_files_in_staging_area_that_dont_match_original(repository: Path) -> Generator[str, Any, None]: - staging_area_path = os.path.join(repository, '.wit', 'staging_area') - all_files_in_repository_and_sub_dirs = get_all_files_and_dirs_in_repository(repository) - all_files_in_staging_area_and_sub = get_all_files_in_dir_and_subs(staging_area_path) - yield from get_names_of_changed_files( - all_files_in_staging_area_and_sub, all_files_in_repository_and_sub_dirs, staging_area_path, repository - ) +def get_new_and_changed_files(cmp: dircmp[Union[str, bytes]], staging_area_path: Union[Path, str]) -> Iterator[str]: + yield from get_new_files_added(cmp, staging_area_path) + yield from get_changed_files(cmp, staging_area_path) -def get_all_files_and_dirs_in_repository(repository: Path) -> Generator[Union[bytes, str], Any, None]: - for (root, dirs, files) in os.walk(repository, topdown=True): - if '.wit' not in Path(root).parts: - for file in files: - yield os.path.join(root, file) +def get_changed_files(cmp: dircmp[Union[str, bytes]], staging_area_path) -> Iterator[str]: + diff_files = cmp.diff_files + start_path = os.path.join(get_directory_with_wit(Path.cwd()), '.wit', 'staging_area') + for diff in diff_files: + file_path = os.path.join(staging_area_path, diff) + rel = os.path.relpath(file_path, start=start_path) + yield rel -def get_files_not_in_staging_area(repository: Path) -> Generator[Any, Any, None]: - staging_area_path = os.path.join(repository, '.wit', 'staging_area') - files_names_in_repository_and_sub_dirs = get_files_names_of_repository_and_subs(repository) - all_files_in_staging_area_and_sub_dirs = get_files_of_dir_and_subdirs(staging_area_path) - for file in files_names_in_repository_and_sub_dirs: - if file not in all_files_in_staging_area_and_sub_dirs: - yield file +def get_new_files_added(cmp: dircmp[Union[str, bytes]], staging_area_path: Union[Path, str]) -> Iterator[str]: + new_files_added = cmp.right_only + start_path = staging_area_path + for f in new_files_added: + f_path = os.path.join(staging_area_path, f) + if os.path.isfile(f_path): + yield f + else: + yield from get_all_files_in_directory_and_subs(f_path, start_path) -def get_files_names_of_repository_and_subs(repository: Path): - for (root, dirs, files) in os.walk(repository, topdown=True): - if '.wit' not in Path(root).parts: - for file in files: - yield file +def get_changes_not_staged_for_commit( + repository: Union[Path, str], staging_area_path: Union[Path, str] +) -> Iterator[str]: + cmp = dircmp(repository, staging_area_path) + yield from get_changed_files(cmp, staging_area_path) + for common_dir in cmp.common_dirs: + path_in_repository = os.path.join(repository, common_dir) + path_in_staging_area = os.path.join(staging_area_path, common_dir) + yield from get_changes_not_staged_for_commit(path_in_repository, path_in_staging_area) -def get_files_of_dir_and_subdirs(file_path: str) -> Generator[Any, Any, None]: - for (root, dirs, files) in os.walk(file_path, topdown=True): - for file in files: - yield file +def get_untracked_files(repository: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: + cmp = dircmp(staging_area_path, repository, ignore=['.wit']) + yield from get_new_files_added(cmp, repository) + for common_dir in cmp.common_dirs: + path_in_repository = os.path.join(repository, common_dir) + path_in_staging_area = os.path.join(staging_area_path, common_dir) + yield from get_untracked_files(path_in_repository, path_in_staging_area) def checkout(commit_id_or_branch: str) -> None: repository = get_directory_with_wit(Path.cwd()) + commit_path = os.path.join(repository, '.wit', 'images', commit_id_or_branch) + staging_area_path = os.path.join(repository, '.wit', 'staging_area') + last_commit_id = get_parent_head(repository) + last_commit_path = os.path.join(repository, '.wit', 'images', last_commit_id) if not repository: raise WitError("<.wit> file not found") - references_file = repository.joinpath('.wit', 'references.txt') - last_commit_id = get_parent_head(repository) if ( - list(get_files_added_since_last_commit(last_commit_id, repository)) - or list(get_files_changed_since_last_commit(last_commit_id, repository)) - or list(get_files_in_staging_area_that_dont_match_original(repository)) + list(get_changes_to_be_committed(last_commit_path, staging_area_path)) + or list(get_changes_not_staged_for_commit(repository, staging_area_path)) ): raise FilesDoesntMatchError("There are files added or changed after last commit") + references_file = repository.joinpath('.wit', 'references.txt') commit_id = get_commit_id_of_branch(commit_id_or_branch, references_file) - print(commit_id) - change_files_in_main_folder(repository, commit_id) + change_files_in_main_folder(commit_path, repository) change_head_in_references_file(commit_id, references_file) - change_staging_area_folder(repository, commit_id) - write_activated(commit_id, commit_id_or_branch, repository) # + change_staging_area_folder(staging_area_path, commit_path) + write_activated(commit_id_or_branch, repository) -def write_activated(commit_id: str, commit_id_or_branch: str, repository: Path) -> None: +def write_activated(commit_id_or_branch: str, repository: Path) -> None: activated_path = repository.joinpath('.wit', 'activated.txt') - Path(activated_path).write_text(commit_id_or_branch) + activated_path.write_text(commit_id_or_branch) + + +def change_head_in_references_file(commit_id: str, references_file: Path) -> None: + with references_file.open() as file: + branches = file.readlines()[1:] + branches_txt = ''.join(branches) + references_file.write_text(f'HEAD={commit_id}\n{branches_txt}') def get_commit_id_of_branch(commit_id_or_branch: str, references_file: Path) -> str: @@ -272,54 +258,37 @@ def get_commit_id_of_branch(commit_id_or_branch: str, references_file: Path) -> return commit_id_or_branch -def change_head_in_references_file(commit_id: str, references_file: Path) -> None: - with references_file.open() as file: - branches = file.readlines()[1:] - branches_txt = ''.join(branches) - references_file.write_text(f'HEAD={commit_id}\n{branches_txt}') - - def get_master_commit_id(references_file: Path) -> str: with references_file.open() as file: references_content = file.readlines() - master_line = references_content[1].split('=') + master_line = references_content[-1].split('=') commit_id = master_line[-1].strip() return commit_id -def change_files_in_main_folder(repository: Path, commit_id: str) -> None: - commit_path = os.path.join(repository, '.wit', 'images', commit_id) - # all_files_in_repository_and_sub_dirs = get_all_files_and_dirs_in_repository(repository) - all_files_in_repository_and_sub_dirs = [] - for (root, dirs, files) in os.walk(repository, topdown=True): - if '.wit' not in Path(root).parts: - for file in files: - all_files_in_repository_and_sub_dirs.append(os.path.join(root, file)) - # all_files_in_commit_and_sub_dirs = get_files_of_dir_and_subdirs(commit_path) # didn't work with the functions - all_files_in_commit_and_sub_dirs = [] - for (root, dirs, files) in os.walk(commit_path, topdown=True): - for file in files: - all_files_in_commit_and_sub_dirs.append(os.path.join(root, file)) - for c_file in all_files_in_commit_and_sub_dirs: - for r_file in all_files_in_repository_and_sub_dirs: - if Path(r_file).relative_to(repository) == Path(c_file).relative_to(commit_path): - shutil.copy2(c_file, r_file) +def change_files_in_main_folder(commit_path: str, repository: Path) -> None: + files_committed = get_all_files_in_directory_and_subs(commit_path, commit_path) + for committed_file in files_committed: + path_in_commit = os.path.join(commit_path, committed_file) + with open(path_in_commit, 'r') as committed_file_h: + content = committed_file_h.read() + path_in_repository = os.path.join(repository, committed_file) + with open(path_in_repository, "w") as original_file: + original_file.write(content) -def change_staging_area_folder(dir_with_wit: Path, commit_id: str): - staging_area_path = dir_with_wit.joinpath('.wit', 'staging_area') - commit_path = dir_with_wit.joinpath('.wit', 'images', commit_id) - for file_or_dir in staging_area_path.iterdir(): +def change_staging_area_folder(staging_area_path: str, commit_path: str): + for file_or_dir in Path(staging_area_path).iterdir(): if file_or_dir.is_file(): file_or_dir.unlink() else: shutil.rmtree(file_or_dir) - for file in commit_path.iterdir(): + for file in Path(commit_path).iterdir(): rel_path = Path(file).relative_to(commit_path) if file.is_file(): - shutil.copy2(file, staging_area_path.joinpath(rel_path)) + shutil.copy2(file, Path(staging_area_path).joinpath(rel_path)) else: - shutil.copytree(file, staging_area_path.joinpath(rel_path)) + shutil.copytree(file, Path(staging_area_path).joinpath(rel_path)) def branch(name: str) -> None: @@ -341,7 +310,7 @@ class FilesDoesntMatchError(Exception): def is_command_correct(argv: list[str]) -> bool: - if argv[1] in ['init', 'status']: + if argv[1] in {'init', 'status'}: return len(argv) == 2 else: return len(argv) == 3 diff --git a/checkout.py b/checkout.py index 52f833f..40eeb0a 100644 --- a/checkout.py +++ b/checkout.py @@ -159,7 +159,6 @@ def get_changed_files(cmp: dircmp[Union[str, bytes]], staging_area_path) -> Iter start_path = os.path.join(get_directory_with_wit(Path.cwd()), '.wit', 'staging_area') for diff in diff_files: file_path = os.path.join(staging_area_path, diff) - rel = os.path.relpath(file_path, start=start_path) yield rel diff --git a/wit.py b/wit.py index bb702b3..526133d 100644 --- a/wit.py +++ b/wit.py @@ -1,4 +1,3 @@ -# upload 176 import datetime import filecmp import os @@ -127,9 +126,9 @@ def write_references(commit_id: str, dir_with_wit: Path) -> None: content = ref_file.read_text().split() head_line = content[0] head_id = head_line.split('=')[1] - branch_data = content[1:] + branches_data = content[1:] new_content = head_line - for line in branch_data: + for line in branches_data: name_and_id = line.split('=') branch_name = name_and_id[0] branch_id = name_and_id[1] From b79d2a054505c8288c2bde0d955b8cf402a349a2 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Mon, 10 Jan 2022 15:17:41 +0200 Subject: [PATCH 20/73] finish branch --- branch.py | 64 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/branch.py b/branch.py index cabb39e..cb357af 100644 --- a/branch.py +++ b/branch.py @@ -60,7 +60,6 @@ def commit(message: str) -> None: create_commit_txt_file(dir_with_wit, images_path, path_of_new_folder, message) save_files(dir_with_wit, path_of_new_folder) commit_id = os.path.basename(path_of_new_folder) - write_references(commit_id, dir_with_wit) @@ -116,20 +115,20 @@ def write_references(commit_id: str, dir_with_wit: Path) -> None: ref_file = wit_folder.joinpath('references.txt') activated_path = wit_folder.joinpath('activated.txt') activated_branch = activated_path.read_text() - new_content = '='.join((activated_branch, commit_id)) + new_content = '='.join((activated_branch, commit_id)) # ??? if ref_file.exists(): - content = ref_file.read_text().split() - head_line = content[0] - head_id = head_line.split('=')[1] - branches_data = content[1:] - new_content = head_line + with open(ref_file, "r") as references_file: + data = references_file.readlines() + current_head_id = data[0].split("=")[1].strip() + branches_data = data[1:] + new_content = "" for line in branches_data: - name_and_id = line.split('=') - branch_name = name_and_id[0] - branch_id = name_and_id[1] + branch_name = line.split("=")[0] + branch_id = line.split("=")[1].strip() if branch_name == activated_branch: - if branch_id == head_id: - line = '='.join((branch_name, commit_id)) + activated_id = branch_id + if activated_id == current_head_id: + line = "=".join((branch_name, commit_id)) new_content += line ref_file.write_text(f'HEAD={commit_id}\n{new_content}') @@ -214,7 +213,6 @@ def get_untracked_files(repository: Union[Path, str], staging_area_path: Union[P def checkout(commit_id_or_branch: str) -> None: repository = get_directory_with_wit(Path.cwd()) - commit_path = os.path.join(repository, '.wit', 'images', commit_id_or_branch) staging_area_path = os.path.join(repository, '.wit', 'staging_area') last_commit_id = get_parent_head(repository) last_commit_path = os.path.join(repository, '.wit', 'images', last_commit_id) @@ -227,10 +225,14 @@ def checkout(commit_id_or_branch: str) -> None: raise FilesDoesntMatchError("There are files added or changed after last commit") references_file = repository.joinpath('.wit', 'references.txt') commit_id = get_commit_id_of_branch(commit_id_or_branch, references_file) + if commit_id != commit_id_or_branch: + write_activated(commit_id_or_branch, repository) + commit_path = os.path.join(repository, '.wit', 'images', commit_id) change_files_in_main_folder(commit_path, repository) change_head_in_references_file(commit_id, references_file) change_staging_area_folder(staging_area_path, commit_path) - write_activated(commit_id_or_branch, repository) + if commit_id != commit_id_or_branch: + write_activated(commit_id_or_branch, repository) def write_activated(commit_id_or_branch: str, repository: Path) -> None: @@ -252,20 +254,12 @@ def get_commit_id_of_branch(commit_id_or_branch: str, references_file: Path) -> for branch_line in branches_data: name_and_id = branch_line.split('=') branch_name = name_and_id[0] - branch_id = name_and_id[1] + branch_id = name_and_id[1].strip() if branch_name == commit_id_or_branch: return branch_id return commit_id_or_branch -def get_master_commit_id(references_file: Path) -> str: - with references_file.open() as file: - references_content = file.readlines() - master_line = references_content[-1].split('=') - commit_id = master_line[-1].strip() - return commit_id - - def change_files_in_main_folder(commit_path: str, repository: Path) -> None: files_committed = get_all_files_in_directory_and_subs(commit_path, commit_path) for committed_file in files_committed: @@ -277,6 +271,30 @@ def change_files_in_main_folder(commit_path: str, repository: Path) -> None: original_file.write(content) +# בהתחלה עשיתי את הפונקציה כמו שמופיע למטה בהמשך ההערה, והערת לי שיש דרך הרבה יותר פשוטה להעתיק תיקיה +# ושיש פונקציה קיימת שיכולה לעזור לי, ולכן שינתי את הפונקציה כמו שמופיע למעלה. +# אבל ככה יש בעיה במקרה והתווסף קובץ חדש, ורוצים לעשות checkout לקומיט מלפני יצירת הקובץ, +# ואז בעצם בעידכון הקבצים בתיקיה צריך למחוק את הקובץ לחלוטין. +# לא הצלחתי לחשוב על פתרון פשוט לזה חוץ צלהשתמש בדרך המסורבלת יותר שאיתה התחלתי. +# אשמח לתובנות. +# +# def change_files_in_main_folder(repository: Path, commit_id: str) -> None: +# commit_path = os.path.join(repository, '.wit', 'images', commit_id) +# all_files_in_repository_and_sub_dirs = [] +# for (root, dirs, files) in os.walk(repository, topdown=True): +# if '.wit' not in Path(root).parts: +# for file in files: +# all_files_in_repository_and_sub_dirs.append(os.path.join(root, file)) +# all_files_in_commit_and_sub_dirs = [] +# for (root, dirs, files) in os.walk(commit_path, topdown=True): +# for file in files: +# all_files_in_commit_and_sub_dirs.append(os.path.join(root, file)) +# for c_file in all_files_in_commit_and_sub_dirs: +# for r_file in all_files_in_repository_and_sub_dirs: +# if Path(r_file).relative_to(repository) == Path(c_file).relative_to(commit_path): +# shutil.copy2(c_file, r_file) + + def change_staging_area_folder(staging_area_path: str, commit_path: str): for file_or_dir in Path(staging_area_path).iterdir(): if file_or_dir.is_file(): From e51e079caa1342fe468a1df73ef44453ad26f529 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Mon, 10 Jan 2022 22:59:59 +0200 Subject: [PATCH 21/73] All wit files after changes --- .gitignore | 2 + add.py | 57 ++---- branch.py | 364 +------------------------------------ checkout.py | 299 ++++++------------------------ commit.py | 122 ++++--------- errors.py | 6 + init.py | 18 +- status.py | 161 ++-------------- wit.py | 347 +---------------------------------- wit_checks.py | 315 -------------------------------- wit_exercises/add1.py | 74 ++++++++ wit_exercises/checkout1.py | 300 ++++++++++++++++++++++++++++++ wit_exercises/commit1.py | 140 ++++++++++++++ wit_exercises/init1.py | 22 +++ wit_exercises/status1.py | 225 +++++++++++++++++++++++ 15 files changed, 897 insertions(+), 1555 deletions(-) create mode 100644 errors.py delete mode 100644 wit_checks.py create mode 100644 wit_exercises/add1.py create mode 100644 wit_exercises/checkout1.py create mode 100644 wit_exercises/commit1.py create mode 100644 wit_exercises/init1.py create mode 100644 wit_exercises/status1.py diff --git a/.gitignore b/.gitignore index f92b431..46b6905 100644 --- a/.gitignore +++ b/.gitignore @@ -129,3 +129,5 @@ dmypy.json .pyre/ .wit .idea +__pycache__ +wit_exercises \ No newline at end of file diff --git a/add.py b/add.py index a75d30b..0f42ed0 100644 --- a/add.py +++ b/add.py @@ -1,33 +1,24 @@ -# upload 171 +from errors import WitError import os from pathlib import Path import shutil -import sys -from typing import Union - - -def init() -> None: - cwd = os.getcwd() - wit_path = os.path.join(cwd, '.wit') - os.mkdir(wit_path) - os.mkdir(os.path.join(wit_path, 'images')) - os.mkdir(os.path.join(wit_path, 'staging_area')) +from typing import Optional def add(path_to_add: str) -> None: - file = Path(os.path.abspath(path_to_add)) - directory_with_wit = get_directory_with_wit(file) - if not directory_with_wit: + file_to_add = Path(os.path.abspath(path_to_add)) + repository = get_directory_with_wit(file_to_add) + if not repository: raise WitError("<.wit> file not found") - destination = directory_with_wit.joinpath('.wit', 'staging_area') - directories_to_copy = file.relative_to(directory_with_wit).parts[:-1] + destination = repository.joinpath('.wit', 'staging_area') + directories_to_copy = file_to_add.relative_to(repository).parts[:-1] for dir_name in directories_to_copy: dirs = os.listdir(destination) destination = destination.joinpath(dir_name) if dir_name not in dirs: destination.mkdir() - save_the_copy(destination, file) + save_the_copy(destination, file_to_add) def save_the_copy(destination: Path, file: Path) -> None: @@ -40,35 +31,9 @@ def save_the_copy(destination: Path, file: Path) -> None: shutil.copytree(file, destination_of_folder_if_doesnt_exists) -def get_directory_with_wit(file: Path) -> Union[Path, bool]: +def get_directory_with_wit(file: Path) -> Optional[Path]: for parent in file.parents: dir_lst = os.listdir(parent) - if '.wit' in dir_lst: # and os.path.isdir(os.path.abspath('.wit')): > never True. also with iterdir. why? + if '.wit' in dir_lst: return parent - return False - - -class WitError(Exception): - pass - - -def is_init_status_command_correct(argv: list[str]) -> bool: - return len(argv) == 2 - - -def is_add_or_commit_command_correct(argv: list[str]) -> bool: - return len(argv) == 3 - - -if sys.argv[1] == 'init': - if is_init_status_command_correct(sys.argv): - init() - else: - print(fr"Usage: python {sys.argv[0]} init") - - -elif sys.argv[1] == 'add': - if is_add_or_commit_command_correct(sys.argv): - add(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} add ") + return None diff --git a/branch.py b/branch.py index cb357af..5b85721 100644 --- a/branch.py +++ b/branch.py @@ -1,312 +1,8 @@ -import datetime -from filecmp import dircmp -import os -from pathlib import Path -import random -import shutil -import sys -from typing import Optional, Union, Iterator - - -def init() -> None: - cwd = os.getcwd() - wit_path = os.path.join(cwd, '.wit') - os.mkdir(wit_path) - os.mkdir(os.path.join(wit_path, 'images')) - os.mkdir(os.path.join(wit_path, 'staging_area')) - activated_path = os.path.join(wit_path, 'activated.txt') - Path(activated_path).write_text('master') - - -def add(path_to_add: str) -> None: - file_to_add = Path(os.path.abspath(path_to_add)) - repository = get_directory_with_wit(file_to_add) - if not repository: - raise WitError("<.wit> file not found") - destination = repository.joinpath('.wit', 'staging_area') - directories_to_copy = file_to_add.relative_to(repository).parts[:-1] - for dir_name in directories_to_copy: - dirs = os.listdir(destination) - destination = destination.joinpath(dir_name) - if dir_name not in dirs: - destination.mkdir() - save_the_copy(destination, file_to_add) - - -def save_the_copy(destination: Path, file: Path) -> None: - if file.is_file(): - shutil.copy2(file, destination) - else: - destination_of_folder_if_doesnt_exists = destination.joinpath(file.name) - if destination_of_folder_if_doesnt_exists.exists(): - shutil.rmtree(destination_of_folder_if_doesnt_exists) - shutil.copytree(file, destination_of_folder_if_doesnt_exists) - - -def get_directory_with_wit(file: Path) -> Optional[Path]: - for parent in file.parents: - dir_lst = os.listdir(parent) - if '.wit' in dir_lst: - return parent - return None - - -def commit(message: str) -> None: - dir_with_wit = get_directory_with_wit(Path.cwd()) - if not dir_with_wit: - raise WitError("<.wit> file not found") - images_path = dir_with_wit.joinpath('.wit', 'images') - path_of_new_folder = create_commit_folder(images_path) - create_commit_txt_file(dir_with_wit, images_path, path_of_new_folder, message) - save_files(dir_with_wit, path_of_new_folder) - commit_id = os.path.basename(path_of_new_folder) - write_references(commit_id, dir_with_wit) - - -def create_commit_folder(images_path: Path) -> str: - folder_name = create_folder_name() - path_of_new_folder = os.path.join(images_path, folder_name) - os.mkdir(path_of_new_folder) - return path_of_new_folder - - -def create_folder_name(): - length = 20 - chars = '1234567890abcdef' - folder_name = ''.join(random.choices(chars, k=length)) - return folder_name - - -def create_commit_txt_file(dir_with_wit: Path, images_path: Path, path_of_new_folder: str, message: str) -> None: - parent_head = get_parent_head(dir_with_wit) - txt_file = images_path.joinpath(Path(path_of_new_folder).name + '.txt') - txt_file.write_text( - f'parent = {parent_head if parent_head else None}\n' - f'date = {datetime.datetime.now().strftime("%c")}\n' - f'message = {message}' - ) - - -def get_parent_head(dir_with_wit: Path) -> str: - wit_folder = dir_with_wit.joinpath('.wit') - references_file = wit_folder.joinpath('references.txt') - if references_file.exists(): - ref_path = wit_folder.joinpath('references.txt') - with ref_path.open() as f_h: - references_content = f_h.readlines() - head_line = references_content[0].split('=') - return head_line[1].strip() - return '' - - -def save_files(dir_with_wit: Path, path_of_new_folder: str) -> None: - staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') - for item in os.listdir(staging_area_path): - src = os.path.join(staging_area_path, item) - dst = os.path.join(path_of_new_folder, item) - if os.path.isfile(src): - shutil.copy2(src, dst) - else: - shutil.copytree(src, dst) - - -def write_references(commit_id: str, dir_with_wit: Path) -> None: - wit_folder = dir_with_wit.joinpath('.wit') - ref_file = wit_folder.joinpath('references.txt') - activated_path = wit_folder.joinpath('activated.txt') - activated_branch = activated_path.read_text() - new_content = '='.join((activated_branch, commit_id)) # ??? - if ref_file.exists(): - with open(ref_file, "r") as references_file: - data = references_file.readlines() - current_head_id = data[0].split("=")[1].strip() - branches_data = data[1:] - new_content = "" - for line in branches_data: - branch_name = line.split("=")[0] - branch_id = line.split("=")[1].strip() - if branch_name == activated_branch: - activated_id = branch_id - if activated_id == current_head_id: - line = "=".join((branch_name, commit_id)) - new_content += line - ref_file.write_text(f'HEAD={commit_id}\n{new_content}') - - -def status() -> None: - repository = get_directory_with_wit(Path.cwd()) - if not repository: - raise WitError("<.wit> file not found") - commit_id = get_parent_head(repository) - commit_path = os.path.join(repository, '.wit', 'images', commit_id) - staging_area_path = os.path.join(repository, '.wit', 'staging_area') - changes_to_be_committed = list(get_changes_to_be_committed(commit_path, staging_area_path)) - changes_not_staged_for_commit = list(get_changes_not_staged_for_commit(repository, staging_area_path)) - untracked_files = list(get_untracked_files(repository, staging_area_path)) - print( - f"Commit id: {commit_id}\n" - f"Changes to be committed: {changes_to_be_committed}\n" - f"Changes not staged for commit: {changes_not_staged_for_commit}\n" - f"Untracked files: {untracked_files}" - ) - - -def get_all_files_in_directory_and_subs(directory: Union[Path, str], start_path: Union[Path, str]) -> Iterator[str]: - for (root, dirs, files) in os.walk(directory, topdown=True): - for file in files: - file_path = os.path.join(root, file) - rel = os.path.relpath(file_path, start=start_path) - yield rel - - -def get_changes_to_be_committed(commit_path: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: - cmp = dircmp(commit_path, staging_area_path) - yield from get_new_and_changed_files(cmp, staging_area_path) - for d, d_cmp in cmp.subdirs.items(): - yield from get_new_and_changed_files(d_cmp, os.path.join(staging_area_path, d)) - - -def get_new_and_changed_files(cmp: dircmp[Union[str, bytes]], staging_area_path: Union[Path, str]) -> Iterator[str]: - yield from get_new_files_added(cmp, staging_area_path) - yield from get_changed_files(cmp, staging_area_path) - +from add import get_directory_with_wit +from commit import get_parent_head +from errors import WitError -def get_changed_files(cmp: dircmp[Union[str, bytes]], staging_area_path) -> Iterator[str]: - diff_files = cmp.diff_files - start_path = os.path.join(get_directory_with_wit(Path.cwd()), '.wit', 'staging_area') - for diff in diff_files: - file_path = os.path.join(staging_area_path, diff) - rel = os.path.relpath(file_path, start=start_path) - yield rel - - -def get_new_files_added(cmp: dircmp[Union[str, bytes]], staging_area_path: Union[Path, str]) -> Iterator[str]: - new_files_added = cmp.right_only - start_path = staging_area_path - for f in new_files_added: - f_path = os.path.join(staging_area_path, f) - if os.path.isfile(f_path): - yield f - else: - yield from get_all_files_in_directory_and_subs(f_path, start_path) - - -def get_changes_not_staged_for_commit( - repository: Union[Path, str], staging_area_path: Union[Path, str] -) -> Iterator[str]: - cmp = dircmp(repository, staging_area_path) - yield from get_changed_files(cmp, staging_area_path) - for common_dir in cmp.common_dirs: - path_in_repository = os.path.join(repository, common_dir) - path_in_staging_area = os.path.join(staging_area_path, common_dir) - yield from get_changes_not_staged_for_commit(path_in_repository, path_in_staging_area) - - -def get_untracked_files(repository: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: - cmp = dircmp(staging_area_path, repository, ignore=['.wit']) - yield from get_new_files_added(cmp, repository) - for common_dir in cmp.common_dirs: - path_in_repository = os.path.join(repository, common_dir) - path_in_staging_area = os.path.join(staging_area_path, common_dir) - yield from get_untracked_files(path_in_repository, path_in_staging_area) - - -def checkout(commit_id_or_branch: str) -> None: - repository = get_directory_with_wit(Path.cwd()) - staging_area_path = os.path.join(repository, '.wit', 'staging_area') - last_commit_id = get_parent_head(repository) - last_commit_path = os.path.join(repository, '.wit', 'images', last_commit_id) - if not repository: - raise WitError("<.wit> file not found") - if ( - list(get_changes_to_be_committed(last_commit_path, staging_area_path)) - or list(get_changes_not_staged_for_commit(repository, staging_area_path)) - ): - raise FilesDoesntMatchError("There are files added or changed after last commit") - references_file = repository.joinpath('.wit', 'references.txt') - commit_id = get_commit_id_of_branch(commit_id_or_branch, references_file) - if commit_id != commit_id_or_branch: - write_activated(commit_id_or_branch, repository) - commit_path = os.path.join(repository, '.wit', 'images', commit_id) - change_files_in_main_folder(commit_path, repository) - change_head_in_references_file(commit_id, references_file) - change_staging_area_folder(staging_area_path, commit_path) - if commit_id != commit_id_or_branch: - write_activated(commit_id_or_branch, repository) - - -def write_activated(commit_id_or_branch: str, repository: Path) -> None: - activated_path = repository.joinpath('.wit', 'activated.txt') - activated_path.write_text(commit_id_or_branch) - - -def change_head_in_references_file(commit_id: str, references_file: Path) -> None: - with references_file.open() as file: - branches = file.readlines()[1:] - branches_txt = ''.join(branches) - references_file.write_text(f'HEAD={commit_id}\n{branches_txt}') - - -def get_commit_id_of_branch(commit_id_or_branch: str, references_file: Path) -> str: - with references_file.open() as file: - references_content = file.readlines() - branches_data = references_content[1:] - for branch_line in branches_data: - name_and_id = branch_line.split('=') - branch_name = name_and_id[0] - branch_id = name_and_id[1].strip() - if branch_name == commit_id_or_branch: - return branch_id - return commit_id_or_branch - - -def change_files_in_main_folder(commit_path: str, repository: Path) -> None: - files_committed = get_all_files_in_directory_and_subs(commit_path, commit_path) - for committed_file in files_committed: - path_in_commit = os.path.join(commit_path, committed_file) - with open(path_in_commit, 'r') as committed_file_h: - content = committed_file_h.read() - path_in_repository = os.path.join(repository, committed_file) - with open(path_in_repository, "w") as original_file: - original_file.write(content) - - -# בהתחלה עשיתי את הפונקציה כמו שמופיע למטה בהמשך ההערה, והערת לי שיש דרך הרבה יותר פשוטה להעתיק תיקיה -# ושיש פונקציה קיימת שיכולה לעזור לי, ולכן שינתי את הפונקציה כמו שמופיע למעלה. -# אבל ככה יש בעיה במקרה והתווסף קובץ חדש, ורוצים לעשות checkout לקומיט מלפני יצירת הקובץ, -# ואז בעצם בעידכון הקבצים בתיקיה צריך למחוק את הקובץ לחלוטין. -# לא הצלחתי לחשוב על פתרון פשוט לזה חוץ צלהשתמש בדרך המסורבלת יותר שאיתה התחלתי. -# אשמח לתובנות. -# -# def change_files_in_main_folder(repository: Path, commit_id: str) -> None: -# commit_path = os.path.join(repository, '.wit', 'images', commit_id) -# all_files_in_repository_and_sub_dirs = [] -# for (root, dirs, files) in os.walk(repository, topdown=True): -# if '.wit' not in Path(root).parts: -# for file in files: -# all_files_in_repository_and_sub_dirs.append(os.path.join(root, file)) -# all_files_in_commit_and_sub_dirs = [] -# for (root, dirs, files) in os.walk(commit_path, topdown=True): -# for file in files: -# all_files_in_commit_and_sub_dirs.append(os.path.join(root, file)) -# for c_file in all_files_in_commit_and_sub_dirs: -# for r_file in all_files_in_repository_and_sub_dirs: -# if Path(r_file).relative_to(repository) == Path(c_file).relative_to(commit_path): -# shutil.copy2(c_file, r_file) - - -def change_staging_area_folder(staging_area_path: str, commit_path: str): - for file_or_dir in Path(staging_area_path).iterdir(): - if file_or_dir.is_file(): - file_or_dir.unlink() - else: - shutil.rmtree(file_or_dir) - for file in Path(commit_path).iterdir(): - rel_path = Path(file).relative_to(commit_path) - if file.is_file(): - shutil.copy2(file, Path(staging_area_path).joinpath(rel_path)) - else: - shutil.copytree(file, Path(staging_area_path).joinpath(rel_path)) +from pathlib import Path def branch(name: str) -> None: @@ -317,55 +13,3 @@ def branch(name: str) -> None: commit_id = get_parent_head(repository) with references_file.open('a') as ref_file: ref_file.write(f'\n{name}={commit_id}') - - -class WitError(Exception): - pass - - -class FilesDoesntMatchError(Exception): - pass - - -def is_command_correct(argv: list[str]) -> bool: - if argv[1] in {'init', 'status'}: - return len(argv) == 2 - else: - return len(argv) == 3 - - -if sys.argv[1] == 'init': - if is_command_correct(sys.argv): - init() - else: - print(fr"Usage: python {sys.argv[0]} init") - -elif sys.argv[1] == 'add': - if is_command_correct(sys.argv): - add(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} add ") - -elif sys.argv[1] == 'commit': - if is_command_correct(sys.argv): - commit(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} commit MESSAGE") - -elif sys.argv[1] == 'status': - if is_command_correct(sys.argv): - status() - else: - print(fr"Usage: python {sys.argv[0]} status") - -elif sys.argv[1] == 'checkout': - if is_command_correct(sys.argv): - checkout(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} checkout ") - -elif sys.argv[1] == 'branch': - if is_command_correct(sys.argv): - branch(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} branch ") diff --git a/checkout.py b/checkout.py index 40eeb0a..5122728 100644 --- a/checkout.py +++ b/checkout.py @@ -1,202 +1,16 @@ -# upload 174 -import datetime -from filecmp import dircmp +from add import get_directory_with_wit +from commit import get_parent_head +from errors import FilesDoesntMatchError, WitError + import os from pathlib import Path -import random import shutil -import sys -from typing import Optional, Union, Iterator - - -def init() -> None: - cwd = os.getcwd() - wit_path = os.path.join(cwd, '.wit') - os.mkdir(wit_path) - os.mkdir(os.path.join(wit_path, 'images')) - os.mkdir(os.path.join(wit_path, 'staging_area')) - - -def add(path_to_add: str) -> None: - file = Path(os.path.abspath(path_to_add)) - directory_with_wit = get_directory_with_wit(file) - if not directory_with_wit: - raise WitError("<.wit> file not found") - destination = directory_with_wit.joinpath('.wit', 'staging_area') - directories_to_copy = file.relative_to(directory_with_wit).parts[:-1] - for dir_name in directories_to_copy: - dirs = os.listdir(destination) - destination = destination.joinpath(dir_name) - if dir_name not in dirs: - destination.mkdir() - save_the_copy(destination, file) - - -def save_the_copy(destination: Path, file: Path) -> None: - if file.is_file(): - shutil.copy2(file, destination) - else: - destination_of_folder_if_doesnt_exists = destination.joinpath(file.name) - if destination_of_folder_if_doesnt_exists.exists(): - shutil.rmtree(destination_of_folder_if_doesnt_exists) - shutil.copytree(file, destination_of_folder_if_doesnt_exists) - - -def get_directory_with_wit(file: Path) -> Optional[Path]: - parents = file.parents - for p in parents: - wit = Path.joinpath(p, '.wit') - if wit.is_dir(): - return p - return None - - -def commit(message: str) -> None: - dir_with_wit = get_directory_with_wit(Path.cwd()) - if not dir_with_wit: - raise WitError("<.wit> file not found") - images_path = dir_with_wit.joinpath('.wit', 'images') - path_of_new_folder = create_commit_folder(images_path) - create_commit_txt_file(dir_with_wit, images_path, path_of_new_folder, message) - save_files(dir_with_wit, path_of_new_folder) - commit_id = os.path.basename(path_of_new_folder) - write_references(commit_id, dir_with_wit) - - -def create_commit_folder(images_path: Path) -> str: - folder_name = create_folder_name() - path_of_new_folder = os.path.join(images_path, folder_name) - os.mkdir(path_of_new_folder) - return path_of_new_folder - - -def create_folder_name(): - length = 20 - chars = '1234567890abcdef' - folder_name = ''.join(random.choice(chars) for _ in range(length)) - return folder_name +from status import get_changes_to_be_committed, get_changes_not_staged_for_commit, get_all_files_in_directory_and_subs -def create_commit_txt_file(dir_with_wit: Path, images_path: Path, path_of_new_folder: str, message: str) -> None: - parent_head = get_parent_head(dir_with_wit) - txt_file = images_path.joinpath(Path(path_of_new_folder).name + '.txt') - txt_file.write_text( - f'parent = {parent_head if parent_head else None}\n' - f'date = {datetime.datetime.now().strftime("%c")}\n' - f'message = {message}' - ) - -def get_parent_head(dir_with_wit: Path) -> str: - wit_folder = dir_with_wit.joinpath('.wit') - references_file = wit_folder.joinpath('references.txt') - if references_file.exists(): - ref_path = wit_folder.joinpath('references.txt') - with ref_path.open() as f_h: - references_content = f_h.readlines() - head_line = references_content[0].split('=') - return head_line[1].strip() - return '' - - -def save_files(dir_with_wit: Path, path_of_new_folder: str) -> None: - staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') - for item in os.listdir(staging_area_path): - src = os.path.join(staging_area_path, item) - dst = os.path.join(path_of_new_folder, item) - if os.path.isfile(src): - shutil.copy2(src, dst) - else: - shutil.copytree(src, dst) - - -def write_references(commit_id: str, dir_with_wit: Path) -> None: - wit_folder = dir_with_wit.joinpath('.wit') - ref_file = wit_folder.joinpath('references.txt') - ref_file.write_text(f'HEAD={commit_id}\nMASTER={commit_id}\n') - - -def status() -> None: +def checkout(commit_id_or_branch: str) -> None: repository = get_directory_with_wit(Path.cwd()) - if not repository: - raise WitError("<.wit> file not found") - commit_id = get_parent_head(repository) - commit_path = os.path.join(repository, '.wit', 'images', commit_id) - staging_area_path = os.path.join(repository, '.wit', 'staging_area') - changes_to_be_committed = list(get_changes_to_be_committed(commit_path, staging_area_path)) - changes_not_staged_for_commit = list(get_changes_not_staged_for_commit(repository, staging_area_path)) - untracked_files = list(get_untracked_files(repository, staging_area_path)) - print( - f"Commit id: {commit_id}\n" - f"Changes to be committed: {changes_to_be_committed}\n" - f"Changes not staged for commit: {changes_not_staged_for_commit}\n" - f"Untracked files: {untracked_files}" - ) - - -def get_all_files_in_directory_and_subs(directory: Union[Path, str], start_path: Union[Path, str]) -> Iterator[str]: - for (root, dirs, files) in os.walk(directory, topdown=True): - for file in files: - file_path = os.path.join(root, file) - rel = os.path.relpath(file_path, start=start_path) - yield rel - - -def get_changes_to_be_committed(commit_path: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: - cmp = dircmp(commit_path, staging_area_path) - yield from get_new_and_changed_files(cmp, staging_area_path) - for d, d_cmp in cmp.subdirs.items(): - yield from get_new_and_changed_files(d_cmp, os.path.join(staging_area_path, d)) - - -def get_new_and_changed_files(cmp: dircmp[Union[str, bytes]], staging_area_path: Union[Path, str]) -> Iterator[str]: - yield from get_new_files_added(cmp, staging_area_path) - yield from get_changed_files(cmp, staging_area_path) - - -def get_changed_files(cmp: dircmp[Union[str, bytes]], staging_area_path) -> Iterator[str]: - diff_files = cmp.diff_files - start_path = os.path.join(get_directory_with_wit(Path.cwd()), '.wit', 'staging_area') - for diff in diff_files: - file_path = os.path.join(staging_area_path, diff) - rel = os.path.relpath(file_path, start=start_path) - yield rel - - -def get_new_files_added(cmp: dircmp[Union[str, bytes]], staging_area_path: Union[Path, str]) -> Iterator[str]: - new_files_added = cmp.right_only - start_path = staging_area_path - for f in new_files_added: - f_path = os.path.join(staging_area_path, f) - if os.path.isfile(f_path): - yield f - else: - yield from get_all_files_in_directory_and_subs(f_path, start_path) - - -def get_changes_not_staged_for_commit( - repository: Union[Path, str], staging_area_path: Union[Path, str] -) -> Iterator[str]: - cmp = dircmp(repository, staging_area_path) - yield from get_changed_files(cmp, staging_area_path) - for common_dir in cmp.common_dirs: - path_in_repository = os.path.join(repository, common_dir) - path_in_staging_area = os.path.join(staging_area_path, common_dir) - yield from get_changes_not_staged_for_commit(path_in_repository, path_in_staging_area) - - -def get_untracked_files(repository: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: - cmp = dircmp(staging_area_path, repository, ignore=['.wit']) - yield from get_new_files_added(cmp, repository) - for common_dir in cmp.common_dirs: - path_in_repository = os.path.join(repository, common_dir) - path_in_staging_area = os.path.join(staging_area_path, common_dir) - yield from get_untracked_files(path_in_repository, path_in_staging_area) - - -def checkout(commit_id: str) -> None: - repository = get_directory_with_wit(Path.cwd()) - commit_path = os.path.join(repository, '.wit', 'images', commit_id) staging_area_path = os.path.join(repository, '.wit', 'staging_area') last_commit_id = get_parent_head(repository) last_commit_path = os.path.join(repository, '.wit', 'images', last_commit_id) @@ -208,25 +22,40 @@ def checkout(commit_id: str) -> None: ): raise FilesDoesntMatchError("There are files added or changed after last commit") references_file = repository.joinpath('.wit', 'references.txt') - if commit_id == 'master': - commit_id = get_master_commit_id(references_file) + commit_id = get_commit_id_of_branch(commit_id_or_branch, references_file) + if commit_id != commit_id_or_branch: + write_activated(commit_id_or_branch, repository) + commit_path = os.path.join(repository, '.wit', 'images', commit_id) change_files_in_main_folder(commit_path, repository) change_head_in_references_file(commit_id, references_file) change_staging_area_folder(staging_area_path, commit_path) + if commit_id != commit_id_or_branch: + write_activated(commit_id_or_branch, repository) + + +def write_activated(commit_id_or_branch: str, repository: Path) -> None: + activated_path = repository.joinpath('.wit', 'activated.txt') + activated_path.write_text(commit_id_or_branch) def change_head_in_references_file(commit_id: str, references_file: Path) -> None: with references_file.open() as file: - content = file.readlines() - references_file.write_text(f'HEAD={commit_id}\n{content[1:]}') + branches = file.readlines()[1:] + branches_txt = ''.join(branches) + references_file.write_text(f'HEAD={commit_id}\n{branches_txt}') -def get_master_commit_id(references_file: Path) -> str: +def get_commit_id_of_branch(commit_id_or_branch: str, references_file: Path) -> str: with references_file.open() as file: references_content = file.readlines() - master_line = references_content[-1].split('=') - commit_id = master_line[-1].strip() - return commit_id + branches_data = references_content[1:] + for branch_line in branches_data: + name_and_id = branch_line.split('=') + branch_name = name_and_id[0] + branch_id = name_and_id[1].strip() + if branch_name == commit_id_or_branch: + return branch_id + return commit_id_or_branch def change_files_in_main_folder(commit_path: str, repository: Path) -> None: @@ -240,6 +69,30 @@ def change_files_in_main_folder(commit_path: str, repository: Path) -> None: original_file.write(content) +# בהתחלה עשיתי את הפונקציה כמו שמופיע למטה בהמשך ההערה, והערת לי שיש דרך הרבה יותר פשוטה להעתיק תיקיה +# ושיש פונקציה קיימת שיכולה לעזור לי, ולכן שינתי את הפונקציה כמו שמופיע למעלה. +# אבל ככה יש בעיה במקרה והתווסף קובץ חדש, ורוצים לעשות checkout לקומיט מלפני יצירת הקובץ, +# ואז בעצם בעידכון הקבצים בתיקיה צריך למחוק את הקובץ לחלוטין. +# לא הצלחתי לחשוב על פתרון פשוט לזה חוץ צלהשתמש בדרך המסורבלת יותר שאיתה התחלתי. +# אשמח לתובנות. +# +# def change_files_in_main_folder(repository: Path, commit_id: str) -> None: +# commit_path = os.path.join(repository, '.wit', 'images', commit_id) +# all_files_in_repository_and_sub_dirs = [] +# for (root, dirs, files) in os.walk(repository, topdown=True): +# if '.wit' not in Path(root).parts: +# for file in files: +# all_files_in_repository_and_sub_dirs.append(os.path.join(root, file)) +# all_files_in_commit_and_sub_dirs = [] +# for (root, dirs, files) in os.walk(commit_path, topdown=True): +# for file in files: +# all_files_in_commit_and_sub_dirs.append(os.path.join(root, file)) +# for c_file in all_files_in_commit_and_sub_dirs: +# for r_file in all_files_in_repository_and_sub_dirs: +# if Path(r_file).relative_to(repository) == Path(c_file).relative_to(commit_path): +# shutil.copy2(c_file, r_file) + + def change_staging_area_folder(staging_area_path: str, commit_path: str): for file_or_dir in Path(staging_area_path).iterdir(): if file_or_dir.is_file(): @@ -252,49 +105,3 @@ def change_staging_area_folder(staging_area_path: str, commit_path: str): shutil.copy2(file, Path(staging_area_path).joinpath(rel_path)) else: shutil.copytree(file, Path(staging_area_path).joinpath(rel_path)) - - -class WitError(Exception): - pass - - -class FilesDoesntMatchError(Exception): - pass - - -def is_command_correct(argv: list[str]) -> bool: - if argv[1] in {'init', 'status'}: - return len(argv) == 2 - else: - return len(argv) == 3 - - -if sys.argv[1] == 'init': - if is_command_correct(sys.argv): - init() - else: - print(fr"Usage: python {sys.argv[0]} init") - -elif sys.argv[1] == 'add': - if is_command_correct(sys.argv): - add(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} add ") - -elif sys.argv[1] == 'commit': - if is_command_correct(sys.argv): - commit(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} commit MESSAGE") - -elif sys.argv[1] == 'status': - if is_command_correct(sys.argv): - status() - else: - print(fr"Usage: python {sys.argv[0]} status") - -elif sys.argv[1] == 'checkout': - if is_command_correct(sys.argv): - checkout(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} checkout ") diff --git a/commit.py b/commit.py index c429d77..2d064ce 100644 --- a/commit.py +++ b/commit.py @@ -1,52 +1,13 @@ -# upload 172 +from add import get_directory_with_wit + import datetime + +from errors import WitError + import os from pathlib import Path import random import shutil -import sys -from typing import Union - - -def init() -> None: - cwd = os.getcwd() - wit_path = os.path.join(cwd, '.wit') - os.mkdir(wit_path) - os.mkdir(os.path.join(wit_path, 'images')) - os.mkdir(os.path.join(wit_path, 'staging_area')) - - -def add(path_to_add: str) -> None: - file = Path(os.path.abspath(path_to_add)) - directory_with_wit = get_directory_with_wit(file) - if not directory_with_wit: - raise WitError("<.wit> file not found") - destination = directory_with_wit.joinpath('.wit', 'staging_area') - directories_to_copy = file.relative_to(directory_with_wit).parts[:-1] - for dir_name in directories_to_copy: - dirs = os.listdir(destination) - destination = destination.joinpath(dir_name) - if dir_name not in dirs: - destination.mkdir() - save_the_copy(destination, file) - - -def save_the_copy(destination: Path, file: Path) -> None: - if file.is_file(): - shutil.copy2(file, destination) - else: - destination_of_folder_if_doesnt_exists = destination.joinpath(file.name) - if destination_of_folder_if_doesnt_exists.exists(): - shutil.rmtree(destination_of_folder_if_doesnt_exists) - shutil.copytree(file, destination_of_folder_if_doesnt_exists) - - -def get_directory_with_wit(file: Path) -> Union[Path, bool]: - for parent in file.parents: - dir_lst = os.listdir(parent) - if '.wit' in dir_lst: # and os.path.isdir(os.path.abspath('.wit')): > never True. also with iterdir. why? - return parent - return False def commit(message: str) -> None: @@ -62,14 +23,19 @@ def commit(message: str) -> None: def create_commit_folder(images_path: Path) -> str: - length = 20 - chars = '1234567890abcdef' - folder_name = ''.join(random.choice(chars) for _ in range(length)) + folder_name = create_folder_name() path_of_new_folder = os.path.join(images_path, folder_name) os.mkdir(path_of_new_folder) return path_of_new_folder +def create_folder_name(): + length = 20 + chars = '1234567890abcdef' + folder_name = ''.join(random.choices(chars, k=length)) + return folder_name + + def create_commit_txt_file(dir_with_wit: Path, images_path: Path, path_of_new_folder: str, message: str) -> None: parent_head = get_parent_head(dir_with_wit) txt_file = images_path.joinpath(Path(path_of_new_folder).name + '.txt') @@ -81,12 +47,14 @@ def create_commit_txt_file(dir_with_wit: Path, images_path: Path, path_of_new_fo def get_parent_head(dir_with_wit: Path) -> str: - wit_folder = dir_with_wit.joinpath('.wit') # repository + r'\.wit' - if 'references.txt' in os.listdir(wit_folder): + wit_folder = dir_with_wit.joinpath('.wit') + references_file = wit_folder.joinpath('references.txt') + if references_file.exists(): ref_path = wit_folder.joinpath('references.txt') with ref_path.open() as f_h: - references_file = f_h.readlines() - return references_file[0][5:].strip() + references_content = f_h.readlines() + head_line = references_content[0].split('=') + return head_line[1].strip() return '' @@ -104,37 +72,21 @@ def save_files(dir_with_wit: Path, path_of_new_folder: str) -> None: def write_references(commit_id: str, dir_with_wit: Path) -> None: wit_folder = dir_with_wit.joinpath('.wit') ref_file = wit_folder.joinpath('references.txt') - ref_file.write_text(f'HEAD={commit_id}\nMASTER={commit_id}\n') - - -class WitError(Exception): - pass - - -def is_init_status_command_correct(argv: list[str]) -> bool: - return len(argv) == 2 - - -def is_add_or_commit_command_correct(argv: list[str]) -> bool: - return len(argv) == 3 - - -if sys.argv[1] == 'init': - if is_init_status_command_correct(sys.argv): - init() - else: - print(fr"Usage: python {sys.argv[0]} init") - - -elif sys.argv[1] == 'add': - if is_add_or_commit_command_correct(sys.argv): - add(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} add ") - - -elif sys.argv[1] == 'commit': - if is_add_or_commit_command_correct(sys.argv): - commit(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} commit MESSAGE") + activated_path = wit_folder.joinpath('activated.txt') + activated_branch = activated_path.read_text() + new_content = '='.join((activated_branch, commit_id)) # ??? + if ref_file.exists(): + with open(ref_file, "r") as references_file: + data = references_file.readlines() + current_head_id = data[0].split("=")[1].strip() + branches_data = data[1:] + new_content = "" + for line in branches_data: + branch_name = line.split("=")[0] + branch_id = line.split("=")[1].strip() + if branch_name == activated_branch: + activated_id = branch_id + if activated_id == current_head_id: + line = "=".join((branch_name, commit_id)) + new_content += line + ref_file.write_text(f'HEAD={commit_id}\n{new_content}') diff --git a/errors.py b/errors.py new file mode 100644 index 0000000..eb31492 --- /dev/null +++ b/errors.py @@ -0,0 +1,6 @@ +class WitError(Exception): + pass + + +class FilesDoesntMatchError(Exception): + pass diff --git a/init.py b/init.py index 7f91f61..67c888c 100644 --- a/init.py +++ b/init.py @@ -1,22 +1,12 @@ -# upload 170 import os -import sys +from pathlib import Path -def init(): +def init() -> None: cwd = os.getcwd() wit_path = os.path.join(cwd, '.wit') os.mkdir(wit_path) os.mkdir(os.path.join(wit_path, 'images')) os.mkdir(os.path.join(wit_path, 'staging_area')) - - -def is_init_command_correct(argv): - return len(argv) == 2 - - -if sys.argv[1] == 'init': - if is_init_command_correct(sys.argv): - init() - else: - print(r"Usage: python C:\Users\israe\PycharmProjects\wit_project\wit.py init") + activated_path = os.path.join(wit_path, 'activated.txt') + Path(activated_path).write_text('master') diff --git a/status.py b/status.py index 30a8671..58d8a5b 100644 --- a/status.py +++ b/status.py @@ -1,116 +1,11 @@ -# upload 173 -import datetime +from add import get_directory_with_wit +from commit import get_parent_head +from errors import WitError + from filecmp import dircmp import os from pathlib import Path -import random -import shutil -import sys -from typing import Iterator, Optional, Union - - -def init() -> None: - cwd = os.getcwd() - wit_path = os.path.join(cwd, '.wit') - os.mkdir(wit_path) - os.mkdir(os.path.join(wit_path, 'images')) - os.mkdir(os.path.join(wit_path, 'staging_area')) - - -def add(path_to_add: str) -> None: - file = Path(os.path.abspath(path_to_add)) - directory_with_wit = get_directory_with_wit(file) - if not directory_with_wit: - raise WitError("<.wit> file not found") - destination = directory_with_wit.joinpath('.wit', 'staging_area') - directories_to_copy = file.relative_to(directory_with_wit).parts[:-1] - for dir_name in directories_to_copy: - dirs = os.listdir(destination) - destination = destination.joinpath(dir_name) - if dir_name not in dirs: - destination.mkdir() - save_the_copy(destination, file) - - -def save_the_copy(destination: Path, file: Path) -> None: - if file.is_file(): - shutil.copy2(file, destination) - else: - destination_of_folder_if_doesnt_exists = destination.joinpath(file.name) - if destination_of_folder_if_doesnt_exists.exists(): - shutil.rmtree(destination_of_folder_if_doesnt_exists) - shutil.copytree(file, destination_of_folder_if_doesnt_exists) - - -# get the repository if exists, else- None. -def get_directory_with_wit(file: Path) -> Optional[Path]: - parents = file.parents - for p in parents: - wit = Path.joinpath(p, '.wit') - if wit.is_dir(): - return p - return None - - -def commit(message: str) -> None: - dir_with_wit = get_directory_with_wit(Path.cwd()) - if not dir_with_wit: - raise WitError("<.wit> file not found") - images_path = dir_with_wit.joinpath('.wit', 'images') - path_of_new_folder = create_commit_folder(images_path) - create_commit_txt_file(dir_with_wit, images_path, path_of_new_folder, message) - save_files(dir_with_wit, path_of_new_folder) - commit_id = os.path.basename(path_of_new_folder) - write_references(commit_id, dir_with_wit) - - -def create_commit_folder(images_path: Path) -> str: - length = 20 - chars = '1234567890abcdef' - folder_name = ''.join(random.choice(chars) for _ in range(length)) - path_of_new_folder = os.path.join(images_path, folder_name) - os.mkdir(path_of_new_folder) - return path_of_new_folder - - -def create_commit_txt_file(dir_with_wit: Path, images_path: Path, path_of_new_folder: str, message: str) -> None: - parent_head = get_parent_head(dir_with_wit) - txt_file = images_path.joinpath(Path(path_of_new_folder).name + '.txt') - txt_file.write_text( - f'parent = {parent_head if parent_head else None}\n' - f'date = {datetime.datetime.now().strftime("%c")}\n' - f'message = {message}' - ) - - -# if references file exists- return the HEAD, else- return ''. -def get_parent_head(dir_with_wit: Path) -> str: - wit_folder = dir_with_wit.joinpath('.wit') - references_file = wit_folder.joinpath('references.txt') - if references_file.exists(): - ref_path = wit_folder.joinpath('references.txt') - with ref_path.open() as f_h: - references_content = f_h.readlines() - head_line = references_content[0].split('=') - return head_line[1].strip() - return '' - - -def save_files(dir_with_wit: Path, path_of_new_folder: str) -> None: - staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') - for item in os.listdir(staging_area_path): - src = os.path.join(staging_area_path, item) - dst = os.path.join(path_of_new_folder, item) - if os.path.isfile(src): - shutil.copy2(src, dst) - else: - shutil.copytree(src, dst) - - -def write_references(commit_id: str, dir_with_wit: Path) -> None: - wit_folder = dir_with_wit.joinpath('.wit') - ref_file = wit_folder.joinpath('references.txt') - ref_file.write_text(f'HEAD={commit_id}\nMASTER={commit_id}\n') +from typing import Union, Iterator def status() -> None: @@ -156,14 +51,13 @@ def get_changed_files(cmp: dircmp[Union[str, bytes]], staging_area_path) -> Iter start_path = os.path.join(get_directory_with_wit(Path.cwd()), '.wit', 'staging_area') for diff in diff_files: file_path = os.path.join(staging_area_path, diff) - rel = os.path.relpath(file_path, start=start_path) yield rel def get_new_files_added(cmp: dircmp[Union[str, bytes]], staging_area_path: Union[Path, str]) -> Iterator[str]: new_files_added = cmp.right_only - start_path = get_directory_with_wit(Path.cwd()) + start_path = staging_area_path for f in new_files_added: f_path = os.path.join(staging_area_path, f) if os.path.isfile(f_path): @@ -185,41 +79,8 @@ def get_changes_not_staged_for_commit( def get_untracked_files(repository: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: cmp = dircmp(staging_area_path, repository, ignore=['.wit']) - yield from get_new_files_added(cmp, repository) # - - -class WitError(Exception): - pass - - -def is_init_status_command_correct(argv: list[str]) -> bool: - return len(argv) == 2 - - -def is_add_or_commit_command_correct(argv: list[str]) -> bool: - return len(argv) == 3 - - -if sys.argv[1] == 'init': - if is_init_status_command_correct(sys.argv): - init() - else: - print(fr"Usage: python {sys.argv[0]} init") - -elif sys.argv[1] == 'add': - if is_add_or_commit_command_correct(sys.argv): - add(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} add ") - -elif sys.argv[1] == 'commit': - if is_add_or_commit_command_correct(sys.argv): - commit(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} commit MESSAGE") - -elif sys.argv[1] == 'status': - if is_init_status_command_correct(sys.argv): - status() - else: - print(fr"Usage: python {sys.argv[0]} status") + yield from get_new_files_added(cmp, repository) + for common_dir in cmp.common_dirs: + path_in_repository = os.path.join(repository, common_dir) + path_in_staging_area = os.path.join(staging_area_path, common_dir) + yield from get_untracked_files(path_in_repository, path_in_staging_area) diff --git a/wit.py b/wit.py index 526133d..f0d146d 100644 --- a/wit.py +++ b/wit.py @@ -1,346 +1,15 @@ -import datetime -import filecmp -import os -from pathlib import Path -import random -import shutil -import sys -from typing import Any, Generator, Optional, Union - - -def init() -> None: - cwd = os.getcwd() - wit_path = os.path.join(cwd, '.wit') - os.mkdir(wit_path) - os.mkdir(os.path.join(wit_path, 'images')) - os.mkdir(os.path.join(wit_path, 'staging_area')) - activated_path = os.path.join(wit_path, 'activated.txt') - Path(activated_path).write_text('master') - - -def add(path_to_add: str) -> None: - file_to_add = Path(os.path.abspath(path_to_add)) - repository = get_directory_with_wit(file_to_add) - if not repository: - raise WitError("<.wit> file not found") - destination = repository.joinpath('.wit', 'staging_area') - directories_to_copy = file_to_add.relative_to(repository).parts[:-1] - for dir_name in directories_to_copy: - dirs = os.listdir(destination) - destination = destination.joinpath(dir_name) - if dir_name not in dirs: - destination.mkdir() - save_the_copy(destination, file_to_add) - - -def save_the_copy(destination: Path, file: Path) -> None: - if file.is_file(): - shutil.copy2(file, destination) - else: - destination_of_folder_if_doesnt_exists = destination.joinpath(file.name) - if destination_of_folder_if_doesnt_exists.exists(): - shutil.rmtree(destination_of_folder_if_doesnt_exists) - shutil.copytree(file, destination_of_folder_if_doesnt_exists) - - -def get_directory_with_wit(file: Path) -> Optional[Path]: - for parent in file.parents: - dir_lst = os.listdir(parent) - if '.wit' in dir_lst: - return parent - return None - - -def commit(message: str) -> None: - dir_with_wit = get_directory_with_wit(Path.cwd()) - if not dir_with_wit: - raise WitError("<.wit> file not found") - images_path = dir_with_wit.joinpath('.wit', 'images') - path_of_new_folder = create_commit_folder(images_path) - create_commit_txt_file(dir_with_wit, images_path, path_of_new_folder, message) - save_files(dir_with_wit, path_of_new_folder) - commit_id = os.path.basename(path_of_new_folder) - - write_references(commit_id, dir_with_wit) - - -def create_commit_folder(images_path: Path) -> str: - folder_name = create_commit_name() - path_of_new_folder = os.path.join(images_path, folder_name) - os.mkdir(path_of_new_folder) - return path_of_new_folder - - -def create_commit_name(): - length = 20 - chars = '1234567890abcdef' - folder_name = ''.join(random.choices(chars, k=length)) - return folder_name - - -def create_commit_txt_file(dir_with_wit: Path, images_path: Path, path_of_new_folder: str, message: str) -> None: - parent_head = get_parent_head(dir_with_wit) - txt_file = images_path.joinpath(Path(path_of_new_folder).name + '.txt') - txt_file.write_text( - f'parent = {parent_head if parent_head else None}\n' - f'date = {datetime.datetime.now().strftime("%c")}\n' - f'message = {message}' - ) - - -def get_parent_head(dir_with_wit: Path) -> str: - wit_folder = dir_with_wit.joinpath('.wit') - references_file = wit_folder.joinpath('references.txt') - if references_file.exists(): - ref_path = wit_folder.joinpath('references.txt') - with ref_path.open() as f_h: - references_content = f_h.readlines() - head_line = references_content[0].split('=') - return head_line[1].strip() - return '' - - -def save_files(dir_with_wit: Path, path_of_new_folder: str) -> None: - staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') - for item in os.listdir(staging_area_path): - src = os.path.join(staging_area_path, item) - dst = os.path.join(path_of_new_folder, item) - if os.path.isfile(src): - shutil.copy2(src, dst) - else: - shutil.copytree(src, dst) - - -# בעת הרצת פקודת commit, יתעדכן (כרגיל) ה־HEAD כך שיצביע ל־commit החדש שנוצר. -# לפני עדכון ה־HEAD, בדקו אם ה־branch שנמצא במצב “פעיל” מצביע לאותו מקום שבו נמצא ה־HEAD. -# אם כן, עדכנו את references.txt כך שה־branch יצביע למספר ה־commit החדש שנוצר. - -def write_references(commit_id: str, dir_with_wit: Path) -> None: - wit_folder = dir_with_wit.joinpath('.wit') - ref_file = wit_folder.joinpath('references.txt') - # new_branch_id = commit_id # new_master = commit_id - activated_path = wit_folder.joinpath('activated.txt') - activated_branch = activated_path.read_text() - new_content = '='.join((activated_branch, commit_id)) - if ref_file.exists(): - content = ref_file.read_text().split() - head_line = content[0] - head_id = head_line.split('=')[1] - branches_data = content[1:] - new_content = head_line - for line in branches_data: - name_and_id = line.split('=') - branch_name = name_and_id[0] - branch_id = name_and_id[1] - if branch_name == activated_branch: - if branch_id == head_id: - line = '='.join((branch_name, commit_id)) - new_content += line - ref_file.write_text(f'HEAD={commit_id}\n{new_content}') - - -def status() -> None: - repository = get_directory_with_wit(Path.cwd()) - if not repository: - raise WitError("<.wit> file not found") - commit_id = get_parent_head(repository) - files_added_since_last_commit = get_files_added_since_last_commit(commit_id, repository) - files_changed_since_last_commit = get_files_changed_since_last_commit(commit_id, repository) - files_in_staging_area_that_dont_match_original = get_files_in_staging_area_that_dont_match_original(repository) - files_not_in_staging_area = get_files_not_in_staging_area(repository) - print( - f"Commit id: {commit_id}\n" - f"Changes to be committed: {(list(files_added_since_last_commit) + list(files_changed_since_last_commit))}\n" - f"Changes not staged for commit: {list(files_in_staging_area_that_dont_match_original)}\n" - f"Untracked files: {list(files_not_in_staging_area)}" - ) - - -def get_files_added_since_last_commit(commit_id: str, repository: Path) -> Generator[Any, Any, None]: - commit_path = os.path.join(repository, '.wit', 'images', commit_id) - staging_area_path = os.path.join(repository, '.wit', 'staging_area') - all_files_in_stagind_area_and_sub = get_files_of_dir_and_subdirs(staging_area_path) - all_files_in_commit_and_sub_dirs = get_files_of_dir_and_subdirs(commit_path) - for file in all_files_in_stagind_area_and_sub: - if file not in all_files_in_commit_and_sub_dirs: - yield file - - -def get_files_changed_since_last_commit(commit_id: str, repository: Path) -> Generator[str, Any, None]: - commit_path = os.path.join(repository, '.wit', 'images', commit_id) - staging_area_path = os.path.join(repository, '.wit', 'staging_area') - all_files_in_commit_and_sub = get_all_files_in_dir_and_subs(commit_path) - all_files_in_staging_area_and_sub = get_all_files_in_dir_and_subs(staging_area_path) - yield from get_names_of_changed_files( - all_files_in_commit_and_sub, all_files_in_staging_area_and_sub, commit_path, staging_area_path - ) - +from add import add +from branch import branch +from checkout import checkout +from commit import commit +from init import init +from status import status -def get_names_of_changed_files( - all_files_in_commit_and_sub: Generator[Union[bytes, str], Any, None], - all_files_in_staging_area_and_sub: Generator[Union[bytes, str], Any, None], - commit_path: Union[str, Path], - staging_area_path: Union[str, Path] -) -> Generator[str, Any, None]: - for s_file in all_files_in_staging_area_and_sub: - for c_file in all_files_in_commit_and_sub: - if Path(s_file).relative_to(staging_area_path) == Path(c_file).relative_to(commit_path): - if not filecmp.cmp(s_file, c_file): - yield Path(s_file).name - - -def get_all_files_in_dir_and_subs(commit_path: str) -> Generator[Union[bytes, str], Any, None]: - for (root, dirs, files) in os.walk(commit_path, topdown=True): - for file in files: - yield os.path.join(root, file) - - -def get_files_in_staging_area_that_dont_match_original(repository: Path) -> Generator[str, Any, None]: - staging_area_path = os.path.join(repository, '.wit', 'staging_area') - all_files_in_repository_and_sub_dirs = get_all_files_and_dirs_in_repository(repository) - all_files_in_staging_area_and_sub = get_all_files_in_dir_and_subs(staging_area_path) - yield from get_names_of_changed_files( - all_files_in_staging_area_and_sub, all_files_in_repository_and_sub_dirs, staging_area_path, repository - ) - - -def get_all_files_and_dirs_in_repository(repository: Path) -> Generator[Union[bytes, str], Any, None]: - for (root, dirs, files) in os.walk(repository, topdown=True): - if '.wit' not in Path(root).parts: - for file in files: - yield os.path.join(root, file) - - -def get_files_not_in_staging_area(repository: Path) -> Generator[Any, Any, None]: - staging_area_path = os.path.join(repository, '.wit', 'staging_area') - files_names_in_repository_and_sub_dirs = get_files_names_of_repository_and_subs(repository) - all_files_in_staging_area_and_sub_dirs = get_files_of_dir_and_subdirs(staging_area_path) - for file in files_names_in_repository_and_sub_dirs: - if file not in all_files_in_staging_area_and_sub_dirs: - yield file - - -def get_files_names_of_repository_and_subs(repository: Path): - for (root, dirs, files) in os.walk(repository, topdown=True): - if '.wit' not in Path(root).parts: - for file in files: - yield file - - -def get_files_of_dir_and_subdirs(file_path: str) -> Generator[Any, Any, None]: - for (root, dirs, files) in os.walk(file_path, topdown=True): - for file in files: - yield file - - -def checkout(commit_id_or_branch: str) -> None: - repository = get_directory_with_wit(Path.cwd()) - if not repository: - raise WitError("<.wit> file not found") - references_file = repository.joinpath('.wit', 'references.txt') - last_commit_id = get_parent_head(repository) - if ( - list(get_files_added_since_last_commit(last_commit_id, repository)) - or list(get_files_changed_since_last_commit(last_commit_id, repository)) - or list(get_files_in_staging_area_that_dont_match_original(repository)) - ): - raise FilesDoesntMatchError("There are files added or changed after last commit") - commit_id = get_commit_id_of_branch(commit_id_or_branch, references_file) - print(commit_id) - change_files_in_main_folder(repository, commit_id) - change_head_in_references_file(commit_id, references_file) - change_staging_area_folder(repository, commit_id) - write_activated(commit_id, commit_id_or_branch, repository) # - - -def write_activated(commit_id: str, commit_id_or_branch: str, repository: Path) -> None: - activated_path = repository.joinpath('.wit', 'activated.txt') - Path(activated_path).write_text(commit_id_or_branch) - - -def get_commit_id_of_branch(commit_id_or_branch: str, references_file: Path) -> str: - with references_file.open() as file: - references_content = file.readlines() - branches_data = references_content[1:] - for branch_line in branches_data: - name_and_id = branch_line.split('=') - branch_name = name_and_id[0] - branch_id = name_and_id[1] - if branch_name == commit_id_or_branch: - return branch_id - return commit_id_or_branch - - -def change_head_in_references_file(commit_id: str, references_file: Path) -> None: - with references_file.open() as file: - branches = file.readlines()[1:] - branches_txt = ''.join(branches) - references_file.write_text(f'HEAD={commit_id}\n{branches_txt}') - - -def get_master_commit_id(references_file: Path) -> str: - with references_file.open() as file: - references_content = file.readlines() - master_line = references_content[1].split('=') - commit_id = master_line[-1].strip() - return commit_id - - -def change_files_in_main_folder(repository: Path, commit_id: str) -> None: - commit_path = os.path.join(repository, '.wit', 'images', commit_id) - # all_files_in_repository_and_sub_dirs = get_all_files_and_dirs_in_repository(repository) - all_files_in_repository_and_sub_dirs = [] - for (root, dirs, files) in os.walk(repository, topdown=True): - if '.wit' not in Path(root).parts: - for file in files: - all_files_in_repository_and_sub_dirs.append(os.path.join(root, file)) - # all_files_in_commit_and_sub_dirs = get_files_of_dir_and_subdirs(commit_path) # didn't work with the functions - all_files_in_commit_and_sub_dirs = [] - for (root, dirs, files) in os.walk(commit_path, topdown=True): - for file in files: - all_files_in_commit_and_sub_dirs.append(os.path.join(root, file)) - for c_file in all_files_in_commit_and_sub_dirs: - for r_file in all_files_in_repository_and_sub_dirs: - if Path(r_file).relative_to(repository) == Path(c_file).relative_to(commit_path): - shutil.copy2(c_file, r_file) - - -def change_staging_area_folder(dir_with_wit: Path, commit_id: str): - staging_area_path = dir_with_wit.joinpath('.wit', 'staging_area') - commit_path = dir_with_wit.joinpath('.wit', 'images', commit_id) - for file_or_dir in staging_area_path.iterdir(): - if file_or_dir.is_file(): - file_or_dir.unlink() - else: - shutil.rmtree(file_or_dir) - for file in commit_path.iterdir(): - rel_path = Path(file).relative_to(commit_path) - if file.is_file(): - shutil.copy2(file, staging_area_path.joinpath(rel_path)) - else: - shutil.copytree(file, staging_area_path.joinpath(rel_path)) - - -def branch(name: str) -> None: - repository = get_directory_with_wit(Path.cwd()) - if not repository: - raise WitError("<.wit> file not found") - references_file = repository.joinpath('.wit', 'references.txt') - commit_id = get_parent_head(repository) - with references_file.open('a') as ref_file: - ref_file.write(f'\n{name}={commit_id}') - - -class WitError(Exception): - pass - - -class FilesDoesntMatchError(Exception): - pass +import sys def is_command_correct(argv: list[str]) -> bool: - if argv[1] in ['init', 'status']: + if argv[1] in {'init', 'status'}: return len(argv) == 2 else: return len(argv) == 3 diff --git a/wit_checks.py b/wit_checks.py deleted file mode 100644 index 25bc449..0000000 --- a/wit_checks.py +++ /dev/null @@ -1,315 +0,0 @@ -# upload 172 -import datetime -import filecmp -import os -from pathlib import Path -import random -import shutil -import sys -from typing import Union - - -def init() -> None: - cwd = os.getcwd() - wit_path = os.path.join(cwd, '.wit') - os.mkdir(wit_path) - os.mkdir(os.path.join(wit_path, 'images')) - os.mkdir(os.path.join(wit_path, 'staging_area')) - - -def add(path_to_add: str) -> None: - file = Path(os.path.abspath(path_to_add)) - directory_with_wit = get_directory_with_wit(file) - if not directory_with_wit: - raise WitError("<.wit> file not found") - destination = directory_with_wit.joinpath('.wit', 'staging_area') - directories_to_copy = file.relative_to(directory_with_wit).parts[:-1] - for dir_name in directories_to_copy: - dirs = os.listdir(destination) - destination = destination.joinpath(dir_name) - if dir_name not in dirs: - destination.mkdir() - save_the_copy(destination, file) - - -def save_the_copy(destination: Path, file: Path) -> None: - if file.is_file(): - shutil.copy2(file, destination) - else: - destination_of_folder_if_doesnt_exists = destination.joinpath(file.name) - if destination_of_folder_if_doesnt_exists.exists(): - shutil.rmtree(destination_of_folder_if_doesnt_exists) - shutil.copytree(file, destination_of_folder_if_doesnt_exists) - - -def get_directory_with_wit(file: Path) -> Union[Path, bool]: - for parent in file.parents: - dir_lst = os.listdir(parent) - if '.wit' in dir_lst: # and os.path.isdir(os.path.abspath('.wit')): > never True. also with iterdir. why? - return parent - return False - - -def commit(message: str) -> None: - dir_with_wit = get_directory_with_wit(Path.cwd()) - if not dir_with_wit: - raise WitError("<.wit> file not found") - images_path = dir_with_wit.joinpath('.wit', 'images') - path_of_new_folder = create_commit_folder(images_path) - create_commit_txt_file(dir_with_wit, images_path, path_of_new_folder, message) - save_files(dir_with_wit, path_of_new_folder) - commit_id = os.path.basename(path_of_new_folder) - write_references(commit_id, dir_with_wit) - - -def create_commit_folder(images_path: Path) -> str: - length = 20 - chars = '1234567890abcdef' - folder_name = ''.join(random.choice(chars) for _ in range(length)) - path_of_new_folder = os.path.join(images_path, folder_name) - os.mkdir(path_of_new_folder) - return path_of_new_folder - - -def create_commit_txt_file(dir_with_wit: Path, images_path: Path, path_of_new_folder: str, message: str) -> None: - parent_head = get_parent_head(dir_with_wit) - txt_file = images_path.joinpath(Path(path_of_new_folder).name + '.txt') - txt_file.write_text( - f'parent = {parent_head if parent_head else None}\n' - f'date = {datetime.datetime.now().strftime("%c")}\n' - f'message = {message}' - ) - - -def get_parent_head(dir_with_wit: Path) -> str: - wit_folder = dir_with_wit.joinpath('.wit') # repository + r'\.wit' - if 'references.txt' in os.listdir(wit_folder): - ref_path = wit_folder.joinpath('references.txt') - with ref_path.open() as f_h: - references_file = f_h.readlines() - return references_file[0][5:].strip() - return '' - - -def save_files(dir_with_wit: Path, path_of_new_folder: str) -> None: - staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') - for item in os.listdir(staging_area_path): - src = os.path.join(staging_area_path, item) - dst = os.path.join(path_of_new_folder, item) - if os.path.isfile(src): - shutil.copy2(src, dst) - else: - shutil.copytree(src, dst) # todo ?? - - -def write_references(commit_id: str, dir_with_wit: Path) -> None: - wit_folder = dir_with_wit.joinpath('.wit') - ref_file = wit_folder.joinpath('references.txt') - old_commit_id = get_parent_head(dir_with_wit) - print(old_commit_id) - master_id = get_master_commit_id(ref_file) - if old_commit_id == master_id: - ref_file.write_text(f'HEAD={commit_id}\nMASTER={commit_id}\n') - else: - ref_file.write_text(f'HEAD={commit_id}\nMASTER={master_id}\n') - - -########### - - -def status(): - dir_with_wit = get_directory_with_wit(Path.cwd()) - if not dir_with_wit: - raise WitError("<.wit> file not found") - commit_id = get_parent_head(dir_with_wit) - files_added_or_changed_since_last_commit = get_files_added_or_changed_since_last_commit(commit_id, dir_with_wit) - files_in_staging_area_that_dont_match_original = get_files_in_staging_area_that_dont_match_original(dir_with_wit) - files_not_in_staging_area = get_files_not_in_staging_area(dir_with_wit) - print( - f"Commit id: {commit_id}\n" - f"Changes to be committed: {[file for file in files_added_or_changed_since_last_commit if file]}\n" - f"Changes not staged for commit: {[file for file in files_in_staging_area_that_dont_match_original if file]}\n" - f"Untracked files: {[file for file in files_not_in_staging_area]}" - ) - - -def get_files_added_or_changed_since_last_commit(commit_id: str, dir_with_wit: Path) -> list[str]: - commit_path = os.path.join(dir_with_wit, '.wit', 'images', commit_id) - staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') - dir_cmp = filecmp.dircmp(a=commit_path, b=staging_area_path) - yield dir_cmp.right_only - yield dir_cmp.diff_files - # while dir_cmp.subdirs: - for sub in dir_cmp.subdirs.values(): - dir_cmp = sub - yield dir_cmp.right_only - yield dir_cmp.diff_files - # return dir_cmp.right_only + dir_cmp.diff_files - - -def get_files_in_staging_area_that_dont_match_original(dir_with_wit: Path) -> list[str]: - staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') - dir_cmp = filecmp.dircmp(a=dir_with_wit, b=staging_area_path) - yield dir_cmp.diff_files - # while dir_cmp.subdirs: - for sub in dir_cmp.subdirs.values(): - yield sub.diff_files - - -def get_files_not_in_staging_area(dir_with_wit: Path) -> list[str]: - staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') - dir_cmp = filecmp.dircmp(a=dir_with_wit, b=staging_area_path) - yield dir_cmp.left_only - for sub in dir_cmp.subdirs.values(): - yield sub.left_only - - -########## -# -# -# -# -# def status(): -# repository = get_directory_with_wit(Path.cwd()) -# if not repository: -# raise WitError("<.wit> file not found") -# commit_id = get_parent_head(repository) -# commit_path = os.path.join(repository, '.wit', 'images', commit_id) -# staging_area_path = os.path.join(repository, '.wit', 'staging_area') -# cmp = filecmp.dircmp(staging_area_path, commit_path) -# files_added_since_last_commit = [f for f in get_files_added_since_last_commit(cmp)] -# print(files_added_since_last_commit) -# -# -# -# # -# # files_in_staging_area_that_dont_match_original = get_files_in_staging_area_that_dont_match_original(repository) -# # files_not_in_staging_area = get_files_not_in_staging_area(repository) -# # print( -# # f"Commit id: {commit_id}\n" -# # f"Changes to be committed: {files_added_or_changed_since_last_commit}\n" -# # f"Changes not staged for commit: {[file for file in files_in_staging_area_that_dont_match_original if file]}\n" -# # f"Untracked files: {[file for file in files_not_in_staging_area]}" -# -# # ) -# -# -# def get_files_added_since_last_commit(cmp): -# # cmp = filecmp.dircmp(staging_area_path, commit_path) -# for name in cmp.left_only: -# yield name -# for sub_cmp in cmp.subdirs.values(): -# get_files_added_since_last_commit(sub_cmp) -# -# -# -# # for file_name in Path(staging_area_path).iterdir(): -# # if file_name.name not in [f.name for f in Path(commit_path).iterdir()]: -# # yield file_name.name -# # elif file_name.is_dir(): -# # path_in_staging_area = os.path.join(staging_area_path, file_name.name) -# # path_in_commit = os.path.join(commit_path, file_name.name) -# # get_files_changed_since_last_commit(path_in_commit, path_in_staging_area) -# # -# -# -# -# -# -# -# -# -# -# -# def get_files_changed_since_last_commit(staging_area_path: str, commit_path: str): -# pass -############ - - -def checkout(commit_id: str): - dir_with_wit = get_directory_with_wit(Path.cwd()) - if not dir_with_wit: - raise WitError("<.wit> file not found") - # if files_added_or_changed_since_last_commit or files_in_staging_area_that_dont_match_original: - # return False - references_file = dir_with_wit.joinpath('.wit', 'references.txt') - - if commit_id == 'master': - commit_id = get_master_commit_id(references_file) - change_files_in_main_folder(dir_with_wit, commit_id) - with references_file.open() as file: - master = file.readlines()[1] - references_file.write_text(f'HEAD={commit_id}\n{master}\n') - change_staging_area_folder(dir_with_wit, commit_id) - - -def get_master_commit_id(references_file): - with references_file.open() as file: - commit_id = file.readlines()[1][7:].strip() - return commit_id - - -def change_files_in_main_folder(dir_with_wit: Path, commit_id : str) -> None: - commit_path = os.path.join(dir_with_wit, '.wit', 'images', commit_id) - for item in os.listdir(commit_path): - src = os.path.join(commit_path, item) - dst = os.path.join(dir_with_wit, item) - if os.path.isfile(src): - shutil.copy2(src, dst) - elif os.path.exists(dst): - print("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") # todo how to replace if exists - else: - shutil.copytree(src, dst) - - -def change_staging_area_folder(dir_with_wit, commit_id): - staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') - commit_path = os.path.join(dir_with_wit, '.wit', 'images', commit_id) - shutil.rmtree(staging_area_path) - shutil.copytree(commit_path, staging_area_path) - - - - -class WitError(Exception): - pass - - -def is_init_status_command_correct(argv: list[str]) -> bool: - return len(argv) == 2 - - -def is_add_commit_checkout_command_correct(argv: list[str]) -> bool: - return len(argv) == 3 - - -if sys.argv[1] == 'init': - if is_init_status_command_correct(sys.argv): - init() - else: - print(fr"Usage: python {sys.argv[0]} init") - -elif sys.argv[1] == 'add': - if is_add_commit_checkout_command_correct(sys.argv): - add(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} add ") - -elif sys.argv[1] == 'commit': - if is_add_commit_checkout_command_correct(sys.argv): - commit(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} commit MESSAGE") - -elif sys.argv[1] == 'status': - if is_init_status_command_correct(sys.argv): - status() - else: - print(fr"Usage: python {sys.argv[0]} status") - -elif sys.argv[1] == 'checkout': - if is_add_commit_checkout_command_correct(sys.argv): - checkout(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} checkout ") - diff --git a/wit_exercises/add1.py b/wit_exercises/add1.py new file mode 100644 index 0000000..a75d30b --- /dev/null +++ b/wit_exercises/add1.py @@ -0,0 +1,74 @@ +# upload 171 + +import os +from pathlib import Path +import shutil +import sys +from typing import Union + + +def init() -> None: + cwd = os.getcwd() + wit_path = os.path.join(cwd, '.wit') + os.mkdir(wit_path) + os.mkdir(os.path.join(wit_path, 'images')) + os.mkdir(os.path.join(wit_path, 'staging_area')) + + +def add(path_to_add: str) -> None: + file = Path(os.path.abspath(path_to_add)) + directory_with_wit = get_directory_with_wit(file) + if not directory_with_wit: + raise WitError("<.wit> file not found") + destination = directory_with_wit.joinpath('.wit', 'staging_area') + directories_to_copy = file.relative_to(directory_with_wit).parts[:-1] + for dir_name in directories_to_copy: + dirs = os.listdir(destination) + destination = destination.joinpath(dir_name) + if dir_name not in dirs: + destination.mkdir() + save_the_copy(destination, file) + + +def save_the_copy(destination: Path, file: Path) -> None: + if file.is_file(): + shutil.copy2(file, destination) + else: + destination_of_folder_if_doesnt_exists = destination.joinpath(file.name) + if destination_of_folder_if_doesnt_exists.exists(): + shutil.rmtree(destination_of_folder_if_doesnt_exists) + shutil.copytree(file, destination_of_folder_if_doesnt_exists) + + +def get_directory_with_wit(file: Path) -> Union[Path, bool]: + for parent in file.parents: + dir_lst = os.listdir(parent) + if '.wit' in dir_lst: # and os.path.isdir(os.path.abspath('.wit')): > never True. also with iterdir. why? + return parent + return False + + +class WitError(Exception): + pass + + +def is_init_status_command_correct(argv: list[str]) -> bool: + return len(argv) == 2 + + +def is_add_or_commit_command_correct(argv: list[str]) -> bool: + return len(argv) == 3 + + +if sys.argv[1] == 'init': + if is_init_status_command_correct(sys.argv): + init() + else: + print(fr"Usage: python {sys.argv[0]} init") + + +elif sys.argv[1] == 'add': + if is_add_or_commit_command_correct(sys.argv): + add(sys.argv[2]) + else: + print(fr"Usage: python {sys.argv[0]} add ") diff --git a/wit_exercises/checkout1.py b/wit_exercises/checkout1.py new file mode 100644 index 0000000..40eeb0a --- /dev/null +++ b/wit_exercises/checkout1.py @@ -0,0 +1,300 @@ +# upload 174 +import datetime +from filecmp import dircmp +import os +from pathlib import Path +import random +import shutil +import sys +from typing import Optional, Union, Iterator + + +def init() -> None: + cwd = os.getcwd() + wit_path = os.path.join(cwd, '.wit') + os.mkdir(wit_path) + os.mkdir(os.path.join(wit_path, 'images')) + os.mkdir(os.path.join(wit_path, 'staging_area')) + + +def add(path_to_add: str) -> None: + file = Path(os.path.abspath(path_to_add)) + directory_with_wit = get_directory_with_wit(file) + if not directory_with_wit: + raise WitError("<.wit> file not found") + destination = directory_with_wit.joinpath('.wit', 'staging_area') + directories_to_copy = file.relative_to(directory_with_wit).parts[:-1] + for dir_name in directories_to_copy: + dirs = os.listdir(destination) + destination = destination.joinpath(dir_name) + if dir_name not in dirs: + destination.mkdir() + save_the_copy(destination, file) + + +def save_the_copy(destination: Path, file: Path) -> None: + if file.is_file(): + shutil.copy2(file, destination) + else: + destination_of_folder_if_doesnt_exists = destination.joinpath(file.name) + if destination_of_folder_if_doesnt_exists.exists(): + shutil.rmtree(destination_of_folder_if_doesnt_exists) + shutil.copytree(file, destination_of_folder_if_doesnt_exists) + + +def get_directory_with_wit(file: Path) -> Optional[Path]: + parents = file.parents + for p in parents: + wit = Path.joinpath(p, '.wit') + if wit.is_dir(): + return p + return None + + +def commit(message: str) -> None: + dir_with_wit = get_directory_with_wit(Path.cwd()) + if not dir_with_wit: + raise WitError("<.wit> file not found") + images_path = dir_with_wit.joinpath('.wit', 'images') + path_of_new_folder = create_commit_folder(images_path) + create_commit_txt_file(dir_with_wit, images_path, path_of_new_folder, message) + save_files(dir_with_wit, path_of_new_folder) + commit_id = os.path.basename(path_of_new_folder) + write_references(commit_id, dir_with_wit) + + +def create_commit_folder(images_path: Path) -> str: + folder_name = create_folder_name() + path_of_new_folder = os.path.join(images_path, folder_name) + os.mkdir(path_of_new_folder) + return path_of_new_folder + + +def create_folder_name(): + length = 20 + chars = '1234567890abcdef' + folder_name = ''.join(random.choice(chars) for _ in range(length)) + return folder_name + + +def create_commit_txt_file(dir_with_wit: Path, images_path: Path, path_of_new_folder: str, message: str) -> None: + parent_head = get_parent_head(dir_with_wit) + txt_file = images_path.joinpath(Path(path_of_new_folder).name + '.txt') + txt_file.write_text( + f'parent = {parent_head if parent_head else None}\n' + f'date = {datetime.datetime.now().strftime("%c")}\n' + f'message = {message}' + ) + + +def get_parent_head(dir_with_wit: Path) -> str: + wit_folder = dir_with_wit.joinpath('.wit') + references_file = wit_folder.joinpath('references.txt') + if references_file.exists(): + ref_path = wit_folder.joinpath('references.txt') + with ref_path.open() as f_h: + references_content = f_h.readlines() + head_line = references_content[0].split('=') + return head_line[1].strip() + return '' + + +def save_files(dir_with_wit: Path, path_of_new_folder: str) -> None: + staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') + for item in os.listdir(staging_area_path): + src = os.path.join(staging_area_path, item) + dst = os.path.join(path_of_new_folder, item) + if os.path.isfile(src): + shutil.copy2(src, dst) + else: + shutil.copytree(src, dst) + + +def write_references(commit_id: str, dir_with_wit: Path) -> None: + wit_folder = dir_with_wit.joinpath('.wit') + ref_file = wit_folder.joinpath('references.txt') + ref_file.write_text(f'HEAD={commit_id}\nMASTER={commit_id}\n') + + +def status() -> None: + repository = get_directory_with_wit(Path.cwd()) + if not repository: + raise WitError("<.wit> file not found") + commit_id = get_parent_head(repository) + commit_path = os.path.join(repository, '.wit', 'images', commit_id) + staging_area_path = os.path.join(repository, '.wit', 'staging_area') + changes_to_be_committed = list(get_changes_to_be_committed(commit_path, staging_area_path)) + changes_not_staged_for_commit = list(get_changes_not_staged_for_commit(repository, staging_area_path)) + untracked_files = list(get_untracked_files(repository, staging_area_path)) + print( + f"Commit id: {commit_id}\n" + f"Changes to be committed: {changes_to_be_committed}\n" + f"Changes not staged for commit: {changes_not_staged_for_commit}\n" + f"Untracked files: {untracked_files}" + ) + + +def get_all_files_in_directory_and_subs(directory: Union[Path, str], start_path: Union[Path, str]) -> Iterator[str]: + for (root, dirs, files) in os.walk(directory, topdown=True): + for file in files: + file_path = os.path.join(root, file) + rel = os.path.relpath(file_path, start=start_path) + yield rel + + +def get_changes_to_be_committed(commit_path: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: + cmp = dircmp(commit_path, staging_area_path) + yield from get_new_and_changed_files(cmp, staging_area_path) + for d, d_cmp in cmp.subdirs.items(): + yield from get_new_and_changed_files(d_cmp, os.path.join(staging_area_path, d)) + + +def get_new_and_changed_files(cmp: dircmp[Union[str, bytes]], staging_area_path: Union[Path, str]) -> Iterator[str]: + yield from get_new_files_added(cmp, staging_area_path) + yield from get_changed_files(cmp, staging_area_path) + + +def get_changed_files(cmp: dircmp[Union[str, bytes]], staging_area_path) -> Iterator[str]: + diff_files = cmp.diff_files + start_path = os.path.join(get_directory_with_wit(Path.cwd()), '.wit', 'staging_area') + for diff in diff_files: + file_path = os.path.join(staging_area_path, diff) + rel = os.path.relpath(file_path, start=start_path) + yield rel + + +def get_new_files_added(cmp: dircmp[Union[str, bytes]], staging_area_path: Union[Path, str]) -> Iterator[str]: + new_files_added = cmp.right_only + start_path = staging_area_path + for f in new_files_added: + f_path = os.path.join(staging_area_path, f) + if os.path.isfile(f_path): + yield f + else: + yield from get_all_files_in_directory_and_subs(f_path, start_path) + + +def get_changes_not_staged_for_commit( + repository: Union[Path, str], staging_area_path: Union[Path, str] +) -> Iterator[str]: + cmp = dircmp(repository, staging_area_path) + yield from get_changed_files(cmp, staging_area_path) + for common_dir in cmp.common_dirs: + path_in_repository = os.path.join(repository, common_dir) + path_in_staging_area = os.path.join(staging_area_path, common_dir) + yield from get_changes_not_staged_for_commit(path_in_repository, path_in_staging_area) + + +def get_untracked_files(repository: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: + cmp = dircmp(staging_area_path, repository, ignore=['.wit']) + yield from get_new_files_added(cmp, repository) + for common_dir in cmp.common_dirs: + path_in_repository = os.path.join(repository, common_dir) + path_in_staging_area = os.path.join(staging_area_path, common_dir) + yield from get_untracked_files(path_in_repository, path_in_staging_area) + + +def checkout(commit_id: str) -> None: + repository = get_directory_with_wit(Path.cwd()) + commit_path = os.path.join(repository, '.wit', 'images', commit_id) + staging_area_path = os.path.join(repository, '.wit', 'staging_area') + last_commit_id = get_parent_head(repository) + last_commit_path = os.path.join(repository, '.wit', 'images', last_commit_id) + if not repository: + raise WitError("<.wit> file not found") + if ( + list(get_changes_to_be_committed(last_commit_path, staging_area_path)) + or list(get_changes_not_staged_for_commit(repository, staging_area_path)) + ): + raise FilesDoesntMatchError("There are files added or changed after last commit") + references_file = repository.joinpath('.wit', 'references.txt') + if commit_id == 'master': + commit_id = get_master_commit_id(references_file) + change_files_in_main_folder(commit_path, repository) + change_head_in_references_file(commit_id, references_file) + change_staging_area_folder(staging_area_path, commit_path) + + +def change_head_in_references_file(commit_id: str, references_file: Path) -> None: + with references_file.open() as file: + content = file.readlines() + references_file.write_text(f'HEAD={commit_id}\n{content[1:]}') + + +def get_master_commit_id(references_file: Path) -> str: + with references_file.open() as file: + references_content = file.readlines() + master_line = references_content[-1].split('=') + commit_id = master_line[-1].strip() + return commit_id + + +def change_files_in_main_folder(commit_path: str, repository: Path) -> None: + files_committed = get_all_files_in_directory_and_subs(commit_path, commit_path) + for committed_file in files_committed: + path_in_commit = os.path.join(commit_path, committed_file) + with open(path_in_commit, 'r') as committed_file_h: + content = committed_file_h.read() + path_in_repository = os.path.join(repository, committed_file) + with open(path_in_repository, "w") as original_file: + original_file.write(content) + + +def change_staging_area_folder(staging_area_path: str, commit_path: str): + for file_or_dir in Path(staging_area_path).iterdir(): + if file_or_dir.is_file(): + file_or_dir.unlink() + else: + shutil.rmtree(file_or_dir) + for file in Path(commit_path).iterdir(): + rel_path = Path(file).relative_to(commit_path) + if file.is_file(): + shutil.copy2(file, Path(staging_area_path).joinpath(rel_path)) + else: + shutil.copytree(file, Path(staging_area_path).joinpath(rel_path)) + + +class WitError(Exception): + pass + + +class FilesDoesntMatchError(Exception): + pass + + +def is_command_correct(argv: list[str]) -> bool: + if argv[1] in {'init', 'status'}: + return len(argv) == 2 + else: + return len(argv) == 3 + + +if sys.argv[1] == 'init': + if is_command_correct(sys.argv): + init() + else: + print(fr"Usage: python {sys.argv[0]} init") + +elif sys.argv[1] == 'add': + if is_command_correct(sys.argv): + add(sys.argv[2]) + else: + print(fr"Usage: python {sys.argv[0]} add ") + +elif sys.argv[1] == 'commit': + if is_command_correct(sys.argv): + commit(sys.argv[2]) + else: + print(fr"Usage: python {sys.argv[0]} commit MESSAGE") + +elif sys.argv[1] == 'status': + if is_command_correct(sys.argv): + status() + else: + print(fr"Usage: python {sys.argv[0]} status") + +elif sys.argv[1] == 'checkout': + if is_command_correct(sys.argv): + checkout(sys.argv[2]) + else: + print(fr"Usage: python {sys.argv[0]} checkout ") diff --git a/wit_exercises/commit1.py b/wit_exercises/commit1.py new file mode 100644 index 0000000..c429d77 --- /dev/null +++ b/wit_exercises/commit1.py @@ -0,0 +1,140 @@ +# upload 172 +import datetime +import os +from pathlib import Path +import random +import shutil +import sys +from typing import Union + + +def init() -> None: + cwd = os.getcwd() + wit_path = os.path.join(cwd, '.wit') + os.mkdir(wit_path) + os.mkdir(os.path.join(wit_path, 'images')) + os.mkdir(os.path.join(wit_path, 'staging_area')) + + +def add(path_to_add: str) -> None: + file = Path(os.path.abspath(path_to_add)) + directory_with_wit = get_directory_with_wit(file) + if not directory_with_wit: + raise WitError("<.wit> file not found") + destination = directory_with_wit.joinpath('.wit', 'staging_area') + directories_to_copy = file.relative_to(directory_with_wit).parts[:-1] + for dir_name in directories_to_copy: + dirs = os.listdir(destination) + destination = destination.joinpath(dir_name) + if dir_name not in dirs: + destination.mkdir() + save_the_copy(destination, file) + + +def save_the_copy(destination: Path, file: Path) -> None: + if file.is_file(): + shutil.copy2(file, destination) + else: + destination_of_folder_if_doesnt_exists = destination.joinpath(file.name) + if destination_of_folder_if_doesnt_exists.exists(): + shutil.rmtree(destination_of_folder_if_doesnt_exists) + shutil.copytree(file, destination_of_folder_if_doesnt_exists) + + +def get_directory_with_wit(file: Path) -> Union[Path, bool]: + for parent in file.parents: + dir_lst = os.listdir(parent) + if '.wit' in dir_lst: # and os.path.isdir(os.path.abspath('.wit')): > never True. also with iterdir. why? + return parent + return False + + +def commit(message: str) -> None: + dir_with_wit = get_directory_with_wit(Path.cwd()) + if not dir_with_wit: + raise WitError("<.wit> file not found") + images_path = dir_with_wit.joinpath('.wit', 'images') + path_of_new_folder = create_commit_folder(images_path) + create_commit_txt_file(dir_with_wit, images_path, path_of_new_folder, message) + save_files(dir_with_wit, path_of_new_folder) + commit_id = os.path.basename(path_of_new_folder) + write_references(commit_id, dir_with_wit) + + +def create_commit_folder(images_path: Path) -> str: + length = 20 + chars = '1234567890abcdef' + folder_name = ''.join(random.choice(chars) for _ in range(length)) + path_of_new_folder = os.path.join(images_path, folder_name) + os.mkdir(path_of_new_folder) + return path_of_new_folder + + +def create_commit_txt_file(dir_with_wit: Path, images_path: Path, path_of_new_folder: str, message: str) -> None: + parent_head = get_parent_head(dir_with_wit) + txt_file = images_path.joinpath(Path(path_of_new_folder).name + '.txt') + txt_file.write_text( + f'parent = {parent_head if parent_head else None}\n' + f'date = {datetime.datetime.now().strftime("%c")}\n' + f'message = {message}' + ) + + +def get_parent_head(dir_with_wit: Path) -> str: + wit_folder = dir_with_wit.joinpath('.wit') # repository + r'\.wit' + if 'references.txt' in os.listdir(wit_folder): + ref_path = wit_folder.joinpath('references.txt') + with ref_path.open() as f_h: + references_file = f_h.readlines() + return references_file[0][5:].strip() + return '' + + +def save_files(dir_with_wit: Path, path_of_new_folder: str) -> None: + staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') + for item in os.listdir(staging_area_path): + src = os.path.join(staging_area_path, item) + dst = os.path.join(path_of_new_folder, item) + if os.path.isfile(src): + shutil.copy2(src, dst) + else: + shutil.copytree(src, dst) + + +def write_references(commit_id: str, dir_with_wit: Path) -> None: + wit_folder = dir_with_wit.joinpath('.wit') + ref_file = wit_folder.joinpath('references.txt') + ref_file.write_text(f'HEAD={commit_id}\nMASTER={commit_id}\n') + + +class WitError(Exception): + pass + + +def is_init_status_command_correct(argv: list[str]) -> bool: + return len(argv) == 2 + + +def is_add_or_commit_command_correct(argv: list[str]) -> bool: + return len(argv) == 3 + + +if sys.argv[1] == 'init': + if is_init_status_command_correct(sys.argv): + init() + else: + print(fr"Usage: python {sys.argv[0]} init") + + +elif sys.argv[1] == 'add': + if is_add_or_commit_command_correct(sys.argv): + add(sys.argv[2]) + else: + print(fr"Usage: python {sys.argv[0]} add ") + + +elif sys.argv[1] == 'commit': + if is_add_or_commit_command_correct(sys.argv): + commit(sys.argv[2]) + else: + print(fr"Usage: python {sys.argv[0]} commit MESSAGE") diff --git a/wit_exercises/init1.py b/wit_exercises/init1.py new file mode 100644 index 0000000..7f91f61 --- /dev/null +++ b/wit_exercises/init1.py @@ -0,0 +1,22 @@ +# upload 170 +import os +import sys + + +def init(): + cwd = os.getcwd() + wit_path = os.path.join(cwd, '.wit') + os.mkdir(wit_path) + os.mkdir(os.path.join(wit_path, 'images')) + os.mkdir(os.path.join(wit_path, 'staging_area')) + + +def is_init_command_correct(argv): + return len(argv) == 2 + + +if sys.argv[1] == 'init': + if is_init_command_correct(sys.argv): + init() + else: + print(r"Usage: python C:\Users\israe\PycharmProjects\wit_project\wit.py init") diff --git a/wit_exercises/status1.py b/wit_exercises/status1.py new file mode 100644 index 0000000..30a8671 --- /dev/null +++ b/wit_exercises/status1.py @@ -0,0 +1,225 @@ +# upload 173 +import datetime +from filecmp import dircmp +import os +from pathlib import Path +import random +import shutil +import sys +from typing import Iterator, Optional, Union + + +def init() -> None: + cwd = os.getcwd() + wit_path = os.path.join(cwd, '.wit') + os.mkdir(wit_path) + os.mkdir(os.path.join(wit_path, 'images')) + os.mkdir(os.path.join(wit_path, 'staging_area')) + + +def add(path_to_add: str) -> None: + file = Path(os.path.abspath(path_to_add)) + directory_with_wit = get_directory_with_wit(file) + if not directory_with_wit: + raise WitError("<.wit> file not found") + destination = directory_with_wit.joinpath('.wit', 'staging_area') + directories_to_copy = file.relative_to(directory_with_wit).parts[:-1] + for dir_name in directories_to_copy: + dirs = os.listdir(destination) + destination = destination.joinpath(dir_name) + if dir_name not in dirs: + destination.mkdir() + save_the_copy(destination, file) + + +def save_the_copy(destination: Path, file: Path) -> None: + if file.is_file(): + shutil.copy2(file, destination) + else: + destination_of_folder_if_doesnt_exists = destination.joinpath(file.name) + if destination_of_folder_if_doesnt_exists.exists(): + shutil.rmtree(destination_of_folder_if_doesnt_exists) + shutil.copytree(file, destination_of_folder_if_doesnt_exists) + + +# get the repository if exists, else- None. +def get_directory_with_wit(file: Path) -> Optional[Path]: + parents = file.parents + for p in parents: + wit = Path.joinpath(p, '.wit') + if wit.is_dir(): + return p + return None + + +def commit(message: str) -> None: + dir_with_wit = get_directory_with_wit(Path.cwd()) + if not dir_with_wit: + raise WitError("<.wit> file not found") + images_path = dir_with_wit.joinpath('.wit', 'images') + path_of_new_folder = create_commit_folder(images_path) + create_commit_txt_file(dir_with_wit, images_path, path_of_new_folder, message) + save_files(dir_with_wit, path_of_new_folder) + commit_id = os.path.basename(path_of_new_folder) + write_references(commit_id, dir_with_wit) + + +def create_commit_folder(images_path: Path) -> str: + length = 20 + chars = '1234567890abcdef' + folder_name = ''.join(random.choice(chars) for _ in range(length)) + path_of_new_folder = os.path.join(images_path, folder_name) + os.mkdir(path_of_new_folder) + return path_of_new_folder + + +def create_commit_txt_file(dir_with_wit: Path, images_path: Path, path_of_new_folder: str, message: str) -> None: + parent_head = get_parent_head(dir_with_wit) + txt_file = images_path.joinpath(Path(path_of_new_folder).name + '.txt') + txt_file.write_text( + f'parent = {parent_head if parent_head else None}\n' + f'date = {datetime.datetime.now().strftime("%c")}\n' + f'message = {message}' + ) + + +# if references file exists- return the HEAD, else- return ''. +def get_parent_head(dir_with_wit: Path) -> str: + wit_folder = dir_with_wit.joinpath('.wit') + references_file = wit_folder.joinpath('references.txt') + if references_file.exists(): + ref_path = wit_folder.joinpath('references.txt') + with ref_path.open() as f_h: + references_content = f_h.readlines() + head_line = references_content[0].split('=') + return head_line[1].strip() + return '' + + +def save_files(dir_with_wit: Path, path_of_new_folder: str) -> None: + staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') + for item in os.listdir(staging_area_path): + src = os.path.join(staging_area_path, item) + dst = os.path.join(path_of_new_folder, item) + if os.path.isfile(src): + shutil.copy2(src, dst) + else: + shutil.copytree(src, dst) + + +def write_references(commit_id: str, dir_with_wit: Path) -> None: + wit_folder = dir_with_wit.joinpath('.wit') + ref_file = wit_folder.joinpath('references.txt') + ref_file.write_text(f'HEAD={commit_id}\nMASTER={commit_id}\n') + + +def status() -> None: + repository = get_directory_with_wit(Path.cwd()) + if not repository: + raise WitError("<.wit> file not found") + commit_id = get_parent_head(repository) + commit_path = os.path.join(repository, '.wit', 'images', commit_id) + staging_area_path = os.path.join(repository, '.wit', 'staging_area') + changes_to_be_committed = list(get_changes_to_be_committed(commit_path, staging_area_path)) + changes_not_staged_for_commit = list(get_changes_not_staged_for_commit(repository, staging_area_path)) + untracked_files = list(get_untracked_files(repository, staging_area_path)) + print( + f"Commit id: {commit_id}\n" + f"Changes to be committed: {changes_to_be_committed}\n" + f"Changes not staged for commit: {changes_not_staged_for_commit}\n" + f"Untracked files: {untracked_files}" + ) + + +def get_all_files_in_directory_and_subs(directory: Union[Path, str], start_path: Union[Path, str]) -> Iterator[str]: + for (root, dirs, files) in os.walk(directory, topdown=True): + for file in files: + file_path = os.path.join(root, file) + rel = os.path.relpath(file_path, start=start_path) + yield rel + + +def get_changes_to_be_committed(commit_path: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: + cmp = dircmp(commit_path, staging_area_path) + yield from get_new_and_changed_files(cmp, staging_area_path) + for d, d_cmp in cmp.subdirs.items(): + yield from get_new_and_changed_files(d_cmp, os.path.join(staging_area_path, d)) + + +def get_new_and_changed_files(cmp: dircmp[Union[str, bytes]], staging_area_path: Union[Path, str]) -> Iterator[str]: + yield from get_new_files_added(cmp, staging_area_path) + yield from get_changed_files(cmp, staging_area_path) + + +def get_changed_files(cmp: dircmp[Union[str, bytes]], staging_area_path) -> Iterator[str]: + diff_files = cmp.diff_files + start_path = os.path.join(get_directory_with_wit(Path.cwd()), '.wit', 'staging_area') + for diff in diff_files: + file_path = os.path.join(staging_area_path, diff) + + rel = os.path.relpath(file_path, start=start_path) + yield rel + + +def get_new_files_added(cmp: dircmp[Union[str, bytes]], staging_area_path: Union[Path, str]) -> Iterator[str]: + new_files_added = cmp.right_only + start_path = get_directory_with_wit(Path.cwd()) + for f in new_files_added: + f_path = os.path.join(staging_area_path, f) + if os.path.isfile(f_path): + yield f + else: + yield from get_all_files_in_directory_and_subs(f_path, start_path) + + +def get_changes_not_staged_for_commit( + repository: Union[Path, str], staging_area_path: Union[Path, str] +) -> Iterator[str]: + cmp = dircmp(repository, staging_area_path) + yield from get_changed_files(cmp, staging_area_path) + for common_dir in cmp.common_dirs: + path_in_repository = os.path.join(repository, common_dir) + path_in_staging_area = os.path.join(staging_area_path, common_dir) + yield from get_changes_not_staged_for_commit(path_in_repository, path_in_staging_area) + + +def get_untracked_files(repository: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: + cmp = dircmp(staging_area_path, repository, ignore=['.wit']) + yield from get_new_files_added(cmp, repository) # + + +class WitError(Exception): + pass + + +def is_init_status_command_correct(argv: list[str]) -> bool: + return len(argv) == 2 + + +def is_add_or_commit_command_correct(argv: list[str]) -> bool: + return len(argv) == 3 + + +if sys.argv[1] == 'init': + if is_init_status_command_correct(sys.argv): + init() + else: + print(fr"Usage: python {sys.argv[0]} init") + +elif sys.argv[1] == 'add': + if is_add_or_commit_command_correct(sys.argv): + add(sys.argv[2]) + else: + print(fr"Usage: python {sys.argv[0]} add ") + +elif sys.argv[1] == 'commit': + if is_add_or_commit_command_correct(sys.argv): + commit(sys.argv[2]) + else: + print(fr"Usage: python {sys.argv[0]} commit MESSAGE") + +elif sys.argv[1] == 'status': + if is_init_status_command_correct(sys.argv): + status() + else: + print(fr"Usage: python {sys.argv[0]} status") From 38baf1a73149a43e5261f83fc26b70051f154096 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Wed, 23 Feb 2022 14:13:05 +0200 Subject: [PATCH 22/73] finished conftest, test_init --- project/__init__.py | 0 add.py => project/add.py | 0 branch.py => project/branch.py | 0 checkout.py => project/checkout.py | 0 commit.py => project/commit.py | 0 errors.py => project/errors.py | 0 init.py => project/init.py | 5 +- status.py => project/status.py | 0 wit.py => project/wit.py | 0 test_wit/file1.txt | 0 test_wit/folder1/file2.txt | 0 test_wit/folder1/folder2/file3.txt | 0 tests/__init__.py | 0 tests/conftest.py | 21 ++ tests/test_add.py | 9 + tests/test_init.py | 13 ++ wit_exercises/add1.py | 74 ------- wit_exercises/checkout1.py | 300 ----------------------------- wit_exercises/commit1.py | 140 -------------- wit_exercises/init1.py | 22 --- wit_exercises/status1.py | 225 ---------------------- 21 files changed, 47 insertions(+), 762 deletions(-) create mode 100644 project/__init__.py rename add.py => project/add.py (100%) rename branch.py => project/branch.py (100%) rename checkout.py => project/checkout.py (100%) rename commit.py => project/commit.py (100%) rename errors.py => project/errors.py (100%) rename init.py => project/init.py (69%) rename status.py => project/status.py (100%) rename wit.py => project/wit.py (100%) create mode 100644 test_wit/file1.txt create mode 100644 test_wit/folder1/file2.txt create mode 100644 test_wit/folder1/folder2/file3.txt create mode 100644 tests/__init__.py create mode 100644 tests/conftest.py create mode 100644 tests/test_add.py create mode 100644 tests/test_init.py delete mode 100644 wit_exercises/add1.py delete mode 100644 wit_exercises/checkout1.py delete mode 100644 wit_exercises/commit1.py delete mode 100644 wit_exercises/init1.py delete mode 100644 wit_exercises/status1.py diff --git a/project/__init__.py b/project/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/add.py b/project/add.py similarity index 100% rename from add.py rename to project/add.py diff --git a/branch.py b/project/branch.py similarity index 100% rename from branch.py rename to project/branch.py diff --git a/checkout.py b/project/checkout.py similarity index 100% rename from checkout.py rename to project/checkout.py diff --git a/commit.py b/project/commit.py similarity index 100% rename from commit.py rename to project/commit.py diff --git a/errors.py b/project/errors.py similarity index 100% rename from errors.py rename to project/errors.py diff --git a/init.py b/project/init.py similarity index 69% rename from init.py rename to project/init.py index 67c888c..0290086 100644 --- a/init.py +++ b/project/init.py @@ -1,9 +1,12 @@ import os from pathlib import Path +from typing import Optional -def init() -> None: +def init(folder_name: Optional[str] = None) -> None: cwd = os.getcwd() + if folder_name: + cwd = os.path.join(cwd, folder_name) wit_path = os.path.join(cwd, '.wit') os.mkdir(wit_path) os.mkdir(os.path.join(wit_path, 'images')) diff --git a/status.py b/project/status.py similarity index 100% rename from status.py rename to project/status.py diff --git a/wit.py b/project/wit.py similarity index 100% rename from wit.py rename to project/wit.py diff --git a/test_wit/file1.txt b/test_wit/file1.txt new file mode 100644 index 0000000..e69de29 diff --git a/test_wit/folder1/file2.txt b/test_wit/folder1/file2.txt new file mode 100644 index 0000000..e69de29 diff --git a/test_wit/folder1/folder2/file3.txt b/test_wit/folder1/folder2/file3.txt new file mode 100644 index 0000000..e69de29 diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..007258c --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,21 @@ +import os +from pathlib import Path +import pytest + + +@pytest.fixture() +def test_folder(): + folder_name = 'test_wit' + os.mkdir(folder_name) + file1_path = Path(folder_name).joinpath('file1.txt') + file1_path.write_text("") + folder1_path = os.path.join(folder_name, 'folder1') + os.mkdir(folder1_path) + file2_path = Path(folder1_path).joinpath('file2.txt') + file2_path.write_text("") + folder2_path = os.path.join(folder1_path, 'folder2') + os.mkdir(folder2_path) + file3_path = Path(folder2_path).joinpath('file3.txt') + file3_path.write_text("") + return folder_name # yield? + # os.unlink(folder_name) diff --git a/tests/test_add.py b/tests/test_add.py new file mode 100644 index 0000000..4b0df3d --- /dev/null +++ b/tests/test_add.py @@ -0,0 +1,9 @@ +# import os +# from pathlib import Path +# import pytest +# from project import add +# +# def test_add(): +# os.mkdir('test_wit_files') +# Path('wit').joinpath('test_wit_1.txt').write_text('test') +# add() \ No newline at end of file diff --git a/tests/test_init.py b/tests/test_init.py new file mode 100644 index 0000000..a08a6b7 --- /dev/null +++ b/tests/test_init.py @@ -0,0 +1,13 @@ +import os +from pathlib import Path +import pytest +from project import init + + +def test_init(test_folder): + init.init(test_folder) + test_wit_path = Path(test_folder).joinpath('.wit') + assert test_wit_path.is_dir() + assert test_wit_path.joinpath('images').is_dir() + assert test_wit_path.joinpath('staging_area').is_dir() + assert test_wit_path.joinpath('activated.txt').read_text() == 'master' diff --git a/wit_exercises/add1.py b/wit_exercises/add1.py deleted file mode 100644 index a75d30b..0000000 --- a/wit_exercises/add1.py +++ /dev/null @@ -1,74 +0,0 @@ -# upload 171 - -import os -from pathlib import Path -import shutil -import sys -from typing import Union - - -def init() -> None: - cwd = os.getcwd() - wit_path = os.path.join(cwd, '.wit') - os.mkdir(wit_path) - os.mkdir(os.path.join(wit_path, 'images')) - os.mkdir(os.path.join(wit_path, 'staging_area')) - - -def add(path_to_add: str) -> None: - file = Path(os.path.abspath(path_to_add)) - directory_with_wit = get_directory_with_wit(file) - if not directory_with_wit: - raise WitError("<.wit> file not found") - destination = directory_with_wit.joinpath('.wit', 'staging_area') - directories_to_copy = file.relative_to(directory_with_wit).parts[:-1] - for dir_name in directories_to_copy: - dirs = os.listdir(destination) - destination = destination.joinpath(dir_name) - if dir_name not in dirs: - destination.mkdir() - save_the_copy(destination, file) - - -def save_the_copy(destination: Path, file: Path) -> None: - if file.is_file(): - shutil.copy2(file, destination) - else: - destination_of_folder_if_doesnt_exists = destination.joinpath(file.name) - if destination_of_folder_if_doesnt_exists.exists(): - shutil.rmtree(destination_of_folder_if_doesnt_exists) - shutil.copytree(file, destination_of_folder_if_doesnt_exists) - - -def get_directory_with_wit(file: Path) -> Union[Path, bool]: - for parent in file.parents: - dir_lst = os.listdir(parent) - if '.wit' in dir_lst: # and os.path.isdir(os.path.abspath('.wit')): > never True. also with iterdir. why? - return parent - return False - - -class WitError(Exception): - pass - - -def is_init_status_command_correct(argv: list[str]) -> bool: - return len(argv) == 2 - - -def is_add_or_commit_command_correct(argv: list[str]) -> bool: - return len(argv) == 3 - - -if sys.argv[1] == 'init': - if is_init_status_command_correct(sys.argv): - init() - else: - print(fr"Usage: python {sys.argv[0]} init") - - -elif sys.argv[1] == 'add': - if is_add_or_commit_command_correct(sys.argv): - add(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} add ") diff --git a/wit_exercises/checkout1.py b/wit_exercises/checkout1.py deleted file mode 100644 index 40eeb0a..0000000 --- a/wit_exercises/checkout1.py +++ /dev/null @@ -1,300 +0,0 @@ -# upload 174 -import datetime -from filecmp import dircmp -import os -from pathlib import Path -import random -import shutil -import sys -from typing import Optional, Union, Iterator - - -def init() -> None: - cwd = os.getcwd() - wit_path = os.path.join(cwd, '.wit') - os.mkdir(wit_path) - os.mkdir(os.path.join(wit_path, 'images')) - os.mkdir(os.path.join(wit_path, 'staging_area')) - - -def add(path_to_add: str) -> None: - file = Path(os.path.abspath(path_to_add)) - directory_with_wit = get_directory_with_wit(file) - if not directory_with_wit: - raise WitError("<.wit> file not found") - destination = directory_with_wit.joinpath('.wit', 'staging_area') - directories_to_copy = file.relative_to(directory_with_wit).parts[:-1] - for dir_name in directories_to_copy: - dirs = os.listdir(destination) - destination = destination.joinpath(dir_name) - if dir_name not in dirs: - destination.mkdir() - save_the_copy(destination, file) - - -def save_the_copy(destination: Path, file: Path) -> None: - if file.is_file(): - shutil.copy2(file, destination) - else: - destination_of_folder_if_doesnt_exists = destination.joinpath(file.name) - if destination_of_folder_if_doesnt_exists.exists(): - shutil.rmtree(destination_of_folder_if_doesnt_exists) - shutil.copytree(file, destination_of_folder_if_doesnt_exists) - - -def get_directory_with_wit(file: Path) -> Optional[Path]: - parents = file.parents - for p in parents: - wit = Path.joinpath(p, '.wit') - if wit.is_dir(): - return p - return None - - -def commit(message: str) -> None: - dir_with_wit = get_directory_with_wit(Path.cwd()) - if not dir_with_wit: - raise WitError("<.wit> file not found") - images_path = dir_with_wit.joinpath('.wit', 'images') - path_of_new_folder = create_commit_folder(images_path) - create_commit_txt_file(dir_with_wit, images_path, path_of_new_folder, message) - save_files(dir_with_wit, path_of_new_folder) - commit_id = os.path.basename(path_of_new_folder) - write_references(commit_id, dir_with_wit) - - -def create_commit_folder(images_path: Path) -> str: - folder_name = create_folder_name() - path_of_new_folder = os.path.join(images_path, folder_name) - os.mkdir(path_of_new_folder) - return path_of_new_folder - - -def create_folder_name(): - length = 20 - chars = '1234567890abcdef' - folder_name = ''.join(random.choice(chars) for _ in range(length)) - return folder_name - - -def create_commit_txt_file(dir_with_wit: Path, images_path: Path, path_of_new_folder: str, message: str) -> None: - parent_head = get_parent_head(dir_with_wit) - txt_file = images_path.joinpath(Path(path_of_new_folder).name + '.txt') - txt_file.write_text( - f'parent = {parent_head if parent_head else None}\n' - f'date = {datetime.datetime.now().strftime("%c")}\n' - f'message = {message}' - ) - - -def get_parent_head(dir_with_wit: Path) -> str: - wit_folder = dir_with_wit.joinpath('.wit') - references_file = wit_folder.joinpath('references.txt') - if references_file.exists(): - ref_path = wit_folder.joinpath('references.txt') - with ref_path.open() as f_h: - references_content = f_h.readlines() - head_line = references_content[0].split('=') - return head_line[1].strip() - return '' - - -def save_files(dir_with_wit: Path, path_of_new_folder: str) -> None: - staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') - for item in os.listdir(staging_area_path): - src = os.path.join(staging_area_path, item) - dst = os.path.join(path_of_new_folder, item) - if os.path.isfile(src): - shutil.copy2(src, dst) - else: - shutil.copytree(src, dst) - - -def write_references(commit_id: str, dir_with_wit: Path) -> None: - wit_folder = dir_with_wit.joinpath('.wit') - ref_file = wit_folder.joinpath('references.txt') - ref_file.write_text(f'HEAD={commit_id}\nMASTER={commit_id}\n') - - -def status() -> None: - repository = get_directory_with_wit(Path.cwd()) - if not repository: - raise WitError("<.wit> file not found") - commit_id = get_parent_head(repository) - commit_path = os.path.join(repository, '.wit', 'images', commit_id) - staging_area_path = os.path.join(repository, '.wit', 'staging_area') - changes_to_be_committed = list(get_changes_to_be_committed(commit_path, staging_area_path)) - changes_not_staged_for_commit = list(get_changes_not_staged_for_commit(repository, staging_area_path)) - untracked_files = list(get_untracked_files(repository, staging_area_path)) - print( - f"Commit id: {commit_id}\n" - f"Changes to be committed: {changes_to_be_committed}\n" - f"Changes not staged for commit: {changes_not_staged_for_commit}\n" - f"Untracked files: {untracked_files}" - ) - - -def get_all_files_in_directory_and_subs(directory: Union[Path, str], start_path: Union[Path, str]) -> Iterator[str]: - for (root, dirs, files) in os.walk(directory, topdown=True): - for file in files: - file_path = os.path.join(root, file) - rel = os.path.relpath(file_path, start=start_path) - yield rel - - -def get_changes_to_be_committed(commit_path: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: - cmp = dircmp(commit_path, staging_area_path) - yield from get_new_and_changed_files(cmp, staging_area_path) - for d, d_cmp in cmp.subdirs.items(): - yield from get_new_and_changed_files(d_cmp, os.path.join(staging_area_path, d)) - - -def get_new_and_changed_files(cmp: dircmp[Union[str, bytes]], staging_area_path: Union[Path, str]) -> Iterator[str]: - yield from get_new_files_added(cmp, staging_area_path) - yield from get_changed_files(cmp, staging_area_path) - - -def get_changed_files(cmp: dircmp[Union[str, bytes]], staging_area_path) -> Iterator[str]: - diff_files = cmp.diff_files - start_path = os.path.join(get_directory_with_wit(Path.cwd()), '.wit', 'staging_area') - for diff in diff_files: - file_path = os.path.join(staging_area_path, diff) - rel = os.path.relpath(file_path, start=start_path) - yield rel - - -def get_new_files_added(cmp: dircmp[Union[str, bytes]], staging_area_path: Union[Path, str]) -> Iterator[str]: - new_files_added = cmp.right_only - start_path = staging_area_path - for f in new_files_added: - f_path = os.path.join(staging_area_path, f) - if os.path.isfile(f_path): - yield f - else: - yield from get_all_files_in_directory_and_subs(f_path, start_path) - - -def get_changes_not_staged_for_commit( - repository: Union[Path, str], staging_area_path: Union[Path, str] -) -> Iterator[str]: - cmp = dircmp(repository, staging_area_path) - yield from get_changed_files(cmp, staging_area_path) - for common_dir in cmp.common_dirs: - path_in_repository = os.path.join(repository, common_dir) - path_in_staging_area = os.path.join(staging_area_path, common_dir) - yield from get_changes_not_staged_for_commit(path_in_repository, path_in_staging_area) - - -def get_untracked_files(repository: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: - cmp = dircmp(staging_area_path, repository, ignore=['.wit']) - yield from get_new_files_added(cmp, repository) - for common_dir in cmp.common_dirs: - path_in_repository = os.path.join(repository, common_dir) - path_in_staging_area = os.path.join(staging_area_path, common_dir) - yield from get_untracked_files(path_in_repository, path_in_staging_area) - - -def checkout(commit_id: str) -> None: - repository = get_directory_with_wit(Path.cwd()) - commit_path = os.path.join(repository, '.wit', 'images', commit_id) - staging_area_path = os.path.join(repository, '.wit', 'staging_area') - last_commit_id = get_parent_head(repository) - last_commit_path = os.path.join(repository, '.wit', 'images', last_commit_id) - if not repository: - raise WitError("<.wit> file not found") - if ( - list(get_changes_to_be_committed(last_commit_path, staging_area_path)) - or list(get_changes_not_staged_for_commit(repository, staging_area_path)) - ): - raise FilesDoesntMatchError("There are files added or changed after last commit") - references_file = repository.joinpath('.wit', 'references.txt') - if commit_id == 'master': - commit_id = get_master_commit_id(references_file) - change_files_in_main_folder(commit_path, repository) - change_head_in_references_file(commit_id, references_file) - change_staging_area_folder(staging_area_path, commit_path) - - -def change_head_in_references_file(commit_id: str, references_file: Path) -> None: - with references_file.open() as file: - content = file.readlines() - references_file.write_text(f'HEAD={commit_id}\n{content[1:]}') - - -def get_master_commit_id(references_file: Path) -> str: - with references_file.open() as file: - references_content = file.readlines() - master_line = references_content[-1].split('=') - commit_id = master_line[-1].strip() - return commit_id - - -def change_files_in_main_folder(commit_path: str, repository: Path) -> None: - files_committed = get_all_files_in_directory_and_subs(commit_path, commit_path) - for committed_file in files_committed: - path_in_commit = os.path.join(commit_path, committed_file) - with open(path_in_commit, 'r') as committed_file_h: - content = committed_file_h.read() - path_in_repository = os.path.join(repository, committed_file) - with open(path_in_repository, "w") as original_file: - original_file.write(content) - - -def change_staging_area_folder(staging_area_path: str, commit_path: str): - for file_or_dir in Path(staging_area_path).iterdir(): - if file_or_dir.is_file(): - file_or_dir.unlink() - else: - shutil.rmtree(file_or_dir) - for file in Path(commit_path).iterdir(): - rel_path = Path(file).relative_to(commit_path) - if file.is_file(): - shutil.copy2(file, Path(staging_area_path).joinpath(rel_path)) - else: - shutil.copytree(file, Path(staging_area_path).joinpath(rel_path)) - - -class WitError(Exception): - pass - - -class FilesDoesntMatchError(Exception): - pass - - -def is_command_correct(argv: list[str]) -> bool: - if argv[1] in {'init', 'status'}: - return len(argv) == 2 - else: - return len(argv) == 3 - - -if sys.argv[1] == 'init': - if is_command_correct(sys.argv): - init() - else: - print(fr"Usage: python {sys.argv[0]} init") - -elif sys.argv[1] == 'add': - if is_command_correct(sys.argv): - add(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} add ") - -elif sys.argv[1] == 'commit': - if is_command_correct(sys.argv): - commit(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} commit MESSAGE") - -elif sys.argv[1] == 'status': - if is_command_correct(sys.argv): - status() - else: - print(fr"Usage: python {sys.argv[0]} status") - -elif sys.argv[1] == 'checkout': - if is_command_correct(sys.argv): - checkout(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} checkout ") diff --git a/wit_exercises/commit1.py b/wit_exercises/commit1.py deleted file mode 100644 index c429d77..0000000 --- a/wit_exercises/commit1.py +++ /dev/null @@ -1,140 +0,0 @@ -# upload 172 -import datetime -import os -from pathlib import Path -import random -import shutil -import sys -from typing import Union - - -def init() -> None: - cwd = os.getcwd() - wit_path = os.path.join(cwd, '.wit') - os.mkdir(wit_path) - os.mkdir(os.path.join(wit_path, 'images')) - os.mkdir(os.path.join(wit_path, 'staging_area')) - - -def add(path_to_add: str) -> None: - file = Path(os.path.abspath(path_to_add)) - directory_with_wit = get_directory_with_wit(file) - if not directory_with_wit: - raise WitError("<.wit> file not found") - destination = directory_with_wit.joinpath('.wit', 'staging_area') - directories_to_copy = file.relative_to(directory_with_wit).parts[:-1] - for dir_name in directories_to_copy: - dirs = os.listdir(destination) - destination = destination.joinpath(dir_name) - if dir_name not in dirs: - destination.mkdir() - save_the_copy(destination, file) - - -def save_the_copy(destination: Path, file: Path) -> None: - if file.is_file(): - shutil.copy2(file, destination) - else: - destination_of_folder_if_doesnt_exists = destination.joinpath(file.name) - if destination_of_folder_if_doesnt_exists.exists(): - shutil.rmtree(destination_of_folder_if_doesnt_exists) - shutil.copytree(file, destination_of_folder_if_doesnt_exists) - - -def get_directory_with_wit(file: Path) -> Union[Path, bool]: - for parent in file.parents: - dir_lst = os.listdir(parent) - if '.wit' in dir_lst: # and os.path.isdir(os.path.abspath('.wit')): > never True. also with iterdir. why? - return parent - return False - - -def commit(message: str) -> None: - dir_with_wit = get_directory_with_wit(Path.cwd()) - if not dir_with_wit: - raise WitError("<.wit> file not found") - images_path = dir_with_wit.joinpath('.wit', 'images') - path_of_new_folder = create_commit_folder(images_path) - create_commit_txt_file(dir_with_wit, images_path, path_of_new_folder, message) - save_files(dir_with_wit, path_of_new_folder) - commit_id = os.path.basename(path_of_new_folder) - write_references(commit_id, dir_with_wit) - - -def create_commit_folder(images_path: Path) -> str: - length = 20 - chars = '1234567890abcdef' - folder_name = ''.join(random.choice(chars) for _ in range(length)) - path_of_new_folder = os.path.join(images_path, folder_name) - os.mkdir(path_of_new_folder) - return path_of_new_folder - - -def create_commit_txt_file(dir_with_wit: Path, images_path: Path, path_of_new_folder: str, message: str) -> None: - parent_head = get_parent_head(dir_with_wit) - txt_file = images_path.joinpath(Path(path_of_new_folder).name + '.txt') - txt_file.write_text( - f'parent = {parent_head if parent_head else None}\n' - f'date = {datetime.datetime.now().strftime("%c")}\n' - f'message = {message}' - ) - - -def get_parent_head(dir_with_wit: Path) -> str: - wit_folder = dir_with_wit.joinpath('.wit') # repository + r'\.wit' - if 'references.txt' in os.listdir(wit_folder): - ref_path = wit_folder.joinpath('references.txt') - with ref_path.open() as f_h: - references_file = f_h.readlines() - return references_file[0][5:].strip() - return '' - - -def save_files(dir_with_wit: Path, path_of_new_folder: str) -> None: - staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') - for item in os.listdir(staging_area_path): - src = os.path.join(staging_area_path, item) - dst = os.path.join(path_of_new_folder, item) - if os.path.isfile(src): - shutil.copy2(src, dst) - else: - shutil.copytree(src, dst) - - -def write_references(commit_id: str, dir_with_wit: Path) -> None: - wit_folder = dir_with_wit.joinpath('.wit') - ref_file = wit_folder.joinpath('references.txt') - ref_file.write_text(f'HEAD={commit_id}\nMASTER={commit_id}\n') - - -class WitError(Exception): - pass - - -def is_init_status_command_correct(argv: list[str]) -> bool: - return len(argv) == 2 - - -def is_add_or_commit_command_correct(argv: list[str]) -> bool: - return len(argv) == 3 - - -if sys.argv[1] == 'init': - if is_init_status_command_correct(sys.argv): - init() - else: - print(fr"Usage: python {sys.argv[0]} init") - - -elif sys.argv[1] == 'add': - if is_add_or_commit_command_correct(sys.argv): - add(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} add ") - - -elif sys.argv[1] == 'commit': - if is_add_or_commit_command_correct(sys.argv): - commit(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} commit MESSAGE") diff --git a/wit_exercises/init1.py b/wit_exercises/init1.py deleted file mode 100644 index 7f91f61..0000000 --- a/wit_exercises/init1.py +++ /dev/null @@ -1,22 +0,0 @@ -# upload 170 -import os -import sys - - -def init(): - cwd = os.getcwd() - wit_path = os.path.join(cwd, '.wit') - os.mkdir(wit_path) - os.mkdir(os.path.join(wit_path, 'images')) - os.mkdir(os.path.join(wit_path, 'staging_area')) - - -def is_init_command_correct(argv): - return len(argv) == 2 - - -if sys.argv[1] == 'init': - if is_init_command_correct(sys.argv): - init() - else: - print(r"Usage: python C:\Users\israe\PycharmProjects\wit_project\wit.py init") diff --git a/wit_exercises/status1.py b/wit_exercises/status1.py deleted file mode 100644 index 30a8671..0000000 --- a/wit_exercises/status1.py +++ /dev/null @@ -1,225 +0,0 @@ -# upload 173 -import datetime -from filecmp import dircmp -import os -from pathlib import Path -import random -import shutil -import sys -from typing import Iterator, Optional, Union - - -def init() -> None: - cwd = os.getcwd() - wit_path = os.path.join(cwd, '.wit') - os.mkdir(wit_path) - os.mkdir(os.path.join(wit_path, 'images')) - os.mkdir(os.path.join(wit_path, 'staging_area')) - - -def add(path_to_add: str) -> None: - file = Path(os.path.abspath(path_to_add)) - directory_with_wit = get_directory_with_wit(file) - if not directory_with_wit: - raise WitError("<.wit> file not found") - destination = directory_with_wit.joinpath('.wit', 'staging_area') - directories_to_copy = file.relative_to(directory_with_wit).parts[:-1] - for dir_name in directories_to_copy: - dirs = os.listdir(destination) - destination = destination.joinpath(dir_name) - if dir_name not in dirs: - destination.mkdir() - save_the_copy(destination, file) - - -def save_the_copy(destination: Path, file: Path) -> None: - if file.is_file(): - shutil.copy2(file, destination) - else: - destination_of_folder_if_doesnt_exists = destination.joinpath(file.name) - if destination_of_folder_if_doesnt_exists.exists(): - shutil.rmtree(destination_of_folder_if_doesnt_exists) - shutil.copytree(file, destination_of_folder_if_doesnt_exists) - - -# get the repository if exists, else- None. -def get_directory_with_wit(file: Path) -> Optional[Path]: - parents = file.parents - for p in parents: - wit = Path.joinpath(p, '.wit') - if wit.is_dir(): - return p - return None - - -def commit(message: str) -> None: - dir_with_wit = get_directory_with_wit(Path.cwd()) - if not dir_with_wit: - raise WitError("<.wit> file not found") - images_path = dir_with_wit.joinpath('.wit', 'images') - path_of_new_folder = create_commit_folder(images_path) - create_commit_txt_file(dir_with_wit, images_path, path_of_new_folder, message) - save_files(dir_with_wit, path_of_new_folder) - commit_id = os.path.basename(path_of_new_folder) - write_references(commit_id, dir_with_wit) - - -def create_commit_folder(images_path: Path) -> str: - length = 20 - chars = '1234567890abcdef' - folder_name = ''.join(random.choice(chars) for _ in range(length)) - path_of_new_folder = os.path.join(images_path, folder_name) - os.mkdir(path_of_new_folder) - return path_of_new_folder - - -def create_commit_txt_file(dir_with_wit: Path, images_path: Path, path_of_new_folder: str, message: str) -> None: - parent_head = get_parent_head(dir_with_wit) - txt_file = images_path.joinpath(Path(path_of_new_folder).name + '.txt') - txt_file.write_text( - f'parent = {parent_head if parent_head else None}\n' - f'date = {datetime.datetime.now().strftime("%c")}\n' - f'message = {message}' - ) - - -# if references file exists- return the HEAD, else- return ''. -def get_parent_head(dir_with_wit: Path) -> str: - wit_folder = dir_with_wit.joinpath('.wit') - references_file = wit_folder.joinpath('references.txt') - if references_file.exists(): - ref_path = wit_folder.joinpath('references.txt') - with ref_path.open() as f_h: - references_content = f_h.readlines() - head_line = references_content[0].split('=') - return head_line[1].strip() - return '' - - -def save_files(dir_with_wit: Path, path_of_new_folder: str) -> None: - staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') - for item in os.listdir(staging_area_path): - src = os.path.join(staging_area_path, item) - dst = os.path.join(path_of_new_folder, item) - if os.path.isfile(src): - shutil.copy2(src, dst) - else: - shutil.copytree(src, dst) - - -def write_references(commit_id: str, dir_with_wit: Path) -> None: - wit_folder = dir_with_wit.joinpath('.wit') - ref_file = wit_folder.joinpath('references.txt') - ref_file.write_text(f'HEAD={commit_id}\nMASTER={commit_id}\n') - - -def status() -> None: - repository = get_directory_with_wit(Path.cwd()) - if not repository: - raise WitError("<.wit> file not found") - commit_id = get_parent_head(repository) - commit_path = os.path.join(repository, '.wit', 'images', commit_id) - staging_area_path = os.path.join(repository, '.wit', 'staging_area') - changes_to_be_committed = list(get_changes_to_be_committed(commit_path, staging_area_path)) - changes_not_staged_for_commit = list(get_changes_not_staged_for_commit(repository, staging_area_path)) - untracked_files = list(get_untracked_files(repository, staging_area_path)) - print( - f"Commit id: {commit_id}\n" - f"Changes to be committed: {changes_to_be_committed}\n" - f"Changes not staged for commit: {changes_not_staged_for_commit}\n" - f"Untracked files: {untracked_files}" - ) - - -def get_all_files_in_directory_and_subs(directory: Union[Path, str], start_path: Union[Path, str]) -> Iterator[str]: - for (root, dirs, files) in os.walk(directory, topdown=True): - for file in files: - file_path = os.path.join(root, file) - rel = os.path.relpath(file_path, start=start_path) - yield rel - - -def get_changes_to_be_committed(commit_path: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: - cmp = dircmp(commit_path, staging_area_path) - yield from get_new_and_changed_files(cmp, staging_area_path) - for d, d_cmp in cmp.subdirs.items(): - yield from get_new_and_changed_files(d_cmp, os.path.join(staging_area_path, d)) - - -def get_new_and_changed_files(cmp: dircmp[Union[str, bytes]], staging_area_path: Union[Path, str]) -> Iterator[str]: - yield from get_new_files_added(cmp, staging_area_path) - yield from get_changed_files(cmp, staging_area_path) - - -def get_changed_files(cmp: dircmp[Union[str, bytes]], staging_area_path) -> Iterator[str]: - diff_files = cmp.diff_files - start_path = os.path.join(get_directory_with_wit(Path.cwd()), '.wit', 'staging_area') - for diff in diff_files: - file_path = os.path.join(staging_area_path, diff) - - rel = os.path.relpath(file_path, start=start_path) - yield rel - - -def get_new_files_added(cmp: dircmp[Union[str, bytes]], staging_area_path: Union[Path, str]) -> Iterator[str]: - new_files_added = cmp.right_only - start_path = get_directory_with_wit(Path.cwd()) - for f in new_files_added: - f_path = os.path.join(staging_area_path, f) - if os.path.isfile(f_path): - yield f - else: - yield from get_all_files_in_directory_and_subs(f_path, start_path) - - -def get_changes_not_staged_for_commit( - repository: Union[Path, str], staging_area_path: Union[Path, str] -) -> Iterator[str]: - cmp = dircmp(repository, staging_area_path) - yield from get_changed_files(cmp, staging_area_path) - for common_dir in cmp.common_dirs: - path_in_repository = os.path.join(repository, common_dir) - path_in_staging_area = os.path.join(staging_area_path, common_dir) - yield from get_changes_not_staged_for_commit(path_in_repository, path_in_staging_area) - - -def get_untracked_files(repository: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: - cmp = dircmp(staging_area_path, repository, ignore=['.wit']) - yield from get_new_files_added(cmp, repository) # - - -class WitError(Exception): - pass - - -def is_init_status_command_correct(argv: list[str]) -> bool: - return len(argv) == 2 - - -def is_add_or_commit_command_correct(argv: list[str]) -> bool: - return len(argv) == 3 - - -if sys.argv[1] == 'init': - if is_init_status_command_correct(sys.argv): - init() - else: - print(fr"Usage: python {sys.argv[0]} init") - -elif sys.argv[1] == 'add': - if is_add_or_commit_command_correct(sys.argv): - add(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} add ") - -elif sys.argv[1] == 'commit': - if is_add_or_commit_command_correct(sys.argv): - commit(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} commit MESSAGE") - -elif sys.argv[1] == 'status': - if is_init_status_command_correct(sys.argv): - status() - else: - print(fr"Usage: python {sys.argv[0]} status") From 33097b946ae3fcb77d389967f9d0a989971a3da1 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Wed, 23 Feb 2022 21:34:33 +0200 Subject: [PATCH 23/73] start test_add. not finished --- project/add.py | 2 +- test_wit/file1.txt | 0 test_wit/folder1/file2.txt | 0 test_wit/folder1/folder2/file3.txt | 0 tests/conftest.py | 5 +-- tests/test_add.py | 51 +++++++++++++++++++++++++----- tests/test_init.py | 2 +- 7 files changed, 48 insertions(+), 12 deletions(-) delete mode 100644 test_wit/file1.txt delete mode 100644 test_wit/folder1/file2.txt delete mode 100644 test_wit/folder1/folder2/file3.txt diff --git a/project/add.py b/project/add.py index 0f42ed0..e2ecf32 100644 --- a/project/add.py +++ b/project/add.py @@ -1,4 +1,4 @@ -from errors import WitError +from project.errors import WitError import os from pathlib import Path diff --git a/test_wit/file1.txt b/test_wit/file1.txt deleted file mode 100644 index e69de29..0000000 diff --git a/test_wit/folder1/file2.txt b/test_wit/folder1/file2.txt deleted file mode 100644 index e69de29..0000000 diff --git a/test_wit/folder1/folder2/file3.txt b/test_wit/folder1/folder2/file3.txt deleted file mode 100644 index e69de29..0000000 diff --git a/tests/conftest.py b/tests/conftest.py index 007258c..8d7b6fb 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,5 @@ import os +import shutil from pathlib import Path import pytest @@ -17,5 +18,5 @@ def test_folder(): os.mkdir(folder2_path) file3_path = Path(folder2_path).joinpath('file3.txt') file3_path.write_text("") - return folder_name # yield? - # os.unlink(folder_name) + yield folder_name + shutil.rmtree(folder_name) diff --git a/tests/test_add.py b/tests/test_add.py index 4b0df3d..f33e7de 100644 --- a/tests/test_add.py +++ b/tests/test_add.py @@ -1,9 +1,44 @@ -# import os -# from pathlib import Path -# import pytest -# from project import add -# +import os +from pathlib import Path +import pytest +from project import add, init + + +# @pytest.mark.parametrize( +# 'file_path, parent', +# [ +# (Path('')) +# ] +# ) + + + +@pytest.mark.parametrize( + 'path, parent', + [ + (Path('test_wit').joinpath('file1.txt'), Path('test_wit')), + (Path('test_wit').joinpath('folder1', 'folder2'), Path('test_wit')), + (Path('test_wit').joinpath('folder1', 'folder2', 'file3'), Path('test_wit')) + ] +) +def test_get_directory_with_wit(test_folder, path, parent): + init.init(test_folder) + assert add.get_directory_with_wit(path) == parent + + +@pytest.mark.parametrize( + 'destination_in_wit, file, new_destination', + [ + (Path('file1.txt'), Path('test_wit').joinpath('file1.txt'), Path('test_wit')), + (Path('folder1').joinpath('folder2'), Path('test_wit')), + (Path('test_wit').joinpath('folder1', 'folder2', 'file3'), Path('test_wit')) + ] +) +def test_save_the_copy(test_folder, destination_in_wit, file, new_destination): + init.init(test_folder) + destination = Path('test_wit').joinpath('.wit', 'staging_area') + add.save_the_copy(destination.joinpath(destination_in_wit), file) + assert destination.joinpath(destination_in_wit).exists() + # def test_add(): -# os.mkdir('test_wit_files') -# Path('wit').joinpath('test_wit_1.txt').write_text('test') -# add() \ No newline at end of file +# pass \ No newline at end of file diff --git a/tests/test_init.py b/tests/test_init.py index a08a6b7..434e93b 100644 --- a/tests/test_init.py +++ b/tests/test_init.py @@ -1,6 +1,6 @@ -import os from pathlib import Path import pytest + from project import init From 6a78f968e333348830d109cd47bca5dc30411c14 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Wed, 23 Feb 2022 23:26:33 +0200 Subject: [PATCH 24/73] add graph to wit file --- project/graph.py | 2 ++ project/wit.py | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 project/graph.py diff --git a/project/graph.py b/project/graph.py new file mode 100644 index 0000000..67467df --- /dev/null +++ b/project/graph.py @@ -0,0 +1,2 @@ +def graph(): + pass \ No newline at end of file diff --git a/project/wit.py b/project/wit.py index f0d146d..c54f606 100644 --- a/project/wit.py +++ b/project/wit.py @@ -3,13 +3,14 @@ from checkout import checkout from commit import commit from init import init +from project.graph import graph from status import status import sys def is_command_correct(argv: list[str]) -> bool: - if argv[1] in {'init', 'status'}: + if argv[1] in {'init', 'status', 'graph'}: return len(argv) == 2 else: return len(argv) == 3 @@ -50,3 +51,9 @@ def is_command_correct(argv: list[str]) -> bool: branch(sys.argv[2]) else: print(fr"Usage: python {sys.argv[0]} branch ") + +elif sys.argv[1] == 'graph': + if is_command_correct(sys.argv): + graph() + else: + print(fr"Usage: python {sys.argv[0]} graph") From 6a833b33891f9594db360a2e67f4b5a144e4e623 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Fri, 25 Feb 2022 11:10:23 +0200 Subject: [PATCH 25/73] fix bugs --- problems.txt | 6 ++++++ project/add.py | 17 ++++++++++------- project/branch.py | 4 ++-- project/checkout.py | 35 +++++++++++++++++++++-------------- project/commit.py | 34 ++++++++++++++++------------------ project/graph.py | 22 +++++++++++++++++++++- project/status.py | 34 ++++++++++++++++++++++------------ project/wit.py | 2 +- tests/test_add.py | 2 +- 9 files changed, 100 insertions(+), 56 deletions(-) create mode 100644 problems.txt diff --git a/problems.txt b/problems.txt new file mode 100644 index 0000000..855ad00 --- /dev/null +++ b/problems.txt @@ -0,0 +1,6 @@ +add "C:\Users\israe\Desktop\test\folder1\folder2\folder3" -> status: +###Untracked files:### +file3.txt +instead of: +###Untracked files:### +folder2\file3.txt \ No newline at end of file diff --git a/project/add.py b/project/add.py index e2ecf32..3561b0b 100644 --- a/project/add.py +++ b/project/add.py @@ -1,4 +1,4 @@ -from project.errors import WitError +from errors import WitError import os from pathlib import Path @@ -7,18 +7,18 @@ def add(path_to_add: str) -> None: - file_to_add = Path(os.path.abspath(path_to_add)) - repository = get_directory_with_wit(file_to_add) + path = Path(os.path.abspath(path_to_add)) + repository = get_repository_path(path) if not repository: raise WitError("<.wit> file not found") destination = repository.joinpath('.wit', 'staging_area') - directories_to_copy = file_to_add.relative_to(repository).parts[:-1] + directories_to_copy = path.relative_to(repository).parts[:-1] for dir_name in directories_to_copy: dirs = os.listdir(destination) destination = destination.joinpath(dir_name) if dir_name not in dirs: destination.mkdir() - save_the_copy(destination, file_to_add) + save_the_copy(destination, path) def save_the_copy(destination: Path, file: Path) -> None: @@ -31,8 +31,11 @@ def save_the_copy(destination: Path, file: Path) -> None: shutil.copytree(file, destination_of_folder_if_doesnt_exists) -def get_directory_with_wit(file: Path) -> Optional[Path]: - for parent in file.parents: +def get_repository_path(path: Path) -> Optional[Path]: + if path.is_dir(): + if '.wit' in os.listdir(path): + return path + for parent in path.parents: dir_lst = os.listdir(parent) if '.wit' in dir_lst: return parent diff --git a/project/branch.py b/project/branch.py index 5b85721..fb90559 100644 --- a/project/branch.py +++ b/project/branch.py @@ -1,4 +1,4 @@ -from add import get_directory_with_wit +from add import get_repository_path from commit import get_parent_head from errors import WitError @@ -6,7 +6,7 @@ def branch(name: str) -> None: - repository = get_directory_with_wit(Path.cwd()) + repository = get_repository_path(Path.cwd()) if not repository: raise WitError("<.wit> file not found") references_file = repository.joinpath('.wit', 'references.txt') diff --git a/project/checkout.py b/project/checkout.py index 5122728..c2ef592 100644 --- a/project/checkout.py +++ b/project/checkout.py @@ -1,21 +1,22 @@ -from add import get_directory_with_wit +import re + +from add import get_repository_path from commit import get_parent_head from errors import FilesDoesntMatchError, WitError +from status import get_changes_to_be_committed, get_changes_not_staged_for_commit, get_all_files_in_directory_and_subs import os from pathlib import Path import shutil -from status import get_changes_to_be_committed, get_changes_not_staged_for_commit, get_all_files_in_directory_and_subs - def checkout(commit_id_or_branch: str) -> None: - repository = get_directory_with_wit(Path.cwd()) + repository = get_repository_path(Path.cwd()) + if not repository: + raise WitError("<.wit> file not found") staging_area_path = os.path.join(repository, '.wit', 'staging_area') last_commit_id = get_parent_head(repository) last_commit_path = os.path.join(repository, '.wit', 'images', last_commit_id) - if not repository: - raise WitError("<.wit> file not found") if ( list(get_changes_to_be_committed(last_commit_path, staging_area_path)) or list(get_changes_not_staged_for_commit(repository, staging_area_path)) @@ -46,15 +47,21 @@ def change_head_in_references_file(commit_id: str, references_file: Path) -> Non def get_commit_id_of_branch(commit_id_or_branch: str, references_file: Path) -> str: + branch_regex = re.compile(r"^(?P\w+)=(?P\w){20}$") with references_file.open() as file: - references_content = file.readlines() - branches_data = references_content[1:] - for branch_line in branches_data: - name_and_id = branch_line.split('=') - branch_name = name_and_id[0] - branch_id = name_and_id[1].strip() - if branch_name == commit_id_or_branch: - return branch_id + for line in file: + match = branch_regex.match(line) + if match.groupdict()['branch_name'] == commit_id_or_branch: + return match.groupdict()['branch_id'] + # references_content = file.readlines() + # branches_data = references_content[1:] + + # for branch_line in branches_data: + # name_and_id = branch_line.split('=') + # branch_name = name_and_id[0] + # branch_id = name_and_id[1].strip() + # if branch_name == commit_id_or_branch: + # return branch_id return commit_id_or_branch diff --git a/project/commit.py b/project/commit.py index 2d064ce..aaa0698 100644 --- a/project/commit.py +++ b/project/commit.py @@ -1,9 +1,7 @@ -from add import get_directory_with_wit - -import datetime - +from add import get_repository_path from errors import WitError +import datetime import os from pathlib import Path import random @@ -11,15 +9,15 @@ def commit(message: str) -> None: - dir_with_wit = get_directory_with_wit(Path.cwd()) - if not dir_with_wit: + repository = get_repository_path(Path.cwd()) + if not repository: raise WitError("<.wit> file not found") - images_path = dir_with_wit.joinpath('.wit', 'images') + images_path = repository.joinpath('.wit', 'images') path_of_new_folder = create_commit_folder(images_path) - create_commit_txt_file(dir_with_wit, images_path, path_of_new_folder, message) - save_files(dir_with_wit, path_of_new_folder) + create_commit_txt_file(repository, images_path, path_of_new_folder, message) + save_files(repository, path_of_new_folder) commit_id = os.path.basename(path_of_new_folder) - write_references(commit_id, dir_with_wit) + write_references(commit_id, repository) def create_commit_folder(images_path: Path) -> str: @@ -36,8 +34,8 @@ def create_folder_name(): return folder_name -def create_commit_txt_file(dir_with_wit: Path, images_path: Path, path_of_new_folder: str, message: str) -> None: - parent_head = get_parent_head(dir_with_wit) +def create_commit_txt_file(repository: Path, images_path: Path, path_of_new_folder: str, message: str) -> None: + parent_head = get_parent_head(repository) txt_file = images_path.joinpath(Path(path_of_new_folder).name + '.txt') txt_file.write_text( f'parent = {parent_head if parent_head else None}\n' @@ -46,8 +44,8 @@ def create_commit_txt_file(dir_with_wit: Path, images_path: Path, path_of_new_fo ) -def get_parent_head(dir_with_wit: Path) -> str: - wit_folder = dir_with_wit.joinpath('.wit') +def get_parent_head(repository: Path) -> str: + wit_folder = repository.joinpath('.wit') references_file = wit_folder.joinpath('references.txt') if references_file.exists(): ref_path = wit_folder.joinpath('references.txt') @@ -58,8 +56,8 @@ def get_parent_head(dir_with_wit: Path) -> str: return '' -def save_files(dir_with_wit: Path, path_of_new_folder: str) -> None: - staging_area_path = os.path.join(dir_with_wit, '.wit', 'staging_area') +def save_files(repository: Path, path_of_new_folder: str) -> None: + staging_area_path = os.path.join(repository, '.wit', 'staging_area') for item in os.listdir(staging_area_path): src = os.path.join(staging_area_path, item) dst = os.path.join(path_of_new_folder, item) @@ -69,8 +67,8 @@ def save_files(dir_with_wit: Path, path_of_new_folder: str) -> None: shutil.copytree(src, dst) -def write_references(commit_id: str, dir_with_wit: Path) -> None: - wit_folder = dir_with_wit.joinpath('.wit') +def write_references(commit_id: str, repository: Path) -> None: + wit_folder = repository.joinpath('.wit') ref_file = wit_folder.joinpath('references.txt') activated_path = wit_folder.joinpath('activated.txt') activated_branch = activated_path.read_text() diff --git a/project/graph.py b/project/graph.py index 67467df..9890b9c 100644 --- a/project/graph.py +++ b/project/graph.py @@ -1,2 +1,22 @@ +import graphviz +from pathlib import Path + +from add import get_repository_path +from errors import WitError + + def graph(): - pass \ No newline at end of file + repository = get_repository_path(Path.cwd()) + if not repository: + raise WitError("<.wit> file not found") + +# +# dot = graphviz.Digraph(comment='The Round Table') +# +# dot.node('A', 'King Arthur') +# dot.node('B', 'Sir Bedevere the Wise') +# dot.node('L', 'Sir Lancelot the Brave') +# dot.edges(['AB', 'AL']) +# dot.edge('B', 'L', constraint='false') +# +# dot.render('FileName', view=True) \ No newline at end of file diff --git a/project/status.py b/project/status.py index 58d8a5b..0a03f7b 100644 --- a/project/status.py +++ b/project/status.py @@ -1,4 +1,4 @@ -from add import get_directory_with_wit +from add import get_repository_path from commit import get_parent_head from errors import WitError @@ -8,24 +8,34 @@ from typing import Union, Iterator -def status() -> None: - repository = get_directory_with_wit(Path.cwd()) +def status(): + repository = get_repository_path(Path.cwd()) if not repository: raise WitError("<.wit> file not found") + staging_area_path = os.path.join(repository, '.wit', 'staging_area') commit_id = get_parent_head(repository) + print(commit_id) + message_if_no_commit = "No commit was done yet." commit_path = os.path.join(repository, '.wit', 'images', commit_id) - staging_area_path = os.path.join(repository, '.wit', 'staging_area') - changes_to_be_committed = list(get_changes_to_be_committed(commit_path, staging_area_path)) - changes_not_staged_for_commit = list(get_changes_not_staged_for_commit(repository, staging_area_path)) - untracked_files = list(get_untracked_files(repository, staging_area_path)) + print(commit_path) + changes_to_be_committed = show_files(get_changes_to_be_committed(commit_path, staging_area_path)) + changes_not_staged_for_commit = show_files(get_changes_not_staged_for_commit(repository, staging_area_path)) + untracked_files = show_files(get_untracked_files(repository, staging_area_path)) print( - f"Commit id: {commit_id}\n" - f"Changes to be committed: {changes_to_be_committed}\n" - f"Changes not staged for commit: {changes_not_staged_for_commit}\n" - f"Untracked files: {untracked_files}" + f"###Commit id:###\n{commit_id if commit_id else message_if_no_commit}\n\n" + f"###Changes to be committed:###\n{changes_to_be_committed}\n\n" + f"###Changes not staged for commit:###\n{changes_not_staged_for_commit}\n\n" + f"###Untracked files:###\n{untracked_files}\n" ) +def show_files(files: Iterator[str]) -> str: + files_str = "" + for file_path in files: + files_str += f"{file_path}\n" + return files_str + + def get_all_files_in_directory_and_subs(directory: Union[Path, str], start_path: Union[Path, str]) -> Iterator[str]: for (root, dirs, files) in os.walk(directory, topdown=True): for file in files: @@ -48,7 +58,7 @@ def get_new_and_changed_files(cmp: dircmp[Union[str, bytes]], staging_area_path: def get_changed_files(cmp: dircmp[Union[str, bytes]], staging_area_path) -> Iterator[str]: diff_files = cmp.diff_files - start_path = os.path.join(get_directory_with_wit(Path.cwd()), '.wit', 'staging_area') + start_path = os.path.join(get_repository_path(Path.cwd()), '.wit', 'staging_area') for diff in diff_files: file_path = os.path.join(staging_area_path, diff) rel = os.path.relpath(file_path, start=start_path) diff --git a/project/wit.py b/project/wit.py index c54f606..8a6d29e 100644 --- a/project/wit.py +++ b/project/wit.py @@ -3,7 +3,7 @@ from checkout import checkout from commit import commit from init import init -from project.graph import graph +from graph import graph from status import status import sys diff --git a/tests/test_add.py b/tests/test_add.py index f33e7de..590d587 100644 --- a/tests/test_add.py +++ b/tests/test_add.py @@ -23,7 +23,7 @@ ) def test_get_directory_with_wit(test_folder, path, parent): init.init(test_folder) - assert add.get_directory_with_wit(path) == parent + assert add.get_repository_path(path) == parent @pytest.mark.parametrize( From 3f9b4ffd0a5bbd1b6268db90618587e548822aa1 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Sun, 27 Feb 2022 11:22:18 +0200 Subject: [PATCH 26/73] status almost fixed. wrote problem in the file --- project/status.py | 67 +++++++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/project/status.py b/project/status.py index 0a03f7b..8fbc09e 100644 --- a/project/status.py +++ b/project/status.py @@ -1,12 +1,17 @@ -from add import get_repository_path -from commit import get_parent_head -from errors import WitError - from filecmp import dircmp import os from pathlib import Path from typing import Union, Iterator +from add import get_repository_path +from commit import get_parent_head +from errors import WitError + +# Problems: +# Untracked files: if I add folders or files to folder2 (test\folder1\folder2) or to folder inside it- +# they don't appear in Untracked files. +# . + def status(): repository = get_repository_path(Path.cwd()) @@ -14,10 +19,8 @@ def status(): raise WitError("<.wit> file not found") staging_area_path = os.path.join(repository, '.wit', 'staging_area') commit_id = get_parent_head(repository) - print(commit_id) message_if_no_commit = "No commit was done yet." commit_path = os.path.join(repository, '.wit', 'images', commit_id) - print(commit_path) changes_to_be_committed = show_files(get_changes_to_be_committed(commit_path, staging_area_path)) changes_not_staged_for_commit = show_files(get_changes_not_staged_for_commit(repository, staging_area_path)) untracked_files = show_files(get_untracked_files(repository, staging_area_path)) @@ -30,55 +33,56 @@ def status(): def show_files(files: Iterator[str]) -> str: - files_str = "" - for file_path in files: - files_str += f"{file_path}\n" - return files_str + return '\n'.join(files) def get_all_files_in_directory_and_subs(directory: Union[Path, str], start_path: Union[Path, str]) -> Iterator[str]: - for (root, dirs, files) in os.walk(directory, topdown=True): + for root, dirs, files in os.walk(directory, topdown=True): + if not files and not dirs: + yield os.path.relpath(root, start_path) for file in files: - file_path = os.path.join(root, file) - rel = os.path.relpath(file_path, start=start_path) - yield rel + file_abs_path = os.path.join(root, file) + yield os.path.relpath(file_abs_path, start_path) + for dir_name in dirs: + yield from get_all_files_in_directory_and_subs(dir_name, os.path.join(start_path, dir_name)) def get_changes_to_be_committed(commit_path: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: + """Yield files that the user added to staging area since last commit and will be added to the next commit.""" cmp = dircmp(commit_path, staging_area_path) yield from get_new_and_changed_files(cmp, staging_area_path) for d, d_cmp in cmp.subdirs.items(): yield from get_new_and_changed_files(d_cmp, os.path.join(staging_area_path, d)) -def get_new_and_changed_files(cmp: dircmp[Union[str, bytes]], staging_area_path: Union[Path, str]) -> Iterator[str]: - yield from get_new_files_added(cmp, staging_area_path) - yield from get_changed_files(cmp, staging_area_path) +def get_new_and_changed_files(cmp: dircmp[Union[str, bytes]], dir_path: Union[Path, str]) -> Iterator[str]: + """Yield files that are new in the directory or have different content.""" + yield from get_new_files_added(cmp, dir_path) + yield from get_changed_files(cmp, dir_path) -def get_changed_files(cmp: dircmp[Union[str, bytes]], staging_area_path) -> Iterator[str]: +def get_changed_files(cmp: dircmp[Union[str, bytes]], dir_path: Union[Path, str]) -> Iterator[str]: + """Yield files that have different content.""" diff_files = cmp.diff_files start_path = os.path.join(get_repository_path(Path.cwd()), '.wit', 'staging_area') for diff in diff_files: - file_path = os.path.join(staging_area_path, diff) + file_path = os.path.join(dir_path, diff) rel = os.path.relpath(file_path, start=start_path) yield rel -def get_new_files_added(cmp: dircmp[Union[str, bytes]], staging_area_path: Union[Path, str]) -> Iterator[str]: +def get_new_files_added(cmp: dircmp[Union[str, bytes]], dir_path: Union[Path, str], start_path=None) -> Iterator[str]: + """Yield files that are new in the directory.""" new_files_added = cmp.right_only - start_path = staging_area_path for f in new_files_added: - f_path = os.path.join(staging_area_path, f) + f_path = os.path.join(dir_path, f) if os.path.isfile(f_path): - yield f - else: - yield from get_all_files_in_directory_and_subs(f_path, start_path) + yield f if not start_path else os.path.relpath(f_path, start=start_path) + yield from get_all_files_in_directory_and_subs(f_path, start_path=dir_path if not start_path else start_path) -def get_changes_not_staged_for_commit( - repository: Union[Path, str], staging_area_path: Union[Path, str] -) -> Iterator[str]: +def get_changes_not_staged_for_commit(repository: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: + """Yield files in staging area which their content in repository doesn't match their content in staging area.""" cmp = dircmp(repository, staging_area_path) yield from get_changed_files(cmp, staging_area_path) for common_dir in cmp.common_dirs: @@ -88,9 +92,8 @@ def get_changes_not_staged_for_commit( def get_untracked_files(repository: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: + """Yield files that exist only in repository and were never added to staging area.""" cmp = dircmp(staging_area_path, repository, ignore=['.wit']) yield from get_new_files_added(cmp, repository) - for common_dir in cmp.common_dirs: - path_in_repository = os.path.join(repository, common_dir) - path_in_staging_area = os.path.join(staging_area_path, common_dir) - yield from get_untracked_files(path_in_repository, path_in_staging_area) + for d, d_cmp in cmp.subdirs.items(): + yield from get_new_files_added(d_cmp, os.path.join(repository, d), start_path=repository) From 02bb584e53bc05329bf78c3d5b246def095ce3ba Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Mon, 28 Feb 2022 08:50:08 +0200 Subject: [PATCH 27/73] add status problem description --- .gitignore | 3 ++- problems.txt | 5 ++++- project/status.py | 5 ++--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 46b6905..3589f50 100644 --- a/.gitignore +++ b/.gitignore @@ -130,4 +130,5 @@ dmypy.json .wit .idea __pycache__ -wit_exercises \ No newline at end of file +wit_exercises +problems.txt \ No newline at end of file diff --git a/problems.txt b/problems.txt index 855ad00..00b0721 100644 --- a/problems.txt +++ b/problems.txt @@ -3,4 +3,7 @@ add "C:\Users\israe\Desktop\test\folder1\folder2\folder3" -> status: file3.txt instead of: ###Untracked files:### -folder2\file3.txt \ No newline at end of file +folder2\file3.txt + +###Changes to be committed:### +folder2\folder3\file4.txt \ No newline at end of file diff --git a/project/status.py b/project/status.py index 8fbc09e..fbd69c1 100644 --- a/project/status.py +++ b/project/status.py @@ -8,9 +8,8 @@ from errors import WitError # Problems: -# Untracked files: if I add folders or files to folder2 (test\folder1\folder2) or to folder inside it- -# they don't appear in Untracked files. -# . +# Untracked files: if I do "add" to a file/ folder inside folder 1 (test\folder1\folder2\...) - +# all other files/ folders inside don't appear in Untracked files. def status(): From 4a08aaa52f80039418a4be1c8948182c3d2d3799 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Mon, 28 Feb 2022 09:16:39 +0200 Subject: [PATCH 28/73] problems in 2 functions --- project/status.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/project/status.py b/project/status.py index fbd69c1..aaf7b11 100644 --- a/project/status.py +++ b/project/status.py @@ -7,10 +7,6 @@ from commit import get_parent_head from errors import WitError -# Problems: -# Untracked files: if I do "add" to a file/ folder inside folder 1 (test\folder1\folder2\...) - -# all other files/ folders inside don't appear in Untracked files. - def status(): repository = get_repository_path(Path.cwd()) @@ -48,6 +44,7 @@ def get_all_files_in_directory_and_subs(directory: Union[Path, str], start_path: def get_changes_to_be_committed(commit_path: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: """Yield files that the user added to staging area since last commit and will be added to the next commit.""" + # sometimes I get the full path of the file and sometimes only the file name. cmp = dircmp(commit_path, staging_area_path) yield from get_new_and_changed_files(cmp, staging_area_path) for d, d_cmp in cmp.subdirs.items(): @@ -92,7 +89,19 @@ def get_changes_not_staged_for_commit(repository: Union[Path, str], staging_area def get_untracked_files(repository: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: """Yield files that exist only in repository and were never added to staging area.""" + # this gives all untracked files, but I didn't succeed to get full path correctly: + cmp = dircmp(staging_area_path, repository, ignore=['.wit']) + yield from get_new_files_added(cmp, repository) + for common_dir in cmp.common_dirs: + path_in_repository = os.path.join(repository, common_dir) + path_in_staging_area = os.path.join(staging_area_path, common_dir) + yield from get_untracked_files(path_in_repository, path_in_staging_area) + """ + here I managed to get full path correctly, but if I do "add" to a file / folder inside folder 1 + (test\folder1\folder2\...) - all other files/ folders inside don't appear in Untracked files. + cmp = dircmp(staging_area_path, repository, ignore=['.wit']) yield from get_new_files_added(cmp, repository) for d, d_cmp in cmp.subdirs.items(): yield from get_new_files_added(d_cmp, os.path.join(repository, d), start_path=repository) + """ From 974bff15748586db66fa6cc9bb41127816683a94 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Mon, 28 Feb 2022 15:16:39 +0200 Subject: [PATCH 29/73] commit before check. problems in status --- .gitignore | 3 ++- problems.txt | 26 ++++++++++++++-------- project/add.py | 4 ++-- project/branch.py | 4 ++-- project/checkout.py | 54 +++++++++++++++++++++++---------------------- project/commit.py | 25 +++++++++++++-------- project/errors.py | 4 ++++ project/status.py | 23 +++++++++---------- 8 files changed, 82 insertions(+), 61 deletions(-) diff --git a/.gitignore b/.gitignore index 3589f50..36abbd8 100644 --- a/.gitignore +++ b/.gitignore @@ -131,4 +131,5 @@ dmypy.json .idea __pycache__ wit_exercises -problems.txt \ No newline at end of file +problems.txt +project\graph.py \ No newline at end of file diff --git a/problems.txt b/problems.txt index 00b0721..2e772c8 100644 --- a/problems.txt +++ b/problems.txt @@ -1,9 +1,17 @@ -add "C:\Users\israe\Desktop\test\folder1\folder2\folder3" -> status: -###Untracked files:### -file3.txt -instead of: -###Untracked files:### -folder2\file3.txt - -###Changes to be committed:### -folder2\folder3\file4.txt \ No newline at end of file +init > status > untracked: OK. all files. full path. + +add file1 > status: still OK. + +commit > status OK. + +add "C:\Users\israe\Desktop\test\folder1\folder2\folder3" > status: Untracked with files names only. + +commit > Untracked still with names. + +branch + checkout branch > status same + +add "C:\Users\israe\Desktop\test\folder1\folder2\file3.txt" > status: file not in Changes to be committed. + +change file > file appears only in Changes not staged for commit. + +commit > same diff --git a/project/add.py b/project/add.py index 3561b0b..d768d5b 100644 --- a/project/add.py +++ b/project/add.py @@ -1,10 +1,10 @@ -from errors import WitError - import os from pathlib import Path import shutil from typing import Optional +from errors import WitError + def add(path_to_add: str) -> None: path = Path(os.path.abspath(path_to_add)) diff --git a/project/branch.py b/project/branch.py index fb90559..a668394 100644 --- a/project/branch.py +++ b/project/branch.py @@ -1,9 +1,9 @@ +from pathlib import Path + from add import get_repository_path from commit import get_parent_head from errors import WitError -from pathlib import Path - def branch(name: str) -> None: repository = get_repository_path(Path.cwd()) diff --git a/project/checkout.py b/project/checkout.py index c2ef592..5d64b0d 100644 --- a/project/checkout.py +++ b/project/checkout.py @@ -1,22 +1,20 @@ -import re - -from add import get_repository_path -from commit import get_parent_head -from errors import FilesDoesntMatchError, WitError -from status import get_changes_to_be_committed, get_changes_not_staged_for_commit, get_all_files_in_directory_and_subs - import os from pathlib import Path import shutil +from add import get_repository_path +from commit import get_parent_head, get_commit_id_of_branch +from errors import FilesDoesntMatchError, WitError, BranchDoesntExistError +from status import get_changes_to_be_committed, get_changes_not_staged_for_commit, get_all_files_in_directory_and_subs + def checkout(commit_id_or_branch: str) -> None: repository = get_repository_path(Path.cwd()) - if not repository: - raise WitError("<.wit> file not found") staging_area_path = os.path.join(repository, '.wit', 'staging_area') last_commit_id = get_parent_head(repository) last_commit_path = os.path.join(repository, '.wit', 'images', last_commit_id) + if not repository: + raise WitError("<.wit> file not found") if ( list(get_changes_to_be_committed(last_commit_path, staging_area_path)) or list(get_changes_not_staged_for_commit(repository, staging_area_path)) @@ -24,6 +22,8 @@ def checkout(commit_id_or_branch: str) -> None: raise FilesDoesntMatchError("There are files added or changed after last commit") references_file = repository.joinpath('.wit', 'references.txt') commit_id = get_commit_id_of_branch(commit_id_or_branch, references_file) + if not commit_id: + raise BranchDoesntExistError("Branch doesn't exist.") if commit_id != commit_id_or_branch: write_activated(commit_id_or_branch, repository) commit_path = os.path.join(repository, '.wit', 'images', commit_id) @@ -46,23 +46,25 @@ def change_head_in_references_file(commit_id: str, references_file: Path) -> Non references_file.write_text(f'HEAD={commit_id}\n{branches_txt}') -def get_commit_id_of_branch(commit_id_or_branch: str, references_file: Path) -> str: - branch_regex = re.compile(r"^(?P\w+)=(?P\w){20}$") - with references_file.open() as file: - for line in file: - match = branch_regex.match(line) - if match.groupdict()['branch_name'] == commit_id_or_branch: - return match.groupdict()['branch_id'] - # references_content = file.readlines() - # branches_data = references_content[1:] - - # for branch_line in branches_data: - # name_and_id = branch_line.split('=') - # branch_name = name_and_id[0] - # branch_id = name_and_id[1].strip() - # if branch_name == commit_id_or_branch: - # return branch_id - return commit_id_or_branch +# def get_commit_id_of_branch(commit_id_or_branch: str, references_file: Path) -> str: +# branch_regex = re.compile(r"^(?P\w+)=(?P\w{20})$") +# with references_file.open() as file: +# for line in file: +# match = branch_regex.match(line) +# # print(f"match.groupdict()['branch_name']: {match.groupdict()['branch_name']}") +# # print(f"match.groupdict()['branch_id']: {match.groupdict()['branch_id']}") +# if match.groupdict()['branch_name'] == commit_id_or_branch: +# return match.groupdict()['branch_id'] +# # references_content = file.readlines() +# # branches_data = references_content[1:] +# +# # for branch_line in branches_data: +# # name_and_id = branch_line.split('=') +# # branch_name = name_and_id[0] +# # branch_id = name_and_id[1].strip() +# # if branch_name == commit_id_or_branch: +# # return branch_id +# return commit_id_or_branch def change_files_in_main_folder(commit_path: str, repository: Path) -> None: diff --git a/project/commit.py b/project/commit.py index aaa0698..be1610e 100644 --- a/project/commit.py +++ b/project/commit.py @@ -1,12 +1,13 @@ -from add import get_repository_path -from errors import WitError - import datetime import os from pathlib import Path import random +import re import shutil +from add import get_repository_path +from errors import WitError + def commit(message: str) -> None: repository = get_repository_path(Path.cwd()) @@ -44,15 +45,21 @@ def create_commit_txt_file(repository: Path, images_path: Path, path_of_new_fold ) +def get_commit_id_of_branch(branch: str, references_file: Path) -> str: + branch_regex = re.compile(r"^(?P\w+)=(?P\w{20})$") + with references_file.open() as file: + for line in file: + match = branch_regex.match(line) + if match.groupdict()['branch_name'] == branch: + return match.groupdict()['branch_id'] + return branch if branch.isdigit() else '' + + def get_parent_head(repository: Path) -> str: wit_folder = repository.joinpath('.wit') references_file = wit_folder.joinpath('references.txt') if references_file.exists(): - ref_path = wit_folder.joinpath('references.txt') - with ref_path.open() as f_h: - references_content = f_h.readlines() - head_line = references_content[0].split('=') - return head_line[1].strip() + return get_commit_id_of_branch('HEAD', references_file) return '' @@ -86,5 +93,5 @@ def write_references(commit_id: str, repository: Path) -> None: activated_id = branch_id if activated_id == current_head_id: line = "=".join((branch_name, commit_id)) - new_content += line + new_content += line + "\n" ref_file.write_text(f'HEAD={commit_id}\n{new_content}') diff --git a/project/errors.py b/project/errors.py index eb31492..622630c 100644 --- a/project/errors.py +++ b/project/errors.py @@ -4,3 +4,7 @@ class WitError(Exception): class FilesDoesntMatchError(Exception): pass + + +class BranchDoesntExistError(Exception): + pass diff --git a/project/status.py b/project/status.py index aaf7b11..0699326 100644 --- a/project/status.py +++ b/project/status.py @@ -7,6 +7,10 @@ from commit import get_parent_head from errors import WitError +# If I do "add" to a file / folder inside folder 1 (test\folder1\folder2\...) - +# sometimes all other files/ folders inside don't appear in Untracked files. +# and other times they don't appear in Changes to be committed. Very weired... + def status(): repository = get_repository_path(Path.cwd()) @@ -89,19 +93,14 @@ def get_changes_not_staged_for_commit(repository: Union[Path, str], staging_area def get_untracked_files(repository: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: """Yield files that exist only in repository and were never added to staging area.""" - # this gives all untracked files, but I didn't succeed to get full path correctly: - cmp = dircmp(staging_area_path, repository, ignore=['.wit']) - yield from get_new_files_added(cmp, repository) - for common_dir in cmp.common_dirs: - path_in_repository = os.path.join(repository, common_dir) - path_in_staging_area = os.path.join(staging_area_path, common_dir) - yield from get_untracked_files(path_in_repository, path_in_staging_area) - """ - here I managed to get full path correctly, but if I do "add" to a file / folder inside folder 1 - (test\folder1\folder2\...) - all other files/ folders inside don't appear in Untracked files. - + # # this gives all untracked files, but I didn't succeed to get full path correctly: + # cmp = dircmp(staging_area_path, repository, ignore=['.wit']) + # yield from get_new_files_added(cmp, repository) + # for common_dir in cmp.common_dirs: + # path_in_repository = os.path.join(repository, common_dir) + # path_in_staging_area = os.path.join(staging_area_path, common_dir) + # yield from get_untracked_files(path_in_repository, path_in_staging_area) cmp = dircmp(staging_area_path, repository, ignore=['.wit']) yield from get_new_files_added(cmp, repository) for d, d_cmp in cmp.subdirs.items(): yield from get_new_files_added(d_cmp, os.path.join(repository, d), start_path=repository) - """ From 1ec54f326313377a5f1b8a32028dbd282adcdde3 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Mon, 28 Feb 2022 15:24:44 +0200 Subject: [PATCH 30/73] commit before check. problems in status --- .gitignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 36abbd8..a707d19 100644 --- a/.gitignore +++ b/.gitignore @@ -131,5 +131,5 @@ dmypy.json .idea __pycache__ wit_exercises -problems.txt -project\graph.py \ No newline at end of file +C:\Users\israe\projects\wit_project\wit\problems.txt +C:\Users\israe\projects\wit_project\wit\project\graph.py \ No newline at end of file From 660cf90ff97414dbacbc87684dafea91ffbfe091 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Tue, 1 Mar 2022 10:57:49 +0200 Subject: [PATCH 31/73] add graph, fix commit and checkout --- .gitignore | 3 +-- problems.txt | 17 ----------------- project/add.py | 4 ++++ project/checkout.py | 4 +++- project/commit.py | 42 ++++++++++++++++++++++------------------- project/graph.py | 46 ++++++++++++++++++++++++++++++++++----------- project/status.py | 9 +++++++-- 7 files changed, 73 insertions(+), 52 deletions(-) delete mode 100644 problems.txt diff --git a/.gitignore b/.gitignore index a707d19..efdc847 100644 --- a/.gitignore +++ b/.gitignore @@ -131,5 +131,4 @@ dmypy.json .idea __pycache__ wit_exercises -C:\Users\israe\projects\wit_project\wit\problems.txt -C:\Users\israe\projects\wit_project\wit\project\graph.py \ No newline at end of file +/tests/ diff --git a/problems.txt b/problems.txt deleted file mode 100644 index 2e772c8..0000000 --- a/problems.txt +++ /dev/null @@ -1,17 +0,0 @@ -init > status > untracked: OK. all files. full path. - -add file1 > status: still OK. - -commit > status OK. - -add "C:\Users\israe\Desktop\test\folder1\folder2\folder3" > status: Untracked with files names only. - -commit > Untracked still with names. - -branch + checkout branch > status same - -add "C:\Users\israe\Desktop\test\folder1\folder2\file3.txt" > status: file not in Changes to be committed. - -change file > file appears only in Changes not staged for commit. - -commit > same diff --git a/project/add.py b/project/add.py index d768d5b..2c71d69 100644 --- a/project/add.py +++ b/project/add.py @@ -13,8 +13,11 @@ def add(path_to_add: str) -> None: raise WitError("<.wit> file not found") destination = repository.joinpath('.wit', 'staging_area') directories_to_copy = path.relative_to(repository).parts[:-1] + # print(f"directories_to_copy: {directories_to_copy}") for dir_name in directories_to_copy: + # print(f"dir name: {dir_name}") dirs = os.listdir(destination) + # print(f"dirs: {dirs}") destination = destination.joinpath(dir_name) if dir_name not in dirs: destination.mkdir() @@ -26,6 +29,7 @@ def save_the_copy(destination: Path, file: Path) -> None: shutil.copy2(file, destination) else: destination_of_folder_if_doesnt_exists = destination.joinpath(file.name) + # print(f"destination_of_folder_if_doesnt_exists: {destination_of_folder_if_doesnt_exists}") if destination_of_folder_if_doesnt_exists.exists(): shutil.rmtree(destination_of_folder_if_doesnt_exists) shutil.copytree(file, destination_of_folder_if_doesnt_exists) diff --git a/project/checkout.py b/project/checkout.py index 5d64b0d..a82777b 100644 --- a/project/checkout.py +++ b/project/checkout.py @@ -3,7 +3,7 @@ import shutil from add import get_repository_path -from commit import get_parent_head, get_commit_id_of_branch +from commit import get_commit_id_of_branch, get_parent_head from errors import FilesDoesntMatchError, WitError, BranchDoesntExistError from status import get_changes_to_be_committed, get_changes_not_staged_for_commit, get_all_files_in_directory_and_subs @@ -70,7 +70,9 @@ def change_head_in_references_file(commit_id: str, references_file: Path) -> Non def change_files_in_main_folder(commit_path: str, repository: Path) -> None: files_committed = get_all_files_in_directory_and_subs(commit_path, commit_path) for committed_file in files_committed: + # print(f"committed file: {committed_file}") path_in_commit = os.path.join(commit_path, committed_file) + # print(path_in_commit) with open(path_in_commit, 'r') as committed_file_h: content = committed_file_h.read() path_in_repository = os.path.join(repository, committed_file) diff --git a/project/commit.py b/project/commit.py index be1610e..3df20e4 100644 --- a/project/commit.py +++ b/project/commit.py @@ -28,7 +28,7 @@ def create_commit_folder(images_path: Path) -> str: return path_of_new_folder -def create_folder_name(): +def create_folder_name() -> str: length = 20 chars = '1234567890abcdef' folder_name = ''.join(random.choices(chars, k=length)) @@ -52,13 +52,14 @@ def get_commit_id_of_branch(branch: str, references_file: Path) -> str: match = branch_regex.match(line) if match.groupdict()['branch_name'] == branch: return match.groupdict()['branch_id'] - return branch if branch.isdigit() else '' + return branch def get_parent_head(repository: Path) -> str: wit_folder = repository.joinpath('.wit') references_file = wit_folder.joinpath('references.txt') if references_file.exists(): + # print(get_commit_id_of_branch('HEAD', references_file)) return get_commit_id_of_branch('HEAD', references_file) return '' @@ -76,22 +77,25 @@ def save_files(repository: Path, path_of_new_folder: str) -> None: def write_references(commit_id: str, repository: Path) -> None: wit_folder = repository.joinpath('.wit') - ref_file = wit_folder.joinpath('references.txt') + references_file = wit_folder.joinpath('references.txt') + parent_head = get_parent_head(repository) + # print(parent_head) activated_path = wit_folder.joinpath('activated.txt') activated_branch = activated_path.read_text() - new_content = '='.join((activated_branch, commit_id)) # ??? - if ref_file.exists(): - with open(ref_file, "r") as references_file: - data = references_file.readlines() - current_head_id = data[0].split("=")[1].strip() - branches_data = data[1:] - new_content = "" - for line in branches_data: - branch_name = line.split("=")[0] - branch_id = line.split("=")[1].strip() - if branch_name == activated_branch: - activated_id = branch_id - if activated_id == current_head_id: - line = "=".join((branch_name, commit_id)) - new_content += line + "\n" - ref_file.write_text(f'HEAD={commit_id}\n{new_content}') + if references_file.exists(): + change_head_and_branch_id(activated_branch, commit_id, parent_head, references_file) + else: + references_file.write_text(f'HEAD={commit_id}\n{"=".join((activated_branch, commit_id))}') + + +def change_head_and_branch_id(activated_branch: str, commit_id: str, parent_head: str, references_file: Path) -> None: + regex = re.compile(fr"^{activated_branch}={parent_head}$", flags=re.MULTILINE) + head_regex = re.compile(fr"^HEAD={parent_head}$", flags=re.MULTILINE) + # print(regex) + data = references_file.read_text() + match = regex.findall(data) + # print(match) + if match: + new = regex.sub(f"{activated_branch}={commit_id}", data) + new = head_regex.sub(f"HEAD={commit_id}", new) + references_file.write_text(new) diff --git a/project/graph.py b/project/graph.py index 9890b9c..a66a314 100644 --- a/project/graph.py +++ b/project/graph.py @@ -1,7 +1,10 @@ -import graphviz +from graphviz import Digraph from pathlib import Path +import re + from add import get_repository_path +from commit import get_parent_head from errors import WitError @@ -9,14 +12,35 @@ def graph(): repository = get_repository_path(Path.cwd()) if not repository: raise WitError("<.wit> file not found") + current_commit_id = get_parent_head(repository) + commit_id = current_commit_id + dot = init_graph() + wit_dir = repository.joinpath('.wit') + images_path = wit_dir.joinpath('images') + regex = re.compile(r"^parent = (?P\w{20})$", flags=re.MULTILINE) + while commit_id: + commit_file = images_path.joinpath(f"{commit_id}.txt") + create_node(commit_id, dot) + commit_txt = commit_file.read_text() + parent_id_match = regex.match(commit_txt) + if parent_id_match: + parent_id = parent_id_match.group('commit_id') + # print(f"***********parent id: {parent_id}*************") + create_node(parent_id, dot) + dot.edge(commit_id, parent_id) + commit_id = parent_id if parent_id_match else None + dot.render(f'Graph {current_commit_id}', wit_dir, view=True, cleanup=True) + + +def create_node(commit_id: str, dot: Digraph) -> None: + dot.node(commit_id, commit_id[:6] + '...') + -# -# dot = graphviz.Digraph(comment='The Round Table') -# -# dot.node('A', 'King Arthur') -# dot.node('B', 'Sir Bedevere the Wise') -# dot.node('L', 'Sir Lancelot the Brave') -# dot.edges(['AB', 'AL']) -# dot.edge('B', 'L', constraint='false') -# -# dot.render('FileName', view=True) \ No newline at end of file +def init_graph() -> Digraph: + dot = Digraph( + 'graph', + comment='Graph', + node_attr={'color': 'lightblue2', 'style': 'filled', 'shape': 'circle'} + ) + dot.attr(rankdir='LR', size='8,5') + return dot diff --git a/project/status.py b/project/status.py index 0699326..472ecd0 100644 --- a/project/status.py +++ b/project/status.py @@ -6,7 +6,6 @@ from add import get_repository_path from commit import get_parent_head from errors import WitError - # If I do "add" to a file / folder inside folder 1 (test\folder1\folder2\...) - # sometimes all other files/ folders inside don't appear in Untracked files. # and other times they don't appear in Changes to be committed. Very weired... @@ -41,9 +40,15 @@ def get_all_files_in_directory_and_subs(directory: Union[Path, str], start_path: yield os.path.relpath(root, start_path) for file in files: file_abs_path = os.path.join(root, file) + # print( + # f"***abs path: {file_abs_path}\n" + # f"***start: {start_path}\n" + # f"***rel: {os.path.relpath(file_abs_path, start_path)}" + # ) yield os.path.relpath(file_abs_path, start_path) for dir_name in dirs: - yield from get_all_files_in_directory_and_subs(dir_name, os.path.join(start_path, dir_name)) + # print(dir_name) + yield from get_all_files_in_directory_and_subs(os.path.join(directory, dir_name), start_path) def get_changes_to_be_committed(commit_path: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: From 9d9d2a66461dea5d8624c2aecff9ff770ff29ae5 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Wed, 9 Mar 2022 08:39:13 +0200 Subject: [PATCH 32/73] fix project files --- .gitignore | 3 +- project/add.py | 58 ++++++++--------- project/branch.py | 10 +-- project/checkout.py | 82 +++++------------------ project/commit.py | 56 +++++----------- project/errors.py | 8 ++- project/global_functions.py | 38 +++++++++++ project/graph.py | 23 ++++--- project/init.py | 13 +++- project/status.py | 16 ++--- project/wit.py | 125 +++++++++++++++++++----------------- tests/test_add.py | 4 +- tests/test_init.py | 2 +- 13 files changed, 208 insertions(+), 230 deletions(-) create mode 100644 project/global_functions.py diff --git a/.gitignore b/.gitignore index efdc847..5e69497 100644 --- a/.gitignore +++ b/.gitignore @@ -128,7 +128,6 @@ dmypy.json # Pyre type checker .pyre/ .wit -.idea +/.idea/ __pycache__ wit_exercises -/tests/ diff --git a/project/add.py b/project/add.py index 2c71d69..581c86c 100644 --- a/project/add.py +++ b/project/add.py @@ -1,46 +1,40 @@ -import os +from glob import glob from pathlib import Path import shutil -from typing import Optional from errors import WitError +from global_functions import get_repository_path -def add(path_to_add: str) -> None: - path = Path(os.path.abspath(path_to_add)) +def add_function(path_to_add: str) -> None: + path = Path(path_to_add).resolve() repository = get_repository_path(path) if not repository: raise WitError("<.wit> file not found") - destination = repository.joinpath('.wit', 'staging_area') - directories_to_copy = path.relative_to(repository).parts[:-1] - # print(f"directories_to_copy: {directories_to_copy}") + destination = get_destination(path, repository) + save_the_copy(destination, path) + + +def update_destination(destination: Path, directories_to_copy: tuple[str, ...]) -> Path: for dir_name in directories_to_copy: - # print(f"dir name: {dir_name}") - dirs = os.listdir(destination) - # print(f"dirs: {dirs}") - destination = destination.joinpath(dir_name) - if dir_name not in dirs: + destination = destination / dir_name + if not glob(str(destination)): destination.mkdir() - save_the_copy(destination, path) + return destination + + +def get_destination(path: Path, repository: Path) -> Path: + destination = repository / '.wit' / 'staging_area' + directories_to_copy = path.relative_to(repository).parts[:-1] + destination = update_destination(destination, directories_to_copy) + return destination -def save_the_copy(destination: Path, file: Path) -> None: - if file.is_file(): - shutil.copy2(file, destination) +def save_the_copy(destination: Path, path: Path) -> None: + if path.is_file(): + shutil.copy2(path, destination) else: - destination_of_folder_if_doesnt_exists = destination.joinpath(file.name) - # print(f"destination_of_folder_if_doesnt_exists: {destination_of_folder_if_doesnt_exists}") - if destination_of_folder_if_doesnt_exists.exists(): - shutil.rmtree(destination_of_folder_if_doesnt_exists) - shutil.copytree(file, destination_of_folder_if_doesnt_exists) - - -def get_repository_path(path: Path) -> Optional[Path]: - if path.is_dir(): - if '.wit' in os.listdir(path): - return path - for parent in path.parents: - dir_lst = os.listdir(parent) - if '.wit' in dir_lst: - return parent - return None + destination_of_folder = destination / path.name + if destination_of_folder.exists(): + shutil.rmtree(destination_of_folder) + shutil.copytree(path, destination_of_folder) diff --git a/project/branch.py b/project/branch.py index a668394..8f67b6f 100644 --- a/project/branch.py +++ b/project/branch.py @@ -1,15 +1,15 @@ from pathlib import Path -from add import get_repository_path -from commit import get_parent_head +from commit import get_head_reference from errors import WitError +from global_functions import get_repository_path -def branch(name: str) -> None: +def branch_function(name: str) -> None: repository = get_repository_path(Path.cwd()) if not repository: raise WitError("<.wit> file not found") - references_file = repository.joinpath('.wit', 'references.txt') - commit_id = get_parent_head(repository) + references_file = repository / '.wit' / 'references.txt' + commit_id = get_head_reference(repository) with references_file.open('a') as ref_file: ref_file.write(f'\n{name}={commit_id}') diff --git a/project/checkout.py b/project/checkout.py index a82777b..e2fd8a8 100644 --- a/project/checkout.py +++ b/project/checkout.py @@ -1,35 +1,34 @@ -import os from pathlib import Path import shutil +from typing import Union -from add import get_repository_path -from commit import get_commit_id_of_branch, get_parent_head from errors import FilesDoesntMatchError, WitError, BranchDoesntExistError +from global_functions import get_repository_path, get_commit_id_of_branch, get_head_reference from status import get_changes_to_be_committed, get_changes_not_staged_for_commit, get_all_files_in_directory_and_subs -def checkout(commit_id_or_branch: str) -> None: +def checkout_function(commit_id_or_branch: str) -> None: repository = get_repository_path(Path.cwd()) - staging_area_path = os.path.join(repository, '.wit', 'staging_area') - last_commit_id = get_parent_head(repository) - last_commit_path = os.path.join(repository, '.wit', 'images', last_commit_id) + staging_area_path = repository / '.wit' / 'staging_area' + last_commit_id = get_head_reference(repository) + last_commit_path = repository / '.wit' / 'images' / last_commit_id if not repository: raise WitError("<.wit> file not found") if ( list(get_changes_to_be_committed(last_commit_path, staging_area_path)) or list(get_changes_not_staged_for_commit(repository, staging_area_path)) ): - raise FilesDoesntMatchError("There are files added or changed after last commit") - references_file = repository.joinpath('.wit', 'references.txt') + raise FilesDoesntMatchError("There are files added or changed after last commit_function") + references_file = repository / '.wit' / 'references.txt' commit_id = get_commit_id_of_branch(commit_id_or_branch, references_file) if not commit_id: raise BranchDoesntExistError("Branch doesn't exist.") if commit_id != commit_id_or_branch: write_activated(commit_id_or_branch, repository) - commit_path = os.path.join(repository, '.wit', 'images', commit_id) - change_files_in_main_folder(commit_path, repository) - change_head_in_references_file(commit_id, references_file) - change_staging_area_folder(staging_area_path, commit_path) + commit_path = repository / '.wit' / 'images' / commit_id + update_files_in_main_folder(commit_path, repository) + update_head_in_references_file(commit_id, references_file) + update_staging_area_folder(staging_area_path, commit_path) if commit_id != commit_id_or_branch: write_activated(commit_id_or_branch, repository) @@ -39,72 +38,25 @@ def write_activated(commit_id_or_branch: str, repository: Path) -> None: activated_path.write_text(commit_id_or_branch) -def change_head_in_references_file(commit_id: str, references_file: Path) -> None: +def update_head_in_references_file(commit_id: str, references_file: Path) -> None: with references_file.open() as file: branches = file.readlines()[1:] branches_txt = ''.join(branches) references_file.write_text(f'HEAD={commit_id}\n{branches_txt}') -# def get_commit_id_of_branch(commit_id_or_branch: str, references_file: Path) -> str: -# branch_regex = re.compile(r"^(?P\w+)=(?P\w{20})$") -# with references_file.open() as file: -# for line in file: -# match = branch_regex.match(line) -# # print(f"match.groupdict()['branch_name']: {match.groupdict()['branch_name']}") -# # print(f"match.groupdict()['branch_id']: {match.groupdict()['branch_id']}") -# if match.groupdict()['branch_name'] == commit_id_or_branch: -# return match.groupdict()['branch_id'] -# # references_content = file.readlines() -# # branches_data = references_content[1:] -# -# # for branch_line in branches_data: -# # name_and_id = branch_line.split('=') -# # branch_name = name_and_id[0] -# # branch_id = name_and_id[1].strip() -# # if branch_name == commit_id_or_branch: -# # return branch_id -# return commit_id_or_branch - - -def change_files_in_main_folder(commit_path: str, repository: Path) -> None: +def update_files_in_main_folder(commit_path: Union[str, Path], repository: Path) -> None: files_committed = get_all_files_in_directory_and_subs(commit_path, commit_path) for committed_file in files_committed: - # print(f"committed file: {committed_file}") - path_in_commit = os.path.join(commit_path, committed_file) - # print(path_in_commit) + path_in_commit = commit_path / committed_file with open(path_in_commit, 'r') as committed_file_h: content = committed_file_h.read() - path_in_repository = os.path.join(repository, committed_file) + path_in_repository = repository / committed_file with open(path_in_repository, "w") as original_file: original_file.write(content) -# בהתחלה עשיתי את הפונקציה כמו שמופיע למטה בהמשך ההערה, והערת לי שיש דרך הרבה יותר פשוטה להעתיק תיקיה -# ושיש פונקציה קיימת שיכולה לעזור לי, ולכן שינתי את הפונקציה כמו שמופיע למעלה. -# אבל ככה יש בעיה במקרה והתווסף קובץ חדש, ורוצים לעשות checkout לקומיט מלפני יצירת הקובץ, -# ואז בעצם בעידכון הקבצים בתיקיה צריך למחוק את הקובץ לחלוטין. -# לא הצלחתי לחשוב על פתרון פשוט לזה חוץ צלהשתמש בדרך המסורבלת יותר שאיתה התחלתי. -# אשמח לתובנות. -# -# def change_files_in_main_folder(repository: Path, commit_id: str) -> None: -# commit_path = os.path.join(repository, '.wit', 'images', commit_id) -# all_files_in_repository_and_sub_dirs = [] -# for (root, dirs, files) in os.walk(repository, topdown=True): -# if '.wit' not in Path(root).parts: -# for file in files: -# all_files_in_repository_and_sub_dirs.append(os.path.join(root, file)) -# all_files_in_commit_and_sub_dirs = [] -# for (root, dirs, files) in os.walk(commit_path, topdown=True): -# for file in files: -# all_files_in_commit_and_sub_dirs.append(os.path.join(root, file)) -# for c_file in all_files_in_commit_and_sub_dirs: -# for r_file in all_files_in_repository_and_sub_dirs: -# if Path(r_file).relative_to(repository) == Path(c_file).relative_to(commit_path): -# shutil.copy2(c_file, r_file) - - -def change_staging_area_folder(staging_area_path: str, commit_path: str): +def update_staging_area_folder(staging_area_path: Union[str, Path], commit_path: Union[str, Path]): for file_or_dir in Path(staging_area_path).iterdir(): if file_or_dir.is_file(): file_or_dir.unlink() diff --git a/project/commit.py b/project/commit.py index 3df20e4..25981b8 100644 --- a/project/commit.py +++ b/project/commit.py @@ -5,15 +5,15 @@ import re import shutil -from add import get_repository_path from errors import WitError +from global_functions import get_repository_path, get_head_reference -def commit(message: str) -> None: +def commit_function(message: str) -> None: repository = get_repository_path(Path.cwd()) if not repository: raise WitError("<.wit> file not found") - images_path = repository.joinpath('.wit', 'images') + images_path = repository / '.wit' / 'images' path_of_new_folder = create_commit_folder(images_path) create_commit_txt_file(repository, images_path, path_of_new_folder, message) save_files(repository, path_of_new_folder) @@ -21,9 +21,9 @@ def commit(message: str) -> None: write_references(commit_id, repository) -def create_commit_folder(images_path: Path) -> str: +def create_commit_folder(images_path: Path) -> Path: folder_name = create_folder_name() - path_of_new_folder = os.path.join(images_path, folder_name) + path_of_new_folder = images_path / folder_name os.mkdir(path_of_new_folder) return path_of_new_folder @@ -35,9 +35,9 @@ def create_folder_name() -> str: return folder_name -def create_commit_txt_file(repository: Path, images_path: Path, path_of_new_folder: str, message: str) -> None: - parent_head = get_parent_head(repository) - txt_file = images_path.joinpath(Path(path_of_new_folder).name + '.txt') +def create_commit_txt_file(repository: Path, images_path: Path, path_of_new_folder: Path, message: str) -> None: + parent_head = get_head_reference(repository) + txt_file = images_path / (path_of_new_folder.name + '.txt') txt_file.write_text( f'parent = {parent_head if parent_head else None}\n' f'date = {datetime.datetime.now().strftime("%c")}\n' @@ -45,42 +45,22 @@ def create_commit_txt_file(repository: Path, images_path: Path, path_of_new_fold ) -def get_commit_id_of_branch(branch: str, references_file: Path) -> str: - branch_regex = re.compile(r"^(?P\w+)=(?P\w{20})$") - with references_file.open() as file: - for line in file: - match = branch_regex.match(line) - if match.groupdict()['branch_name'] == branch: - return match.groupdict()['branch_id'] - return branch - - -def get_parent_head(repository: Path) -> str: - wit_folder = repository.joinpath('.wit') - references_file = wit_folder.joinpath('references.txt') - if references_file.exists(): - # print(get_commit_id_of_branch('HEAD', references_file)) - return get_commit_id_of_branch('HEAD', references_file) - return '' - - -def save_files(repository: Path, path_of_new_folder: str) -> None: - staging_area_path = os.path.join(repository, '.wit', 'staging_area') +def save_files(repository: Path, path_of_new_folder: Path) -> None: + staging_area_path = repository / '.wit' / 'staging_area' for item in os.listdir(staging_area_path): - src = os.path.join(staging_area_path, item) - dst = os.path.join(path_of_new_folder, item) - if os.path.isfile(src): + src = staging_area_path / item + dst = path_of_new_folder / item + if src.is_file(): shutil.copy2(src, dst) else: shutil.copytree(src, dst) def write_references(commit_id: str, repository: Path) -> None: - wit_folder = repository.joinpath('.wit') - references_file = wit_folder.joinpath('references.txt') - parent_head = get_parent_head(repository) - # print(parent_head) - activated_path = wit_folder.joinpath('activated.txt') + wit_folder = repository / '.wit' + references_file = wit_folder / 'references.txt' + parent_head = get_head_reference(repository) + activated_path = wit_folder / 'activated.txt' activated_branch = activated_path.read_text() if references_file.exists(): change_head_and_branch_id(activated_branch, commit_id, parent_head, references_file) @@ -91,10 +71,8 @@ def write_references(commit_id: str, repository: Path) -> None: def change_head_and_branch_id(activated_branch: str, commit_id: str, parent_head: str, references_file: Path) -> None: regex = re.compile(fr"^{activated_branch}={parent_head}$", flags=re.MULTILINE) head_regex = re.compile(fr"^HEAD={parent_head}$", flags=re.MULTILINE) - # print(regex) data = references_file.read_text() match = regex.findall(data) - # print(match) if match: new = regex.sub(f"{activated_branch}={commit_id}", data) new = head_regex.sub(f"HEAD={commit_id}", new) diff --git a/project/errors.py b/project/errors.py index 622630c..c57d8d5 100644 --- a/project/errors.py +++ b/project/errors.py @@ -2,9 +2,13 @@ class WitError(Exception): pass -class FilesDoesntMatchError(Exception): +class FilesDoesntMatchError(WitError): pass -class BranchDoesntExistError(Exception): +class BranchDoesntExistError(WitError): + pass + + +class WitExistsError(WitError): pass diff --git a/project/global_functions.py b/project/global_functions.py new file mode 100644 index 0000000..c701458 --- /dev/null +++ b/project/global_functions.py @@ -0,0 +1,38 @@ +from glob import glob +from pathlib import Path +import re +from typing import Optional + + +branch_regex = re.compile(r"^(?P\w+)=(?P\w{20})$") + + +def get_repository_path(path: Path) -> Optional[Path]: + if path.is_dir(): + if glob(str(path / '.wit')): + return path + for directory in path.parents: + if glob(str(directory / '.wit')): + return directory + return None + + +def get_commit_id_of_branch(branch: str, references_file: Path) -> str: + with references_file.open() as file: + branches_commits_dict = {} + for line in file: + match = branch_regex.match(line) + branches_commits_dict[match.group('branch_name')] = match.group('branch_id') + if branch in branches_commits_dict: + return branches_commits_dict[branch] + if branch in branches_commits_dict.values(): + return branch + return '' + + +def get_head_reference(repository: Path) -> str: + wit_folder = repository.joinpath('.wit') + references_file = wit_folder.joinpath('references.txt') + if references_file.exists(): + return get_commit_id_of_branch('HEAD', references_file) + return '' diff --git a/project/graph.py b/project/graph.py index a66a314..d73ec45 100644 --- a/project/graph.py +++ b/project/graph.py @@ -2,30 +2,29 @@ from pathlib import Path import re - -from add import get_repository_path -from commit import get_parent_head from errors import WitError +from global_functions import get_repository_path, get_head_reference + + +regex = re.compile(r"^parent = (?P\w{20})$", flags=re.MULTILINE) -def graph(): +def graph_function(): repository = get_repository_path(Path.cwd()) if not repository: raise WitError("<.wit> file not found") - current_commit_id = get_parent_head(repository) + current_commit_id = get_head_reference(repository) commit_id = current_commit_id dot = init_graph() - wit_dir = repository.joinpath('.wit') - images_path = wit_dir.joinpath('images') - regex = re.compile(r"^parent = (?P\w{20})$", flags=re.MULTILINE) + wit_dir = repository / '.wit' + images_path = wit_dir / 'images' while commit_id: - commit_file = images_path.joinpath(f"{commit_id}.txt") + commit_file = images_path / (commit_id + ".txt") create_node(commit_id, dot) commit_txt = commit_file.read_text() parent_id_match = regex.match(commit_txt) if parent_id_match: parent_id = parent_id_match.group('commit_id') - # print(f"***********parent id: {parent_id}*************") create_node(parent_id, dot) dot.edge(commit_id, parent_id) commit_id = parent_id if parent_id_match else None @@ -38,9 +37,9 @@ def create_node(commit_id: str, dot: Digraph) -> None: def init_graph() -> Digraph: dot = Digraph( - 'graph', + 'graph_function', comment='Graph', - node_attr={'color': 'lightblue2', 'style': 'filled', 'shape': 'circle'} + node_attr={'color': 'lightblue2', 'style': 'filled', 'shape': 'circle'}, ) dot.attr(rankdir='LR', size='8,5') return dot diff --git a/project/init.py b/project/init.py index 0290086..98db9c7 100644 --- a/project/init.py +++ b/project/init.py @@ -2,12 +2,19 @@ from pathlib import Path from typing import Optional +from errors import WitExistsError -def init(folder_name: Optional[str] = None) -> None: + +def init_function() -> None: cwd = os.getcwd() - if folder_name: - cwd = os.path.join(cwd, folder_name) + # if folder_name: + # if os.path.isabs(folder_name): + # cwd = folder_name + # else: + # cwd = os.path.join(cwd, folder_name) wit_path = os.path.join(cwd, '.wit') + if os.path.exists(wit_path): + raise WitExistsError("The folder already has .wit directory") os.mkdir(wit_path) os.mkdir(os.path.join(wit_path, 'images')) os.mkdir(os.path.join(wit_path, 'staging_area')) diff --git a/project/status.py b/project/status.py index 472ecd0..efa7c7f 100644 --- a/project/status.py +++ b/project/status.py @@ -3,21 +3,21 @@ from pathlib import Path from typing import Union, Iterator -from add import get_repository_path -from commit import get_parent_head from errors import WitError -# If I do "add" to a file / folder inside folder 1 (test\folder1\folder2\...) - +from global_functions import get_repository_path, get_head_reference + +# If I do "add_function" to a file / folder inside folder 1 (test\folder1\folder2\...) - # sometimes all other files/ folders inside don't appear in Untracked files. # and other times they don't appear in Changes to be committed. Very weired... -def status(): +def status_function(): repository = get_repository_path(Path.cwd()) if not repository: raise WitError("<.wit> file not found") staging_area_path = os.path.join(repository, '.wit', 'staging_area') - commit_id = get_parent_head(repository) - message_if_no_commit = "No commit was done yet." + commit_id = get_head_reference(repository) + message_if_no_commit = "No commit_function was done yet." commit_path = os.path.join(repository, '.wit', 'images', commit_id) changes_to_be_committed = show_files(get_changes_to_be_committed(commit_path, staging_area_path)) changes_not_staged_for_commit = show_files(get_changes_not_staged_for_commit(repository, staging_area_path)) @@ -25,7 +25,7 @@ def status(): print( f"###Commit id:###\n{commit_id if commit_id else message_if_no_commit}\n\n" f"###Changes to be committed:###\n{changes_to_be_committed}\n\n" - f"###Changes not staged for commit:###\n{changes_not_staged_for_commit}\n\n" + f"###Changes not staged for commit_function:###\n{changes_not_staged_for_commit}\n\n" f"###Untracked files:###\n{untracked_files}\n" ) @@ -52,7 +52,7 @@ def get_all_files_in_directory_and_subs(directory: Union[Path, str], start_path: def get_changes_to_be_committed(commit_path: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: - """Yield files that the user added to staging area since last commit and will be added to the next commit.""" + """Yield files that the user added to staging area since last commit_function and will be added to the next commit_function.""" # sometimes I get the full path of the file and sometimes only the file name. cmp = dircmp(commit_path, staging_area_path) yield from get_new_and_changed_files(cmp, staging_area_path) diff --git a/project/wit.py b/project/wit.py index 8a6d29e..25dee7e 100644 --- a/project/wit.py +++ b/project/wit.py @@ -1,59 +1,66 @@ -from add import add -from branch import branch -from checkout import checkout -from commit import commit -from init import init -from graph import graph -from status import status - -import sys - - -def is_command_correct(argv: list[str]) -> bool: - if argv[1] in {'init', 'status', 'graph'}: - return len(argv) == 2 - else: - return len(argv) == 3 - - -if sys.argv[1] == 'init': - if is_command_correct(sys.argv): - init() - else: - print(fr"Usage: python {sys.argv[0]} init") - -elif sys.argv[1] == 'add': - if is_command_correct(sys.argv): - add(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} add ") - -elif sys.argv[1] == 'commit': - if is_command_correct(sys.argv): - commit(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} commit MESSAGE") - -elif sys.argv[1] == 'status': - if is_command_correct(sys.argv): - status() - else: - print(fr"Usage: python {sys.argv[0]} status") - -elif sys.argv[1] == 'checkout': - if is_command_correct(sys.argv): - checkout(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} checkout ") - -elif sys.argv[1] == 'branch': - if is_command_correct(sys.argv): - branch(sys.argv[2]) - else: - print(fr"Usage: python {sys.argv[0]} branch ") - -elif sys.argv[1] == 'graph': - if is_command_correct(sys.argv): - graph() - else: - print(fr"Usage: python {sys.argv[0]} graph") +import click + +from add import add_function +from branch import branch_function +from checkout import checkout_function +from commit import commit_function +from graph import graph_function +from init import init_function +from status import status_function + + +@click.group() +def cli(): + pass + + +@cli.command() +def init(): + """Create a wit folder in the directory.""" + init_function() + + +@cli.command() +@click.argument('path', type=click.Path(exists=True)) +def add(path): + """Add file or folder to staging area.""" + add_function(path) + + +@cli.command() +@click.argument('message') +def commit(message): + """Save image of current files in staging area. + Save a message. + """ + commit_function(message) + + +@cli.command() +def status(): + """Show the status of files in directory.""" + status_function() + + +@cli.command() +@click.argument('commit_id_or_branch') +def checkout(commit_id_or_branch): + """Switch to another commit or branch, which will be activated.""" + checkout_function(commit_id_or_branch) + + +@cli.command() +@click.argument('branch_name') +def branch(branch_name): + """Create a new branch.""" + branch_function(branch_name) + + +@cli.command() +def graph(): + """Show graph of commits from current commit to the first.""" + graph_function() + + +if __name__ == "__main__": + cli() diff --git a/tests/test_add.py b/tests/test_add.py index 590d587..aa7a589 100644 --- a/tests/test_add.py +++ b/tests/test_add.py @@ -22,7 +22,7 @@ ] ) def test_get_directory_with_wit(test_folder, path, parent): - init.init(test_folder) + init.init_function(test_folder) assert add.get_repository_path(path) == parent @@ -35,7 +35,7 @@ def test_get_directory_with_wit(test_folder, path, parent): ] ) def test_save_the_copy(test_folder, destination_in_wit, file, new_destination): - init.init(test_folder) + init.init_function(test_folder) destination = Path('test_wit').joinpath('.wit', 'staging_area') add.save_the_copy(destination.joinpath(destination_in_wit), file) assert destination.joinpath(destination_in_wit).exists() diff --git a/tests/test_init.py b/tests/test_init.py index 434e93b..228e6b6 100644 --- a/tests/test_init.py +++ b/tests/test_init.py @@ -5,7 +5,7 @@ def test_init(test_folder): - init.init(test_folder) + init.init_function(test_folder) test_wit_path = Path(test_folder).joinpath('.wit') assert test_wit_path.is_dir() assert test_wit_path.joinpath('images').is_dir() From 2e208911362a1a7fec01fce80cff90b8d8f19642 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Wed, 9 Mar 2022 08:43:31 +0200 Subject: [PATCH 33/73] change init function - no arguments --- project/init.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/project/init.py b/project/init.py index 98db9c7..ea2a385 100644 --- a/project/init.py +++ b/project/init.py @@ -1,17 +1,11 @@ import os from pathlib import Path -from typing import Optional from errors import WitExistsError def init_function() -> None: cwd = os.getcwd() - # if folder_name: - # if os.path.isabs(folder_name): - # cwd = folder_name - # else: - # cwd = os.path.join(cwd, folder_name) wit_path = os.path.join(cwd, '.wit') if os.path.exists(wit_path): raise WitExistsError("The folder already has .wit directory") From 5c33a6b2538ba911a37f56b91f85548360df7117 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Thu, 10 Mar 2022 08:22:14 +0200 Subject: [PATCH 34/73] add merge file, add click function to wit file --- project/merge.py | 2 ++ project/wit.py | 8 ++++++++ 2 files changed, 10 insertions(+) create mode 100644 project/merge.py diff --git a/project/merge.py b/project/merge.py new file mode 100644 index 0000000..29bceed --- /dev/null +++ b/project/merge.py @@ -0,0 +1,2 @@ +def merge_function(branch: str) -> None: + pass diff --git a/project/wit.py b/project/wit.py index 25dee7e..061d9e1 100644 --- a/project/wit.py +++ b/project/wit.py @@ -6,6 +6,7 @@ from commit import commit_function from graph import graph_function from init import init_function +from merge import merge_function from status import status_function @@ -62,5 +63,12 @@ def graph(): graph_function() +@cli.command() +@click.argument('branch_name') +def merge(branch_name): + """Merge the files in the current commit with the branch.""" + merge_function(branch_name) + + if __name__ == "__main__": cli() From 75e1ffa0323f3858b24fe052aed58aeab2ceaabf Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Mon, 14 Mar 2022 08:23:36 +0200 Subject: [PATCH 35/73] merge done. todo: two parents to a commit --- project/add.py | 6 +- project/branch.py | 7 ++- project/checkout.py | 17 ++++-- project/commit.py | 27 +++++---- project/errors.py | 12 ++++ project/global_functions.py | 40 ++++++++++--- project/merge.py | 114 +++++++++++++++++++++++++++++++++++- project/status.py | 32 +++++----- 8 files changed, 208 insertions(+), 47 deletions(-) diff --git a/project/add.py b/project/add.py index 581c86c..eed58be 100644 --- a/project/add.py +++ b/project/add.py @@ -25,8 +25,10 @@ def update_destination(destination: Path, directories_to_copy: tuple[str, ...]) def get_destination(path: Path, repository: Path) -> Path: destination = repository / '.wit' / 'staging_area' - directories_to_copy = path.relative_to(repository).parts[:-1] - destination = update_destination(destination, directories_to_copy) + file_path = path.relative_to(repository) + file_parts = file_path.parts + parents_dirs = file_parts[:-1] + destination = update_destination(destination, parents_dirs) return destination diff --git a/project/branch.py b/project/branch.py index 8f67b6f..b5f34bb 100644 --- a/project/branch.py +++ b/project/branch.py @@ -1,8 +1,8 @@ from pathlib import Path from commit import get_head_reference -from errors import WitError -from global_functions import get_repository_path +from errors import WitError, BranchExistsError +from global_functions import get_repository_path, get_branches_commits def branch_function(name: str) -> None: @@ -10,6 +10,9 @@ def branch_function(name: str) -> None: if not repository: raise WitError("<.wit> file not found") references_file = repository / '.wit' / 'references.txt' + existing_branches = get_branches_commits(references_file) + if name in existing_branches: + raise BranchExistsError(f"Branch {name} already exists.") commit_id = get_head_reference(repository) with references_file.open('a') as ref_file: ref_file.write(f'\n{name}={commit_id}') diff --git a/project/checkout.py b/project/checkout.py index e2fd8a8..b69343d 100644 --- a/project/checkout.py +++ b/project/checkout.py @@ -3,8 +3,13 @@ from typing import Union from errors import FilesDoesntMatchError, WitError, BranchDoesntExistError -from global_functions import get_repository_path, get_commit_id_of_branch, get_head_reference -from status import get_changes_to_be_committed, get_changes_not_staged_for_commit, get_all_files_in_directory_and_subs +from global_functions import ( + get_repository_path, + get_commit_id_of_branch, + get_head_reference, + get_all_files_in_directory_and_subs, +) +from status import get_changes_to_be_committed, get_changes_not_staged_for_commit def checkout_function(commit_id_or_branch: str) -> None: @@ -25,16 +30,16 @@ def checkout_function(commit_id_or_branch: str) -> None: raise BranchDoesntExistError("Branch doesn't exist.") if commit_id != commit_id_or_branch: write_activated(commit_id_or_branch, repository) + else: + write_activated('', repository) commit_path = repository / '.wit' / 'images' / commit_id update_files_in_main_folder(commit_path, repository) update_head_in_references_file(commit_id, references_file) update_staging_area_folder(staging_area_path, commit_path) - if commit_id != commit_id_or_branch: - write_activated(commit_id_or_branch, repository) def write_activated(commit_id_or_branch: str, repository: Path) -> None: - activated_path = repository.joinpath('.wit', 'activated.txt') + activated_path = repository / '.wit' / 'activated.txt' activated_path.write_text(commit_id_or_branch) @@ -46,7 +51,7 @@ def update_head_in_references_file(commit_id: str, references_file: Path) -> Non def update_files_in_main_folder(commit_path: Union[str, Path], repository: Path) -> None: - files_committed = get_all_files_in_directory_and_subs(commit_path, commit_path) + files_committed = get_all_files_in_directory_and_subs(commit_path) for committed_file in files_committed: path_in_commit = commit_path / committed_file with open(path_in_commit, 'r') as committed_file_h: diff --git a/project/commit.py b/project/commit.py index 25981b8..4b8906e 100644 --- a/project/commit.py +++ b/project/commit.py @@ -4,18 +4,19 @@ import random import re import shutil +from typing import Optional from errors import WitError -from global_functions import get_repository_path, get_head_reference +from global_functions import get_repository_path, get_head_reference, get_activated_branch -def commit_function(message: str) -> None: +def commit_function(message: str, second_parent: Optional[str] = None) -> None: repository = get_repository_path(Path.cwd()) if not repository: raise WitError("<.wit> file not found") images_path = repository / '.wit' / 'images' path_of_new_folder = create_commit_folder(images_path) - create_commit_txt_file(repository, images_path, path_of_new_folder, message) + create_commit_txt_file(repository, images_path, path_of_new_folder, message, second_parent) save_files(repository, path_of_new_folder) commit_id = os.path.basename(path_of_new_folder) write_references(commit_id, repository) @@ -35,8 +36,16 @@ def create_folder_name() -> str: return folder_name -def create_commit_txt_file(repository: Path, images_path: Path, path_of_new_folder: Path, message: str) -> None: +def create_commit_txt_file( + repository: Path, + images_path: Path, + path_of_new_folder: Path, + message: str, + second_parent: Optional[str] = None, +) -> None: parent_head = get_head_reference(repository) + if second_parent: + parent_head += ', ' + second_parent txt_file = images_path / (path_of_new_folder.name + '.txt') txt_file.write_text( f'parent = {parent_head if parent_head else None}\n' @@ -60,8 +69,7 @@ def write_references(commit_id: str, repository: Path) -> None: wit_folder = repository / '.wit' references_file = wit_folder / 'references.txt' parent_head = get_head_reference(repository) - activated_path = wit_folder / 'activated.txt' - activated_branch = activated_path.read_text() + activated_branch = get_activated_branch(wit_folder) if references_file.exists(): change_head_and_branch_id(activated_branch, commit_id, parent_head, references_file) else: @@ -73,7 +81,6 @@ def change_head_and_branch_id(activated_branch: str, commit_id: str, parent_head head_regex = re.compile(fr"^HEAD={parent_head}$", flags=re.MULTILINE) data = references_file.read_text() match = regex.findall(data) - if match: - new = regex.sub(f"{activated_branch}={commit_id}", data) - new = head_regex.sub(f"HEAD={commit_id}", new) - references_file.write_text(new) + new = regex.sub(f"{activated_branch}={commit_id}", data) if match else data + new = head_regex.sub(f"HEAD={commit_id}", new) + references_file.write_text(new) diff --git a/project/errors.py b/project/errors.py index c57d8d5..fb2f4e8 100644 --- a/project/errors.py +++ b/project/errors.py @@ -10,5 +10,17 @@ class BranchDoesntExistError(WitError): pass +class BranchExistsError(WitError): + pass + + class WitExistsError(WitError): pass + + +class MergeError(WitError): + pass + + +class NoCommonCommitError(WitError): + pass diff --git a/project/global_functions.py b/project/global_functions.py index c701458..1b4525f 100644 --- a/project/global_functions.py +++ b/project/global_functions.py @@ -1,8 +1,8 @@ +import os from glob import glob from pathlib import Path import re -from typing import Optional - +from typing import Optional, Iterator, Union branch_regex = re.compile(r"^(?P\w+)=(?P\w{20})$") @@ -18,16 +18,21 @@ def get_repository_path(path: Path) -> Optional[Path]: def get_commit_id_of_branch(branch: str, references_file: Path) -> str: + branches_commits_dict = get_branches_commits(references_file) + if branch in branches_commits_dict: + return branches_commits_dict[branch] + if branch in branches_commits_dict.values(): + return branch + return '' + + +def get_branches_commits(references_file: Path) -> dict[str, str]: with references_file.open() as file: branches_commits_dict = {} for line in file: match = branch_regex.match(line) branches_commits_dict[match.group('branch_name')] = match.group('branch_id') - if branch in branches_commits_dict: - return branches_commits_dict[branch] - if branch in branches_commits_dict.values(): - return branch - return '' + return branches_commits_dict def get_head_reference(repository: Path) -> str: @@ -36,3 +41,24 @@ def get_head_reference(repository: Path) -> str: if references_file.exists(): return get_commit_id_of_branch('HEAD', references_file) return '' + + +def get_activated_branch(wit_folder: Path) -> str: + activated_path = wit_folder / 'activated.txt' + return activated_path.read_text() + + +def get_all_files_in_directory_and_subs( + directory: Union[Path, str], + start_path: Optional[Union[Path, str]] = None, +) -> Iterator[Path]: + if not start_path: + start_path = directory + for root, dirs, files in os.walk(directory, topdown=True): + if not files and not dirs: + yield Path(root).relative_to(start_path) + for file in files: + file_abs_path = Path(root) / file + yield file_abs_path.relative_to(start_path) + for dir_name in dirs: + yield from get_all_files_in_directory_and_subs(directory / dir_name, start_path) diff --git a/project/merge.py b/project/merge.py index 29bceed..dbaa536 100644 --- a/project/merge.py +++ b/project/merge.py @@ -1,2 +1,112 @@ -def merge_function(branch: str) -> None: - pass +import re +from pathlib import Path +from typing import Iterator + +from commit import commit_function +from errors import WitError, MergeError, NoCommonCommitError, FilesDoesntMatchError +from global_functions import ( + get_commit_id_of_branch, + get_head_reference, + get_repository_path, + get_activated_branch, + get_all_files_in_directory_and_subs, +) +from status import get_changes_to_be_committed, get_changes_not_staged_for_commit + +regex = re.compile(r"^parent = (?P\w{20})$", flags=re.MULTILINE) + + +def merge_function(branch_name: str) -> None: + repository = get_repository_path(Path.cwd()) + if not repository: + raise WitError("<.wit> file not found") + branch_commit_id, head_reference, last_commit_path, staging_area_path, wit_dir = get_paths_and_commit_ids( + branch_name, repository + ) + if ( + list(get_changes_to_be_committed(last_commit_path, staging_area_path)) + or list(get_changes_not_staged_for_commit(repository, staging_area_path)) + ): + raise FilesDoesntMatchError("There are files added or changed after last commit_function") + if branch_commit_id == head_reference: + raise MergeError('Head is already at the branch you are trying to merge.') + common_commit = get_common_commit(wit_dir, branch_commit_id, head_reference) + if not common_commit: + raise NoCommonCommitError(f"There is no common commit with {branch_name}.") + branch_dir, branch_files, common_dir, common_files, staging_area_files = get_dirs_and_files( + branch_commit_id, common_commit, staging_area_path, wit_dir, + ) + for file_path in common_files: + if file_path not in branch_files or file_path not in staging_area_files: + raise NotImplementedError(f"The file {file_path} was deleted. Deleting files not implemented yet.") + content_in_branch, content_in_common, content_in_staging_area = get_file_content_in_dirs( + branch_dir, common_dir, file_path, staging_area_path + ) + if content_in_common != content_in_branch: + if content_in_common != content_in_staging_area: + raise NotImplementedError( + f"The file {file_path} was changed both in {branch_name} and in current branch." + ) + (staging_area_path / file_path).write_text(content_in_branch) + for file_path in branch_files: + if file_path not in common_files: + content_in_branch = (branch_dir / file_path).read_text() + (staging_area_path / file_path).write_text(content_in_branch) + commit_merge(branch_commit_id, branch_name, head_reference, wit_dir) + + +def commit_merge(branch_commit_id: str, branch_name: str, head_reference: str, wit_dir: Path): + activated = get_activated_branch(wit_dir) + message = f"Commit after merge of {activated if activated else head_reference} and {branch_name}." + commit_function(message, branch_commit_id) + + +def get_file_content_in_dirs( + branch_dir: Path, common_dir: Path, file_path: Path, staging_area_path: Path +) -> tuple[str, ...]: + content_in_common = (common_dir / file_path).read_text() + content_in_branch = (branch_dir / file_path).read_text() + content_in_staging_area = (staging_area_path / file_path).read_text() + return content_in_branch, content_in_common, content_in_staging_area + + +def get_dirs_and_files( + branch_commit_id: str, common_commit: str, staging_area_path: Path, wit_dir: Path +) -> tuple[Path, Iterator[Path], Path, Iterator[Path], Iterator[Path]]: + common_dir = wit_dir / 'images' / common_commit + common_files = get_all_files_in_directory_and_subs(common_dir) + branch_dir = wit_dir / 'images' / branch_commit_id + branch_files = get_all_files_in_directory_and_subs(branch_dir) + staging_area_files = get_all_files_in_directory_and_subs(staging_area_path) + return branch_dir, branch_files, common_dir, common_files, staging_area_files + + +def get_paths_and_commit_ids(branch_name: str, repository: Path) -> tuple[str, str, Path, Path, Path]: + wit_dir = repository / '.wit' + staging_area_path = wit_dir / 'staging_area' + head_reference = get_head_reference(repository) + last_commit_path = repository / '.wit' / 'images' / head_reference + references_file = wit_dir / 'references.txt' + branch_commit_id = get_commit_id_of_branch(branch_name, references_file) + return branch_commit_id, head_reference, last_commit_path, staging_area_path, wit_dir + + +def get_common_commit(wit_dir: Path, branch_commit_id: str, head_reference: str) -> str: + branch_parents = set(get_parents_commits(wit_dir, branch_commit_id)) + head_parents = set(get_parents_commits(wit_dir, head_reference)) + common = branch_parents.intersection(head_parents) + if common: + return common.pop() + return '' + + +def get_parents_commits(wit_dir: Path, commit_id: str) -> Iterator[str]: + images_path = wit_dir / 'images' + while commit_id: + commit_file = images_path / (commit_id + ".txt") + commit_txt = commit_file.read_text() + parent_id_match = regex.match(commit_txt) + if parent_id_match: # if parent != None + parent_id = parent_id_match.group('commit_id') + yield parent_id + commit_id = parent_id if parent_id_match else None diff --git a/project/status.py b/project/status.py index efa7c7f..b7e32cb 100644 --- a/project/status.py +++ b/project/status.py @@ -4,7 +4,7 @@ from typing import Union, Iterator from errors import WitError -from global_functions import get_repository_path, get_head_reference +from global_functions import get_repository_path, get_head_reference, get_all_files_in_directory_and_subs # If I do "add_function" to a file / folder inside folder 1 (test\folder1\folder2\...) - # sometimes all other files/ folders inside don't appear in Untracked files. @@ -34,25 +34,21 @@ def show_files(files: Iterator[str]) -> str: return '\n'.join(files) -def get_all_files_in_directory_and_subs(directory: Union[Path, str], start_path: Union[Path, str]) -> Iterator[str]: - for root, dirs, files in os.walk(directory, topdown=True): - if not files and not dirs: - yield os.path.relpath(root, start_path) - for file in files: - file_abs_path = os.path.join(root, file) - # print( - # f"***abs path: {file_abs_path}\n" - # f"***start: {start_path}\n" - # f"***rel: {os.path.relpath(file_abs_path, start_path)}" - # ) - yield os.path.relpath(file_abs_path, start_path) - for dir_name in dirs: - # print(dir_name) - yield from get_all_files_in_directory_and_subs(os.path.join(directory, dir_name), start_path) +# def get_all_files_in_directory_and_subs(directory: Union[Path, str], start_path: Union[Path, str]) -> Iterator[Path]: +# for root, dirs, files in os.walk(directory, topdown=True): +# if not files and not dirs: +# yield Path(root).relative_to(start_path) +# for file in files: +# file_abs_path = Path(root) / file +# yield file_abs_path.relative_to(start_path) +# for dir_name in dirs: +# yield from get_all_files_in_directory_and_subs(directory / dir_name, start_path) def get_changes_to_be_committed(commit_path: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: - """Yield files that the user added to staging area since last commit_function and will be added to the next commit_function.""" + """ + Yield files that the user added to staging area since last commit_function and will be added + to the next commit_function.""" # sometimes I get the full path of the file and sometimes only the file name. cmp = dircmp(commit_path, staging_area_path) yield from get_new_and_changed_files(cmp, staging_area_path) @@ -80,7 +76,7 @@ def get_new_files_added(cmp: dircmp[Union[str, bytes]], dir_path: Union[Path, st """Yield files that are new in the directory.""" new_files_added = cmp.right_only for f in new_files_added: - f_path = os.path.join(dir_path, f) + f_path = Path(dir_path) / f if os.path.isfile(f_path): yield f if not start_path else os.path.relpath(f_path, start=start_path) yield from get_all_files_in_directory_and_subs(f_path, start_path=dir_path if not start_path else start_path) From a6b3a44fec4d54ebfd4af5951e0b1bd2fec72a12 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Mon, 14 Mar 2022 23:30:29 +0200 Subject: [PATCH 36/73] finished status. merge doesnt work correctly --- project/checkout.py | 16 ++-- project/global_functions.py | 34 +++++---- project/merge.py | 104 ++++++++++++------------- project/status.py | 147 ++++++++++++++---------------------- 4 files changed, 132 insertions(+), 169 deletions(-) diff --git a/project/checkout.py b/project/checkout.py index b69343d..d9fe329 100644 --- a/project/checkout.py +++ b/project/checkout.py @@ -6,7 +6,6 @@ from global_functions import ( get_repository_path, get_commit_id_of_branch, - get_head_reference, get_all_files_in_directory_and_subs, ) from status import get_changes_to_be_committed, get_changes_not_staged_for_commit @@ -15,12 +14,10 @@ def checkout_function(commit_id_or_branch: str) -> None: repository = get_repository_path(Path.cwd()) staging_area_path = repository / '.wit' / 'staging_area' - last_commit_id = get_head_reference(repository) - last_commit_path = repository / '.wit' / 'images' / last_commit_id if not repository: raise WitError("<.wit> file not found") if ( - list(get_changes_to_be_committed(last_commit_path, staging_area_path)) + list(get_changes_to_be_committed(repository, staging_area_path)) or list(get_changes_not_staged_for_commit(repository, staging_area_path)) ): raise FilesDoesntMatchError("There are files added or changed after last commit_function") @@ -54,11 +51,12 @@ def update_files_in_main_folder(commit_path: Union[str, Path], repository: Path) files_committed = get_all_files_in_directory_and_subs(commit_path) for committed_file in files_committed: path_in_commit = commit_path / committed_file - with open(path_in_commit, 'r') as committed_file_h: - content = committed_file_h.read() - path_in_repository = repository / committed_file - with open(path_in_repository, "w") as original_file: - original_file.write(content) + if path_in_commit.is_file(): + with open(path_in_commit, 'r') as committed_file_h: + content = committed_file_h.read() + path_in_repository = repository / committed_file + with open(path_in_repository, "w") as original_file: + original_file.write(content) def update_staging_area_folder(staging_area_path: Union[str, Path], commit_path: Union[str, Path]): diff --git a/project/global_functions.py b/project/global_functions.py index 1b4525f..73cf29c 100644 --- a/project/global_functions.py +++ b/project/global_functions.py @@ -2,7 +2,7 @@ from glob import glob from pathlib import Path import re -from typing import Optional, Iterator, Union +from typing import Optional, Iterator branch_regex = re.compile(r"^(?P\w+)=(?P\w{20})$") @@ -48,17 +48,21 @@ def get_activated_branch(wit_folder: Path) -> str: return activated_path.read_text() -def get_all_files_in_directory_and_subs( - directory: Union[Path, str], - start_path: Optional[Union[Path, str]] = None, -) -> Iterator[Path]: - if not start_path: - start_path = directory - for root, dirs, files in os.walk(directory, topdown=True): - if not files and not dirs: - yield Path(root).relative_to(start_path) - for file in files: - file_abs_path = Path(root) / file - yield file_abs_path.relative_to(start_path) - for dir_name in dirs: - yield from get_all_files_in_directory_and_subs(directory / dir_name, start_path) +def get_all_files_in_directory_and_subs(directory: Path, repo: bool = False) -> Iterator[Path]: + if repo: + for root, dirs, files in os.walk(directory, topdown=True): + if files: + for file in files: + if '.wit' not in root: + yield (Path(root) / file).relative_to(directory) + else: + if '.wit' not in root and not dirs: + yield Path(root).relative_to(directory) + else: + for root, dirs, files in os.walk(directory, topdown=True): + if files: + for file in files: + yield (Path(root) / file).relative_to(directory) + else: + if not dirs: + yield Path(root).relative_to(directory) diff --git a/project/merge.py b/project/merge.py index dbaa536..d3a7c10 100644 --- a/project/merge.py +++ b/project/merge.py @@ -1,4 +1,5 @@ import re +from glob import glob from pathlib import Path from typing import Iterator @@ -13,84 +14,65 @@ ) from status import get_changes_to_be_committed, get_changes_not_staged_for_commit -regex = re.compile(r"^parent = (?P\w{20})$", flags=re.MULTILINE) +# regex = re.compile(r"^parent = (?P\w{20})$", flags=re.MULTILINE) +regex = re.compile(r"^parent = (?P\w{20})(, (?P\w{20}))?$", flags=re.MULTILINE) def merge_function(branch_name: str) -> None: repository = get_repository_path(Path.cwd()) if not repository: raise WitError("<.wit> file not found") - branch_commit_id, head_reference, last_commit_path, staging_area_path, wit_dir = get_paths_and_commit_ids( - branch_name, repository - ) + wit_dir = repository / '.wit' + staging_area_path = wit_dir / 'staging_area' + references_file = wit_dir / 'references.txt' + head_reference = get_head_reference(repository) + branch_commit_id = get_commit_id_of_branch(branch_name, references_file) if ( - list(get_changes_to_be_committed(last_commit_path, staging_area_path)) + list(get_changes_to_be_committed(repository, staging_area_path)) or list(get_changes_not_staged_for_commit(repository, staging_area_path)) ): raise FilesDoesntMatchError("There are files added or changed after last commit_function") if branch_commit_id == head_reference: raise MergeError('Head is already at the branch you are trying to merge.') common_commit = get_common_commit(wit_dir, branch_commit_id, head_reference) + # print(f"common: {common_commit}") if not common_commit: raise NoCommonCommitError(f"There is no common commit with {branch_name}.") - branch_dir, branch_files, common_dir, common_files, staging_area_files = get_dirs_and_files( - branch_commit_id, common_commit, staging_area_path, wit_dir, - ) + common_dir = wit_dir / 'images' / common_commit + branch_dir = wit_dir / 'images' / branch_commit_id + common_files = get_all_files_in_directory_and_subs(common_dir) + branch_files = get_all_files_in_directory_and_subs(branch_dir) for file_path in common_files: - if file_path not in branch_files or file_path not in staging_area_files: + path_in_staging_area = staging_area_path / file_path + path_in_branch = branch_dir / file_path + # print(set(set(branch_files))) + # print(f"path_in_staging_area: {path_in_staging_area}") + # print(f"file_path not in branch_files: {file_path not in set(branch_files)}") + # print(f"glob(str(path_in_staging_area)): {glob(str(path_in_staging_area))}") + if not glob(str(path_in_branch)) or not glob(str(path_in_staging_area)): raise NotImplementedError(f"The file {file_path} was deleted. Deleting files not implemented yet.") - content_in_branch, content_in_common, content_in_staging_area = get_file_content_in_dirs( - branch_dir, common_dir, file_path, staging_area_path - ) - if content_in_common != content_in_branch: - if content_in_common != content_in_staging_area: - raise NotImplementedError( - f"The file {file_path} was changed both in {branch_name} and in current branch." - ) - (staging_area_path / file_path).write_text(content_in_branch) + elif file_path.is_file(): + content_in_common = (common_dir / file_path).read_text() + print(f"content_in_common: {content_in_common}") + content_in_branch = (branch_dir / file_path).read_text() + print(f"content_in_branch: {content_in_branch}") + content_in_staging_area = (staging_area_path / file_path).read_text() + print(f"content_in_staging: {content_in_staging_area}") + if content_in_common != content_in_branch: + if content_in_common != content_in_staging_area: + raise NotImplementedError(f"{file_path} was changed in both branches. Not implemented yet.") + (staging_area_path / file_path).write_text(content_in_branch) for file_path in branch_files: - if file_path not in common_files: + # path_in_common = common_dir / file_path + # if not glob(str(path_in_common)): + if file_path.is_file(): content_in_branch = (branch_dir / file_path).read_text() (staging_area_path / file_path).write_text(content_in_branch) - commit_merge(branch_commit_id, branch_name, head_reference, wit_dir) - - -def commit_merge(branch_commit_id: str, branch_name: str, head_reference: str, wit_dir: Path): activated = get_activated_branch(wit_dir) message = f"Commit after merge of {activated if activated else head_reference} and {branch_name}." commit_function(message, branch_commit_id) -def get_file_content_in_dirs( - branch_dir: Path, common_dir: Path, file_path: Path, staging_area_path: Path -) -> tuple[str, ...]: - content_in_common = (common_dir / file_path).read_text() - content_in_branch = (branch_dir / file_path).read_text() - content_in_staging_area = (staging_area_path / file_path).read_text() - return content_in_branch, content_in_common, content_in_staging_area - - -def get_dirs_and_files( - branch_commit_id: str, common_commit: str, staging_area_path: Path, wit_dir: Path -) -> tuple[Path, Iterator[Path], Path, Iterator[Path], Iterator[Path]]: - common_dir = wit_dir / 'images' / common_commit - common_files = get_all_files_in_directory_and_subs(common_dir) - branch_dir = wit_dir / 'images' / branch_commit_id - branch_files = get_all_files_in_directory_and_subs(branch_dir) - staging_area_files = get_all_files_in_directory_and_subs(staging_area_path) - return branch_dir, branch_files, common_dir, common_files, staging_area_files - - -def get_paths_and_commit_ids(branch_name: str, repository: Path) -> tuple[str, str, Path, Path, Path]: - wit_dir = repository / '.wit' - staging_area_path = wit_dir / 'staging_area' - head_reference = get_head_reference(repository) - last_commit_path = repository / '.wit' / 'images' / head_reference - references_file = wit_dir / 'references.txt' - branch_commit_id = get_commit_id_of_branch(branch_name, references_file) - return branch_commit_id, head_reference, last_commit_path, staging_area_path, wit_dir - - def get_common_commit(wit_dir: Path, branch_commit_id: str, head_reference: str) -> str: branch_parents = set(get_parents_commits(wit_dir, branch_commit_id)) head_parents = set(get_parents_commits(wit_dir, head_reference)) @@ -102,11 +84,21 @@ def get_common_commit(wit_dir: Path, branch_commit_id: str, head_reference: str) def get_parents_commits(wit_dir: Path, commit_id: str) -> Iterator[str]: images_path = wit_dir / 'images' + yield from get_parents_of_commit_id(commit_id, images_path) + + +def get_parents_of_commit_id(commit_id: str, images_path: Path) -> Iterator[str]: while commit_id: commit_file = images_path / (commit_id + ".txt") commit_txt = commit_file.read_text() parent_id_match = regex.match(commit_txt) if parent_id_match: # if parent != None - parent_id = parent_id_match.group('commit_id') - yield parent_id - commit_id = parent_id if parent_id_match else None + parent_id_1 = parent_id_match.group('commit_id_1') + parent_id_2 = parent_id_match.group('commit_id_2') + print(f"*******{parent_id_1}*******") + print(f"*******{parent_id_2}*******") + yield parent_id_1 + if parent_id_2: + yield parent_id_2 + yield from get_parents_of_commit_id(parent_id_2, images_path) + commit_id = parent_id_1 if parent_id_match else None diff --git a/project/status.py b/project/status.py index b7e32cb..5bdc93c 100644 --- a/project/status.py +++ b/project/status.py @@ -1,107 +1,76 @@ -from filecmp import dircmp -import os +from glob import glob from pathlib import Path -from typing import Union, Iterator +from typing import Iterator from errors import WitError from global_functions import get_repository_path, get_head_reference, get_all_files_in_directory_and_subs -# If I do "add_function" to a file / folder inside folder 1 (test\folder1\folder2\...) - -# sometimes all other files/ folders inside don't appear in Untracked files. -# and other times they don't appear in Changes to be committed. Very weired... - def status_function(): repository = get_repository_path(Path.cwd()) if not repository: raise WitError("<.wit> file not found") - staging_area_path = os.path.join(repository, '.wit', 'staging_area') - commit_id = get_head_reference(repository) - message_if_no_commit = "No commit_function was done yet." - commit_path = os.path.join(repository, '.wit', 'images', commit_id) - changes_to_be_committed = show_files(get_changes_to_be_committed(commit_path, staging_area_path)) + staging_area_path = repository / '.wit' / 'staging_area' + last_commit_id = get_head_reference(repository) + message_if_no_commit = "No commit was done yet." + changes_to_be_committed = show_files(get_changes_to_be_committed(repository, staging_area_path)) changes_not_staged_for_commit = show_files(get_changes_not_staged_for_commit(repository, staging_area_path)) untracked_files = show_files(get_untracked_files(repository, staging_area_path)) print( - f"###Commit id:###\n{commit_id if commit_id else message_if_no_commit}\n\n" + f"###Commit id:###\n{last_commit_id if last_commit_id else message_if_no_commit}\n\n" f"###Changes to be committed:###\n{changes_to_be_committed}\n\n" - f"###Changes not staged for commit_function:###\n{changes_not_staged_for_commit}\n\n" + f"###Changes not staged for commit:###\n{changes_not_staged_for_commit}\n\n" f"###Untracked files:###\n{untracked_files}\n" ) -def show_files(files: Iterator[str]) -> str: - return '\n'.join(files) - - -# def get_all_files_in_directory_and_subs(directory: Union[Path, str], start_path: Union[Path, str]) -> Iterator[Path]: -# for root, dirs, files in os.walk(directory, topdown=True): -# if not files and not dirs: -# yield Path(root).relative_to(start_path) -# for file in files: -# file_abs_path = Path(root) / file -# yield file_abs_path.relative_to(start_path) -# for dir_name in dirs: -# yield from get_all_files_in_directory_and_subs(directory / dir_name, start_path) - - -def get_changes_to_be_committed(commit_path: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: - """ - Yield files that the user added to staging area since last commit_function and will be added - to the next commit_function.""" - # sometimes I get the full path of the file and sometimes only the file name. - cmp = dircmp(commit_path, staging_area_path) - yield from get_new_and_changed_files(cmp, staging_area_path) - for d, d_cmp in cmp.subdirs.items(): - yield from get_new_and_changed_files(d_cmp, os.path.join(staging_area_path, d)) - - -def get_new_and_changed_files(cmp: dircmp[Union[str, bytes]], dir_path: Union[Path, str]) -> Iterator[str]: - """Yield files that are new in the directory or have different content.""" - yield from get_new_files_added(cmp, dir_path) - yield from get_changed_files(cmp, dir_path) - - -def get_changed_files(cmp: dircmp[Union[str, bytes]], dir_path: Union[Path, str]) -> Iterator[str]: - """Yield files that have different content.""" - diff_files = cmp.diff_files - start_path = os.path.join(get_repository_path(Path.cwd()), '.wit', 'staging_area') - for diff in diff_files: - file_path = os.path.join(dir_path, diff) - rel = os.path.relpath(file_path, start=start_path) - yield rel - - -def get_new_files_added(cmp: dircmp[Union[str, bytes]], dir_path: Union[Path, str], start_path=None) -> Iterator[str]: - """Yield files that are new in the directory.""" - new_files_added = cmp.right_only - for f in new_files_added: - f_path = Path(dir_path) / f - if os.path.isfile(f_path): - yield f if not start_path else os.path.relpath(f_path, start=start_path) - yield from get_all_files_in_directory_and_subs(f_path, start_path=dir_path if not start_path else start_path) - - -def get_changes_not_staged_for_commit(repository: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: - """Yield files in staging area which their content in repository doesn't match their content in staging area.""" - cmp = dircmp(repository, staging_area_path) - yield from get_changed_files(cmp, staging_area_path) - for common_dir in cmp.common_dirs: - path_in_repository = os.path.join(repository, common_dir) - path_in_staging_area = os.path.join(staging_area_path, common_dir) - yield from get_changes_not_staged_for_commit(path_in_repository, path_in_staging_area) - - -def get_untracked_files(repository: Union[Path, str], staging_area_path: Union[Path, str]) -> Iterator[str]: - """Yield files that exist only in repository and were never added to staging area.""" - # # this gives all untracked files, but I didn't succeed to get full path correctly: - # cmp = dircmp(staging_area_path, repository, ignore=['.wit']) - # yield from get_new_files_added(cmp, repository) - # for common_dir in cmp.common_dirs: - # path_in_repository = os.path.join(repository, common_dir) - # path_in_staging_area = os.path.join(staging_area_path, common_dir) - # yield from get_untracked_files(path_in_repository, path_in_staging_area) - cmp = dircmp(staging_area_path, repository, ignore=['.wit']) - yield from get_new_files_added(cmp, repository) - for d, d_cmp in cmp.subdirs.items(): - yield from get_new_files_added(d_cmp, os.path.join(repository, d), start_path=repository) +def show_files(files: Iterator[Path]) -> str: + txt = '' + for file in files: + txt += str(file) + '\n' + return txt + + +def get_changes_to_be_committed(repository: Path, staging_area_path: Path) -> Iterator[Path]: + last_commit_id = get_head_reference(repository) + files_in_staging_area = get_all_files_in_directory_and_subs(staging_area_path) + if not last_commit_id: + for file_path in files_in_staging_area: + yield file_path + else: + commit_path = repository / '.wit' / 'images' / last_commit_id + for file_path in files_in_staging_area: + path_in_last_commit = commit_path / file_path + if not glob(str(path_in_last_commit)): + yield file_path + elif file_path.is_file(): + if check_if_file_changed(file_path, staging_area_path, commit_path): + yield file_path + + +def check_if_file_changed(file_path: Path, dir_1: Path, dir_2: Path) -> bool: + content_in_dir_1 = (dir_1 / file_path).read_text() + content_in_dir_2 = (dir_2 / file_path).read_text() + return content_in_dir_1 != content_in_dir_2 + + +def get_changes_not_staged_for_commit(repository: Path, staging_area_path: Path) -> Iterator[Path]: + files_in_staging_area = get_all_files_in_directory_and_subs(staging_area_path) + for file_path in files_in_staging_area: + path_in_repository = repository / file_path + if not glob(str(path_in_repository)): + raise NotImplementedError(f"The file {file_path} was deleted. Deleting files not implemented yet.") + if file_path.is_file(): + if check_if_file_changed(file_path, staging_area_path, repository): + yield file_path + + +def get_untracked_files(repository: Path, staging_area_path: Path) -> Iterator[Path]: + files_in_repository = get_all_files_in_directory_and_subs(repository, repo=True) + for file_path in files_in_repository: + path_in_staging_area = staging_area_path / file_path + if not glob(str(path_in_staging_area)): + yield file_path + + +# TODO: מה קורה אם לא עשו שום קומיט עדיין \ No newline at end of file From 7fe4fd5c7851aa2f9c015d7ffaf05e52ec174679 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Tue, 15 Mar 2022 15:51:23 +0200 Subject: [PATCH 37/73] almost finished. todo: merge- change files in repo --- project/add.py | 5 ++- project/branch.py | 4 +- project/checkout.py | 6 +-- project/commit.py | 2 +- project/graph.py | 27 ++++++++---- project/merge.py | 103 ++++++++++++++++++++++++++++++-------------- project/status.py | 7 +-- 7 files changed, 99 insertions(+), 55 deletions(-) diff --git a/project/add.py b/project/add.py index eed58be..39f69eb 100644 --- a/project/add.py +++ b/project/add.py @@ -1,6 +1,7 @@ from glob import glob from pathlib import Path import shutil +from typing import Iterator from errors import WitError from global_functions import get_repository_path @@ -15,7 +16,7 @@ def add_function(path_to_add: str) -> None: save_the_copy(destination, path) -def update_destination(destination: Path, directories_to_copy: tuple[str, ...]) -> Path: +def update_destination(destination: Path, directories_to_copy: Iterator[str]) -> Path: for dir_name in directories_to_copy: destination = destination / dir_name if not glob(str(destination)): @@ -27,7 +28,7 @@ def get_destination(path: Path, repository: Path) -> Path: destination = repository / '.wit' / 'staging_area' file_path = path.relative_to(repository) file_parts = file_path.parts - parents_dirs = file_parts[:-1] + parents_dirs = (part for part in file_parts if part != file_path.name) destination = update_destination(destination, parents_dirs) return destination diff --git a/project/branch.py b/project/branch.py index b5f34bb..ceaa7b0 100644 --- a/project/branch.py +++ b/project/branch.py @@ -1,8 +1,8 @@ from pathlib import Path from commit import get_head_reference -from errors import WitError, BranchExistsError -from global_functions import get_repository_path, get_branches_commits +from errors import BranchExistsError, WitError +from global_functions import get_branches_commits, get_repository_path def branch_function(name: str) -> None: diff --git a/project/checkout.py b/project/checkout.py index d9fe329..2573988 100644 --- a/project/checkout.py +++ b/project/checkout.py @@ -4,11 +4,11 @@ from errors import FilesDoesntMatchError, WitError, BranchDoesntExistError from global_functions import ( - get_repository_path, - get_commit_id_of_branch, get_all_files_in_directory_and_subs, + get_commit_id_of_branch, + get_repository_path, ) -from status import get_changes_to_be_committed, get_changes_not_staged_for_commit +from status import get_changes_not_staged_for_commit, get_changes_to_be_committed def checkout_function(commit_id_or_branch: str) -> None: diff --git a/project/commit.py b/project/commit.py index 4b8906e..ecbd2b1 100644 --- a/project/commit.py +++ b/project/commit.py @@ -7,7 +7,7 @@ from typing import Optional from errors import WitError -from global_functions import get_repository_path, get_head_reference, get_activated_branch +from global_functions import get_activated_branch, get_head_reference, get_repository_path def commit_function(message: str, second_parent: Optional[str] = None) -> None: diff --git a/project/graph.py b/project/graph.py index d73ec45..188bfb1 100644 --- a/project/graph.py +++ b/project/graph.py @@ -3,13 +3,12 @@ import re from errors import WitError -from global_functions import get_repository_path, get_head_reference +from global_functions import get_head_reference, get_repository_path +regex = re.compile(r"^parent = (?P\w{20})(, (?P\w{20}))?$", flags=re.MULTILINE) -regex = re.compile(r"^parent = (?P\w{20})$", flags=re.MULTILINE) - -def graph_function(): +def graph_function() -> None: repository = get_repository_path(Path.cwd()) if not repository: raise WitError("<.wit> file not found") @@ -18,17 +17,26 @@ def graph_function(): dot = init_graph() wit_dir = repository / '.wit' images_path = wit_dir / 'images' + create_nodes(commit_id, dot, images_path) + dot.render(f'Graph {current_commit_id}', wit_dir, view=True, cleanup=True) + + +def create_nodes(commit_id: str, dot: Digraph, images_path: Path) -> None: while commit_id: commit_file = images_path / (commit_id + ".txt") create_node(commit_id, dot) commit_txt = commit_file.read_text() parent_id_match = regex.match(commit_txt) if parent_id_match: - parent_id = parent_id_match.group('commit_id') - create_node(parent_id, dot) - dot.edge(commit_id, parent_id) - commit_id = parent_id if parent_id_match else None - dot.render(f'Graph {current_commit_id}', wit_dir, view=True, cleanup=True) + parent_id_1 = parent_id_match.group('commit_id_1') + parent_id_2 = parent_id_match.group('commit_id_2') + create_node(parent_id_1, dot) + dot.edge(commit_id, parent_id_1) + if parent_id_2: + create_node(parent_id_2, dot) + dot.edge(commit_id, parent_id_2) + create_nodes(parent_id_2, dot, images_path) + commit_id = parent_id_1 if parent_id_match else '' def create_node(commit_id: str, dot: Digraph) -> None: @@ -40,6 +48,7 @@ def init_graph() -> Digraph: 'graph_function', comment='Graph', node_attr={'color': 'lightblue2', 'style': 'filled', 'shape': 'circle'}, + strict=True, ) dot.attr(rankdir='LR', size='8,5') return dot diff --git a/project/merge.py b/project/merge.py index d3a7c10..d3eeaee 100644 --- a/project/merge.py +++ b/project/merge.py @@ -1,20 +1,20 @@ -import re from glob import glob +import os from pathlib import Path +import re from typing import Iterator from commit import commit_function from errors import WitError, MergeError, NoCommonCommitError, FilesDoesntMatchError from global_functions import ( + get_activated_branch, + get_all_files_in_directory_and_subs, get_commit_id_of_branch, get_head_reference, get_repository_path, - get_activated_branch, - get_all_files_in_directory_and_subs, ) from status import get_changes_to_be_committed, get_changes_not_staged_for_commit -# regex = re.compile(r"^parent = (?P\w{20})$", flags=re.MULTILINE) regex = re.compile(r"^parent = (?P\w{20})(, (?P\w{20}))?$", flags=re.MULTILINE) @@ -35,47 +35,86 @@ def merge_function(branch_name: str) -> None: if branch_commit_id == head_reference: raise MergeError('Head is already at the branch you are trying to merge.') common_commit = get_common_commit(wit_dir, branch_commit_id, head_reference) - # print(f"common: {common_commit}") if not common_commit: raise NoCommonCommitError(f"There is no common commit with {branch_name}.") common_dir = wit_dir / 'images' / common_commit branch_dir = wit_dir / 'images' / branch_commit_id - common_files = get_all_files_in_directory_and_subs(common_dir) - branch_files = get_all_files_in_directory_and_subs(branch_dir) + branch_files, common_files = get_common_and_branch_files(branch_dir, common_dir) + check_common_commit_and_update_staging_area(branch_dir, common_dir, common_files, staging_area_path) + check_branch_and_update_staging_area(branch_dir, branch_files, common_dir, staging_area_path) + commit_merge(branch_commit_id, branch_name, head_reference, wit_dir) + + +def check_branch_and_update_staging_area( + branch_dir: Path, branch_files: Iterator[Path], common_dir: Path, staging_area_path: Path +) -> None: + for file_path in branch_files: + path_in_branch, path_in_common, path_in_staging_area = get_file_path_in_all_dirs( + file_path, branch_dir, common_dir, staging_area_path + ) + if not glob(str(path_in_common)): + create_new_file_in_staging_area(file_path, path_in_branch, path_in_staging_area) + + +def check_common_commit_and_update_staging_area( + branch_dir: Path, common_dir: Path, common_files: Iterator[Path], staging_area_path: Path +) -> None: for file_path in common_files: - path_in_staging_area = staging_area_path / file_path - path_in_branch = branch_dir / file_path - # print(set(set(branch_files))) - # print(f"path_in_staging_area: {path_in_staging_area}") - # print(f"file_path not in branch_files: {file_path not in set(branch_files)}") - # print(f"glob(str(path_in_staging_area)): {glob(str(path_in_staging_area))}") + path_in_branch, path_in_common, path_in_staging_area = get_file_path_in_all_dirs( + file_path, branch_dir, common_dir, staging_area_path + ) if not glob(str(path_in_branch)) or not glob(str(path_in_staging_area)): raise NotImplementedError(f"The file {file_path} was deleted. Deleting files not implemented yet.") elif file_path.is_file(): - content_in_common = (common_dir / file_path).read_text() - print(f"content_in_common: {content_in_common}") - content_in_branch = (branch_dir / file_path).read_text() - print(f"content_in_branch: {content_in_branch}") - content_in_staging_area = (staging_area_path / file_path).read_text() - print(f"content_in_staging: {content_in_staging_area}") - if content_in_common != content_in_branch: - if content_in_common != content_in_staging_area: - raise NotImplementedError(f"{file_path} was changed in both branches. Not implemented yet.") - (staging_area_path / file_path).write_text(content_in_branch) - for file_path in branch_files: - # path_in_common = common_dir / file_path - # if not glob(str(path_in_common)): - if file_path.is_file(): - content_in_branch = (branch_dir / file_path).read_text() - (staging_area_path / file_path).write_text(content_in_branch) + update_file_in_staging_area(file_path, path_in_branch, path_in_common, path_in_staging_area) + + +def get_common_and_branch_files(branch_dir: Path, common_dir: Path) -> tuple[Iterator[Path], Iterator[Path]]: + common_files = get_all_files_in_directory_and_subs(common_dir) + branch_files = get_all_files_in_directory_and_subs(branch_dir) + return branch_files, common_files + + +def update_file_in_staging_area( + file_path: Path, path_in_branch: Path, path_in_common: Path, path_in_staging_area: Path +) -> None: + content_in_common = path_in_common.read_text() + content_in_branch = path_in_branch.read_text() + content_in_staging_area = path_in_staging_area.read_text() + if content_in_common != content_in_branch: + if content_in_common != content_in_staging_area: + raise NotImplementedError(f"{file_path} was changed in both branches. Not implemented yet.") + path_in_staging_area.write_text(content_in_branch) + + +def get_file_path_in_all_dirs( + file_path: Path, branch_dir: Path, common_dir: Path, staging_area_path: Path +) -> tuple[Path, ...]: + path_in_common = common_dir / file_path + path_in_staging_area = staging_area_path / file_path + path_in_branch = branch_dir / file_path + return path_in_branch, path_in_common, path_in_staging_area + + +def commit_merge(branch_commit_id: str, branch_name: str, head_reference: str, wit_dir: Path) -> None: activated = get_activated_branch(wit_dir) message = f"Commit after merge of {activated if activated else head_reference} and {branch_name}." commit_function(message, branch_commit_id) +def create_new_file_in_staging_area(file_path: Path, path_in_branch: Path, path_in_staging_area: Path) -> None: + if file_path.is_file(): + content_in_branch = path_in_branch.read_text() + path_in_staging_area.write_text(content_in_branch) + else: + os.mkdir(path_in_staging_area) + + def get_common_commit(wit_dir: Path, branch_commit_id: str, head_reference: str) -> str: branch_parents = set(get_parents_commits(wit_dir, branch_commit_id)) + branch_parents.add(branch_commit_id) head_parents = set(get_parents_commits(wit_dir, head_reference)) + head_parents.add(head_reference) common = branch_parents.intersection(head_parents) if common: return common.pop() @@ -92,13 +131,11 @@ def get_parents_of_commit_id(commit_id: str, images_path: Path) -> Iterator[str] commit_file = images_path / (commit_id + ".txt") commit_txt = commit_file.read_text() parent_id_match = regex.match(commit_txt) - if parent_id_match: # if parent != None + if parent_id_match: parent_id_1 = parent_id_match.group('commit_id_1') parent_id_2 = parent_id_match.group('commit_id_2') - print(f"*******{parent_id_1}*******") - print(f"*******{parent_id_2}*******") yield parent_id_1 if parent_id_2: yield parent_id_2 yield from get_parents_of_commit_id(parent_id_2, images_path) - commit_id = parent_id_1 if parent_id_match else None + commit_id = parent_id_1 if parent_id_match else '' diff --git a/project/status.py b/project/status.py index 5bdc93c..5c08b5e 100644 --- a/project/status.py +++ b/project/status.py @@ -3,10 +3,10 @@ from typing import Iterator from errors import WitError -from global_functions import get_repository_path, get_head_reference, get_all_files_in_directory_and_subs +from global_functions import get_all_files_in_directory_and_subs, get_head_reference, get_repository_path -def status_function(): +def status_function() -> None: repository = get_repository_path(Path.cwd()) if not repository: raise WitError("<.wit> file not found") @@ -71,6 +71,3 @@ def get_untracked_files(repository: Path, staging_area_path: Path) -> Iterator[P path_in_staging_area = staging_area_path / file_path if not glob(str(path_in_staging_area)): yield file_path - - -# TODO: מה קורה אם לא עשו שום קומיט עדיין \ No newline at end of file From 1d8af8b816c218672bbc61685e18e5d7d0cbb0c5 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Wed, 16 Mar 2022 00:06:59 +0200 Subject: [PATCH 38/73] finished --- project/merge.py | 73 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 19 deletions(-) diff --git a/project/merge.py b/project/merge.py index d3eeaee..66ee2ea 100644 --- a/project/merge.py +++ b/project/merge.py @@ -40,33 +40,49 @@ def merge_function(branch_name: str) -> None: common_dir = wit_dir / 'images' / common_commit branch_dir = wit_dir / 'images' / branch_commit_id branch_files, common_files = get_common_and_branch_files(branch_dir, common_dir) - check_common_commit_and_update_staging_area(branch_dir, common_dir, common_files, staging_area_path) - check_branch_and_update_staging_area(branch_dir, branch_files, common_dir, staging_area_path) + check_common_commit_and_update_staging_area_and_repository( + branch_dir, common_dir, common_files, staging_area_path, repository + ) + check_branch_and_update_staging_area_and_repository( + branch_dir, branch_files, common_dir, staging_area_path, repository + ) commit_merge(branch_commit_id, branch_name, head_reference, wit_dir) -def check_branch_and_update_staging_area( - branch_dir: Path, branch_files: Iterator[Path], common_dir: Path, staging_area_path: Path +def check_branch_and_update_staging_area_and_repository( + branch_dir: Path, + branch_files: Iterator[Path], + common_dir: Path, + staging_area_path: Path, + repository: Path, ) -> None: for file_path in branch_files: - path_in_branch, path_in_common, path_in_staging_area = get_file_path_in_all_dirs( - file_path, branch_dir, common_dir, staging_area_path + path_in_branch, path_in_common, path_in_staging_area, path_in_repository = ( + get_file_path_in_all_dirs(file_path, branch_dir, common_dir, staging_area_path, repository) ) if not glob(str(path_in_common)): - create_new_file_in_staging_area(file_path, path_in_branch, path_in_staging_area) + create_new_file_in_staging_area_and_repository( + file_path, path_in_branch, path_in_staging_area, path_in_repository + ) -def check_common_commit_and_update_staging_area( - branch_dir: Path, common_dir: Path, common_files: Iterator[Path], staging_area_path: Path +def check_common_commit_and_update_staging_area_and_repository( + branch_dir: Path, + common_dir: Path, + common_files: Iterator[Path], + staging_area_path: Path, + repository: Path, ) -> None: for file_path in common_files: - path_in_branch, path_in_common, path_in_staging_area = get_file_path_in_all_dirs( - file_path, branch_dir, common_dir, staging_area_path + path_in_branch, path_in_common, path_in_staging_area, path_in_repository = ( + get_file_path_in_all_dirs(file_path, branch_dir, common_dir, staging_area_path, repository) ) if not glob(str(path_in_branch)) or not glob(str(path_in_staging_area)): raise NotImplementedError(f"The file {file_path} was deleted. Deleting files not implemented yet.") elif file_path.is_file(): - update_file_in_staging_area(file_path, path_in_branch, path_in_common, path_in_staging_area) + update_file_in_staging_area_and_repository( + file_path, path_in_branch, path_in_common, path_in_staging_area, path_in_repository + ) def get_common_and_branch_files(branch_dir: Path, common_dir: Path) -> tuple[Iterator[Path], Iterator[Path]]: @@ -75,8 +91,12 @@ def get_common_and_branch_files(branch_dir: Path, common_dir: Path) -> tuple[Ite return branch_files, common_files -def update_file_in_staging_area( - file_path: Path, path_in_branch: Path, path_in_common: Path, path_in_staging_area: Path +def update_file_in_staging_area_and_repository( + file_path: Path, + path_in_branch: Path, + path_in_common: Path, + path_in_staging_area: Path, + path_in_repository: Path, ) -> None: content_in_common = path_in_common.read_text() content_in_branch = path_in_branch.read_text() @@ -85,15 +105,21 @@ def update_file_in_staging_area( if content_in_common != content_in_staging_area: raise NotImplementedError(f"{file_path} was changed in both branches. Not implemented yet.") path_in_staging_area.write_text(content_in_branch) + path_in_repository.write_text(content_in_branch) def get_file_path_in_all_dirs( - file_path: Path, branch_dir: Path, common_dir: Path, staging_area_path: Path + file_path: Path, + branch_dir: Path, + common_dir: Path, + staging_area_path: Path, + repository: Path, ) -> tuple[Path, ...]: path_in_common = common_dir / file_path path_in_staging_area = staging_area_path / file_path path_in_branch = branch_dir / file_path - return path_in_branch, path_in_common, path_in_staging_area + path_in_repository = repository / file_path + return path_in_branch, path_in_common, path_in_staging_area, path_in_repository def commit_merge(branch_commit_id: str, branch_name: str, head_reference: str, wit_dir: Path) -> None: @@ -102,19 +128,28 @@ def commit_merge(branch_commit_id: str, branch_name: str, head_reference: str, w commit_function(message, branch_commit_id) -def create_new_file_in_staging_area(file_path: Path, path_in_branch: Path, path_in_staging_area: Path) -> None: +def create_new_file_in_staging_area_and_repository( + file_path: Path, + path_in_branch: Path, + path_in_staging_area: Path, + path_in_repository: Path, +) -> None: if file_path.is_file(): content_in_branch = path_in_branch.read_text() path_in_staging_area.write_text(content_in_branch) + path_in_repository.write_text(content_in_branch) else: os.mkdir(path_in_staging_area) + os.mkdir(path_in_repository) def get_common_commit(wit_dir: Path, branch_commit_id: str, head_reference: str) -> str: branch_parents = set(get_parents_commits(wit_dir, branch_commit_id)) - branch_parents.add(branch_commit_id) head_parents = set(get_parents_commits(wit_dir, head_reference)) - head_parents.add(head_reference) + if branch_commit_id in head_parents: + return branch_commit_id + if head_reference in branch_parents: + return head_reference common = branch_parents.intersection(head_parents) if common: return common.pop() From 66c34664ea11b6cb1827b944bbcf3e810514ae0c Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Sun, 20 Mar 2022 12:28:42 +0200 Subject: [PATCH 39/73] isort & black --- project/add.py | 6 +- project/branch.py | 6 +- project/checkout.py | 37 +++++----- project/commit.py | 58 +++++++++------- project/global_functions.py | 30 ++++---- project/graph.py | 31 +++++---- project/init.py | 10 +-- project/merge.py | 132 +++++++++++++++++++++--------------- project/status.py | 34 +++++++--- project/wit.py | 11 ++- tests/__init__.py | 0 tests/conftest.py | 22 ------ tests/test_add.py | 44 ------------ tests/test_init.py | 13 ---- 14 files changed, 209 insertions(+), 225 deletions(-) delete mode 100644 tests/__init__.py delete mode 100644 tests/conftest.py delete mode 100644 tests/test_add.py delete mode 100644 tests/test_init.py diff --git a/project/add.py b/project/add.py index 39f69eb..06eed9a 100644 --- a/project/add.py +++ b/project/add.py @@ -1,8 +1,10 @@ +import shutil from glob import glob from pathlib import Path -import shutil from typing import Iterator +import flask +import pytest from errors import WitError from global_functions import get_repository_path @@ -25,7 +27,7 @@ def update_destination(destination: Path, directories_to_copy: Iterator[str]) -> def get_destination(path: Path, repository: Path) -> Path: - destination = repository / '.wit' / 'staging_area' + destination = repository / ".wit" / "staging_area" file_path = path.relative_to(repository) file_parts = file_path.parts parents_dirs = (part for part in file_parts if part != file_path.name) diff --git a/project/branch.py b/project/branch.py index ceaa7b0..0858125 100644 --- a/project/branch.py +++ b/project/branch.py @@ -9,10 +9,10 @@ def branch_function(name: str) -> None: repository = get_repository_path(Path.cwd()) if not repository: raise WitError("<.wit> file not found") - references_file = repository / '.wit' / 'references.txt' + references_file = repository / ".wit" / "references.txt" existing_branches = get_branches_commits(references_file) if name in existing_branches: raise BranchExistsError(f"Branch {name} already exists.") commit_id = get_head_reference(repository) - with references_file.open('a') as ref_file: - ref_file.write(f'\n{name}={commit_id}') + with references_file.open("a") as ref_file: + ref_file.write(f"\n{name}={commit_id}") diff --git a/project/checkout.py b/project/checkout.py index 2573988..3e6621e 100644 --- a/project/checkout.py +++ b/project/checkout.py @@ -1,8 +1,8 @@ -from pathlib import Path import shutil +from pathlib import Path from typing import Union -from errors import FilesDoesntMatchError, WitError, BranchDoesntExistError +from errors import BranchDoesntExistError, FilesDoesntMatchError, WitError from global_functions import ( get_all_files_in_directory_and_subs, get_commit_id_of_branch, @@ -13,53 +13,58 @@ def checkout_function(commit_id_or_branch: str) -> None: repository = get_repository_path(Path.cwd()) - staging_area_path = repository / '.wit' / 'staging_area' + staging_area_path = repository / ".wit" / "staging_area" if not repository: raise WitError("<.wit> file not found") - if ( - list(get_changes_to_be_committed(repository, staging_area_path)) - or list(get_changes_not_staged_for_commit(repository, staging_area_path)) + if list(get_changes_to_be_committed(repository, staging_area_path)) or list( + get_changes_not_staged_for_commit(repository, staging_area_path) ): - raise FilesDoesntMatchError("There are files added or changed after last commit_function") - references_file = repository / '.wit' / 'references.txt' + raise FilesDoesntMatchError( + "There are files added or changed after last commit_function" + ) + references_file = repository / ".wit" / "references.txt" commit_id = get_commit_id_of_branch(commit_id_or_branch, references_file) if not commit_id: raise BranchDoesntExistError("Branch doesn't exist.") if commit_id != commit_id_or_branch: write_activated(commit_id_or_branch, repository) else: - write_activated('', repository) - commit_path = repository / '.wit' / 'images' / commit_id + write_activated("", repository) + commit_path = repository / ".wit" / "images" / commit_id update_files_in_main_folder(commit_path, repository) update_head_in_references_file(commit_id, references_file) update_staging_area_folder(staging_area_path, commit_path) def write_activated(commit_id_or_branch: str, repository: Path) -> None: - activated_path = repository / '.wit' / 'activated.txt' + activated_path = repository / ".wit" / "activated.txt" activated_path.write_text(commit_id_or_branch) def update_head_in_references_file(commit_id: str, references_file: Path) -> None: with references_file.open() as file: branches = file.readlines()[1:] - branches_txt = ''.join(branches) - references_file.write_text(f'HEAD={commit_id}\n{branches_txt}') + branches_txt = "".join(branches) + references_file.write_text(f"HEAD={commit_id}\n{branches_txt}") -def update_files_in_main_folder(commit_path: Union[str, Path], repository: Path) -> None: +def update_files_in_main_folder( + commit_path: Union[str, Path], repository: Path +) -> None: files_committed = get_all_files_in_directory_and_subs(commit_path) for committed_file in files_committed: path_in_commit = commit_path / committed_file if path_in_commit.is_file(): - with open(path_in_commit, 'r') as committed_file_h: + with open(path_in_commit, "r") as committed_file_h: content = committed_file_h.read() path_in_repository = repository / committed_file with open(path_in_repository, "w") as original_file: original_file.write(content) -def update_staging_area_folder(staging_area_path: Union[str, Path], commit_path: Union[str, Path]): +def update_staging_area_folder( + staging_area_path: Union[str, Path], commit_path: Union[str, Path] +): for file_or_dir in Path(staging_area_path).iterdir(): if file_or_dir.is_file(): file_or_dir.unlink() diff --git a/project/commit.py b/project/commit.py index ecbd2b1..f8b51dd 100644 --- a/project/commit.py +++ b/project/commit.py @@ -1,22 +1,28 @@ import datetime import os -from pathlib import Path import random import re import shutil +from pathlib import Path from typing import Optional from errors import WitError -from global_functions import get_activated_branch, get_head_reference, get_repository_path +from global_functions import ( + get_activated_branch, + get_head_reference, + get_repository_path, +) def commit_function(message: str, second_parent: Optional[str] = None) -> None: repository = get_repository_path(Path.cwd()) if not repository: raise WitError("<.wit> file not found") - images_path = repository / '.wit' / 'images' + images_path = repository / ".wit" / "images" path_of_new_folder = create_commit_folder(images_path) - create_commit_txt_file(repository, images_path, path_of_new_folder, message, second_parent) + create_commit_txt_file( + repository, images_path, path_of_new_folder, message, second_parent + ) save_files(repository, path_of_new_folder) commit_id = os.path.basename(path_of_new_folder) write_references(commit_id, repository) @@ -31,31 +37,31 @@ def create_commit_folder(images_path: Path) -> Path: def create_folder_name() -> str: length = 20 - chars = '1234567890abcdef' - folder_name = ''.join(random.choices(chars, k=length)) + chars = "1234567890abcdef" + folder_name = "".join(random.choices(chars, k=length)) return folder_name def create_commit_txt_file( - repository: Path, - images_path: Path, - path_of_new_folder: Path, - message: str, - second_parent: Optional[str] = None, + repository: Path, + images_path: Path, + path_of_new_folder: Path, + message: str, + second_parent: Optional[str] = None, ) -> None: parent_head = get_head_reference(repository) if second_parent: - parent_head += ', ' + second_parent - txt_file = images_path / (path_of_new_folder.name + '.txt') + parent_head += ", " + second_parent + txt_file = images_path / (path_of_new_folder.name + ".txt") txt_file.write_text( - f'parent = {parent_head if parent_head else None}\n' + f"parent = {parent_head if parent_head else None}\n" f'date = {datetime.datetime.now().strftime("%c")}\n' - f'message = {message}' + f"message = {message}" ) def save_files(repository: Path, path_of_new_folder: Path) -> None: - staging_area_path = repository / '.wit' / 'staging_area' + staging_area_path = repository / ".wit" / "staging_area" for item in os.listdir(staging_area_path): src = staging_area_path / item dst = path_of_new_folder / item @@ -66,19 +72,25 @@ def save_files(repository: Path, path_of_new_folder: Path) -> None: def write_references(commit_id: str, repository: Path) -> None: - wit_folder = repository / '.wit' - references_file = wit_folder / 'references.txt' + wit_folder = repository / ".wit" + references_file = wit_folder / "references.txt" parent_head = get_head_reference(repository) activated_branch = get_activated_branch(wit_folder) if references_file.exists(): - change_head_and_branch_id(activated_branch, commit_id, parent_head, references_file) + change_head_and_branch_id( + activated_branch, commit_id, parent_head, references_file + ) else: - references_file.write_text(f'HEAD={commit_id}\n{"=".join((activated_branch, commit_id))}') + references_file.write_text( + f'HEAD={commit_id}\n{"=".join((activated_branch, commit_id))}' + ) -def change_head_and_branch_id(activated_branch: str, commit_id: str, parent_head: str, references_file: Path) -> None: - regex = re.compile(fr"^{activated_branch}={parent_head}$", flags=re.MULTILINE) - head_regex = re.compile(fr"^HEAD={parent_head}$", flags=re.MULTILINE) +def change_head_and_branch_id( + activated_branch: str, commit_id: str, parent_head: str, references_file: Path +) -> None: + regex = re.compile(rf"^{activated_branch}={parent_head}$", flags=re.MULTILINE) + head_regex = re.compile(rf"^HEAD={parent_head}$", flags=re.MULTILINE) data = references_file.read_text() match = regex.findall(data) new = regex.sub(f"{activated_branch}={commit_id}", data) if match else data diff --git a/project/global_functions.py b/project/global_functions.py index 73cf29c..ce92a50 100644 --- a/project/global_functions.py +++ b/project/global_functions.py @@ -1,18 +1,18 @@ import os +import re from glob import glob from pathlib import Path -import re -from typing import Optional, Iterator +from typing import Iterator, Optional branch_regex = re.compile(r"^(?P\w+)=(?P\w{20})$") def get_repository_path(path: Path) -> Optional[Path]: if path.is_dir(): - if glob(str(path / '.wit')): + if glob(str(path / ".wit")): return path for directory in path.parents: - if glob(str(directory / '.wit')): + if glob(str(directory / ".wit")): return directory return None @@ -23,7 +23,7 @@ def get_commit_id_of_branch(branch: str, references_file: Path) -> str: return branches_commits_dict[branch] if branch in branches_commits_dict.values(): return branch - return '' + return "" def get_branches_commits(references_file: Path) -> dict[str, str]: @@ -31,32 +31,34 @@ def get_branches_commits(references_file: Path) -> dict[str, str]: branches_commits_dict = {} for line in file: match = branch_regex.match(line) - branches_commits_dict[match.group('branch_name')] = match.group('branch_id') + branches_commits_dict[match.group("branch_name")] = match.group("branch_id") return branches_commits_dict def get_head_reference(repository: Path) -> str: - wit_folder = repository.joinpath('.wit') - references_file = wit_folder.joinpath('references.txt') + wit_folder = repository.joinpath(".wit") + references_file = wit_folder.joinpath("references.txt") if references_file.exists(): - return get_commit_id_of_branch('HEAD', references_file) - return '' + return get_commit_id_of_branch("HEAD", references_file) + return "" def get_activated_branch(wit_folder: Path) -> str: - activated_path = wit_folder / 'activated.txt' + activated_path = wit_folder / "activated.txt" return activated_path.read_text() -def get_all_files_in_directory_and_subs(directory: Path, repo: bool = False) -> Iterator[Path]: +def get_all_files_in_directory_and_subs( + directory: Path, repo: bool = False +) -> Iterator[Path]: if repo: for root, dirs, files in os.walk(directory, topdown=True): if files: for file in files: - if '.wit' not in root: + if ".wit" not in root: yield (Path(root) / file).relative_to(directory) else: - if '.wit' not in root and not dirs: + if ".wit" not in root and not dirs: yield Path(root).relative_to(directory) else: for root, dirs, files in os.walk(directory, topdown=True): diff --git a/project/graph.py b/project/graph.py index 188bfb1..a4a53b3 100644 --- a/project/graph.py +++ b/project/graph.py @@ -1,11 +1,14 @@ -from graphviz import Digraph -from pathlib import Path import re +from pathlib import Path from errors import WitError from global_functions import get_head_reference, get_repository_path +from graphviz import Digraph -regex = re.compile(r"^parent = (?P\w{20})(, (?P\w{20}))?$", flags=re.MULTILINE) +regex = re.compile( + r"^parent = (?P\w{20})(, (?P\w{20}))?$", + flags=re.MULTILINE, +) def graph_function() -> None: @@ -15,10 +18,10 @@ def graph_function() -> None: current_commit_id = get_head_reference(repository) commit_id = current_commit_id dot = init_graph() - wit_dir = repository / '.wit' - images_path = wit_dir / 'images' + wit_dir = repository / ".wit" + images_path = wit_dir / "images" create_nodes(commit_id, dot, images_path) - dot.render(f'Graph {current_commit_id}', wit_dir, view=True, cleanup=True) + dot.render(f"Graph {current_commit_id}", wit_dir, view=True, cleanup=True) def create_nodes(commit_id: str, dot: Digraph, images_path: Path) -> None: @@ -28,27 +31,27 @@ def create_nodes(commit_id: str, dot: Digraph, images_path: Path) -> None: commit_txt = commit_file.read_text() parent_id_match = regex.match(commit_txt) if parent_id_match: - parent_id_1 = parent_id_match.group('commit_id_1') - parent_id_2 = parent_id_match.group('commit_id_2') + parent_id_1 = parent_id_match.group("commit_id_1") + parent_id_2 = parent_id_match.group("commit_id_2") create_node(parent_id_1, dot) dot.edge(commit_id, parent_id_1) if parent_id_2: create_node(parent_id_2, dot) dot.edge(commit_id, parent_id_2) create_nodes(parent_id_2, dot, images_path) - commit_id = parent_id_1 if parent_id_match else '' + commit_id = parent_id_1 if parent_id_match else "" def create_node(commit_id: str, dot: Digraph) -> None: - dot.node(commit_id, commit_id[:6] + '...') + dot.node(commit_id, commit_id[:6] + "...") def init_graph() -> Digraph: dot = Digraph( - 'graph_function', - comment='Graph', - node_attr={'color': 'lightblue2', 'style': 'filled', 'shape': 'circle'}, + "graph_function", + comment="Graph", + node_attr={"color": "lightblue2", "style": "filled", "shape": "circle"}, strict=True, ) - dot.attr(rankdir='LR', size='8,5') + dot.attr(rankdir="LR", size="8,5") return dot diff --git a/project/init.py b/project/init.py index ea2a385..126aac0 100644 --- a/project/init.py +++ b/project/init.py @@ -6,11 +6,11 @@ def init_function() -> None: cwd = os.getcwd() - wit_path = os.path.join(cwd, '.wit') + wit_path = os.path.join(cwd, ".wit") if os.path.exists(wit_path): raise WitExistsError("The folder already has .wit directory") os.mkdir(wit_path) - os.mkdir(os.path.join(wit_path, 'images')) - os.mkdir(os.path.join(wit_path, 'staging_area')) - activated_path = os.path.join(wit_path, 'activated.txt') - Path(activated_path).write_text('master') + os.mkdir(os.path.join(wit_path, "images")) + os.mkdir(os.path.join(wit_path, "staging_area")) + activated_path = os.path.join(wit_path, "activated.txt") + Path(activated_path).write_text("master") diff --git a/project/merge.py b/project/merge.py index 66ee2ea..ea431cd 100644 --- a/project/merge.py +++ b/project/merge.py @@ -1,11 +1,11 @@ -from glob import glob import os -from pathlib import Path import re +from glob import glob +from pathlib import Path from typing import Iterator from commit import commit_function -from errors import WitError, MergeError, NoCommonCommitError, FilesDoesntMatchError +from errors import FilesDoesntMatchError, MergeError, NoCommonCommitError, WitError from global_functions import ( get_activated_branch, get_all_files_in_directory_and_subs, @@ -13,32 +13,36 @@ get_head_reference, get_repository_path, ) -from status import get_changes_to_be_committed, get_changes_not_staged_for_commit +from status import get_changes_not_staged_for_commit, get_changes_to_be_committed -regex = re.compile(r"^parent = (?P\w{20})(, (?P\w{20}))?$", flags=re.MULTILINE) +regex = re.compile( + r"^parent = (?P\w{20})(, (?P\w{20}))?$", + flags=re.MULTILINE, +) def merge_function(branch_name: str) -> None: repository = get_repository_path(Path.cwd()) if not repository: raise WitError("<.wit> file not found") - wit_dir = repository / '.wit' - staging_area_path = wit_dir / 'staging_area' - references_file = wit_dir / 'references.txt' + wit_dir = repository / ".wit" + staging_area_path = wit_dir / "staging_area" + references_file = wit_dir / "references.txt" head_reference = get_head_reference(repository) branch_commit_id = get_commit_id_of_branch(branch_name, references_file) - if ( - list(get_changes_to_be_committed(repository, staging_area_path)) - or list(get_changes_not_staged_for_commit(repository, staging_area_path)) + if list(get_changes_to_be_committed(repository, staging_area_path)) or list( + get_changes_not_staged_for_commit(repository, staging_area_path) ): - raise FilesDoesntMatchError("There are files added or changed after last commit_function") + raise FilesDoesntMatchError( + "There are files added or changed after last commit_function" + ) if branch_commit_id == head_reference: - raise MergeError('Head is already at the branch you are trying to merge.') + raise MergeError("Head is already at the branch you are trying to merge.") common_commit = get_common_commit(wit_dir, branch_commit_id, head_reference) if not common_commit: raise NoCommonCommitError(f"There is no common commit with {branch_name}.") - common_dir = wit_dir / 'images' / common_commit - branch_dir = wit_dir / 'images' / branch_commit_id + common_dir = wit_dir / "images" / common_commit + branch_dir = wit_dir / "images" / branch_commit_id branch_files, common_files = get_common_and_branch_files(branch_dir, common_dir) check_common_commit_and_update_staging_area_and_repository( branch_dir, common_dir, common_files, staging_area_path, repository @@ -50,15 +54,20 @@ def merge_function(branch_name: str) -> None: def check_branch_and_update_staging_area_and_repository( - branch_dir: Path, - branch_files: Iterator[Path], - common_dir: Path, - staging_area_path: Path, - repository: Path, + branch_dir: Path, + branch_files: Iterator[Path], + common_dir: Path, + staging_area_path: Path, + repository: Path, ) -> None: for file_path in branch_files: - path_in_branch, path_in_common, path_in_staging_area, path_in_repository = ( - get_file_path_in_all_dirs(file_path, branch_dir, common_dir, staging_area_path, repository) + ( + path_in_branch, + path_in_common, + path_in_staging_area, + path_in_repository, + ) = get_file_path_in_all_dirs( + file_path, branch_dir, common_dir, staging_area_path, repository ) if not glob(str(path_in_common)): create_new_file_in_staging_area_and_repository( @@ -67,53 +76,68 @@ def check_branch_and_update_staging_area_and_repository( def check_common_commit_and_update_staging_area_and_repository( - branch_dir: Path, - common_dir: Path, - common_files: Iterator[Path], - staging_area_path: Path, - repository: Path, + branch_dir: Path, + common_dir: Path, + common_files: Iterator[Path], + staging_area_path: Path, + repository: Path, ) -> None: for file_path in common_files: - path_in_branch, path_in_common, path_in_staging_area, path_in_repository = ( - get_file_path_in_all_dirs(file_path, branch_dir, common_dir, staging_area_path, repository) + ( + path_in_branch, + path_in_common, + path_in_staging_area, + path_in_repository, + ) = get_file_path_in_all_dirs( + file_path, branch_dir, common_dir, staging_area_path, repository ) if not glob(str(path_in_branch)) or not glob(str(path_in_staging_area)): - raise NotImplementedError(f"The file {file_path} was deleted. Deleting files not implemented yet.") + raise NotImplementedError( + f"The file {file_path} was deleted. Deleting files not implemented yet." + ) elif file_path.is_file(): update_file_in_staging_area_and_repository( - file_path, path_in_branch, path_in_common, path_in_staging_area, path_in_repository + file_path, + path_in_branch, + path_in_common, + path_in_staging_area, + path_in_repository, ) -def get_common_and_branch_files(branch_dir: Path, common_dir: Path) -> tuple[Iterator[Path], Iterator[Path]]: +def get_common_and_branch_files( + branch_dir: Path, common_dir: Path +) -> tuple[Iterator[Path], Iterator[Path]]: common_files = get_all_files_in_directory_and_subs(common_dir) branch_files = get_all_files_in_directory_and_subs(branch_dir) return branch_files, common_files def update_file_in_staging_area_and_repository( - file_path: Path, - path_in_branch: Path, - path_in_common: Path, - path_in_staging_area: Path, - path_in_repository: Path, + file_path: Path, + path_in_branch: Path, + path_in_common: Path, + path_in_staging_area: Path, + path_in_repository: Path, ) -> None: content_in_common = path_in_common.read_text() content_in_branch = path_in_branch.read_text() content_in_staging_area = path_in_staging_area.read_text() if content_in_common != content_in_branch: if content_in_common != content_in_staging_area: - raise NotImplementedError(f"{file_path} was changed in both branches. Not implemented yet.") + raise NotImplementedError( + f"{file_path} was changed in both branches. Not implemented yet." + ) path_in_staging_area.write_text(content_in_branch) path_in_repository.write_text(content_in_branch) def get_file_path_in_all_dirs( - file_path: Path, - branch_dir: Path, - common_dir: Path, - staging_area_path: Path, - repository: Path, + file_path: Path, + branch_dir: Path, + common_dir: Path, + staging_area_path: Path, + repository: Path, ) -> tuple[Path, ...]: path_in_common = common_dir / file_path path_in_staging_area = staging_area_path / file_path @@ -122,17 +146,19 @@ def get_file_path_in_all_dirs( return path_in_branch, path_in_common, path_in_staging_area, path_in_repository -def commit_merge(branch_commit_id: str, branch_name: str, head_reference: str, wit_dir: Path) -> None: +def commit_merge( + branch_commit_id: str, branch_name: str, head_reference: str, wit_dir: Path +) -> None: activated = get_activated_branch(wit_dir) message = f"Commit after merge of {activated if activated else head_reference} and {branch_name}." commit_function(message, branch_commit_id) def create_new_file_in_staging_area_and_repository( - file_path: Path, - path_in_branch: Path, - path_in_staging_area: Path, - path_in_repository: Path, + file_path: Path, + path_in_branch: Path, + path_in_staging_area: Path, + path_in_repository: Path, ) -> None: if file_path.is_file(): content_in_branch = path_in_branch.read_text() @@ -153,11 +179,11 @@ def get_common_commit(wit_dir: Path, branch_commit_id: str, head_reference: str) common = branch_parents.intersection(head_parents) if common: return common.pop() - return '' + return "" def get_parents_commits(wit_dir: Path, commit_id: str) -> Iterator[str]: - images_path = wit_dir / 'images' + images_path = wit_dir / "images" yield from get_parents_of_commit_id(commit_id, images_path) @@ -167,10 +193,10 @@ def get_parents_of_commit_id(commit_id: str, images_path: Path) -> Iterator[str] commit_txt = commit_file.read_text() parent_id_match = regex.match(commit_txt) if parent_id_match: - parent_id_1 = parent_id_match.group('commit_id_1') - parent_id_2 = parent_id_match.group('commit_id_2') + parent_id_1 = parent_id_match.group("commit_id_1") + parent_id_2 = parent_id_match.group("commit_id_2") yield parent_id_1 if parent_id_2: yield parent_id_2 yield from get_parents_of_commit_id(parent_id_2, images_path) - commit_id = parent_id_1 if parent_id_match else '' + commit_id = parent_id_1 if parent_id_match else "" diff --git a/project/status.py b/project/status.py index 5c08b5e..cca1a2f 100644 --- a/project/status.py +++ b/project/status.py @@ -3,18 +3,26 @@ from typing import Iterator from errors import WitError -from global_functions import get_all_files_in_directory_and_subs, get_head_reference, get_repository_path +from global_functions import ( + get_all_files_in_directory_and_subs, + get_head_reference, + get_repository_path, +) def status_function() -> None: repository = get_repository_path(Path.cwd()) if not repository: raise WitError("<.wit> file not found") - staging_area_path = repository / '.wit' / 'staging_area' + staging_area_path = repository / ".wit" / "staging_area" last_commit_id = get_head_reference(repository) message_if_no_commit = "No commit was done yet." - changes_to_be_committed = show_files(get_changes_to_be_committed(repository, staging_area_path)) - changes_not_staged_for_commit = show_files(get_changes_not_staged_for_commit(repository, staging_area_path)) + changes_to_be_committed = show_files( + get_changes_to_be_committed(repository, staging_area_path) + ) + changes_not_staged_for_commit = show_files( + get_changes_not_staged_for_commit(repository, staging_area_path) + ) untracked_files = show_files(get_untracked_files(repository, staging_area_path)) print( f"###Commit id:###\n{last_commit_id if last_commit_id else message_if_no_commit}\n\n" @@ -25,20 +33,22 @@ def status_function() -> None: def show_files(files: Iterator[Path]) -> str: - txt = '' + txt = "" for file in files: - txt += str(file) + '\n' + txt += str(file) + "\n" return txt -def get_changes_to_be_committed(repository: Path, staging_area_path: Path) -> Iterator[Path]: +def get_changes_to_be_committed( + repository: Path, staging_area_path: Path +) -> Iterator[Path]: last_commit_id = get_head_reference(repository) files_in_staging_area = get_all_files_in_directory_and_subs(staging_area_path) if not last_commit_id: for file_path in files_in_staging_area: yield file_path else: - commit_path = repository / '.wit' / 'images' / last_commit_id + commit_path = repository / ".wit" / "images" / last_commit_id for file_path in files_in_staging_area: path_in_last_commit = commit_path / file_path if not glob(str(path_in_last_commit)): @@ -54,12 +64,16 @@ def check_if_file_changed(file_path: Path, dir_1: Path, dir_2: Path) -> bool: return content_in_dir_1 != content_in_dir_2 -def get_changes_not_staged_for_commit(repository: Path, staging_area_path: Path) -> Iterator[Path]: +def get_changes_not_staged_for_commit( + repository: Path, staging_area_path: Path +) -> Iterator[Path]: files_in_staging_area = get_all_files_in_directory_and_subs(staging_area_path) for file_path in files_in_staging_area: path_in_repository = repository / file_path if not glob(str(path_in_repository)): - raise NotImplementedError(f"The file {file_path} was deleted. Deleting files not implemented yet.") + raise NotImplementedError( + f"The file {file_path} was deleted. Deleting files not implemented yet." + ) if file_path.is_file(): if check_if_file_changed(file_path, staging_area_path, repository): yield file_path diff --git a/project/wit.py b/project/wit.py index 061d9e1..255f292 100644 --- a/project/wit.py +++ b/project/wit.py @@ -1,5 +1,4 @@ import click - from add import add_function from branch import branch_function from checkout import checkout_function @@ -22,14 +21,14 @@ def init(): @cli.command() -@click.argument('path', type=click.Path(exists=True)) +@click.argument("path", type=click.Path(exists=True)) def add(path): """Add file or folder to staging area.""" add_function(path) @cli.command() -@click.argument('message') +@click.argument("message") def commit(message): """Save image of current files in staging area. Save a message. @@ -44,14 +43,14 @@ def status(): @cli.command() -@click.argument('commit_id_or_branch') +@click.argument("commit_id_or_branch") def checkout(commit_id_or_branch): """Switch to another commit or branch, which will be activated.""" checkout_function(commit_id_or_branch) @cli.command() -@click.argument('branch_name') +@click.argument("branch_name") def branch(branch_name): """Create a new branch.""" branch_function(branch_name) @@ -64,7 +63,7 @@ def graph(): @cli.command() -@click.argument('branch_name') +@click.argument("branch_name") def merge(branch_name): """Merge the files in the current commit with the branch.""" merge_function(branch_name) diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/tests/conftest.py b/tests/conftest.py deleted file mode 100644 index 8d7b6fb..0000000 --- a/tests/conftest.py +++ /dev/null @@ -1,22 +0,0 @@ -import os -import shutil -from pathlib import Path -import pytest - - -@pytest.fixture() -def test_folder(): - folder_name = 'test_wit' - os.mkdir(folder_name) - file1_path = Path(folder_name).joinpath('file1.txt') - file1_path.write_text("") - folder1_path = os.path.join(folder_name, 'folder1') - os.mkdir(folder1_path) - file2_path = Path(folder1_path).joinpath('file2.txt') - file2_path.write_text("") - folder2_path = os.path.join(folder1_path, 'folder2') - os.mkdir(folder2_path) - file3_path = Path(folder2_path).joinpath('file3.txt') - file3_path.write_text("") - yield folder_name - shutil.rmtree(folder_name) diff --git a/tests/test_add.py b/tests/test_add.py deleted file mode 100644 index aa7a589..0000000 --- a/tests/test_add.py +++ /dev/null @@ -1,44 +0,0 @@ -import os -from pathlib import Path -import pytest -from project import add, init - - -# @pytest.mark.parametrize( -# 'file_path, parent', -# [ -# (Path('')) -# ] -# ) - - - -@pytest.mark.parametrize( - 'path, parent', - [ - (Path('test_wit').joinpath('file1.txt'), Path('test_wit')), - (Path('test_wit').joinpath('folder1', 'folder2'), Path('test_wit')), - (Path('test_wit').joinpath('folder1', 'folder2', 'file3'), Path('test_wit')) - ] -) -def test_get_directory_with_wit(test_folder, path, parent): - init.init_function(test_folder) - assert add.get_repository_path(path) == parent - - -@pytest.mark.parametrize( - 'destination_in_wit, file, new_destination', - [ - (Path('file1.txt'), Path('test_wit').joinpath('file1.txt'), Path('test_wit')), - (Path('folder1').joinpath('folder2'), Path('test_wit')), - (Path('test_wit').joinpath('folder1', 'folder2', 'file3'), Path('test_wit')) - ] -) -def test_save_the_copy(test_folder, destination_in_wit, file, new_destination): - init.init_function(test_folder) - destination = Path('test_wit').joinpath('.wit', 'staging_area') - add.save_the_copy(destination.joinpath(destination_in_wit), file) - assert destination.joinpath(destination_in_wit).exists() - -# def test_add(): -# pass \ No newline at end of file diff --git a/tests/test_init.py b/tests/test_init.py deleted file mode 100644 index 228e6b6..0000000 --- a/tests/test_init.py +++ /dev/null @@ -1,13 +0,0 @@ -from pathlib import Path -import pytest - -from project import init - - -def test_init(test_folder): - init.init_function(test_folder) - test_wit_path = Path(test_folder).joinpath('.wit') - assert test_wit_path.is_dir() - assert test_wit_path.joinpath('images').is_dir() - assert test_wit_path.joinpath('staging_area').is_dir() - assert test_wit_path.joinpath('activated.txt').read_text() == 'master' From ad1b99267fca8e814c647635f71d1bcb04b6de46 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Sun, 20 Mar 2022 23:57:54 +0200 Subject: [PATCH 40/73] change to utils. add isort.cfg --- .isort.cfg | 3 +++ project/add.py | 2 +- project/branch.py | 3 +-- project/checkout.py | 6 ++---- project/commit.py | 2 +- project/graph.py | 6 +++--- project/merge.py | 2 +- project/status.py | 2 +- project/{global_functions.py => utils.py} | 0 requirements.txt | 6 ++++++ setup.py | 3 +++ 11 files changed, 22 insertions(+), 13 deletions(-) create mode 100644 .isort.cfg rename project/{global_functions.py => utils.py} (100%) create mode 100644 requirements.txt create mode 100644 setup.py diff --git a/.isort.cfg b/.isort.cfg new file mode 100644 index 0000000..3a2ebe1 --- /dev/null +++ b/.isort.cfg @@ -0,0 +1,3 @@ +[settings] +profile=black +known_first_party=add,branch,checkout,commit,errors,graph,init,merge,status,utils,wit diff --git a/project/add.py b/project/add.py index 06eed9a..e750ecf 100644 --- a/project/add.py +++ b/project/add.py @@ -6,7 +6,7 @@ import flask import pytest from errors import WitError -from global_functions import get_repository_path +from utils import get_repository_path def add_function(path_to_add: str) -> None: diff --git a/project/branch.py b/project/branch.py index 0858125..33fe77f 100644 --- a/project/branch.py +++ b/project/branch.py @@ -1,8 +1,7 @@ from pathlib import Path -from commit import get_head_reference from errors import BranchExistsError, WitError -from global_functions import get_branches_commits, get_repository_path +from utils import get_branches_commits, get_repository_path, get_head_reference def branch_function(name: str) -> None: diff --git a/project/checkout.py b/project/checkout.py index 3e6621e..f5409bb 100644 --- a/project/checkout.py +++ b/project/checkout.py @@ -3,7 +3,7 @@ from typing import Union from errors import BranchDoesntExistError, FilesDoesntMatchError, WitError -from global_functions import ( +from utils import ( get_all_files_in_directory_and_subs, get_commit_id_of_branch, get_repository_path, @@ -19,9 +19,7 @@ def checkout_function(commit_id_or_branch: str) -> None: if list(get_changes_to_be_committed(repository, staging_area_path)) or list( get_changes_not_staged_for_commit(repository, staging_area_path) ): - raise FilesDoesntMatchError( - "There are files added or changed after last commit_function" - ) + raise FilesDoesntMatchError("There are files added or changed after last commit_function") references_file = repository / ".wit" / "references.txt" commit_id = get_commit_id_of_branch(commit_id_or_branch, references_file) if not commit_id: diff --git a/project/commit.py b/project/commit.py index f8b51dd..34061b4 100644 --- a/project/commit.py +++ b/project/commit.py @@ -7,7 +7,7 @@ from typing import Optional from errors import WitError -from global_functions import ( +from utils import ( get_activated_branch, get_head_reference, get_repository_path, diff --git a/project/graph.py b/project/graph.py index a4a53b3..241cb46 100644 --- a/project/graph.py +++ b/project/graph.py @@ -2,10 +2,10 @@ from pathlib import Path from errors import WitError -from global_functions import get_head_reference, get_repository_path +from utils import get_head_reference, get_repository_path from graphviz import Digraph -regex = re.compile( +parent_id_regex = re.compile( r"^parent = (?P\w{20})(, (?P\w{20}))?$", flags=re.MULTILINE, ) @@ -29,7 +29,7 @@ def create_nodes(commit_id: str, dot: Digraph, images_path: Path) -> None: commit_file = images_path / (commit_id + ".txt") create_node(commit_id, dot) commit_txt = commit_file.read_text() - parent_id_match = regex.match(commit_txt) + parent_id_match = parent_id_regex.match(commit_txt) if parent_id_match: parent_id_1 = parent_id_match.group("commit_id_1") parent_id_2 = parent_id_match.group("commit_id_2") diff --git a/project/merge.py b/project/merge.py index ea431cd..bf60448 100644 --- a/project/merge.py +++ b/project/merge.py @@ -6,7 +6,7 @@ from commit import commit_function from errors import FilesDoesntMatchError, MergeError, NoCommonCommitError, WitError -from global_functions import ( +from utils import ( get_activated_branch, get_all_files_in_directory_and_subs, get_commit_id_of_branch, diff --git a/project/status.py b/project/status.py index cca1a2f..3ea978b 100644 --- a/project/status.py +++ b/project/status.py @@ -3,7 +3,7 @@ from typing import Iterator from errors import WitError -from global_functions import ( +from utils import ( get_all_files_in_directory_and_subs, get_head_reference, get_repository_path, diff --git a/project/global_functions.py b/project/utils.py similarity index 100% rename from project/global_functions.py rename to project/utils.py diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..547c6db --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +pytest~=7.0.1 +project~=0.0.0 +Flask~=2.0.3 +click~=8.0.4 +graphviz~=0.19.1 +setuptools~=57.4.0 \ No newline at end of file diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..10856f6 --- /dev/null +++ b/setup.py @@ -0,0 +1,3 @@ +from setuptools import find_packages, setup + +setup(name="project", packages=find_packages()) From 5d53930857f1d9bb219cba92a8db65d3a3d085ea Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Mon, 21 Mar 2022 00:00:16 +0200 Subject: [PATCH 41/73] run isort --- project/add.py | 2 -- project/branch.py | 2 +- project/checkout.py | 2 +- project/commit.py | 6 +----- project/graph.py | 3 ++- project/merge.py | 2 +- project/wit.py | 1 + 7 files changed, 7 insertions(+), 11 deletions(-) diff --git a/project/add.py b/project/add.py index e750ecf..2360ce3 100644 --- a/project/add.py +++ b/project/add.py @@ -3,8 +3,6 @@ from pathlib import Path from typing import Iterator -import flask -import pytest from errors import WitError from utils import get_repository_path diff --git a/project/branch.py b/project/branch.py index 33fe77f..d12e217 100644 --- a/project/branch.py +++ b/project/branch.py @@ -1,7 +1,7 @@ from pathlib import Path from errors import BranchExistsError, WitError -from utils import get_branches_commits, get_repository_path, get_head_reference +from utils import get_branches_commits, get_head_reference, get_repository_path def branch_function(name: str) -> None: diff --git a/project/checkout.py b/project/checkout.py index f5409bb..5dd453b 100644 --- a/project/checkout.py +++ b/project/checkout.py @@ -3,12 +3,12 @@ from typing import Union from errors import BranchDoesntExistError, FilesDoesntMatchError, WitError +from status import get_changes_not_staged_for_commit, get_changes_to_be_committed from utils import ( get_all_files_in_directory_and_subs, get_commit_id_of_branch, get_repository_path, ) -from status import get_changes_not_staged_for_commit, get_changes_to_be_committed def checkout_function(commit_id_or_branch: str) -> None: diff --git a/project/commit.py b/project/commit.py index 34061b4..ac5e34b 100644 --- a/project/commit.py +++ b/project/commit.py @@ -7,11 +7,7 @@ from typing import Optional from errors import WitError -from utils import ( - get_activated_branch, - get_head_reference, - get_repository_path, -) +from utils import get_activated_branch, get_head_reference, get_repository_path def commit_function(message: str, second_parent: Optional[str] = None) -> None: diff --git a/project/graph.py b/project/graph.py index 241cb46..7b2e40c 100644 --- a/project/graph.py +++ b/project/graph.py @@ -1,9 +1,10 @@ import re from pathlib import Path +from graphviz import Digraph + from errors import WitError from utils import get_head_reference, get_repository_path -from graphviz import Digraph parent_id_regex = re.compile( r"^parent = (?P\w{20})(, (?P\w{20}))?$", diff --git a/project/merge.py b/project/merge.py index bf60448..a856d41 100644 --- a/project/merge.py +++ b/project/merge.py @@ -6,6 +6,7 @@ from commit import commit_function from errors import FilesDoesntMatchError, MergeError, NoCommonCommitError, WitError +from status import get_changes_not_staged_for_commit, get_changes_to_be_committed from utils import ( get_activated_branch, get_all_files_in_directory_and_subs, @@ -13,7 +14,6 @@ get_head_reference, get_repository_path, ) -from status import get_changes_not_staged_for_commit, get_changes_to_be_committed regex = re.compile( r"^parent = (?P\w{20})(, (?P\w{20}))?$", diff --git a/project/wit.py b/project/wit.py index 255f292..47802b0 100644 --- a/project/wit.py +++ b/project/wit.py @@ -1,4 +1,5 @@ import click + from add import add_function from branch import branch_function from checkout import checkout_function From 0ceab020e8ef3fed24b962780274d7e3688b7d9f Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Mon, 21 Mar 2022 00:02:05 +0200 Subject: [PATCH 42/73] run black --- project/checkout.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/project/checkout.py b/project/checkout.py index 5dd453b..3d4c75c 100644 --- a/project/checkout.py +++ b/project/checkout.py @@ -19,7 +19,9 @@ def checkout_function(commit_id_or_branch: str) -> None: if list(get_changes_to_be_committed(repository, staging_area_path)) or list( get_changes_not_staged_for_commit(repository, staging_area_path) ): - raise FilesDoesntMatchError("There are files added or changed after last commit_function") + raise FilesDoesntMatchError( + "There are files added or changed after last commit_function" + ) references_file = repository / ".wit" / "references.txt" commit_id = get_commit_id_of_branch(commit_id_or_branch, references_file) if not commit_id: From 5f1bd1e7ae2f0603c761974143f78ad7fc4583ab Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Mon, 21 Mar 2022 15:55:11 +0200 Subject: [PATCH 43/73] fixed files --- project/add.py | 57 +++++++++++++------------- project/branch.py | 11 +++-- project/checkout.py | 38 +++++++++++------- project/commit.py | 97 +++++++++++++++++++++++++++------------------ project/graph.py | 6 +-- project/merge.py | 44 ++++++++++---------- project/status.py | 29 +++++++------- project/utils.py | 89 ++++++++++++++++++++++++++--------------- 8 files changed, 213 insertions(+), 158 deletions(-) diff --git a/project/add.py b/project/add.py index 2360ce3..04f4e81 100644 --- a/project/add.py +++ b/project/add.py @@ -1,10 +1,8 @@ import shutil -from glob import glob from pathlib import Path -from typing import Iterator from errors import WitError -from utils import get_repository_path +from utils import get_repository_path, get_staging_area def add_function(path_to_add: str) -> None: @@ -12,32 +10,33 @@ def add_function(path_to_add: str) -> None: repository = get_repository_path(path) if not repository: raise WitError("<.wit> file not found") - destination = get_destination(path, repository) - save_the_copy(destination, path) + copy_to_staging_area(path, repository) -def update_destination(destination: Path, directories_to_copy: Iterator[str]) -> Path: - for dir_name in directories_to_copy: - destination = destination / dir_name - if not glob(str(destination)): - destination.mkdir() - return destination - - -def get_destination(path: Path, repository: Path) -> Path: - destination = repository / ".wit" / "staging_area" - file_path = path.relative_to(repository) - file_parts = file_path.parts - parents_dirs = (part for part in file_parts if part != file_path.name) - destination = update_destination(destination, parents_dirs) - return destination - - -def save_the_copy(destination: Path, path: Path) -> None: - if path.is_file(): - shutil.copy2(path, destination) +def copy_to_staging_area(path: Path, repository: Path) -> None: + staging_area_path = get_staging_area(repository) + relative_path = path.relative_to(repository) + if path.is_dir(): + copy_dir_to_staging_area(staging_area_path, path, relative_path) else: - destination_of_folder = destination / path.name - if destination_of_folder.exists(): - shutil.rmtree(destination_of_folder) - shutil.copytree(path, destination_of_folder) + copy_file_to_staging_area(staging_area_path, path, relative_path) + + +def copy_file_to_staging_area( + staging_area_path: Path, path: Path, relative_path: Path +) -> None: + parents_path = relative_path.parents[0] + destination = staging_area_path + if parents_path.name: + destination = staging_area_path / parents_path + destination.mkdir(parents=True, exist_ok=True) + shutil.copy2(path, destination) + + +def copy_dir_to_staging_area( + staging_area_path: Path, path: Path, relative_path: Path +) -> None: + destination = staging_area_path / relative_path + if destination.exists(): + shutil.rmtree(destination) + shutil.copytree(path, destination) diff --git a/project/branch.py b/project/branch.py index d12e217..947fd39 100644 --- a/project/branch.py +++ b/project/branch.py @@ -1,15 +1,20 @@ from pathlib import Path from errors import BranchExistsError, WitError -from utils import get_branches_commits, get_head_reference, get_repository_path +from utils import ( + get_existing_branches, + get_head_reference, + get_references_path, + get_repository_path, +) def branch_function(name: str) -> None: repository = get_repository_path(Path.cwd()) if not repository: raise WitError("<.wit> file not found") - references_file = repository / ".wit" / "references.txt" - existing_branches = get_branches_commits(references_file) + references_file = get_references_path(repository) + existing_branches = get_existing_branches(references_file) if name in existing_branches: raise BranchExistsError(f"Branch {name} already exists.") commit_id = get_head_reference(repository) diff --git a/project/checkout.py b/project/checkout.py index 3d4c75c..a8184a7 100644 --- a/project/checkout.py +++ b/project/checkout.py @@ -5,24 +5,23 @@ from errors import BranchDoesntExistError, FilesDoesntMatchError, WitError from status import get_changes_not_staged_for_commit, get_changes_to_be_committed from utils import ( + get_activated_path, get_all_files_in_directory_and_subs, get_commit_id_of_branch, + get_commit_path, + get_references_path, get_repository_path, + get_staging_area, ) def checkout_function(commit_id_or_branch: str) -> None: repository = get_repository_path(Path.cwd()) - staging_area_path = repository / ".wit" / "staging_area" + staging_area_path = get_staging_area(repository) if not repository: raise WitError("<.wit> file not found") - if list(get_changes_to_be_committed(repository, staging_area_path)) or list( - get_changes_not_staged_for_commit(repository, staging_area_path) - ): - raise FilesDoesntMatchError( - "There are files added or changed after last commit_function" - ) - references_file = repository / ".wit" / "references.txt" + raise_for_unsaved_work(repository) + references_file = get_references_path(repository) commit_id = get_commit_id_of_branch(commit_id_or_branch, references_file) if not commit_id: raise BranchDoesntExistError("Branch doesn't exist.") @@ -30,14 +29,25 @@ def checkout_function(commit_id_or_branch: str) -> None: write_activated(commit_id_or_branch, repository) else: write_activated("", repository) - commit_path = repository / ".wit" / "images" / commit_id + commit_path = get_commit_path(repository, commit_id) update_files_in_main_folder(commit_path, repository) update_head_in_references_file(commit_id, references_file) update_staging_area_folder(staging_area_path, commit_path) +def raise_for_unsaved_work(repository: Path) -> None: + files_added_since_last_commit = list(get_changes_to_be_committed(repository)) + changed_files_since_last_commit = list( + get_changes_not_staged_for_commit(repository) + ) + if files_added_since_last_commit or changed_files_since_last_commit: + raise FilesDoesntMatchError( + "There are files added or changed since last commit_function" + ) + + def write_activated(commit_id_or_branch: str, repository: Path) -> None: - activated_path = repository / ".wit" / "activated.txt" + activated_path = get_activated_path(repository) activated_path.write_text(commit_id_or_branch) @@ -62,9 +72,7 @@ def update_files_in_main_folder( original_file.write(content) -def update_staging_area_folder( - staging_area_path: Union[str, Path], commit_path: Union[str, Path] -): +def update_staging_area_folder(staging_area_path: Path, commit_path: Path) -> None: for file_or_dir in Path(staging_area_path).iterdir(): if file_or_dir.is_file(): file_or_dir.unlink() @@ -73,6 +81,6 @@ def update_staging_area_folder( for file in Path(commit_path).iterdir(): rel_path = Path(file).relative_to(commit_path) if file.is_file(): - shutil.copy2(file, Path(staging_area_path).joinpath(rel_path)) + shutil.copy2(file, staging_area_path / rel_path) else: - shutil.copytree(file, Path(staging_area_path).joinpath(rel_path)) + shutil.copytree(file, staging_area_path / rel_path) diff --git a/project/commit.py b/project/commit.py index ac5e34b..87fafb7 100644 --- a/project/commit.py +++ b/project/commit.py @@ -7,48 +7,51 @@ from typing import Optional from errors import WitError -from utils import get_activated_branch, get_head_reference, get_repository_path +from utils import ( + get_activated_branch, + get_commit_path, + get_head_reference, + get_references_path, + get_repository_path, + get_staging_area, +) + +LENGTH = 20 +CHARS = "1234567890abcdef" def commit_function(message: str, second_parent: Optional[str] = None) -> None: repository = get_repository_path(Path.cwd()) if not repository: raise WitError("<.wit> file not found") - images_path = repository / ".wit" / "images" - path_of_new_folder = create_commit_folder(images_path) - create_commit_txt_file( - repository, images_path, path_of_new_folder, message, second_parent - ) - save_files(repository, path_of_new_folder) - commit_id = os.path.basename(path_of_new_folder) - write_references(commit_id, repository) + new_commit_id = create_commit_id() + create_commit_folder(new_commit_id, repository) + create_commit_txt_file(repository, new_commit_id, message, second_parent) + save_files_in_new_commit(repository, new_commit_id) + write_references(new_commit_id, repository) -def create_commit_folder(images_path: Path) -> Path: - folder_name = create_folder_name() - path_of_new_folder = images_path / folder_name +def create_commit_folder(new_commit_id: str, repository: Path) -> None: + path_of_new_folder = get_commit_path(repository, new_commit_id) os.mkdir(path_of_new_folder) - return path_of_new_folder -def create_folder_name() -> str: - length = 20 - chars = "1234567890abcdef" - folder_name = "".join(random.choices(chars, k=length)) - return folder_name +def create_commit_id() -> str: + commit_id = "".join(random.choices(CHARS, k=LENGTH)) + return commit_id def create_commit_txt_file( repository: Path, - images_path: Path, - path_of_new_folder: Path, + new_commit_id: str, message: str, second_parent: Optional[str] = None, ) -> None: parent_head = get_head_reference(repository) if second_parent: parent_head += ", " + second_parent - txt_file = images_path / (path_of_new_folder.name + ".txt") + new_commit_path = get_commit_path(repository, new_commit_id) + txt_file = new_commit_path.with_suffix(".txt") txt_file.write_text( f"parent = {parent_head if parent_head else None}\n" f'date = {datetime.datetime.now().strftime("%c")}\n' @@ -56,11 +59,12 @@ def create_commit_txt_file( ) -def save_files(repository: Path, path_of_new_folder: Path) -> None: - staging_area_path = repository / ".wit" / "staging_area" - for item in os.listdir(staging_area_path): - src = staging_area_path / item - dst = path_of_new_folder / item +def save_files_in_new_commit(repository: Path, new_commit_id: str) -> None: + staging_area_path = get_staging_area(repository) + commit_path = get_commit_path(repository, new_commit_id) + for item in staging_area_path.iterdir(): + src = staging_area_path / item.name + dst = commit_path / item.name if src.is_file(): shutil.copy2(src, dst) else: @@ -68,27 +72,42 @@ def save_files(repository: Path, path_of_new_folder: Path) -> None: def write_references(commit_id: str, repository: Path) -> None: - wit_folder = repository / ".wit" - references_file = wit_folder / "references.txt" + references_file = get_references_path(repository) parent_head = get_head_reference(repository) - activated_branch = get_activated_branch(wit_folder) + activated_branch = get_activated_branch(repository) if references_file.exists(): change_head_and_branch_id( activated_branch, commit_id, parent_head, references_file ) else: - references_file.write_text( - f'HEAD={commit_id}\n{"=".join((activated_branch, commit_id))}' - ) + change_only_head(activated_branch, commit_id, references_file) + + +def change_only_head( + activated_branch: str, commit_id: str, references_file: Path +) -> None: + new_line = "=".join((activated_branch, commit_id)) + references_file.write_text(f"HEAD={commit_id}\n{new_line}") def change_head_and_branch_id( activated_branch: str, commit_id: str, parent_head: str, references_file: Path ) -> None: - regex = re.compile(rf"^{activated_branch}={parent_head}$", flags=re.MULTILINE) - head_regex = re.compile(rf"^HEAD={parent_head}$", flags=re.MULTILINE) - data = references_file.read_text() - match = regex.findall(data) - new = regex.sub(f"{activated_branch}={commit_id}", data) if match else data - new = head_regex.sub(f"HEAD={commit_id}", new) - references_file.write_text(new) + activated_regex = rf"^{activated_branch}={parent_head}$" + head_regex = rf"^HEAD={parent_head}$" + references_data = references_file.read_text() + activated_match = re.findall(activated_regex, references_data, flags=re.MULTILINE) + new_references_content = ( + re.sub( + activated_regex, + f"{activated_branch}={commit_id}", + references_data, + flags=re.MULTILINE, + ) + if activated_match + else references_data + ) + new_references_content = re.sub( + head_regex, f"HEAD={commit_id}", new_references_content, flags=re.MULTILINE + ) + references_file.write_text(new_references_content) diff --git a/project/graph.py b/project/graph.py index 7b2e40c..4168cab 100644 --- a/project/graph.py +++ b/project/graph.py @@ -4,7 +4,7 @@ from graphviz import Digraph from errors import WitError -from utils import get_head_reference, get_repository_path +from utils import get_head_reference, get_images_path, get_repository_path, get_wit_dir parent_id_regex = re.compile( r"^parent = (?P\w{20})(, (?P\w{20}))?$", @@ -19,8 +19,8 @@ def graph_function() -> None: current_commit_id = get_head_reference(repository) commit_id = current_commit_id dot = init_graph() - wit_dir = repository / ".wit" - images_path = wit_dir / "images" + wit_dir = get_wit_dir(repository) + images_path = get_images_path(repository) create_nodes(commit_id, dot, images_path) dot.render(f"Graph {current_commit_id}", wit_dir, view=True, cleanup=True) diff --git a/project/merge.py b/project/merge.py index a856d41..bce3a82 100644 --- a/project/merge.py +++ b/project/merge.py @@ -4,15 +4,19 @@ from pathlib import Path from typing import Iterator +from checkout import raise_for_unsaved_work from commit import commit_function -from errors import FilesDoesntMatchError, MergeError, NoCommonCommitError, WitError -from status import get_changes_not_staged_for_commit, get_changes_to_be_committed +from errors import MergeError, NoCommonCommitError, WitError from utils import ( get_activated_branch, get_all_files_in_directory_and_subs, get_commit_id_of_branch, + get_commit_path, get_head_reference, + get_images_path, + get_references_path, get_repository_path, + get_staging_area, ) regex = re.compile( @@ -25,24 +29,18 @@ def merge_function(branch_name: str) -> None: repository = get_repository_path(Path.cwd()) if not repository: raise WitError("<.wit> file not found") - wit_dir = repository / ".wit" - staging_area_path = wit_dir / "staging_area" - references_file = wit_dir / "references.txt" + staging_area_path = get_staging_area(repository) + references_file = get_references_path(repository) head_reference = get_head_reference(repository) branch_commit_id = get_commit_id_of_branch(branch_name, references_file) - if list(get_changes_to_be_committed(repository, staging_area_path)) or list( - get_changes_not_staged_for_commit(repository, staging_area_path) - ): - raise FilesDoesntMatchError( - "There are files added or changed after last commit_function" - ) + raise_for_unsaved_work(repository) if branch_commit_id == head_reference: raise MergeError("Head is already at the branch you are trying to merge.") - common_commit = get_common_commit(wit_dir, branch_commit_id, head_reference) + common_commit = get_common_commit(repository, branch_commit_id, head_reference) if not common_commit: raise NoCommonCommitError(f"There is no common commit with {branch_name}.") - common_dir = wit_dir / "images" / common_commit - branch_dir = wit_dir / "images" / branch_commit_id + common_dir = get_commit_path(repository, common_commit) + branch_dir = get_commit_path(repository, branch_commit_id) branch_files, common_files = get_common_and_branch_files(branch_dir, common_dir) check_common_commit_and_update_staging_area_and_repository( branch_dir, common_dir, common_files, staging_area_path, repository @@ -50,7 +48,7 @@ def merge_function(branch_name: str) -> None: check_branch_and_update_staging_area_and_repository( branch_dir, branch_files, common_dir, staging_area_path, repository ) - commit_merge(branch_commit_id, branch_name, head_reference, wit_dir) + commit_merge(branch_commit_id, branch_name, head_reference, repository) def check_branch_and_update_staging_area_and_repository( @@ -147,9 +145,9 @@ def get_file_path_in_all_dirs( def commit_merge( - branch_commit_id: str, branch_name: str, head_reference: str, wit_dir: Path + branch_commit_id: str, branch_name: str, head_reference: str, repository: Path ) -> None: - activated = get_activated_branch(wit_dir) + activated = get_activated_branch(repository) message = f"Commit after merge of {activated if activated else head_reference} and {branch_name}." commit_function(message, branch_commit_id) @@ -169,9 +167,11 @@ def create_new_file_in_staging_area_and_repository( os.mkdir(path_in_repository) -def get_common_commit(wit_dir: Path, branch_commit_id: str, head_reference: str) -> str: - branch_parents = set(get_parents_commits(wit_dir, branch_commit_id)) - head_parents = set(get_parents_commits(wit_dir, head_reference)) +def get_common_commit( + repository: Path, branch_commit_id: str, head_reference: str +) -> str: + branch_parents = set(get_parents_commits(repository, branch_commit_id)) + head_parents = set(get_parents_commits(repository, head_reference)) if branch_commit_id in head_parents: return branch_commit_id if head_reference in branch_parents: @@ -182,8 +182,8 @@ def get_common_commit(wit_dir: Path, branch_commit_id: str, head_reference: str) return "" -def get_parents_commits(wit_dir: Path, commit_id: str) -> Iterator[str]: - images_path = wit_dir / "images" +def get_parents_commits(repository: Path, commit_id: str) -> Iterator[str]: + images_path = get_images_path(repository) yield from get_parents_of_commit_id(commit_id, images_path) diff --git a/project/status.py b/project/status.py index 3ea978b..ab9522f 100644 --- a/project/status.py +++ b/project/status.py @@ -5,8 +5,11 @@ from errors import WitError from utils import ( get_all_files_in_directory_and_subs, + get_all_files_in_repository_and_subs, + get_commit_path, get_head_reference, get_repository_path, + get_staging_area, ) @@ -14,16 +17,13 @@ def status_function() -> None: repository = get_repository_path(Path.cwd()) if not repository: raise WitError("<.wit> file not found") - staging_area_path = repository / ".wit" / "staging_area" last_commit_id = get_head_reference(repository) message_if_no_commit = "No commit was done yet." - changes_to_be_committed = show_files( - get_changes_to_be_committed(repository, staging_area_path) - ) + changes_to_be_committed = show_files(get_changes_to_be_committed(repository)) changes_not_staged_for_commit = show_files( - get_changes_not_staged_for_commit(repository, staging_area_path) + get_changes_not_staged_for_commit(repository) ) - untracked_files = show_files(get_untracked_files(repository, staging_area_path)) + untracked_files = show_files(get_untracked_files(repository)) print( f"###Commit id:###\n{last_commit_id if last_commit_id else message_if_no_commit}\n\n" f"###Changes to be committed:###\n{changes_to_be_committed}\n\n" @@ -39,16 +39,15 @@ def show_files(files: Iterator[Path]) -> str: return txt -def get_changes_to_be_committed( - repository: Path, staging_area_path: Path -) -> Iterator[Path]: +def get_changes_to_be_committed(repository: Path) -> Iterator[Path]: + staging_area_path = get_staging_area(repository) last_commit_id = get_head_reference(repository) files_in_staging_area = get_all_files_in_directory_and_subs(staging_area_path) if not last_commit_id: for file_path in files_in_staging_area: yield file_path else: - commit_path = repository / ".wit" / "images" / last_commit_id + commit_path = get_commit_path(repository, last_commit_id) for file_path in files_in_staging_area: path_in_last_commit = commit_path / file_path if not glob(str(path_in_last_commit)): @@ -64,9 +63,8 @@ def check_if_file_changed(file_path: Path, dir_1: Path, dir_2: Path) -> bool: return content_in_dir_1 != content_in_dir_2 -def get_changes_not_staged_for_commit( - repository: Path, staging_area_path: Path -) -> Iterator[Path]: +def get_changes_not_staged_for_commit(repository: Path) -> Iterator[Path]: + staging_area_path = get_staging_area(repository) files_in_staging_area = get_all_files_in_directory_and_subs(staging_area_path) for file_path in files_in_staging_area: path_in_repository = repository / file_path @@ -79,8 +77,9 @@ def get_changes_not_staged_for_commit( yield file_path -def get_untracked_files(repository: Path, staging_area_path: Path) -> Iterator[Path]: - files_in_repository = get_all_files_in_directory_and_subs(repository, repo=True) +def get_untracked_files(repository: Path) -> Iterator[Path]: + staging_area_path = get_staging_area(repository) + files_in_repository = get_all_files_in_repository_and_subs(repository) for file_path in files_in_repository: path_in_staging_area = staging_area_path / file_path if not glob(str(path_in_staging_area)): diff --git a/project/utils.py b/project/utils.py index ce92a50..54786fe 100644 --- a/project/utils.py +++ b/project/utils.py @@ -4,7 +4,9 @@ from pathlib import Path from typing import Iterator, Optional -branch_regex = re.compile(r"^(?P\w+)=(?P\w{20})$") +branch_regex = re.compile( + r"^(?P\w+)=(?P\w{20})$", flags=re.MULTILINE +) def get_repository_path(path: Path) -> Optional[Path]: @@ -18,7 +20,7 @@ def get_repository_path(path: Path) -> Optional[Path]: def get_commit_id_of_branch(branch: str, references_file: Path) -> str: - branches_commits_dict = get_branches_commits(references_file) + branches_commits_dict = get_existing_branches(references_file) if branch in branches_commits_dict: return branches_commits_dict[branch] if branch in branches_commits_dict.values(): @@ -26,45 +28,68 @@ def get_commit_id_of_branch(branch: str, references_file: Path) -> str: return "" -def get_branches_commits(references_file: Path) -> dict[str, str]: +def get_existing_branches(references_file: Path) -> set: with references_file.open() as file: - branches_commits_dict = {} - for line in file: - match = branch_regex.match(line) - branches_commits_dict[match.group("branch_name")] = match.group("branch_id") - return branches_commits_dict + branches_data = file.read() + branches = set() + branch_matches = branch_regex.findall(branches_data) + for branch_name, _ in branch_matches: + branches.add(branch_name) + return branches def get_head_reference(repository: Path) -> str: - wit_folder = repository.joinpath(".wit") - references_file = wit_folder.joinpath("references.txt") + references_file = get_references_path(repository) if references_file.exists(): return get_commit_id_of_branch("HEAD", references_file) return "" -def get_activated_branch(wit_folder: Path) -> str: - activated_path = wit_folder / "activated.txt" +def get_activated_branch(repository: Path) -> str: + activated_path = get_activated_path(repository) return activated_path.read_text() -def get_all_files_in_directory_and_subs( - directory: Path, repo: bool = False -) -> Iterator[Path]: - if repo: - for root, dirs, files in os.walk(directory, topdown=True): - if files: - for file in files: - if ".wit" not in root: - yield (Path(root) / file).relative_to(directory) - else: - if ".wit" not in root and not dirs: - yield Path(root).relative_to(directory) - else: - for root, dirs, files in os.walk(directory, topdown=True): - if files: - for file in files: - yield (Path(root) / file).relative_to(directory) - else: - if not dirs: - yield Path(root).relative_to(directory) +def get_all_files_in_directory_and_subs(directory: Path) -> Iterator[Path]: + for root, dirs, files in os.walk(directory, topdown=True): + if files: + for file in files: + yield (Path(root) / file).relative_to(directory) + else: + if not dirs: + yield Path(root).relative_to(directory) + + +def get_all_files_in_repository_and_subs(repository: Path) -> Iterator[Path]: + for root, dirs, files in os.walk(repository, topdown=True): + if files: + for file in files: + if ".wit" not in root: + yield (Path(root) / file).relative_to(repository) + else: + if ".wit" not in root and not dirs: + yield Path(root).relative_to(repository) + + +def get_wit_dir(repository: Path) -> Path: + return repository / ".wit" + + +def get_staging_area(repository: Path) -> Path: + return get_wit_dir(repository) / "staging_area" + + +def get_references_path(repository: Path) -> Path: + return get_wit_dir(repository) / "references.txt" + + +def get_images_path(repository: Path) -> Path: + return get_wit_dir(repository) / "images" + + +def get_commit_path(repository: Path, commit_id: str): + return get_images_path(repository) / commit_id + + +def get_activated_path(repository: Path) -> Path: + return get_wit_dir(repository) / "activated.txt" From 9461e0b977b0bdf82752c9702ad495d9f419a21c Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Mon, 21 Mar 2022 16:01:49 +0200 Subject: [PATCH 44/73] fix get_branches_commits --- project/branch.py | 4 ++-- project/utils.py | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/project/branch.py b/project/branch.py index 947fd39..d06e9cc 100644 --- a/project/branch.py +++ b/project/branch.py @@ -2,7 +2,7 @@ from errors import BranchExistsError, WitError from utils import ( - get_existing_branches, + get_branches_commits, get_head_reference, get_references_path, get_repository_path, @@ -14,7 +14,7 @@ def branch_function(name: str) -> None: if not repository: raise WitError("<.wit> file not found") references_file = get_references_path(repository) - existing_branches = get_existing_branches(references_file) + existing_branches = get_branches_commits(references_file) if name in existing_branches: raise BranchExistsError(f"Branch {name} already exists.") commit_id = get_head_reference(repository) diff --git a/project/utils.py b/project/utils.py index 54786fe..d623600 100644 --- a/project/utils.py +++ b/project/utils.py @@ -20,7 +20,7 @@ def get_repository_path(path: Path) -> Optional[Path]: def get_commit_id_of_branch(branch: str, references_file: Path) -> str: - branches_commits_dict = get_existing_branches(references_file) + branches_commits_dict = get_branches_commits(references_file) if branch in branches_commits_dict: return branches_commits_dict[branch] if branch in branches_commits_dict.values(): @@ -28,14 +28,14 @@ def get_commit_id_of_branch(branch: str, references_file: Path) -> str: return "" -def get_existing_branches(references_file: Path) -> set: +def get_branches_commits(references_file: Path) -> dict[str, str]: with references_file.open() as file: branches_data = file.read() - branches = set() + branches_commits = {} branch_matches = branch_regex.findall(branches_data) - for branch_name, _ in branch_matches: - branches.add(branch_name) - return branches + for branch_name, commit_id in branch_matches: + branches_commits[branch_name] = commit_id + return branches_commits def get_head_reference(repository: Path) -> str: From bca39e63000eeb7c216f1c57c6083f79dfd27b1d Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Mon, 21 Mar 2022 16:09:17 +0200 Subject: [PATCH 45/73] remove idea\.name, add .idea to gitignore --- .idea/.name | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .idea/.name diff --git a/.idea/.name b/.idea/.name deleted file mode 100644 index d454935..0000000 --- a/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -checkout.py \ No newline at end of file From ea1eee454d7f3a39a0a87f9367b91c2e6418d534 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Mon, 21 Mar 2022 21:33:52 +0200 Subject: [PATCH 46/73] change init.py- uses utils functions --- .gitignore | 1 + project/init.py | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 5e69497..cd9419d 100644 --- a/.gitignore +++ b/.gitignore @@ -131,3 +131,4 @@ dmypy.json /.idea/ __pycache__ wit_exercises +.idea diff --git a/project/init.py b/project/init.py index 126aac0..1cc9652 100644 --- a/project/init.py +++ b/project/init.py @@ -1,16 +1,18 @@ -import os from pathlib import Path from errors import WitExistsError +from utils import get_activated_path, get_images_path, get_staging_area, get_wit_dir def init_function() -> None: - cwd = os.getcwd() - wit_path = os.path.join(cwd, ".wit") - if os.path.exists(wit_path): + cwd = Path.cwd() + wit_path = get_wit_dir(cwd) + if wit_path.exists(): raise WitExistsError("The folder already has .wit directory") - os.mkdir(wit_path) - os.mkdir(os.path.join(wit_path, "images")) - os.mkdir(os.path.join(wit_path, "staging_area")) - activated_path = os.path.join(wit_path, "activated.txt") - Path(activated_path).write_text("master") + wit_path.mkdir() + images_path = get_images_path(cwd) + images_path.mkdir() + staging_area_path = get_staging_area(cwd) + staging_area_path.mkdir() + activated_path = get_activated_path(cwd) + activated_path.write_text("master") From b6da7f14343bcc1d65b6a36fb0cfae48308569f1 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Tue, 22 Mar 2022 09:14:57 +0200 Subject: [PATCH 47/73] fix imports. done: conftest, test_init, test_add --- project/add.py | 4 ++-- project/branch.py | 4 ++-- project/checkout.py | 6 +++--- project/commit.py | 4 ++-- project/graph.py | 4 ++-- project/init.py | 4 ++-- project/merge.py | 8 ++++---- project/status.py | 4 ++-- project/wit.py | 16 ++++++++-------- setup.py | 10 ++++++++-- 10 files changed, 35 insertions(+), 29 deletions(-) diff --git a/project/add.py b/project/add.py index 04f4e81..f78f803 100644 --- a/project/add.py +++ b/project/add.py @@ -1,8 +1,8 @@ import shutil from pathlib import Path -from errors import WitError -from utils import get_repository_path, get_staging_area +from project.errors import WitError +from project.utils import get_repository_path, get_staging_area def add_function(path_to_add: str) -> None: diff --git a/project/branch.py b/project/branch.py index d06e9cc..ca75532 100644 --- a/project/branch.py +++ b/project/branch.py @@ -1,7 +1,7 @@ from pathlib import Path -from errors import BranchExistsError, WitError -from utils import ( +from project.errors import BranchExistsError, WitError +from project.utils import ( get_branches_commits, get_head_reference, get_references_path, diff --git a/project/checkout.py b/project/checkout.py index a8184a7..265d2d5 100644 --- a/project/checkout.py +++ b/project/checkout.py @@ -2,9 +2,9 @@ from pathlib import Path from typing import Union -from errors import BranchDoesntExistError, FilesDoesntMatchError, WitError -from status import get_changes_not_staged_for_commit, get_changes_to_be_committed -from utils import ( +from project.errors import BranchDoesntExistError, FilesDoesntMatchError, WitError +from project.status import get_changes_not_staged_for_commit, get_changes_to_be_committed +from project.utils import ( get_activated_path, get_all_files_in_directory_and_subs, get_commit_id_of_branch, diff --git a/project/commit.py b/project/commit.py index 87fafb7..a7dcf94 100644 --- a/project/commit.py +++ b/project/commit.py @@ -6,8 +6,8 @@ from pathlib import Path from typing import Optional -from errors import WitError -from utils import ( +from project.errors import WitError +from project.utils import ( get_activated_branch, get_commit_path, get_head_reference, diff --git a/project/graph.py b/project/graph.py index 4168cab..7042d0d 100644 --- a/project/graph.py +++ b/project/graph.py @@ -3,8 +3,8 @@ from graphviz import Digraph -from errors import WitError -from utils import get_head_reference, get_images_path, get_repository_path, get_wit_dir +from project.errors import WitError +from project.utils import get_head_reference, get_images_path, get_repository_path, get_wit_dir parent_id_regex = re.compile( r"^parent = (?P\w{20})(, (?P\w{20}))?$", diff --git a/project/init.py b/project/init.py index 1cc9652..d8b2ee1 100644 --- a/project/init.py +++ b/project/init.py @@ -1,7 +1,7 @@ from pathlib import Path -from errors import WitExistsError -from utils import get_activated_path, get_images_path, get_staging_area, get_wit_dir +from project.errors import WitExistsError +from project.utils import get_activated_path, get_images_path, get_staging_area, get_wit_dir def init_function() -> None: diff --git a/project/merge.py b/project/merge.py index bce3a82..00c6f9b 100644 --- a/project/merge.py +++ b/project/merge.py @@ -4,10 +4,10 @@ from pathlib import Path from typing import Iterator -from checkout import raise_for_unsaved_work -from commit import commit_function -from errors import MergeError, NoCommonCommitError, WitError -from utils import ( +from project.checkout import raise_for_unsaved_work +from project.commit import commit_function +from project.errors import MergeError, NoCommonCommitError, WitError +from project.utils import ( get_activated_branch, get_all_files_in_directory_and_subs, get_commit_id_of_branch, diff --git a/project/status.py b/project/status.py index ab9522f..3bbe88f 100644 --- a/project/status.py +++ b/project/status.py @@ -2,8 +2,8 @@ from pathlib import Path from typing import Iterator -from errors import WitError -from utils import ( +from project.errors import WitError +from project.utils import ( get_all_files_in_directory_and_subs, get_all_files_in_repository_and_subs, get_commit_path, diff --git a/project/wit.py b/project/wit.py index 47802b0..91bd2f6 100644 --- a/project/wit.py +++ b/project/wit.py @@ -1,13 +1,13 @@ import click -from add import add_function -from branch import branch_function -from checkout import checkout_function -from commit import commit_function -from graph import graph_function -from init import init_function -from merge import merge_function -from status import status_function +from project.add import add_function +from project.branch import branch_function +from project.checkout import checkout_function +from project.commit import commit_function +from project.graph import graph_function +from project.init import init_function +from project.merge import merge_function +from project.status import status_function @click.group() diff --git a/setup.py b/setup.py index 10856f6..b74b84b 100644 --- a/setup.py +++ b/setup.py @@ -1,3 +1,9 @@ -from setuptools import find_packages, setup +from setuptools import setup, find_packages -setup(name="project", packages=find_packages()) + +setup( + name='project', + package_dir={'project': 'project'}, + include_package_data=True, + packages=["project"], +) From 900039e627eff431ea3564dcbaa85c2dacf096bb Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Tue, 22 Mar 2022 09:52:44 +0200 Subject: [PATCH 48/73] done: test_commit --- .coverage | Bin 0 -> 53248 bytes .gitignore | 24 ++++++++++++------------ 2 files changed, 12 insertions(+), 12 deletions(-) create mode 100644 .coverage diff --git a/.coverage b/.coverage new file mode 100644 index 0000000000000000000000000000000000000000..6aa12dfd65578d1a94c4a6a893e5e63c7bf545c8 GIT binary patch literal 53248 zcmeI4(Tf|$9mjXIE3H;KX_DH9>K?B5p+&yr?(DlOp*~+@UmZV$goea!2}JFBC5`UZ zmUiXc)!9dIuCi17(muJAQrgGT{sVa{4YUs>siDMArO@WB34stw`Vtc2{$_Sp(%F`g z2>59DE|O+;c7F5w&1ZfyquE*M+>6h<5w}`?&~YMbRe4NNRpqp0DT-2{cZuHVVNgU* zPbgGJ;^U$PW$E0768nKNllz6jepGsyEzbP5bgcM~nQik{@pr~WvrQLpfB*=900@A9 zB+!3x#;6=Rq+Y)kIrTP=0;j=)__K88rL!C7&sygvigc z{9>=u6^%m@vEs-dCpk_w@{`I=+%^wr%VB-@G-rxjv}i2V^W4ilK4|;}Ybd!OtKsArfK zFqUkv>TSQi*Vm-Sgq%7EjRk48R?lmQt`dqmH2iHIIGcPaxf%}(`|U{NI?HCRa`wnL z*BQ8gy*!8(`iF8xWo}NrZb~;wS}O^RJuZ~C;m^p1e2TJb)qfne%nPd z8D7oiDko>h87@q)m&Ir9#!DG#@=Zh1@6ezx-r63MMat0R=lIUzw$rB3r0ci=by*sN z;~Bsb8JiAecItjFlKv}BrF)9GXJ~I+!08%ioqwWT6N!V zbH|IP1j_hqNUGe>lB(~Yj7|;92zNvoo7+`sN;;>A(fvI2wX|DNq|GwPHJ{?n%UzU_goyh$qO{j(wCf3_YmwxaEQ}bgBa7|7Ock<(p5~=5zou!ktK!LmmE$Wbi^o?NS5~a!C)U2Ty0-jn zmeJ-a$-ewkORGyOmsI_5|GD&uidU*<)@rryhx9B&t>%V-!)vu};9um8h!U>2k)52$ zlUi+?d)u{I+pX7X^b8^hB0^h6Wo?e0W8jA}L8?l`Vz+w`Ng42!H?xfB*=900@8p2!H?xfB*=52?=Og z$&|nUXV(<=3Hyk>$NowG1NbI;gZ-ZUhTWuO93TJ!AOHd&00JNY0w4eaAOHd&00Li> zK)$G}=2wdU`ef%|fnrY-KF|H~?yo=o=r3=6_SSoM|C%vPN^BA@=NyGBlZV!F$lw37Hx%|M{r~@m?BDEN_ILIUdz=0P;186H0|Y<-1V8`;KmY_l z00ck)1V8`;Kw!TJh(*6zEXtrzkb!B+AfK0kVaOntlR-8s16`MarpX|a(dh<&-2Yb| z+pmg1F9?7D2!H?xfB*=900@8p2!H?xfWV_5Aol;U{(lstp#ua!00ck)1V8`;KmY_l s00ck)1on@B`29cD|NF-unn3^rKmY_l00ck)1V8`;KmY_l;876xA0ykPXaE2J literal 0 HcmV?d00001 diff --git a/.gitignore b/.gitignore index cd9419d..7fdad2a 100644 --- a/.gitignore +++ b/.gitignore @@ -38,18 +38,18 @@ pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.py,cover -.hypothesis/ -.pytest_cache/ +#htmlcov/ +#.tox/ +#.nox/ +#.coverage +#.coverage.* +#.cache +#nosetests.xml +#coverage.xml +#*.cover +#*.py,cover +#.hypothesis/ +#.pytest_cache/ # Translations *.mo From 46fece9245b59b9f11781328371c074457d34cc9 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Tue, 22 Mar 2022 11:01:40 +0200 Subject: [PATCH 49/73] gitignore --- .coverage | Bin 53248 -> 53248 bytes .gitignore | 48 ++++++++++++------------------------------------ 2 files changed, 12 insertions(+), 36 deletions(-) diff --git a/.coverage b/.coverage index 6aa12dfd65578d1a94c4a6a893e5e63c7bf545c8..94f4070f6f2cf27790a63b51752134dbd58d8b1d 100644 GIT binary patch delta 20 bcmZozz}&Eac|)x}tEr`xf!XFJ{kjDJOJWB& delta 20 bcmZozz}&Eac|)x}tBJ9dp~dDV{kjDJOEm{H diff --git a/.gitignore b/.gitignore index 7fdad2a..4334b17 100644 --- a/.gitignore +++ b/.gitignore @@ -2,10 +2,8 @@ __pycache__/ *.py[cod] *$py.class - # C extensions *.so - # Distribution / packaging .Python build/ @@ -26,81 +24,64 @@ share/python-wheels/ .installed.cfg *.egg MANIFEST - # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec - # Installer logs pip-log.txt pip-delete-this-directory.txt - # Unit test / coverage reports -#htmlcov/ -#.tox/ -#.nox/ -#.coverage -#.coverage.* -#.cache -#nosetests.xml -#coverage.xml -#*.cover -#*.py,cover -#.hypothesis/ -#.pytest_cache/ - +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ # Translations *.mo *.pot - # Django stuff: *.log local_settings.py db.sqlite3 db.sqlite3-journal - # Flask stuff: instance/ .webassets-cache - # Scrapy stuff: .scrapy - # Sphinx documentation docs/_build/ - # PyBuilder target/ - # Jupyter Notebook .ipynb_checkpoints - # IPython profile_default/ ipython_config.py - # pyenv .python-version - # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. # However, in case of collaboration, if having platform-specific dependencies or dependencies # having no cross-platform support, pipenv may install dependencies that don't work, or not # install all needed dependencies. #Pipfile.lock - # PEP 582; used by e.g. github.com/David-OConnor/pyflow __pypackages__/ - # Celery stuff celerybeat-schedule celerybeat.pid - # SageMath parsed files *.sage.py - # Environments .env .venv @@ -109,17 +90,13 @@ venv/ ENV/ env.bak/ venv.bak/ - # Spyder project settings .spyderproject .spyproject - # Rope project settings .ropeproject - # mkdocs documentation /site - # mypy .mypy_cache/ .dmypy.json @@ -131,4 +108,3 @@ dmypy.json /.idea/ __pycache__ wit_exercises -.idea From f1faea392fdc1d78a9a9c239cffb675928f2b772 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Tue, 22 Mar 2022 11:25:48 +0200 Subject: [PATCH 50/73] add tests --- .coverage | Bin 53248 -> 53248 bytes .gitignore | 4 +-- requirements.txt | 1 - setup.py | 2 +- tests/__init__.py | 0 tests/__pycache__/__init__.cpython-39.pyc | Bin 0 -> 148 bytes .../conftest.cpython-39-pytest-7.0.1.pyc | Bin 0 -> 759 bytes .../test_add.cpython-39-pytest-7.0.1.pyc | Bin 0 -> 1358 bytes .../test_commit.cpython-39-pytest-7.0.1.pyc | Bin 0 -> 2332 bytes .../test_init.cpython-39-pytest-7.0.1.pyc | Bin 0 -> 2261 bytes tests/conftest.py | 18 +++++++++++ tests/test_add.py | 22 ++++++++++++++ tests/test_commit.py | 28 ++++++++++++++++++ tests/test_init.py | 23 ++++++++++++++ 14 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 tests/__init__.py create mode 100644 tests/__pycache__/__init__.cpython-39.pyc create mode 100644 tests/__pycache__/conftest.cpython-39-pytest-7.0.1.pyc create mode 100644 tests/__pycache__/test_add.cpython-39-pytest-7.0.1.pyc create mode 100644 tests/__pycache__/test_commit.cpython-39-pytest-7.0.1.pyc create mode 100644 tests/__pycache__/test_init.cpython-39-pytest-7.0.1.pyc create mode 100644 tests/conftest.py create mode 100644 tests/test_add.py create mode 100644 tests/test_commit.py create mode 100644 tests/test_init.py diff --git a/.coverage b/.coverage index 94f4070f6f2cf27790a63b51752134dbd58d8b1d..948b5255bf50e824546d35ea8a4f0e6ccba8335f 100644 GIT binary patch delta 23 ecmZozz}&Eac|(;xhoPaBk%^Uw`Q|45x&;7TatF}> delta 23 ecmZozz}&Eac|(;xhk>P)sil>H+2$twx&;7T?g!fd diff --git a/.gitignore b/.gitignore index 4334b17..b61e184 100644 --- a/.gitignore +++ b/.gitignore @@ -101,10 +101,10 @@ venv.bak/ .mypy_cache/ .dmypy.json dmypy.json - +json # Pyre type checker .pyre/ .wit /.idea/ -__pycache__ wit_exercises +\__pycache__ \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 547c6db..826fb02 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,4 @@ pytest~=7.0.1 -project~=0.0.0 Flask~=2.0.3 click~=8.0.4 graphviz~=0.19.1 diff --git a/setup.py b/setup.py index b74b84b..b038e4b 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,4 @@ -from setuptools import setup, find_packages +from setuptools import setup setup( diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/__pycache__/__init__.cpython-39.pyc b/tests/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1f81002c13ec7ea1e3d930a820da2d534411a49e GIT binary patch literal 148 zcmYe~<>g`kf|ee!BoO@=L?8o3AjbiSi&=m~3PUi1CZpdI zlUZDpm>N@1l%JKFTv8lUo>>wP<$%~RC8@8nu5av6D@<0%Z5nb`b;!ibx@}^#_t};=-BIHSgez zeI>4)`U;(Tq@2_w?s(rF@Aw_bVm6Bjj>Y%Oo41sZ-xeGX55X0RTB2fvK}}L{D{VYV zfHb4jhanQAfs2G`h%2q5W}J?J@Ng9~kBy#y`7HQJ9wD7D_(GEK57s2h1k6mdLg&?{ zEw$)c6DqD08W{0a+4Z~xyYnzCr4hoIKDST>%^6^q(jY zj0AJCr!0I1hwQ%S$V1uqKhoZQw8M%(wEu`r?kwGSnMRr`o!<$ahE-QHF3(?#i?0ba zVP8nzYGopRFK}bG{xPmZ&CeJ5UK=ui3kwGGgEf=D1kGCWrZ;}GWi;U5aL%?$tm literal 0 HcmV?d00001 diff --git a/tests/__pycache__/test_add.cpython-39-pytest-7.0.1.pyc b/tests/__pycache__/test_add.cpython-39-pytest-7.0.1.pyc new file mode 100644 index 0000000000000000000000000000000000000000..527386afe076f83555fa7ef0b495e8d12ca00228 GIT binary patch literal 1358 zcmZ8h&5q+l5bm}e$FY-{%<{W%V1eqZQhzX2)H%~8r_Xzm|g}b8z z!ZVoK01-scf@IXKUg>*;k}}9TwAF-J=rrA|3#(T|WiRVFonORdk|mB0iheoB2Ecbj z_=aRhvU`2J9g6OZi0D_k^F&X?Z^(vbCxU)M(&SHgnOvmQ_PG#jx|mN)Ud=&{UghRX zr78vda3&4YhR^c(jBzFTgyOON0MAGS^94-(5{MyN+K?Tkqye8kBx~BxttUK0jK2*` zXGeej0Qj(>*WC@EufWFuzKu`Ge0WCmSEt}Te&4|q1T6J0R*{j~jLfaEB#o?BY1^4x ziCo$EM&(8_BS96`OWbBd#d9sS^1&d5CfZ=mOPP8$GG)zbZmzN(?qt)vkiQW%fIWXb zeevn|TP>9y=UQ<&u2pp{Cq|ENa>Mol@?$)y9c2)>QN6T7cbR*YNeo;MF4V37XiOuR zeX5SpkOW_3roxk{zv`iQhJLN?Ppd*mbvAC-^D(L(Io0w1R1@^+FhXE(x)l5b%)cox zUPBs40*2Z64Xh}wy~eu^)_&t}$U0~O-3Tf?)7geQ@|x(cO?MkLkTCTUxE^wINTB2W z9d&E4qr(5if0wK~CI%#FAgvqvBNT8z*8VzhX$vk^&$)((ng^dete1~d9sjUr9(?Yg z^8*CT9y(3+NZ#fU;duQpjo0>VOc%@N|0%-Mw|>1mMRJ}2d7SnY20?X^V0csj#D?uv zw*RbNvdcwYn0&5nSX2{UXd46SGRKvDpXsY=Q3$4Ft=O!nE_uPQYHW{bK9vaDqvy^Y z=n~f+_ANH8RLKpKw{^ki-1SdrleV^8KGhJ7IYDC*G@=d2*J<@)Ce-Hz|B{8Re_?L+FyyA&9~VWY zdz*L9-2!FhD^lcLA)oE zQGaO8W5@hM6{B~b&eQ|#p9CeJarp?eCTb%~G%|jXO>Nx*Tf4Mp5X$el;8Ulxo-IuqW#gDl-O?%D z=WObgp85~`I>Ifz0T&+H2iDA?@!&XwKcDRnumvToMgB>>puucD>5Unu+J!HImk!MD zi>7FmKCLCF*Amogfg_zdP&_D&DWp6cWc%S!3&XiqW!jOmp%3&?CsA-ZdhOc!eDH9@QrBy%E7 z=W_}UP)zum^YLITi$uri!6Z*c3G!`%`3B9o80N`oNQmGhk!jd86m)KfJ+S!{f|*x0HX)d066+HgJECXrW(E`^3RU7aZcquL-4ARqqA z{4SU4&_06^-XVw*VRVHss^Nj#gy6BLwuA*B*rkmiApoWGjfDvO%vDo6fRd;W%=8c>wKV=rpp>5(Vs z3y}SVo`m$@)LS9#la4qBFFk!J39!>X+S0eP}IqZB3#YGgCP^^MLv~EWZFt~ZtUAPW%Bw62fQ@DYk@Afkmd-Z1E7`EqoXJNP?_sA3c`n#7Z2%FOP{cG@J& zUYc?y#|rh3MO^p~ocR&Ha^epl)D!RPncYqz4oEPov0p!a$Is)}_UlbL9iPDS{pH>L zOM{T#vC(`0BlqDI&!J$1(VRq7*G6F)gp$IFY+Cg=k)wOu$c5U-y`mMh>OMd60Wh9xAK03{W6puI`a6md)Ka=s{N&i4*gMMhK_E9S1XMnMcs~K!$MRJsicnCwN zSpHB37k!WtVhJ`8HS%T73ih(Kg0Z*XEcq^Od|7$&;u>- zaI|gLTAaFeL6iH+22EbA$!ln`L6sYJ$?+V*fg~23ptTk$tZrS?Q82P1tX^0%SIt=VX%G%g-XpAiuH1z+4 z%48dq8CQ~d^C{x|xy53CdGymBDYZPsNoWjmu_2X)kgn^A|zyYTv> z79(&pW_QmYBtoQIF1^1zJlhC`|6Oe??PzFi0)bIOtD#uQ1Re~3v>f^)<>5KOa}k=# z9GY+9#5EwPIK7qh^L%58pdZ7TiYuwy{^Q77`6>xe7IZJtH zb4*W2-@{@Zi%l%)*n9?ySuEzDP!=d&J)dbrtOr5Y@LJgAHu^YK;8k#ccoy%UWVy`xLOJ>1AjyUD z0o9>MxVjaKDa_ z=_i;Bb%=H7^bAyMI!84Z18uGu4hF>#5@FcknCUpCI@Lyz)pUBz#(LGLs5YBDYt6<+ zv+-&3o2_Qg-KfE{RYj&6y4SnbTK|Rc4?x%J?T6cYU%{pqdzs)#x;Ny5C+UF{dwL&N z4Yc<#mO_^?-VZCoGZpCg))zw?Micrnq#oU;FX>N|e+1aI%#XJKF1^nD_rQ?kiejFk z1apLhZ2iL`*!BfnjgR44wBUDPQqrI8!40qqDE_{NSD#tB8#>Au2xT7}&h~pEP<;ukbk!SlH{~qv9u&Y}KekH|QxKgfy z35XHb^H7}$gaZkE5N>Qr9d)g|n&^!wd!H2pc9N&}a4iI$xc6Ye0_qt7l($UJ`x`Zb BZW{mq literal 0 HcmV?d00001 diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..48ff19d --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,18 @@ +import os + +import pytest + +from project.init import init_function + + +@pytest.fixture(scope="session") +def test_folder(tmp_path_factory): + test_folder = tmp_path_factory.mktemp('test_wit') + last_folder = test_folder / 'folder1' / 'folder2' + last_folder.mkdir(parents=True, exist_ok=True) + (test_folder / 'file1.txt').write_text("") + (test_folder / 'folder1' / 'file2.txt').write_text("") + (last_folder / 'file3.txt').write_text("") + os.chdir(test_folder) + init_function() + return test_folder diff --git a/tests/test_add.py b/tests/test_add.py new file mode 100644 index 0000000..7bf586e --- /dev/null +++ b/tests/test_add.py @@ -0,0 +1,22 @@ +import os +import pytest + +from project.add import add_function +from project.errors import WitError +from project.utils import get_staging_area + + +def test_raise_error(tmp_path): + os.chdir(tmp_path) + test_file = tmp_path / 'test.txt' + test_file.write_text("") + with pytest.raises(WitError): + add_function(test_file.name) + + +@pytest.mark.parametrize('file_to_add', ['file1.txt', r'folder1\folder2\file3.txt', r'folder1\folder2']) +def test_add_function(test_folder, file_to_add): + os.chdir(test_folder) + add_function(test_folder / file_to_add) + path_in_staging_area = get_staging_area(test_folder) / file_to_add + assert path_in_staging_area.exists() diff --git a/tests/test_commit.py b/tests/test_commit.py new file mode 100644 index 0000000..a5c0f07 --- /dev/null +++ b/tests/test_commit.py @@ -0,0 +1,28 @@ +import os + +import pytest + +from project.commit import commit_function +from project.errors import WitError +from project.utils import get_head_reference, get_commit_path, get_commit_id_of_branch, get_references_path + + +def test_raise_error(tmp_path): + os.chdir(tmp_path) + with pytest.raises(WitError): + commit_function("") + + +def test_commit(test_folder): + os.chdir(test_folder) + commit_function("test commit") + commit_id = get_head_reference(test_folder) + commit_txt_file = get_commit_path(test_folder, commit_id).with_suffix(".txt") + assert commit_id + assert "test commit" in commit_txt_file.read_text() + + +def test_second_commit(test_folder): + commit_function("test second commit") + references_path = get_references_path(test_folder) + assert get_head_reference(test_folder) == get_commit_id_of_branch("master", references_path) diff --git a/tests/test_init.py b/tests/test_init.py new file mode 100644 index 0000000..a1e1ff9 --- /dev/null +++ b/tests/test_init.py @@ -0,0 +1,23 @@ +import os +import shutil +from pathlib import Path +import pytest + +from project.errors import WitExistsError +from project.init import init_function +from project.utils import get_wit_dir, get_images_path, get_staging_area, get_activated_path + + +def test_wit_dir(test_folder): + wit_path = get_wit_dir(test_folder) + assert wit_path.is_dir() + assert get_images_path(test_folder).is_dir() + assert get_staging_area(test_folder).is_dir() + assert get_activated_path(test_folder).read_text() == "master" + + +def test_wit_exists(test_folder): + os.chdir(test_folder) + with pytest.raises(WitExistsError): + init_function() + From 4370aea12e6ab7f0e8e4b7c44919cca09b74657c Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Tue, 22 Mar 2022 11:27:32 +0200 Subject: [PATCH 51/73] . --- tests/__pycache__/__init__.cpython-39.pyc | Bin 148 -> 0 bytes .../conftest.cpython-39-pytest-7.0.1.pyc | Bin 759 -> 0 bytes .../test_add.cpython-39-pytest-7.0.1.pyc | Bin 1358 -> 0 bytes .../test_commit.cpython-39-pytest-7.0.1.pyc | Bin 2332 -> 0 bytes .../test_init.cpython-39-pytest-7.0.1.pyc | Bin 2261 -> 0 bytes 5 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tests/__pycache__/__init__.cpython-39.pyc delete mode 100644 tests/__pycache__/conftest.cpython-39-pytest-7.0.1.pyc delete mode 100644 tests/__pycache__/test_add.cpython-39-pytest-7.0.1.pyc delete mode 100644 tests/__pycache__/test_commit.cpython-39-pytest-7.0.1.pyc delete mode 100644 tests/__pycache__/test_init.cpython-39-pytest-7.0.1.pyc diff --git a/tests/__pycache__/__init__.cpython-39.pyc b/tests/__pycache__/__init__.cpython-39.pyc deleted file mode 100644 index 1f81002c13ec7ea1e3d930a820da2d534411a49e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmYe~<>g`kf|ee!BoO@=L?8o3AjbiSi&=m~3PUi1CZpdI zlUZDpm>N@1l%JKFTv8lUo>>wP<$%~RC8@8nu5av6D@<0%Z5nb`b;!ibx@}^#_t};=-BIHSgez zeI>4)`U;(Tq@2_w?s(rF@Aw_bVm6Bjj>Y%Oo41sZ-xeGX55X0RTB2fvK}}L{D{VYV zfHb4jhanQAfs2G`h%2q5W}J?J@Ng9~kBy#y`7HQJ9wD7D_(GEK57s2h1k6mdLg&?{ zEw$)c6DqD08W{0a+4Z~xyYnzCr4hoIKDST>%^6^q(jY zj0AJCr!0I1hwQ%S$V1uqKhoZQw8M%(wEu`r?kwGSnMRr`o!<$ahE-QHF3(?#i?0ba zVP8nzYGopRFK}bG{xPmZ&CeJ5UK=ui3kwGGgEf=D1kGCWrZ;}GWi;U5aL%?$tm diff --git a/tests/__pycache__/test_add.cpython-39-pytest-7.0.1.pyc b/tests/__pycache__/test_add.cpython-39-pytest-7.0.1.pyc deleted file mode 100644 index 527386afe076f83555fa7ef0b495e8d12ca00228..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1358 zcmZ8h&5q+l5bm}e$FY-{%<{W%V1eqZQhzX2)H%~8r_Xzm|g}b8z z!ZVoK01-scf@IXKUg>*;k}}9TwAF-J=rrA|3#(T|WiRVFonORdk|mB0iheoB2Ecbj z_=aRhvU`2J9g6OZi0D_k^F&X?Z^(vbCxU)M(&SHgnOvmQ_PG#jx|mN)Ud=&{UghRX zr78vda3&4YhR^c(jBzFTgyOON0MAGS^94-(5{MyN+K?Tkqye8kBx~BxttUK0jK2*` zXGeej0Qj(>*WC@EufWFuzKu`Ge0WCmSEt}Te&4|q1T6J0R*{j~jLfaEB#o?BY1^4x ziCo$EM&(8_BS96`OWbBd#d9sS^1&d5CfZ=mOPP8$GG)zbZmzN(?qt)vkiQW%fIWXb zeevn|TP>9y=UQ<&u2pp{Cq|ENa>Mol@?$)y9c2)>QN6T7cbR*YNeo;MF4V37XiOuR zeX5SpkOW_3roxk{zv`iQhJLN?Ppd*mbvAC-^D(L(Io0w1R1@^+FhXE(x)l5b%)cox zUPBs40*2Z64Xh}wy~eu^)_&t}$U0~O-3Tf?)7geQ@|x(cO?MkLkTCTUxE^wINTB2W z9d&E4qr(5if0wK~CI%#FAgvqvBNT8z*8VzhX$vk^&$)((ng^dete1~d9sjUr9(?Yg z^8*CT9y(3+NZ#fU;duQpjo0>VOc%@N|0%-Mw|>1mMRJ}2d7SnY20?X^V0csj#D?uv zw*RbNvdcwYn0&5nSX2{UXd46SGRKvDpXsY=Q3$4Ft=O!nE_uPQYHW{bK9vaDqvy^Y z=n~f+_ANH8RLKpKw{^ki-1SdrleV^8KGhJ7IYDC*G@=d2*J<@)Ce-Hz|B{8Re_?L+FyyA&9~VWY zdz*L9-2!FhD^lcLA)oE zQGaO8W5@hM6{B~b&eQ|#p9CeJarp?eCTb%~G%|jXO>Nx*Tf4Mp5X$el;8Ulxo-IuqW#gDl-O?%D z=WObgp85~`I>Ifz0T&+H2iDA?@!&XwKcDRnumvToMgB>>puucD>5Unu+J!HImk!MD zi>7FmKCLCF*Amogfg_zdP&_D&DWp6cWc%S!3&XiqW!jOmp%3&?CsA-ZdhOc!eDH9@QrBy%E7 z=W_}UP)zum^YLITi$uri!6Z*c3G!`%`3B9o80N`oNQmGhk!jd86m)KfJ+S!{f|*x0HX)d066+HgJECXrW(E`^3RU7aZcquL-4ARqqA z{4SU4&_06^-XVw*VRVHss^Nj#gy6BLwuA*B*rkmiApoWGjfDvO%vDo6fRd;W%=8c>wKV=rpp>5(Vs z3y}SVo`m$@)LS9#la4qBFFk!J39!>X+S0eP}IqZB3#YGgCP^^MLv~EWZFt~ZtUAPW%Bw62fQ@DYk@Afkmd-Z1E7`EqoXJNP?_sA3c`n#7Z2%FOP{cG@J& zUYc?y#|rh3MO^p~ocR&Ha^epl)D!RPncYqz4oEPov0p!a$Is)}_UlbL9iPDS{pH>L zOM{T#vC(`0BlqDI&!J$1(VRq7*G6F)gp$IFY+Cg=k)wOu$c5U-y`mMh>OMd60Wh9xAK03{W6puI`a6md)Ka=s{N&i4*gMMhK_E9S1XMnMcs~K!$MRJsicnCwN zSpHB37k!WtVhJ`8HS%T73ih(Kg0Z*XEcq^Od|7$&;u>- zaI|gLTAaFeL6iH+22EbA$!ln`L6sYJ$?+V*fg~23ptTk$tZrS?Q82P1tX^0%SIt=VX%G%g-XpAiuH1z+4 z%48dq8CQ~d^C{x|xy53CdGymBDYZPsNoWjmu_2X)kgn^A|zyYTv> z79(&pW_QmYBtoQIF1^1zJlhC`|6Oe??PzFi0)bIOtD#uQ1Re~3v>f^)<>5KOa}k=# z9GY+9#5EwPIK7qh^L%58pdZ7TiYuwy{^Q77`6>xe7IZJtH zb4*W2-@{@Zi%l%)*n9?ySuEzDP!=d&J)dbrtOr5Y@LJgAHu^YK;8k#ccoy%UWVy`xLOJ>1AjyUD z0o9>MxVjaKDa_ z=_i;Bb%=H7^bAyMI!84Z18uGu4hF>#5@FcknCUpCI@Lyz)pUBz#(LGLs5YBDYt6<+ zv+-&3o2_Qg-KfE{RYj&6y4SnbTK|Rc4?x%J?T6cYU%{pqdzs)#x;Ny5C+UF{dwL&N z4Yc<#mO_^?-VZCoGZpCg))zw?Micrnq#oU;FX>N|e+1aI%#XJKF1^nD_rQ?kiejFk z1apLhZ2iL`*!BfnjgR44wBUDPQqrI8!40qqDE_{NSD#tB8#>Au2xT7}&h~pEP<;ukbk!SlH{~qv9u&Y}KekH|QxKgfy z35XHb^H7}$gaZkE5N>Qr9d)g|n&^!wd!H2pc9N&}a4iI$xc6Ye0_qt7l($UJ`x`Zb BZW{mq From ae8b8261897896931775340800d8074ad5d5b99c Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Tue, 22 Mar 2022 21:50:50 +0200 Subject: [PATCH 52/73] done: test_graph. fix other tests and graph return --- .coverage | Bin 53248 -> 53248 bytes project/checkout.py | 5 ++++- project/graph.py | 18 ++++++++++++--- project/init.py | 7 +++++- setup.py | 5 ++--- tests/conftest.py | 10 ++++----- tests/test_add.py | 7 ++++-- tests/test_commit.py | 11 ++++++++-- tests/test_graph.py | 51 +++++++++++++++++++++++++++++++++++++++++++ tests/test_init.py | 11 ++++++---- 10 files changed, 104 insertions(+), 21 deletions(-) create mode 100644 tests/test_graph.py diff --git a/.coverage b/.coverage index 948b5255bf50e824546d35ea8a4f0e6ccba8335f..0e4517903ca3c6c76cb6483348da27189c17b618 100644 GIT binary patch delta 707 zcmY+BT}V@57{||Xb35Dn@tm_3Nv;A335#4B1vZ^fceNSiMO~<@F;t?p<}4<;sTEzU z?^99G$L{KCRKvTmNnL~r8(J5ER(CFfKE!TDhu+?EXd|zl=l|#bJn!$}ok*J|(xw+< zty0^bj=k+2?zZey>y+HApd|rb!(})KRys?sQ9s>47KloY5hs3!@8J`;5iMmE`6aS+ zDQ00(RB!utsLY3K!{OoB?nwNAtlsdq+s}legCSjlAqS&@$Pkwvsvh<4RA+n=jKl)5 z(Gl)>3EyMld)y>A6bha`JF4&T;9BxjG!PEz(_Zv1X}nl(EY05X#p*csvH*vulWfHA z$z3{!PlAM9_&&W3Z{P~;A&cZVTISrZklNeltyeszaUI=Fs-SY!u~k_??djjO9+h^R zCr!p2{tuPZf;CcH4Xz{Yi#0VX;1Hk!KcEaBVG#;24bR~*T!k@+KtCLTPH=&PlYXH| zNimByhw`Zs-zM{}Th3c&&K1Vz*}zY>DXD4R6;`Q;nx)9h1bDy&nJuiuylagz<+6!} z1yPVL=2o=^Q6{=Wz6-hiB~&c4_<)4D z0v% diff --git a/project/checkout.py b/project/checkout.py index 265d2d5..0fe1efb 100644 --- a/project/checkout.py +++ b/project/checkout.py @@ -3,7 +3,10 @@ from typing import Union from project.errors import BranchDoesntExistError, FilesDoesntMatchError, WitError -from project.status import get_changes_not_staged_for_commit, get_changes_to_be_committed +from project.status import ( + get_changes_not_staged_for_commit, + get_changes_to_be_committed, +) from project.utils import ( get_activated_path, get_all_files_in_directory_and_subs, diff --git a/project/graph.py b/project/graph.py index 7042d0d..a750e97 100644 --- a/project/graph.py +++ b/project/graph.py @@ -1,10 +1,16 @@ import re from pathlib import Path +from typing import Optional from graphviz import Digraph from project.errors import WitError -from project.utils import get_head_reference, get_images_path, get_repository_path, get_wit_dir +from project.utils import ( + get_head_reference, + get_images_path, + get_repository_path, + get_wit_dir, +) parent_id_regex = re.compile( r"^parent = (?P\w{20})(, (?P\w{20}))?$", @@ -12,7 +18,7 @@ ) -def graph_function() -> None: +def graph_function(test: bool = False) -> Optional[str]: repository = get_repository_path(Path.cwd()) if not repository: raise WitError("<.wit> file not found") @@ -22,7 +28,13 @@ def graph_function() -> None: wit_dir = get_wit_dir(repository) images_path = get_images_path(repository) create_nodes(commit_id, dot, images_path) - dot.render(f"Graph {current_commit_id}", wit_dir, view=True, cleanup=True) + dot.render( + filename=f"Graph_{current_commit_id}", + directory=wit_dir, + view=True, + cleanup=True, + ) + return dot.source if test else None def create_nodes(commit_id: str, dot: Digraph, images_path: Path) -> None: diff --git a/project/init.py b/project/init.py index d8b2ee1..e5b7e72 100644 --- a/project/init.py +++ b/project/init.py @@ -1,7 +1,12 @@ from pathlib import Path from project.errors import WitExistsError -from project.utils import get_activated_path, get_images_path, get_staging_area, get_wit_dir +from project.utils import ( + get_activated_path, + get_images_path, + get_staging_area, + get_wit_dir, +) def init_function() -> None: diff --git a/setup.py b/setup.py index b038e4b..dadd890 100644 --- a/setup.py +++ b/setup.py @@ -1,9 +1,8 @@ from setuptools import setup - setup( - name='project', - package_dir={'project': 'project'}, + name="project", + package_dir={"project": "project"}, include_package_data=True, packages=["project"], ) diff --git a/tests/conftest.py b/tests/conftest.py index 48ff19d..b758333 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -7,12 +7,12 @@ @pytest.fixture(scope="session") def test_folder(tmp_path_factory): - test_folder = tmp_path_factory.mktemp('test_wit') - last_folder = test_folder / 'folder1' / 'folder2' + test_folder = tmp_path_factory.mktemp("test_wit") + last_folder = test_folder / "folder1" / "folder2" last_folder.mkdir(parents=True, exist_ok=True) - (test_folder / 'file1.txt').write_text("") - (test_folder / 'folder1' / 'file2.txt').write_text("") - (last_folder / 'file3.txt').write_text("") + (test_folder / "file1.txt").write_text("") + (test_folder / "folder1" / "file2.txt").write_text("") + (last_folder / "file3.txt").write_text("") os.chdir(test_folder) init_function() return test_folder diff --git a/tests/test_add.py b/tests/test_add.py index 7bf586e..ccb4583 100644 --- a/tests/test_add.py +++ b/tests/test_add.py @@ -1,4 +1,5 @@ import os + import pytest from project.add import add_function @@ -8,13 +9,15 @@ def test_raise_error(tmp_path): os.chdir(tmp_path) - test_file = tmp_path / 'test.txt' + test_file = tmp_path / "test.txt" test_file.write_text("") with pytest.raises(WitError): add_function(test_file.name) -@pytest.mark.parametrize('file_to_add', ['file1.txt', r'folder1\folder2\file3.txt', r'folder1\folder2']) +@pytest.mark.parametrize( + "file_to_add", ["file1.txt", r"folder1\folder2\file3.txt", r"folder1\folder2"] +) def test_add_function(test_folder, file_to_add): os.chdir(test_folder) add_function(test_folder / file_to_add) diff --git a/tests/test_commit.py b/tests/test_commit.py index a5c0f07..57465d1 100644 --- a/tests/test_commit.py +++ b/tests/test_commit.py @@ -4,7 +4,12 @@ from project.commit import commit_function from project.errors import WitError -from project.utils import get_head_reference, get_commit_path, get_commit_id_of_branch, get_references_path +from project.utils import ( + get_commit_id_of_branch, + get_commit_path, + get_head_reference, + get_references_path, +) def test_raise_error(tmp_path): @@ -25,4 +30,6 @@ def test_commit(test_folder): def test_second_commit(test_folder): commit_function("test second commit") references_path = get_references_path(test_folder) - assert get_head_reference(test_folder) == get_commit_id_of_branch("master", references_path) + assert get_head_reference(test_folder) == get_commit_id_of_branch( + "master", references_path + ) diff --git a/tests/test_graph.py b/tests/test_graph.py new file mode 100644 index 0000000..8b7b22b --- /dev/null +++ b/tests/test_graph.py @@ -0,0 +1,51 @@ +import os +from pathlib import Path + +import pytest + +from project.add import add_function +from project.branch import branch_function +from project.checkout import checkout_function +from project.commit import commit_function +from project.errors import WitError +from project.graph import graph_function +from project.merge import merge_function +from project.utils import ( + get_branches_commits, + get_head_reference, + get_references_path, + get_wit_dir, +) + + +def test_raise_error(tmp_path, test_folder): + os.chdir(tmp_path) + with pytest.raises(WitError): + graph_function() + + +def test_graph_function(test_folder): + os.chdir(test_folder) + create_branch_and_checkout("branch1") + change_add_and_commit_file3(test_folder) + checkout_function("master") + merge_function("branch1") + dot_source = graph_function(test=True) + current_commit_id = get_head_reference(test_folder) + wit_dir = get_wit_dir(test_folder) + references_file = get_references_path(test_folder) + assert wit_dir / f"Graph_{current_commit_id}.pdf" in set(wit_dir.iterdir()) + for commit in get_branches_commits(references_file).values(): + assert commit in dot_source + + +def create_branch_and_checkout(branch_name: str) -> None: + branch_function(branch_name) + checkout_function(branch_name) + + +def change_add_and_commit_file3(test_folder: Path) -> None: + file3 = test_folder / r"folder1\folder2\file3.txt" + file3.write_text("1") + add_function(str(file3)) + commit_function("add file3") diff --git a/tests/test_init.py b/tests/test_init.py index a1e1ff9..d81b816 100644 --- a/tests/test_init.py +++ b/tests/test_init.py @@ -1,11 +1,15 @@ import os -import shutil -from pathlib import Path + import pytest from project.errors import WitExistsError from project.init import init_function -from project.utils import get_wit_dir, get_images_path, get_staging_area, get_activated_path +from project.utils import ( + get_activated_path, + get_images_path, + get_staging_area, + get_wit_dir, +) def test_wit_dir(test_folder): @@ -20,4 +24,3 @@ def test_wit_exists(test_folder): os.chdir(test_folder) with pytest.raises(WitExistsError): init_function() - From 42bd93f22c03694678bb811a9cc31aaa075a1759 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Tue, 22 Mar 2022 22:55:03 +0200 Subject: [PATCH 53/73] add test_branch --- .coverage | Bin 53248 -> 53248 bytes .gitignore | 12 ------------ project/branch.py | 1 + tests/test_branch.py | 30 ++++++++++++++++++++++++++++++ 4 files changed, 31 insertions(+), 12 deletions(-) create mode 100644 tests/test_branch.py diff --git a/.coverage b/.coverage index 0e4517903ca3c6c76cb6483348da27189c17b618..6b282fffa58705a4e10e9530fbe21851b9f8ce51 100644 GIT binary patch delta 645 zcmYMvT}V@57zgm3oo(lwo%g)YIcF!8K}BC6eK<{xlI0e4x6eK4p~!V>5|D847?}@r zjout=iVu5bwy~1$zE;~#Mg3hX`zF%xGJ@4oy~Y2Y->n!`9|S${PgiFeYKzhk?ks(lB$f=R=oSQ7WU)a! y<>}tq5F}x{7mAf%Jjsn8;hiN)3gdfu9a2P?IAn$t`|T~kr*GP3Pyv~Hqo7JF}l%cOKM}JF_cP*rYdbA z8W*Uj7mXo4Sh^x&4`Y`$r`^$xYE5XqVCa*`xzBJ2 zgCe~Z-gG;J)I>6o_M|d6!I-&K@Ts9+;TyH1H^?_YH#rh#}9J>3^e)jkH=8QseL3|cwi z`QI<{kDnHB3`)xfH&7bc`NuEv*Dt!XuEhXT01LiA72ZJwitr2`!vnYq7a#>u2*O@) zgUS6qlAK~VMAbCjTbZ>wr+_{!KR;U>m}OmG*{Ymv`#&(t5^ZORIWX`6H%v6MGV?Ds z>4eAiBq@l3a%t+D-6-m~*5J>=)UGlrRavG>(RgEOt5fF@;?#&Hat~SAa@F&&x&FKJ zo`>CEWUq?$OqI>9P*q;L)K9+L8l=?5m1K6>u7V=-V9MvRSy~*~D2*|hR!5p81BR)5 Oa|6F428H2A{oWt@(!!De diff --git a/.gitignore b/.gitignore index b61e184..c8f766a 100644 --- a/.gitignore +++ b/.gitignore @@ -33,18 +33,6 @@ MANIFEST pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.py,cover -.hypothesis/ -.pytest_cache/ # Translations *.mo *.pot diff --git a/project/branch.py b/project/branch.py index ca75532..1dbe52c 100644 --- a/project/branch.py +++ b/project/branch.py @@ -18,5 +18,6 @@ def branch_function(name: str) -> None: if name in existing_branches: raise BranchExistsError(f"Branch {name} already exists.") commit_id = get_head_reference(repository) + # TODO: if no commit was done yet- create references file / raise error with references_file.open("a") as ref_file: ref_file.write(f"\n{name}={commit_id}") diff --git a/tests/test_branch.py b/tests/test_branch.py new file mode 100644 index 0000000..ebd44d6 --- /dev/null +++ b/tests/test_branch.py @@ -0,0 +1,30 @@ +import os + +import pytest + +from project.branch import branch_function +from project.errors import WitError, BranchExistsError +from project.utils import get_references_path, get_head_reference + + +def test_raise_error(tmp_path): + os.chdir(tmp_path) + with pytest.raises(WitError): + branch_function("") + + +def test_branch_function(test_folder): # fail + os.chdir(test_folder) + branch_function("TestBranch") + commit_id = get_head_reference(test_folder) + references_file = get_references_path(test_folder) + assert f"TestBranch={commit_id}" in references_file + + +def test_branch_exists_error(test_folder): # fail + with pytest.raises(BranchExistsError): + branch_function("TestBranch") + + +# TODO: test if no commit was done yet. +# test second branch. From f0555d149daaf0fbed21571b7d0a1173947b7fd6 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Wed, 23 Mar 2022 00:35:18 +0200 Subject: [PATCH 54/73] add test_checkout --- .coverage | Bin 53248 -> 53248 bytes .gitignore | 2 -- project/branch.py | 15 +++++----- project/checkout.py | 10 +++---- project/errors.py | 2 +- tests/test_branch.py | 12 ++++++-- tests/test_checkout.py | 63 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 87 insertions(+), 17 deletions(-) create mode 100644 tests/test_checkout.py diff --git a/.coverage b/.coverage index 6b282fffa58705a4e10e9530fbe21851b9f8ce51..21590ed2ff20db3a31dc26b6dc7e12744b8eaf59 100644 GIT binary patch delta 683 zcmZ9HT}YEr9LD$VefROc=i~o=h=Ejw70F5+7!oROWzdb=?7~6xMM$KSn~Q>?jcsN( zQJJ2;C_%64E`oI#P4Xhl(44TlLI@gold`MP=yY6LMR(70{?BvxJ*inaH7mcm)~2=Z z@_IYly`A2JnX$Gp-D9Bv8@z*Y=mi&Dpm%7HT4aSVGC&Oc2~XjE3@C>lqJfN|??cWW zOR=RTHW_T53LtejGJK_V^m>=c?giT!?NcRVOVJCL&y5a=gHIP}`FGlK`aw8Hwaab? zG>NkQ;C`0sGudii3-bq5edzq)#pu^>} z>P*Y2A6C+i+GuSsIxr#fS@;6?o{i4^rTlwtF;RLhaOi-75LM!CXYooZBT;m zP=L>ngDkv;7w`-w;RalS6L1W=papi>jvL^E9biilo+A>!}%6qba1{eCwKvWfP11 z>;~VKESG)Xc&Q|nol9Jyh6wC5UZ%hDHqJjru`Yarp7*Vl_%vuBTs^F(3d^!ig>Iq| zn`Cpx-xSM-B!h^TJtU&6@%Wcm4`2RaCs>g>)a^JwQ79IQ#l|`$A|CY9`Gijw`TJ~n zp}-gIZcV(JTEhm{RH5qC{BqI9o=@y{JWlo$ZnC9`4%vbPbKT!-hlCgv0+&++CCkc; I&&0jI08QK4!2kdN delta 609 zcmZozz}&Eac|(Ohmyv>zk(H^Tm7(S4CjBM>4I%EC4E%@qTlk&%+4)ZL_3-)e3G-g$ zoy;4^E6j6=XChB9j~Mq&?wOkf1#-FB?1Wet8W|@~^wXGZ@5?>8&zocNWp5L%+|;7< zRK0>qYk|pqe#TtsMTrF&K&}n{Eln%&&|y&0qS$$2HMODwV7vgw{ImA(CxDr_+9u!c&G48;uYaL z#Uswo!F`J-gs+$XFn=qbKkp^pAfC(Ivw&{T@+U8bNMG zu^%YhUwit0{D=SI^?&}@Kl}glC*vQsbN^ZR1b_e z{(pSG+Mkop|DR^!;sy$faldMKex8|w3& None: if not repository: raise WitError("<.wit> file not found") references_file = get_references_path(repository) - existing_branches = get_branches_commits(references_file) - if name in existing_branches: - raise BranchExistsError(f"Branch {name} already exists.") - commit_id = get_head_reference(repository) - # TODO: if no commit was done yet- create references file / raise error - with references_file.open("a") as ref_file: - ref_file.write(f"\n{name}={commit_id}") + if references_file.exists(): + existing_branches = get_branches_commits(references_file) + if name in existing_branches: + raise BranchExistsError(f"Branch {name} already exists.") + commit_id = get_head_reference(repository) + with references_file.open("a") as ref_file: + ref_file.write(f"\n{name}={commit_id}") + diff --git a/project/checkout.py b/project/checkout.py index 0fe1efb..efc56a3 100644 --- a/project/checkout.py +++ b/project/checkout.py @@ -2,7 +2,7 @@ from pathlib import Path from typing import Union -from project.errors import BranchDoesntExistError, FilesDoesntMatchError, WitError +from project.errors import BranchDoesntExistError, FilesDoNotMatchError, WitError from project.status import ( get_changes_not_staged_for_commit, get_changes_to_be_committed, @@ -20,7 +20,6 @@ def checkout_function(commit_id_or_branch: str) -> None: repository = get_repository_path(Path.cwd()) - staging_area_path = get_staging_area(repository) if not repository: raise WitError("<.wit> file not found") raise_for_unsaved_work(repository) @@ -35,16 +34,17 @@ def checkout_function(commit_id_or_branch: str) -> None: commit_path = get_commit_path(repository, commit_id) update_files_in_main_folder(commit_path, repository) update_head_in_references_file(commit_id, references_file) + staging_area_path = get_staging_area(repository) update_staging_area_folder(staging_area_path, commit_path) def raise_for_unsaved_work(repository: Path) -> None: - files_added_since_last_commit = list(get_changes_to_be_committed(repository)) - changed_files_since_last_commit = list( + files_added_since_last_commit = set(get_changes_to_be_committed(repository)) + changed_files_since_last_commit = set( get_changes_not_staged_for_commit(repository) ) if files_added_since_last_commit or changed_files_since_last_commit: - raise FilesDoesntMatchError( + raise FilesDoNotMatchError( "There are files added or changed since last commit_function" ) diff --git a/project/errors.py b/project/errors.py index fb2f4e8..ed0a65a 100644 --- a/project/errors.py +++ b/project/errors.py @@ -2,7 +2,7 @@ class WitError(Exception): pass -class FilesDoesntMatchError(WitError): +class FilesDoNotMatchError(WitError): pass diff --git a/tests/test_branch.py b/tests/test_branch.py index ebd44d6..75643d1 100644 --- a/tests/test_branch.py +++ b/tests/test_branch.py @@ -1,10 +1,14 @@ import os +import shutil import pytest +from project.add import add_function from project.branch import branch_function +from project.commit import commit_function from project.errors import WitError, BranchExistsError -from project.utils import get_references_path, get_head_reference +from project.init import init_function +from project.utils import get_references_path, get_head_reference, get_wit_dir def test_raise_error(tmp_path): @@ -15,10 +19,14 @@ def test_raise_error(tmp_path): def test_branch_function(test_folder): # fail os.chdir(test_folder) + file2 = test_folder / "folder1" / "file2.txt" + file2.write_text("test branch") + add_function(file2) + commit_function("test branch") branch_function("TestBranch") commit_id = get_head_reference(test_folder) references_file = get_references_path(test_folder) - assert f"TestBranch={commit_id}" in references_file + assert f"TestBranch={commit_id}" in references_file.read_text() def test_branch_exists_error(test_folder): # fail diff --git a/tests/test_checkout.py b/tests/test_checkout.py new file mode 100644 index 0000000..37b0301 --- /dev/null +++ b/tests/test_checkout.py @@ -0,0 +1,63 @@ +import os +import random + +import pytest + +from project.add import add_function +from project.branch import branch_function +from project.checkout import checkout_function +from project.commit import commit_function +from project.errors import WitError, BranchDoesntExistError, FilesDoNotMatchError +from project.utils import get_activated_branch, get_commit_id_of_branch, get_references_path, get_activated_path, \ + get_head_reference + + +def test_raise_wit_error(tmp_path): + os.chdir(tmp_path) + with pytest.raises(WitError): + checkout_function("branch") + + +def test_raise_branch_doesnt_exist_error(test_folder): + os.chdir(test_folder) + commit_function("") + with pytest.raises(BranchDoesntExistError): + checkout_function("branch") + +# checkout id +def test_raise_files_do_not_match_error_changed(test_folder): + branch_function("branch") + checkout_function("branch") + file1 = test_folder / "file1.txt" + file1.write_text("FilesDoNotMatchError1") + with pytest.raises(FilesDoNotMatchError): + checkout_function("master") + + +def test_raise_files_do_not_match_error_added(test_folder): + file1 = test_folder / "file1.txt" + add_function(file1) + with pytest.raises(FilesDoNotMatchError): + checkout_function("master") + + +def test_checkout_function(test_folder): + commit_function("") + checkout_function("master") + file1 = test_folder / "file1.txt" + assert get_activated_branch(test_folder) == "master" + assert file1.read_text() != "FilesDoNotMatchError1" + + +def test_checkout_id(test_folder): + file1 = test_folder / "file1.txt" + add_function(file1) + commit_function("") + test_id = get_head_reference(test_folder) + file2 = test_folder / "folder1" / "file2.txt" + add_function(file2) + commit_function(file2) + checkout_function(test_id) + activated_branch = get_activated_branch(test_folder) + assert not activated_branch + checkout_function("master") From 484bd0c2f8e69a8a93a832e44c63b013014dc920 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Wed, 23 Mar 2022 10:32:19 +0200 Subject: [PATCH 55/73] finished tests: branch, checkout, commit, graph --- .coverage | Bin 53248 -> 53248 bytes project/checkout.py | 2 +- project/merge.py | 2 +- project/utils.py | 13 ++++++++++--- tests/test_branch.py | 22 ++++++++++------------ tests/test_checkout.py | 23 +++++++++++++++-------- tests/test_commit.py | 2 +- tests/test_graph.py | 25 ++++++++++++++++--------- 8 files changed, 54 insertions(+), 35 deletions(-) diff --git a/.coverage b/.coverage index 21590ed2ff20db3a31dc26b6dc7e12744b8eaf59..431aa51da8e5939a084a86b04f0a041da53b640d 100644 GIT binary patch delta 188 zcmZozz}&Eac|(;xhoOO$k)@Tf(dH)omH>@+4E#U&-}67`zsrA#e;@y5{$>2L_$TmJ z@n`Xe^Skm}@@w%+@%`j`x7o1aHJ=fBl|NlRe&np1r%Lu%Z|M2Jk z&&ihk+7fm53hn-%|INh515(NJ>iFlMpMU;*UOBnCU)}K4=RZGXxH*6_5*%js@&7)v obFu?DBJ8jJykQn%12Wav_I*4*|GfSD&yEafX=$4;_3JqR0I&o|o&W#< delta 189 zcmZozz}&Eac|(;xhk=2Wv4NF=$>t{gmH>^94E#U&-}67`zsrA#e?R{g{^k6$`6u#M z^XKqK^1Jg}^Xu}<^8MlaxLHu(FyG{NecG}te1a^DoN|Ke8Xy1H|Ns9?K92y9FC}oz z{=v`xlg<0J#cS>r+WkNOn~9ePC?Ught^fJw=bt~zPp;}$H@J5GvpqXE2T($S!^}SZ p-)DACb|6QD{nej0%z|t{rV87>kLRb?+dXe)ICJLA=1cv04gfRrM#umF diff --git a/project/checkout.py b/project/checkout.py index efc56a3..815eb3a 100644 --- a/project/checkout.py +++ b/project/checkout.py @@ -24,7 +24,7 @@ def checkout_function(commit_id_or_branch: str) -> None: raise WitError("<.wit> file not found") raise_for_unsaved_work(repository) references_file = get_references_path(repository) - commit_id = get_commit_id_of_branch(commit_id_or_branch, references_file) + commit_id = get_commit_id_of_branch(repository, commit_id_or_branch, references_file) if not commit_id: raise BranchDoesntExistError("Branch doesn't exist.") if commit_id != commit_id_or_branch: diff --git a/project/merge.py b/project/merge.py index 00c6f9b..b4ea21e 100644 --- a/project/merge.py +++ b/project/merge.py @@ -32,7 +32,7 @@ def merge_function(branch_name: str) -> None: staging_area_path = get_staging_area(repository) references_file = get_references_path(repository) head_reference = get_head_reference(repository) - branch_commit_id = get_commit_id_of_branch(branch_name, references_file) + branch_commit_id = get_commit_id_of_branch(repository, branch_name, references_file) raise_for_unsaved_work(repository) if branch_commit_id == head_reference: raise MergeError("Head is already at the branch you are trying to merge.") diff --git a/project/utils.py b/project/utils.py index d623600..0b3da25 100644 --- a/project/utils.py +++ b/project/utils.py @@ -19,15 +19,22 @@ def get_repository_path(path: Path) -> Optional[Path]: return None -def get_commit_id_of_branch(branch: str, references_file: Path) -> str: +def get_commit_id_of_branch(repository: Path, branch: str, references_file: Path) -> str: branches_commits_dict = get_branches_commits(references_file) if branch in branches_commits_dict: return branches_commits_dict[branch] - if branch in branches_commits_dict.values(): + if branch in list(get_all_commits(repository)): return branch return "" +def get_all_commits(repository: Path) -> Iterator[str]: + images_path = get_images_path(repository) + for file_name in images_path.iterdir(): + if file_name.is_dir(): + yield file_name.name + + def get_branches_commits(references_file: Path) -> dict[str, str]: with references_file.open() as file: branches_data = file.read() @@ -41,7 +48,7 @@ def get_branches_commits(references_file: Path) -> dict[str, str]: def get_head_reference(repository: Path) -> str: references_file = get_references_path(repository) if references_file.exists(): - return get_commit_id_of_branch("HEAD", references_file) + return get_commit_id_of_branch(repository, "HEAD", references_file) return "" diff --git a/tests/test_branch.py b/tests/test_branch.py index 75643d1..c438805 100644 --- a/tests/test_branch.py +++ b/tests/test_branch.py @@ -1,5 +1,4 @@ import os -import shutil import pytest @@ -7,7 +6,6 @@ from project.branch import branch_function from project.commit import commit_function from project.errors import WitError, BranchExistsError -from project.init import init_function from project.utils import get_references_path, get_head_reference, get_wit_dir @@ -17,22 +15,22 @@ def test_raise_error(tmp_path): branch_function("") -def test_branch_function(test_folder): # fail +def test_branch_function(test_folder): os.chdir(test_folder) - file2 = test_folder / "folder1" / "file2.txt" - file2.write_text("test branch") - add_function(file2) - commit_function("test branch") + change_add_and_commit_file2(test_folder) branch_function("TestBranch") commit_id = get_head_reference(test_folder) references_file = get_references_path(test_folder) assert f"TestBranch={commit_id}" in references_file.read_text() -def test_branch_exists_error(test_folder): # fail - with pytest.raises(BranchExistsError): - branch_function("TestBranch") +def change_add_and_commit_file2(test_folder): + file2 = test_folder / "folder1" / "file2.txt" + file2.write_text("test branch") + add_function(file2) + commit_function("test branch") -# TODO: test if no commit was done yet. -# test second branch. +def test_branch_exists_error(test_folder): + with pytest.raises(BranchExistsError): + branch_function("TestBranch") diff --git a/tests/test_checkout.py b/tests/test_checkout.py index 37b0301..b5f7283 100644 --- a/tests/test_checkout.py +++ b/tests/test_checkout.py @@ -1,5 +1,4 @@ import os -import random import pytest @@ -24,7 +23,7 @@ def test_raise_branch_doesnt_exist_error(test_folder): with pytest.raises(BranchDoesntExistError): checkout_function("branch") -# checkout id + def test_raise_files_do_not_match_error_changed(test_folder): branch_function("branch") checkout_function("branch") @@ -50,14 +49,22 @@ def test_checkout_function(test_folder): def test_checkout_id(test_folder): - file1 = test_folder / "file1.txt" - add_function(file1) - commit_function("") + add_and_commit_file1(test_folder) test_id = get_head_reference(test_folder) - file2 = test_folder / "folder1" / "file2.txt" - add_function(file2) - commit_function(file2) + add_and_commit_file2(test_folder) checkout_function(test_id) activated_branch = get_activated_branch(test_folder) assert not activated_branch checkout_function("master") + + +def add_and_commit_file2(test_folder): + file2 = test_folder / "folder1" / "file2.txt" + add_function(file2) + commit_function(file2) + + +def add_and_commit_file1(test_folder): + file1 = test_folder / "file1.txt" + add_function(file1) + commit_function("") diff --git a/tests/test_commit.py b/tests/test_commit.py index 57465d1..d866837 100644 --- a/tests/test_commit.py +++ b/tests/test_commit.py @@ -31,5 +31,5 @@ def test_second_commit(test_folder): commit_function("test second commit") references_path = get_references_path(test_folder) assert get_head_reference(test_folder) == get_commit_id_of_branch( - "master", references_path + test_folder, "master", references_path ) diff --git a/tests/test_graph.py b/tests/test_graph.py index 8b7b22b..0770652 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -1,5 +1,4 @@ import os -from pathlib import Path import pytest @@ -9,12 +8,11 @@ from project.commit import commit_function from project.errors import WitError from project.graph import graph_function -from project.merge import merge_function +from project.merge import merge_function, get_parents_commits from project.utils import ( - get_branches_commits, get_head_reference, get_references_path, - get_wit_dir, + get_wit_dir, get_commit_id_of_branch, ) @@ -28,24 +26,33 @@ def test_graph_function(test_folder): os.chdir(test_folder) create_branch_and_checkout("branch1") change_add_and_commit_file3(test_folder) + references_file = get_references_path(test_folder) checkout_function("master") + branch_commit_id = get_commit_id_of_branch(test_folder, "branch1", references_file) merge_function("branch1") dot_source = graph_function(test=True) current_commit_id = get_head_reference(test_folder) wit_dir = get_wit_dir(test_folder) - references_file = get_references_path(test_folder) + commits_in_graph = get_commits_in_graph(branch_commit_id, current_commit_id, test_folder) assert wit_dir / f"Graph_{current_commit_id}.pdf" in set(wit_dir.iterdir()) - for commit in get_branches_commits(references_file).values(): + for commit in commits_in_graph: assert commit in dot_source -def create_branch_and_checkout(branch_name: str) -> None: +def get_commits_in_graph(branch_commit_id, current_commit_id, test_folder): + parents_commits_of_branch = set(get_parents_commits(test_folder, branch_commit_id)) + parents_commits_of_master = set(get_parents_commits(test_folder, current_commit_id)) + commits_in_graph = parents_commits_of_branch.union(parents_commits_of_master) + return commits_in_graph + + +def create_branch_and_checkout(branch_name): branch_function(branch_name) checkout_function(branch_name) -def change_add_and_commit_file3(test_folder: Path) -> None: +def change_add_and_commit_file3(test_folder): file3 = test_folder / r"folder1\folder2\file3.txt" file3.write_text("1") - add_function(str(file3)) + add_function(file3) commit_function("add file3") From fbdcc6da234f462b851313e9f7f34f9eb71af62b Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Wed, 23 Mar 2022 11:04:26 +0200 Subject: [PATCH 56/73] add test_merge, fix raise-merge-error in merge --- .coverage | Bin 53248 -> 53248 bytes project/merge.py | 14 +++++++------- tests/test_merge.py | 23 +++++++++++++++++++++++ 3 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 tests/test_merge.py diff --git a/.coverage b/.coverage index 431aa51da8e5939a084a86b04f0a041da53b640d..749f8eae740aba3d96c317ca5e32f36fde21f69f 100644 GIT binary patch delta 215 zcmZozz}&Eac|)x}tBIMFsqy9}{U!ls5pI#m><;Qo+#;I=1)gv**^5jT^fBklO)W}K z)hnp96J}v(WSl(FPh+yZFZbp??=lvk7SYM<0YELHKrK(XCSQ!v1xdp7h}g3mF^;d?rny+NIc?=QkSw0CeL#pa1{> delta 154 zcmZozz}&Eac|)x}tC6LZvC-xx{U!lsVeZh$><;Ri1qIZ(+3bW_7#bNTPxRB6Z12mx zxzD?d1*jlwGJ60>fd)6LJxe1al6-WT3bQcZyUFYgAo&A)Vw}P(jGQ9EuNvmF%L@US r4nq6b4-`&j>DOob@aO-}IsB6?`%g0q^Vd#hp8(S0&%e2LezO4p>$xq; diff --git a/project/merge.py b/project/merge.py index b4ea21e..2f5a71c 100644 --- a/project/merge.py +++ b/project/merge.py @@ -29,13 +29,13 @@ def merge_function(branch_name: str) -> None: repository = get_repository_path(Path.cwd()) if not repository: raise WitError("<.wit> file not found") - staging_area_path = get_staging_area(repository) + activated = get_activated_branch(repository) + if branch_name == activated: + raise MergeError("Head is already at the branch you are trying to merge.") references_file = get_references_path(repository) head_reference = get_head_reference(repository) branch_commit_id = get_commit_id_of_branch(repository, branch_name, references_file) raise_for_unsaved_work(repository) - if branch_commit_id == head_reference: - raise MergeError("Head is already at the branch you are trying to merge.") common_commit = get_common_commit(repository, branch_commit_id, head_reference) if not common_commit: raise NoCommonCommitError(f"There is no common commit with {branch_name}.") @@ -43,10 +43,10 @@ def merge_function(branch_name: str) -> None: branch_dir = get_commit_path(repository, branch_commit_id) branch_files, common_files = get_common_and_branch_files(branch_dir, common_dir) check_common_commit_and_update_staging_area_and_repository( - branch_dir, common_dir, common_files, staging_area_path, repository + branch_dir, common_dir, common_files, repository ) check_branch_and_update_staging_area_and_repository( - branch_dir, branch_files, common_dir, staging_area_path, repository + branch_dir, branch_files, common_dir, repository ) commit_merge(branch_commit_id, branch_name, head_reference, repository) @@ -55,9 +55,9 @@ def check_branch_and_update_staging_area_and_repository( branch_dir: Path, branch_files: Iterator[Path], common_dir: Path, - staging_area_path: Path, repository: Path, ) -> None: + staging_area_path = get_staging_area(repository) for file_path in branch_files: ( path_in_branch, @@ -77,9 +77,9 @@ def check_common_commit_and_update_staging_area_and_repository( branch_dir: Path, common_dir: Path, common_files: Iterator[Path], - staging_area_path: Path, repository: Path, ) -> None: + staging_area_path = get_staging_area(repository) for file_path in common_files: ( path_in_branch, diff --git a/tests/test_merge.py b/tests/test_merge.py new file mode 100644 index 0000000..b6dda15 --- /dev/null +++ b/tests/test_merge.py @@ -0,0 +1,23 @@ +import os + +import pytest + +from project.errors import WitError +from project.merge import merge_function + + +def test_raise_error(tmp_path): + os.chdir(tmp_path) + test_file = tmp_path / "test.txt" + test_file.write_text("") + with pytest.raises(WitError): + merge_function("") + + +# on master. +# new branch > change file > checkout master > merge new branch +# assert file has changed + +# on master. +# new branch > change file > checkout master > change file > merge new branch +# assert: raise NotImplementedError - f"{file_path} was changed in both branches. Not implemented yet." From a3413de140309c8e684c2697cfd4d84ca1f4adea Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Wed, 23 Mar 2022 14:23:58 +0200 Subject: [PATCH 57/73] delete no common commit error pessibility --- .coverage | Bin 53248 -> 53248 bytes project/errors.py | 3 --- project/merge.py | 2 -- tests/test_add.py | 2 +- tests/test_branch.py | 2 +- tests/test_commit.py | 2 +- tests/test_graph.py | 2 +- tests/test_merge.py | 25 ++++++++++++++++++++----- 8 files changed, 24 insertions(+), 14 deletions(-) diff --git a/.coverage b/.coverage index 749f8eae740aba3d96c317ca5e32f36fde21f69f..311058a7d4b1b60df67173495ea412eacc06e563 100644 GIT binary patch delta 57 zcmZozz}&Eac|)~6yP=hVnU$&K<|h4?0LCYi*&8$%pKKNs*uuxfA;QAQDI}6rCpYu9RL>K69NDL delta 56 zcmZozz}&Eac|)~6yMdL7nU$&W<|h4?0LG`2*&8$%pKcZu*viMrF2cgdDIk(nH~C$k M7~}rUto^?o00vnSpa1{> diff --git a/project/errors.py b/project/errors.py index ed0a65a..c06d4ec 100644 --- a/project/errors.py +++ b/project/errors.py @@ -21,6 +21,3 @@ class WitExistsError(WitError): class MergeError(WitError): pass - -class NoCommonCommitError(WitError): - pass diff --git a/project/merge.py b/project/merge.py index 2f5a71c..ad075ae 100644 --- a/project/merge.py +++ b/project/merge.py @@ -37,8 +37,6 @@ def merge_function(branch_name: str) -> None: branch_commit_id = get_commit_id_of_branch(repository, branch_name, references_file) raise_for_unsaved_work(repository) common_commit = get_common_commit(repository, branch_commit_id, head_reference) - if not common_commit: - raise NoCommonCommitError(f"There is no common commit with {branch_name}.") common_dir = get_commit_path(repository, common_commit) branch_dir = get_commit_path(repository, branch_commit_id) branch_files, common_files = get_common_and_branch_files(branch_dir, common_dir) diff --git a/tests/test_add.py b/tests/test_add.py index ccb4583..66998a8 100644 --- a/tests/test_add.py +++ b/tests/test_add.py @@ -7,7 +7,7 @@ from project.utils import get_staging_area -def test_raise_error(tmp_path): +def test_raise_wit_error(tmp_path): os.chdir(tmp_path) test_file = tmp_path / "test.txt" test_file.write_text("") diff --git a/tests/test_branch.py b/tests/test_branch.py index c438805..cc75d5b 100644 --- a/tests/test_branch.py +++ b/tests/test_branch.py @@ -9,7 +9,7 @@ from project.utils import get_references_path, get_head_reference, get_wit_dir -def test_raise_error(tmp_path): +def test_raise_wit_error(tmp_path): os.chdir(tmp_path) with pytest.raises(WitError): branch_function("") diff --git a/tests/test_commit.py b/tests/test_commit.py index d866837..6dd7dc4 100644 --- a/tests/test_commit.py +++ b/tests/test_commit.py @@ -12,7 +12,7 @@ ) -def test_raise_error(tmp_path): +def test_raise_wit_error(tmp_path): os.chdir(tmp_path) with pytest.raises(WitError): commit_function("") diff --git a/tests/test_graph.py b/tests/test_graph.py index 0770652..c39b42a 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -16,7 +16,7 @@ ) -def test_raise_error(tmp_path, test_folder): +def test_raise_wit_error(tmp_path, test_folder): os.chdir(tmp_path) with pytest.raises(WitError): graph_function() diff --git a/tests/test_merge.py b/tests/test_merge.py index b6dda15..074971e 100644 --- a/tests/test_merge.py +++ b/tests/test_merge.py @@ -2,11 +2,13 @@ import pytest -from project.errors import WitError +from project.branch import branch_function +from project.checkout import checkout_function +from project.errors import WitError, MergeError from project.merge import merge_function -def test_raise_error(tmp_path): +def test_raise_wit_error(tmp_path): os.chdir(tmp_path) test_file = tmp_path / "test.txt" test_file.write_text("") @@ -14,10 +16,23 @@ def test_raise_error(tmp_path): merge_function("") -# on master. -# new branch > change file > checkout master > merge new branch -# assert file has changed +def test_raise_merge_error(test_folder): + os.chdir(test_folder) + with pytest.raises(MergeError): + merge_function("master") # on master. # new branch > change file > checkout master > change file > merge new branch # assert: raise NotImplementedError - f"{file_path} was changed in both branches. Not implemented yet." +def test_raise_changed_file_error(test_folder): + branch_function("TestChanged") + checkout_function("TestChanged") + file1 = test_folder / "file1.txt" + file1.write_text() + folder1 = test_folder / "folder1" + + + +# on master. +# new branch > change file > checkout master > change another file > checkout branch > merge master +# assert both files has changed From 629f796606b6718fc68ed3181ff06d4253868b1a Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Wed, 23 Mar 2022 15:56:43 +0200 Subject: [PATCH 58/73] done: test_merge --- .coverage | Bin 53248 -> 53248 bytes project/merge.py | 2 +- tests/conftest.py | 8 ++++++++ tests/test_branch.py | 15 ++++----------- tests/test_checkout.py | 22 ++++++---------------- tests/test_merge.py | 38 +++++++++++++++++++++++++++++--------- 6 files changed, 48 insertions(+), 37 deletions(-) diff --git a/.coverage b/.coverage index 311058a7d4b1b60df67173495ea412eacc06e563..e805cc413fb464a0d586e0ecb5a5a6860991643c 100644 GIT binary patch delta 495 zcmZozz}&Eac|)~6yQ!6_p_QT0<|h4K0d5YyQ+&OA{(Qo`S2s&J6!7vV6(!~+XXq7F zI&iTtG_p>f=%+FHzpn_B4d>(lKO0sn4rYdGpr8RuW?p8=WN$x%$p?Hn*pl;ebAjAW zzdBY+7G{P@kP7C+l$6O1{-@OVIeEi)F7gHNo#wvGC&E3AXEI+O|6%@C-fO&5c!hWZ zc?7t_xJ5S$3Owc7EE-+P#07T)_vFAB3j~*IvVWW{E2lMcH6xM};!vFsSI=U_TnSbH za=~VY_+tuM4;c7=^1tJM#($IlJpXR~rTnw`C-ArOSM%raNAkP#Tl4Gi%kcf?`@r`A z=!^|~0(>GYjGS^Jug;%8{Jr7-fA-1m`ou-=fBG-}=l@Z8`~UyX{{Q@$`A6-X|NN7s z`UC2Dd4S4gcwU|V{PXkApYj~sK&}wC)QA6^TtJox*Q?5ZmYkd*Cg-a^ZEnKL0nQZ*!F!qKmWY_{LhXIX=!O3tROwCKo&O( kkR`!lW*`6WGdmkIki*Nz%*4qAWQZ`m`ZIs?kA4mZ0L?n5mjD0& delta 494 zcmZozz}&Eac|)~6yP=hVnU$&K<|h4K0d97_lYBjVetg2b7dJ~e6!3B<=jY~Tmgp5! z+Hg${^fR8^<;%s&$->acI{Cbx#$DX8A_mNfDJheE{0u-cV0M>Z z9jg@!Geb2;)iYZ&SA*oh4%qAve@sE^2?PI6{`dUP`S0>y;@`)=nSUAoEdB}nRs31};ry=r zmi$`$QhY!8-tj#Fx?&3-7l#N7Bd3r^R-N4B4}IdIwWt5bfA}w6|L2eWv;RMTGX7yZ z_n&>TOn*Q<9}iHW9M7xcpMQS-`SW?D2sedzZyAvPdWjcwn@^YhQ!&;RVm rkd~Il$qJHY1+v&USb$6+7NB8l%=|zmA2SmN6G(_j>;L8-{TvPe|F5HZ diff --git a/project/merge.py b/project/merge.py index ad075ae..6924e07 100644 --- a/project/merge.py +++ b/project/merge.py @@ -6,7 +6,7 @@ from project.checkout import raise_for_unsaved_work from project.commit import commit_function -from project.errors import MergeError, NoCommonCommitError, WitError +from project.errors import MergeError, WitError from project.utils import ( get_activated_branch, get_all_files_in_directory_and_subs, diff --git a/tests/conftest.py b/tests/conftest.py index b758333..bdf7af2 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,6 +2,8 @@ import pytest +from project.add import add_function +from project.commit import commit_function from project.init import init_function @@ -16,3 +18,9 @@ def test_folder(tmp_path_factory): os.chdir(test_folder) init_function() return test_folder + + +def change_add_and_commit_file(file_path, txt): + file_path.write_text(txt) + add_function(file_path) + commit_function("") diff --git a/tests/test_branch.py b/tests/test_branch.py index cc75d5b..2bf10fd 100644 --- a/tests/test_branch.py +++ b/tests/test_branch.py @@ -2,11 +2,10 @@ import pytest -from project.add import add_function from project.branch import branch_function -from project.commit import commit_function from project.errors import WitError, BranchExistsError -from project.utils import get_references_path, get_head_reference, get_wit_dir +from project.utils import get_references_path, get_head_reference +from tests.conftest import change_add_and_commit_file def test_raise_wit_error(tmp_path): @@ -17,20 +16,14 @@ def test_raise_wit_error(tmp_path): def test_branch_function(test_folder): os.chdir(test_folder) - change_add_and_commit_file2(test_folder) + file2 = test_folder / "folder1" / "file2.txt" + change_add_and_commit_file(file2, "test branch") branch_function("TestBranch") commit_id = get_head_reference(test_folder) references_file = get_references_path(test_folder) assert f"TestBranch={commit_id}" in references_file.read_text() -def change_add_and_commit_file2(test_folder): - file2 = test_folder / "folder1" / "file2.txt" - file2.write_text("test branch") - add_function(file2) - commit_function("test branch") - - def test_branch_exists_error(test_folder): with pytest.raises(BranchExistsError): branch_function("TestBranch") diff --git a/tests/test_checkout.py b/tests/test_checkout.py index b5f7283..78b4e34 100644 --- a/tests/test_checkout.py +++ b/tests/test_checkout.py @@ -7,8 +7,8 @@ from project.checkout import checkout_function from project.commit import commit_function from project.errors import WitError, BranchDoesntExistError, FilesDoNotMatchError -from project.utils import get_activated_branch, get_commit_id_of_branch, get_references_path, get_activated_path, \ - get_head_reference +from project.utils import get_activated_branch, get_head_reference +from tests.conftest import change_add_and_commit_file def test_raise_wit_error(tmp_path): @@ -49,22 +49,12 @@ def test_checkout_function(test_folder): def test_checkout_id(test_folder): - add_and_commit_file1(test_folder) + file1 = test_folder / "file1.txt" + change_add_and_commit_file(file1, "") test_id = get_head_reference(test_folder) - add_and_commit_file2(test_folder) + file2 = test_folder / "folder1" / "file2.txt" + change_add_and_commit_file(file2, "") checkout_function(test_id) activated_branch = get_activated_branch(test_folder) assert not activated_branch checkout_function("master") - - -def add_and_commit_file2(test_folder): - file2 = test_folder / "folder1" / "file2.txt" - add_function(file2) - commit_function(file2) - - -def add_and_commit_file1(test_folder): - file1 = test_folder / "file1.txt" - add_function(file1) - commit_function("") diff --git a/tests/test_merge.py b/tests/test_merge.py index 074971e..2eb880a 100644 --- a/tests/test_merge.py +++ b/tests/test_merge.py @@ -4,8 +4,10 @@ from project.branch import branch_function from project.checkout import checkout_function +from project.utils import get_staging_area from project.errors import WitError, MergeError from project.merge import merge_function +from tests.conftest import change_add_and_commit_file def test_raise_wit_error(tmp_path): @@ -21,18 +23,36 @@ def test_raise_merge_error(test_folder): with pytest.raises(MergeError): merge_function("master") -# on master. -# new branch > change file > checkout master > change file > merge new branch -# assert: raise NotImplementedError - f"{file_path} was changed in both branches. Not implemented yet." + def test_raise_changed_file_error(test_folder): branch_function("TestChanged") checkout_function("TestChanged") file1 = test_folder / "file1.txt" - file1.write_text() - folder1 = test_folder / "folder1" - + change_add_and_commit_file(file1, "changed") + # folder1 = test_folder / "folder1" + checkout_function("master") + change_add_and_commit_file(file1, "changed again") + with pytest.raises(NotImplementedError): + merge_function("TestChanged") -# on master. -# new branch > change file > checkout master > change another file > checkout branch > merge master -# assert both files has changed +def test_merge_function(test_folder): + file1 = test_folder / "file1.txt" + change_add_and_commit_file(file1, "") # zero + branch_function("TestMerge") + checkout_function("TestMerge") + folder1 = test_folder / "folder1" + new = folder1 / 'new.txt' + change_add_and_commit_file(new, "new") + checkout_function("master") + file1 = test_folder / "file1.txt" + change_add_and_commit_file(file1, "merge") + checkout_function("TestMerge") + merge_function("master") + staging_area_path = get_staging_area(test_folder) + file1_in_staging_area = staging_area_path / "file1.txt" + new_in_staging_area = staging_area_path / "folder1" / 'new.txt' + assert file1.read_text() == "merge" + assert file1_in_staging_area.read_text() == "merge" + assert new.read_text() == "new" + assert new_in_staging_area.read_text() == "new" From 09ec3c571fd7ca5d88d270ed3c05176463146b65 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Wed, 23 Mar 2022 23:12:25 +0200 Subject: [PATCH 59/73] done: test_status. adjust also other files --- .coverage | Bin 53248 -> 53248 bytes project/add.py | 3 ++- project/graph.py | 4 ++-- project/status.py | 6 ++++-- tests/test_graph.py | 2 +- tests/test_merge.py | 28 ++++++++++++++++++++-------- tests/test_status.py | 24 ++++++++++++++++++++++++ 7 files changed, 53 insertions(+), 14 deletions(-) create mode 100644 tests/test_status.py diff --git a/.coverage b/.coverage index e805cc413fb464a0d586e0ecb5a5a6860991643c..ed1e4de7c2f3dbdac554f633f081f2cbb93e1efb 100644 GIT binary patch delta 305 zcmZozz}&Eac|(;xhmom>lHZNrieH;wn(r6i zd%pX8SAga%;*;hSWnttL5q)LzpOH@l$dnU#HUIg~^Z)<DLw(F;mc$A|M%JFhjX7F|H(W#vcFK~Ab(m~8V4&-Qiv7E;${J|Bv|t5 p_WgOzKlxd|9J45Y{$%zEnoRupK#Ohp+1Y>!7)3=lm(A}o001KlW*-0m delta 238 zcmZozz}&Eac|(;xhoPyJsiBpj(dH)oCIMy%E-? zC?PtTJpd%}lxy None: +def add_function(path_to_add: Union[str, Path]) -> None: path = Path(path_to_add).resolve() repository = get_repository_path(path) if not repository: diff --git a/project/graph.py b/project/graph.py index a750e97..37aeabc 100644 --- a/project/graph.py +++ b/project/graph.py @@ -18,7 +18,7 @@ ) -def graph_function(test: bool = False) -> Optional[str]: +def graph_function() -> Optional[str]: repository = get_repository_path(Path.cwd()) if not repository: raise WitError("<.wit> file not found") @@ -34,7 +34,7 @@ def graph_function(test: bool = False) -> Optional[str]: view=True, cleanup=True, ) - return dot.source if test else None + return dot.source def create_nodes(commit_id: str, dot: Digraph, images_path: Path) -> None: diff --git a/project/status.py b/project/status.py index 3bbe88f..b6766bf 100644 --- a/project/status.py +++ b/project/status.py @@ -13,7 +13,7 @@ ) -def status_function() -> None: +def status_function() -> tuple[Iterator[Path], Iterator[Path], Iterator[Path]]: repository = get_repository_path(Path.cwd()) if not repository: raise WitError("<.wit> file not found") @@ -24,12 +24,14 @@ def status_function() -> None: get_changes_not_staged_for_commit(repository) ) untracked_files = show_files(get_untracked_files(repository)) - print( + output = ( f"###Commit id:###\n{last_commit_id if last_commit_id else message_if_no_commit}\n\n" f"###Changes to be committed:###\n{changes_to_be_committed}\n\n" f"###Changes not staged for commit:###\n{changes_not_staged_for_commit}\n\n" f"###Untracked files:###\n{untracked_files}\n" ) + print(output) + return get_changes_to_be_committed(repository), get_changes_not_staged_for_commit(repository), get_untracked_files(repository) def show_files(files: Iterator[Path]) -> str: diff --git a/tests/test_graph.py b/tests/test_graph.py index c39b42a..45cfc8c 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -30,7 +30,7 @@ def test_graph_function(test_folder): checkout_function("master") branch_commit_id = get_commit_id_of_branch(test_folder, "branch1", references_file) merge_function("branch1") - dot_source = graph_function(test=True) + dot_source = graph_function() current_commit_id = get_head_reference(test_folder) wit_dir = get_wit_dir(test_folder) commits_in_graph = get_commits_in_graph(branch_commit_id, current_commit_id, test_folder) diff --git a/tests/test_merge.py b/tests/test_merge.py index 2eb880a..cb21e1c 100644 --- a/tests/test_merge.py +++ b/tests/test_merge.py @@ -2,9 +2,11 @@ import pytest +from project.add import add_function from project.branch import branch_function from project.checkout import checkout_function -from project.utils import get_staging_area +from project.commit import commit_function +from project.utils import get_staging_area, get_all_files_in_repository_and_subs from project.errors import WitError, MergeError from project.merge import merge_function from tests.conftest import change_add_and_commit_file @@ -12,8 +14,6 @@ def test_raise_wit_error(tmp_path): os.chdir(tmp_path) - test_file = tmp_path / "test.txt" - test_file.write_text("") with pytest.raises(WitError): merge_function("") @@ -29,7 +29,6 @@ def test_raise_changed_file_error(test_folder): checkout_function("TestChanged") file1 = test_folder / "file1.txt" change_add_and_commit_file(file1, "changed") - # folder1 = test_folder / "folder1" checkout_function("master") change_add_and_commit_file(file1, "changed again") with pytest.raises(NotImplementedError): @@ -37,13 +36,11 @@ def test_raise_changed_file_error(test_folder): def test_merge_function(test_folder): - file1 = test_folder / "file1.txt" - change_add_and_commit_file(file1, "") # zero + reset_files_in_repo(test_folder) branch_function("TestMerge") checkout_function("TestMerge") folder1 = test_folder / "folder1" - new = folder1 / 'new.txt' - change_add_and_commit_file(new, "new") + new = add_new_file_and_commit(folder1) checkout_function("master") file1 = test_folder / "file1.txt" change_add_and_commit_file(file1, "merge") @@ -56,3 +53,18 @@ def test_merge_function(test_folder): assert file1_in_staging_area.read_text() == "merge" assert new.read_text() == "new" assert new_in_staging_area.read_text() == "new" + checkout_function("master") + + +def reset_files_in_repo(test_folder): + files_in_repo = get_all_files_in_repository_and_subs(test_folder) + for file_path in files_in_repo: + file_path.write_text("") + add_function(file_path) + commit_function("") + + +def add_new_file_and_commit(folder): + new = folder / 'new.txt' + change_add_and_commit_file(new, "new") + return new diff --git a/tests/test_status.py b/tests/test_status.py new file mode 100644 index 0000000..d7c62d3 --- /dev/null +++ b/tests/test_status.py @@ -0,0 +1,24 @@ +import os + +import pytest + +from project.errors import WitError +from project.status import status_function +from project.utils import get_all_files_in_directory_and_subs, get_all_files_in_repository_and_subs, get_staging_area + + +def test_raise_wit_error(tmp_path): + os.chdir(tmp_path) + with pytest.raises(WitError): + status_function() + + +def test_status(test_folder): + os.chdir(test_folder) + changes_to_be_committed, changes_not_staged_for_commit, untracked_files = status_function() + assert not list(changes_to_be_committed) + assert not list(changes_not_staged_for_commit) + staging_area = get_staging_area(test_folder) + all_files = get_all_files_in_repository_and_subs(test_folder) + files_in_staging_area = get_all_files_in_directory_and_subs(staging_area) + assert set(untracked_files).union(set(files_in_staging_area)) == set(all_files) From b34ad5ff159ecc07d87e76f69d7b5f8b769a5fc5 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Wed, 23 Mar 2022 23:54:46 +0200 Subject: [PATCH 60/73] isort & black --- .coverage | Bin 53248 -> 53248 bytes project/branch.py | 1 - project/checkout.py | 8 ++++---- project/errors.py | 1 - project/status.py | 6 +++++- project/utils.py | 4 +++- tests/test_branch.py | 4 ++-- tests/test_checkout.py | 2 +- tests/test_graph.py | 9 ++++++--- tests/test_merge.py | 8 ++++---- tests/test_status.py | 12 ++++++++++-- 11 files changed, 35 insertions(+), 20 deletions(-) diff --git a/.coverage b/.coverage index ed1e4de7c2f3dbdac554f633f081f2cbb93e1efb..756a5cffa6d351d2352f6d636897828893e31a84 100644 GIT binary patch delta 32 ocmZozz}&Eac|)x}tBHY?vEk+>{fqHzAJ2V${D*OKWdCvp0Mn%oSO5S3 delta 32 ocmZozz}&Eac|)x}tAV+dq4DM>{fqHz59dBV{*!rgWdCvp0MG9Y@c;k- diff --git a/project/branch.py b/project/branch.py index b13cc98..3f36029 100644 --- a/project/branch.py +++ b/project/branch.py @@ -21,4 +21,3 @@ def branch_function(name: str) -> None: commit_id = get_head_reference(repository) with references_file.open("a") as ref_file: ref_file.write(f"\n{name}={commit_id}") - diff --git a/project/checkout.py b/project/checkout.py index 815eb3a..f45b3f5 100644 --- a/project/checkout.py +++ b/project/checkout.py @@ -24,7 +24,9 @@ def checkout_function(commit_id_or_branch: str) -> None: raise WitError("<.wit> file not found") raise_for_unsaved_work(repository) references_file = get_references_path(repository) - commit_id = get_commit_id_of_branch(repository, commit_id_or_branch, references_file) + commit_id = get_commit_id_of_branch( + repository, commit_id_or_branch, references_file + ) if not commit_id: raise BranchDoesntExistError("Branch doesn't exist.") if commit_id != commit_id_or_branch: @@ -40,9 +42,7 @@ def checkout_function(commit_id_or_branch: str) -> None: def raise_for_unsaved_work(repository: Path) -> None: files_added_since_last_commit = set(get_changes_to_be_committed(repository)) - changed_files_since_last_commit = set( - get_changes_not_staged_for_commit(repository) - ) + changed_files_since_last_commit = set(get_changes_not_staged_for_commit(repository)) if files_added_since_last_commit or changed_files_since_last_commit: raise FilesDoNotMatchError( "There are files added or changed since last commit_function" diff --git a/project/errors.py b/project/errors.py index c06d4ec..11b9d16 100644 --- a/project/errors.py +++ b/project/errors.py @@ -20,4 +20,3 @@ class WitExistsError(WitError): class MergeError(WitError): pass - diff --git a/project/status.py b/project/status.py index b6766bf..f7f01aa 100644 --- a/project/status.py +++ b/project/status.py @@ -31,7 +31,11 @@ def status_function() -> tuple[Iterator[Path], Iterator[Path], Iterator[Path]]: f"###Untracked files:###\n{untracked_files}\n" ) print(output) - return get_changes_to_be_committed(repository), get_changes_not_staged_for_commit(repository), get_untracked_files(repository) + return ( + get_changes_to_be_committed(repository), + get_changes_not_staged_for_commit(repository), + get_untracked_files(repository), + ) def show_files(files: Iterator[Path]) -> str: diff --git a/project/utils.py b/project/utils.py index 0b3da25..869eefd 100644 --- a/project/utils.py +++ b/project/utils.py @@ -19,7 +19,9 @@ def get_repository_path(path: Path) -> Optional[Path]: return None -def get_commit_id_of_branch(repository: Path, branch: str, references_file: Path) -> str: +def get_commit_id_of_branch( + repository: Path, branch: str, references_file: Path +) -> str: branches_commits_dict = get_branches_commits(references_file) if branch in branches_commits_dict: return branches_commits_dict[branch] diff --git a/tests/test_branch.py b/tests/test_branch.py index 2bf10fd..43e41a6 100644 --- a/tests/test_branch.py +++ b/tests/test_branch.py @@ -3,8 +3,8 @@ import pytest from project.branch import branch_function -from project.errors import WitError, BranchExistsError -from project.utils import get_references_path, get_head_reference +from project.errors import BranchExistsError, WitError +from project.utils import get_head_reference, get_references_path from tests.conftest import change_add_and_commit_file diff --git a/tests/test_checkout.py b/tests/test_checkout.py index 78b4e34..bddecd8 100644 --- a/tests/test_checkout.py +++ b/tests/test_checkout.py @@ -6,7 +6,7 @@ from project.branch import branch_function from project.checkout import checkout_function from project.commit import commit_function -from project.errors import WitError, BranchDoesntExistError, FilesDoNotMatchError +from project.errors import BranchDoesntExistError, FilesDoNotMatchError, WitError from project.utils import get_activated_branch, get_head_reference from tests.conftest import change_add_and_commit_file diff --git a/tests/test_graph.py b/tests/test_graph.py index 45cfc8c..3441736 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -8,11 +8,12 @@ from project.commit import commit_function from project.errors import WitError from project.graph import graph_function -from project.merge import merge_function, get_parents_commits +from project.merge import get_parents_commits, merge_function from project.utils import ( + get_commit_id_of_branch, get_head_reference, get_references_path, - get_wit_dir, get_commit_id_of_branch, + get_wit_dir, ) @@ -33,7 +34,9 @@ def test_graph_function(test_folder): dot_source = graph_function() current_commit_id = get_head_reference(test_folder) wit_dir = get_wit_dir(test_folder) - commits_in_graph = get_commits_in_graph(branch_commit_id, current_commit_id, test_folder) + commits_in_graph = get_commits_in_graph( + branch_commit_id, current_commit_id, test_folder + ) assert wit_dir / f"Graph_{current_commit_id}.pdf" in set(wit_dir.iterdir()) for commit in commits_in_graph: assert commit in dot_source diff --git a/tests/test_merge.py b/tests/test_merge.py index cb21e1c..8cada93 100644 --- a/tests/test_merge.py +++ b/tests/test_merge.py @@ -6,9 +6,9 @@ from project.branch import branch_function from project.checkout import checkout_function from project.commit import commit_function -from project.utils import get_staging_area, get_all_files_in_repository_and_subs -from project.errors import WitError, MergeError +from project.errors import MergeError, WitError from project.merge import merge_function +from project.utils import get_all_files_in_repository_and_subs, get_staging_area from tests.conftest import change_add_and_commit_file @@ -48,7 +48,7 @@ def test_merge_function(test_folder): merge_function("master") staging_area_path = get_staging_area(test_folder) file1_in_staging_area = staging_area_path / "file1.txt" - new_in_staging_area = staging_area_path / "folder1" / 'new.txt' + new_in_staging_area = staging_area_path / "folder1" / "new.txt" assert file1.read_text() == "merge" assert file1_in_staging_area.read_text() == "merge" assert new.read_text() == "new" @@ -65,6 +65,6 @@ def reset_files_in_repo(test_folder): def add_new_file_and_commit(folder): - new = folder / 'new.txt' + new = folder / "new.txt" change_add_and_commit_file(new, "new") return new diff --git a/tests/test_status.py b/tests/test_status.py index d7c62d3..98aaf5f 100644 --- a/tests/test_status.py +++ b/tests/test_status.py @@ -4,7 +4,11 @@ from project.errors import WitError from project.status import status_function -from project.utils import get_all_files_in_directory_and_subs, get_all_files_in_repository_and_subs, get_staging_area +from project.utils import ( + get_all_files_in_directory_and_subs, + get_all_files_in_repository_and_subs, + get_staging_area, +) def test_raise_wit_error(tmp_path): @@ -15,7 +19,11 @@ def test_raise_wit_error(tmp_path): def test_status(test_folder): os.chdir(test_folder) - changes_to_be_committed, changes_not_staged_for_commit, untracked_files = status_function() + ( + changes_to_be_committed, + changes_not_staged_for_commit, + untracked_files, + ) = status_function() assert not list(changes_to_be_committed) assert not list(changes_not_staged_for_commit) staging_area = get_staging_area(test_folder) From 1dda30aee0adf8c33bdb8a01662ae7a2e8f16def Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Thu, 24 Mar 2022 12:33:37 +0200 Subject: [PATCH 61/73] change test_folder --- .coverage | Bin 53248 -> 53248 bytes project/commit.py | 3 ++- tests/conftest.py | 44 ++++++++++++++++++++++++++++++++--------- tests/test_branch.py | 7 ++++--- tests/test_checkout.py | 30 +++++++++++++--------------- tests/test_commit.py | 22 +++++++++------------ tests/test_graph.py | 27 ++++++++----------------- tests/test_merge.py | 35 +++++++++++++++++--------------- tests/test_status.py | 11 ++++++++--- 9 files changed, 99 insertions(+), 80 deletions(-) diff --git a/.coverage b/.coverage index 756a5cffa6d351d2352f6d636897828893e31a84..d1455cfd2923168a170a35d8f6640bbffc118b45 100644 GIT binary patch delta 314 zcmZozz}&Eac|(Ohmx+R*p_QSzm7&q*CjFKGoeK>7KlxwtKjy#2e};cM|3d!h{5|}Q z{N?-^{Gt3#{AT_}=o};k&R|P+%UPESD$?Bd3_?HRtpH?fFH3Yz2{5^Pm3& z^6DA*C%^BLsxSZZ|ERqE|NTGf>;5tC@BeJi$SVj`CnLD7@i8LUXT|g#GA+R;QsHQg?9hX|7POl z0Sd|Ryn4R#=jWf#`8l|OTp@0$5C1v2fGjo$US5UBg{=dKe=j8MMr?U#P z0p&E<_I*5GZ}-3EocR73GiNeRKHo1U&dtUQl;UG%;$Z^PQcSP@$e*)(UbFdUKf40} D2kmW{ delta 327 zcmZozz}&Eac|(Ohm$8D8v6YE|m9gRGCjFKGohuCdKl$JBKjXj2f1ZCg|5Ec#*3KPqqkfB(<=x;lpa{hxu#1VPFK*EK%=umAu5nS5RWAYVq{m3+m& z|25~>x%h!xG5%K#&(AXp@&VZ@e0dE2|33Tt@!aRfe;5UMK|;KFED!$I-7B>FfBrWU zFAvB7o>%8T|NQ*(r#uHYkSoM3_2EA!7Yhf_aa^w||5;A%=~wWa^ZEbr{eMnA|9_fE zhz+Ppjcwn@^YhQ!&;NXoKP@edgB7Hc70BXd0kR}m^6K{edCt$q4CL@JGjTEjX%VJZ Nf9A7q{@Ks&008{}dOH9B diff --git a/project/commit.py b/project/commit.py index a7dcf94..f03f2c4 100644 --- a/project/commit.py +++ b/project/commit.py @@ -20,7 +20,7 @@ CHARS = "1234567890abcdef" -def commit_function(message: str, second_parent: Optional[str] = None) -> None: +def commit_function(message: str, second_parent: Optional[str] = None) -> str: repository = get_repository_path(Path.cwd()) if not repository: raise WitError("<.wit> file not found") @@ -29,6 +29,7 @@ def commit_function(message: str, second_parent: Optional[str] = None) -> None: create_commit_txt_file(repository, new_commit_id, message, second_parent) save_files_in_new_commit(repository, new_commit_id) write_references(new_commit_id, repository) + return new_commit_id def create_commit_folder(new_commit_id: str, repository: Path) -> None: diff --git a/tests/conftest.py b/tests/conftest.py index bdf7af2..f151ed4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -7,20 +7,46 @@ from project.init import init_function -@pytest.fixture(scope="session") -def test_folder(tmp_path_factory): - test_folder = tmp_path_factory.mktemp("test_wit") - last_folder = test_folder / "folder1" / "folder2" +@pytest.fixture() +def test_folder(tmp_path): + test_wit = tmp_path / "test_wit" + last_folder = test_wit / "folder1" / "folder2" last_folder.mkdir(parents=True, exist_ok=True) - (test_folder / "file1.txt").write_text("") - (test_folder / "folder1" / "file2.txt").write_text("") + (test_wit / "file1.txt").write_text("") + (test_wit / "folder1" / "file2.txt").write_text("") (last_folder / "file3.txt").write_text("") - os.chdir(test_folder) + os.chdir(test_wit) init_function() - return test_folder + return test_wit + + +@pytest.fixture() +def file1(test_folder): + return test_folder / "file1.txt" + + +@pytest.fixture() +def folder1(test_folder): + return test_folder / "folder1" + + +@pytest.fixture() +def file2(folder1): + return folder1 / "file2.txt" + + +@pytest.fixture() +def folder2(folder1): + return folder1 / "folder2" + + +@pytest.fixture() +def file3(folder2): + return folder2 / "file3.txt" def change_add_and_commit_file(file_path, txt): file_path.write_text(txt) add_function(file_path) - commit_function("") + commit_id = commit_function("") + return commit_id diff --git a/tests/test_branch.py b/tests/test_branch.py index 43e41a6..9d83bfa 100644 --- a/tests/test_branch.py +++ b/tests/test_branch.py @@ -14,9 +14,8 @@ def test_raise_wit_error(tmp_path): branch_function("") -def test_branch_function(test_folder): +def test_branch_function(test_folder, file2): os.chdir(test_folder) - file2 = test_folder / "folder1" / "file2.txt" change_add_and_commit_file(file2, "test branch") branch_function("TestBranch") commit_id = get_head_reference(test_folder) @@ -24,6 +23,8 @@ def test_branch_function(test_folder): assert f"TestBranch={commit_id}" in references_file.read_text() -def test_branch_exists_error(test_folder): +def test_branch_exists_error(test_folder, file2): + change_add_and_commit_file(file2, "test branch") + branch_function("TestBranch") with pytest.raises(BranchExistsError): branch_function("TestBranch") diff --git a/tests/test_checkout.py b/tests/test_checkout.py index bddecd8..bf4ab14 100644 --- a/tests/test_checkout.py +++ b/tests/test_checkout.py @@ -5,7 +5,6 @@ from project.add import add_function from project.branch import branch_function from project.checkout import checkout_function -from project.commit import commit_function from project.errors import BranchDoesntExistError, FilesDoNotMatchError, WitError from project.utils import get_activated_branch, get_head_reference from tests.conftest import change_add_and_commit_file @@ -17,44 +16,43 @@ def test_raise_wit_error(tmp_path): checkout_function("branch") -def test_raise_branch_doesnt_exist_error(test_folder): +def test_raise_branch_doesnt_exist_error(test_folder, file1): os.chdir(test_folder) - commit_function("") + change_add_and_commit_file(file1, "") with pytest.raises(BranchDoesntExistError): checkout_function("branch") -def test_raise_files_do_not_match_error_changed(test_folder): +def test_raise_files_do_not_match_error_changed(test_folder, file1): + change_add_and_commit_file(file1, "") branch_function("branch") checkout_function("branch") - file1 = test_folder / "file1.txt" file1.write_text("FilesDoNotMatchError1") with pytest.raises(FilesDoNotMatchError): checkout_function("master") -def test_raise_files_do_not_match_error_added(test_folder): - file1 = test_folder / "file1.txt" - add_function(file1) +def test_raise_files_do_not_match_error_added(test_folder, file1, file2): + change_add_and_commit_file(file1, "") + add_function(file2) with pytest.raises(FilesDoNotMatchError): checkout_function("master") -def test_checkout_function(test_folder): - commit_function("") +def test_checkout_function(test_folder, file1): + change_add_and_commit_file(file1, "") + branch_function("branch") + checkout_function("branch") + change_add_and_commit_file(file1, "changed") checkout_function("master") - file1 = test_folder / "file1.txt" assert get_activated_branch(test_folder) == "master" - assert file1.read_text() != "FilesDoNotMatchError1" + assert file1.read_text() == "" -def test_checkout_id(test_folder): - file1 = test_folder / "file1.txt" +def test_checkout_id(test_folder, file1, file2): change_add_and_commit_file(file1, "") test_id = get_head_reference(test_folder) - file2 = test_folder / "folder1" / "file2.txt" change_add_and_commit_file(file2, "") checkout_function(test_id) activated_branch = get_activated_branch(test_folder) assert not activated_branch - checkout_function("master") diff --git a/tests/test_commit.py b/tests/test_commit.py index 6dd7dc4..b5af480 100644 --- a/tests/test_commit.py +++ b/tests/test_commit.py @@ -2,14 +2,11 @@ import pytest +from project.add import add_function from project.commit import commit_function from project.errors import WitError -from project.utils import ( - get_commit_id_of_branch, - get_commit_path, - get_head_reference, - get_references_path, -) +from project.utils import get_commit_path, get_head_reference +from tests.conftest import change_add_and_commit_file def test_raise_wit_error(tmp_path): @@ -18,8 +15,9 @@ def test_raise_wit_error(tmp_path): commit_function("") -def test_commit(test_folder): +def test_commit(test_folder, file1): os.chdir(test_folder) + add_function(file1) commit_function("test commit") commit_id = get_head_reference(test_folder) commit_txt_file = get_commit_path(test_folder, commit_id).with_suffix(".txt") @@ -27,9 +25,7 @@ def test_commit(test_folder): assert "test commit" in commit_txt_file.read_text() -def test_second_commit(test_folder): - commit_function("test second commit") - references_path = get_references_path(test_folder) - assert get_head_reference(test_folder) == get_commit_id_of_branch( - test_folder, "master", references_path - ) +def test_second_commit(test_folder, file1): + change_add_and_commit_file(file1, "") + new_commit_id = change_add_and_commit_file(file1, "1") + assert get_head_reference(test_folder) == new_commit_id diff --git a/tests/test_graph.py b/tests/test_graph.py index 3441736..741dd8c 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -2,10 +2,8 @@ import pytest -from project.add import add_function from project.branch import branch_function from project.checkout import checkout_function -from project.commit import commit_function from project.errors import WitError from project.graph import graph_function from project.merge import get_parents_commits, merge_function @@ -15,6 +13,7 @@ get_references_path, get_wit_dir, ) +from tests.conftest import change_add_and_commit_file def test_raise_wit_error(tmp_path, test_folder): @@ -23,14 +22,16 @@ def test_raise_wit_error(tmp_path, test_folder): graph_function() -def test_graph_function(test_folder): +def test_graph_function(test_folder, file1, file3): os.chdir(test_folder) - create_branch_and_checkout("branch1") - change_add_and_commit_file3(test_folder) - references_file = get_references_path(test_folder) + change_add_and_commit_file(file1, "") + branch_function("branch1") + checkout_function("branch1") + change_add_and_commit_file(file3, "1") checkout_function("master") - branch_commit_id = get_commit_id_of_branch(test_folder, "branch1", references_file) merge_function("branch1") + references_file = get_references_path(test_folder) + branch_commit_id = get_commit_id_of_branch(test_folder, "branch1", references_file) dot_source = graph_function() current_commit_id = get_head_reference(test_folder) wit_dir = get_wit_dir(test_folder) @@ -47,15 +48,3 @@ def get_commits_in_graph(branch_commit_id, current_commit_id, test_folder): parents_commits_of_master = set(get_parents_commits(test_folder, current_commit_id)) commits_in_graph = parents_commits_of_branch.union(parents_commits_of_master) return commits_in_graph - - -def create_branch_and_checkout(branch_name): - branch_function(branch_name) - checkout_function(branch_name) - - -def change_add_and_commit_file3(test_folder): - file3 = test_folder / r"folder1\folder2\file3.txt" - file3.write_text("1") - add_function(file3) - commit_function("add file3") diff --git a/tests/test_merge.py b/tests/test_merge.py index 8cada93..fb12ba4 100644 --- a/tests/test_merge.py +++ b/tests/test_merge.py @@ -2,13 +2,11 @@ import pytest -from project.add import add_function from project.branch import branch_function from project.checkout import checkout_function -from project.commit import commit_function from project.errors import MergeError, WitError from project.merge import merge_function -from project.utils import get_all_files_in_repository_and_subs, get_staging_area +from project.utils import get_staging_area from tests.conftest import change_add_and_commit_file @@ -24,10 +22,10 @@ def test_raise_merge_error(test_folder): merge_function("master") -def test_raise_changed_file_error(test_folder): +def test_raise_changed_file_error(test_folder, file1): + change_add_and_commit_file(file1, "") branch_function("TestChanged") checkout_function("TestChanged") - file1 = test_folder / "file1.txt" change_add_and_commit_file(file1, "changed") checkout_function("master") change_add_and_commit_file(file1, "changed again") @@ -35,14 +33,12 @@ def test_raise_changed_file_error(test_folder): merge_function("TestChanged") -def test_merge_function(test_folder): - reset_files_in_repo(test_folder) +def test_merge_function(test_folder, file1, folder1): + change_add_and_commit_file(file1, "") branch_function("TestMerge") checkout_function("TestMerge") - folder1 = test_folder / "folder1" new = add_new_file_and_commit(folder1) checkout_function("master") - file1 = test_folder / "file1.txt" change_add_and_commit_file(file1, "merge") checkout_function("TestMerge") merge_function("master") @@ -53,15 +49,22 @@ def test_merge_function(test_folder): assert file1_in_staging_area.read_text() == "merge" assert new.read_text() == "new" assert new_in_staging_area.read_text() == "new" - checkout_function("master") -def reset_files_in_repo(test_folder): - files_in_repo = get_all_files_in_repository_and_subs(test_folder) - for file_path in files_in_repo: - file_path.write_text("") - add_function(file_path) - commit_function("") +def test_merge_function2(test_folder, file1, file3): + change_add_and_commit_file(file1, "") + branch_function("branch1") + checkout_function("branch1") + change_add_and_commit_file(file3, "1") + checkout_function("master") + merge_function("branch1") + staging_area_path = get_staging_area(test_folder) + file1_in_staging_area = staging_area_path / "file1.txt" + file3_in_staging_area = staging_area_path / "folder2" / "file3.txt" + assert file1.read_text() == "" + assert file1_in_staging_area.read_text() == "" + assert file3.read_text() == "1" + assert file3_in_staging_area.read_text() == "1" def add_new_file_and_commit(folder): diff --git a/tests/test_status.py b/tests/test_status.py index 98aaf5f..3ef2cd6 100644 --- a/tests/test_status.py +++ b/tests/test_status.py @@ -2,6 +2,7 @@ import pytest +from project.add import add_function from project.errors import WitError from project.status import status_function from project.utils import ( @@ -9,6 +10,7 @@ get_all_files_in_repository_and_subs, get_staging_area, ) +from tests.conftest import change_add_and_commit_file def test_raise_wit_error(tmp_path): @@ -17,15 +19,18 @@ def test_raise_wit_error(tmp_path): status_function() -def test_status(test_folder): +def test_status(test_folder, file1, file3): os.chdir(test_folder) + change_add_and_commit_file(file1, "") + add_function(file3) + file1.write_text("1") ( changes_to_be_committed, changes_not_staged_for_commit, untracked_files, ) = status_function() - assert not list(changes_to_be_committed) - assert not list(changes_not_staged_for_commit) + assert set(changes_to_be_committed) == {file3.relative_to(test_folder)} + assert set(changes_not_staged_for_commit) == {file1.relative_to(test_folder)} staging_area = get_staging_area(test_folder) all_files = get_all_files_in_repository_and_subs(test_folder) files_in_staging_area = get_all_files_in_directory_and_subs(staging_area) From 94df4642accde4ced470185a5c306721725b9b42 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Thu, 24 Mar 2022 13:21:45 +0200 Subject: [PATCH 62/73] fix: merge, test_merge --- .coverage | Bin 53248 -> 53248 bytes project/merge.py | 3 +++ tests/test_merge.py | 4 ++-- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.coverage b/.coverage index d1455cfd2923168a170a35d8f6640bbffc118b45..3be28ff8cc18bd8794146c6e9629149b269abdea 100644 GIT binary patch delta 132 zcmV-~0DJ#{paX!Q1F(B92QxY`IXW{nvw|<9Py;s)DYGbmuMQUKAO<|h5c0nBFn8k;p5*7J#7b3Xsyo?nE8kyAnB)%@o_ zfxLPK{>g9q)byG6_kXr$ None: if file_path.is_file(): content_in_branch = path_in_branch.read_text() + file_parent = path_in_staging_area.parent + if not file_parent.exists(): + file_parent.mkdir(parents=True) path_in_staging_area.write_text(content_in_branch) path_in_repository.write_text(content_in_branch) else: diff --git a/tests/test_merge.py b/tests/test_merge.py index fb12ba4..c24c0ba 100644 --- a/tests/test_merge.py +++ b/tests/test_merge.py @@ -59,8 +59,8 @@ def test_merge_function2(test_folder, file1, file3): checkout_function("master") merge_function("branch1") staging_area_path = get_staging_area(test_folder) - file1_in_staging_area = staging_area_path / "file1.txt" - file3_in_staging_area = staging_area_path / "folder2" / "file3.txt" + file1_in_staging_area = staging_area_path / file1.relative_to(test_folder) + file3_in_staging_area = staging_area_path / file3.relative_to(test_folder) assert file1.read_text() == "" assert file1_in_staging_area.read_text() == "" assert file3.read_text() == "1" From 01e962827085d53bfd8e16b53ca40b6e66f59f45 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Fri, 25 Mar 2022 10:08:29 +0300 Subject: [PATCH 63/73] finished tests and fixed project files --- .coverage | Bin 53248 -> 53248 bytes project/checkout.py | 14 +++++---- project/merge.py | 5 ++- project/status.py | 7 ++--- tests/conftest.py | 20 ++++++++++++ tests/test_add.py | 15 +++++++-- tests/test_checkout.py | 16 +++++++++- tests/test_merge.py | 69 ++++++++++++++++++++++++++++++++--------- tests/test_status.py | 33 ++++++++++++++++++++ tests/test_utils.py | 6 ++++ 10 files changed, 154 insertions(+), 31 deletions(-) create mode 100644 tests/test_utils.py diff --git a/.coverage b/.coverage index 3be28ff8cc18bd8794146c6e9629149b269abdea..24f9e2f3931415f1ea77be8c6a28af63d9a58f75 100644 GIT binary patch delta 432 zcmXw!O-mb56ox1B;W&59Jtmo4R75RgA&4fmwN|T67Otv@?u1%5LQoLXHZ4@JP3p>B zn%sf}isMfZ<5G0fO*e+(Ub7n+N-MbW(!tx~!p(V~_waDwl=ijKzIO02O-A}2XT~!l z<4=a`+v)9gjgbmBvjZxr)MM?hiRv;Qn;oSe-mk3}hTd#ule+T7;ElQd!x`N`yUNXZ zw5w<@6aH&yusUN~4>scqOV8`}E0M}DdaQteD`>(w{DdRegKw|{pP&FMFb|V33@LEv z4ZWi0^anl0dpmToh3OHCvUkxWW_L1p)R3+xw-OH4ekbsJ(U6{OxKapdC2;8^f|6(U z#u2me3$1x8^FqG3lYh#dybN6zNAXOWytDl5(jrI>2{!Mxh=s_kApGr{e7BsQ9zCtqYLQms-ZgT$oUJ2u z=o_C;LLXW*EL2lL#q3i9A-@;S#yme_M0CrdDp3@L!74Yu4ydq-&p!p8_Y9S>dfuyK F{sX}Nk_P|) delta 362 zcmZozz}&Eac|(Ohmx+R*v6Z2vm9gpOCjBM>W>Kz7li3}#Hwy|Z;9_$SWnpM!oqXO; zW0N-vD^Tw8WcC1%+(NF&fiV`Fxubuo=!x=OVBr7B|C;|X|26(I{M-2#@=xdQ;cw(G z=g;5|<#*yY=hx(y|n|FgdCpZ$;8Isf@5i}ag$ z$k*H0pOY8l1*%oy&0~3R|M$;AyZ`5ZGx72Og=BbMJ^%UV=bz8)9Na*z5VzEa|D0Sv zmI&9Y%6~PSoFFFWt3Pj;Cr|0ucNE`0W9Cdo4pxv-*0i)VZWbU*f+eqR-=F8)Y|KCo vA2SmV6Ofi-di7_1@i|L*Rz?<1PCh0s1_lOE{`|@86F@;^%fC5){zL-+Gl_Qz diff --git a/project/checkout.py b/project/checkout.py index f45b3f5..f239a35 100644 --- a/project/checkout.py +++ b/project/checkout.py @@ -67,12 +67,14 @@ def update_files_in_main_folder( files_committed = get_all_files_in_directory_and_subs(commit_path) for committed_file in files_committed: path_in_commit = commit_path / committed_file - if path_in_commit.is_file(): - with open(path_in_commit, "r") as committed_file_h: - content = committed_file_h.read() - path_in_repository = repository / committed_file - with open(path_in_repository, "w") as original_file: - original_file.write(content) + path_in_repository = repository / committed_file + update_file_in_repository(path_in_commit, path_in_repository) + + +def update_file_in_repository(path_in_commit: Path, path_in_repository: Path) -> None: + if path_in_commit.is_file(): + content = path_in_commit.read_text() + path_in_repository.write_text(content) def update_staging_area_folder(staging_area_path: Path, commit_path: Path) -> None: diff --git a/project/merge.py b/project/merge.py index 022b3bd..c339602 100644 --- a/project/merge.py +++ b/project/merge.py @@ -1,4 +1,3 @@ -import os import re from glob import glob from pathlib import Path @@ -164,8 +163,8 @@ def create_new_file_in_staging_area_and_repository( path_in_staging_area.write_text(content_in_branch) path_in_repository.write_text(content_in_branch) else: - os.mkdir(path_in_staging_area) - os.mkdir(path_in_repository) + path_in_staging_area.mkdir(parents=True, exist_ok=True) + path_in_repository.mkdir(parents=True, exist_ok=True) def get_common_commit( diff --git a/project/status.py b/project/status.py index f7f01aa..9248adc 100644 --- a/project/status.py +++ b/project/status.py @@ -1,6 +1,6 @@ from glob import glob from pathlib import Path -from typing import Iterator +from typing import Iterator, Optional from project.errors import WitError from project.utils import ( @@ -45,13 +45,12 @@ def show_files(files: Iterator[Path]) -> str: return txt -def get_changes_to_be_committed(repository: Path) -> Iterator[Path]: +def get_changes_to_be_committed(repository: Path) -> Optional[Iterator[Path]]: staging_area_path = get_staging_area(repository) last_commit_id = get_head_reference(repository) files_in_staging_area = get_all_files_in_directory_and_subs(staging_area_path) if not last_commit_id: - for file_path in files_in_staging_area: - yield file_path + return None else: commit_path = get_commit_path(repository, last_commit_id) for file_path in files_in_staging_area: diff --git a/tests/conftest.py b/tests/conftest.py index f151ed4..a80e8f6 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,6 +5,7 @@ from project.add import add_function from project.commit import commit_function from project.init import init_function +from project.utils import get_staging_area @pytest.fixture() @@ -15,6 +16,8 @@ def test_folder(tmp_path): (test_wit / "file1.txt").write_text("") (test_wit / "folder1" / "file2.txt").write_text("") (last_folder / "file3.txt").write_text("") + empty_folder = test_wit / "empty" + empty_folder.mkdir() os.chdir(test_wit) init_function() return test_wit @@ -45,8 +48,25 @@ def file3(folder2): return folder2 / "file3.txt" +@pytest.fixture() +def empty_folder(test_folder): + return test_folder / "empty" + + def change_add_and_commit_file(file_path, txt): file_path.write_text(txt) add_function(file_path) commit_id = commit_function("") return commit_id + + +def add_new_file_and_commit(folder): + new = folder / "file_path.txt" + change_add_and_commit_file(new, "file_path") + return new + + +def get_file_path_in_staging_area(file_path, folder): + staging_area = get_staging_area(folder) + path_in_staging_area = staging_area / file_path.relative_to(folder) + return path_in_staging_area diff --git a/tests/test_add.py b/tests/test_add.py index 66998a8..5e3a5e0 100644 --- a/tests/test_add.py +++ b/tests/test_add.py @@ -4,7 +4,7 @@ from project.add import add_function from project.errors import WitError -from project.utils import get_staging_area +from tests.conftest import get_file_path_in_staging_area def test_raise_wit_error(tmp_path): @@ -20,6 +20,15 @@ def test_raise_wit_error(tmp_path): ) def test_add_function(test_folder, file_to_add): os.chdir(test_folder) - add_function(test_folder / file_to_add) - path_in_staging_area = get_staging_area(test_folder) / file_to_add + file_path = test_folder / file_to_add + add_function(file_path) + path_in_staging_area = get_file_path_in_staging_area(file_path, test_folder) assert path_in_staging_area.exists() + + +def test_add_dir_already_added(test_folder, file3, folder2): + add_function(folder2) + file3.write_text("1") + add_function(folder2) + file3_in_staging_area = get_file_path_in_staging_area(file3, test_folder) + assert file3_in_staging_area.read_text() == "1" diff --git a/tests/test_checkout.py b/tests/test_checkout.py index bf4ab14..80e6f25 100644 --- a/tests/test_checkout.py +++ b/tests/test_checkout.py @@ -7,7 +7,11 @@ from project.checkout import checkout_function from project.errors import BranchDoesntExistError, FilesDoNotMatchError, WitError from project.utils import get_activated_branch, get_head_reference -from tests.conftest import change_add_and_commit_file +from tests.conftest import ( + add_new_file_and_commit, + change_add_and_commit_file, + get_file_path_in_staging_area, +) def test_raise_wit_error(tmp_path): @@ -56,3 +60,13 @@ def test_checkout_id(test_folder, file1, file2): checkout_function(test_id) activated_branch = get_activated_branch(test_folder) assert not activated_branch + + +def test_add_new_file_and_checkout(test_folder, file1, file2): + change_add_and_commit_file(file1, "") + branch_function("branch") + checkout_function("branch") + new = add_new_file_and_commit(test_folder) + checkout_function("master") + new_in_staging_area = get_file_path_in_staging_area(new, test_folder) + assert not new_in_staging_area.exists() diff --git a/tests/test_merge.py b/tests/test_merge.py index c24c0ba..5c44824 100644 --- a/tests/test_merge.py +++ b/tests/test_merge.py @@ -2,12 +2,17 @@ import pytest +from project.add import add_function from project.branch import branch_function from project.checkout import checkout_function +from project.commit import commit_function from project.errors import MergeError, WitError from project.merge import merge_function -from project.utils import get_staging_area -from tests.conftest import change_add_and_commit_file +from tests.conftest import ( + add_new_file_and_commit, + change_add_and_commit_file, + get_file_path_in_staging_area, +) def test_raise_wit_error(tmp_path): @@ -42,13 +47,12 @@ def test_merge_function(test_folder, file1, folder1): change_add_and_commit_file(file1, "merge") checkout_function("TestMerge") merge_function("master") - staging_area_path = get_staging_area(test_folder) - file1_in_staging_area = staging_area_path / "file1.txt" - new_in_staging_area = staging_area_path / "folder1" / "new.txt" + file1_in_staging_area = get_file_path_in_staging_area(file1, test_folder) + new_in_staging_area = get_file_path_in_staging_area(new, test_folder) assert file1.read_text() == "merge" assert file1_in_staging_area.read_text() == "merge" - assert new.read_text() == "new" - assert new_in_staging_area.read_text() == "new" + assert new.read_text() == "file_path" + assert new_in_staging_area.read_text() == "file_path" def test_merge_function2(test_folder, file1, file3): @@ -58,16 +62,53 @@ def test_merge_function2(test_folder, file1, file3): change_add_and_commit_file(file3, "1") checkout_function("master") merge_function("branch1") - staging_area_path = get_staging_area(test_folder) - file1_in_staging_area = staging_area_path / file1.relative_to(test_folder) - file3_in_staging_area = staging_area_path / file3.relative_to(test_folder) + file1_in_staging_area = get_file_path_in_staging_area(file1, test_folder) + file3_in_staging_area = get_file_path_in_staging_area(file3, test_folder) assert file1.read_text() == "" assert file1_in_staging_area.read_text() == "" assert file3.read_text() == "1" assert file3_in_staging_area.read_text() == "1" -def add_new_file_and_commit(folder): - new = folder / "new.txt" - change_add_and_commit_file(new, "new") - return new +def test_raise_deleted_file_error(test_folder, file1, file2): + change_add_and_commit_file(file1, "") + branch_function("TestMerge") + checkout_function("TestMerge") + file2.unlink() + checkout_function("master") + with pytest.raises(NotImplementedError): + merge_function("TestMerge") + + +def test_create_file_and_merge(test_folder, file1): + change_add_and_commit_file(file1, "") + branch_function("TestMerge") + checkout_function("TestMerge") + new = add_new_file_and_commit(test_folder) + checkout_function("master") + merge_function("TestMerge") + new_in_staging_area = get_file_path_in_staging_area(new, test_folder) + assert new_in_staging_area.read_text() == "file_path" + + +def test_merge_master(test_folder, file1, file2): + change_add_and_commit_file(file1, "") + branch_function("TestMerge") + checkout_function("TestMerge") + change_add_and_commit_file(file2, "1") + merge_function("master") + + +def test_create_folder_and_merge(test_folder, file1): + change_add_and_commit_file(file1, "") + branch_function("TestMerge") + checkout_function("TestMerge") + new = test_folder / "file_path" + new.mkdir() + add_function(new) + commit_function("") + checkout_function("master") + merge_function("TestMerge") + new_in_staging_area = get_file_path_in_staging_area(new, test_folder) + assert new_in_staging_area.exists() + assert new.exists() diff --git a/tests/test_status.py b/tests/test_status.py index 3ef2cd6..e9edaa4 100644 --- a/tests/test_status.py +++ b/tests/test_status.py @@ -35,3 +35,36 @@ def test_status(test_folder, file1, file3): all_files = get_all_files_in_repository_and_subs(test_folder) files_in_staging_area = get_all_files_in_directory_and_subs(staging_area) assert set(untracked_files).union(set(files_in_staging_area)) == set(all_files) + + +def test_status_if_no_commit_was_done(test_folder): + ( + changes_to_be_committed, + changes_not_staged_for_commit, + untracked_files, + ) = status_function() + all_files = get_all_files_in_repository_and_subs(test_folder) + assert not set(changes_to_be_committed) + assert set(untracked_files) == set(all_files) + + +def test_commit_change_file_again_and_add(test_folder, file3): + change_add_and_commit_file(file3, "") + file3.write_text("1") + add_function(file3) + file3_name = file3.relative_to(test_folder) + ( + changes_to_be_committed, + changes_not_staged_for_commit, + untracked_files, + ) = status_function() + assert set(changes_to_be_committed) == {file3_name} + assert not set(changes_not_staged_for_commit) + assert file3_name not in set(untracked_files) + + +def test_delete_added_file(test_folder, file2): + change_add_and_commit_file(file2, "") + file2.unlink() + with pytest.raises(NotImplementedError): + status_function() diff --git a/tests/test_utils.py b/tests/test_utils.py new file mode 100644 index 0000000..b3cf845 --- /dev/null +++ b/tests/test_utils.py @@ -0,0 +1,6 @@ +from project.utils import get_all_files_in_repository_and_subs + + +def test_get_all_files_in_repository(test_folder, empty_folder): + all_files = get_all_files_in_repository_and_subs(test_folder) + assert empty_folder.relative_to(test_folder) in set(all_files) From d7a56c168bc6d9b03cdc3ae3d604c5867f28d2fa Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Fri, 25 Mar 2022 10:29:54 +0300 Subject: [PATCH 64/73] fix requirements --- requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 826fb02..2e4865b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,4 @@ pytest~=7.0.1 -Flask~=2.0.3 click~=8.0.4 graphviz~=0.19.1 setuptools~=57.4.0 \ No newline at end of file From b87e7e296310db3c9ccf280af730dd20256fb5e9 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Milano <97195051+RuthMahallaMilano@users.noreply.github.com> Date: Tue, 12 Apr 2022 23:11:21 +0300 Subject: [PATCH 65/73] Update project/checkout.py Co-authored-by: Yam Mesicka --- project/checkout.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/project/checkout.py b/project/checkout.py index f239a35..6dee97f 100644 --- a/project/checkout.py +++ b/project/checkout.py @@ -29,10 +29,8 @@ def checkout_function(commit_id_or_branch: str) -> None: ) if not commit_id: raise BranchDoesntExistError("Branch doesn't exist.") - if commit_id != commit_id_or_branch: - write_activated(commit_id_or_branch, repository) - else: - write_activated("", repository) + checkout_to = commit_id_or_branch if commit_id != commit_id_or_branch else "" + write_activated(checkout_to, repository) commit_path = get_commit_path(repository, commit_id) update_files_in_main_folder(commit_path, repository) update_head_in_references_file(commit_id, references_file) From c43126862aae3f879a2a358e0102c5a28712012e Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Milano <97195051+RuthMahallaMilano@users.noreply.github.com> Date: Wed, 13 Apr 2022 10:35:03 +0300 Subject: [PATCH 66/73] Update project/utils.py Co-authored-by: Yam Mesicka --- project/utils.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/project/utils.py b/project/utils.py index 869eefd..3c485ed 100644 --- a/project/utils.py +++ b/project/utils.py @@ -5,7 +5,14 @@ from typing import Iterator, Optional branch_regex = re.compile( - r"^(?P\w+)=(?P\w{20})$", flags=re.MULTILINE +BRANCH_REGEX = re.compile( + r"^" + r"(?P\w+)" + r"=" + r"(?P[0-9a-fA-F]{20})" + r"$", + flags=re.MULTILINE, +) ) From eed7d9c9f95626200ec39dac0c13bf2320d90ac5 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Mon, 25 Apr 2022 22:05:26 +0300 Subject: [PATCH 67/73] fix files after review --- .coverage | Bin 53248 -> 53248 bytes project/add.py | 4 +- project/branch.py | 21 ++--- project/checkout.py | 24 ++---- project/commit.py | 13 ++-- project/errors.py | 4 + project/graph.py | 13 +--- project/init.py | 8 +- project/merge.py | 180 +++++++++++++++++++------------------------ project/status.py | 67 ++++------------ project/utils.py | 87 ++++++++++++++++----- tests/conftest.py | 4 +- tests/test_branch.py | 7 +- tests/test_graph.py | 4 +- tests/test_init.py | 8 +- tests/test_status.py | 11 +-- 16 files changed, 211 insertions(+), 244 deletions(-) diff --git a/.coverage b/.coverage index 24f9e2f3931415f1ea77be8c6a28af63d9a58f75..c498aa58affa169b33aa7b08ebb8ad18d74a4cd4 100644 GIT binary patch delta 627 zcmYL@PiWIn9LL-BPnx_WFKJW3GF-*W6zYnNo2zAMPa@fhe{QoBhOAYjZfu=U9DCis zYm0q73Y}UcDxLyCbdrMG^yMecB6M~w$ zq9)VnY-T#EP8wSiuOy+x&+!uI0}So}$w=p4b0fJpzFo|~)%rqxZT0eUBd-K~n;~o# z$2)r5AH(wO6rR)BV3cC~ynL~v1KiRhxUZ{RZE>Z#NH^Cd+%9Ig>dM0M16nmmSNV{5 z`Ur&YFV$)f>&EBV8-XM*iwgM0^~Dza0G|nmLRX0LZN3P);4YB4jv-5B4tM4Y_*Plv zPRyui=^6$)>sRpCQfeqNr$<6DEx74FHDmC>y{qi8nT%Uyl|2@d{_jozq%RA`mr~)v z*eCb~Zo?Mbf=}QhI1g{a8JLDiI3oTPe~1T0y4e*G9}oK3M0~PIHpZ+eL7{C_vCo@C zBLkwuXuTA(Va`MzagjGLO~SBIN|mVH++jv#8nf~*Uy>lQ=OPO^=)LPKc`n)~j409T zIqA?x(127o0z9NW0d1z?k$r|0X+w%=JFWu-nv=p~pZip^9Mjo@{1EUq^U~ZgHRSnO zK!E}hN52`4qwx%9H@tO`V~3fw-Jcc{iO?L4B#uaop=q4)!rNrpB5gFlCV6)@OraVs jfBa*T!TOB#;(M>xlXFCaR)7uBn-Z#2Dq*AFPUZgrS9sSr delta 615 zcmX|5OKTHR7;T!zJnqcgnaspRk)~o7Rfvg6OJc2=DF`kSYP!&c4S`ac+C`Guq>Dgg z5_xDslj2D-Eb7m-1Hkd1>e*Bdq6e4KMQ=X|HQV=eAjUu=2# zfX6>Gan?8Mo0$#x8@IeqMZUttI0!y~hu{iO8b0kAJF2;isS5#ZcGF(8fr`L1jnT(|P^l-#dh#8KM{>Q+PB9gigyOK$z{stk6C8m#d#V?+8 zzkx5|Hmt%s@FvW{6&QmTpdU^`Md%8jg?7VNtO`2svRRnpF5^TCt94wE6+)*Jquw!F zxQ<&YHciaPL{wy>Sf|`h0yXDH>)}tFG4c66{#vf%gPy9Aqc<@nNW?HMJuiL2UX1rL zoJjbXXi)h+Zc+>!G(n@=>q-KFle&-|!N0@dU42{cK#3n{eA;$+@XNdr#&h3*z!7Pj zGdgC^>~%YC8W8RTW8X2u5~Q$3zF%M&0*^69?@NcG>4AYJ28AN%G}U)J!RI=-tedEX kAKPUIQKuZQezf#3E=bMbZmm|c(Dp&fo=hei?XpMv1JDB7Y5)KL diff --git a/project/add.py b/project/add.py index 4770702..ab988af 100644 --- a/project/add.py +++ b/project/add.py @@ -3,7 +3,7 @@ from typing import Union from project.errors import WitError -from project.utils import get_repository_path, get_staging_area +from project.utils import get_repository_path, get_staging_area_path def add_function(path_to_add: Union[str, Path]) -> None: @@ -15,7 +15,7 @@ def add_function(path_to_add: Union[str, Path]) -> None: def copy_to_staging_area(path: Path, repository: Path) -> None: - staging_area_path = get_staging_area(repository) + staging_area_path = get_staging_area_path(repository) relative_path = path.relative_to(repository) if path.is_dir(): copy_dir_to_staging_area(staging_area_path, path, relative_path) diff --git a/project/branch.py b/project/branch.py index 3f36029..9c385c1 100644 --- a/project/branch.py +++ b/project/branch.py @@ -1,8 +1,8 @@ from pathlib import Path -from project.errors import BranchExistsError, WitError +from project.errors import BranchExistsError, BranchNotCreatedError, WitError from project.utils import ( - get_branches_commits, + get_commits_by_branches, get_head_reference, get_references_path, get_repository_path, @@ -14,10 +14,13 @@ def branch_function(name: str) -> None: if not repository: raise WitError("<.wit> file not found") references_file = get_references_path(repository) - if references_file.exists(): - existing_branches = get_branches_commits(references_file) - if name in existing_branches: - raise BranchExistsError(f"Branch {name} already exists.") - commit_id = get_head_reference(repository) - with references_file.open("a") as ref_file: - ref_file.write(f"\n{name}={commit_id}") + if not references_file.exists(): + raise BranchNotCreatedError( + "No commit was done yet. Can't create a new branch." + ) + existing_branches = get_commits_by_branches(references_file) + if name in existing_branches: + raise BranchExistsError(f"Branch {name} already exists.") + commit_id = get_head_reference(repository) + with references_file.open("a") as ref_file: + ref_file.write(f"\n{name}={commit_id}") diff --git a/project/checkout.py b/project/checkout.py index f239a35..6018f1e 100644 --- a/project/checkout.py +++ b/project/checkout.py @@ -2,11 +2,7 @@ from pathlib import Path from typing import Union -from project.errors import BranchDoesntExistError, FilesDoNotMatchError, WitError -from project.status import ( - get_changes_not_staged_for_commit, - get_changes_to_be_committed, -) +from project.errors import BranchDoesntExistError, WitError from project.utils import ( get_activated_path, get_all_files_in_directory_and_subs, @@ -14,7 +10,8 @@ get_commit_path, get_references_path, get_repository_path, - get_staging_area, + get_staging_area_path, + raise_for_unsaved_work, ) @@ -36,19 +33,10 @@ def checkout_function(commit_id_or_branch: str) -> None: commit_path = get_commit_path(repository, commit_id) update_files_in_main_folder(commit_path, repository) update_head_in_references_file(commit_id, references_file) - staging_area_path = get_staging_area(repository) + staging_area_path = get_staging_area_path(repository) update_staging_area_folder(staging_area_path, commit_path) -def raise_for_unsaved_work(repository: Path) -> None: - files_added_since_last_commit = set(get_changes_to_be_committed(repository)) - changed_files_since_last_commit = set(get_changes_not_staged_for_commit(repository)) - if files_added_since_last_commit or changed_files_since_last_commit: - raise FilesDoNotMatchError( - "There are files added or changed since last commit_function" - ) - - def write_activated(commit_id_or_branch: str, repository: Path) -> None: activated_path = get_activated_path(repository) activated_path.write_text(commit_id_or_branch) @@ -56,8 +44,8 @@ def write_activated(commit_id_or_branch: str, repository: Path) -> None: def update_head_in_references_file(commit_id: str, references_file: Path) -> None: with references_file.open() as file: - branches = file.readlines()[1:] - branches_txt = "".join(branches) + file.readline() + branches_txt = file.read() references_file.write_text(f"HEAD={commit_id}\n{branches_txt}") diff --git a/project/commit.py b/project/commit.py index f03f2c4..af6a1b7 100644 --- a/project/commit.py +++ b/project/commit.py @@ -13,7 +13,7 @@ get_head_reference, get_references_path, get_repository_path, - get_staging_area, + get_staging_area_path, ) LENGTH = 20 @@ -61,7 +61,7 @@ def create_commit_txt_file( def save_files_in_new_commit(repository: Path, new_commit_id: str) -> None: - staging_area_path = get_staging_area(repository) + staging_area_path = get_staging_area_path(repository) commit_path = get_commit_path(repository, new_commit_id) for item in staging_area_path.iterdir(): src = staging_area_path / item.name @@ -98,17 +98,14 @@ def change_head_and_branch_id( head_regex = rf"^HEAD={parent_head}$" references_data = references_file.read_text() activated_match = re.findall(activated_regex, references_data, flags=re.MULTILINE) - new_references_content = ( - re.sub( + if activated_match: + references_data = re.sub( activated_regex, f"{activated_branch}={commit_id}", references_data, flags=re.MULTILINE, ) - if activated_match - else references_data - ) new_references_content = re.sub( - head_regex, f"HEAD={commit_id}", new_references_content, flags=re.MULTILINE + head_regex, f"HEAD={commit_id}", references_data, flags=re.MULTILINE ) references_file.write_text(new_references_content) diff --git a/project/errors.py b/project/errors.py index 11b9d16..17e3acf 100644 --- a/project/errors.py +++ b/project/errors.py @@ -20,3 +20,7 @@ class WitExistsError(WitError): class MergeError(WitError): pass + + +class BranchNotCreatedError(WitError): + pass diff --git a/project/graph.py b/project/graph.py index 37aeabc..e89b020 100644 --- a/project/graph.py +++ b/project/graph.py @@ -1,4 +1,3 @@ -import re from pathlib import Path from typing import Optional @@ -6,15 +5,11 @@ from project.errors import WitError from project.utils import ( + PARENT_ID_REGEX, get_head_reference, get_images_path, get_repository_path, - get_wit_dir, -) - -parent_id_regex = re.compile( - r"^parent = (?P\w{20})(, (?P\w{20}))?$", - flags=re.MULTILINE, + get_wit_path, ) @@ -25,7 +20,7 @@ def graph_function() -> Optional[str]: current_commit_id = get_head_reference(repository) commit_id = current_commit_id dot = init_graph() - wit_dir = get_wit_dir(repository) + wit_dir = get_wit_path(repository) images_path = get_images_path(repository) create_nodes(commit_id, dot, images_path) dot.render( @@ -42,7 +37,7 @@ def create_nodes(commit_id: str, dot: Digraph, images_path: Path) -> None: commit_file = images_path / (commit_id + ".txt") create_node(commit_id, dot) commit_txt = commit_file.read_text() - parent_id_match = parent_id_regex.match(commit_txt) + parent_id_match = PARENT_ID_REGEX.match(commit_txt) if parent_id_match: parent_id_1 = parent_id_match.group("commit_id_1") parent_id_2 = parent_id_match.group("commit_id_2") diff --git a/project/init.py b/project/init.py index e5b7e72..27edd72 100644 --- a/project/init.py +++ b/project/init.py @@ -4,20 +4,20 @@ from project.utils import ( get_activated_path, get_images_path, - get_staging_area, - get_wit_dir, + get_staging_area_path, + get_wit_path, ) def init_function() -> None: cwd = Path.cwd() - wit_path = get_wit_dir(cwd) + wit_path = get_wit_path(cwd) if wit_path.exists(): raise WitExistsError("The folder already has .wit directory") wit_path.mkdir() images_path = get_images_path(cwd) images_path.mkdir() - staging_area_path = get_staging_area(cwd) + staging_area_path = get_staging_area_path(cwd) staging_area_path.mkdir() activated_path = get_activated_path(cwd) activated_path.write_text("master") diff --git a/project/merge.py b/project/merge.py index c339602..2b29174 100644 --- a/project/merge.py +++ b/project/merge.py @@ -1,12 +1,11 @@ -import re -from glob import glob +from collections import namedtuple from pathlib import Path from typing import Iterator -from project.checkout import raise_for_unsaved_work from project.commit import commit_function from project.errors import MergeError, WitError from project.utils import ( + PARENT_ID_REGEX, get_activated_branch, get_all_files_in_directory_and_subs, get_commit_id_of_branch, @@ -15,13 +14,11 @@ get_images_path, get_references_path, get_repository_path, - get_staging_area, + get_staging_area_path, + raise_for_unsaved_work, ) -regex = re.compile( - r"^parent = (?P\w{20})(, (?P\w{20}))?$", - flags=re.MULTILINE, -) +Paths = namedtuple("Paths", ["branch", "common", "staging_area", "repository"]) def merge_function(branch_name: str) -> None: @@ -35,139 +32,118 @@ def merge_function(branch_name: str) -> None: head_reference = get_head_reference(repository) branch_commit_id = get_commit_id_of_branch(repository, branch_name, references_file) raise_for_unsaved_work(repository) - common_commit = get_common_commit(repository, branch_commit_id, head_reference) - common_dir = get_commit_path(repository, common_commit) - branch_dir = get_commit_path(repository, branch_commit_id) - branch_files, common_files = get_common_and_branch_files(branch_dir, common_dir) + common_commit_id = get_common_commit_id( + repository, + branch_commit_id, + head_reference, + ) + common_commit_path = get_commit_path(repository, common_commit_id) + branch_path = get_commit_path(repository, branch_commit_id) + staging_area_path = get_staging_area_path(repository) check_common_commit_and_update_staging_area_and_repository( - branch_dir, common_dir, common_files, repository + branch_path, + common_commit_path, + repository, + staging_area_path, ) check_branch_and_update_staging_area_and_repository( - branch_dir, branch_files, common_dir, repository + branch_path, + common_commit_path, + repository, + staging_area_path, ) commit_merge(branch_commit_id, branch_name, head_reference, repository) def check_branch_and_update_staging_area_and_repository( - branch_dir: Path, - branch_files: Iterator[Path], - common_dir: Path, + branch_path: Path, + common_commit_path: Path, repository: Path, + staging_area_path: Path, ) -> None: - staging_area_path = get_staging_area(repository) + branch_files = get_all_files_in_directory_and_subs(branch_path) for file_path in branch_files: - ( - path_in_branch, - path_in_common, - path_in_staging_area, - path_in_repository, - ) = get_file_path_in_all_dirs( - file_path, branch_dir, common_dir, staging_area_path, repository + paths = Paths( + branch_path / file_path, + common_commit_path / file_path, + staging_area_path / file_path, + repository / file_path, ) - if not glob(str(path_in_common)): - create_new_file_in_staging_area_and_repository( - file_path, path_in_branch, path_in_staging_area, path_in_repository - ) + files_in_common_that_match_file = common_commit_path.glob(str(file_path)) + if not set(files_in_common_that_match_file): + create_new_file_in_staging_area_and_repository(file_path, paths) + + +def create_new_file_in_staging_area_and_repository( + file_path: Path, paths: Paths +) -> None: + if file_path.is_file(): + content_in_branch = paths.branch.read_text() + file_parent = paths.staging_area.parent + if not file_parent.exists(): + file_parent.mkdir(parents=True) + paths.staging_area.write_text(content_in_branch) + paths.repository.write_text(content_in_branch) + else: + paths.staging_area.mkdir(parents=True, exist_ok=True) + paths.repository.mkdir(parents=True, exist_ok=True) def check_common_commit_and_update_staging_area_and_repository( - branch_dir: Path, - common_dir: Path, - common_files: Iterator[Path], + branch_path: Path, + common_commit_path: Path, repository: Path, + staging_area_path: Path, ) -> None: - staging_area_path = get_staging_area(repository) + common_files = get_all_files_in_directory_and_subs(common_commit_path) for file_path in common_files: - ( - path_in_branch, - path_in_common, - path_in_staging_area, - path_in_repository, - ) = get_file_path_in_all_dirs( - file_path, branch_dir, common_dir, staging_area_path, repository - ) - if not glob(str(path_in_branch)) or not glob(str(path_in_staging_area)): + if check_if_file_was_deleted(file_path, branch_path, staging_area_path): raise NotImplementedError( f"The file {file_path} was deleted. Deleting files not implemented yet." ) - elif file_path.is_file(): - update_file_in_staging_area_and_repository( - file_path, - path_in_branch, - path_in_common, - path_in_staging_area, - path_in_repository, + if file_path.is_file(): + paths = Paths( + branch_path / file_path, + common_commit_path / file_path, + staging_area_path / file_path, + repository / file_path, ) + update_file_in_staging_area_and_repository(file_path, paths) -def get_common_and_branch_files( - branch_dir: Path, common_dir: Path -) -> tuple[Iterator[Path], Iterator[Path]]: - common_files = get_all_files_in_directory_and_subs(common_dir) - branch_files = get_all_files_in_directory_and_subs(branch_dir) - return branch_files, common_files +def check_if_file_was_deleted( + file_path: Path, branch_path: Path, staging_area_path: Path +) -> bool: + files_in_branch_that_match_file = branch_path.glob(str(file_path)) + deleted_in_branch = not set(files_in_branch_that_match_file) + files_in_staging_area_that_match_file = staging_area_path.glob(str(file_path)) + deleted_in_current = not set(files_in_staging_area_that_match_file) + return deleted_in_branch or deleted_in_current -def update_file_in_staging_area_and_repository( - file_path: Path, - path_in_branch: Path, - path_in_common: Path, - path_in_staging_area: Path, - path_in_repository: Path, -) -> None: - content_in_common = path_in_common.read_text() - content_in_branch = path_in_branch.read_text() - content_in_staging_area = path_in_staging_area.read_text() +def update_file_in_staging_area_and_repository(file_path: Path, paths: Paths) -> None: + content_in_common = paths.common.read_text() + content_in_branch = paths.branch.read_text() + content_in_staging_area = paths.staging_area.read_text() if content_in_common != content_in_branch: if content_in_common != content_in_staging_area: raise NotImplementedError( f"{file_path} was changed in both branches. Not implemented yet." ) - path_in_staging_area.write_text(content_in_branch) - path_in_repository.write_text(content_in_branch) - - -def get_file_path_in_all_dirs( - file_path: Path, - branch_dir: Path, - common_dir: Path, - staging_area_path: Path, - repository: Path, -) -> tuple[Path, ...]: - path_in_common = common_dir / file_path - path_in_staging_area = staging_area_path / file_path - path_in_branch = branch_dir / file_path - path_in_repository = repository / file_path - return path_in_branch, path_in_common, path_in_staging_area, path_in_repository + paths.staging_area.write_text(content_in_branch) + paths.repository.write_text(content_in_branch) def commit_merge( branch_commit_id: str, branch_name: str, head_reference: str, repository: Path ) -> None: activated = get_activated_branch(repository) - message = f"Commit after merge of {activated if activated else head_reference} and {branch_name}." + current_branch = activated if activated else head_reference + message = f"Commit after merge of {current_branch} and {branch_name}." commit_function(message, branch_commit_id) -def create_new_file_in_staging_area_and_repository( - file_path: Path, - path_in_branch: Path, - path_in_staging_area: Path, - path_in_repository: Path, -) -> None: - if file_path.is_file(): - content_in_branch = path_in_branch.read_text() - file_parent = path_in_staging_area.parent - if not file_parent.exists(): - file_parent.mkdir(parents=True) - path_in_staging_area.write_text(content_in_branch) - path_in_repository.write_text(content_in_branch) - else: - path_in_staging_area.mkdir(parents=True, exist_ok=True) - path_in_repository.mkdir(parents=True, exist_ok=True) - - -def get_common_commit( +def get_common_commit_id( repository: Path, branch_commit_id: str, head_reference: str ) -> str: branch_parents = set(get_parents_commits(repository, branch_commit_id)) @@ -191,7 +167,7 @@ def get_parents_of_commit_id(commit_id: str, images_path: Path) -> Iterator[str] while commit_id: commit_file = images_path / (commit_id + ".txt") commit_txt = commit_file.read_text() - parent_id_match = regex.match(commit_txt) + parent_id_match = PARENT_ID_REGEX.match(commit_txt) if parent_id_match: parent_id_1 = parent_id_match.group("commit_id_1") parent_id_2 = parent_id_match.group("commit_id_2") diff --git a/project/status.py b/project/status.py index 9248adc..02e8f41 100644 --- a/project/status.py +++ b/project/status.py @@ -1,15 +1,14 @@ -from glob import glob from pathlib import Path -from typing import Iterator, Optional +from typing import Iterator from project.errors import WitError from project.utils import ( - get_all_files_in_directory_and_subs, get_all_files_in_repository_and_subs, - get_commit_path, + get_changes_not_staged_for_commit, + get_changes_to_be_committed, get_head_reference, get_repository_path, - get_staging_area, + get_staging_area_path, ) @@ -19,11 +18,11 @@ def status_function() -> tuple[Iterator[Path], Iterator[Path], Iterator[Path]]: raise WitError("<.wit> file not found") last_commit_id = get_head_reference(repository) message_if_no_commit = "No commit was done yet." - changes_to_be_committed = show_files(get_changes_to_be_committed(repository)) - changes_not_staged_for_commit = show_files( + changes_to_be_committed = stringify_files(get_changes_to_be_committed(repository)) + changes_not_staged_for_commit = stringify_files( get_changes_not_staged_for_commit(repository) ) - untracked_files = show_files(get_untracked_files(repository)) + untracked_files = stringify_files(get_untracked_files(repository)) output = ( f"###Commit id:###\n{last_commit_id if last_commit_id else message_if_no_commit}\n\n" f"###Changes to be committed:###\n{changes_to_be_committed}\n\n" @@ -38,54 +37,16 @@ def status_function() -> tuple[Iterator[Path], Iterator[Path], Iterator[Path]]: ) -def show_files(files: Iterator[Path]) -> str: - txt = "" - for file in files: - txt += str(file) + "\n" - return txt - - -def get_changes_to_be_committed(repository: Path) -> Optional[Iterator[Path]]: - staging_area_path = get_staging_area(repository) - last_commit_id = get_head_reference(repository) - files_in_staging_area = get_all_files_in_directory_and_subs(staging_area_path) - if not last_commit_id: - return None - else: - commit_path = get_commit_path(repository, last_commit_id) - for file_path in files_in_staging_area: - path_in_last_commit = commit_path / file_path - if not glob(str(path_in_last_commit)): - yield file_path - elif file_path.is_file(): - if check_if_file_changed(file_path, staging_area_path, commit_path): - yield file_path - - -def check_if_file_changed(file_path: Path, dir_1: Path, dir_2: Path) -> bool: - content_in_dir_1 = (dir_1 / file_path).read_text() - content_in_dir_2 = (dir_2 / file_path).read_text() - return content_in_dir_1 != content_in_dir_2 - - -def get_changes_not_staged_for_commit(repository: Path) -> Iterator[Path]: - staging_area_path = get_staging_area(repository) - files_in_staging_area = get_all_files_in_directory_and_subs(staging_area_path) - for file_path in files_in_staging_area: - path_in_repository = repository / file_path - if not glob(str(path_in_repository)): - raise NotImplementedError( - f"The file {file_path} was deleted. Deleting files not implemented yet." - ) - if file_path.is_file(): - if check_if_file_changed(file_path, staging_area_path, repository): - yield file_path +def stringify_files(files: Iterator[Path]) -> str: + return "\n".join([str(file_name) for file_name in files]) def get_untracked_files(repository: Path) -> Iterator[Path]: - staging_area_path = get_staging_area(repository) + staging_area_path = get_staging_area_path(repository) files_in_repository = get_all_files_in_repository_and_subs(repository) for file_path in files_in_repository: - path_in_staging_area = staging_area_path / file_path - if not glob(str(path_in_staging_area)): + files_in_staging_area_that_match_file_path = staging_area_path.glob( + str(file_path) + ) + if not set(files_in_staging_area_that_match_file_path): yield file_path diff --git a/project/utils.py b/project/utils.py index 869eefd..6d33cef 100644 --- a/project/utils.py +++ b/project/utils.py @@ -1,28 +1,38 @@ import os import re -from glob import glob from pathlib import Path -from typing import Iterator, Optional +from typing import Any, Iterator, Optional -branch_regex = re.compile( - r"^(?P\w+)=(?P\w{20})$", flags=re.MULTILINE +from project.errors import FilesDoNotMatchError + +BRANCH_REGEX = re.compile( + r"^" r"(?P\w+)" r"=" r"(?P\w{20})" r"$", + flags=re.MULTILINE, +) + + +PARENT_ID_REGEX = re.compile( + r"^parent = " r"(?P\w{20})" r"(, (?P\w{20}))" r"?$", + flags=re.MULTILINE, ) def get_repository_path(path: Path) -> Optional[Path]: if path.is_dir(): - if glob(str(path / ".wit")): + if set(path.glob(".wit")): return path for directory in path.parents: - if glob(str(directory / ".wit")): + if set(directory.glob(".wit")): return directory return None def get_commit_id_of_branch( - repository: Path, branch: str, references_file: Path + repository: Path, + branch: str, + references_file: Path, ) -> str: - branches_commits_dict = get_branches_commits(references_file) + branches_commits_dict = get_commits_by_branches(references_file) if branch in branches_commits_dict: return branches_commits_dict[branch] if branch in list(get_all_commits(repository)): @@ -37,14 +47,11 @@ def get_all_commits(repository: Path) -> Iterator[str]: yield file_name.name -def get_branches_commits(references_file: Path) -> dict[str, str]: +def get_commits_by_branches(references_file: Path) -> dict[str, str]: with references_file.open() as file: branches_data = file.read() - branches_commits = {} - branch_matches = branch_regex.findall(branches_data) - for branch_name, commit_id in branch_matches: - branches_commits[branch_name] = commit_id - return branches_commits + branch_matches = BRANCH_REGEX.findall(branches_data) + return dict(branch_matches) def get_head_reference(repository: Path) -> str: @@ -80,25 +87,63 @@ def get_all_files_in_repository_and_subs(repository: Path) -> Iterator[Path]: yield Path(root).relative_to(repository) -def get_wit_dir(repository: Path) -> Path: +def get_wit_path(repository: Path) -> Path: return repository / ".wit" -def get_staging_area(repository: Path) -> Path: - return get_wit_dir(repository) / "staging_area" +def get_staging_area_path(repository: Path) -> Path: + return get_wit_path(repository) / "staging_area" def get_references_path(repository: Path) -> Path: - return get_wit_dir(repository) / "references.txt" + return get_wit_path(repository) / "references.txt" def get_images_path(repository: Path) -> Path: - return get_wit_dir(repository) / "images" + return get_wit_path(repository) / "images" -def get_commit_path(repository: Path, commit_id: str): +def get_commit_path(repository: Path, commit_id: str) -> Path: return get_images_path(repository) / commit_id def get_activated_path(repository: Path) -> Path: - return get_wit_dir(repository) / "activated.txt" + return get_wit_path(repository) / "activated.txt" + + +def check_if_file_changed(file_path: Path, dir_1: Path, dir_2: Path) -> bool: + content_in_dir_1 = (dir_1 / file_path).read_text() + content_in_dir_2 = (dir_2 / file_path).read_text() + return content_in_dir_1 != content_in_dir_2 + + +def get_changes_to_be_committed(repository: Path) -> Optional[Iterator[Path]]: + staging_area_path = get_staging_area_path(repository) + last_commit_id = get_head_reference(repository) + files_in_staging_area = get_all_files_in_directory_and_subs(staging_area_path) + if not last_commit_id: + return None + commit_path = get_commit_path(repository, last_commit_id) + for file_path in files_in_staging_area: + files_in_last_commit_that_match_file_path = commit_path.glob(str(file_path)) + if not set(files_in_last_commit_that_match_file_path): + yield file_path + elif file_path.is_file(): + if check_if_file_changed(file_path, staging_area_path, commit_path): + yield file_path + + +def get_changes_not_staged_for_commit(repository: Path) -> Optional[Iterator[Path]]: + staging_area_path = get_staging_area_path(repository) + files_in_staging_area = get_all_files_in_directory_and_subs(staging_area_path) + for file_path in files_in_staging_area: + if file_path.is_file(): + if check_if_file_changed(file_path, staging_area_path, repository): + yield file_path + + +def raise_for_unsaved_work(repository: Path) -> None: + files_added_since_last_commit = set(get_changes_to_be_committed(repository)) + changed_files_since_last_commit = set(get_changes_not_staged_for_commit(repository)) + if files_added_since_last_commit or changed_files_since_last_commit: + raise FilesDoNotMatchError("There are files added or changed since last commit") diff --git a/tests/conftest.py b/tests/conftest.py index a80e8f6..31af5b6 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,7 +5,7 @@ from project.add import add_function from project.commit import commit_function from project.init import init_function -from project.utils import get_staging_area +from project.utils import get_staging_area_path @pytest.fixture() @@ -67,6 +67,6 @@ def add_new_file_and_commit(folder): def get_file_path_in_staging_area(file_path, folder): - staging_area = get_staging_area(folder) + staging_area = get_staging_area_path(folder) path_in_staging_area = staging_area / file_path.relative_to(folder) return path_in_staging_area diff --git a/tests/test_branch.py b/tests/test_branch.py index 9d83bfa..7b44edf 100644 --- a/tests/test_branch.py +++ b/tests/test_branch.py @@ -3,7 +3,7 @@ import pytest from project.branch import branch_function -from project.errors import BranchExistsError, WitError +from project.errors import BranchExistsError, BranchNotCreatedError, WitError from project.utils import get_head_reference, get_references_path from tests.conftest import change_add_and_commit_file @@ -28,3 +28,8 @@ def test_branch_exists_error(test_folder, file2): branch_function("TestBranch") with pytest.raises(BranchExistsError): branch_function("TestBranch") + + +def test_branch_not_created_error(test_folder): + with pytest.raises(BranchNotCreatedError): + branch_function("branch") diff --git a/tests/test_graph.py b/tests/test_graph.py index 741dd8c..5c3e735 100644 --- a/tests/test_graph.py +++ b/tests/test_graph.py @@ -11,7 +11,7 @@ get_commit_id_of_branch, get_head_reference, get_references_path, - get_wit_dir, + get_wit_path, ) from tests.conftest import change_add_and_commit_file @@ -34,7 +34,7 @@ def test_graph_function(test_folder, file1, file3): branch_commit_id = get_commit_id_of_branch(test_folder, "branch1", references_file) dot_source = graph_function() current_commit_id = get_head_reference(test_folder) - wit_dir = get_wit_dir(test_folder) + wit_dir = get_wit_path(test_folder) commits_in_graph = get_commits_in_graph( branch_commit_id, current_commit_id, test_folder ) diff --git a/tests/test_init.py b/tests/test_init.py index d81b816..e217d6d 100644 --- a/tests/test_init.py +++ b/tests/test_init.py @@ -7,16 +7,16 @@ from project.utils import ( get_activated_path, get_images_path, - get_staging_area, - get_wit_dir, + get_staging_area_path, + get_wit_path, ) def test_wit_dir(test_folder): - wit_path = get_wit_dir(test_folder) + wit_path = get_wit_path(test_folder) assert wit_path.is_dir() assert get_images_path(test_folder).is_dir() - assert get_staging_area(test_folder).is_dir() + assert get_staging_area_path(test_folder).is_dir() assert get_activated_path(test_folder).read_text() == "master" diff --git a/tests/test_status.py b/tests/test_status.py index e9edaa4..14396b7 100644 --- a/tests/test_status.py +++ b/tests/test_status.py @@ -8,7 +8,7 @@ from project.utils import ( get_all_files_in_directory_and_subs, get_all_files_in_repository_and_subs, - get_staging_area, + get_staging_area_path, ) from tests.conftest import change_add_and_commit_file @@ -31,7 +31,7 @@ def test_status(test_folder, file1, file3): ) = status_function() assert set(changes_to_be_committed) == {file3.relative_to(test_folder)} assert set(changes_not_staged_for_commit) == {file1.relative_to(test_folder)} - staging_area = get_staging_area(test_folder) + staging_area = get_staging_area_path(test_folder) all_files = get_all_files_in_repository_and_subs(test_folder) files_in_staging_area = get_all_files_in_directory_and_subs(staging_area) assert set(untracked_files).union(set(files_in_staging_area)) == set(all_files) @@ -61,10 +61,3 @@ def test_commit_change_file_again_and_add(test_folder, file3): assert set(changes_to_be_committed) == {file3_name} assert not set(changes_not_staged_for_commit) assert file3_name not in set(untracked_files) - - -def test_delete_added_file(test_folder, file2): - change_add_and_commit_file(file2, "") - file2.unlink() - with pytest.raises(NotImplementedError): - status_function() From c40949d68e43099aadc814e52753ff51e3401669 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Date: Mon, 25 Apr 2022 22:27:20 +0300 Subject: [PATCH 68/73] fix files --- .coverage | Bin 53248 -> 53248 bytes project/commit.py | 2 +- project/init.py | 2 +- project/merge.py | 1 + project/utils.py | 14 +++++++++++--- 5 files changed, 14 insertions(+), 5 deletions(-) diff --git a/.coverage b/.coverage index c498aa58affa169b33aa7b08ebb8ad18d74a4cd4..da721f533e820f332e1afedb644171aa3cb9098b 100644 GIT binary patch delta 165 zcmZozz}&Eac>|jQS2P3vH2zlpO#bN2f&$+BlOyyM6ipS3jI4}ItxPQVnV6-;%TkMq zGxPJz^o;e4G8kE88(k;Q)R$3mEGTeEEJ=)s3Cd5*&CE-Wi3zAI$;i)x(Z-gWZ|Q%F zWBM#T`BI;ysKdYi|7w5!KllIH|GJ;g@BjJvf6jmY$qM~bh1(=Pp8x-|#_sv-`)AIa PvH5RbZ@2kGzl8$;C{ade delta 168 zcmZozz}&Eac>|jQR|Et9Wd0`pH2#Rqf&w1=lcV(&6ipNi46KYTtxU}LnV6-;%TkMq zGxPJz^o;e4vKd)q8@(sb(U(yzD9X=DO)e>pi7C%4iHGvQoS2xh)V#8on4HX{&A0Tw z#W6iMpM0s$QdHr8{r`P`>YvwtuHXOXbN;_S_2>SxPgdxkDt!Fo`Tsv_?4HlQf9A{? QoB#Iw&zU!$=(lhH0O5K@^Z)<= diff --git a/project/commit.py b/project/commit.py index af6a1b7..7a3117b 100644 --- a/project/commit.py +++ b/project/commit.py @@ -55,7 +55,7 @@ def create_commit_txt_file( txt_file = new_commit_path.with_suffix(".txt") txt_file.write_text( f"parent = {parent_head if parent_head else None}\n" - f'date = {datetime.datetime.now().strftime("%c")}\n' + f"date = {datetime.datetime.now().strftime('%c')}\n" f"message = {message}" ) diff --git a/project/init.py b/project/init.py index 27edd72..4eb8704 100644 --- a/project/init.py +++ b/project/init.py @@ -13,7 +13,7 @@ def init_function() -> None: cwd = Path.cwd() wit_path = get_wit_path(cwd) if wit_path.exists(): - raise WitExistsError("The folder already has .wit directory") + raise WitExistsError("The folder is already a wit directory.") wit_path.mkdir() images_path = get_images_path(cwd) images_path.mkdir() diff --git a/project/merge.py b/project/merge.py index 2b29174..1cc99df 100644 --- a/project/merge.py +++ b/project/merge.py @@ -18,6 +18,7 @@ raise_for_unsaved_work, ) + Paths = namedtuple("Paths", ["branch", "common", "staging_area", "repository"]) diff --git a/project/utils.py b/project/utils.py index 6d33cef..374b2fd 100644 --- a/project/utils.py +++ b/project/utils.py @@ -1,18 +1,26 @@ import os import re from pathlib import Path -from typing import Any, Iterator, Optional +from typing import Iterator, Optional from project.errors import FilesDoNotMatchError + BRANCH_REGEX = re.compile( - r"^" r"(?P\w+)" r"=" r"(?P\w{20})" r"$", + r"^" + r"(?P\w+)" + r"=" + r"(?P\w{20})" + r"$", flags=re.MULTILINE, ) PARENT_ID_REGEX = re.compile( - r"^parent = " r"(?P\w{20})" r"(, (?P\w{20}))" r"?$", + r"^parent = " + r"(?P\w{20})" + r"(, (?P\w{20}))" + r"?$", flags=re.MULTILINE, ) From f50cf1e45374c6dc16cfe8a23885ba0ee0a69154 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Milano <97195051+RuthMahallaMilano@users.noreply.github.com> Date: Wed, 27 Apr 2022 13:44:44 +0300 Subject: [PATCH 69/73] Create README.md --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..60b8bac --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +# Wit + +Wit is a program that allows you to create backups of text files and folders, similar to Git. + +In order to run the software, the following steps must be performed: +1. git clone the repo +2. create a vitrual environnment +3. install the requirements fron requirenents.txt file +4. install the packeges of the project by "pip install -e ." +5. go to the folder you want to set as a Wit repository +6. to start a repository, run "python \wit\project\wit.py init" +7. you can always run "python \wit\project\wit.py -- help" to see all possible commands From f8050b24ad7ac15a37ba6f92d8c5b29c2dcac699 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Milano <97195051+RuthMahallaMilano@users.noreply.github.com> Date: Wed, 27 Apr 2022 13:45:19 +0300 Subject: [PATCH 70/73] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 60b8bac..255f80b 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Wit is a program that allows you to create backups of text files and folders, similar to Git. -In order to run the software, the following steps must be performed: +In order to run Wit, the following steps must be performed: 1. git clone the repo 2. create a vitrual environnment 3. install the requirements fron requirenents.txt file From f48c2cf1447de5eb155f1e05276a7030f77929bc Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Milano <97195051+RuthMahallaMilano@users.noreply.github.com> Date: Wed, 27 Apr 2022 13:46:18 +0300 Subject: [PATCH 71/73] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 255f80b..da27fb7 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Wit is a program that allows you to create backups of text files and folders, similar to Git. -In order to run Wit, the following steps must be performed: +In order to run Wit, the follow the next steps: 1. git clone the repo 2. create a vitrual environnment 3. install the requirements fron requirenents.txt file From b735ae5454328ad90cd5ca700f5009b56b994f57 Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Milano <97195051+RuthMahallaMilano@users.noreply.github.com> Date: Mon, 16 May 2022 00:40:18 +0300 Subject: [PATCH 72/73] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index da27fb7..1ac5069 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # Wit -Wit is a program that allows you to create backups of text files and folders, similar to Git. +Wit is a version control system that simulates Git's behavior, which includes commands such as add, branch, commit, status, and checkout. I also implemented a basic merge and graph, which is a kind of graphical log. In order to run Wit, the follow the next steps: 1. git clone the repo 2. create a vitrual environnment 3. install the requirements fron requirenents.txt file -4. install the packeges of the project by "pip install -e ." -5. go to the folder you want to set as a Wit repository +4. install the packeges of the project (using "pip install -e .") +5. go to the folder you want to beckup and set as a Wit repository 6. to start a repository, run "python \wit\project\wit.py init" 7. you can always run "python \wit\project\wit.py -- help" to see all possible commands From 3960fbca4ed9757e271e9b706e0f5017f30ac93b Mon Sep 17 00:00:00 2001 From: Ruth Mahalla Milano <97195051+RuthMahallaMilano@users.noreply.github.com> Date: Sat, 21 May 2022 22:40:04 +0300 Subject: [PATCH 73/73] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1ac5069..27f599d 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Wit is a version control system that simulates Git's behavior, which includes commands such as add, branch, commit, status, and checkout. I also implemented a basic merge and graph, which is a kind of graphical log. -In order to run Wit, the follow the next steps: +In order to run Wit, follow the next steps: 1. git clone the repo 2. create a vitrual environnment 3. install the requirements fron requirenents.txt file