Exemplo n.º 1
0
def commitRangeFromReview(db, user, review, filter, file_ids):
    edges = cursor = db.cursor()

    if filter == "pending":
        cursor.execute("""SELECT DISTINCT changesets.parent, changesets.child
                            FROM changesets
                            JOIN reviewfiles ON (reviewfiles.changeset=changesets.id)
                            JOIN reviewuserfiles ON (reviewuserfiles.file=reviewfiles.id)
                           WHERE reviewfiles.review=%s
                             AND reviewuserfiles.uid=%s
                             AND reviewfiles.state='pending'""",
                       (review.id, user.id))
    elif filter == "reviewable":
        cursor.execute("""SELECT DISTINCT changesets.parent, changesets.child
                            FROM changesets
                            JOIN reviewfiles ON (reviewfiles.changeset=changesets.id)
                            JOIN reviewuserfiles ON (reviewuserfiles.file=reviewfiles.id)
                           WHERE reviewfiles.review=%s
                             AND reviewuserfiles.uid=%s""",
                       (review.id, user.id))
    elif filter == "relevant":
        filters = review_filters.Filters()
        filters.load(db, review=review, user=user)

        cursor.execute("""SELECT DISTINCT changesets.parent, changesets.child, reviewfiles.file, reviewuserfiles.uid IS NOT NULL
                            FROM changesets
                            JOIN reviewfiles ON (reviewfiles.changeset=changesets.id)
                 LEFT OUTER JOIN reviewuserfiles ON (reviewuserfiles.file=reviewfiles.id
                                                 AND reviewuserfiles.uid=%s)
                           WHERE reviewfiles.review=%s""",
                       (user.id, review.id))

        edges = set()

        for parent_id, child_id, file_id, is_reviewer in cursor:
            if is_reviewer or filters.isRelevant(db, user, file_id):
                edges.add((parent_id, child_id))
    elif filter == "files":
        assert len(file_ids) != 0

        cursor.execute("""SELECT DISTINCT changesets.parent, changesets.child
                            FROM changesets
                            JOIN reviewchangesets ON (reviewchangesets.changeset=changesets.id)
                            JOIN fileversions ON (fileversions.changeset=changesets.id)
                           WHERE reviewchangesets.review=%s
                             AND fileversions.file=ANY (%s)""",
                       (review.id, list(file_ids)))
    else:
        raise Exception, "invalid filter: %s" % filter

    listed_commits = set()
    with_pending = set()

    for parent_id, child_id in edges:
        listed_commits.add(child_id)
        with_pending.add((parent_id, child_id))

    if len(listed_commits) == 1:
        return None, gitutils.Commit.fromId(db, review.repository, child_id).sha1, list(listed_commits), listed_commits

    if filter in ("reviewable", "relevant", "files"):
        cursor.execute("SELECT child FROM changesets JOIN reviewchangesets ON (changeset=id) WHERE review=%s", (review.id,))
        all_commits = [gitutils.Commit.fromId(db, review.repository, commit_id) for (commit_id,) in cursor]

        commitset = CommitSet(review.branch.commits)
        tails = commitset.getFilteredTails(review.repository)

        if len(commitset) == 0: raise Exception, "empty commit-set"
        elif len(tails) > 1:
            ancestor = review.repository.getCommonAncestor(tails)
            paths = []

            cursor.execute("SELECT DISTINCT file FROM reviewfiles WHERE review=%s", (review.id,))
            files_in_review = set(file_id for (file_id,) in cursor)

            if filter == "files":
                files_in_review &= file_ids

            paths_in_review = set(dbutils.describe_file(db, file_id) for file_id in files_in_review)
            paths_in_upstreams = set()

            for tail in tails:
                paths_in_upstream = set(review.repository.run("diff", "--name-only", "%s..%s" % (ancestor, tail)).splitlines())
                paths_in_upstreams |= paths_in_upstream

                paths.append((tail, paths_in_upstream))

            overlapping_changes = paths_in_review & paths_in_upstreams

            if overlapping_changes:
                candidates = []

                for index1, data in enumerate(paths):
                    for index2, (tail, paths_in_upstream) in enumerate(paths):
                        if index1 != index2 and paths_in_upstream & paths_in_review:
                            break
                    else:
                        candidates.append(data)
            else:
                candidates = paths

            if not candidates:
                paths.sort(cmp=lambda a, b: cmp(len(a[1]), len(b[1])))

                url = "/%s/%s..%s?file=%s" % (review.repository.name, paths[0][0][:8], review.branch.head.sha1[:8], ",".join(map(str, sorted(files_in_review))))

                message = """\
<p>It is not possible to generate a diff of the requested set of
commits that contains only changes from those commits.</p>

<p>The following files would contain unrelated changes:<p>
<pre style='padding-left: 2em'>%s</pre>

<p>You can use the URL below if you want to view this diff anyway,
including the unrelated changes.</p>
<pre style='padding-left: 2em'><a href='%s'>%s%s</a></pre>""" % ("\n".join(sorted(overlapping_changes)), url, dbutils.getURLPrefix(db), url)

                raise page.utils.DisplayMessage(title="Impossible Diff",
                                                body=message,
                                                review=review,
                                                html=True)
            else:
                candidates.sort(cmp=lambda a, b: cmp(len(b[1]), len(a[1])))

                return candidates[0][0], review.branch.head.sha1, all_commits, listed_commits

        elif len(tails) == 0: raise Exception, "impossible commit-set (%r)" % commitset

        return tails.pop(), review.branch.head.sha1, all_commits, listed_commits
Exemplo n.º 2
0
 def getFilteredTails(self):
     commitset = CommitSet(self.branch.commits)
     return commitset.getFilteredTails(self.branch.repository)
Exemplo n.º 3
0
def commitRangeFromReview(db, user, review, filter, file_ids):
    edges = cursor = db.cursor()

    if filter == "pending":
        cursor.execute("""SELECT DISTINCT changesets.parent, changesets.child
                            FROM changesets
                            JOIN reviewfiles ON (reviewfiles.changeset=changesets.id)
                            JOIN reviewuserfiles ON (reviewuserfiles.file=reviewfiles.id)
                           WHERE reviewfiles.review=%s
                             AND reviewuserfiles.uid=%s
                             AND reviewfiles.state='pending'""",
                       (review.id, user.id))
    elif filter == "reviewable":
        cursor.execute("""SELECT DISTINCT changesets.parent, changesets.child
                            FROM changesets
                            JOIN reviewfiles ON (reviewfiles.changeset=changesets.id)
                            JOIN reviewuserfiles ON (reviewuserfiles.file=reviewfiles.id)
                           WHERE reviewfiles.review=%s
                             AND reviewuserfiles.uid=%s""",
                       (review.id, user.id))
    elif filter == "relevant":
        filters = review_filters.Filters()
        filters.load(db, review=review, user=user)

        cursor.execute("""SELECT DISTINCT changesets.parent, changesets.child, reviewfiles.file, reviewuserfiles.uid IS NOT NULL
                            FROM changesets
                            JOIN reviewfiles ON (reviewfiles.changeset=changesets.id)
                 LEFT OUTER JOIN reviewuserfiles ON (reviewuserfiles.file=reviewfiles.id
                                                 AND reviewuserfiles.uid=%s)
                           WHERE reviewfiles.review=%s""",
                       (user.id, review.id))

        edges = set()

        for parent_id, child_id, file_id, is_reviewer in cursor:
            if is_reviewer or filters.isRelevant(db, user, file_id):
                edges.add((parent_id, child_id))
    elif filter == "files":
        assert len(file_ids) != 0

        cursor.execute("""SELECT DISTINCT changesets.parent, changesets.child
                            FROM changesets
                            JOIN reviewchangesets ON (reviewchangesets.changeset=changesets.id)
                            JOIN fileversions ON (fileversions.changeset=changesets.id)
                           WHERE reviewchangesets.review=%s
                             AND fileversions.file=ANY (%s)""",
                       (review.id, list(file_ids)))
    else:
        raise Exception, "invalid filter: %s" % filter

    listed_commits = set()
    with_pending = set()

    for parent_id, child_id in edges:
        listed_commits.add(child_id)
        with_pending.add((parent_id, child_id))

    if len(listed_commits) == 1:
        return None, gitutils.Commit.fromId(db, review.repository, child_id).sha1, list(listed_commits), listed_commits

    if filter in ("reviewable", "relevant", "files"):
        cursor.execute("SELECT child FROM changesets JOIN reviewchangesets ON (changeset=id) WHERE review=%s", (review.id,))
        all_commits = [gitutils.Commit.fromId(db, review.repository, commit_id) for (commit_id,) in cursor]

        commitset = CommitSet(review.branch.commits)
        tails = commitset.getFilteredTails(review.repository)

        if len(commitset) == 0: raise Exception, "empty commit-set"
        elif len(tails) > 1:
            ancestor = review.repository.getCommonAncestor(tails)
            paths = []

            cursor.execute("SELECT DISTINCT file FROM reviewfiles WHERE review=%s", (review.id,))
            files_in_review = set(file_id for (file_id,) in cursor)

            if filter == "files":
                files_in_review &= file_ids

            paths_in_review = set(dbutils.describe_file(db, file_id) for file_id in files_in_review)
            paths_in_upstreams = set()

            for tail in tails:
                paths_in_upstream = set(review.repository.run("diff", "--name-only", "%s..%s" % (ancestor, tail)).splitlines())
                paths_in_upstreams |= paths_in_upstream

                paths.append((tail, paths_in_upstream))

            overlapping_changes = paths_in_review & paths_in_upstreams

            if overlapping_changes:
                candidates = []

                for index1, data in enumerate(paths):
                    for index2, (tail, paths_in_upstream) in enumerate(paths):
                        if index1 != index2 and paths_in_upstream & paths_in_review:
                            break
                    else:
                        candidates.append(data)
            else:
                candidates = paths

            if not candidates:
                paths.sort(cmp=lambda a, b: cmp(len(a[1]), len(b[1])))

                url = "/%s/%s..%s?file=%s" % (review.repository.name, paths[0][0][:8], review.branch.head.sha1[:8], ",".join(map(str, sorted(files_in_review))))

                message = """\
<p>It is not possible to generate a diff of the requested set of
commits that contains only changes from those commits.</p>

<p>The following files would contain unrelated changes:<p>
<pre style='padding-left: 2em'>%s</pre>

<p>You can use the URL below if you want to view this diff anyway,
including the unrelated changes.</p>
<pre style='padding-left: 2em'><a href='%s'>%s%s</a></pre>""" % ("\n".join(sorted(overlapping_changes)), url, dbutils.getURLPrefix(db), url)

                raise page.utils.DisplayMessage(title="Impossible Diff",
                                                body=message,
                                                review=review,
                                                html=True)
            else:
                candidates.sort(cmp=lambda a, b: cmp(len(b[1]), len(a[1])))

                return candidates[0][0], review.branch.head.sha1, all_commits, listed_commits

        elif len(tails) == 0: raise Exception, "impossible commit-set (%r)" % commitset

        return tails.pop(), review.branch.head.sha1, all_commits, listed_commits
Exemplo n.º 4
0
 def getFilteredTails(self):
     commitset = CommitSet(self.branch.commits)
     return commitset.getFilteredTails(self.branch.repository)