Source code for evariste.plugins.vcs
# Copyright Louis Paternault 2015-2022
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Access to VCS (git, etc.) versionned files.
Every path processed here is a :class:`pathlib.Path` object.
.. autoclass:: VCS
:members:
:special-members: __contains__
"""
import abc
import os
import pathlib
import typing
from datetime import datetime
from ...errors import EvaristeError
from ...tree import Root
from .. import Plugin
class NoRepositoryError(EvaristeError):
"""No repository contains the given path."""
def __init__(self, vcstype, directory):
super().__init__()
self.directory = directory
self.vcstype = vcstype
def __str__(self):
# pylint: disable=line-too-long
return f"Could not find any {self.vcstype} repository containing directory '{self.directory}'."
[docs]
class VCS(Plugin, metaclass=abc.ABCMeta):
"""Generic class to access to versionned files.
To write a new VCS plugin, one has to subclass this class, and implement every abstract method
(see for instance the implementation of :class:`evariste.plugin.vcs.git.Git`).
"""
plugin_type = "vcs"
global_default_setup = {"setup": {"source": "."}}
@property
def source(self) -> pathlib.Path:
"""Return an absolute version of source setup option."""
return pathlib.Path(self.shared.setup["setup"]["source"]).resolve()
[docs]
@abc.abstractmethod
def walk(self) -> typing.Iterable[pathlib.Path]:
"""Iterate versionned files, descendants of source (as defined by setup file)."""
raise NotImplementedError()
[docs]
@abc.abstractmethod
def __contains__(self, path: pathlib.Path) -> bool:
"""Return ``True`` iff ``path`` is versionned."""
raise NotImplementedError()
@property
@abc.abstractmethod
def workdir(self) -> pathlib.Path:
"""Return path of the root of the repository."""
raise NotImplementedError()
[docs]
def from_repo(self, path: pathlib.Path) -> pathlib.Path:
"""Return ``path``, relative to the repository root."""
return path.resolve().relative_to(self.workdir)
[docs]
def last_modified(self, path: pathlib.Path) -> datetime:
"""Return the datetime of last modification."""
return datetime.fromtimestamp(os.path.getmtime(path.as_posix()))