347 lines
12 KiB
Python
347 lines
12 KiB
Python
import os, commands, re, tempfile
|
|
from subprocess import Popen, PIPE, STDOUT
|
|
|
|
import buffer, default, dirutil, lex, regex, util, window
|
|
from point import Point
|
|
import buffer.color
|
|
|
|
from method import Method, Argument
|
|
|
|
class SvnException(Exception):
|
|
pass
|
|
|
|
statuses = {
|
|
' ': 'Unmodified',
|
|
'A': 'Added',
|
|
'C': 'Conflicted',
|
|
'D': 'Deleted',
|
|
'I': 'Ignored',
|
|
'M': 'Modified',
|
|
'R': 'Replaced',
|
|
'X': 'External',
|
|
'?': 'Unknown',
|
|
'!': 'Missing',
|
|
'~': 'Obstructed',
|
|
}
|
|
|
|
def get_status(path, base=None):
|
|
if base is None: base = os.getcwd() + os.path.sep
|
|
if path.startswith(base): path = path[len(base):]
|
|
|
|
cmd = "svn status -v %r" % path
|
|
status, data = commands.getstatusoutput(cmd)
|
|
status = status >> 8
|
|
|
|
if status != 0:
|
|
raise SvnException("Problems with 'svn status': %d" % status)
|
|
|
|
c = data[0]
|
|
status = statuses.get(c, 'Error (%s)' % c)
|
|
fields = data[6:].split()
|
|
|
|
try:
|
|
rrev, lrev, lauthor, filename = fields
|
|
except:
|
|
raise Exception, '%r %r' % (fields, data[6:])
|
|
|
|
return {
|
|
'svn-filename': filename,
|
|
'svn-status': status,
|
|
'svn-lrev': lrev,
|
|
'svn-rrev': rrev,
|
|
'svn-author': lauthor,
|
|
}
|
|
|
|
class SvnCommit(Method):
|
|
'''diff the current file with the version in SVN'''
|
|
args = [Argument("msg", type=type(""), prompt="Commit Message: ")]
|
|
regex = re.compile(r'^Committed revision ([0-9]+)\.$')
|
|
def _execute(self, w, **vargs):
|
|
if not hasattr(w.buffer, 'path'):
|
|
w.set_error("Buffer has no corresponding file")
|
|
return
|
|
|
|
cwd = os.getcwd() + os.path.sep
|
|
path = w.buffer.path
|
|
if path.startswith(cwd):
|
|
path = path[len(cwd):]
|
|
|
|
cmd = "svn ci -m %r %r" % (vargs['msg'], path)
|
|
(status, data) = commands.getstatusoutput(cmd)
|
|
status = status >> 8
|
|
lines = data.split('\n')
|
|
|
|
if status == 0:
|
|
try:
|
|
for line in lines:
|
|
m = self.regex.match(line)
|
|
if m:
|
|
rev = m.group(1)
|
|
w.buffer.metadata['svn-lrev'] = rev
|
|
w.buffer.metadata['svn-rrev'] = rev
|
|
w.set_error("Committed [%s]" % rev)
|
|
return
|
|
except:
|
|
pass
|
|
w.set_error("Problems with SVN commit: %d" % status)
|
|
w.application.data_buffer("*Commit*", repr(lines), switch_to=True)
|
|
|
|
class SvnStatus(Method):
|
|
column = {
|
|
' ': 'Unmodified',
|
|
'A': 'Added',
|
|
'C': 'Conflicted',
|
|
'D': 'Deleted',
|
|
'I': 'Ignored',
|
|
'M': 'Modified',
|
|
'R': 'Replaced',
|
|
'X': 'External',
|
|
'?': 'Unknown',
|
|
'!': 'Missing',
|
|
'~': 'Obstructed',
|
|
}
|
|
def _execute(self, w, **vargs):
|
|
if not hasattr(w.buffer, 'path'):
|
|
w.set_error("Buffer has no corresponding file")
|
|
return
|
|
|
|
cwd = os.getcwd() + os.path.sep
|
|
path = w.buffer.path
|
|
if path.startswith(cwd):
|
|
path = path[len(cwd):]
|
|
cmd = "svn status -v %r" % path
|
|
(status, data) = commands.getstatusoutput(cmd)
|
|
status = status >> 8
|
|
|
|
if status != 0:
|
|
w.set_error("Problems with 'svn status': %d" % status)
|
|
return
|
|
|
|
c = data[0]
|
|
status = self.column.get(c, 'Error (%s)' % c)
|
|
fields = data[6:].split()
|
|
if len(fields) == 4:
|
|
rrev, lrev, lauthor, filename = fields
|
|
w.buffer.metadata['svn-filename'] = filename
|
|
w.buffer.metadata['svn-status'] = status
|
|
w.buffer.metadata['svn-lrev'] = lrev
|
|
w.buffer.metadata['svn-rrev'] = rrev
|
|
w.buffer.metadata['svn-author'] = lauthor
|
|
w.buffer.metadata['vc-info'] = '[svn:%s/%s]' % (lrev, rrev)
|
|
w.set_error('%s %s %s/%s [%s]' % (filename, status, rrev, lrev, lauthor))
|
|
else:
|
|
w.buffer.metadata['svn-filename'] = path
|
|
w.buffer.metadata['svn-status'] = status
|
|
w.buffer.metadata['vc-info'] = '[svn:%s]' % status.lower()
|
|
w.set_error('%s %s' % (path, status))
|
|
|
|
class SvnLog(Method):
|
|
'''display the SVN log for the current file'''
|
|
sep_re = re.compile('^-+$')
|
|
log_re = re.compile(r'^(.+?) \| (.+?) \| (.{25}) .+? \| (.+)$')
|
|
def _build_entry(self, log_line, mesg_lines):
|
|
log_data = '[c:d:*]%s [g:d:*]%s [b:d:*]%s [c:d:*]%s' % log_line
|
|
mesg_data = '\n'.join(mesg_lines).strip()
|
|
if mesg_data:
|
|
mesg_data += '\n'
|
|
return '[b:d:*]' + log_data + '\n' + mesg_data
|
|
def _execute(self, w, **vargs):
|
|
cmd = "svn log %r" % w.buffer.path
|
|
(status, data) = commands.getstatusoutput(cmd)
|
|
|
|
entries = []
|
|
log_line, mesg_lines = None, []
|
|
for line in data.split('\n'):
|
|
if self.sep_re.match(line):
|
|
if log_line is not None:
|
|
entries.append(self._build_entry(log_line, mesg_lines))
|
|
log_line = None
|
|
else:
|
|
m = self.log_re.match(line)
|
|
if m:
|
|
log_line = m.groups()
|
|
mesg_lines = []
|
|
else:
|
|
assert log_line is not None, '%r %r' % (entries, line)
|
|
mesg_lines.append(line)
|
|
data2 = ''.join(entries)
|
|
|
|
if status == 0 and data:
|
|
w.application.color_data_buffer("*Log*", data2, switch_to=True)
|
|
w.set_error("%s: logfile" % self.name)
|
|
elif status == 0:
|
|
w.set_error("%s: There was no data" % self.name)
|
|
else:
|
|
w.set_error("%s: There was an error (%s)" % (self.name, status))
|
|
|
|
|
|
class SvnDiff(Method):
|
|
'''diff the current file with the version in SVN'''
|
|
def _execute(self, w, **vargs):
|
|
if not hasattr(w.buffer, 'path'):
|
|
w.set_error("Buffer has no corresponding file")
|
|
return
|
|
|
|
cmd = "svn diff %r" % w.buffer.path
|
|
(status, data) = commands.getstatusoutput(cmd)
|
|
|
|
if status == 0:
|
|
if data:
|
|
w.application.data_buffer("*Diff*", data, switch_to=True, modename='diff')
|
|
w.set_error("Differences were found")
|
|
else:
|
|
w.set_error("No difference found")
|
|
else:
|
|
w.set_error("There was an error (%s)" % (status))
|
|
class SvnDiff2(Method):
|
|
'''diff the current file with the version in SVN'''
|
|
rev_regex = re.compile('^[0-9]+$')
|
|
args = [Argument("revision", type=type(""), prompt="Old Revision: ")]
|
|
def _execute(self, w, **vargs):
|
|
if not hasattr(w.buffer, 'path'):
|
|
w.set_error("Buffer has no corresponding file")
|
|
return
|
|
|
|
rev = vargs['revision']
|
|
if not self.rev_regex.match(rev):
|
|
w.set_error("Could not parse revision: %r" % rev)
|
|
return
|
|
|
|
cwd = os.getcwd() + os.path.sep
|
|
path = w.buffer.path
|
|
if path.startswith(cwd):
|
|
path = path[len(cwd):]
|
|
|
|
cmd = "svn diff -r %s %r" % (rev, path)
|
|
(status, data) = commands.getstatusoutput(cmd)
|
|
status = status >> 8
|
|
|
|
if data:
|
|
w.application.data_buffer("*Diff*", data, switch_to=True, modename='diff')
|
|
w.set_error("Differences were found")
|
|
else:
|
|
w.set_error("No difference found")
|
|
class SvnDiff3(Method):
|
|
'''diff the current file with the version in SVN'''
|
|
rev_regex = re.compile('^[0-9]+$')
|
|
args = [Argument("revision1", type=type(""), prompt="Old Revision: "),
|
|
Argument("revision2", type=type(""), prompt="New Revision: ")]
|
|
def _execute(self, w, **vargs):
|
|
if not hasattr(w.buffer, 'path'):
|
|
w.set_error("Buffer has no corresponding file")
|
|
return
|
|
|
|
rev1 = vargs['revision1']
|
|
if not self.rev_regex.match(rev1):
|
|
w.set_error("Could not parse revision1: %r" % rev)
|
|
return
|
|
|
|
rev2 = vargs['revision2']
|
|
if not self.rev_regex.match(rev2):
|
|
w.set_error("Could not parse revision2: %r" % rev)
|
|
return
|
|
|
|
cwd = os.getcwd() + os.path.sep
|
|
path = w.buffer.path
|
|
if path.startswith(cwd):
|
|
path = path[len(cwd):]
|
|
|
|
cmd = "svn diff -r %s:%s %r" % (rev1, rev2, path)
|
|
(status, data) = commands.getstatusoutput(cmd)
|
|
status = status >> 8
|
|
|
|
if data:
|
|
w.application.data_buffer("*Diff*", data, switch_to=True, modename='diff')
|
|
w.set_error("Differences were found")
|
|
else:
|
|
w.set_error("No difference found")
|
|
|
|
class SvnBlame(Method):
|
|
'''show blame output for the current version in SVN'''
|
|
line_re = re.compile('^ *(?P<rev>\d+) *(?P<user>[a-zA-Z0-9_]+) *(?P<date>[-0-9]+) *(?P<time>[:0-9]+) *(?P<tz>-\d{4}) *\((?P<vdate>[^\)]+)\) (?P<content>.*)\n$')
|
|
prefix_fmt = '[b:d:*]%-4(rev)s [c:d:*]%-10(user)s [b:d:*]%10(date)s[d:d:*]'
|
|
def _filter(self, line):
|
|
m = self.line_re.match(line)
|
|
if not m:
|
|
raise SvnException("couldn't parse %r" % line)
|
|
return m.groupdict()
|
|
def _open_pipe(self, w, **vargs):
|
|
cmd = ("/usr/bin/svn", 'blame', '-v', w.buffer.path)
|
|
return Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
|
|
def _execute(self, w, **vargs):
|
|
if not hasattr(w.buffer, 'path'):
|
|
w.set_error("Buffer has no corresponding file")
|
|
return
|
|
|
|
pipe = self._open_pipe(w, **vargs)
|
|
groups = [self._filter(line) for line in pipe.stdout]
|
|
status = pipe.wait() >> 8
|
|
|
|
if w.mode.grammar:
|
|
lexer = lex.Lexer(w.mode, w.mode.grammar)
|
|
tokens = list(lexer.lex([d['content'] for d in groups]))
|
|
groups[t.y]['tokens'] = tokens
|
|
|
|
data = ''
|
|
for d in groups:
|
|
if d['tokens']:
|
|
suffix = ''
|
|
for t in d['tokens']:
|
|
code = buffer.color.get_cbuf_code(t.color)
|
|
suffix += code + util.cbuf_escape(t.string)
|
|
else:
|
|
suffix = d['content'] + '\n'
|
|
data += self.prefix_fmt % d + ' ' + suffix
|
|
|
|
if status == 0:
|
|
w.application.color_data_buffer("*Blame*", data, switch_to=True)
|
|
else:
|
|
w.set_error("There was an error (%s)" % (status))
|
|
#class SvnBlame(Method):
|
|
# '''show blame output for the current version in SVN'''
|
|
# line_re = re.compile('^ *(\d+) *([a-zA-Z0-9_]+) *([-0-9]+) *([:0-9]+) *(-\d{4}) *\(([^\)]+)\) (.*)\n$')
|
|
# def _execute(self, w, **vargs):
|
|
# if not hasattr(w.buffer, 'path'):
|
|
# w.set_error("Buffer has no corresponding file")
|
|
# return
|
|
#
|
|
# cmd = ("/usr/bin/svn", 'blame', '-v', w.buffer.path)
|
|
# pipe = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
|
|
#
|
|
# linetokens = []
|
|
# for line in pipe.stdout:
|
|
# m = self.line_re.match(line)
|
|
# if not m:
|
|
# raise Exception, line
|
|
# (rev, user, date, t, tz, vdate, content) = m.groups()
|
|
# linetokens.append([rev, user, date, content, []])
|
|
# status = pipe.wait() >> 8
|
|
#
|
|
# lines = [x[3] for x in linetokens]
|
|
# if w.mode.grammar:
|
|
# lexer = lex.Lexer(w.mode, w.mode.grammar)
|
|
# lextokens = [[] for l in lines]
|
|
# for t in lexer.lex(lines):
|
|
# linetokens[t.y][4].append(t)
|
|
#
|
|
# lines = []
|
|
# for linetoken in linetokens:
|
|
# (rev, user, date, content, lextokens) = linetoken
|
|
# prefix = '[b:d:*]%-4s [c:d:*]%-10s [b:d:*]%10s[d:d:*]' % (rev, user, date)
|
|
# if lextokens:
|
|
# suffixes = []
|
|
# for lt in lextokens:
|
|
# s = lt.string.replace('\\', '\\\\')
|
|
# s = s.replace('[', '\\[').replace(']', '\\]')
|
|
# suffixes.append('[%s:%s:*]%s' % (lt.color[0], lt.color[1], s))
|
|
# suffix = ''.join(suffixes)
|
|
# else:
|
|
# suffix = content + '\n'
|
|
# lines.append('%s %s' % (prefix, suffix))
|
|
# data = ''.join(lines)
|
|
#
|
|
# if status == 0:
|
|
# w.application.color_data_buffer("*Blame*", data, switch_to=True)
|
|
# else:
|
|
# w.set_error("There was an error (%s)" % (status))
|