From 423da8e34a694aea57e9bc2d78789a4fc2c296d7 Mon Sep 17 00:00:00 2001 From: devdanzin <74280297+devdanzin@users.noreply.github.com> Date: Thu, 28 Sep 2023 11:13:20 -0300 Subject: [PATCH 1/2] Add GitArchiver.is_data_outdated() and .get_file_contents() to support source annotation. --- src/wily/archivers/git.py | 30 ++++++++++++++++++++++++++++++ test/integration/test_archiver.py | 19 +++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/src/wily/archivers/git.py b/src/wily/archivers/git.py index 71e8b802..dedeed27 100644 --- a/src/wily/archivers/git.py +++ b/src/wily/archivers/git.py @@ -4,6 +4,7 @@ Implementation of the archiver API for the gitpython module. """ import logging +from pathlib import Path from typing import Any, Dict, List, Tuple import git.exc @@ -195,3 +196,32 @@ def find(self, search: str) -> Revision: modified_files=modified_files, deleted_files=deleted_files, ) + + def is_data_outdated(self, filename: str, key: str) -> bool: + """ + Check whether file contents match between revision and working directory. + + :param filename: The name of the file to check. + :param key: The revision to which compare file contents. + :return: Whether the working directory copy of the file is outdated. + """ + commit = self.repo.rev_parse(key) + filepath = str(Path(self.repo.working_dir) / filename) + diff = commit.diff(None, filepath) + return bool(diff and diff[0].change_type == "M") + + def get_file_contents(self, rev_key: str, filename: str) -> str: + """ + Get contents of a file in a given git revision. + + :param rev_key: The key for the revision at which to fetch the file. + :param filename: The name of the file for which to get the contents. + :return: The file contents. + """ + git_filename = filename.replace("\\", "/") + contents = self.repo.git.execute( + ["git", "show", f"{rev_key}:{git_filename}"], + as_process=False, + stdout_as_string=True, + ) + return str(contents) diff --git a/test/integration/test_archiver.py b/test/integration/test_archiver.py index 9c6e9274..53948509 100644 --- a/test/integration/test_archiver.py +++ b/test/integration/test_archiver.py @@ -1,6 +1,7 @@ import pathlib import pytest +from git.exc import GitCommandError from git.repo.base import Repo from git.util import Actor @@ -64,6 +65,24 @@ def test_git_end_to_end(tmpdir): assert (tmppath / "test.py").exists() + # Test that outdated file contents are detected + archiver2 = GitArchiver(config) + outdated = archiver2.is_data_outdated("test.py", "HEAD") + assert not outdated + with open(tmppath / "test.py", "w") as file2: + file2.write("print(2)") + outdated = archiver2.is_data_outdated("test.py", "HEAD") + assert outdated + + # Test that file contents can be fetched for different revisions + content = archiver2.get_file_contents("HEAD", "test.py") + assert content == "print(1)" + with pytest.raises(GitCommandError): + # Error if file is not known in revision + content = archiver2.get_file_contents("HEAD~1", "test.py") + content = archiver2.get_file_contents("HEAD~1", ".gitignore") + assert content == ".wily/" + def test_dirty_git(tmpdir): """Check that repository fails to initialise if unchecked files are in the repo""" From e32546185e21dd6d3a8768073ac4fbfaaf068595 Mon Sep 17 00:00:00 2001 From: devdanzin <74280297+devdanzin@users.noreply.github.com> Date: Thu, 28 Sep 2023 11:35:38 -0300 Subject: [PATCH 2/2] Fix unrelated typing issue. --- test/integration/test_archiver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/test_archiver.py b/test/integration/test_archiver.py index 53948509..8c300bc2 100644 --- a/test/integration/test_archiver.py +++ b/test/integration/test_archiver.py @@ -57,7 +57,7 @@ def test_git_end_to_end(tmpdir): and revisions[1].key not in commit2.name_rev ) - checkout = archiver.checkout(revisions[1], None) + checkout = archiver.checkout(revisions[1], {}) assert not (tmppath / "test.py").exists()