mercurial/vfs.py
changeset 51884 f79f98733a5b
parent 51883 1edac12af730
child 51885 adbb183c2f27
equal deleted inserted replaced
51883:1edac12af730 51884:f79f98733a5b
     5 # This software may be used and distributed according to the terms of the
     5 # This software may be used and distributed according to the terms of the
     6 # GNU General Public License version 2 or any later version.
     6 # GNU General Public License version 2 or any later version.
     7 
     7 
     8 from __future__ import annotations
     8 from __future__ import annotations
     9 
     9 
       
    10 import abc
    10 import contextlib
    11 import contextlib
    11 import os
    12 import os
    12 import shutil
    13 import shutil
    13 import stat
    14 import stat
    14 import threading
    15 import threading
    44         # advance mtime (see issue5418)
    45         # advance mtime (see issue5418)
    45         util.rename(util.mktempcopy(path), path)
    46         util.rename(util.mktempcopy(path), path)
    46         checkandavoid()
    47         checkandavoid()
    47 
    48 
    48 
    49 
    49 class abstractvfs:
    50 class abstractvfs(abc.ABC):
    50     """Abstract base class; cannot be instantiated"""
    51     """Abstract base class; cannot be instantiated"""
    51 
    52 
    52     # default directory separator for vfs
    53     # default directory separator for vfs
    53     #
    54     #
    54     # Other vfs code always use `/` and this works fine because python file API
    55     # Other vfs code always use `/` and this works fine because python file API
    55     # abstract the use of `/` and make it work transparently. For consistency
    56     # abstract the use of `/` and make it work transparently. For consistency
    56     # vfs will always use `/` when joining. This avoid some confusion in
    57     # vfs will always use `/` when joining. This avoid some confusion in
    57     # encoded vfs (see issue6546)
    58     # encoded vfs (see issue6546)
    58     _dir_sep = b'/'
    59     _dir_sep = b'/'
    59 
    60 
    60     def __init__(self, *args, **kwargs):
       
    61         '''Prevent instantiation; don't call this from subclasses.'''
       
    62         raise NotImplementedError('attempted instantiating ' + str(type(self)))
       
    63 
       
    64     # TODO: type return, which is util.posixfile wrapped by a proxy
    61     # TODO: type return, which is util.posixfile wrapped by a proxy
       
    62     @abc.abstractmethod
    65     def __call__(self, path: bytes, mode: bytes = b'rb', **kwargs):
    63     def __call__(self, path: bytes, mode: bytes = b'rb', **kwargs):
    66         raise NotImplementedError
    64         ...
    67 
    65 
       
    66     @abc.abstractmethod
    68     def _auditpath(self, path: bytes, mode: bytes):
    67     def _auditpath(self, path: bytes, mode: bytes):
    69         raise NotImplementedError
    68         ...
    70 
    69 
       
    70     @abc.abstractmethod
    71     def join(self, path: Optional[bytes], *insidef: bytes) -> bytes:
    71     def join(self, path: Optional[bytes], *insidef: bytes) -> bytes:
    72         raise NotImplementedError
    72         ...
    73 
    73 
    74     def tryread(self, path: bytes) -> bytes:
    74     def tryread(self, path: bytes) -> bytes:
    75         '''gracefully return an empty string for missing files'''
    75         '''gracefully return an empty string for missing files'''
    76         try:
    76         try:
    77             return self.read(path)
    77             return self.read(path)
   623 
   623 
   624 
   624 
   625 opener = vfs
   625 opener = vfs
   626 
   626 
   627 
   627 
   628 class proxyvfs(abstractvfs):
   628 class proxyvfs(abstractvfs, abc.ABC):
   629     def __init__(self, vfs: "vfs"):
   629     def __init__(self, vfs: "vfs"):
   630         self.vfs = vfs
   630         self.vfs = vfs
   631 
   631 
   632     @property
   632     @property
   633     def createmode(self):
   633     def createmode(self):
   682 
   682 
   683     def join(self, path: Optional[bytes], *insidef: bytes) -> bytes:
   683     def join(self, path: Optional[bytes], *insidef: bytes) -> bytes:
   684         return self.vfs.join(path, *insidef)
   684         return self.vfs.join(path, *insidef)
   685 
   685 
   686 
   686 
   687 class closewrapbase:
   687 class closewrapbase(abc.ABC):
   688     """Base class of wrapper, which hooks closing
   688     """Base class of wrapper, which hooks closing
   689 
   689 
   690     Do not instantiate outside of the vfs layer.
   690     Do not instantiate outside of the vfs layer.
   691     """
   691     """
   692 
   692 
   704 
   704 
   705     def __enter__(self):
   705     def __enter__(self):
   706         self._origfh.__enter__()
   706         self._origfh.__enter__()
   707         return self
   707         return self
   708 
   708 
       
   709     @abc.abstractmethod
   709     def __exit__(self, exc_type, exc_value, exc_tb):
   710     def __exit__(self, exc_type, exc_value, exc_tb):
   710         raise NotImplementedError('attempted instantiating ' + str(type(self)))
   711         ...
   711 
   712 
       
   713     @abc.abstractmethod
   712     def close(self):
   714     def close(self):
   713         raise NotImplementedError('attempted instantiating ' + str(type(self)))
   715         ...
   714 
   716 
   715 
   717 
   716 class delayclosedfile(closewrapbase):
   718 class delayclosedfile(closewrapbase):
   717     """Proxy for a file object whose close is delayed.
   719     """Proxy for a file object whose close is delayed.
   718 
   720