# vim: set fileencoding=utf-8 : # # (C) 2010 Rob Browning # 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, please see # """provides git-dch helpers""" import re MAX_CHANGELOG_LINE_LENGTH = 76 def extract_git_dch_cmds(lines, options): """Return a dictionary of all Git-Dch: commands found in lines. The command keys will be lowercased, i.e. {'ignore' : True, 'short': True}. For now, all the options are binary. Also return all of the lines that do not contain Git-Dch: commands.""" commands = {} other_lines = [] for line in lines: if line.startswith('Git-Dch: ') or line.startswith('Gbp-Dch: '): cmd = line.split(' ', 1)[1].strip().lower() commands[cmd] = True else: other_lines.append(line) return (commands, other_lines) def filter_ignore_rx_matches(lines, options): """Filter any lines that match options.ignore_regex (i.e. --ignore-regex).""" if options.ignore_regex: ignore_re = re.compile(options.ignore_regex) return [line for line in lines if not ignore_re.match(line)] else: return lines def extract_bts_cmds(lines, opts): """Return a dictionary of the bug tracking system commands contained in the given lines. i.e. {'closed' : [1], 'fixed': [3, 4]}. Right now, this will only notice a single directive clause on a line. Also return all of the lines that do not contain bug tracking system commands.""" _bug_re = re.compile(opts.meta_closes_bugnum, re.I) bts_rx = re.compile(r'(?P%s):\s+%s' % (opts.meta_closes, opts.meta_closes_bugnum), re.I) commands = {} other_lines = [] for line in lines: m = bts_rx.match(line) if m: bug_nums = [bug.strip() for bug in _bug_re.findall(line, re.I)] try: commands[m.group('bts')] += bug_nums except KeyError: commands[m.group('bts')] = bug_nums else: other_lines.append(line) return (commands, other_lines) def extract_thanks_info(lines, options): """Return a list of all of the Thanks: entries, and a list of all of the lines that do not contain Thanks: entries.""" thanks = [] thanks_re = re.compile(r'thanks:\s+', re.I) other_lines = [] for line in lines: if thanks_re.match(line): thanks.append(line.split(' ', 1)[1].strip()) else: other_lines.append(line) return (thanks, other_lines) def _ispunct(ch): return not ch.isalnum() and not ch.isspace() def terminate_first_line_if_needed(lines): """Terminate the first line of lines with a '.' if multi-line.""" # Don't add a period to empty or one line commit messages. if len(lines) < 2: return lines if lines[0] and _ispunct(lines[0][-1]): return lines if lines[1] and (_ispunct(lines[1][0]) or lines[1][0].islower()): return lines return [lines[0] + "."] + lines[1:] def format_changelog_entry(commit_info, options, last_commit=False): """Return a list of lines (without newlines) as the changelog entry for commit_info (generated by GitRepository.get_commit_info()). If last_commit is not False, then this entry is the last one in the series.""" entry = [commit_info['subject']] body = commit_info['body'].splitlines() commitid = commit_info['id'] (git_dch_cmds, body) = extract_git_dch_cmds(body, options) if 'ignore' in git_dch_cmds: return None if options.idlen: entry[0] = '[%s] ' % commitid[0:options.idlen] + entry[0] bts_cmds = {} thanks = [] if options.meta: (bts_cmds, body) = extract_bts_cmds(body, options) (thanks, body) = extract_thanks_info(body, options) body = filter_ignore_rx_matches(body, options) if 'full' in git_dch_cmds or (options.full and 'short' not in git_dch_cmds): # Add all non-blank body lines. entry.extend([line for line in body if line.strip()]) if thanks: # Last wins for now (match old behavior). thanks_msg = 'Thanks to %s' % thanks[-1] entry.extend([thanks_msg]) for bts in bts_cmds: bts_msg = '(%s: %s)' % (bts, ', '.join(bts_cmds[bts])) if len(entry[-1]) + len(bts_msg) >= MAX_CHANGELOG_LINE_LENGTH: entry.extend(['']) else: entry[-1] += " " entry[-1] += bts_msg entry = terminate_first_line_if_needed(entry) return entry