def _parse_line(self, line): if not line: if self.commit is not None and self.state == SVNParser.COMMIT \ or self.state == SVNParser.FILES: self.state = SVNParser.MESSAGE elif self.state == SVNParser.MESSAGE: self.__append_message_line() return # Message if self.state == SVNParser.MESSAGE and self.msg_lines > 0: self.__append_message_line(line) return # Invalid commit. Some svn repos like asterisk have commits like this: # r176840 | (no author) | (no date) | 1 line # without any canged path, so I think we can just ignore them if self.patterns['invalid'].match(line): printdbg("SVN Parser: skipping invalid commit: %s", (line, )) self.state = SVNParser.COMMIT self.commit = None return # Separator if self.patterns['separator'].match(line): if self.commit is None or self.state == SVNParser.COMMIT: return elif self.state == SVNParser.MESSAGE \ or self.state == SVNParser.FILES: # We can go directly from FILES to COMMIT # when there is an empty log message if self.msg_lines > 0: printout("Warning (%d): parsing svn log, missing " + \ "lines in commit message!", (self.n_line,)) self.__convert_commit_actions(self.commit) self.handler.commit(self.commit) self.state = SVNParser.COMMIT self.commit = None self.msg_lines = 0 else: printout("Warning (%d): parsing svn log, unexpected separator", (self.n_line, )) return # Commit match = self.patterns['commit'].match(line) if match and self.state == SVNParser.COMMIT: commit = Commit() commit.revision = match.group(1) commit.committer = Person() commit.committer.name = match.group(2) commit.date = datetime.datetime(int(match.group(3)), int(match.group(4)), int(match.group(5)), int(match.group(6)), int(match.group(7)), int(match.group(8))) self.msg_lines = int(match.group(10)) self.commit = commit self.handler.committer(commit.committer) return elif match and self.state == SVNParser.MESSAGE: # It seems a piece of a log message has been copied as # part of the commit message self.commit.message += line + '\n' return elif match and self.state != SVNParser.COMMIT: printout("Warning (%d): parsing svn log, unexpected line %s", (self.n_line, line)) return # Files if self.state == SVNParser.COMMIT: if self.patterns['paths'].match(line): self.state = SVNParser.FILES else: printout("Warning(%d): parsing svn log, unexpected line %s", (self.n_line, line)) return # File moved/copied/replaced match = self.patterns['file-moved'].match(line) if match: if self.state != SVNParser.FILES: printout("Warning (%d): parsing svn log, unexpected line %s", (self.n_line, line)) return action = Action() action.type = match.group(1) action.f1 = match.group(2) action.f2 = match.group(3) action.rev = match.group(4) action.branch_f1 = self.__guess_branch_from_path(action.f1) action.branch_f2 = self.__guess_branch_from_path(action.f2) self.commit.actions.append(action) self.handler.file(action.f1) return # File match = self.patterns['file'].match(line) if match: if self.state != SVNParser.FILES: printout("Warning (%d): parsing svn log, unexpected line %s", (self.n_line, line)) return path = match.group(2) if path != '/': # path == '/' is probably a properties change in / # not interesting for us, ignoring action = Action() action.type = match.group(1) action.f1 = path action.branch_f1 = self.__guess_branch_from_path(path) self.commit.actions.append(action) self.handler.file(path) return
def _parse_line(self, line): if not line: if self.commit is not None and self.state == SVNParser.COMMIT \ or self.state == SVNParser.FILES: self.state = SVNParser.MESSAGE elif self.state == SVNParser.MESSAGE: self.__append_message_line() return # Message if self.state == SVNParser.MESSAGE and self.msg_lines > 0: self.__append_message_line(line) return # Invalid commit. Some svn repos like asterisk have commits like this: # r176840 | (no author) | (no date) | 1 line # without any canged path, so I think we can just ignore them if self.patterns['invalid'].match(line): printdbg("SVN Parser: skipping invalid commit: %s", (line,)) self.state = SVNParser.COMMIT self.commit = None return # Separator if self.patterns['separator'].match(line): if self.commit is None or self.state == SVNParser.COMMIT: return elif self.state == SVNParser.MESSAGE \ or self.state == SVNParser.FILES: # We can go directly from FILES to COMMIT # when there is an empty log message if self.msg_lines > 0: printout("Warning (%d): parsing svn log, missing " + \ "lines in commit message!", (self.n_line,)) self.__convert_commit_actions(self.commit) self.handler.commit(self.commit) self.state = SVNParser.COMMIT self.commit = None self.msg_lines = 0 else: printout("Warning (%d): parsing svn log, unexpected separator", (self.n_line,)) return # Commit match = self.patterns['commit'].match(line) if match and self.state == SVNParser.COMMIT: commit = Commit() commit.revision = match.group(1) commit.committer = Person() commit.committer.name = match.group(2) commit.commit_date = datetime.datetime(int(match.group(3)), int(match.group(4)), int(match.group(5)), int(match.group(6)), int(match.group(7)), int(match.group(8))) self.msg_lines = int(match.group(10)) self.commit = commit self.handler.committer(commit.committer) return elif match and self.state == SVNParser.MESSAGE: # It seems a piece of a log message has been copied as # part of the commit message self.commit.message += line + '\n' return elif match and self.state != SVNParser.COMMIT: printout("Warning (%d): parsing svn log, unexpected line %s", (self.n_line, line)) return # Files if self.state == SVNParser.COMMIT: if self.patterns['paths'].match(line): self.state = SVNParser.FILES else: printout("Warning(%d): parsing svn log, unexpected line %s", (self.n_line, line)) return # File moved/copied/replaced match = self.patterns['file-moved'].match(line) if match: if self.state != SVNParser.FILES: printout("Warning (%d): parsing svn log, unexpected line %s", (self.n_line, line)) return action = Action() action.type = match.group(1) action.f1 = match.group(2) action.f2 = match.group(3) action.rev = match.group(4) action.branch_f1 = self.__guess_branch_from_path(action.f1) action.branch_f2 = self.__guess_branch_from_path(action.f2) self.commit.actions.append(action) self.handler.file(action.f1) return # File match = self.patterns['file'].match(line) if match: if self.state != SVNParser.FILES: printout("Warning (%d): parsing svn log, unexpected line %s", (self.n_line, line)) return path = match.group(2) if path != '/': # path == '/' is probably a properties change in / # not interesting for us, ignoring action = Action() action.type = match.group(1) action.f1 = path action.branch_f1 = self.__guess_branch_from_path(path) self.commit.actions.append(action) self.handler.file(path) return
def _parse_line(self, line): if line is None or line == '': return # Ignore for patt in self.patterns['ignore']: if patt.match(line): return # Commit match = self.patterns['commit'].match(line) if match: if self.commit is not None: # Skip commits on svn tags if self.branch.tail.svn_tag is None: self.handler.commit(self.branch.tail.commit) self.commit = Commit() self.commit.revision = match.group(1) parents = match.group(3) if parents: parents = parents.split() git_commit = self.GitCommit(self.commit, parents) # If a specific branch has been configured, there # won't be any decoration, so a branch needs to be # created if Config().branch is not None: self.branch = self.GitBranch(self.GitBranch.LOCAL, Config().branch, git_commit) decorate = match.group(5) branch = None if decorate: # Remote branch m = re.search(self.patterns['branch'], decorate) if m: branch = self.GitBranch(self.GitBranch.REMOTE, m.group(1), git_commit) printdbg("Branch '%s' head at acommit %s", (branch.name, self.commit.revision)) else: # Local Branch m = re.search(self.patterns['local-branch'], decorate) if m: branch = self.GitBranch(self.GitBranch.LOCAL, m.group(1), git_commit) printdbg("Commit %s on local branch '%s'", (self.commit.revision, branch.name)) # If local branch was merged we just ignore this # decoration if self.branch and \ self.branch.is_my_parent(git_commit): printdbg("Local branch '%s' was merged", (branch.name,)) branch = None else: # Stash m = re.search(self.patterns['stash'], decorate) if m: branch = self.GitBranch(self.GitBranch.STASH, "stash", git_commit) printdbg("Commit %s on stash", (self.commit.revision,)) # Tag m = re.search(self.patterns['tag'], decorate) if m: self.commit.tags = [m.group(1)] printdbg("Commit %s tagged as '%s'", (self.commit.revision, self.commit.tags[0])) if branch is not None and self.branch is not None: # Detect empty branches. Ideally, the head of a branch # can't have children. When this happens is because the # branch is empty, so we just ignore such branch if self.branch.is_my_parent(git_commit): printout("Warning: Detected empty branch '%s', " + \ "it'll be ignored", (branch.name,)) branch = None if len(self.branches) >= 2: # If current commit is the start point of a new branch # we have to look at all the current branches since # we haven't inserted the new branch yet. # If not, look at all other branches excluding the current one for i, b in enumerate(self.branches): if i == 0 and branch is None: continue if b.is_my_parent(git_commit): # We assume current branch is always the last one # AFAIK there's no way to make sure this is right printdbg("Start point of branch '%s' at commit %s", (self.branches[0].name, self.commit.revision)) self.branches.pop(0) self.branch = b if self.branch and self.branch.tail.svn_tag is not None and \ self.branch.is_my_parent(git_commit): # There's a pending tag in previous commit pending_tag = self.branch.tail.svn_tag printdbg("Move pending tag '%s' from previous commit %s " + \ "to current %s", (pending_tag, self.branch.tail.commit.revision, self.commit.revision)) if self.commit.tags and pending_tag not in self.commit.tags: self.commit.tags.append(pending_tag) else: self.commit.tags = [pending_tag] self.branch.tail.svn_tag = None if branch is not None: self.branch = branch # Insert master always at the end if branch.is_remote() and branch.name == 'master': self.branches.append(self.branch) else: self.branches.insert(0, self.branch) else: self.branch.set_tail(git_commit) if parents and len(parents) > 1 and not Config().analyze_merges: #Skip merge commits self.commit = None return elif self.commit is None: return # Committer match = self.patterns['committer'].match(line) if match: self.commit.committer = Person() self.commit.committer.name = match.group(1) self.commit.committer.email = match.group(2) self.handler.committer(self.commit.committer) return # Author match = self.patterns['author'].match(line) if match: self.commit.author = Person() self.commit.author.name = match.group(1) self.commit.author.email = match.group(2) self.handler.author(self.commit.author) return # Commit Date match = self.patterns['commit-date'].match(line) if match: self.commit.commit_date = datetime.datetime(*(time.strptime(\ match.group(1).strip(" "), "%a %b %d %H:%M:%S %Y")[0:6])) return # Author Date match = self.patterns['author-date'].match(line) if match: self.commit.author_date = datetime.datetime(*(time.strptime(\ match.group(1).strip(" "), "%a %b %d %H:%M:%S %Y")[0:6])) return # File match = self.patterns['file'].match(line) if match: action = Action() action.type = match.group(1) action.f1 = match.group(2) self.commit.actions.append(action) self.handler.file(action.f1) return # File moved/copied match = self.patterns['file-moved'].match(line) if match: action = Action() type = match.group(1) if type == 'R': action.type = 'V' else: action.type = type action.f1 = match.group(3) action.f2 = match.group(2) action.rev = self.commit.revision self.commit.actions.append(action) self.handler.file(action.f1) return # Message self.commit.message += line + '\n' assert True, "Not match for line %s" % (line)
def _parse_line(self, line): if line is None or line == '': return # Separator match = self.patterns['separator'].match(line) if match: self.flush() return # Ignore details about merges match = self.patterns['ignore'].match(line) if match: self.state = BzrParser.UNKNOWN return # Commit match = self.patterns['commit'].match(line) if match: self.flush() self.commit = Commit() self.commit.revision = match.group(1) self.state = BzrParser.COMMIT return # Committer match = self.patterns['committer'].match(line) if match: self.commit.committer = Person() self.commit.committer.name = match.group(1) self.commit.committer.email = match.group(2) self.handler.committer(self.commit.committer) return # Author match = self.patterns['author'].match(line) if match: self.commit.author = Person() self.commit.author.name = match.group(1) self.commit.author.email = match.group(2) self.handler.author(self.commit.author) return # Date match = self.patterns['commit-date'].match(line) if match: self.commit.commit_date = datetime.datetime(*(time.strptime (match.group(1).strip(" "), "%Y-%m-%d %H:%M:%S")[0:6])) # datetime.datetime.strptime not supported by Python2.4 #self.commit.commit_date = datetime.datetime.strptime(\ # match.group(1).strip(" "), "%a %b %d %H:%M:%S %Y") return # Message match = self.patterns['message'].match(line) if match: self.state = BzrParser.MESSAGE return # Added files match = self.patterns['added'].match(line) if match: self.state = BzrParser.ADDED return # Modified files match = self.patterns['modified'].match(line) if match: self.state = BzrParser.MODIFIED return # Removed files match = self.patterns['removed'].match(line) if match: self.state = BzrParser.REMOVED return # Renamed files match = self.patterns['renamed'].match(line) if match: self.state = BzrParser.RENAMED return if self.state == BzrParser.MESSAGE: self.commit.message += line.lstrip() + '\n' elif self.state == BzrParser.ADDED or \ self.state == BzrParser.MODIFIED or \ self.state == BzrParser.REMOVED: action = Action() if self.state == BzrParser.ADDED: action.type = 'A' elif self.state == BzrParser.MODIFIED: action.type = 'M' elif self.state == BzrParser.REMOVED: action.type = 'D' action.f1 = line.strip() self.commit.actions.append(action) self.handler.file(action.f1) elif self.state == BzrParser.RENAMED: m = re.compile("^[ \t]+(.*) => (.*)$").match(line) if not m: return action = Action() action.type = 'V' action.f1 = m.group(2) action.f2 = m.group(1) self.commit.actions.append(action) self.handler.file(action.f1) else: self.state = BzrParser.UNKNOWN
def _parse_line (self, line): if line is None or line == '': return # Ignore for patt in self.patterns['ignore']: if patt.match (line): return # Commit match = self.patterns['commit'].match (line) if match: if self.commit is not None and self.branch.is_remote (): if self.branch.tail.svn_tag is None: # Skip commits on svn tags self.handler.commit (self.branch.tail.commit) self.commit = Commit () self.commit.revision = match.group (1) parents = match.group (3) if parents: parents = parents.split () git_commit = self.GitCommit (self.commit, parents) decorate = match.group (5) branch = None if decorate: # Remote branch m = re.search (self.patterns['branch'], decorate) if m: branch = self.GitBranch (self.GitBranch.REMOTE, m.group (1), git_commit) printdbg ("Branch '%s' head at acommit %s", (branch.name, self.commit.revision)) else: # Local Branch m = re.search (self.patterns['local-branch'], decorate) if m: branch = self.GitBranch (self.GitBranch.LOCAL, m.group (1), git_commit) printdbg ("Commit %s on local branch '%s'", (self.commit.revision, branch.name)) # If local branch was merged we just ignore this decoration if self.branch and self.branch.is_my_parent (git_commit): printdbg ("Local branch '%s' was merged", (branch.name,)) branch = None else: # Stash m = re.search (self.patterns['stash'], decorate) if m: branch = self.GitBranch (self.GitBranch.STASH, "stash", git_commit) printdbg ("Commit %s on stash", (self.commit.revision,)) # Tag m = re.search (self.patterns['tag'], decorate) if m: self.commit.tags = [m.group (1)] printdbg ("Commit %s tagged as '%s'", (self.commit.revision, self.commit.tags[0])) if branch is not None and self.branch is not None: # Detect empty branches. Ideally, the head of a branch # can't have children. When this happens is because the # branch is empty, so we just ignore such branch if self.branch.is_my_parent (git_commit): printout ("Warning: Detected empty branch '%s', it'll be ignored", (branch.name,)) branch = None if len (self.branches) >= 2: # If current commit is the start point of a new branch # we have to look at all the current branches since # we haven't inserted the new branch yet. # If not, look at all other branches excluding the current one for i, b in enumerate (self.branches): if i == 0 and branch is None: continue if b.is_my_parent (git_commit): # We assume current branch is always the last one # AFAIK there's no way to make sure this is right printdbg ("Start point of branch '%s' at commit %s", (self.branches[0].name, self.commit.revision)) self.branches.pop (0) self.branch = b if self.branch and self.branch.tail.svn_tag is not None and self.branch.is_my_parent (git_commit): # There's a pending tag in previous commit pending_tag = self.branch.tail.svn_tag printdbg ("Move pending tag '%s' from previous commit %s to current %s", (pending_tag, self.branch.tail.commit.revision, self.commit.revision)) if self.commit.tags and pending_tag not in self.commit.tags: self.commit.tags.append (pending_tag) else: self.commit.tags = [pending_tag] self.branch.tail.svn_tag = None if branch is not None: self.branch = branch # Insert master always at the end if branch.is_remote () and branch.name == 'master': self.branches.append (self.branch) else: self.branches.insert (0, self.branch) else: self.branch.set_tail (git_commit) return # Committer match = self.patterns['committer'].match (line) if match: self.commit.committer = Person () self.commit.committer.name = match.group (1) self.commit.committer.email = match.group (2) self.handler.committer (self.commit.committer) return # Author match = self.patterns['author'].match (line) if match: self.commit.author = Person () self.commit.author.name = match.group (1) self.commit.author.email = match.group (2) self.handler.author (self.commit.author) return # Date match = self.patterns['date'].match (line) if match: self.commit.date = datetime.datetime (* (time.strptime (match.group (1).strip (" "), "%a %b %d %H:%M:%S %Y")[0:6])) # datetime.datetime.strptime not supported by Python2.4 #self.commit.date = datetime.datetime.strptime (match.group (1).strip (" "), "%a %b %d %H:%M:%S %Y") return # File match = self.patterns['file'].match (line) if match: action = Action () action.type = match.group (1) action.f1 = match.group (2) self.commit.actions.append (action) self.handler.file (action.f1) return # File moved/copied match = self.patterns['file-moved'].match (line) if match: action = Action () type = match.group (1) if type == 'R': action.type = 'V' else: action.type = type action.f1 = match.group (3) action.f2 = match.group (2) action.rev = self.commit.revision self.commit.actions.append (action) self.handler.file (action.f1) return # This is a workaround for a bug in the GNOME Git migration # There are commits on tags not correctly detected like this one: # http://git.gnome.org/cgit/evolution/commit/?id=b8e52acac2b9fc5414a7795a73c74f7ee4eeb71f # We want to ignore commits on tags since it doesn't make any sense in Git if self.is_gnome: match = self.patterns['svn-tag'].match (line.strip ()) if match: printout ("Warning: detected a commit on a svn tag: %s", (match.group (0),)) tag = match.group (1) if self.commit.tags and tag in self.commit.tags: # The commit will be ignored, so move the tag # to the next (previous in history) commit self.branch.tail.svn_tag = tag # Message self.commit.message += line + '\n' assert True, "Not match for line %s" % (line)
def _parse_line(self, line): if line is None or line == '': return # Separator match = self.patterns['separator'].match(line) if match: self.flush() return # Ignore details about merges match = self.patterns['ignore'].match(line) if match: self.state = BzrParser.UNKNOWN return # Commit match = self.patterns['commit'].match(line) if match: self.flush() self.commit = Commit() self.commit.revision = match.group(1) self.state = BzrParser.COMMIT return # Committer match = self.patterns['committer'].match(line) if match: self.commit.committer = Person() self.commit.committer.name = match.group(1) self.commit.committer.email = match.group(2) self.handler.committer(self.commit.committer) return # Author match = self.patterns['author'].match(line) if match: self.commit.author = Person() self.commit.author.name = match.group(1) self.commit.author.email = match.group(2) self.handler.author(self.commit.author) return # Date match = self.patterns['date'].match(line) if match: self.commit.date = datetime.datetime(*(time.strptime (match.group(1).strip(" "), "%Y-%m-%d %H:%M:%S")[0:6])) # datetime.datetime.strptime not supported by Python2.4 #self.commit.date = datetime.datetime.strptime(\ # match.group(1).strip(" "), "%a %b %d %H:%M:%S %Y") return # Message match = self.patterns['message'].match(line) if match: self.state = BzrParser.MESSAGE return # Added files match = self.patterns['added'].match(line) if match: self.state = BzrParser.ADDED return # Modified files match = self.patterns['modified'].match(line) if match: self.state = BzrParser.MODIFIED return # Removed files match = self.patterns['removed'].match(line) if match: self.state = BzrParser.REMOVED return # Renamed files match = self.patterns['renamed'].match(line) if match: self.state = BzrParser.RENAMED return if self.state == BzrParser.MESSAGE: self.commit.message += line.lstrip() + '\n' elif self.state == BzrParser.ADDED or \ self.state == BzrParser.MODIFIED or \ self.state == BzrParser.REMOVED: action = Action() if self.state == BzrParser.ADDED: action.type = 'A' elif self.state == BzrParser.MODIFIED: action.type = 'M' elif self.state == BzrParser.REMOVED: action.type = 'D' action.f1 = line.strip() self.commit.actions.append(action) self.handler.file(action.f1) elif self.state == BzrParser.RENAMED: m = re.compile("^[ \t]+(.*) => (.*)$").match(line) if not m: return action = Action() action.type = 'V' action.f1 = m.group(2) action.f2 = m.group(1) self.commit.actions.append(action) self.handler.file(action.f1) else: self.state = BzrParser.UNKNOWN
def _parse_line(self, line): if line is None or line == '': return # Ignore for patt in self.patterns['ignore']: if patt.match(line): return # Commit match = self.patterns['commit'].match(line) if match: if self.commit is not None: # Skip commits on svn tags if self.branch.tail.svn_tag is None: self.handler.commit(self.branch.tail.commit) if self.patterns['replace-commit'].search(line): printdbg("Skipping commit, because it's a replacement") self.commit = None return self.commit = Commit() self.commit.revision = match.group(1) parents = match.group(3) if parents: parents = parents.split() git_commit = self.GitCommit(self.commit, parents) # If a specific branch has been configured, there # won't be any decoration, so a branch needs to be # created if Config().branch is not None: self.branch = self.GitBranch(self.GitBranch.LOCAL, Config().branch, git_commit) decorate = match.group(5) branch = None if decorate: # Remote branch m = re.search(self.patterns['branch'], decorate) if m: branch = self.GitBranch(self.GitBranch.REMOTE, m.group(2), git_commit) printdbg("Branch '%s' head at acommit %s", (branch.name, self.commit.revision)) else: # Local Branch m = re.search(self.patterns['local-branch'], decorate) if m: branch = self.GitBranch(self.GitBranch.LOCAL, m.group(1), git_commit) printdbg("Commit %s on local branch '%s'", (self.commit.revision, branch.name)) # If local branch was merged we just ignore this # decoration if self.branch and \ self.branch.is_my_parent(git_commit): printdbg("Local branch '%s' was merged", (branch.name, )) branch = None else: # Stash m = re.search(self.patterns['stash'], decorate) if m: branch = self.GitBranch(self.GitBranch.STASH, "stash", git_commit) printdbg("Commit %s on stash", (self.commit.revision, )) # Tag m = re.search(self.patterns['tag'], decorate) if m: self.commit.tags = [m.group(1)] printdbg("Commit %s tagged as '%s'", (self.commit.revision, self.commit.tags[0])) if branch is not None and self.branch is not None: # Detect empty branches. Ideally, the head of a branch # can't have children. When this happens is because the # branch is empty, so we just ignore such branch if self.branch.is_my_parent(git_commit): printout("Warning: Detected empty branch '%s', " + \ "it'll be ignored", (branch.name,)) branch = None if len(self.branches) >= 2: # If current commit is the start point of a new branch # we have to look at all the current branches since # we haven't inserted the new branch yet. # If not, look at all other branches excluding the current one for i, b in enumerate(self.branches): if i == 0 and branch is None: continue if b.is_my_parent(git_commit): # We assume current branch is always the last one # AFAIK there's no way to make sure this is right printdbg("Start point of branch '%s' at commit %s", (self.branches[0].name, self.commit.revision)) self.branches.pop(0) self.branch = b if self.branch and self.branch.tail.svn_tag is not None and \ self.branch.is_my_parent(git_commit): # There's a pending tag in previous commit pending_tag = self.branch.tail.svn_tag printdbg("Move pending tag '%s' from previous commit %s " + \ "to current %s", (pending_tag, self.branch.tail.commit.revision, self.commit.revision)) if self.commit.tags and pending_tag not in self.commit.tags: self.commit.tags.append(pending_tag) else: self.commit.tags = [pending_tag] self.branch.tail.svn_tag = None if branch is not None: self.branch = branch # Insert master always at the end if branch.is_remote() and branch.name == 'master': self.branches.append(self.branch) else: self.branches.insert(0, self.branch) else: self.branch.set_tail(git_commit) if parents and len(parents) > 1 and not Config().analyze_merges: #Skip merge commits self.commit = None return elif self.commit is None: return # Committer match = self.patterns['committer'].match(line) if match: self.commit.committer = Person() self.commit.committer.name = match.group(1) self.commit.committer.email = match.group(2) self.handler.committer(self.commit.committer) return # Author match = self.patterns['author'].match(line) if match: self.commit.author = Person() self.commit.author.name = match.group(1) self.commit.author.email = match.group(2) self.handler.author(self.commit.author) return # Commit Date match = self.patterns['commit-date'].match(line) if match: self.commit.commit_date = datetime.datetime(*(time.strptime(\ match.group(1).strip(" "), "%a %b %d %H:%M:%S %Y")[0:6])) return # Author Date match = self.patterns['author-date'].match(line) if match: self.commit.author_date = datetime.datetime(*(time.strptime(\ match.group(1).strip(" "), "%a %b %d %H:%M:%S %Y")[0:6])) return # File match = self.patterns['file'].match(line) if match: action = Action() action.type = match.group(1) action.f1 = match.group(2) self.commit.actions.append(action) self.handler.file(action.f1) return # File moved/copied match = self.patterns['file-moved'].match(line) if match: action = Action() type = match.group(1) if type == 'R': action.type = 'V' else: action.type = type action.f1 = match.group(3) action.f2 = match.group(2) action.rev = self.commit.revision self.commit.actions.append(action) self.handler.file(action.f1) return # Message self.commit.message += line + '\n' assert True, "Not match for line %s" % (line)
def _parse_line(self, line): if not line: if self.commit is None: return if self.rev_separator is not None: self.rev_separator += '\n' elif self.file_separator is not None: self.file_separator += '\n' elif self.commit.message is not None: self.commit.message += '\n' return # Revision Separator if self.patterns['rev-separator'].match(line): # Ignore separators so that we don't # include it in the commit message if self.rev_separator is None: self.rev_separator = line else: self.rev_separator += line + '\n' return # File Separator if self.patterns['file-separator'].match(line): # Ignore separators so that we don't # include it in the commit message if self.file_separator is None: self.file_separator = line else: self.file_separator += line + '\n' return # File match = self.patterns['file'].match(line) if match: self.flush() path = match.group(1) path = path[len(self.root_path):] path = path[:path.rfind(',')] self.file = path self.branches = {} self.tags = {} self.commit = None self.file_separator = None return # Branch match = self.patterns['branch'].match(line) if match: self.branches[match.group(2) + match.group(4)] = match.group(1) return # Tag (Keep this always after Branch pattern) match = self.patterns['tag'].match(line) if match: revision = match.group(2) # We are ignoring 1.1.1.1 revisions, # so in case there's a tag pointing to that # revision we have to redirect it to 1.1 revision if revision == '1.1.1.1': revision = '1.1' self.tags.setdefault(revision, []).append(match.group(1)) return # Revision match = self.patterns['revision'].match(line) if match and self.rev_separator is not None: self._handle_commit() revision = match.group(1) commit = Commit() # composed rev: revision + | + file path # to make sure revision is unique commit.composed_rev = True commit.revision = "%s|%s" % (revision, self.file) commit.tags = self.tags.get(revision, None) self.commit = commit self.rev_separator = None return # Commit info (date, author, etc.) match = self.patterns['info'].match(line) if match and self.commit is not None: commit = self.commit revision = commit.revision.split('|')[0] if revision == '1.1.1.1': self.commit = None return commit.committer = Person() commit.committer.name = match.group(8) self.handler.committer(commit.committer) commit.date = datetime.datetime(int(match.group(1)), int(match.group(2)), int(match.group(3)), int(match.group(4)), int(match.group(5)), int(match.group(6))) if match.group(10) is not None: self.lines[commit.revision] = (int(match.group(11)), int(match.group(12))) else: self.lines[commit.revision] = (0, 0) action = Action() act = match.group(9) if act == 'dead': action.type = 'D' self.file = self.file.replace('/Attic', '') commit.revision = commit.revision.replace('/Attic', '') elif revision == '1.1': action.type = 'A' else: action.type = 'M' action.f1 = self.file # Branch try: last_dot = revision.rfind('.') prefix = revision[:last_dot] branch = self.branches[prefix] if self.file_added_on_branch and \ self.file_added_on_branch == prefix and \ revision[last_dot + 1:] == '1': action.type = 'A' self.file_added_on_branch = None except KeyError: branch = 'trunk' commit.branch = branch commit.actions.append(action) return # Branches match = self.patterns['branches'].match(line) if match: if self.commit is None: return action = self.commit.actions[0] revision = self.commit.revision.split('|')[0] if action.type == 'D' and revision == '1.1': # File added on a branch self.file_added_on_branch = match.group(1) # Discard this commit self.commit = None return # Message. if self.commit is not None: if self.rev_separator is not None: # Previous separator was probably a # false positive self.commit.message += self.rev_separator + '\n' self.rev_separator = None if self.file_separator is not None: # Previous separator was probably a # false positive self.commit.message += self.file_separator + '\n' self.file_separator = None self.commit.message += line + '\n'
def _parse_line(self, line): if line is None or line == '': return # Ignore for patt in self.patterns['ignore']: if patt.match(line): return # Commit match = self.patterns['commit'].match(line) if match: if self.commit is not None and self.branch is not None: if self.branch.tail.svn_tag is None: # Skip commits on svn tags self.handler.commit(self.branch.tail.commit) self.commit = Commit() self.commit.revision = match.group(1) parents = match.group(3) if parents: parents = parents.split() self.commit.parents = parents git_commit = self.GitCommit(self.commit, parents) decorate = match.group(5) branch = None if decorate: # Remote branch m = re.search(self.patterns['branch'], decorate) if m: branch = self.GitBranch(self.GitBranch.REMOTE, m.group(1), git_commit) printdbg("Branch '%s' head at acommit %s", (branch.name, self.commit.revision)) else: # Local Branch m = re.search(self.patterns['local-branch'], decorate) if m: branch = self.GitBranch(self.GitBranch.LOCAL, m.group(1), git_commit) printdbg("Commit %s on local branch '%s'", (self.commit.revision, branch.name)) # If local branch was merged we just ignore this decoration if self.branch and self.branch.is_my_parent(git_commit): printdbg("Local branch '%s' was merged", (branch.name,)) branch = None else: # Stash m = re.search(self.patterns['stash'], decorate) if m: branch = self.GitBranch(self.GitBranch.STASH, "stash", git_commit) printdbg("Commit %s on stash", (self.commit.revision,)) # Tag m = re.search(self.patterns['tag'], decorate) if m: self.commit.tags = [m.group(1)] printdbg("Commit %s tagged as '%s'", (self.commit.revision, self.commit.tags[0])) if not branch and not self.branch: branch = self.GitBranch(self.GitBranch.LOCAL, "(no-branch)", git_commit) printdbg("Commit %s on unknown local branch '%s'", (self.commit.revision, branch.name)) # This part of code looks wired at first time so here is a small description what it does: # # * self.branch is the branch to which the last inspected commit belonged to # * branch is the branch of the current parsed commit # # This check is only to find branches which are fully merged into a already analyzed branch # # For more detailed information see https://github.com/MetricsGrimoire/CVSAnalY/issues/64 if branch is not None and self.branch is not None: # Detect empty branches. # Ideally, the head of a branch can't have children. # When this happens is because the branch is empty, so we just ignore such branch. if self.branch.is_my_parent(git_commit): printout( "Info: Branch '%s' will be ignored, because it was already merged in an active one.", (branch.name,) ) branch = None if len(self.branches) >= 2: # If current commit is the start point of a new branch # we have to look at all the current branches since # we haven't inserted the new branch yet. # If not, look at all other branches excluding the current one for i, b in enumerate(self.branches): if i == 0 and branch is None: continue if b.is_my_parent(git_commit): # We assume current branch is always the last one # AFAIK there's no way to make sure this is right printdbg("Start point of branch '%s' at commit %s", (self.branches[0].name, self.commit.revision)) self.branches.pop(0) self.branch = b if self.branch and self.branch.tail.svn_tag is not None and self.branch.is_my_parent(git_commit): # There's a pending tag in previous commit pending_tag = self.branch.tail.svn_tag printdbg("Move pending tag '%s' from previous commit %s to current %s", (pending_tag, self.branch.tail.commit.revision, self.commit.revision)) if self.commit.tags and pending_tag not in self.commit.tags: self.commit.tags.append(pending_tag) else: self.commit.tags = [pending_tag] self.branch.tail.svn_tag = None if branch is not None: self.branch = branch # Insert master always at the end if branch.name == 'master': self.branches.append(self.branch) else: self.branches.insert(0, self.branch) else: if self.branch is not None: self.branch.set_tail(git_commit) return # Committer match = self.patterns['committer'].match(line) if match: self.commit.committer = Person() self.commit.committer.name = match.group(1) self.commit.committer.email = match.group(2) self.handler.committer(self.commit.committer) return # Author match = self.patterns['author'].match(line) if match: self.commit.author = Person() self.commit.author.name = match.group(1) self.commit.author.email = match.group(2) self.handler.author(self.commit.author) return # Commit date match = self.patterns['date'].match(line) if match: self.commit.date = datetime.datetime( *(time.strptime(match.group(1).strip(" "), "%a %b %d %H:%M:%S %Y")[0:6])) # datetime.datetime.strptime not supported by Python2.4 #self.commit.date = datetime.datetime.strptime (match.group (1).strip (" "), "%a %b %d %H:%M:%S %Y") # match.group(2) represents the timezone. E.g. -0300, +0200, +0430 (Afghanistan) # This string will be parsed to int and recalculated into seconds (60 * 60) self.commit.date_tz = (((int(match.group(2))) * 60 * 60) / 100) return # Author date match = self.patterns['author_date'].match(line) if match: self.commit.author_date = datetime.datetime( *(time.strptime(match.group(1).strip(" "), "%a %b %d %H:%M:%S %Y")[0:6])) # datetime.datetime.strptime not supported by Python2.4 #self.commit.author_date = datetime.datetime.strptime (match.group (1).strip (" "), "%a %b %d %H:%M:%S %Y") # match.group(2) represents the timezone. E.g. -0300, +0200, +0430 (Afghanistan) # This string will be parsed to int and recalculated into seconds (60 * 60) self.commit.author_date_tz = (((int(match.group(2))) * 60 * 60) / 100) return # File match = self.patterns['file'].match(line) if match: action = Action() type = match.group(1) if len(type) > 1: # merge actions if 'M' in type: type = 'M' else: # ignore merge actions without 'M' return action.type = type action.f1 = match.group(2) self.commit.actions.append(action) self.handler.file(action.f1) return # File moved/copied match = self.patterns['file-moved'].match(line) if match: action = Action() type = match.group(1) if type == 'R': action.type = 'V' else: action.type = type action.f1 = match.group(3) action.f2 = match.group(2) action.rev = self.commit.revision self.commit.actions.append(action) self.handler.file(action.f1) return # This is a workaround for a bug in the GNOME Git migration # There are commits on tags not correctly detected like this one: # http://git.gnome.org/cgit/evolution/commit/?id=b8e52acac2b9fc5414a7795a73c74f7ee4eeb71f # We want to ignore commits on tags since it doesn't make any sense in Git if self.is_gnome: match = self.patterns['svn-tag'].match(line.strip()) if match: printout("Warning: detected a commit on a svn tag: %s", (match.group(0),)) tag = match.group(1) if self.commit.tags and tag in self.commit.tags: # The commit will be ignored, so move the tag # to the next (previous in history) commit self.branch.tail.svn_tag = tag # Message self.commit.message += line + '\n' assert True, "Not match for line %s" % (line)