Ejemplo n.º 1
0
    def getRelevantFiles(self, db, user):
        if not self.filters:
            from review.filters import Filters

            self.filters = Filters()
            self.filters.load(db, review=self)
            self.relevant_files = self.filters.getRelevantFiles(db, self)

            cursor = db.cursor()
            cursor.execute(
                "SELECT assignee, file FROM fullreviewuserfiles WHERE review=%s",
                (self.id, ))
            for user_id, file_id in cursor:
                self.relevant_files.setdefault(user_id, set()).add(file_id)

        return self.relevant_files.get(user.id, set())
Ejemplo n.º 2
0
def createCommentChain(db,
                       user,
                       review,
                       chain_type,
                       commit_id=None,
                       origin=None,
                       file_id=None,
                       parent_id=None,
                       child_id=None,
                       old_sha1=None,
                       new_sha1=None,
                       offset=None,
                       count=None):
    if chain_type == "issue" and review.state != "open":
        raise OperationFailure(
            code="reviewclosed",
            title="Review is closed!",
            message=
            "You need to reopen the review before you can raise new issues.")

    cursor = db.cursor()

    if file_id is not None and (parent_id == child_id or parent_id is None):
        cursor.execute(
            """SELECT 1
                            FROM reviewchangesets
                            JOIN fileversions USING (changeset)
                           WHERE reviewchangesets.review=%s
                             AND fileversions.file=%s
                             AND fileversions.old_sha1!='0000000000000000000000000000000000000000'
                             AND fileversions.new_sha1!='0000000000000000000000000000000000000000'""",
            (review.id, file_id))

        if cursor.fetchone():
            cursor.execute(
                """SELECT parent, child
                                FROM changesets
                                JOIN reviewchangesets ON (reviewchangesets.changeset=changesets.id)
                                JOIN fileversions ON (fileversions.changeset=changesets.id)
                               WHERE fileversions.file=%s
                                 AND fileversions.new_sha1=%s""",
                (file_id, new_sha1))

            rows = cursor.fetchall()

            if not rows:
                cursor.execute(
                    """SELECT parent, child
                                    FROM changesets
                                    JOIN reviewchangesets ON (reviewchangesets.changeset=changesets.id)
                                    JOIN fileversions ON (fileversions.changeset=changesets.id)
                                   WHERE fileversions.file=%s
                                     AND fileversions.old_sha1=%s""",
                    (file_id, new_sha1))

                rows = cursor.fetchall()

            parent = child = None

            for row_parent_id, row_child_id in rows:
                if row_child_id == child_id:
                    parent = gitutils.Commit.fromId(db, review.repository,
                                                    row_parent_id)
                    child = gitutils.Commit.fromId(db, review.repository,
                                                   row_child_id)
                    break
                elif row_parent_id == child_id and parent is None:
                    parent = gitutils.Commit.fromId(db, review.repository,
                                                    row_parent_id)
                    child = gitutils.Commit.fromId(db, review.repository,
                                                   row_child_id)

            if parent and child:
                url = "/%s/%s..%s?review=%d&file=%d" % (
                    review.repository.name, parent.sha1[:8], child.sha1[:8],
                    review.id, file_id)
                link = (
                    "<p>The link below goes to a diff that can be use to create the comment:</p>"
                    + "<p style='padding-left: 2em'><a href='%s'>%s%s</a></p>"
                ) % (url, dbutils.getURLPrefix(db), url)
            else:
                link = ""

            raise OperationFailure(
                code="notsupported",
                title="File changed in review",
                message=
                ("<p>Due to limitations in the code used to create comments, "
                 +
                 "it's only possible to create comments via a diff view if " +
                 "the commented file has been changed in the review.</p>" +
                 link),
                is_html=True)

        cursor.execute(
            """INSERT INTO commentchains (review, uid, type, file, first_commit, last_commit)
                               VALUES (%s, %s, %s, %s, %s, %s)
                            RETURNING id""",
            (review.id, user.id, chain_type, file_id, child_id, child_id))
        chain_id = cursor.fetchone()[0]

        cursor.execute(
            """INSERT INTO commentchainlines (chain, uid, commit, sha1, first_line, last_line)
                               VALUES (%s, %s, %s, %s, %s, %s)""",
            (chain_id, user.id, child_id, new_sha1, offset,
             offset + count - 1))
    elif file_id is not None:
        parents_returned = set()

        def getFileParent(new_sha1):
            cursor.execute(
                """SELECT changesets.id, fileversions.old_sha1
                                FROM changesets, reviewchangesets, fileversions
                               WHERE reviewchangesets.review=%s
                                 AND reviewchangesets.changeset=changesets.id
                                 AND fileversions.changeset=changesets.id
                                 AND fileversions.file=%s
                                 AND fileversions.new_sha1=%s""",
                [review.id, file_id, new_sha1])
            try:
                changeset_id, old_sha1 = cursor.fetchone()
                if old_sha1 in parents_returned: return None, None
                parents_returned.add(old_sha1)
                return changeset_id, old_sha1
            except:
                return None, None

        children_returned = set()

        def getFileChild(old_sha1):
            cursor.execute(
                """SELECT changesets.id, fileversions.new_sha1
                                FROM changesets, reviewchangesets, fileversions
                               WHERE reviewchangesets.review=%s
                                 AND reviewchangesets.changeset=changesets.id
                                 AND fileversions.changeset=changesets.id
                                 AND fileversions.file=%s
                                 AND fileversions.old_sha1=%s""",
                [review.id, file_id, old_sha1])
            try:
                changeset_id, new_sha1 = cursor.fetchone()
                if new_sha1 in children_returned: return None, None
                children_returned.add(new_sha1)
                return changeset_id, new_sha1
            except:
                return None, None

        cursor.execute(
            """SELECT changesets.id
                            FROM changesets, reviewchangesets, fileversions
                           WHERE reviewchangesets.review=%s
                             AND reviewchangesets.changeset=changesets.id
                             AND changesets.child=%s
                             AND fileversions.changeset=changesets.id
                             AND fileversions.file=%s
                             AND fileversions.old_sha1=%s
                             AND fileversions.new_sha1=%s""",
            [review.id, child_id, file_id, old_sha1, new_sha1])

        row = cursor.fetchone()

        if not row:
            if origin == "old":
                cursor.execute(
                    """SELECT changesets.id
                                    FROM changesets, reviewchangesets, fileversions
                                   WHERE reviewchangesets.review=%s
                                     AND reviewchangesets.changeset=changesets.id
                                     AND fileversions.changeset=changesets.id
                                     AND fileversions.file=%s
                                     AND fileversions.old_sha1=%s""",
                    [review.id, file_id, old_sha1])
            else:
                cursor.execute(
                    """SELECT changesets.id
                                    FROM changesets, reviewchangesets, fileversions
                                   WHERE reviewchangesets.review=%s
                                     AND reviewchangesets.changeset=changesets.id
                                     AND fileversions.changeset=changesets.id
                                     AND fileversions.file=%s
                                     AND fileversions.new_sha1=%s""",
                    [review.id, file_id, new_sha1])

            row = cursor.fetchone()

        primary_changeset_id = row[0]

        sha1s_older = {}
        sha1s_newer = {old_sha1: (primary_changeset_id, new_sha1)}

        sha1 = new_sha1
        while True:
            changeset_id, next_sha1 = getFileParent(sha1)
            if changeset_id:
                sha1s_older[sha1] = changeset_id, next_sha1
                sha1s_newer[next_sha1] = changeset_id, sha1
                sha1 = next_sha1
            else:
                break

        sha1 = new_sha1
        while True:
            changeset_id, next_sha1 = getFileChild(sha1)
            if changeset_id:
                sha1s_newer[sha1] = changeset_id, next_sha1
                sha1 = next_sha1
            else:
                break

        commentchainlines_values = []
        processed = set()

        def searchOrigin(changeset_id, sha1, search_space, first_line,
                         last_line):
            try:
                while sha1 not in processed:
                    processed.add(sha1)
                    changeset_id, next_sha1 = search_space[sha1]
                    changeset = changeset_load.loadChangeset(
                        db,
                        review.repository,
                        changeset_id,
                        filtered_file_ids=set([file_id]))
                    if len(changeset.child.parents) > 1: break
                    verdict, next_first_line, next_last_line = updateCommentChain(
                        first_line, last_line, changeset.files[0].chunks,
                        forward)
                    if verdict == "modified": break
                    sha1 = next_sha1
                    first_line = next_first_line
                    last_line = next_last_line
            except:
                pass
            return changeset_id, sha1, first_line, last_line

        first_line = offset
        last_line = offset + count - 1

        if origin == 'old':
            changeset_id, sha1, first_line, last_line = searchOrigin(
                primary_changeset_id, old_sha1, sha1s_older, first_line,
                last_line)
            commit_id = diff.Changeset.fromId(db, review.repository,
                                              changeset_id).parent.id
        else:
            changeset_id, sha1, first_line, last_line = searchOrigin(
                primary_changeset_id, new_sha1, sha1s_older, first_line,
                last_line)
            commit_id = diff.Changeset.fromId(db, review.repository,
                                              changeset_id).child.id

        commentchainlines_values.append(
            (user.id, commit_id, sha1, first_line, last_line))
        processed = set()
        processed.add(sha1)

        while sha1 in sha1s_newer:
            changeset_id, sha1 = sha1s_newer[sha1]

            if sha1 in processed: break
            else: processed.add(sha1)

            changeset = changeset_load.loadChangeset(db,
                                                     review.repository,
                                                     changeset_id,
                                                     filtered_file_ids=set(
                                                         [file_id]))

            if len(changeset.child.parents) != 1:
                chunks = diff.parse.parseDifferences(
                    review.repository,
                    from_commit=changeset.parent,
                    to_commit=changeset.child,
                    selected_path=dbutils.describe_file(db, file_id)).chunks
            else:
                chunks = changeset.files[0].chunks

            verdict, first_line, last_line = updateCommentChain(
                first_line, last_line, chunks)

            if verdict == "transfer":
                commentchainlines_values.append(
                    (user.id, changeset.child.getId(db), sha1, first_line,
                     last_line))
            else:
                break

        cursor.execute(
            "INSERT INTO commentchains (review, uid, type, origin, file, first_commit, last_commit) VALUES (%s, %s, %s, %s, %s, %s, %s) RETURNING id",
            [
                review.id, user.id, chain_type, origin, file_id, parent_id,
                child_id
            ])
        chain_id = cursor.fetchone()[0]

        try:
            cursor.executemany(
                "INSERT INTO commentchainlines (chain, uid, commit, sha1, first_line, last_line) VALUES (%s, %s, %s, %s, %s, %s)",
                [(chain_id, ) + values for values in commentchainlines_values])
        except:
            raise Exception, repr(commentchainlines_values)
    elif commit_id is not None:
        commit = gitutils.Commit.fromId(db, review.repository, commit_id)

        cursor.execute(
            "INSERT INTO commentchains (review, uid, type, first_commit, last_commit) VALUES (%s, %s, %s, %s, %s) RETURNING id",
            [review.id, user.id, chain_type, commit_id, commit_id])
        chain_id = cursor.fetchone()[0]

        cursor.execute(
            "INSERT INTO commentchainlines (chain, uid, commit, sha1, first_line, last_line) VALUES (%s, %s, %s, %s, %s, %s)",
            (chain_id, user.id, commit_id, commit.sha1, offset,
             offset + count - 1))
    else:
        cursor.execute(
            "INSERT INTO commentchains (review, uid, type) VALUES (%s, %s, %s) RETURNING id",
            [review.id, user.id, chain_type])
        chain_id = cursor.fetchone()[0]

    commentchainusers = set([user.id] + map(int, review.owners))

    if file_id is not None:
        filters = Filters()
        filters.load(db, review=review)

        for user_id in filters.listUsers(db, file_id):
            commentchainusers.add(user_id)

    cursor.executemany(
        "INSERT INTO commentchainusers (chain, uid) VALUES (%s, %s)",
        [(chain_id, user_id) for user_id in commentchainusers])

    return chain_id