[meld: 1/2] vc: Add a refactored CVS plugin (#170)
- From: Kai Willadsen <kaiw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [meld: 1/2] vc: Add a refactored CVS plugin (#170)
- Date: Sun, 21 Jul 2019 07:54:49 +0000 (UTC)
commit cc9d23f0fe9d0d542d425cf66209f27c75fceaab
Author: gitqlt <vcsqlt gmail com>
Date: Sun Jul 21 07:54:35 2019 +0000
vc: Add a refactored CVS plugin (#170)
The new plugin is based on the existing Mercurial support.
README.md | 2 +-
maint | 2 +-
meld/vc/__init__.py | 4 +-
meld/vc/cvs.py | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 164 insertions(+), 4 deletions(-)
---
diff --git a/README.md b/README.md
index 1ae0af55..8d0f6aed 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@ About Meld
Meld is a visual diff and merge tool targeted at developers. Meld helps you
compare files, directories, and version controlled projects. It provides
two- and three-way comparison of both files and directories, and supports
-many version control systems including Git, Mercurial, Bazaar and Subversion.
+many version control systems including Git, Mercurial, Bazaar, CVS and Subversion.
Meld helps you review code changes, understand patches, and makes enormous
merge conflicts slightly less painful.
diff --git a/maint b/maint
index 31ad25f0..72db0370 100755
--- a/maint
+++ b/maint
@@ -97,7 +97,7 @@ Meld is a visual diff and merge tool. It lets you compare two or three files,
and updates the comparisons while you edit them in-place. You can also compare
folders, launching comparisons of individual files as desired. Last but by no
means least, Meld lets you work with your current changes in a wide variety of
-version control systems, including Git, Bazaar, Mercurial and Subversion.
+version control systems, including Git, Bazaar, Mercurial, CVS and Subversion.
"""
diff --git a/meld/vc/__init__.py b/meld/vc/__init__.py
index 07e7caab..43d35ca4 100644
--- a/meld/vc/__init__.py
+++ b/meld/vc/__init__.py
@@ -22,11 +22,11 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-from . import bzr, darcs, git, mercurial, svn
+from . import bzr, cvs, darcs, git, mercurial, svn
# Tuple of plugins, ordered according to best-guess as to which VC a
# user is likely to want by default in a multiple-VC situation.
-VC_PLUGINS = (git, mercurial, bzr, svn, darcs)
+VC_PLUGINS = (git, mercurial, bzr, svn, darcs, cvs)
def get_vcs(location):
diff --git a/meld/vc/cvs.py b/meld/vc/cvs.py
new file mode 100644
index 00000000..b4c3c96c
--- /dev/null
+++ b/meld/vc/cvs.py
@@ -0,0 +1,160 @@
+# -*- coding: utf-8 -*-
+# Copyright (C) 2002-2005 Stephen Kennedy <stevek gnome org>
+# Copyright (C) 2015 Kai Willadsen <kai willadsen gmail com>
+
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import errno
+import os
+import shutil
+
+from . import _vc
+
+
+class Vc(_vc.Vc):
+
+ # CVSNT is a drop-in replacement for CVS; if found, it is used instead
+ CMD = "cvsnt" if shutil.which("cvsnt") else "cvs"
+ NAME = "CVS"
+ VC_DIR = "CVS"
+ VC_ROOT_WALK = False
+
+ # According to the output of the 'status' command
+ state_map = {
+ "Unknown": _vc.STATE_NONE,
+ "Locally Added": _vc.STATE_NEW,
+ "Up-to-date": _vc.STATE_NORMAL,
+ "!": _vc.STATE_MISSING,
+ "I": _vc.STATE_IGNORED,
+ "Locally Modified": _vc.STATE_MODIFIED,
+ "Locally Removed": _vc.STATE_REMOVED
+ }
+
+ def commit(self, runner, files, message):
+ command = [self.CMD, 'commit', '-m', message]
+ runner(command, files, refresh=True, working_dir=self.root)
+
+ def update(self, runner):
+ command = [self.CMD, 'update']
+ runner(command, [], refresh=True, working_dir=self.root)
+
+ def add(self, runner, afiles):
+ # CVS needs to add files together with all the parents
+ # (if those are Unversioned yet)
+ relfiles = [os.path.relpath(s, self.root)
+ for s in afiles if os.path.isfile(s)]
+ command = [self.CMD, 'add']
+
+ relargs = []
+ for f1 in relfiles:
+ positions = [i for i, ch in enumerate(f1+os.sep) if ch == os.sep]
+ arg1 = [f1[:pos] for pos in positions]
+ relargs += arg1
+
+ absargs = [os.path.join(self.root, a1) for a1 in relargs]
+ runner(command, absargs, refresh=True, working_dir=self.root)
+
+ def remove(self, runner, files):
+ command = [self.CMD, 'remove', '-f']
+ runner(command, files, refresh=True, working_dir=self.root)
+
+ def revert(self, runner, files):
+ command = [self.CMD, 'update', '-C']
+ runner(command, files, refresh=True, working_dir=self.root)
+
+ @classmethod
+ def valid_repo(cls, path):
+ return not _vc.call([cls.CMD, 'ls'], cwd=path)
+
+ def get_path_for_repo_file(self, path, commit=None):
+ if commit is not None:
+ raise NotImplementedError()
+
+ if not path.startswith(self.root + os.path.sep):
+ raise _vc.InvalidVCPath(self, path, "Path not in repository")
+ path = path[len(self.root) + 1:]
+
+ args = [self.CMD, "-q", "update", "-p", path]
+ return _vc.call_temp_output(args, cwd=self.root)
+
+ def _find_files(self, path):
+ relfiles = []
+ loc = os.path.join(self.location, path)
+ for step in os.walk(loc):
+ if not step[0].endswith(self.VC_DIR):
+ ff = [os.path.join(step[0], f1) for f1 in step[2]]
+ relfiles += [os.path.relpath(ff1, loc) for ff1 in ff]
+ return relfiles
+
+ def _update_tree_state_cache(self, path):
+ """ Update the state of the file(s) at self._tree_cache['path'] """
+ while 1:
+ try:
+ # Get the status of files
+
+ path_isdir = os.path.isdir(path)
+ files = self._find_files(path) if path_isdir else [path]
+
+ # Should suppress stderr here
+ proc = _vc.popen([self.CMD, "-Q", "status"] + files,
+ cwd=self.location)
+ entries = [li for li in proc.read().splitlines()
+ if li.startswith('File:')]
+ break
+ except OSError as e:
+ if e.errno != errno.EAGAIN:
+ raise
+
+ if len(entries) == 0 and os.path.isfile(path):
+ # If we're just updating a single file there's a chance that
+ # it was previously modified, and now has been edited so that
+ # it is un-modified. This will result in an empty 'entries' list,
+ # and self._tree_cache['path'] will still contain stale data.
+ # When this corner case occurs we force self._tree_cache['path']
+ # to STATE_NORMAL.
+ self._tree_cache[path] = _vc.STATE_NORMAL
+ else:
+ # There are 1 or more [modified] files, parse their state
+ for entry in zip(files, entries):
+ statekey = entry[1].split(':')[-1].strip()
+ name = entry[0].strip()
+
+ if os.path.basename(name) not in entry[1]:
+ # ? The short filename got from
+ # 'cvs -Q status <path/file>' does not match <file>
+ raise
+
+ path = os.path.join(self.location, name)
+ state = self.state_map.get(statekey, _vc.STATE_NONE)
+ self._tree_cache[path] = state
+ self._add_missing_cache_entry(path, state)
+
+ """
+ # Setting the state of dirs also might be relevant, but not sure
+ # Heuristic to find out the state ('CVS' subdir exists or not)
+ for entry in zip(dirs, [os.path.isdir(os.path.join(d1, self.VC_DIR))
+ for d1 in dirs]):
+ path = os.path.join(self.location, entry[0])
+ state = _vc.STATE_NORMAL if entry[1] else _vc.STATE_NONE
+ self._tree_cache[path] = state
+ self._add_missing_cache_entry(path, state)
+ """
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]