Convert VCSs and rename to VcsRegistry

This commit is contained in:
Romain Failliot 2021-11-18 14:37:42 -05:00
parent ab25807876
commit db36eee4e3
3 changed files with 229 additions and 195 deletions

View File

@ -53,16 +53,7 @@ from urllib.parse import urlparse
from diffuse import utils
from diffuse import constants
from diffuse.vcs.folder_set import FolderSet
from diffuse.vcs.bzr import Bzr
from diffuse.vcs.cvs import Cvs
from diffuse.vcs.darcs import Darcs
from diffuse.vcs.git import Git
from diffuse.vcs.hg import Hg
from diffuse.vcs.mtn import Mtn
from diffuse.vcs.rcs import Rcs
from diffuse.vcs.svk import Svk
from diffuse.vcs.svn import Svn
from diffuse.vcs.vcs_registry import VcsRegistry
if not hasattr(__builtins__, 'WindowsError'):
# define 'WindowsError' so 'except' statements will work on all platforms
@ -1192,191 +1183,7 @@ def convert_to_format(s, format):
s += '\r'
return s
# returns the Windows drive or share from a from an absolute path
def drive_from_path(s):
c = s.split(os.sep)
if len(c) > 3 and c[0] == '' and c[1] == '':
return os.path.join(c[:4])
return c[0]
# escape arguments for use with bash
def bashEscape(s):
return "'" + s.replace("'", "'\\''") + "'"
# utility method to help find folders used by version control systems
def _find_parent_dir_with(path, dir_name):
while True:
name = os.path.join(path, dir_name)
if os.path.isdir(name):
return path
newpath = os.path.dirname(path)
if newpath == path:
break
path = newpath
def _get_bzr_repo(path, prefs):
p = _find_parent_dir_with(path, '.bzr')
if p:
return Bzr(p)
def _get_cvs_repo(path, prefs):
if os.path.isdir(os.path.join(path, 'CVS')):
return Cvs(path)
def _get_darcs_repo(path, prefs):
p = _find_parent_dir_with(path, '_darcs')
if p:
return Darcs(p)
def _get_git_repo(path, prefs):
if 'GIT_DIR' in os.environ:
try:
d = path
ss = utils.popenReadLines(d, [ prefs.getString('git_bin'), 'rev-parse', '--show-prefix' ], prefs, 'git_bash')
if len(ss) > 0:
# be careful to handle trailing slashes
d = d.split(os.sep)
if d[-1] != '':
d.append('')
ss = strip_eol(ss[0]).split('/')
if ss[-1] != '':
ss.append('')
n = len(ss)
if n <= len(d):
del d[-n:]
if len(d) == 0:
d = os.curdir
else:
d = os.sep.join(d)
return Git(d)
except (IOError, OSError, WindowsError):
# working tree not found
pass
# search for .git directory (project) or .git file (submodule)
while True:
name = os.path.join(path, '.git')
if os.path.isdir(name) or os.path.isfile(name):
return Git(path)
newpath = os.path.dirname(path)
if newpath == path:
break
path = newpath
def _get_hg_repo(path, prefs):
p = _find_parent_dir_with(path, '.hg')
if p:
return Hg(p)
def _get_mtn_repo(path, prefs):
p = _find_parent_dir_with(path, '_MTN')
if p:
return Mtn(p)
def _get_rcs_repo(path, prefs):
if os.path.isdir(os.path.join(path, 'RCS')):
return Rcs(path)
# [rfailliot] this code doesn't seem to work, but was in 0.4.8 too.
# I'm letting it here until further tests are done, but it is possible
# this code never actually worked.
try:
for s in os.listdir(path):
if s.endswith(',v') and os.path.isfile(os.path.join(path, s)):
return Rcs(path)
except OSError:
# the user specified an invalid folder name
pass
def _get_svn_repo(path, prefs):
p = _find_parent_dir_with(path, '.svn')
if p:
return Svn(p)
def _get_svk_repo(path, prefs):
name = path
# parse the ~/.svk/config file to discover which directories are part of
# SVK repositories
if utils.isWindows():
name = name.upper()
svkroot = os.environ.get('SVKROOT', None)
if svkroot is None:
svkroot = os.path.expanduser('~/.svk')
svkconfig = os.path.join(svkroot, 'config')
if os.path.isfile(svkconfig):
try:
# find working copies by parsing the config file
f = open(svkconfig, 'r')
ss = readlines(f)
f.close()
projs, sep = [], os.sep
# find the separator character
for s in ss:
if s.startswith(' sep: ') and len(s) > 7:
sep = s[7]
# find the project directories
i = 0
while i < len(ss):
s = ss[i]
i += 1
if s.startswith(' hash: '):
while i < len(ss) and ss[i].startswith(' '):
s = ss[i]
i += 1
if s.endswith(': ') and i < len(ss) and ss[i].startswith(' depotpath: '):
key = s[4:-2].replace(sep, os.sep)
# parse directory path
j, n, tt = 0, len(key), []
while j < n:
if key[j] == '"':
# quoted string
j += 1
while j < n:
if key[j] == '"':
j += 1
break
elif key[j] == '\\':
# escaped character
j += 1
if j < n:
tt.append(key[j])
j += 1
else:
tt.append(key[j])
j += 1
key = ''.join(tt).replace(sep, os.sep)
if utils.isWindows():
key = key.upper()
projs.append(key)
break
# check if the file belongs to one of the project directories
if FolderSet(projs).contains(name):
return Svk(path)
except IOError:
utils.logError(_('Error parsing %s.') % (svkconfig, ))
class VCSs:
def __init__(self):
# initialise the VCS objects
self._get_repo = { 'bzr': _get_bzr_repo, 'cvs': _get_cvs_repo, 'darcs': _get_darcs_repo, 'git': _get_git_repo, 'hg': _get_hg_repo, 'mtn': _get_mtn_repo, 'rcs': _get_rcs_repo, 'svk': _get_svk_repo, 'svn': _get_svn_repo }
def setSearchOrder(self, ordering):
self._search_order = ordering
# determines which VCS to use for files in the named folder
def findByFolder(self, path, prefs):
path = os.path.abspath(path)
for vcs in prefs.getString('vcs_search_order').split():
if vcs in self._get_repo:
repo = self._get_repo[vcs](path, prefs)
if repo:
return repo
# determines which VCS to use for the named file
def findByFilename(self, name, prefs):
if name is not None:
return self.findByFolder(os.path.dirname(name), prefs)
theVCSs = VCSs()
theVCSs = VcsRegistry()
# utility method to step advance an adjustment
def step_adjustment(adj, delta):

View File

@ -104,6 +104,17 @@ def safeRelativePath(abspath1, name, prefs, cygwin_pref):
s = s.replace('/', '\\')
return s
# returns the Windows drive or share from a from an absolute path
def drive_from_path(s):
c = s.split(os.sep)
if len(c) > 3 and c[0] == '' and c[1] == '':
return os.path.join(c[:4])
return c[0]
# escape arguments for use with bash
def bashEscape(s):
return "'" + s.replace("'", "'\\''") + "'"
# use popen to read the output of a command
def popenRead(dn, cmd, prefs, bash_pref, success_results=None):
if success_results is None:

216
src/vcs/vcs_registry.py Normal file
View File

@ -0,0 +1,216 @@
# Diffuse: a graphical tool for merging and comparing text files.
#
# Copyright (C) 2019 Derrick Moser <derrick_moser@yahoo.com>
# Copyright (C) 2021 Romain Failliot <romain.failliot@foolstep.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
import os
from diffuse import utils
from diffuse.vcs.folder_set import FolderSet
from diffuse.vcs.bzr import Bzr
from diffuse.vcs.cvs import Cvs
from diffuse.vcs.darcs import Darcs
from diffuse.vcs.git import Git
from diffuse.vcs.hg import Hg
from diffuse.vcs.mtn import Mtn
from diffuse.vcs.rcs import Rcs
from diffuse.vcs.svk import Svk
from diffuse.vcs.svn import Svn
class VcsRegistry:
def __init__(self):
# initialise the VCS objects
self._get_repo = {
'bzr': _get_bzr_repo,
'cvs': _get_cvs_repo,
'darcs': _get_darcs_repo,
'git': _get_git_repo,
'hg': _get_hg_repo,
'mtn': _get_mtn_repo,
'rcs': _get_rcs_repo,
'svk': _get_svk_repo,
'svn': _get_svn_repo
}
def setSearchOrder(self, ordering):
self._search_order = ordering
# determines which VCS to use for files in the named folder
def findByFolder(self, path, prefs):
path = os.path.abspath(path)
for vcs in prefs.getString('vcs_search_order').split():
if vcs in self._get_repo:
repo = self._get_repo[vcs](path, prefs)
if repo:
return repo
# determines which VCS to use for the named file
def findByFilename(self, name, prefs):
if name is not None:
return self.findByFolder(os.path.dirname(name), prefs)
# utility method to help find folders used by version control systems
def _find_parent_dir_with(path, dir_name):
while True:
name = os.path.join(path, dir_name)
if os.path.isdir(name):
return path
newpath = os.path.dirname(path)
if newpath == path:
break
path = newpath
def _get_bzr_repo(path, prefs):
p = _find_parent_dir_with(path, '.bzr')
if p:
return Bzr(p)
def _get_cvs_repo(path, prefs):
if os.path.isdir(os.path.join(path, 'CVS')):
return Cvs(path)
def _get_darcs_repo(path, prefs):
p = _find_parent_dir_with(path, '_darcs')
if p:
return Darcs(p)
def _get_git_repo(path, prefs):
if 'GIT_DIR' in os.environ:
try:
d = path
ss = utils.popenReadLines(d, [ prefs.getString('git_bin'), 'rev-parse', '--show-prefix' ], prefs, 'git_bash')
if len(ss) > 0:
# be careful to handle trailing slashes
d = d.split(os.sep)
if d[-1] != '':
d.append('')
ss = strip_eol(ss[0]).split('/')
if ss[-1] != '':
ss.append('')
n = len(ss)
if n <= len(d):
del d[-n:]
if len(d) == 0:
d = os.curdir
else:
d = os.sep.join(d)
return Git(d)
except (IOError, OSError, WindowsError):
# working tree not found
pass
# search for .git directory (project) or .git file (submodule)
while True:
name = os.path.join(path, '.git')
if os.path.isdir(name) or os.path.isfile(name):
return Git(path)
newpath = os.path.dirname(path)
if newpath == path:
break
path = newpath
def _get_hg_repo(path, prefs):
p = _find_parent_dir_with(path, '.hg')
if p:
return Hg(p)
def _get_mtn_repo(path, prefs):
p = _find_parent_dir_with(path, '_MTN')
if p:
return Mtn(p)
def _get_rcs_repo(path, prefs):
if os.path.isdir(os.path.join(path, 'RCS')):
return Rcs(path)
# [rfailliot] this code doesn't seem to work, but was in 0.4.8 too.
# I'm letting it here until further tests are done, but it is possible
# this code never actually worked.
try:
for s in os.listdir(path):
if s.endswith(',v') and os.path.isfile(os.path.join(path, s)):
return Rcs(path)
except OSError:
# the user specified an invalid folder name
pass
def _get_svn_repo(path, prefs):
p = _find_parent_dir_with(path, '.svn')
if p:
return Svn(p)
def _get_svk_repo(path, prefs):
name = path
# parse the ~/.svk/config file to discover which directories are part of
# SVK repositories
if utils.isWindows():
name = name.upper()
svkroot = os.environ.get('SVKROOT', None)
if svkroot is None:
svkroot = os.path.expanduser('~/.svk')
svkconfig = os.path.join(svkroot, 'config')
if os.path.isfile(svkconfig):
try:
# find working copies by parsing the config file
f = open(svkconfig, 'r')
ss = readlines(f)
f.close()
projs, sep = [], os.sep
# find the separator character
for s in ss:
if s.startswith(' sep: ') and len(s) > 7:
sep = s[7]
# find the project directories
i = 0
while i < len(ss):
s = ss[i]
i += 1
if s.startswith(' hash: '):
while i < len(ss) and ss[i].startswith(' '):
s = ss[i]
i += 1
if s.endswith(': ') and i < len(ss) and ss[i].startswith(' depotpath: '):
key = s[4:-2].replace(sep, os.sep)
# parse directory path
j, n, tt = 0, len(key), []
while j < n:
if key[j] == '"':
# quoted string
j += 1
while j < n:
if key[j] == '"':
j += 1
break
elif key[j] == '\\':
# escaped character
j += 1
if j < n:
tt.append(key[j])
j += 1
else:
tt.append(key[j])
j += 1
key = ''.join(tt).replace(sep, os.sep)
if utils.isWindows():
key = key.upper()
projs.append(key)
break
# check if the file belongs to one of the project directories
if FolderSet(projs).contains(name):
return Svk(path)
except IOError:
utils.logError(_('Error parsing %s.') % (svkconfig, ))