|
|
|
@ -26,7 +26,6 @@ import glob
|
|
|
|
|
import re
|
|
|
|
|
import shlex
|
|
|
|
|
import stat
|
|
|
|
|
import subprocess
|
|
|
|
|
import unicodedata
|
|
|
|
|
import webbrowser
|
|
|
|
|
|
|
|
|
@ -53,6 +52,7 @@ from gi.repository import PangoCairo
|
|
|
|
|
from urllib.parse import urlparse
|
|
|
|
|
|
|
|
|
|
from diffuse import utils
|
|
|
|
|
from diffuse import constants
|
|
|
|
|
|
|
|
|
|
if not hasattr(__builtins__, 'WindowsError'):
|
|
|
|
|
# define 'WindowsError' so 'except' statements will work on all platforms
|
|
|
|
@ -739,7 +739,7 @@ class Preferences:
|
|
|
|
|
[ 'List',
|
|
|
|
|
[ 'Integer', 'tabs_default_panes', 2, _('Default panes'), 2, 16 ],
|
|
|
|
|
[ 'Boolean', 'tabs_always_show', False, _('Always show the tab bar') ],
|
|
|
|
|
[ 'Boolean', 'tabs_warn_before_quit', True, _('Warn me when closing a tab will quit %s') % utils.APP_NAME ]
|
|
|
|
|
[ 'Boolean', 'tabs_warn_before_quit', True, _('Warn me when closing a tab will quit %s') % constants.APP_NAME ]
|
|
|
|
|
],
|
|
|
|
|
_('Regional Settings'),
|
|
|
|
|
[ 'List',
|
|
|
|
@ -900,7 +900,7 @@ class Preferences:
|
|
|
|
|
ss.append(f'{k} "{v_escaped}"\n')
|
|
|
|
|
ss.sort()
|
|
|
|
|
f = open(self.path, 'w')
|
|
|
|
|
f.write(f'# This prefs file was generated by {utils.APP_NAME} {utils.VERSION}.\n\n')
|
|
|
|
|
f.write(f'# This prefs file was generated by {constants.APP_NAME} {constants.VERSION}.\n\n')
|
|
|
|
|
for s in ss:
|
|
|
|
|
f.write(s)
|
|
|
|
|
f.close()
|
|
|
|
@ -1225,66 +1225,6 @@ def safeRelativePath(abspath1, name, prefs, cygwin_pref):
|
|
|
|
|
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:
|
|
|
|
|
success_results = [ 0 ]
|
|
|
|
|
if utils.isWindows() and prefs.getBool(bash_pref):
|
|
|
|
|
# launch the command from a bash shell is requested
|
|
|
|
|
cmd = [ prefs.convertToNativePath('/bin/bash.exe'), '-l', '-c', 'cd {}; {}'.format(bashEscape(dn), ' '.join([ bashEscape(arg) for arg in cmd ])) ]
|
|
|
|
|
dn = None
|
|
|
|
|
# use subprocess.Popen to retrieve the file contents
|
|
|
|
|
if utils.isWindows():
|
|
|
|
|
info = subprocess.STARTUPINFO()
|
|
|
|
|
info.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
|
|
|
|
info.wShowWindow = subprocess.SW_HIDE
|
|
|
|
|
else:
|
|
|
|
|
info = None
|
|
|
|
|
proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=dn, startupinfo=info)
|
|
|
|
|
proc.stdin.close()
|
|
|
|
|
proc.stderr.close()
|
|
|
|
|
fd = proc.stdout
|
|
|
|
|
# read the command's output
|
|
|
|
|
s = fd.read()
|
|
|
|
|
fd.close()
|
|
|
|
|
if proc.wait() not in success_results:
|
|
|
|
|
raise IOError('Command failed.')
|
|
|
|
|
return s
|
|
|
|
|
|
|
|
|
|
# use popen to read the output of a command
|
|
|
|
|
def popenReadLines(dn, cmd, prefs, bash_pref, success_results=None):
|
|
|
|
|
return strip_eols(splitlines(popenRead(dn, cmd, prefs, bash_pref, success_results).decode('utf-8', errors='ignore')))
|
|
|
|
|
|
|
|
|
|
# simulate use of popen with xargs to read the output of a command
|
|
|
|
|
def popenXArgsReadLines(dn, cmd, args, prefs, bash_pref):
|
|
|
|
|
# os.sysconf() is only available on Unix
|
|
|
|
|
if hasattr(os, 'sysconf'):
|
|
|
|
|
maxsize = os.sysconf('SC_ARG_MAX')
|
|
|
|
|
maxsize -= sum([ len(k) + len(v) + 2 for k, v in os.environ.items() ])
|
|
|
|
|
else:
|
|
|
|
|
# assume the Window's limit to CreateProcess()
|
|
|
|
|
maxsize = 32767
|
|
|
|
|
maxsize -= sum([ len(k) + 1 for k in cmd ])
|
|
|
|
|
|
|
|
|
|
ss = []
|
|
|
|
|
i, s, a = 0, 0, []
|
|
|
|
|
while i < len(args):
|
|
|
|
|
f = (len(a) == 0)
|
|
|
|
|
if f:
|
|
|
|
|
# start a new command line
|
|
|
|
|
a = cmd[:]
|
|
|
|
|
elif s + len(args[i]) + 1 <= maxsize:
|
|
|
|
|
f = True
|
|
|
|
|
if f:
|
|
|
|
|
# append another argument to the current command line
|
|
|
|
|
a.append(args[i])
|
|
|
|
|
s += len(args[i]) + 1
|
|
|
|
|
i += 1
|
|
|
|
|
if i == len(args) or not f:
|
|
|
|
|
ss.extend(popenReadLines(dn, a, prefs, bash_pref))
|
|
|
|
|
s, a = 0, []
|
|
|
|
|
return ss
|
|
|
|
|
|
|
|
|
|
# utility class to help support Git and Monotone
|
|
|
|
|
# represents a set of files and folders of interest for "git status" or
|
|
|
|
|
# "mtn automate inventory"
|
|
|
|
@ -1361,7 +1301,7 @@ class _Bzr:
|
|
|
|
|
isabs |= os.path.isabs(name)
|
|
|
|
|
args.append(safeRelativePath(self.root, name, prefs, 'bzr_cygwin'))
|
|
|
|
|
# run command
|
|
|
|
|
ss = popenReadLines(self.root, args, prefs, 'bzr_bash')
|
|
|
|
|
ss = utils.popenReadLines(self.root, args, prefs, 'bzr_bash')
|
|
|
|
|
# parse response
|
|
|
|
|
prev = 'before:' + rev
|
|
|
|
|
fs = _VcsFolderSet(names)
|
|
|
|
@ -1441,7 +1381,7 @@ class _Bzr:
|
|
|
|
|
prev = '-1'
|
|
|
|
|
fs = _VcsFolderSet(names)
|
|
|
|
|
added, modified, removed, renamed = {}, {}, {}, {}
|
|
|
|
|
for s in popenReadLines(self.root, args, prefs, 'bzr_bash'):
|
|
|
|
|
for s in utils.popenReadLines(self.root, args, prefs, 'bzr_bash'):
|
|
|
|
|
# parse response
|
|
|
|
|
if len(s) < 5:
|
|
|
|
|
continue
|
|
|
|
@ -1498,7 +1438,7 @@ class _Bzr:
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
def getRevision(self, prefs, name, rev):
|
|
|
|
|
return popenRead(self.root, [ prefs.getString('bzr_bin'), 'cat', '--name-from-revision', '-r', rev, safeRelativePath(self.root, name, prefs, 'bzr_cygwin') ], prefs, 'bzr_bash')
|
|
|
|
|
return utils.popenRead(self.root, [ prefs.getString('bzr_bin'), 'cat', '--name-from-revision', '-r', rev, safeRelativePath(self.root, name, prefs, 'bzr_cygwin') ], prefs, 'bzr_bash')
|
|
|
|
|
|
|
|
|
|
def _get_bzr_repo(path, prefs):
|
|
|
|
|
p = _find_parent_dir_with(path, '.bzr')
|
|
|
|
@ -1547,7 +1487,7 @@ class _Cvs:
|
|
|
|
|
prev = 'BASE'
|
|
|
|
|
fs = _VcsFolderSet(names)
|
|
|
|
|
modified = {}
|
|
|
|
|
for s in popenReadLines(self.root, args, prefs, 'cvs_bash'):
|
|
|
|
|
for s in utils.popenReadLines(self.root, args, prefs, 'cvs_bash'):
|
|
|
|
|
# parse response
|
|
|
|
|
if len(s) < 3 or s[0] not in 'ACMR':
|
|
|
|
|
continue
|
|
|
|
@ -1571,10 +1511,10 @@ class _Cvs:
|
|
|
|
|
def getRevision(self, prefs, name, rev):
|
|
|
|
|
if rev == 'BASE' and not os.path.exists(name):
|
|
|
|
|
# find revision for removed files
|
|
|
|
|
for s in popenReadLines(self.root, [ prefs.getString('cvs_bin'), 'status', safeRelativePath(self.root, name, prefs, 'cvs_cygwin') ], prefs, 'cvs_bash'):
|
|
|
|
|
for s in utils.popenReadLines(self.root, [ prefs.getString('cvs_bin'), 'status', safeRelativePath(self.root, name, prefs, 'cvs_cygwin') ], prefs, 'cvs_bash'):
|
|
|
|
|
if s.startswith(' Working revision:\t-'):
|
|
|
|
|
rev = s.split('\t')[1][1:]
|
|
|
|
|
return popenRead(self.root, [ prefs.getString('cvs_bin'), '-Q', 'update', '-p', '-r', rev, safeRelativePath(self.root, name, prefs, 'cvs_cygwin') ], prefs, 'cvs_bash')
|
|
|
|
|
return utils.popenRead(self.root, [ prefs.getString('cvs_bin'), '-Q', 'update', '-p', '-r', rev, safeRelativePath(self.root, name, prefs, 'cvs_cygwin') ], prefs, 'cvs_bash')
|
|
|
|
|
|
|
|
|
|
def _get_cvs_repo(path, prefs):
|
|
|
|
|
if os.path.isdir(os.path.join(path, 'CVS')):
|
|
|
|
@ -1608,7 +1548,7 @@ class _Darcs:
|
|
|
|
|
args.append(safeRelativePath(self.root, name, prefs, 'darcs_cygwin'))
|
|
|
|
|
# run command
|
|
|
|
|
# 'darcs whatsnew' will return 1 if there are no changes
|
|
|
|
|
ss = popenReadLines(self.root, args, prefs, 'darcs_bash', [0, 1])
|
|
|
|
|
ss = utils.popenReadLines(self.root, args, prefs, 'darcs_bash', [0, 1])
|
|
|
|
|
# parse response
|
|
|
|
|
i, n = 0, len(ss)
|
|
|
|
|
if mods:
|
|
|
|
@ -1701,7 +1641,7 @@ class _Darcs:
|
|
|
|
|
except ValueError:
|
|
|
|
|
args.extend([ '-h', rev ])
|
|
|
|
|
args.append(safeRelativePath(self.root, name, prefs, 'darcs_cygwin'))
|
|
|
|
|
return popenRead(self.root, args, prefs, 'darcs_bash')
|
|
|
|
|
return utils.popenRead(self.root, args, prefs, 'darcs_bash')
|
|
|
|
|
|
|
|
|
|
def _get_darcs_repo(path, prefs):
|
|
|
|
|
p = _find_parent_dir_with(path, '_darcs')
|
|
|
|
@ -1727,7 +1667,7 @@ class _Git:
|
|
|
|
|
prev = rev + '^'
|
|
|
|
|
fs = _VcsFolderSet(names)
|
|
|
|
|
modified = {}
|
|
|
|
|
for s in popenReadLines(self.root, args, prefs, 'git_bash'):
|
|
|
|
|
for s in utils.popenReadLines(self.root, args, prefs, 'git_bash'):
|
|
|
|
|
# parse response
|
|
|
|
|
if len(s) < 2 or s[0] not in 'ADM':
|
|
|
|
|
continue
|
|
|
|
@ -1762,7 +1702,7 @@ class _Git:
|
|
|
|
|
fs = _VcsFolderSet(names)
|
|
|
|
|
modified, renamed = {}, {}
|
|
|
|
|
# 'git status' will return 1 when a commit would fail
|
|
|
|
|
for s in popenReadLines(self.root, args, prefs, 'git_bash', [0, 1]):
|
|
|
|
|
for s in utils.popenReadLines(self.root, args, prefs, 'git_bash', [0, 1]):
|
|
|
|
|
# parse response
|
|
|
|
|
if len(s) < 3:
|
|
|
|
|
continue
|
|
|
|
@ -1828,13 +1768,13 @@ class _Git:
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
def getRevision(self, prefs, name, rev):
|
|
|
|
|
return popenRead(self.root, [ prefs.getString('git_bin'), 'show', '{}:{}'.format(rev, relpath(self.root, os.path.abspath(name)).replace(os.sep, '/')) ], prefs, 'git_bash')
|
|
|
|
|
return utils.popenRead(self.root, [ prefs.getString('git_bin'), 'show', '{}:{}'.format(rev, relpath(self.root, os.path.abspath(name)).replace(os.sep, '/')) ], prefs, 'git_bash')
|
|
|
|
|
|
|
|
|
|
def _get_git_repo(path, prefs):
|
|
|
|
|
if 'GIT_DIR' in os.environ:
|
|
|
|
|
try:
|
|
|
|
|
d = path
|
|
|
|
|
ss = popenReadLines(d, [ prefs.getString('git_bin'), 'rev-parse', '--show-prefix' ], prefs, 'git_bash')
|
|
|
|
|
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)
|
|
|
|
@ -1873,7 +1813,7 @@ class _Hg:
|
|
|
|
|
def _getPreviousRevision(self, prefs, rev):
|
|
|
|
|
if rev is None:
|
|
|
|
|
if self.working_rev is None:
|
|
|
|
|
ss = popenReadLines(self.root, [ prefs.getString('hg_bin'), 'id', '-i', '-t' ], prefs, 'hg_bash')
|
|
|
|
|
ss = utils.popenReadLines(self.root, [ prefs.getString('hg_bin'), 'id', '-i', '-t' ], prefs, 'hg_bash')
|
|
|
|
|
if len(ss) != 1:
|
|
|
|
|
raise IOError('Unknown working revision')
|
|
|
|
|
ss = ss[0].split(' ')
|
|
|
|
@ -1901,7 +1841,7 @@ class _Hg:
|
|
|
|
|
prev = self._getPreviousRevision(prefs, rev)
|
|
|
|
|
fs = _VcsFolderSet(names)
|
|
|
|
|
modified = {}
|
|
|
|
|
for s in popenReadLines(self.root, args, prefs, 'hg_bash'):
|
|
|
|
|
for s in utils.popenReadLines(self.root, args, prefs, 'hg_bash'):
|
|
|
|
|
# parse response
|
|
|
|
|
if len(s) < 3 or s[0] not in 'AMR':
|
|
|
|
|
continue
|
|
|
|
@ -1928,7 +1868,7 @@ class _Hg:
|
|
|
|
|
return self._getCommitTemplate(prefs, names, [ 'status', '-q' ], None)
|
|
|
|
|
|
|
|
|
|
def getRevision(self, prefs, name, rev):
|
|
|
|
|
return popenRead(self.root, [ prefs.getString('hg_bin'), 'cat', '-r', rev, safeRelativePath(self.root, name, prefs, 'hg_cygwin') ], prefs, 'hg_bash')
|
|
|
|
|
return utils.popenRead(self.root, [ prefs.getString('hg_bin'), 'cat', '-r', rev, safeRelativePath(self.root, name, prefs, 'hg_cygwin') ], prefs, 'hg_bash')
|
|
|
|
|
|
|
|
|
|
def _get_hg_repo(path, prefs):
|
|
|
|
|
p = _find_parent_dir_with(path, '.hg')
|
|
|
|
@ -1947,7 +1887,7 @@ class _Mtn:
|
|
|
|
|
def getCommitTemplate(self, prefs, rev, names):
|
|
|
|
|
# build command
|
|
|
|
|
vcs_bin = prefs.getString('mtn_bin')
|
|
|
|
|
ss = popenReadLines(self.root, [ vcs_bin, 'automate', 'select', '-q', rev ], prefs, 'mtn_bash')
|
|
|
|
|
ss = utils.popenReadLines(self.root, [ vcs_bin, 'automate', 'select', '-q', rev ], prefs, 'mtn_bash')
|
|
|
|
|
if len(ss) != 1:
|
|
|
|
|
raise IOError('Ambiguous revision specifier')
|
|
|
|
|
args = [ vcs_bin, 'automate', 'get_revision', ss[0] ]
|
|
|
|
@ -1959,7 +1899,7 @@ class _Mtn:
|
|
|
|
|
# run command
|
|
|
|
|
prev = None
|
|
|
|
|
removed, added, modified, renamed = {}, {}, {}, {}
|
|
|
|
|
ss = popenReadLines(self.root, args, prefs, 'mtn_bash')
|
|
|
|
|
ss = utils.popenReadLines(self.root, args, prefs, 'mtn_bash')
|
|
|
|
|
i = 0
|
|
|
|
|
while i < len(ss):
|
|
|
|
|
# process results
|
|
|
|
@ -2002,7 +1942,7 @@ class _Mtn:
|
|
|
|
|
if removed or renamed:
|
|
|
|
|
# remove directories
|
|
|
|
|
removed_dirs = set()
|
|
|
|
|
for s in popenReadLines(self.root, [ vcs_bin, 'automate', 'get_manifest_of', prev ], prefs, 'mtn_bash'):
|
|
|
|
|
for s in utils.popenReadLines(self.root, [ vcs_bin, 'automate', 'get_manifest_of', prev ], prefs, 'mtn_bash'):
|
|
|
|
|
s = shlex.split(s)
|
|
|
|
|
if len(s) > 1 and s[0] == 'dir':
|
|
|
|
|
removed_dirs.add(s[1])
|
|
|
|
@ -2049,7 +1989,7 @@ class _Mtn:
|
|
|
|
|
isabs |= os.path.isabs(name)
|
|
|
|
|
# build list of interesting files
|
|
|
|
|
prev = 'h:'
|
|
|
|
|
ss = popenReadLines(self.root, args, prefs, 'mtn_bash')
|
|
|
|
|
ss = utils.popenReadLines(self.root, args, prefs, 'mtn_bash')
|
|
|
|
|
removed, added, modified, renamed = {}, {}, {}, {}
|
|
|
|
|
i = 0
|
|
|
|
|
while i < len(ss):
|
|
|
|
@ -2110,7 +2050,7 @@ class _Mtn:
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
def getRevision(self, prefs, name, rev):
|
|
|
|
|
return popenRead(self.root, [ prefs.getString('mtn_bin'), 'automate', 'get_file_of', '-q', '-r', rev, safeRelativePath(self.root, name, prefs, 'mtn_cygwin') ], prefs, 'mtn_bash')
|
|
|
|
|
return utils.popenRead(self.root, [ prefs.getString('mtn_bin'), 'automate', 'get_file_of', '-q', '-r', rev, safeRelativePath(self.root, name, prefs, 'mtn_cygwin') ], prefs, 'mtn_bash')
|
|
|
|
|
|
|
|
|
|
def _get_mtn_repo(path, prefs):
|
|
|
|
|
p = _find_parent_dir_with(path, '_MTN')
|
|
|
|
@ -2125,7 +2065,7 @@ class _Rcs:
|
|
|
|
|
def getFileTemplate(self, prefs, name):
|
|
|
|
|
args = [ prefs.getString('rcs_bin_rlog'), '-L', '-h', safeRelativePath(self.root, name, prefs, 'rcs_cygwin') ]
|
|
|
|
|
rev = ''
|
|
|
|
|
for line in popenReadLines(self.root, args, prefs, 'rcs_bash'):
|
|
|
|
|
for line in utils.popenReadLines(self.root, args, prefs, 'rcs_bash'):
|
|
|
|
|
if line.startswith('head: '):
|
|
|
|
|
rev = line[6:]
|
|
|
|
|
return [ (name, rev), (name, None) ]
|
|
|
|
@ -2201,7 +2141,7 @@ class _Rcs:
|
|
|
|
|
args = [ safeRelativePath(self.root, k, prefs, 'rcs_cygwin') for k in r ]
|
|
|
|
|
# run command
|
|
|
|
|
r, k = {}, ''
|
|
|
|
|
for line in popenXArgsReadLines(self.root, cmd, args, prefs, 'rcs_bash'):
|
|
|
|
|
for line in utils.popenXArgsReadLines(self.root, cmd, args, prefs, 'rcs_bash'):
|
|
|
|
|
# parse response
|
|
|
|
|
if line.startswith('Working file: '):
|
|
|
|
|
k = prefs.convertToNativePath(line[14:])
|
|
|
|
@ -2214,7 +2154,7 @@ class _Rcs:
|
|
|
|
|
return [ [ (k, r[k]), (k, None) ] for k in sorted(r.keys()) ]
|
|
|
|
|
|
|
|
|
|
def getRevision(self, prefs, name, rev):
|
|
|
|
|
return popenRead(self.root, [ prefs.getString('rcs_bin_co'), '-p', '-q', '-r' + rev, safeRelativePath(self.root, name, prefs, 'rcs_cygwin') ], prefs, 'rcs_bash')
|
|
|
|
|
return utils.popenRead(self.root, [ prefs.getString('rcs_bin_co'), '-p', '-q', '-r' + rev, safeRelativePath(self.root, name, prefs, 'rcs_cygwin') ], prefs, 'rcs_bash')
|
|
|
|
|
|
|
|
|
|
def _get_rcs_repo(path, prefs):
|
|
|
|
|
if os.path.isdir(os.path.join(path, 'RCS')):
|
|
|
|
@ -2265,7 +2205,7 @@ class _Svn:
|
|
|
|
|
vcs, prefix = self._getVcs(), self._getURLPrefix()
|
|
|
|
|
n = len(prefix)
|
|
|
|
|
args = [ prefs.getString(vcs + '_bin'), 'info' ]
|
|
|
|
|
for s in popenReadLines(self.root, args, prefs, vcs + '_bash'):
|
|
|
|
|
for s in utils.popenReadLines(self.root, args, prefs, vcs + '_bash'):
|
|
|
|
|
if s.startswith(prefix):
|
|
|
|
|
self.url = s[n:]
|
|
|
|
|
break
|
|
|
|
@ -2312,7 +2252,7 @@ class _Svn:
|
|
|
|
|
# run command
|
|
|
|
|
fs = _VcsFolderSet(names)
|
|
|
|
|
modified, added, removed = {}, set(), set()
|
|
|
|
|
for s in popenReadLines(self.root, args, prefs, vcs_bash):
|
|
|
|
|
for s in utils.popenReadLines(self.root, args, prefs, vcs_bash):
|
|
|
|
|
status = self._parseStatusLine(s)
|
|
|
|
|
if status is None:
|
|
|
|
|
continue
|
|
|
|
@ -2368,7 +2308,7 @@ class _Svn:
|
|
|
|
|
# determine which are directories
|
|
|
|
|
added = {}
|
|
|
|
|
for p, v in m.items():
|
|
|
|
|
for s in popenReadLines(self.root, [ vcs_bin, 'list', '-r', rev, '{}/{}'.format(self._getURL(prefs), p.replace(os.sep, '/')) ], prefs, vcs_bash):
|
|
|
|
|
for s in utils.popenReadLines(self.root, [ vcs_bin, 'list', '-r', rev, '{}/{}'.format(self._getURL(prefs), p.replace(os.sep, '/')) ], prefs, vcs_bash):
|
|
|
|
|
if s in v:
|
|
|
|
|
# confirmed as added file
|
|
|
|
|
k = os.path.join(self.root, os.path.join(p, s))
|
|
|
|
@ -2394,7 +2334,7 @@ class _Svn:
|
|
|
|
|
m[d].add(b)
|
|
|
|
|
removed_dir, removed = set(), {}
|
|
|
|
|
for p, v in m.items():
|
|
|
|
|
for s in popenReadLines(self.root, [ vcs_bin, 'list', '-r', prev, '{}/{}'.format(self._getURL(prefs), p.replace(os.sep, '/')) ], prefs, vcs_bash):
|
|
|
|
|
for s in utils.popenReadLines(self.root, [ vcs_bin, 'list', '-r', prev, '{}/{}'.format(self._getURL(prefs), p.replace(os.sep, '/')) ], prefs, vcs_bash):
|
|
|
|
|
if s.endswith('/'):
|
|
|
|
|
s = s[:-1]
|
|
|
|
|
if s in v:
|
|
|
|
@ -2412,7 +2352,7 @@ class _Svn:
|
|
|
|
|
tmp = removed_dir
|
|
|
|
|
removed_dir = set()
|
|
|
|
|
for p in tmp:
|
|
|
|
|
for s in popenReadLines(self.root, [ vcs_bin, 'list', '-r', prev, '{}/{}'.format(self._getURL(prefs), p.replace(os.sep, '/')) ], prefs, vcs_bash):
|
|
|
|
|
for s in utils.popenReadLines(self.root, [ vcs_bin, 'list', '-r', prev, '{}/{}'.format(self._getURL(prefs), p.replace(os.sep, '/')) ], prefs, vcs_bash):
|
|
|
|
|
if s.endswith('/'):
|
|
|
|
|
# confirmed item as directory
|
|
|
|
|
removed_dir.add(os.path.join(p, s[:-1]))
|
|
|
|
@ -2441,8 +2381,8 @@ class _Svn:
|
|
|
|
|
def getRevision(self, prefs, name, rev):
|
|
|
|
|
vcs_bin = prefs.getString('svn_bin')
|
|
|
|
|
if rev in [ 'BASE', 'COMMITTED', 'PREV' ]:
|
|
|
|
|
return popenRead(self.root, [ vcs_bin, 'cat', '{}@{}'.format(safeRelativePath(self.root, name, prefs, 'svn_cygwin'), rev) ], prefs, 'svn_bash')
|
|
|
|
|
return popenRead(self.root, [ vcs_bin, 'cat', '{}/{}@{}'.format(self._getURL(prefs), relpath(self.root, os.path.abspath(name)).replace(os.sep, '/'), rev) ], prefs, 'svn_bash')
|
|
|
|
|
return utils.popenRead(self.root, [ vcs_bin, 'cat', '{}@{}'.format(safeRelativePath(self.root, name, prefs, 'svn_cygwin'), rev) ], prefs, 'svn_bash')
|
|
|
|
|
return utils.popenRead(self.root, [ vcs_bin, 'cat', '{}/{}@{}'.format(self._getURL(prefs), relpath(self.root, os.path.abspath(name)).replace(os.sep, '/'), rev) ], prefs, 'svn_bash')
|
|
|
|
|
|
|
|
|
|
def _get_svn_repo(path, prefs):
|
|
|
|
|
p = _find_parent_dir_with(path, '.svn')
|
|
|
|
@ -2472,7 +2412,7 @@ class _Svk(_Svn):
|
|
|
|
|
return str(int(rev) - 1)
|
|
|
|
|
|
|
|
|
|
def getRevision(self, prefs, name, rev):
|
|
|
|
|
return popenRead(self.root, [ prefs.getString('svk_bin'), 'cat', '-r', rev, '{}/{}'.format(self._getURL(prefs), relpath(self.root, os.path.abspath(name)).replace(os.sep, '/')) ], prefs, 'svk_bash')
|
|
|
|
|
return utils.popenRead(self.root, [ prefs.getString('svk_bin'), 'cat', '-r', rev, '{}/{}'.format(self._getURL(prefs), relpath(self.root, os.path.abspath(name)).replace(os.sep, '/')) ], prefs, 'svk_bash')
|
|
|
|
|
|
|
|
|
|
def _get_svk_repo(path, prefs):
|
|
|
|
|
name = path
|
|
|
|
@ -6548,7 +6488,7 @@ class SearchDialog(Gtk.Dialog):
|
|
|
|
|
|
|
|
|
|
# convenience method to request confirmation when closing the last tab
|
|
|
|
|
def confirmTabClose(parent):
|
|
|
|
|
dialog = utils.MessageDialog(parent, Gtk.MessageType.WARNING, _('Closing this tab will quit %s.') % (utils.APP_NAME, ))
|
|
|
|
|
dialog = utils.MessageDialog(parent, Gtk.MessageType.WARNING, _('Closing this tab will quit %s.') % (constants.APP_NAME, ))
|
|
|
|
|
end = (dialog.run() == Gtk.ResponseType.OK)
|
|
|
|
|
dialog.destroy()
|
|
|
|
|
return end
|
|
|
|
@ -6642,17 +6582,17 @@ class AboutDialog(Gtk.AboutDialog):
|
|
|
|
|
def __init__(self):
|
|
|
|
|
Gtk.AboutDialog.__init__(self)
|
|
|
|
|
self.set_logo_icon_name('io.github.mightycreak.Diffuse')
|
|
|
|
|
self.set_program_name(utils.APP_NAME)
|
|
|
|
|
self.set_version(utils.VERSION)
|
|
|
|
|
self.set_program_name(constants.APP_NAME)
|
|
|
|
|
self.set_version(constants.VERSION)
|
|
|
|
|
self.set_comments(_('Diffuse is a graphical tool for merging and comparing text files.'))
|
|
|
|
|
self.set_copyright(utils.COPYRIGHT)
|
|
|
|
|
self.set_website(utils.WEBSITE)
|
|
|
|
|
self.set_copyright(constants.COPYRIGHT)
|
|
|
|
|
self.set_website(constants.WEBSITE)
|
|
|
|
|
self.set_authors([ 'Derrick Moser <derrick_moser@yahoo.com>',
|
|
|
|
|
'Romain Failliot <romain.failliot@foolstep.com>' ])
|
|
|
|
|
self.set_translator_credits(_('translator-credits'))
|
|
|
|
|
license_text = [
|
|
|
|
|
utils.APP_NAME + ' ' + utils.VERSION + '\n\n',
|
|
|
|
|
utils.COPYRIGHT + '\n\n',
|
|
|
|
|
constants.APP_NAME + ' ' + constants.VERSION + '\n\n',
|
|
|
|
|
constants.COPYRIGHT + '\n\n',
|
|
|
|
|
_('''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
|
|
|
|
@ -6898,7 +6838,7 @@ class Diffuse(Gtk.Window):
|
|
|
|
|
if self.headers[f].has_edits:
|
|
|
|
|
# warn users of any unsaved changes they might lose
|
|
|
|
|
dialog = Gtk.MessageDialog(self.get_toplevel(), Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.WARNING, Gtk.ButtonsType.NONE, _('Save changes before loading the new file?'))
|
|
|
|
|
dialog.set_title(utils.APP_NAME)
|
|
|
|
|
dialog.set_title(constants.APP_NAME)
|
|
|
|
|
dialog.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)
|
|
|
|
|
dialog.add_button(Gtk.STOCK_NO, Gtk.ResponseType.REJECT)
|
|
|
|
|
dialog.add_button(Gtk.STOCK_YES, Gtk.ResponseType.OK)
|
|
|
|
@ -7444,7 +7384,7 @@ class Diffuse(Gtk.Window):
|
|
|
|
|
menuspecs.append([ _('_Help'), [
|
|
|
|
|
[_('_Help Contents...'), self.help_contents_cb, None, Gtk.STOCK_HELP, 'help_contents'],
|
|
|
|
|
[],
|
|
|
|
|
[_('_About %s...') % (utils.APP_NAME, ), self.about_cb, None, Gtk.STOCK_ABOUT, 'about'] ] ])
|
|
|
|
|
[_('_About %s...') % (constants.APP_NAME, ), self.about_cb, None, Gtk.STOCK_ABOUT, 'about'] ] ])
|
|
|
|
|
|
|
|
|
|
# used to disable menu events when switching tabs
|
|
|
|
|
self.menu_update_depth = 0
|
|
|
|
@ -7561,7 +7501,7 @@ class Diffuse(Gtk.Window):
|
|
|
|
|
ss.append(f'{k} {v}\n')
|
|
|
|
|
ss.sort()
|
|
|
|
|
f = open(statepath, 'w')
|
|
|
|
|
f.write(f"# This state file was generated by {utils.APP_NAME} {utils.VERSION}.\n\n")
|
|
|
|
|
f.write(f"# This state file was generated by {constants.APP_NAME} {constants.VERSION}.\n\n")
|
|
|
|
|
for s in ss:
|
|
|
|
|
f.write(s)
|
|
|
|
|
f.close()
|
|
|
|
@ -7601,7 +7541,7 @@ class Diffuse(Gtk.Window):
|
|
|
|
|
buttons=Gtk.ButtonsType.NONE,
|
|
|
|
|
text=_('Some files have unsaved changes. Select the files to save before closing.'))
|
|
|
|
|
dialog.set_resizable(True)
|
|
|
|
|
dialog.set_title(utils.APP_NAME)
|
|
|
|
|
dialog.set_title(constants.APP_NAME)
|
|
|
|
|
# add list of files with unsaved changes
|
|
|
|
|
sw = Gtk.ScrolledWindow.new()
|
|
|
|
|
sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
|
|
|
|
@ -7688,7 +7628,7 @@ class Diffuse(Gtk.Window):
|
|
|
|
|
# update window's title
|
|
|
|
|
def updateTitle(self, viewer):
|
|
|
|
|
title = self.notebook.get_tab_label(viewer).get_text()
|
|
|
|
|
self.set_title(f'{title} - {utils.APP_NAME}')
|
|
|
|
|
self.set_title(f'{title} - {constants.APP_NAME}')
|
|
|
|
|
|
|
|
|
|
# update the message in the status bar
|
|
|
|
|
def setStatus(self, s):
|
|
|
|
@ -8172,7 +8112,7 @@ class Diffuse(Gtk.Window):
|
|
|
|
|
del parts[-1]
|
|
|
|
|
if help_url is None:
|
|
|
|
|
# no local help file is available, show on-line help
|
|
|
|
|
help_url = utils.WEBSITE + 'manual.html'
|
|
|
|
|
help_url = constants.WEBSITE + 'manual.html'
|
|
|
|
|
# ask for localised manual
|
|
|
|
|
if utils.lang is not None:
|
|
|
|
|
help_url += '?lang=' + utils.lang
|
|
|
|
@ -8193,17 +8133,15 @@ GObject.signal_new('reload', Diffuse.FileDiffViewer.PaneHeader, GObject.SignalFl
|
|
|
|
|
GObject.signal_new('save', Diffuse.FileDiffViewer.PaneHeader, GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, ())
|
|
|
|
|
GObject.signal_new('save-as', Diffuse.FileDiffViewer.PaneHeader, GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, ())
|
|
|
|
|
|
|
|
|
|
def main(version, sysconfigdir):
|
|
|
|
|
def main():
|
|
|
|
|
# app = Application()
|
|
|
|
|
# return app.run(sys.argv)
|
|
|
|
|
|
|
|
|
|
utils.VERSION = version
|
|
|
|
|
|
|
|
|
|
args = sys.argv
|
|
|
|
|
argc = len(args)
|
|
|
|
|
|
|
|
|
|
if argc == 2 and args[1] in [ '-v', '--version' ]:
|
|
|
|
|
print('%s %s\n%s' % (utils.APP_NAME, utils.VERSION, utils.COPYRIGHT))
|
|
|
|
|
print('%s %s\n%s' % (constants.APP_NAME, constants.VERSION, constants.COPYRIGHT))
|
|
|
|
|
sys.exit(0)
|
|
|
|
|
if argc == 2 and args[1] in [ '-h', '-?', '--help' ]:
|
|
|
|
|
print(_('''Usage:
|
|
|
|
@ -8270,7 +8208,7 @@ Display Options:
|
|
|
|
|
if utils.isWindows():
|
|
|
|
|
rc_file = os.path.join(utils.bin_dir, 'diffuserc')
|
|
|
|
|
else:
|
|
|
|
|
rc_file = os.path.join(utils.bin_dir, f'{sysconfigdir}/diffuserc')
|
|
|
|
|
rc_file = os.path.join(utils.bin_dir, f'{constants.sysconfigdir}/diffuserc')
|
|
|
|
|
for rc_file in rc_file, os.path.join(rc_dir, 'diffuserc'):
|
|
|
|
|
if os.path.isfile(rc_file):
|
|
|
|
|
rc_files.append(rc_file)
|
|
|
|
|