Source code for wxyz.dvcs.repos.repo_base
""" base DVCS repository widgets
"""
from concurrent.futures import ThreadPoolExecutor
# pylint: disable=no-member
from pathlib import Path
import ipywidgets as W
import traitlets as T
from tornado.ioloop import IOLoop
from ..trackers.tracker_base import Tracker
from ..widget_watch import Watcher
class Remote(W.Widget):
"""a remote DVCS repository"""
name = T.Unicode()
url = T.Unicode()
heads = T.Dict(value_trait=T.Unicode(), default_value=tuple())
auto_fetch = T.Bool(True)
executor = ThreadPoolExecutor(max_workers=1)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.auto_fetch:
self._on_auto_fetch()
async def fetch(self):
"""fetch from the remote"""
await self._fetch()
self.heads = await self._update_heads()
async def push(self, ref):
"""push to the remote"""
await self._push(ref)
@T.observe("auto_fetch")
def _on_auto_fetch(self, _change=None):
"""handle changing the auto fetch preference"""
if self.auto_fetch:
IOLoop.current().add_callback(self.fetch)
[docs]class Repo(W.Widget):
"""base class for a DVCS repo"""
executor = ThreadPoolExecutor(max_workers=1)
# pylint: disable=unused-argument
working_dir = T.Instance(Path)
url = T.Unicode()
watching = T.Bool(default_value=False)
dirty = T.Bool(default_value=False)
changes = T.Tuple(allow_none=True)
head = T.Unicode(help="the symbolic name of the current head")
head_hash = T.Unicode(help="the full hash of the current head")
head_history = T.Tuple()
remotes = T.Dict(value_trait=T.Instance(Remote), default_value=tuple())
_remote_cls = Remote
heads = T.Dict(value_trait=T.Unicode(), default_value=tuple())
_watcher = T.Instance(Watcher, allow_none=True)
_trackers = W.trait_types.TypedTuple(T.Instance(Tracker), default_value=tuple())
_change_link = None
def __init__(self, working_dir, *args, **kwargs):
kwargs["working_dir"] = Path(kwargs.get("working_dir", working_dir))
super().__init__(*args, **kwargs)
T.dlink((self, "working_dir"), (self, "url"), lambda p: p.resolve().as_uri())
@T.default("changes")
def _default_changes(self):
"""nothing should have changed by default"""
return tuple()
@T.observe("watching", "path")
def _on_watching(self, change):
"""react to the watch state (or path) changing"""
if self._watcher:
if self._change_link:
self._change_link.unlink()
self._change_link = None
self._watcher.watching = False
self._watcher = None
if self.watching:
self._watcher = Watcher(self.working_dir)
self._change_link = T.dlink(
(self._watcher, "changes"), (self, "changes"), self._on_watch_changes
)
self._watcher.watching = True
def _on_watch_changes(self, changes):
"""react to changes from the watcher"""
self.log.warn("changes %s", changes)
return changes
[docs] def track(self, **kwargs):
"""create a tracker for the given widget"""
assert self.working_dir.exists()
kwargs["path"] = Path(self.working_dir / kwargs["path"])
tracker_cls = kwargs.pop("tracker_cls", None)
if tracker_cls is None:
tracker_cls = Tracker.detect_tracker(kwargs["path"])
assert tracker_cls is not None
tracker = tracker_cls(**kwargs)
self._trackers += (tracker,)
return tracker
[docs] def add_remote(self, name, url, **kwargs):
"""add a new reference to a remote repository"""
self._update_remotes()
remotes = dict(self.remotes)
old_remote = remotes.get(name)
if old_remote is None:
remotes[name] = self._remote_cls(local=self, name=name, url=url, **kwargs)
else:
old_remote.url = url
self.remotes = remotes