Example #1
0
    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
Example #2
0
    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
Example #3
0
    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'