Exemple #1
0
 def test_class_sublogger_no_context(self):
     profiler = profiling.Profiler('Class.method')
     profiler.start()
     profiler.stop()
     self.assertEqual(log.handlers[0].get_log_events()[0].name,
                      '%s.%s' % (profiling.__name__, 'Class.method'))
Exemple #2
0
 def test_multiple_logging_context(self):
     with profiling.Profiler('profiler1'):
         pass
     with profiling.Profiler('profiler2'):
         pass
     self.assertEqual(len(log.handlers[0].get_log_events()), 2)
Exemple #3
0
 def test_no_sublogger_no_context(self):
     profiler = profiling.Profiler('testing sublogger')
     profiler.start()
     profiler.stop()
     self.assertEqual(log.handlers[0].get_log_events()[0].name,
                      profiling.__name__)
Exemple #4
0
def renderDashboard(req, db, user):
    if user.isAnonymous(): default_show = "open"
    else: default_show = user.getPreference(db, "dashboard.defaultGroups")

    show = req.getParameter("show", default_show)

    if user.isAnonymous():

        def possible(group):
            return group in ("open", "closed")
    else:

        def possible(group):
            return True

    showlist = filter(possible, show.split(","))
    showset = set(showlist)

    if user.getPreference(db, "commit.diff.compactMode"):
        default_compact = "yes"
    else:
        default_compact = "no"

    repository_arg = req.getParameter("repository", None)
    repository = gitutils.Repository.fromParameter(
        db, repository_arg) if repository_arg else None
    compact = req.getParameter("compact", default_compact) == "yes"

    cursor = db.cursor()

    profiler = profiling.Profiler()
    document = htmlutils.Document(req)

    document.setTitle("Dashboard")

    html = document.html()
    head = html.head()
    body = html.body()

    def generateRight(target):
        def addLink(key, title=None):
            if not title: title = key
            if key not in showset:
                target.text("[")
                target.a(href="dashboard?show=%s" %
                         ",".join(showlist + [key])).text("show %s" % title)
                target.text("]")

        if user.isAnonymous():
            addLink("open", "open")
            addLink("closed")
        else:
            target.text("[")
            target.a(href="config?highlight=dashboard.defaultGroups").text(
                "configure defaults")
            target.text("]")

            addLink("owned")
            addLink("draft")
            addLink("active")
            addLink("watched")
            addLink("open", "other open")
            addLink("closed")

    page.utils.generateHeader(body,
                              db,
                              user,
                              current_page="dashboard",
                              generate_right=generateRight,
                              profiler=profiler)

    document.addExternalStylesheet("resource/dashboard.css")
    document.addExternalScript("resource/dashboard.js")
    document.addInternalScript(user.getJS())

    target = body.div("main")

    def flush(target):
        return document.render(stop=target, pretty=not compact)

    def includeReview(review_id):
        if repository:
            cursor = db.cursor()
            cursor.execute(
                "SELECT branches.repository FROM branches JOIN reviews ON (reviews.branch=branches.id) WHERE reviews.id=%s",
                (review_id, ))
            return cursor.fetchone()[0] == repository.id
        else:
            return True

    def sortedReviews(data):
        reviews = []
        for review_id in sorted(data.keys()):
            reviews.append((review_id, data[review_id]))
        return reviews

    def isAccepted(review_ids):
        cursor.execute(
            """SELECT reviews.id, COUNT(reviewfiles.id)=0 AND COUNT(commentchains.id)=0
                            FROM reviews
                 LEFT OUTER JOIN reviewfiles ON (reviewfiles.review=reviews.id
                                             AND reviewfiles.state='pending')
                 LEFT OUTER JOIN commentchains ON (commentchains.review=reviews.id
                                               AND commentchains.type='issue'
                                               AND commentchains.state='open')
                           WHERE reviews.id=ANY (%s)
                        GROUP BY reviews.id""", (review_ids, ))

        return dict(cursor)

    def renderReviews(target, reviews, lines_and_comments=True, links=True):
        cursor.execute("SELECT id, name FROM branches WHERE id=ANY (%s)",
                       (list(branch_id
                             for _, (_, branch_id, _, _) in reviews), ))

        branch_names = dict(cursor)

        cursor.execute(
            "SELECT branches.id, repositories.name FROM branches LEFT JOIN repositories ON (repositories.id = branches.repository) WHERE branches.id=ANY (%s)",
            (list(branch_id for _, (_, branch_id, _, _) in reviews), ))

        repo_names = dict(cursor)

        for review_id, (summary, branch_id, lines, comments) in reviews:
            row = target.tr("review")
            row.td("name").text(branch_names[branch_id])
            row.td("repo_name").text(repo_names[branch_id])
            row.td("title").a(href="r/%d" % review_id).text(summary)

            if lines_and_comments:
                if lines:
                    if links:
                        row.td("lines").a(
                            href="showcommit?review=%d&filter=pending" %
                            review_id).text("%d lines" % (sum(lines)))
                    else:
                        row.td("lines").text("%d lines" % (sum(lines)))
                else:
                    row.td("lines").text()
                if comments:
                    if links:
                        row.td("comments").a(
                            href="showcomments?review=%s&filter=toread" %
                            review_id).text(
                                "%d comment%s" %
                                (comments, "s" if comments > 1 else ""))
                    else:
                        row.td("comments").text(
                            "%d comment%s" %
                            (comments, "s" if comments > 1 else ""))
                else:
                    row.td("comments").text()

    def hidden(what):
        new_show = ",".join(filter(lambda item: item != what, showlist))
        if new_show: return "dashboard?show=%s" % new_show
        else: return "dashboard"

    profiler.check("generate: prologue")

    def renderOwned():
        owned_accepted = []
        owned_open = []

        cursor.execute(
            """SELECT id, summary, branch
                            FROM reviews
                            JOIN reviewusers ON (review=id AND reviewusers.owner)
                           WHERE state='open'
                             AND uid=%s
                        ORDER BY id DESC""", (user.id, ))

        owned = cursor.fetchall()

        profiler.check("query: owned")

        is_accepted = isAccepted(list(review_id for review_id, _, _ in owned))

        for review_id, summary, branch_id in owned:
            if includeReview(review_id):
                if is_accepted[review_id]:
                    owned_accepted.append(
                        (review_id, (summary, branch_id, None, None)))
                else:
                    owned_open.append(
                        (review_id, (summary, branch_id, None, None)))

        profiler.check("processing: owned")

        if owned_accepted or owned_open:
            table = target.table("paleyellow reviews",
                                 id="owned",
                                 align="center",
                                 cellspacing=0)
            table.col(width="15%")
            table.col(width="15%")
            table.col(width="40%")
            table.col(width="15%")
            table.col(width="15%")
            header = table.tr().td("h1", colspan=4).h1()
            header.text("Owned By You")
            header.span("right").a(href=hidden("owned")).text("[hide]")

            if owned_accepted:
                table.tr(id="accepted").td("h2",
                                           colspan=4).h2().text("Accepted")
                renderReviews(table, owned_accepted)

            if owned_open:
                table.tr(id="open").td("h2", colspan=4).h2().text("Pending")
                renderReviews(table, owned_open)

            profiler.check("generate: owned")
            return True

    def renderDraft():
        draft_changes = {}
        draft_comments = {}
        draft_both = {}

        cursor.execute(
            """SELECT reviews.id, reviews.summary, reviews.branch, SUM(reviewfiles.deleted), SUM(reviewfiles.inserted)
                            FROM reviews
                            JOIN reviewfiles ON (reviewfiles.review=reviews.id)
                            JOIN reviewfilechanges ON (reviewfilechanges.file=reviewfiles.id)
                           WHERE reviews.state='open'
                             AND reviewfiles.state=reviewfilechanges.from_state
                             AND reviewfilechanges.state='draft'
                             AND reviewfilechanges.uid=%s
                        GROUP BY reviews.id, reviews.summary, reviews.branch""",
            (user.id, ))

        profiler.check("query: draft lines")

        for review_id, summary, branch_id, deleted_count, inserted_count in cursor:
            if includeReview(review_id):
                draft_changes[review_id] = (summary, branch_id,
                                            (deleted_count,
                                             inserted_count), None)

        profiler.check("processing: draft lines")

        cursor.execute(
            """SELECT reviews.id, reviews.summary, reviews.branch, COUNT(comments.id)
                            FROM reviews
                            JOIN commentchains ON (commentchains.review=reviews.id)
                            JOIN comments ON (comments.chain=commentchains.id)
                           WHERE comments.state='draft'
                             AND comments.uid=%s
                        GROUP BY reviews.id, reviews.summary, reviews.branch""",
            [user.id])

        profiler.check("query: draft comments")

        for review_id, summary, branch_id, comments_count in cursor:
            if includeReview(review_id):
                if draft_changes.has_key(review_id):
                    draft_both[review_id] = (summary, branch_id,
                                             draft_changes[review_id][2],
                                             comments_count)
                    del draft_changes[review_id]
                else:
                    draft_comments[review_id] = (summary, branch_id, None,
                                                 comments_count)

        profiler.check("processing: draft comments")

        if draft_both or draft_changes or draft_comments:
            table = target.table("paleyellow reviews",
                                 id="draft",
                                 align="center",
                                 cellspacing=0)
            table.col(width="15%")
            table.col(width="15%")
            table.col(width="40%")
            table.col(width="15%")
            table.col(width="15%")
            header = table.tr().td("h1", colspan=4).h1()
            header.text("Reviews With Unsubmitted Work")
            header.span("right").a(href=hidden("draft")).text("[hide]")

            if draft_both:
                table.tr(id="draft-changes-comments").td(
                    "h2", colspan=4).h2().text("Draft Changes And Comments")
                renderReviews(table, sortedReviews(draft_both), links=False)

            if draft_changes:
                table.tr(id="draft-changes").td(
                    "h2", colspan=4).h2().text("Draft Changes")
                renderReviews(table, sortedReviews(draft_changes), links=False)

            if draft_comments:
                table.tr(id="draft-comments").td(
                    "h2", colspan=4).h2().text("Draft Comments")
                renderReviews(table,
                              sortedReviews(draft_comments),
                              links=False)

            profiler.check("generate: draft")
            return True

    active = {}

    def fetchActive():
        if not active:
            with_changes = {}
            with_comments = {}
            with_both = {}

            cursor.execute(
                """SELECT reviews.id, reviews.summary, reviews.branch, SUM(reviewfiles.deleted), SUM(reviewfiles.inserted)
                                FROM reviews
                                JOIN reviewusers ON (reviewusers.review=reviews.id
                                                 AND reviewusers.uid=%s)
                                JOIN reviewfiles ON (reviewfiles.review=reviews.id)
                                JOIN reviewuserfiles ON (reviewuserfiles.file=reviewfiles.id
                                                     AND reviewuserfiles.uid=%s)
                               WHERE reviews.state='open'
                                 AND reviewfiles.state='pending'
                            GROUP BY reviews.id, reviews.summary, reviews.branch""",
                (user.id, user.id))

            profiler.check("query: active lines")

            for review_id, summary, branch_id, deleted_count, inserted_count in cursor:
                if includeReview(review_id):
                    with_changes[review_id] = (summary, branch_id,
                                               (deleted_count,
                                                inserted_count), None)

            profiler.check("processing: active lines")

            cursor.execute(
                """SELECT reviews.id, reviews.summary, reviews.branch, unread.count
                                FROM (SELECT commentchains.review AS review, COUNT(commentstoread.comment) AS count
                                        FROM commentchains
                                        JOIN comments ON (comments.chain=commentchains.id)
                                        JOIN commentstoread ON (commentstoread.comment=comments.id
                                                            AND commentstoread.uid=%s)
                                    GROUP BY commentchains.review) AS unread
                                JOIN reviews ON (reviews.id=unread.review)
                               WHERE reviews.state='open'""", (user.id, ))

            profiler.check("query: active comments")

            for review_id, summary, branch_id, comments_count in cursor:
                if includeReview(review_id):
                    if with_changes.has_key(review_id):
                        with_both[review_id] = (summary, branch_id,
                                                with_changes[review_id][2],
                                                comments_count)
                        del with_changes[review_id]
                    else:
                        with_comments[review_id] = (summary, branch_id, None,
                                                    comments_count)

            profiler.check("processing: active comments")

            active["changes"] = with_changes
            active["comments"] = with_comments
            active["both"] = with_both

    def renderActive():
        fetchActive()

        if active["both"] or active["changes"] or active["comments"]:
            table = target.table("paleyellow reviews",
                                 id="active",
                                 align="center",
                                 cellspacing=0)
            table.col(width="15%")
            table.col(width="15%")
            table.col(width="40%")
            table.col(width="15%")
            table.col(width="15%")
            header = table.tr().td("h1", colspan=4).h1()
            header.text("Active Reviews")
            header.span("right").a(href=hidden("active")).text("[hide]")

            if active["both"]:
                review_ids = ",".join(map(str, active["both"].keys()))
                h2 = table.tr(id="active-changes-comments").td(
                    "h2", colspan=4).h2().text("Has Changes And Comments")
                h2.a(href="javascript:void(0);",
                     onclick="markChainsAsRead([%s]);" %
                     review_ids).text("[mark all as read]")
                renderReviews(table, sortedReviews(active["both"]))

            if active["changes"]:
                table.tr(id="active-changes").td(
                    "h2", colspan=4).h2().text("Has Changes")
                renderReviews(table, sortedReviews(active["changes"]))

            if active["comments"]:
                review_ids = ",".join(map(str, active["comments"].keys()))
                h2 = table.tr(id="active-comments").td(
                    "h2", colspan=4).h2().text("Has Comments")
                h2.a(href="javascript:void(0);",
                     onclick="markChainsAsRead([%s]);" %
                     review_ids).text("[mark all as read]")
                renderReviews(table, sortedReviews(active["comments"]))

            profiler.check("generate: active")
            return True

    other = {}

    def fetchWatchedAndClosed():
        if not other:
            if "watched" not in showset:
                state_filter = " WHERE reviews.state='closed'"
            elif "closed" not in showset:
                state_filter = " WHERE reviews.state='open'"
            else:
                state_filter = ""

            profiler.check("query: watched/closed")

            watched = {}
            owned_closed = {}
            other_closed = {}

            if "watched" in showset: fetchActive()

            cursor.execute(
                """SELECT reviews.id, reviews.summary, reviews.branch, reviews.state, reviewusers.owner, reviewusers.uid IS NULL
                                FROM reviews
                     LEFT OUTER JOIN reviewusers ON (reviewusers.review=reviews.id AND reviewusers.uid=%s)"""
                + state_filter, (user.id, ))

            for review_id, summary, branch_id, review_state, is_owner, not_associated in cursor:
                if includeReview(review_id):
                    if review_state == 'open':
                        if is_owner or not_associated:
                            continue

                        fetchActive()

                        if active["both"].has_key(
                                review_id) or active["changes"].has_key(
                                    review_id) or active["comments"].has_key(
                                        review_id):
                            continue

                        watched[review_id] = summary, branch_id, None, None
                    elif is_owner:
                        owned_closed[
                            review_id] = summary, branch_id, None, None
                    else:
                        other_closed[
                            review_id] = summary, branch_id, None, None

            profiler.check("processing: watched/closed")

            other["watched"] = watched
            other["owned-closed"] = owned_closed
            other["other-closed"] = other_closed

    def renderWatched():
        fetchWatchedAndClosed()

        watched = other["watched"]
        accepted = []
        pending = []

        is_accepted = isAccepted(watched.keys())

        for review_id, (summary, branch_id, lines,
                        comments) in sortedReviews(watched):
            if is_accepted[review_id]:
                accepted.append(
                    (review_id, (summary, branch_id, lines, comments)))
            else:
                pending.append(
                    (review_id, (summary, branch_id, lines, comments)))

        if accepted or pending:
            table = target.table("paleyellow reviews",
                                 id="watched",
                                 align="center",
                                 cellspacing=0)
            table.col(width="15%")
            table.col(width="15%")
            table.col(width="70%")
            header = table.tr().td("h1", colspan=4).h1()
            header.text("Watched Reviews")
            header.span("right").a(href=hidden("watched")).text("[hide]")

            if accepted:
                table.tr(id="active-changes-comments").td(
                    "h2", colspan=4).h2().text("Accepted")
                renderReviews(table, accepted, False)

            if pending:
                table.tr(id="active-changes-comments").td(
                    "h2", colspan=4).h2().text("Pending")
                renderReviews(table, pending, False)

            profiler.check("generate: watched")
            return True

    def renderClosed():
        fetchWatchedAndClosed()

        owned_closed = other["owned-closed"]
        other_closed = other["other-closed"]

        if owned_closed or other_closed:
            table = target.table("paleyellow reviews",
                                 id="closed",
                                 align="center",
                                 cellspacing=0)
            table.col(width="15%")
            table.col(width="15%")
            table.col(width="70%")
            header = table.tr().td("h1", colspan=4).h1()
            header.text("Closed Reviews")
            header.span("right").a(href=hidden("closed")).text("[hide]")

            if not user.isAnonymous():
                if owned_closed:
                    table.tr().td("h2", colspan=4).h2().text("Owned")
                    renderReviews(table, sortedReviews(owned_closed), False)

                if other_closed:
                    table.tr().td("h2", colspan=4).h2().text("Other")
                    renderReviews(table, sortedReviews(other_closed), False)
            else:
                renderReviews(table, sortedReviews(other_closed), False)

            profiler.check("generate: closed")
            return True

    def renderOpen():
        other_open = {}

        cursor.execute(
            """SELECT reviews.id, reviews.summary, reviews.branch
                            FROM reviews
                 LEFT OUTER JOIN reviewusers ON (reviewusers.review=reviews.id AND reviewusers.uid=%s)
                           WHERE reviews.state='open'
                             AND reviewusers.uid IS NULL""", [user.id])

        profiler.check("query: open")

        for review_id, summary, branch_id in cursor:
            if includeReview(review_id):
                other_open[review_id] = summary, branch_id, None, None

        profiler.check("processing: open")

        if other_open:
            accepted = []
            pending = []

            for review_id, (summary, branch_id, lines,
                            comments) in sortedReviews(other_open):
                if dbutils.Review.isAccepted(db, review_id):
                    accepted.append(
                        (review_id, (summary, branch_id, lines, comments)))
                else:
                    pending.append(
                        (review_id, (summary, branch_id, lines, comments)))

            table = target.table("paleyellow reviews",
                                 id="open",
                                 align="center",
                                 cellspacing=0)
            table.col(width="15%")
            table.col(width="15%")
            table.col(width="70%")
            header = table.tr().td("h1", colspan=4).h1()
            header.text(
                "Open Reviews" if user.isAnonymous() else "Other Open Reviews")
            header.span("right").a(href=hidden("open")).text("[hide]")

            if accepted:
                table.tr().td("h2", colspan=4).h2().text("Accepted")
                renderReviews(table, accepted, False)

            if pending:
                table.tr().td("h2", colspan=4).h2().text("Pending")
                renderReviews(table, pending, False)

            profiler.check("generate: open")
            return True

    render = {
        "owned": renderOwned,
        "draft": renderDraft,
        "active": renderActive,
        "watched": renderWatched,
        "closed": renderClosed,
        "open": renderOpen
    }

    empty = True

    for item in showlist:
        if item in render:
            target.comment(repr(item))
            if render[item]():
                empty = False
                yield flush(target)

    if empty:
        document.addExternalStylesheet("resource/message.css")
        body.div("message paleyellow").h1("center").text("No reviews!")

    profiler.output(db=db, user=user, target=document)

    yield flush(None)
Exemple #5
0
def renderShowComments(req, db, user):
    context_lines = req.getParameter("context",
                                     user.getPreference(
                                         db, "comment.diff.contextLines"),
                                     filter=int)

    default_compact = "yes" if user.getPreference(
        db, "commit.diff.compactMode") else "no"
    compact = req.getParameter("compact", default_compact) == "yes"

    default_tabify = "yes" if user.getPreference(
        db, "commit.diff.visualTabs") else "no"
    tabify = req.getParameter("tabify", default_tabify) == "yes"

    original = req.getParameter("original", "no") == "yes"

    review_id = req.getParameter("review", filter=int)
    batch_id = req.getParameter("batch", None, filter=int)
    filter = req.getParameter("filter", "all")
    blame = req.getParameter("blame", None)

    profiler = profiling.Profiler()

    review = dbutils.Review.fromId(db, review_id)
    review.repository.enableBlobCache()

    cursor = db.cursor()

    profiler.check("create review")

    if blame is not None:
        blame_user = dbutils.User.fromName(db, blame)

        cursor.execute(
            """SELECT commentchains.id
                            FROM commentchains
                            JOIN commentchainlines ON (commentchainlines.chain=commentchains.id)
                            JOIN fileversions ON (fileversions.new_sha1=commentchainlines.sha1)
                            JOIN changesets ON (changesets.id=fileversions.changeset)
                            JOIN commits ON (commits.id=changesets.child)
                            JOIN gitusers ON (gitusers.id=commits.author_gituser)
                            JOIN usergitemails USING (email)
                            JOIN reviewchangesets ON (reviewchangesets.changeset=changesets.id AND reviewchangesets.review=commentchains.review)
                           WHERE commentchains.review=%s
                             AND usergitemails.uid=%s
                             AND commentchains.state!='empty'
                             AND (commentchains.state!='draft' OR commentchains.uid=%s)
                        ORDER BY commentchains.file, commentchainlines.commit, commentchainlines.first_line""",
            (review.id, blame_user.id, user.id))

        include_chain_ids = set([chain_id for (chain_id, ) in cursor])

        profiler.check("initial blame filtering")
    else:
        include_chain_ids = None

    if filter == "toread":
        query = "SELECT commentchains.id FROM commentchains JOIN comments ON (comments.chain=commentchains.id) JOIN commentstoread ON (commentstoread.comment=comments.id) LEFT OUTER JOIN commentchainlines ON (commentchainlines.chain=commentchains.id) WHERE review=%s AND commentstoread.uid=%s ORDER BY file, commit, first_line"

        cursor.execute(query, (review.id, user.id))
    else:
        query = "SELECT id FROM commentchains LEFT OUTER JOIN commentchainlines ON (chain=id) WHERE review=%s AND commentchains.state!='empty'"
        arguments = [review.id]

        if filter == "issues":
            query += " AND type='issue' AND (commentchains.state!='draft' OR commentchains.uid=%s)"
            arguments.append(user.id)
        elif filter == "draft-issues":
            query += " AND type='issue' AND commentchains.state='draft' AND commentchains.uid=%s"
            arguments.append(user.id)
        elif filter == "open-issues":
            query += " AND type='issue' AND commentchains.state='open'"
        elif filter == "addressed-issues":
            query += " AND type='issue' AND commentchains.state='addressed'"
        elif filter == "closed-issues":
            query += " AND type='issue' AND commentchains.state='closed'"
        elif filter == "notes":
            query += " AND type='note' AND (commentchains.state!='draft' OR commentchains.uid=%s)"
            arguments.append(user.id)
        elif filter == "draft-notes":
            query += " AND type='note' AND commentchains.state='draft' AND commentchains.uid=%s"
            arguments.append(user.id)
        elif filter == "open-notes":
            query += " AND type='note' AND commentchains.state='open'"
        else:
            query += " AND (commentchains.state!='draft' OR commentchains.uid=%s)"
            arguments.append(user.id)

        if batch_id is not None:
            query += " AND batch=%s"
            arguments.append(batch_id)

        # This ordering is inaccurate if comments apply to the same file but
        # different commits, but then, in that case there isn't really a
        # well-defined natural order either.  Two comments that apply to the
        # same file and commit will at least be order by line number, and that's
        # better than nothing.
        query += " ORDER BY file, commit, first_line"

        cursor.execute(query, arguments)

    profiler.check("main query")

    if include_chain_ids is None:
        chain_ids = [chain_id for (chain_id, ) in cursor]
    else:
        chain_ids = [
            chain_id for (chain_id, ) in cursor
            if chain_id in include_chain_ids
        ]

    profiler.check("query result")

    document = htmlutils.Document(req)

    html = document.html()
    head = html.head()
    body = html.body()

    document.addInternalScript(user.getJS(db))
    document.addInternalScript(review.getJS())

    page.utils.generateHeader(
        body,
        db,
        user,
        lambda target: review_utils.renderDraftItems(db, user, review, target),
        extra_links=[("r/%d" % review.id, "Back to Review", True)])

    profiler.check("page header")

    target = body.div("main")

    if chain_ids and not user.isAnonymous() and user.name == req.user:
        document.addInternalScript(
            "$(function () { markChainsAsRead([%s]); });" %
            ", ".join(map(str, chain_ids)))

    #yield document.render(stop=target, pretty=not compact)

    if chain_ids:
        processed = set()

        chains = []
        file_ids = set()
        changesets_files = {}
        changesets = {}

        if blame is not None:
            annotators = {}
            review.branch.loadCommits(db)
            commits = log.commitset.CommitSet(review.branch.commits)

        for chain_id in chain_ids:
            if chain_id in processed:
                continue
            else:
                processed.add(chain_id)

                chain = review_comment.CommentChain.fromId(db,
                                                           chain_id,
                                                           user,
                                                           review=review)
                chains.append(chain)

                if chain.file_id is not None:
                    file_ids.add(chain.file_id)
                    changesets_files.setdefault(
                        (chain.first_commit, chain.last_commit),
                        set()).add(chain.file_id)

        profiler.check("load chains")

        changeset_cache = {}

        for (from_commit,
             to_commit), filtered_file_ids in changesets_files.items():
            changesets[(from_commit,
                        to_commit)] = changeset_utils.createChangeset(
                            db,
                            user,
                            review.repository,
                            from_commit=from_commit,
                            to_commit=to_commit,
                            filtered_file_ids=filtered_file_ids)[0]
            profiler.check("create changesets")

            if blame is not None:
                annotators[(from_commit,
                            to_commit)] = operation.blame.LineAnnotator(
                                db,
                                from_commit,
                                to_commit,
                                file_ids=file_ids,
                                commits=commits,
                                changeset_cache=changeset_cache)
                profiler.check("create annotators")

        for chain in chains:
            if blame is not None and chain.file_id is not None:
                changeset = changesets[(chain.first_commit, chain.last_commit)]
                annotator = annotators[(chain.first_commit, chain.last_commit)]

                offset, count = chain.lines_by_sha1[changeset.getFile(
                    chain.file_id).new_sha1]

                if not annotator.annotate(chain.file_id,
                                          offset,
                                          offset + count - 1,
                                          check_user=blame_user):
                    continue

            profiler.check("detailed blame filtering")

            if chain.file_id is not None:
                from_commit, to_commit = review_html.getCodeCommentChainChangeset(
                    db, chain, original)
                changeset = changesets.get((from_commit, to_commit))
            else:
                changeset = None

            review_html.renderCommentChain(db,
                                           target,
                                           user,
                                           review,
                                           chain,
                                           context_lines=context_lines,
                                           compact=compact,
                                           tabify=tabify,
                                           original=original,
                                           changeset=changeset,
                                           linkify=linkify.Context(
                                               db=db,
                                               request=req,
                                               review=review))

            profiler.check("rendering")

            yield document.render(
                stop=target, pretty=not compact
            ) + "<script>console.log((new Date).toString());</script>"

            profiler.check("transfer")

        page.utils.renderShortcuts(target, "showcomments")
    else:
        target.h1(align="center").text("No comments.")

    profiler.output(db, user, document)

    yield document.render(pretty=not compact)
Exemple #6
0
def renderHome(req, db, user):
    if user.isAnonymous(): raise page.utils.NeedLogin(req)

    profiler = profiling.Profiler()

    cursor = db.cursor()

    readonly = req.getParameter(
        "readonly", "yes" if user.name != req.user else "no") == "yes"
    repository = req.getParameter("repository", None,
                                  gitutils.Repository.FromParameter(db))
    verified_email_id = req.getParameter("email_verified", None, int)

    if not repository:
        repository = user.getDefaultRepository(db)

    title_fullname = user.fullname

    if title_fullname[-1] == 's': title_fullname += "'"
    else: title_fullname += "'s"

    cursor.execute(
        "SELECT email FROM usergitemails WHERE uid=%s ORDER BY email ASC",
        (user.id, ))
    gitemails = ", ".join([email for (email, ) in cursor])

    document = htmlutils.Document(req)

    html = document.html()
    head = html.head()
    body = html.body()

    if user.name == req.user:
        actual_user = None
    else:
        actual_user = req.getUser(db)

    def renderHeaderItems(target):
        if readonly and actual_user and actual_user.hasRole(
                db, "administrator"):
            target.a("button",
                     href="/home?user=%s&readonly=no" % user.name).text("Edit")

    page.utils.generateHeader(body,
                              db,
                              user,
                              generate_right=renderHeaderItems,
                              current_page="home")

    document.addExternalStylesheet("resource/home.css")
    document.addExternalScript("resource/home.js")
    document.addExternalScript("resource/autocomplete.js")
    if repository: document.addInternalScript(repository.getJS())
    else: document.addInternalScript("var repository = null;")
    if actual_user and actual_user.hasRole(db, "administrator"):
        document.addInternalScript("var administrator = true;")
    else:
        document.addInternalScript("var administrator = false;")
    document.addInternalScript(user.getJS())
    document.addInternalScript("user.gitEmails = %s;" % jsify(gitemails))
    document.addInternalScript(
        "var verifyEmailAddresses = %s;" %
        jsify(configuration.base.VERIFY_EMAIL_ADDRESSES))
    document.setTitle("%s Home" % title_fullname)

    target = body.div("main")

    basic = target.table('paleyellow basic', align='center')
    basic.tr().td('h1', colspan=3).h1().text("%s Home" % title_fullname)

    def row(heading, value, help=None, extra_class=None):
        if extra_class:
            row_class = "line " + extra_class
        else:
            row_class = "line"
        main_row = basic.tr(row_class)
        main_row.td('heading').text("%s:" % heading)
        value_cell = main_row.td('value', colspan=2)
        if callable(value): value(value_cell)
        else: value_cell.text(value)
        basic.tr('help').td('help', colspan=3).text(help)

    def renderFullname(target):
        if readonly: target.text(user.fullname)
        else:
            target.input("value", id="user_fullname", value=user.fullname)
            target.span("status", id="status_fullname")
            buttons = target.span("buttons")
            buttons.button(onclick="saveFullname();").text("Save")
            buttons.button(onclick="resetFullname();").text("Reset")

    def renderEmail(target):
        if not actual_user or actual_user.hasRole(db, "administrator"):
            cursor.execute(
                """SELECT id, email, verified
                                FROM useremails
                               WHERE uid=%s
                            ORDER BY id ASC""", (user.id, ))
            rows = cursor.fetchall()
            if rows:
                if len(rows) > 1:
                    target.addClass("multiple")
                addresses = target.div("addresses")
                for email_id, email, verified in rows:
                    checked = "checked" if email == user.email else None
                    selected = " selected" if email == user.email else ""

                    label = addresses.label("address inset flex" + selected,
                                            data_email_id=email_id)
                    if len(rows) > 1:
                        label.input(name="email",
                                    type="radio",
                                    value=email,
                                    checked=checked)
                    label.span("value").text(email)
                    actions = label.span("actions")

                    if verified is False:
                        actions.a("action unverified",
                                  href="#").text("[unverified]")
                    elif verified is True:
                        now = " now" if email_id == verified_email_id else ""
                        actions.span("action verified" +
                                     now).text("[verified]")
                    actions.a("action delete", href="#").text("[delete]")
            else:
                target.i().text("No email address")
            target.span("buttons").button("addemail").text("Add email address")
        elif user.email is None:
            target.i().text("No email address")
        elif user.email_verified is False:
            # Pending verification: don't show to other users.
            target.i().text("Email address not verified")
        else:
            target.span("inset").text(user.email)

    def renderGitEmails(target):
        if readonly: target.text(gitemails)
        else:
            target.input("value", id="user_gitemails", value=gitemails)
            target.span("status", id="status_gitemails")
            buttons = target.span("buttons")
            buttons.button(onclick="saveGitEmails();").text("Save")
            buttons.button(onclick="resetGitEmails();").text("Reset")

    def renderPassword(target):
        cursor.execute("SELECT password IS NOT NULL FROM users WHERE id=%s",
                       (user.id, ))
        has_password = cursor.fetchone()[0]
        if not has_password:
            target.text("not set")
        else:
            target.text("****")
        if not readonly:
            if not has_password or (actual_user and actual_user.hasRole(
                    db, "administrator")):
                target.span("buttons").button(
                    onclick="setPassword();").text("Set password")
            else:
                target.span("buttons").button(
                    onclick="changePassword();").text("Change password")

    row("User ID", str(user.id))
    row("User Name", user.name)
    row("Display Name", renderFullname,
        "This is the name used when displaying commits or comments.")
    row("Primary Email",
        renderEmail,
        "This is the primary email address, to which emails are sent.",
        extra_class="email")
    row(
        "Git Emails", renderGitEmails,
        "These email addresses (comma-separated) are used to map Git commits to the user."
    )

    if configuration.base.AUTHENTICATION_MODE == "critic":
        row("Password", renderPassword, extra_class="password")

    cursor.execute(
        """SELECT provider, account
                        FROM externalusers
                       WHERE uid=%s""", (user.id, ))

    external_accounts = [(auth.PROVIDERS[provider_name], account)
                         for provider_name, account in cursor
                         if provider_name in auth.PROVIDERS]

    if external_accounts:
        basic.tr().td('h2', colspan=3).h2().text("External Accounts")

        for provider, account in external_accounts:

            def renderExternalAccount(target):
                url = provider.getAccountURL(account)
                target.a("external", href=url).text(account)

            row(provider.getTitle(), renderExternalAccount)

    profiler.check("user information")

    filters = page.utils.PaleYellowTable(body, "Filters")
    filters.titleRight.a("button",
                         href="/tutorial?item=filters").text("Tutorial")

    cursor.execute(
        """SELECT repositories.id, repositories.name, repositories.path,
                             filters.id, filters.type, filters.path, NULL, filters.delegate
                        FROM repositories
                        JOIN filters ON (filters.repository=repositories.id)
                       WHERE filters.uid=%s""", (user.id, ))

    rows = cursor.fetchall()

    if configuration.extensions.ENABLED:
        cursor.execute(
            """SELECT repositories.id, repositories.name, repositories.path,
                                 filters.id, 'extensionhook', filters.path, filters.name, filters.data
                            FROM repositories
                            JOIN extensionhookfilters AS filters ON (filters.repository=repositories.id)
                           WHERE filters.uid=%s""", (user.id, ))

        rows.extend(cursor.fetchall())

    FILTER_TYPES = ["reviewer", "watcher", "ignored", "extensionhook"]

    def rowSortKey(row):
        (repository_id, repository_name, repository_path, filter_id,
         filter_type, filter_path, filter_name, filter_data) = row

        # Rows are grouped by repository first and type second, so sort by
        # repository name and filter type primarily.
        #
        # Secondarily sort by filter name (only for extension hook filters; is
        # None for regular filters) and filter path.  This sorting is mostly to
        # achieve a stable order; it has no greater meaning.

        return (repository_name, FILTER_TYPES.index(filter_type), filter_name,
                filter_path)

    rows.sort(key=rowSortKey)

    if rows:
        repository = None
        repository_filters = None
        tbody_reviewer = None
        tbody_watcher = None
        tbody_ignored = None
        tbody_extensionhook = None

        count_matched_files = {}

        for (repository_id, repository_name, repository_path, filter_id,
             filter_type, filter_path, filter_name, filter_data) in rows:
            if not repository or repository.id != repository_id:
                repository = gitutils.Repository.fromId(db, repository_id)
                repository_url = repository.getURL(db, user)
                filters.addSection(repository_name, repository_url)
                repository_filters = filters.addCentered().table(
                    "filters callout")
                tbody_reviewer = tbody_watcher = tbody_ignored = tbody_extensionhook = None

            if filter_type == "reviewer":
                if not tbody_reviewer:
                    tbody_reviewer = repository_filters.tbody()
                    tbody_reviewer.tr().th(colspan=5).text("Reviewer")
                tbody = tbody_reviewer
            elif filter_type == "watcher":
                if not tbody_watcher:
                    tbody_watcher = repository_filters.tbody()
                    tbody_watcher.tr().th(colspan=5).text("Watcher")
                tbody = tbody_watcher
            elif filter_type == "ignored":
                if not tbody_ignored:
                    tbody_ignored = repository_filters.tbody()
                    tbody_ignored.tr().th(colspan=5).text("Ignored")
                tbody = tbody_ignored
            else:
                if not tbody_extensionhook:
                    tbody_extensionhook = repository_filters.tbody()
                    tbody_extensionhook.tr().th(
                        colspan=5).text("Extension hooks")
                tbody = tbody_extensionhook

            row = tbody.tr()
            row.td("path").text(filter_path)

            if filter_type != "extensionhook":
                delegates = row.td("delegates", colspan=2)
                if filter_data:
                    delegates.i().text("Delegates: ")
                    delegates.span("names").text(", ".join(
                        filter_data.split(",")))
            else:
                role = extensions.role.filterhook.getFilterHookRole(
                    db, filter_id)
                if role:
                    title = row.td("title")
                    title.text(role.title)

                    data = row.td("data")
                    data.text(filter_data)
                else:
                    row.td(colspan=2).i().text("Invalid filter")

            if filter_path == "/":
                row.td("files").text("all files")
            else:
                href = "javascript:void(showMatchedFiles(%s, %s));" % (jsify(
                    repository.name), jsify(filter_path))
                row.td("files").a(href=href,
                                  id=("f%d" % filter_id)).text("? files")
                count_matched_files.setdefault(repository_id,
                                               []).append(filter_id)

            links = row.td("links")

            arguments = (jsify(repository.name), filter_id, jsify(filter_type),
                         jsify(filter_path), jsify(filter_data))
            links.a(href="javascript:void(editFilter(%s, %d, %s, %s, %s));" %
                    arguments).text("[edit]")

            if filter_type != "extensionhook":
                links.a(
                    href=
                    "javascript:if (deleteFilterById(%d)) location.reload(); void(0);"
                    % filter_id).text("[delete]")
                links.a(href="javascript:location.href='/config?filter=%d';" %
                        filter_id).text("[preferences]")
            else:
                links.a(
                    href=
                    "javascript:if (deleteExtensionHookFilterById(%d)) location.reload(); void(0);"
                    % filter_id).text("[delete]")

        document.addInternalScript("var count_matched_files = %s;" %
                                   json_encode(count_matched_files.values()))
    else:
        filters.addCentered().p().b().text("No filters")

        # Additionally check if there are in fact no repositories.
        cursor.execute("SELECT 1 FROM repositories")
        if not cursor.fetchone():
            document.addInternalScript("var no_repositories = true;")

    if not readonly:
        filters.addSeparator()
        filters.addCentered().button(
            onclick="editFilter();").text("Add filter")

    profiler.check("filters")

    hidden = body.div("hidden", style="display: none")

    if configuration.extensions.ENABLED:
        filterhooks = extensions.role.filterhook.listFilterHooks(db, user)
    else:
        filterhooks = []

    with hidden.div("filterdialog") as dialog:
        paragraph = dialog.p()
        paragraph.b().text("Repository:")
        paragraph.br()
        page.utils.generateRepositorySelect(db,
                                            user,
                                            paragraph,
                                            name="repository")

        paragraph = dialog.p()
        paragraph.b().text("Filter type:")
        paragraph.br()
        filter_type = paragraph.select(name="type")
        filter_type.option(value="reviewer").text("Reviewer")
        filter_type.option(value="watcher").text("Watcher")
        filter_type.option(value="ignored").text("Ignored")

        for extension, manifest, roles in filterhooks:
            optgroup = filter_type.optgroup(label=extension.getTitle(db))
            for role in roles:
                option = optgroup.option(
                    value="extensionhook",
                    data_extension_id=extension.getExtensionID(db),
                    data_filterhook_name=role.name)
                option.text(role.title)

        paragraph = dialog.p()
        paragraph.b().text("Path:")
        paragraph.br()
        paragraph.input(name="path", type="text")
        paragraph.span("matchedfiles")

        regular_div = dialog.div("regular")

        paragraph = regular_div.p()
        paragraph.b().text("Delegates:")
        paragraph.br()
        paragraph.input(name="delegates", type="text")

        paragraph = regular_div.p()
        label = paragraph.label()
        label.input(name="apply", type="checkbox", checked="checked")
        label.b().text("Apply to existing reviews")

        for extension, manifest, roles in filterhooks:
            for role in roles:
                if not role.data_description:
                    continue

                filterhook_id = "%d_%s" % (extension.getExtensionID(db),
                                           role.name)

                extensionhook_div = dialog.div("extensionhook " +
                                               filterhook_id,
                                               style="display: none")
                extensionhook_div.innerHTML(role.data_description)

                paragraph = extensionhook_div.p()
                paragraph.b().text("Data:")
                paragraph.br()
                paragraph.input(type="text")

    profiler.output(db, user, document)

    return document
Exemple #7
0
def load(data):
    input_stream = InputStream(data)
    lexer = UDMFLexer(input_stream)

    token_stream = CommonTokenStream(lexer)
    parser = UDMFParser(token_stream)
    tree = parser.udmf()

    udmf_map = UDMFMap()
    extractor = UDMFDataExtractor(udmf_map)
    ParseTreeWalker().walk(extractor, tree)

    return udmf_map


if __name__ == '__main__':
    import sys

    if 1 == len(sys.argv):
        print('Usage: %s textmap.txt ...' % __file__)
        sys.exit(0)

    import profiling
    profiler = profiling.Profiler(False)

    for filename in sys.argv[1:]:
        with open(filename) as f:
            print(load(f.read()).astext())

    profiler.close()