def getdiff(ctx, diffopts): """plain-text diff without header (user, commit message, etc)""" output = util.stringio() for chunk, _label in patch.diffui(ctx.repo(), ctx.p1().node(), ctx.node(), None, opts=diffopts): output.write(chunk) return output.getvalue()
def commit_no_print(ui, repo, hooktype, node, parent1, **kwargs): """ Intended for running on commit. I take no responsibility for what might happen if attached to other events. This hook inspects the diff that was just committed and looks for inserted print statements. It does so fairly naively, not caring about the filetype or anything. Also, it does not fail if a print statement is found, as sometimes you might actually mean to do it. """ regex = re.compile(r'^\+\s*print') for line, label in patch.diffui(repo, parent1, node): if regex.match(line): print "YOU COMMITTED A PRINT STATEMENT" return
def check(self): self.ui.debug('checkfiles: considering files:\n %s\n' % '\n '.join(self.files)) if self.use_spaces: indicator = '^' * self.tab_size else: indicator = '^' class State: def __init__(self, ui): self.ui = ui self.ws_begin = False self.ws_end = False self.all_ws = False self.filecount = 0 self.probcount = 0 def endfile(self, file): if file is None: return if self.ws_begin or self.ws_end or self.all_ws: self.filecount += 1 self.ui.status( 'checkfiles: %s:%s%s%s\n' % (file, ' whitespace_begin' if self.ws_begin else '', ' whitespace_end' if self.ws_end else '', ' all_whitespace' if self.all_ws else '')) self.ws_begin = False self.ws_end = False self.all_ws = False else: self.ui.note('checkfiles: %s: ok\n' % file) def found_all_ws(self): self.all_ws = True self.probcount += 1 def found_ws_end(self): self.ws_end = True self.probcount += 1 def found_ws_begin(self): self.ws_begin = True self.probcount += 1 state = State(self.ui) if self.check_diffs: if len(self.ctx.parents()) == 1: # XXX would be nicer if checked_exts were a proper pattern; # then cmdutil.match would work naturally with it try: from mercurial.scmutil import match ctx = self.repo[None] except ImportError: from mercurial.cmdutil import match ctx = self.repo file = None hunk = None lastlabel = None for chunk, label in patch.diffui(self.repo, self.ctx.p1().node(), self.ctx.node(), match(ctx)): if len(label) > 0 or chunk != '\n': self.ui.debug('checkfiles: %s="%s"\n' % (label, chunk)) if label == 'diff.file_b': state.endfile(file) file = re.sub(r'^[+][+][+] b/(.+)\t.+$', r'\1', chunk) if self.is_relevant(file): self.ui.debug('checkfiles: checking %s ...\n' % file) else: file = None elif label == 'diff.hunk': hunk = chunk elif file and label == 'diff.trailingwhitespace' and lastlabel == 'diff.inserted' and chunk != '\r': state.found_ws_end() self.ui.note('%s: trailing whitespace in %s\n' % (file, hunk)) elif file and label == 'diff.inserted' and self.is_ws_before_text( chunk[1:]): state.found_ws_begin() if self.use_spaces: self.ui.note('%s: tab character(s) in %s\n' % (file, hunk)) else: self.ui.note('%s: space(s) before text in %s\n' % (file, hunk)) lastlabel = label state.endfile(file) else: self.ui.note('checkfiles: skipping merge changeset\n') else: for file in filter(self.is_relevant, self.files): self.ui.debug('checkfiles: checking %s ...\n' % file) fctx = self.ctx[file] for num, line in enumerate(fctx.data().splitlines(), 1): if line.isspace(): state.found_all_ws() self.ui.note('%s (%i): all whitespace\n' % (file, num)) elif line.endswith((' ', '\t')): state.found_ws_end() self.ui.note('%s (%i): trailing whitespace\n' % (file, num)) line = line.expandtabs(self.tab_size) non_ws_len = len(line.rstrip()) line_show = ' ' * non_ws_len + '^' * (len(line) - non_ws_len) self.ui.note(' %s\n %s\n' % (line, line_show)) self.detect_ws_before_text(file, num, line, indicator, state) state.endfile(file) if state.filecount > 0: from mercurial.node import short self.ui.warn( 'checkfiles: %i issues(s) found in %i file(s) in %s\n' % (state.probcount, state.filecount, short(self.ctx.node()) if self.ctx.node() else 'working directory')) return state.filecount > 0
def diff(self, diffopts, node1, node2, match, changes=None): in_hunk = False in_diffline = False just_saw_newline = False print_lines_to = False for chunk, label in patch.diffui(self.repo, node1, node2, match, changes, diffopts): if label == 'diff.diffline': # we only print the diffline after checking that the hunk is # interesting, so push the buffer in_diffline = True self.ui.pushbuffer() self.ui.write(chunk, label=label) elif label == 'diff.hunk': # once we get to a hunk, determine if it is interesting in_diffline = False in_hunk = False m = re.match(r"^@@ -(\d+),(\d+) \+(\d+),(\d+) @@$", chunk) lines_from = (int(m.group(1)), int(m.group(2))) lines_to = (int(m.group(3)), int(m.group(4))) try: diffline = self.ui.popbuffer(labeled=True) except: pass if lines_to[0] <= self.line <= lines_to[0] + lines_to[1]: # this is an interesting hunk! in_hunk = True just_saw_newline = False # print the diffline if this is the first good hunk for this file if diffline: self.ui.write(diffline) diffline = None minwidth = len(str(max(lines_to[0], lines_to[0] + lines_to[1]))) self.ui.write(chunk, label=label) line_no_from = lines_from[0] line_no_to = lines_to[0] elif in_diffline: self.ui.write(chunk, label=label) elif in_hunk: if just_saw_newline: # start a new line just_saw_newline = False fmt = '%' + str(minwidth) + 'i' if label == 'diff.deleted': self.ui.write(fmt % line_no_from) line_no_from += 1 elif label == 'diff.inserted': if line_no_to == self.line: self.ui.write((minwidth - 1) * '=' + '>', label='blametrail.currentline') elif print_lines_to: self.ui.write(fmt % line_no_to) else: self.ui.write(minwidth * ' ') line_no_to += 1 else: self.ui.write(fmt % line_no_from) line_no_from += 1 line_no_to += 1 self.ui.write(chunk, label=label) else: # print whatever until we get to the end of the line self.ui.write(chunk, label=label) if chunk == '\n': just_saw_newline = True
def fixup(self): import os.path if self.fixup_diffs: if len(self.ctx.parents()) == 1: ctx = self.repo[None] file = None hunk = None lastlabel = None line_num = None for chunk, label in patch.diffui(self.repo, self.ctx.p1().node(), self.ctx.node(), match(ctx)): if (len(label) == 0 and chunk != '\n') or \ label == 'diff.inserted': line_num += 1 if len(label) > 0 or chunk != '\n': self.ui.debug('checkfiles: %s="%s"\n' % (label, chunk)) if label == 'diff.file_b': file = re.sub(r'^[+][+][+] b/(.+)\t.+$', r'\1', chunk) if self.is_relevant(file): self.ui.debug('checkfiles: checking %s ...\n' % file) else: file = None elif label == 'diff.hunk': hunk = chunk m = re.match(hunk_re, hunk) (start_a, len_a, start_b, len_b) = m.groups() self.ui.debug('checkfiles: parsed: %s, %s, %s, %s\n' % m.groups()) line_num = int(start_b) - 1 elif file and label == 'diff.trailingwhitespace' and \ lastlabel == 'diff.inserted' and chunk != '\r': self.ui.note('%s:%d: trailing whitespace in %s\n' % (file, line_num, hunk)) self.fixup_line_num_in_file(file, line_num) elif file and label == 'diff.inserted' and \ self.is_ws_before_text(chunk[1:]): if self.use_spaces: self.ui.note('%s:%d: tab character(s) in %s\n' % (file, line_num, hunk)) else: self.ui.note('%s:%d: space(s) before text in %s\n' % (file, line_num, hunk)) self.fixup_line_num_in_file(file, line_num) lastlabel = label else: self.ui.note('checkfiles: skipping merge changeset\n') else: for file in filter(self.is_relevant, self.files): data = self.ctx[file].data() lines = data.splitlines() nl_at_eof = data.endswith('\n') if not any(line.isspace() or self.is_ws_before_text(line) or \ line.endswith((' ', '\t')) for line in lines): self.ui.note('checkfiles: %s ok\n' % file) continue self.ui.status('checkfiles: fixing %s\n' % file) with open(os.path.join(self.repo.root, file), 'w') as fileobj: def fixline(): if self.use_spaces: for line in lines: yield line.rstrip().expandtabs(self.tab_size) else: for line in lines: match = re.match(r'^(\t*( \t*)+)[^ \t]', line) if match: ws = match.group(1) text = line[len(ws):] yield ws.expandtabs(self.tab_size).replace( ' ' * self.tab_size, '\t') + text.rstrip() else: yield line.rstrip() fileobj.writelines('\n'.join(fixline())) if nl_at_eof: fileobj.write('\n')
def check(self): self.ui.debug('checkfiles: considering files:\n %s\n' % '\n '.join(self.files)) if self.use_spaces: indicator = '^' * self.tab_size else: indicator = '^' class State: def __init__(self, ui): self.ui = ui self.ws_begin = False self.ws_end = False self.all_ws = False self.filecount = 0 self.probcount = 0 def endfile(self, file): if file is None: return if self.ws_begin or self.ws_end or self.all_ws: self.filecount += 1 self.ui.status('checkfiles: %s:%s%s%s\n' % (file, ' whitespace_begin' if self.ws_begin else '', ' whitespace_end' if self.ws_end else '', ' all_whitespace' if self.all_ws else '')) self.ws_begin = False self.ws_end = False self.all_ws = False else: self.ui.note('checkfiles: %s: ok\n' % file) def found_all_ws(self): self.all_ws = True self.probcount += 1 def found_ws_end(self): self.ws_end = True self.probcount += 1 def found_ws_begin(self): self.ws_begin = True self.probcount += 1 state = State(self.ui) if self.check_diffs: if len(self.ctx.parents()) == 1: ctx = self.repo[None] file = None hunk = None lastlabel = None for chunk, label in patch.diffui(self.repo, self.ctx.p1().node(), self.ctx.node(), match(ctx)): if len(label) > 0 or chunk != '\n': self.ui.debug('checkfiles: %s="%s"\n' % (label, chunk)) if label == 'diff.file_b': state.endfile(file) file = re.sub(r'^[+][+][+] b/(.+)\t.+$', r'\1', chunk) if self.is_relevant(file): self.ui.debug('checkfiles: checking %s ...\n' % file) else: file = None elif label == 'diff.hunk': hunk = chunk elif file and label == 'diff.trailingwhitespace' and \ lastlabel == 'diff.inserted' and chunk != '\r': if self.check_ignores_trailing_ws: # still check for presence of \t tough if self.use_spaces and ('\t' in chunk): state.found_ws_end() self.ui.note('%s: trailing tab in %s\n' % (file, hunk)) else: state.found_ws_end() self.ui.note('%s: trailing whitespace in %s\n' % (file, hunk)) elif file and label == 'diff.inserted' and \ self.is_ws_before_text(chunk[1:]): state.found_ws_begin() if self.use_spaces: self.ui.note('%s: tab character(s) in %s\n' % (file, hunk)) else: self.ui.note('%s: space(s) before text in %s\n' % (file, hunk)) lastlabel = label state.endfile(file) else: self.ui.note('checkfiles: skipping merge changeset\n') else: for file in filter(self.is_relevant, self.files): self.ui.debug('checkfiles: checking %s ...\n' % file) fctx = self.ctx[file] for num, line in enumerate(fctx.data().splitlines(), 1): if line.isspace(): if self.check_ignores_trailing_ws: # still check for presence of \t if self.use_spaces and ('\t' in line): state.found_all_ws() self.ui.note('%s (%i): tabs in all ' \ 'whitespace line\n' % (file, num)) else: state.found_all_ws() self.ui.note('%s (%i): all whitespace\n' % (file, num)) elif line.endswith((' ', '\t')): if self.check_ignores_trailing_ws: # still check for presence of \t if self.use_spaces and ('\t' in line): state.found_ws_end() self.ui.note('%s (%i): trailing tabs\n' % (file, num)) else: state.found_ws_end() self.ui.note('%s (%i): trailing whitespace\n' % (file, num)) line = line.expandtabs(self.tab_size) non_ws_len = len(line.rstrip()) line_show = ' ' * non_ws_len + \ '^' * (len(line) - non_ws_len) self.ui.note(' %s\n %s\n' % (line, line_show)) self.detect_ws_before_text(file, num, line, indicator, state) state.endfile(file) if state.filecount > 0: from mercurial.node import short self.ui.warn('checkfiles: %i issues(s) found in %i file(s) in %s\n' % (state.probcount, state.filecount, short(self.ctx.node()) if self.ctx.node() \ else 'working directory')) return state.filecount > 0