Mercurial > public > mercurial-scm > hg-stable
view mercurial/interfaces/dirstate.py @ 51959:b455dfddfed0
interfaces: convert the zope `Attribute` attrs to regular fields
At this point, we should have a useful protocol class.
The file syntax requires the type to be supplied for any fields that are
declared, but we'll leave the complex ones partially unspecified for now, for
simplicity. (Also, the things documented as `Callable` are really as future
type annotating worked showed- roll with it for now, but they're marked as TODO
for fixing later.) All of the fields and all of the attrs will need type
annotations, or the type rules say they are considered to be `Any`. That can be
done in a separate pass, possibly applying the `dirstate.pyi` file generated
from the concrete class.
The first cut of this turned the `interfaceutil.Attribute` fields into plain
fields, and thus the types on them. PyCharm flagged a few things as having
incompatible signatures when the concrete dirstate class subclassed this, when
the concrete class has them declared as `@property`. So they've been changed to
`@property` here in those cases. The remaining fields that are decorated in the
concrete class have comments noting the differences. We'll see if they need to
be changed going forward, but leave them for now. We'll be in trouble if the
`@util.propertycache` is needed, because we can't import that module here at
runtime, due to circular imports.
author | Matt Harbison <matt_harbison@yahoo.com> |
---|---|
date | Thu, 26 Sep 2024 18:15:36 -0400 |
parents | 13aa17512583 |
children | 3688a984134b |
line wrap: on
line source
from __future__ import annotations import contextlib import typing from typing import ( Callable, Protocol, ) if typing.TYPE_CHECKING: # Almost all mercurial modules are only imported in the type checking phase # to avoid circular imports from .. import ( match as matchmod, ) class idirstate(Protocol): # TODO: convert these constructor args to fields? # def __init__( # self, # opener, # ui, # root, # validate, # sparsematchfn, # nodeconstants, # use_dirstate_v2, # use_tracked_hint=False, # ): # """Create a new dirstate object. # # opener is an open()-like callable that can be used to open the # dirstate file; root is the root of the directory tracked by # the dirstate. # """ # TODO: all these private methods and attributes should be made # public or removed from the interface. # TODO: decorate with `@rootcache(b'.hgignore')` like dirstate class? _ignore: matchmod.basematcher """Matcher for ignored files.""" @property def is_changing_any(self) -> bool: """True if any changes in progress.""" @property def is_changing_parents(self) -> bool: """True if parents changes in progress.""" @property def is_changing_files(self) -> bool: """True if file tracking changes in progress.""" def _ignorefiles(self): """Return a list of files containing patterns to ignore.""" def _ignorefileandline(self, f): """Given a file `f`, return the ignore file and line that ignores it.""" # TODO: decorate with `@util.propertycache` like dirstate class? # (can't because circular import) # TODO: The doc looks wrong- the core class has this as a @property, not a # callable. _checklink: Callable """Callable for checking symlinks.""" # TODO: decorate with `@util.propertycache` like dirstate class? # (can't because circular import) # TODO: The doc looks wrong- the core class has this as a @property, not a # callable. _checkexec: Callable """Callable for checking exec bits.""" @contextlib.contextmanager def changing_parents(self, repo): """Context manager for handling dirstate parents. If an exception occurs in the scope of the context manager, the incoherent dirstate won't be written when wlock is released. """ @contextlib.contextmanager def changing_files(self, repo): """Context manager for handling dirstate files. If an exception occurs in the scope of the context manager, the incoherent dirstate won't be written when wlock is released. """ def hasdir(self, d): pass def flagfunc(self, buildfallback): """build a callable that returns flags associated with a filename The information is extracted from three possible layers: 1. the file system if it supports the information 2. the "fallback" information stored in the dirstate if any 3. a more expensive mechanism inferring the flags from the parents. """ def getcwd(self): """Return the path from which a canonical path is calculated. This path should be used to resolve file patterns or to convert canonical paths back to file paths for display. It shouldn't be used to get real file paths. Use vfs functions instead. """ def pathto(self, f, cwd=None): pass def get_entry(self, path): """return a DirstateItem for the associated path""" def __contains__(self, key): """Check if bytestring `key` is known to the dirstate.""" def __iter__(self): """Iterate the dirstate's contained filenames as bytestrings.""" def items(self): """Iterate the dirstate's entries as (filename, DirstateItem. As usual, filename is a bytestring. """ iteritems = items def parents(self): pass def p1(self): pass def p2(self): pass def branch(self): pass def setparents(self, p1, p2=None): """Set dirstate parents to p1 and p2. When moving from two parents to one, "merged" entries a adjusted to normal and previous copy records discarded and returned by the call. See localrepo.setparents() """ def setbranch(self, branch, transaction): pass def invalidate(self): """Causes the next access to reread the dirstate. This is different from localrepo.invalidatedirstate() because it always rereads the dirstate. Use localrepo.invalidatedirstate() if you want to check whether the dirstate has changed before rereading it.""" def copy(self, source, dest): """Mark dest as a copy of source. Unmark dest if source is None.""" def copied(self, file): pass def copies(self): pass def normalize(self, path, isknown=False, ignoremissing=False): """ normalize the case of a pathname when on a casefolding filesystem isknown specifies whether the filename came from walking the disk, to avoid extra filesystem access. If ignoremissing is True, missing path are returned unchanged. Otherwise, we try harder to normalize possibly existing path components. The normalized case is determined based on the following precedence: - version of name already stored in the dirstate - version of name stored on disk - version provided via command arguments """ def clear(self): pass def rebuild(self, parent, allfiles, changedfiles=None): pass def write(self, tr): pass def addparentchangecallback(self, category, callback): """add a callback to be called when the wd parents are changed Callback will be called with the following arguments: dirstate, (oldp1, oldp2), (newp1, newp2) Category is a unique identifier to allow overwriting an old callback with a newer callback. """ def walk(self, match, subrepos, unknown, ignored, full=True): """ Walk recursively through the directory tree, finding all files matched by match. If full is False, maybe skip some known-clean files. Return a dict mapping filename to stat-like object (either mercurial.osutil.stat instance or return value of os.stat()). """ def status(self, match, subrepos, ignored, clean, unknown): """Determine the status of the working copy relative to the dirstate and return a pair of (unsure, status), where status is of type scmutil.status and: unsure: files that might have been modified since the dirstate was written, but need to be read to be sure (size is the same but mtime differs) status.modified: files that have definitely been modified since the dirstate was written (different size or mode) status.clean: files that have definitely not been modified since the dirstate was written """ def matches(self, match): """ return files in the dirstate (in whatever state) filtered by match """ def verify(self, m1, m2, p1, narrow_matcher=None): """ check the dirstate contents against the parent manifest and yield errors """