pmacs3/method/git.py

216 lines
7.7 KiB
Python
Raw Normal View History

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.colors
from method.vc import VcBlame, VcRevView, VcBase, VcException
from method import Method, Argument, arg
if os.system('which git >/dev/null 2>/dev/null') == 0:
has_git = True
else:
has_git = False
class GitException(Exception):
pass
class GitCommit(VcBase):
'''commit this file's changes'''
args = [Argument("msg", type=type(""), prompt="Commit Message: ")]
regex = re.compile(r'^Committed revision ([0-9]+)\.$')
def _execute(self, w, **vargs):
raise GitException("unimplemented")
class GitStatus(VcBase):
_is_method = True
def _execute(self, w, **vargs):
path = self._get_path(w)
cmd = "git status --porcelain %r" % path
status, data = commands.getstatusoutput(cmd)
status = status >> 8
if status != 0:
raise GitException("Problems with 'git status': %d" % status)
if not data:
w.set_error("%s unchanged" % path)
return
cx = data[0]
cy = data[1]
if cx == ' ':
w.set_error("%s working=%s" % (path, cy))
elif cy == ' ':
w.set_error("%s index=%s" % (path, cx))
else:
w.set_error("%s index=%s working=%s" % (path, cx, cy))
# TODO: handle metadata
#w.buffer.metadata['git-filename'] = filename
#w.buffer.metadata['git-status'] = status
#w.buffer.metadata['git-lrev'] = lrev
#w.buffer.metadata['git-rrev'] = rrev
#w.buffer.metadata['git-author'] = lauthor
#w.buffer.metadata['vc-info'] = '[git:%s/%s]' % (lrev, rrev)
class GitLog(Method):
'''display the Git log for the current file'''
_commit_re = re.compile('^(commit) ([0-9a-f]+)$')
_log_re = re.compile('^([^ ]+:) (.*)$')
def _e(self, s):
return s.replace('\\', '\\\\').replace('[', '\\[').replace(']', '\\]')
def _em(self, m, i):
return self._e(m.group(i))
def _execute(self, w, **vargs):
cmd = "git log %r" % w.buffer.path
status, data = commands.getstatusoutput(cmd)
entries = []
for line in data.split('\n'):
m = self._commit_re.match(line)
if m:
entries.append('[b:d:*]commit [y:d:*]' + self._em(m, 2) + "\n")
continue
m = self._log_re.match(line)
if m:
entries.append('[b:d:*]' + self._em(m, 1) + " [c:d:*]" + self._em(m, 2) + "\n")
continue
entries.append(self._e(line) + "\n")
data2 = ''.join(entries)
if status == 0 and data:
w.application.color_data_buffer("*Log*", data2, switch_to=True)
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 GitDiff(Method):
'''diff the current file with the version in Git'''
def _execute(self, w, **vargs):
if not hasattr(w.buffer, 'path'):
w.set_error("Buffer has no corresponding file")
return
cmd = "git 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 GitDiff2(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 = "git 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 GitDiff3(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 = "git 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 GitBlame(VcBlame):
'''show blame output for the current version in Git'''
# rev, user, date, [time], [timezone], [date-str], content
num_fields = 3
#line_re = re.compile(r'^\^*([0-9a-f]+) \(([a-zA-Z0-9_ ]+|Not Committed Yet) +([-0-9]+) [:0-9]+ +[-\+]\d{4} +\d+\) (.*)\n$')
line_re = re.compile(r'^\^*([0-9a-f]+) +\(([a-zA-Z0-9_ ]+|Not Committed Yet) +([-0-9]+) [:0-9]+ +[-\+]\d{4} +\d+\) (.*)\n$')
prefix_fmt = '[g:d:*]%*s [c:d:*]%-*s [b:d:*]%*s[d:d:*]'
pretest_err_msg = 'Git is not installed'
_is_method = True
def _filter(self, line):
m = self.line_re.match(line)
if not m:
raise VcException("couldn't parse %r" % line)
groups = m.groups()
fields = list(groups[:-1])
if fields[1] == 'Not Committed Yet':
fields[1] = ''
if fields[0] == '00000000':
fields[0] = ''
return {'fields': fields, 'content': groups[-1], 'tokens': []}
def _pretest(self):
return has_git
def _open_pipe(self, w, **vargs):
cmd = ("git", 'blame', w.buffer.path)
return Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
class GitBlame2(GitBlame):
'''show blame output for the specific revision in Git'''
args = [arg("revision", t=type(""), p="Revision: ", h="revision number")]
def _open_pipe(self, w, **vargs):
cmd = ("git", 'blame', vargs['revision'], w.buffer.path)
return Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
class GitRevView(VcRevView):
'''show file contents in Git at revision'''
args = [arg("revision", t=type(""), p="Revision: ", h="revision number")]
namebase = 'Git'
_is_method = True
def _get_cmd(self, w, **vargs):
path = self._get_path(w, **vargs)
return ("git", 'show', vargs['revision'] + ':' + path)