Пример #1
0
def showfilters(req, db, user):
    path = req.getParameter("path", "/")
    repo_name = req.getParameter("repository", None)
    if not repo_name:
        user = req.getParameter("user", req.user)
        if not user:
            raise page.utils.DisplayMessage(
                "The URL must contain either a repository or a user parameter or both."
            )
        repo_name = dbutils.User.fromName(db, user).getPreference(
            db, "defaultRepository")
    repository = gitutils.Repository.fromParameter(db, repo_name)

    path = path.rstrip("/")

    if repository.getHead(db).isDirectory(path):
        show_path = path + "/"
        path += "/dummy.txt"
    else:
        show_path = path

    file_id = dbutils.find_file(db, path=path)

    filters = review_filters.Filters()
    filters.setFiles(db, [file_id])
    filters.load(db, repository=repository, recursive=True)

    reviewers = []
    watchers = []

    for user_id, (filter_type,
                  _delegate) in filters.listUsers(file_id).items():
        if filter_type == 'reviewer': reviewers.append(user_id)
        else: watchers.append(user_id)

    result = "Path: %s\n" % show_path

    reviewers_found = False
    watchers_found = False

    for reviewer_id in sorted(reviewers):
        if not reviewers_found:
            result += "\nReviewers:\n"
            reviewers_found = True

        reviewer = dbutils.User.fromId(db, reviewer_id)
        result += "  %s <%s>\n" % (reviewer.fullname, reviewer.email)

    for watcher_id in sorted(watchers):
        if not watchers_found:
            result += "\nWatchers:\n"
            watchers_found = True

        watcher = dbutils.User.fromId(db, watcher_id)
        result += "  %s <%s>\n" % (watcher.fullname, watcher.email)

    if not reviewers_found and not watchers_found:
        result += "\nNo matching filters found.\n"

    return result
Пример #2
0
def parseReviewFilters(db, data):
    reviewfilters = []

    for filter_data in data:
        filter_username = filter_data["username"]
        filter_type = filter_data["type"]
        filter_path = filter_data["path"]

        filter_user = dbutils.User.fromName(db, filter_username)
        if not filter_user:
            raise OperationError("no such user: '******'" % filter_username)

        filter_directory_id = 0
        filter_file_id = 0

        if filter_path != "/":
            if filter_path[-1] == "/" or dbutils.is_directory(filter_path):
                filter_directory_id = dbutils.find_directory(db,
                                                             path=filter_path)
            else:
                filter_file_id = dbutils.find_file(db, path=filter_path)

        reviewfilters.append((filter_directory_id, filter_file_id, filter_type,
                              None, filter_user.id))

    return reviewfilters
Пример #3
0
    def process(self, db, creator, review_id, filters):
        review = dbutils.Review.fromId(db, review_id)
        by_user = {}

        for filter in filters:
            if "user_ids" in filter:
                user_ids = set(filter["user_ids"])
            else:
                user_ids = set([])

            if "user_names" in filter:
                for user_name in filter["user_names"]:
                    user_ids.add(dbutils.User.fromName(db, user_name).id)

            if "directory_ids" in filter:
                directory_ids = set(filter["directory_ids"])
            else:
                directory_ids = set([])

            if "file_ids" in filter:
                file_ids = set(filter["file_ids"])
            else:
                file_ids = set([])

            if "paths" in filter:
                for path in filter["paths"]:
                    if not path or path == "/":
                        directory_ids.add(0)
                    elif path.endswith("/") or dbutils.is_directory(
                            db, path) or ("." not in path.split("/")[-1]
                                          and not dbutils.is_file(db, path)):
                        directory_ids.add(dbutils.find_directory(db, path))
                    else:
                        file_ids.add(dbutils.find_file(db, path))

            for user_id in user_ids:
                reviewer_directory_ids, reviewer_file_ids, watcher_directory_ids, watcher_file_ids = by_user.setdefault(
                    user_id, (set(), set(), set(), set()))

                if filter["type"] == "reviewer":
                    reviewer_directory_ids |= directory_ids
                    reviewer_file_ids |= file_ids
                else:
                    watcher_directory_ids |= directory_ids
                    watcher_file_ids |= file_ids

        pending_mails = []

        for user_id, args in by_user.items():
            user = dbutils.User.fromId(db, user_id)
            pending_mails.extend(
                review_utils.addReviewFilters(db, creator, user, review,
                                              *args))

        db.commit()

        mailutils.sendPendingMails(pending_mails)

        return OperationResult()
Пример #4
0
def showfilters(req, db, user):
    user = dbutils.User.fromName(db, req.getParameter("user", req.user))
    path = req.getParameter("path")
    repository = gitutils.Repository.fromParameter(db, req.getParameter("repository", user.getPreference(db, "defaultRepository")))

    path = path.rstrip("/")

    if dbutils.is_directory(db, path):
        directory_id = dbutils.find_directory(db, path=path)
        show_path = path + "/"

        cursor = db.cursor()
        cursor.execute("SELECT name FROM files WHERE directory=%s ORDER BY id ASC LIMIT 1", (directory_id,))

        row = cursor.fetchone()
        if row: path += "/" + row[0]
        else: path += "/dummy.txt"
    else:
        show_path = path

    file_id = dbutils.find_file(db, path=path)

    filters = review_filters.Filters()
    filters.load(db, repository=repository, recursive=True)

    reviewers = []
    watchers = []

    for user_id, (filter_type, _delegate) in filters.listUsers(db, file_id).items():
        if filter_type == 'reviewer': reviewers.append(user_id)
        else: watchers.append(user_id)

    result = "Path: %s\n" % show_path

    reviewers_found = False
    watchers_found = False

    for reviewer_id in sorted(reviewers):
        if not reviewers_found:
            result += "\nReviewers:\n"
            reviewers_found = True

        reviewer = dbutils.User.fromId(db, reviewer_id)
        result += "  %s <%s>\n" % (reviewer.fullname, reviewer.email)

    for watcher_id in sorted(watchers):
        if not watchers_found:
            result += "\nWatchers:\n"
            watchers_found = True

        watcher = dbutils.User.fromId(db, watcher_id)
        result += "  %s <%s>\n" % (watcher.fullname, watcher.email)

    if not reviewers_found and not watchers_found:
        result += "\nNo matching filters found.\n"

    return result
Пример #5
0
def showfilters(req, db, user):
    path = req.getParameter("path", "/")
    repo_name = req.getParameter("repository", None)
    if not repo_name:
        user = req.getParameter("user", req.user)
        if not user:
            raise page.utils.DisplayMessage("The URL must contain either a repository or a user parameter or both.")
        repo_name = dbutils.User.fromName(db, user).getPreference(db, "defaultRepository")
    repository = gitutils.Repository.fromParameter(db, repo_name)

    path = path.rstrip("/")

    if repository.getHead(db).isDirectory(path):
        show_path = path + "/"
        path += "/dummy.txt"
    else:
        show_path = path

    file_id = dbutils.find_file(db, path=path)

    filters = review_filters.Filters()
    filters.setFiles(db, [file_id])
    filters.load(db, repository=repository, recursive=True)

    reviewers = []
    watchers = []

    for user_id, (filter_type, _delegate) in filters.listUsers(file_id).items():
        if filter_type == 'reviewer': reviewers.append(user_id)
        else: watchers.append(user_id)

    result = "Path: %s\n" % show_path

    reviewers_found = False
    watchers_found = False

    for reviewer_id in sorted(reviewers):
        if not reviewers_found:
            result += "\nReviewers:\n"
            reviewers_found = True

        reviewer = dbutils.User.fromId(db, reviewer_id)
        result += "  %s <%s>\n" % (reviewer.fullname, reviewer.email)

    for watcher_id in sorted(watchers):
        if not watchers_found:
            result += "\nWatchers:\n"
            watchers_found = True

        watcher = dbutils.User.fromId(db, watcher_id)
        result += "  %s <%s>\n" % (watcher.fullname, watcher.email)

    if not reviewers_found and not watchers_found:
        result += "\nNo matching filters found.\n"

    return result
Пример #6
0
    def process(self, db, creator, review_id, filters):
        review = dbutils.Review.fromId(db, review_id)
        by_user = {}

        for filter in filters:
            if "user_ids" in filter:
                user_ids = set(filter["user_ids"])
            else:
                user_ids = set([])

            if "user_names" in filter:
                for user_name in filter["user_names"]:
                    user_ids.add(dbutils.User.fromName(db, user_name).id)

            if "directory_ids" in filter:
                directory_ids = set(filter["directory_ids"])
            else:
                directory_ids = set([])

            if "file_ids" in filter:
                file_ids = set(filter["file_ids"])
            else:
                file_ids = set([])

            if "paths" in filter:
                for path in filter["paths"]:
                    if not path or path == "/":
                        directory_ids.add(0)
                    elif path.endswith("/") or dbutils.is_directory(db, path) or ("." not in path.split("/")[-1] and not dbutils.is_file(db, path)):
                        directory_ids.add(dbutils.find_directory(db, path))
                    else:
                        file_ids.add(dbutils.find_file(db, path))

            for user_id in user_ids:
                reviewer_directory_ids, reviewer_file_ids, watcher_directory_ids, watcher_file_ids = by_user.setdefault(user_id, (set(), set(), set(), set()))

                if filter["type"] == "reviewer":
                    reviewer_directory_ids |= directory_ids
                    reviewer_file_ids |= file_ids
                else:
                    watcher_directory_ids |= directory_ids
                    watcher_file_ids |= file_ids

        pending_mails = []

        for user_id, args in by_user.items():
            user = dbutils.User.fromId(db, user_id)
            pending_mails.extend(review_utils.addReviewFilters(db, creator, user, review, *args))

        db.commit()

        mailutils.sendPendingMails(pending_mails)

        return OperationResult()
Пример #7
0
def renderShowFilters(req, db, user):
    path = req.getParameter("path", "/")
    repo_name = req.getParameter("repository",
                                 user.getPreference(db, "defaultRepository"))
    repository = gitutils.Repository.fromParameter(db, repo_name)

    show_path = path

    if path.endswith("/") or repository.getHead(db).isDirectory(path):
        path = path.rstrip("/") + "/dummy.txt"

    file_id = dbutils.find_file(db, path=path)

    filters = reviewing.filters.Filters()
    filters.setFiles(db, [file_id])
    filters.load(db, repository=repository, recursive=True)

    reviewers = []
    watchers = []

    for user_id, (filter_type,
                  _delegate) in filters.listUsers(file_id).items():
        if filter_type == 'reviewer': reviewers.append(user_id)
        else: watchers.append(user_id)

    result = "Path: %s\n" % show_path

    reviewers_found = False
    watchers_found = False

    for reviewer_id in sorted(reviewers):
        if not reviewers_found:
            result += "\nReviewers:\n"
            reviewers_found = True

        reviewer = dbutils.User.fromId(db, reviewer_id)
        result += "  %s <%s>\n" % (reviewer.fullname, reviewer.email)

    for watcher_id in sorted(watchers):
        if not watchers_found:
            result += "\nWatchers:\n"
            watchers_found = True

        watcher = dbutils.User.fromId(db, watcher_id)
        result += "  %s <%s>\n" % (watcher.fullname, watcher.email)

    if not reviewers_found and not watchers_found:
        result += "\nNo matching filters found.\n"

    return page.utils.ResponseBody(result, content_type="text/plain")
Пример #8
0
def renderShowFilters(req, db, user):
    path = req.getParameter("path", "/")
    repo_name = req.getParameter(
        "repository", user.getPreference(db, "defaultRepository"))
    repository = gitutils.Repository.fromParameter(db, repo_name)

    show_path = path

    if path.endswith("/") or repository.getHead(db).isDirectory(path):
        path = path.rstrip("/") + "/dummy.txt"

    file_id = dbutils.find_file(db, path=path)

    filters = reviewing.filters.Filters()
    filters.setFiles(db, [file_id])
    filters.load(db, repository=repository, recursive=True)

    reviewers = []
    watchers = []

    for user_id, (filter_type, _delegate) in filters.listUsers(file_id).items():
        if filter_type == 'reviewer': reviewers.append(user_id)
        else: watchers.append(user_id)

    result = "Path: %s\n" % show_path

    reviewers_found = False
    watchers_found = False

    for reviewer_id in sorted(reviewers):
        if not reviewers_found:
            result += "\nReviewers:\n"
            reviewers_found = True

        reviewer = dbutils.User.fromId(db, reviewer_id)
        result += "  %s <%s>\n" % (reviewer.fullname, reviewer.email)

    for watcher_id in sorted(watchers):
        if not watchers_found:
            result += "\nWatchers:\n"
            watchers_found = True

        watcher = dbutils.User.fromId(db, watcher_id)
        result += "  %s <%s>\n" % (watcher.fullname, watcher.email)

    if not reviewers_found and not watchers_found:
        result += "\nNo matching filters found.\n"

    return page.utils.ResponseBody(result, content_type="text/plain")
Пример #9
0
def parseReviewFilters(db, data):
    reviewfilters = []

    for filter_data in data:
        filter_username = filter_data["username"]
        filter_type = filter_data["type"]
        filter_path = filter_data["path"]

        filter_user = dbutils.User.fromName(db, filter_username)
        if not filter_user:
            raise OperationError("no such user: '******'" % filter_username)

        filter_directory_id = 0
        filter_file_id = 0

        if filter_path != "/":
            if filter_path[-1] == "/" or dbutils.is_directory(filter_path):
                filter_directory_id = dbutils.find_directory(db, path=filter_path)
            else:
                filter_file_id = dbutils.find_file(db, path=filter_path)

        reviewfilters.append((filter_directory_id, filter_file_id, filter_type, None, filter_user.id))

    return reviewfilters
Пример #10
0
def renderSearch(req, db, user):
    summary_value = req.getParameter("summary", None)
    summary_mode_value = req.getParameter("summarymode", None)
    branch_value = req.getParameter("branch", None)
    owner_value = req.getParameter("owner", None)
    path_value = req.getParameter("path", None)

    document = htmlutils.Document(req)
    document.setTitle("Search")

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

    page.utils.generateHeader(body, db, user, current_page="search")

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

    cursor = db.cursor()
    cursor.execute(
        "SELECT DISTINCT name, fullname FROM users JOIN reviewusers ON (reviewusers.uid=users.id) WHERE reviewusers.owner"
    )

    users = [("{ label: %s, value: %s }" %
              (htmlutils.jsify("%s (%s)" %
                               (fullname, name)), htmlutils.jsify(name)))
             for name, fullname in cursor]

    document.addInternalScript("var users = [ %s ];" % ", ".join(users))

    search = page.utils.PaleYellowTable(body, "Search")

    def renderSummary(target):
        target.input(name="summary", value=summary_value or "")
        summary_mode = target.select(name="summary_mode")
        summary_mode.option(value="all",
                            selected="selected" if summary_mode_value == "all"
                            else None).text("All words")
        summary_mode.option(value="any",
                            selected="selected" if summary_mode_value == "any"
                            else None).text("Any word")

    def renderBranch(target):
        target.input(name="branch", value=branch_value or "")

    def renderOwner(target):
        target.input(name="owner", value=owner_value or "")

    def renderPath(target):
        target.input(name="path", value=path_value or "")

    def renderButton(target):
        target.button(onclick="search();").text("Search")

    search.addItem("Summary", renderSummary,
                   "Words occurring in the review's summary.")
    search.addItem("Branch", renderBranch, "Name of review branch.")
    search.addItem("Owner", renderOwner, "Owner of the review.")
    search.addItem(
        "Path", renderPath,
        "Path (file or directory) that the review contains changes in.")
    search.addCentered(renderButton)

    if summary_value is not None: summary_value = summary_value.strip()
    if branch_value is not None: branch_value = branch_value.strip()
    if owner_value is not None: owner_value = owner_value.strip()
    if path_value is not None: path_value = path_value.strip()

    if summary_value or branch_value or owner_value or path_value:
        query = """SELECT DISTINCT reviews.id, reviews.summary, branches.name
                     FROM %s
                    WHERE %s"""

        tables = ["reviews", "branches ON (branches.id=reviews.branch)"]
        conditions = []
        arguments = []

        if summary_value:
            words = summary_value.split()
            operator = " AND " if summary_mode_value == "all" else " OR "
            conditions.append(
                "(%s)" % operator.join(["reviews.summary ~* %s"] * len(words)))
            arguments.extend([".*\\m" + word + "\\M.*" for word in words])

        if branch_value:

            def globToSQLPattern(glob):
                pattern = glob.replace("\\",
                                       "\\\\").replace("%", "\\%").replace(
                                           "?", "_").replace("*", "%")
                if pattern[0] != "%": pattern = "%" + pattern
                if pattern[-1] != "%": pattern = pattern + "%"
                return pattern

            conditions.append("branches.name LIKE %s")
            arguments.append(globToSQLPattern(branch_value))

        if owner_value:
            owner = dbutils.User.fromName(db, owner_value)
            tables.append("reviewusers ON (reviewusers.review=reviews.id)")
            conditions.append("reviewusers.uid=%s")
            conditions.append("reviewusers.owner")
            arguments.append(owner.id)

        if path_value:
            file_ids = dbutils.contained_files(
                db, dbutils.find_directory(db, path_value))

            if path_value[-1] != '/':
                file_ids.append(dbutils.find_file(db, path_value))

            tables.append("reviewfiles ON (reviewfiles.review=reviews.id)")
            conditions.append("reviewfiles.file=ANY (%s)")
            arguments.append(file_ids)

        query = """SELECT DISTINCT reviews.id, reviews.summary, branches.name
                     FROM %s
                    WHERE %s
                 ORDER BY reviews.id""" % (" JOIN ".join(tables),
                                           " AND ".join(conditions))

        cursor.execute(query, arguments)

        table = body.div("main").table("paleyellow reviews", align="center")
        table.col(width="20%")
        table.col(width="80%")
        header = table.tr().td("h1", colspan=4).h1()
        header.text("Reviews")

        for review_id, summary, branch_name in cursor:
            row = table.tr("review")
            row.td("name").text(branch_name)
            row.td("title").a(href="r/%d" % review_id).text(summary)

    return document
Пример #11
0
def renderShowFile(req, db, user):
    cursor = db.cursor()

    sha1 = req.getParameter("sha1")
    path = req.getParameter("path")
    line = req.getParameter("line", None)
    review_id = req.getParameter("review", None, filter=int)

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

    if line is None:
        first, last = None, None
    else:
        if "-" in line:
            first, last = map(int, line.split("-"))
        else:
            first = last = int(line)

        context = req.getParameter("context", user.getPreference(db, "commit.diff.contextLines"), int)

        first_with_context = max(1, first - context)
        last_with_context = last + context

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

    compact = req.getParameter("compact", default_compact) == "yes"

    if len(path) == 0 or path[-1:] == "/":
        raise page.utils.DisplayMessage(
            title="Invalid path parameter",
            body="<p>The path must be non-empty and must not end with a <code>/</code>.</p>",
            html=True)
    if path[0] == '/':
        full_path = path
        if path != "/": path = path[1:]
    else:
        full_path = "/" + path
        if not path: path = "/"

    if review_id is None:
        review = None
        repository_arg = req.getParameter("repository", "")
        if repository_arg:
            repository = gitutils.Repository.fromParameter(db, repository_arg)
        else:
            repository = gitutils.Repository.fromSHA1(db, sha1)
    else:
        review = dbutils.Review.fromId(db, review_id)
        repository = review.repository

    document = htmlutils.Document(req)

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

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

    document.addExternalStylesheet("resource/showfile.css")
    document.addInternalStylesheet(htmlutils.stripStylesheet(user.getResource(db, "syntax.css")[1], compact))

    commit = gitutils.Commit.fromSHA1(db, repository, sha1)
    file_sha1 = commit.getFileSHA1(full_path)
    file_id = dbutils.find_file(db, path=path)

    if file_sha1 is None:
        raise page.utils.DisplayMessage(
            title="File does not exist",
            body=("<p>There is no file named <code>%s</code> in the commit "
                  "<a href='/showcommit?repository=%s&amp;sha1=%s'>"
                  "<code>%s</code></a>.</p>"
                  % (htmlutils.htmlify(textutils.escape(full_path)),
                     htmlutils.htmlify(repository.name),
                     htmlutils.htmlify(sha1), htmlutils.htmlify(sha1[:8]))),
            html=True)

    file = diff.File(file_id, path, None, file_sha1, repository)

    # A new file ID might have been added to the database, so need to commit.
    db.commit()

    if file.canHighlight():
        requestHighlights(repository, { file.new_sha1: (file.path, file.getLanguage()) })

    file.loadNewLines(True, request_highlight=True)

    if review:
        document.addInternalScript(user.getJS())
        document.addInternalScript(review.getJS())
        document.addInternalScript("var changeset = { parent: { id: %(id)d, sha1: %(sha1)r }, child: { id: %(id)d, sha1: %(sha1)r } };" % { 'id': commit.getId(db), 'sha1': commit.sha1 })
        document.addInternalScript("var files = { %(id)d: { new_sha1: %(sha1)r }, %(sha1)r: { id: %(id)d, side: 'n' } };" % { 'id': file_id, 'sha1': file_sha1 })
        document.addExternalStylesheet("resource/review.css")
        document.addExternalScript("resource/review.js")

        cursor.execute("""SELECT DISTINCT commentchains.id
                            FROM commentchains
                            JOIN commentchainlines ON (commentchainlines.chain=commentchains.id)
                           WHERE commentchains.review=%s
                             AND commentchains.file=%s
                             AND commentchainlines.sha1=%s
                             AND ((commentchains.state!='draft' OR commentchains.uid=%s)
                              AND commentchains.state!='empty')
                        GROUP BY commentchains.id""",
                       (review.id, file_id, file_sha1, user.id))

        comment_chain_script = ""

        for (chain_id,) in cursor.fetchall():
            chain = review_comment.CommentChain.fromId(db, chain_id, user, review=review)
            chain.loadComments(db, user)

            comment_chain_script += "commentChains.push(%s);\n" % chain.getJSConstructor(file_sha1)

        if comment_chain_script:
            document.addInternalScript(comment_chain_script)

    document.addExternalStylesheet("resource/comment.css")
    document.addExternalScript("resource/comment.js")
    document.addExternalScript("resource/showfile.js")

    if tabify:
        document.addExternalStylesheet("resource/tabify.css")
        document.addExternalScript("resource/tabify.js")
        tabwidth = file.getTabWidth()
        indenttabsmode = file.getIndentTabsMode()

    if user.getPreference(db, "commit.diff.highlightIllegalWhitespace"):
        document.addInternalStylesheet(user.getResource(db, "whitespace.css")[1], compact)

    if first is not None:
        document.addInternalScript("var firstSelectedLine = %d, lastSelectedLine = %d;" % (first, last))

    target = body.div("main")

    if tabify:
        target.script(type="text/javascript").text("calculateTabWidth();")

    table = target.table('file show expanded paleyellow', align='center', cellspacing=0)

    columns = table.colgroup()
    columns.col('edge')
    columns.col('linenr')
    columns.col('line')
    columns.col('middle')
    columns.col('middle')
    columns.col('line')
    columns.col('linenr')
    columns.col('edge')

    thead = table.thead()
    cell = thead.tr().td('h1', colspan=8)
    h1 = cell.h1()

    def make_url(url_path, path):
        params = { "sha1": sha1,
                   "path": path }
        if review is None:
            params["repository"] = str(repository.id)
        else:
            params["review"] = str(review.id)
        return "%s?%s" % (url_path, urllib.urlencode(params))

    h1.a("root", href=make_url("showtree", "/")).text("root")
    h1.span().text('/')

    components = path.split("/")
    for index, component in enumerate(components[:-1]):
        h1.a(href=make_url("showtree", "/".join(components[:index + 1]))).text(component, escape=True)
        h1.span().text('/')

    if first is not None:
        h1.a(href=make_url("showfile", "/".join(components))).text(components[-1], escape=True)
    else:
        h1.text(components[-1], escape=True)

    h1.span("right").a(href=("/download/%s?repository=%s&sha1=%s"
                             % (urllib.quote(path), repository.name, file_sha1)),
                       download=urllib.quote(path)).text("[download]")
    h1.span("right").a(href=("/download/%s?repository=%s&sha1=%s"
                             % (urllib.quote(path), repository.name, file_sha1))).text("[view]")

    table.tbody('spacer top').tr('spacer top').td(colspan=8).text()

    tbody = table.tbody("lines")

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

    for linenr, line in enumerate(file.newLines(True)):
        linenr = linenr + 1
        highlight_class = ""

        if first is not None:
            if not (first_with_context <= linenr <= last_with_context): continue
            if linenr == first:
                highlight_class += " first-selected"
            if linenr == last:
                highlight_class += " last-selected"

        if tabify:
            line = htmlutils.tabify(line, tabwidth, indenttabsmode)

        line = line.replace("\r", "<i class='cr'></i>")

        row = tbody.tr("line context single", id="f%do%dn%d" % (file.id, linenr, linenr))
        row.td("edge").text()
        row.td("linenr old").text(linenr)
        row.td("line single whole%s" % highlight_class, id="f%dn%d" % (file.id, linenr), colspan=4).innerHTML(line)
        row.td("linenr new").text(linenr)
        row.td("edge").text()

        if linenr % 500:
            yield document.render(stop=tbody, pretty=not compact)

    table.tbody('spacer bottom').tr('spacer bottom').td(colspan=8).text()

    yield document.render(pretty=not compact)
Пример #12
0
            teams_per_modules.setdefault(frozenset(modules), set()).update(team)

        for modules, team in teams_per_modules.items():
            row = shared.tr("reviewers")

            cell = row.td("reviewers")
            members = sorted([dbutils.User.fromId(db, user_id).fullname for user_id in team])
            for member in members: cell.text(member).br()
            row.td("willreview").innerHTML("<span class='also'>also</span>&nbsp;review&nbsp;changes&nbsp;in")

            cell = row.td("files")
            for path in diff.File.eliminateCommonPrefixes(sorted(modules)):
                cell.span("file").innerHTML(path).br()

            directory_ids = "[ %s ]" % ", ".join([str(dbutils.find_directory(db, path=path[:-1])) for path in modules if path.endswith("/")])
            file_ids = "[ %s ]" % ", ".join([str(dbutils.find_file(db, path=path)) for path in modules if not path.endswith("/")])
            user_ids = "[ %s ]" % ", ".join(map(str, team))

            cell = row.td("buttons")
            cell.button("accept", critic_directory_ids=directory_ids, critic_file_ids=file_ids, critic_user_ids=user_ids).text("I will review this!")
            cell.button("deny", critic_directory_ids=directory_ids, critic_file_ids=file_ids, critic_user_ids=user_ids).text("They will review this!")

    yield flush(target)

    profiler.check("shared assignments")

    cursor.execute("SELECT batches.id, users.fullname, batches.comment, batches.time FROM batches JOIN users ON (users.id=batches.uid) WHERE batches.review=%s ORDER BY batches.id DESC", [review.id])
    rows = cursor.fetchall()

    if rows:
        notes = dict([(chain.id, chain) for chain in open_notes])
Пример #13
0
def render(db, target, user, repository, review, changesets, commits, listed_commits=None, context_lines=3, is_merge=False, conflicts=False, moves=False, compact=False, wrap=True, tabify=False, profiler=None, rebases=None):
    cursor = db.cursor()

    main = target.div("main", style="border-bottom: 3px solid black; margin-bottom: 20px; padding-bottom: 10px")

    options = {}

    if not user.getPreference(db, "ui.keyboardShortcuts"):
        options['show'] = True

    if user.getPreference(db, "commit.expandAllFiles"):
        options['show'] = True
        options['expand'] = True

    if compact:
        options['compact'] = True

    if tabify:
        options['tabify'] = True

    options['commit'] = changesets[0].child

    if len(changesets) == 1:
        if commits and len(commits) > 1:
            def linkToCommit(commit):
                if review: return "%s/%s?review=%d" % (repository.name, commit.sha1, review.id)
                else: return "%s/%s" % (repository.name, commit.sha1)

            columns = [(10, log_html.WhenColumn()),
                       (5, log_html.TypeColumn()),
                       (65, log_html.SummaryColumn(linkToCommit)),
                       (20, log_html.AuthorColumn())]

            log_html.render(db, main, "Squashed History", commits=commits, listed_commits=listed_commits, rebases=rebases, review=review, columns=columns, collapsable=True)
        elif changesets[0].parent is None or (changesets[0].parent.sha1 in changesets[0].child.parents) or conflicts:
            renderCommitInfo(db, main, user, repository, review, changesets[0].child, conflicts)
        else:
            main.setAttribute("style", "margin-bottom: 20px; padding-bottom: 10px")

        if moves:
            def renderMoveHeaderLeft(db, target, file):
                target.text(file.move_source_file.path)
            def renderMoveHeaderRight(db, target, file):
                target.text(file.move_target_file.path)

            options['show'] = True
            options['expand'] = True
            options['support_expand'] = False
            options['header_left'] = renderMoveHeaderLeft
            options['header_right'] = renderMoveHeaderRight

            context_lines = 0
        else:
            renderCommitFiles(db, target, user, review, changeset=changesets[0])

        yield target

        for stop in changeset_html.render(db, target, user, changesets[0], review, context_lines=context_lines, options=options, wrap=wrap):
            yield stop
    else:
        commit = changesets[0].child

        renderCommitInfo(db, main, user, repository, review, commit)

        if profiler: profiler.check("render commit info")

        nparents = len(changesets)
        target.addInternalScript("var parentsCount = %d;" % nparents)

        files = {}

        for index, changeset in enumerate(changesets):
            for file in changeset.files:
                files.setdefault(file.id, [file.id, file.path, [None] * nparents])[2][index] = file

        renderCommitFiles(db, target, user, review, changesets=changesets, file_id="p%df%%d" % index, approve_file_id="p%da%%d" % index, nparents=nparents, conflicts=changesets[-1].conflicts, files=diff.File.sorted(files.values(), key=lambda x: x[1]))

        if profiler: profiler.check("render commit files")

        mergebase = repository.mergebase(commit, db=db)

        if profiler: profiler.check("merge base")

        yield target

        relevant_commits = []

        cursor.execute("SELECT parent, file, sha1 FROM relevantcommits JOIN commits ON (relevant=id) WHERE commit=%s", (commit.getId(db),))

        rows = cursor.fetchall()

        if rows:
            for index in range(len(changesets)):
                relevant_commits.append({})

            commits_by_sha1 = {}

            for parent_index, file_id, sha1 in rows:
                if sha1 not in commits_by_sha1:
                    commits_by_sha1[sha1] = gitutils.Commit.fromSHA1(db, repository, sha1)
                relevant_commits[parent_index].setdefault(file_id, []).append(commits_by_sha1[sha1])
        else:
            values = []
            commits_by_sha1 = {}

            for index, changeset in enumerate(changesets):
                relevant_files = set([file.path for file in changeset.files])
                files = {}

                if not changeset.conflicts:
                    commit_range = "%s..%s" % (mergebase, changeset.parent.sha1)
                    relevant_lines = repository.run("log", "--name-only", "--full-history", "--format=sha1:%H", commit_range, "--", *relevant_files).splitlines()

                    for line in relevant_lines:
                        if line.startswith("sha1:"):
                            sha1 = line[5:]
                        elif line in relevant_files:
                            if sha1 not in commits_by_sha1:
                                commits_by_sha1[sha1] = gitutils.Commit.fromSHA1(db, repository, sha1)

                            relevant_commit = commits_by_sha1[sha1]
                            file_id = dbutils.find_file(db, path=line)
                            values.append((commit.getId(db), index, file_id, relevant_commit.getId(db)))
                            files.setdefault(file_id, []).append(relevant_commit)

                relevant_commits.append(files)

            cursor.executemany("INSERT INTO relevantcommits (commit, parent, file, relevant) VALUES (%s, %s, %s, %s)", values)

        if profiler: profiler.check("collecting relevant commits")

        target.script(type="text/javascript").text("calculateTabWidth();")

        for index, changeset in enumerate(changesets):
            parent = target.div("parent", id="p%d" % index)

            options['support_expand'] = bool(changeset.conflicts)
            options['file_id'] = lambda base: "p%d%s" % (index, base)
            options['line_id'] = lambda base: "p%d%s" % (index, base)
            options['line_cell_id'] = lambda base: base is not None and "p%d%s" % (index, base) or None
            options['file_id_format'] = "p%df%%d" % index

            relevant_commits_per_file = {}
            for file in changeset.files:
                relevant_commits_per_file[file.id] = []
                for index1, changeset1 in enumerate(changesets):
                    if index1 != index:
                        relevant_commits_per_file[file.id].extend(relevant_commits[index1].get(file.id, []))

            if changeset.conflicts: text = "Merge conflict resolutions"
            else: text = "Changes relative to %s parent" % ("first", "second", "third", "fourth", "fifth", "seventh", "eight", "ninth")[index]

            parent.h1().text(text)

            def renderRelevantCommits(db, target, file):
                commits = relevant_commits_per_file.get(file.id)
                if commits:
                    def linkToCommit(commit):
                        return "%s/%s?file=%d" % (commit.repository.name, commit.sha1, file.id)

                    columns = [(70, log_html.SummaryColumn(linkToCommit=linkToCommit)),
                               (30, log_html.AuthorColumn())]

                    log_html.renderList(db, target, "Relevant Commits", commits, columns=columns, hide_merges=True, className="log relevant")

            options['content_after'] = renderRelevantCommits
            options['parent_index'] = index
            options['merge'] = True

            for stop in changeset_html.render(db, parent, user, changeset, review, context_lines=context_lines, options=options, wrap=wrap, parent_index=index):
                yield stop

        if profiler: profiler.check("render diff")

    if user.getPreference(db, "ui.keyboardShortcuts"):
        page.utils.renderShortcuts(target, "showcommit", merge_parents=len(changesets), squashed_diff=commits and len(commits) > 1)
Пример #14
0
def renderSearch(req, db, user):
    summary_value = req.getParameter("summary", None)
    summary_mode_value = req.getParameter("summarymode", None)
    branch_value = req.getParameter("branch", None)
    owner_value = req.getParameter("owner", None)
    path_value = req.getParameter("path", None)

    document = htmlutils.Document(req)
    document.setTitle("Search")

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

    page.utils.generateHeader(body, db, user, current_page="search")

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

    cursor = db.cursor()
    cursor.execute("SELECT DISTINCT name, fullname FROM users JOIN reviewusers ON (reviewusers.uid=users.id) WHERE reviewusers.owner")

    users = [("{ label: %s, value: %s }" % (htmlutils.jsify("%s (%s)" % (fullname, name)),
                                            htmlutils.jsify(name)))
             for name, fullname in cursor]

    document.addInternalScript("var users = [ %s ];" % ", ".join(users))

    search = page.utils.PaleYellowTable(body, "Search")

    def renderSummary(target):
        target.input(name="summary", value=summary_value or "")
        summary_mode = target.select(name="summary_mode")
        summary_mode.option(value="all", selected="selected" if summary_mode_value == "all" else None).text("All words")
        summary_mode.option(value="any", selected="selected" if summary_mode_value == "any" else None).text("Any word")

    def renderBranch(target):
        target.input(name="branch", value=branch_value or "")

    def renderOwner(target):
        target.input(name="owner", value=owner_value or "")

    def renderPath(target):
        target.input(name="path", value=path_value or "")

    def renderButton(target):
        target.button(onclick="search();").text("Search")

    search.addItem("Summary", renderSummary, "Words occurring in the review's summary.")
    search.addItem("Branch", renderBranch, "Name of review branch.")
    search.addItem("Owner", renderOwner, "Owner of the review.")
    search.addItem("Path", renderPath, "Path (file or directory) that the review contains changes in.")
    search.addCentered(renderButton)

    if summary_value is not None: summary_value = summary_value.strip()
    if branch_value is not None: branch_value = branch_value.strip()
    if owner_value is not None: owner_value = owner_value.strip()
    if path_value is not None: path_value = path_value.strip()

    if summary_value or branch_value or owner_value or path_value:
        query = """SELECT DISTINCT reviews.id, reviews.summary, branches.name
                     FROM %s
                    WHERE %s"""

        tables = ["reviews", "branches ON (branches.id=reviews.branch)"]
        conditions = []
        arguments = []

        if summary_value:
            words = summary_value.split()
            operator = " AND " if summary_mode_value == "all" else " OR "
            conditions.append("(%s)" % operator.join(["reviews.summary ~* %s"] * len(words)))
            arguments.extend([".*\\m" + word + "\\M.*" for word in words])

        if branch_value:
            def globToSQLPattern(glob):
                pattern = glob.replace("\\", "\\\\").replace("%", "\\%").replace("?", "_").replace("*", "%")
                if pattern[0] != "%": pattern = "%" + pattern
                if pattern[-1] != "%": pattern = pattern + "%"
                return pattern

            conditions.append("branches.name LIKE %s")
            arguments.append(globToSQLPattern(branch_value))

        if owner_value:
            owner = dbutils.User.fromName(db, owner_value)
            tables.append("reviewusers ON (reviewusers.review=reviews.id)")
            conditions.append("reviewusers.uid=%s")
            conditions.append("reviewusers.owner")
            arguments.append(owner.id)

        if path_value:
            file_ids = dbutils.contained_files(db, dbutils.find_directory(db, path_value))

            if path_value[-1] != '/':
                file_ids.append(dbutils.find_file(db, path_value))

            tables.append("reviewfiles ON (reviewfiles.review=reviews.id)")
            conditions.append("reviewfiles.file=ANY (%s)")
            arguments.append(file_ids)

        query = """SELECT DISTINCT reviews.id, reviews.summary, branches.name
                     FROM %s
                    WHERE %s
                 ORDER BY reviews.id""" % (" JOIN ".join(tables), " AND ".join(conditions))

        cursor.execute(query, arguments)

        table = body.div("main").table("paleyellow reviews", align="center")
        table.col(width="20%")
        table.col(width="80%")
        header = table.tr().td("h1", colspan=4).h1()
        header.text("Reviews")

        for review_id, summary, branch_name in cursor:
            row = table.tr("review")
            row.td("name").text(branch_name)
            row.td("title").a(href="r/%d" % review_id).text(summary)

    return document
Пример #15
0
def render(db, target, user, repository, review, changesets, commits, listed_commits=None, context_lines=3, is_merge=False, conflicts=False, moves=False, compact=False, wrap=True, tabify=False, profiler=None, rebases=None):
    cursor = db.cursor()

    main = target.div("main", style="border-bottom: 3px solid black; margin-bottom: 20px; padding-bottom: 10px")

    options = {}

    if not user.getPreference(db, "ui.keyboardShortcuts"):
        options['show'] = True

    if user.getPreference(db, "commit.expandAllFiles"):
        options['show'] = True
        options['expand'] = True

    if compact:
        options['compact'] = True

    if tabify:
        options['tabify'] = True

    options['commit'] = changesets[0].child

    if len(changesets) == 1:
        if commits and len(commits) > 1:
            def linkToCommit(commit):
                if review: return "%s/%s?review=%d" % (repository.name, commit.sha1, review.id)
                else: return "%s/%s" % (repository.name, commit.sha1)

            columns = [(10, log_html.WhenColumn()),
                       (5, log_html.TypeColumn()),
                       (65, log_html.SummaryColumn(linkToCommit)),
                       (20, log_html.AuthorColumn())]

            log_html.render(db, main, "Squashed History", commits=commits, listed_commits=listed_commits, rebases=rebases, review=review, columns=columns, collapsable=True)
        elif changesets[0].parent is None or (changesets[0].parent.sha1 in changesets[0].child.parents) or conflicts:
            renderCommitInfo(db, main, user, repository, review, changesets[0].child, conflicts)
        else:
            main.setAttribute("style", "margin-bottom: 20px; padding-bottom: 10px")

        if moves:
            def renderMoveHeaderLeft(db, target, file):
                target.text(file.move_source_file.path)
            def renderMoveHeaderRight(db, target, file):
                target.text(file.move_target_file.path)

            options['show'] = True
            options['expand'] = True
            options['support_expand'] = False
            options['header_left'] = renderMoveHeaderLeft
            options['header_right'] = renderMoveHeaderRight

            context_lines = 0
        else:
            renderCommitFiles(db, target, user, review, changeset=changesets[0])

        yield target

        for stop in changeset_html.render(db, target, user, changesets[0], review, context_lines=context_lines, options=options, wrap=wrap):
            yield stop
    else:
        commit = changesets[0].child

        renderCommitInfo(db, main, user, repository, review, commit)

        if profiler: profiler.check("render commit info")

        nparents = len(changesets)
        target.addInternalScript("var parentsCount = %d;" % nparents)

        files = {}

        for index, changeset in enumerate(changesets):
            for file in changeset.files:
                files.setdefault(file.id, [file.id, file.path, [None] * nparents])[2][index] = file

        renderCommitFiles(db, target, user, review, changesets=changesets, file_id="p%df%%d" % index, approve_file_id="p%da%%d" % index, nparents=nparents, conflicts=changesets[-1].conflicts, files=diff.File.sorted(files.values(), key=lambda x: x[1]))

        if profiler: profiler.check("render commit files")

        mergebase = repository.mergebase(commit, db=db)

        if profiler: profiler.check("merge base")

        yield target

        relevant_commits = []

        cursor.execute("SELECT parent, file, sha1 FROM relevantcommits JOIN commits ON (relevant=id) WHERE commit=%s", (commit.getId(db),))

        rows = cursor.fetchall()

        if rows:
            for index in range(len(changesets)):
                relevant_commits.append({})

            commits_by_sha1 = {}

            for parent_index, file_id, sha1 in rows:
                if sha1 not in commits_by_sha1:
                    commits_by_sha1[sha1] = gitutils.Commit.fromSHA1(db, repository, sha1)
                relevant_commits[parent_index].setdefault(file_id, []).append(commits_by_sha1[sha1])
        else:
            values = []
            commits_by_sha1 = {}

            for index, changeset in enumerate(changesets):
                relevant_files = set([file.path for file in changeset.files])
                files = {}

                if not changeset.conflicts:
                    commit_range = "%s..%s" % (mergebase, changeset.parent.sha1)
                    relevant_lines = repository.run("log", "--name-only", "--full-history", "--format=sha1:%H", commit_range, "--", *relevant_files).splitlines()

                    for line in relevant_lines:
                        if line.startswith("sha1:"):
                            sha1 = line[5:]
                        elif line in relevant_files:
                            if sha1 not in commits_by_sha1:
                                commits_by_sha1[sha1] = gitutils.Commit.fromSHA1(db, repository, sha1)

                            relevant_commit = commits_by_sha1[sha1]
                            file_id = dbutils.find_file(db, path=line)
                            values.append((commit.getId(db), index, file_id, relevant_commit.getId(db)))
                            files.setdefault(file_id, []).append(relevant_commit)

                relevant_commits.append(files)

            cursor.executemany("INSERT INTO relevantcommits (commit, parent, file, relevant) VALUES (%s, %s, %s, %s)", values)

        if profiler: profiler.check("collecting relevant commits")

        target.script(type="text/javascript").text("calculateTabWidth();")

        for index, changeset in enumerate(changesets):
            parent = target.div("parent", id="p%d" % index)

            options['support_expand'] = bool(changeset.conflicts)
            options['file_id'] = lambda base: "p%d%s" % (index, base)
            options['line_id'] = lambda base: "p%d%s" % (index, base)
            options['line_cell_id'] = lambda base: base is not None and "p%d%s" % (index, base) or None
            options['file_id_format'] = "p%df%%d" % index

            relevant_commits_per_file = {}
            for file in changeset.files:
                relevant_commits_per_file[file.id] = []
                for index1, changeset1 in enumerate(changesets):
                    if index1 != index:
                        relevant_commits_per_file[file.id].extend(relevant_commits[index1].get(file.id, []))

            if changeset.conflicts: text = "Merge conflict resolutions"
            else: text = "Changes relative to %s parent" % ("first", "second", "third", "fourth", "fifth", "seventh", "eight", "ninth")[index]

            parent.h1().text(text)

            def renderRelevantCommits(db, target, file):
                commits = relevant_commits_per_file.get(file.id)
                if commits:
                    def linkToCommit(commit):
                        return "%s/%s?file=%d" % (commit.repository.name, commit.sha1, file.id)

                    columns = [(70, log_html.SummaryColumn(linkToCommit=linkToCommit)),
                               (30, log_html.AuthorColumn())]

                    log_html.renderList(db, target, "Relevant Commits", commits, columns=columns, hide_merges=True, className="log relevant")

            options['content_after'] = renderRelevantCommits
            options['parent_index'] = index
            options['merge'] = True

            for stop in changeset_html.render(db, parent, user, changeset, review, context_lines=context_lines, options=options, wrap=wrap, parent_index=index):
                yield stop

        if profiler: profiler.check("render diff")

    if user.getPreference(db, "ui.keyboardShortcuts"):
        page.utils.renderShortcuts(target, "showcommit", merge_parents=len(changesets), squashed_diff=commits and len(commits) > 1)
Пример #16
0
def renderShowFile(req, db, user):
    cursor = db.cursor()

    sha1 = req.getParameter("sha1")
    path = req.getParameter("path")
    line = req.getParameter("line", None)
    review_id = req.getParameter("review", None, filter=int)

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

    if line is None:
        first, last = None, None
    else:
        if "-" in line:
            first, last = map(int, line.split("-"))
        else:
            first = last = int(line)

        context = req.getParameter(
            "context", user.getPreference(db, "commit.diff.contextLines"), int)

        first_with_context = max(1, first - context)
        last_with_context = last + context

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

    compact = req.getParameter("compact", default_compact) == "yes"

    if len(path) == 0 or path[-1:] == "/":
        raise page.utils.DisplayMessage(
            title="Invalid path parameter",
            body=
            "<p>The path must be non-empty and must not end with a <code>/</code>.</p>",
            html=True)
    if path[0] == '/':
        full_path = path
        if path != "/": path = path[1:]
    else:
        full_path = "/" + path
        if not path: path = "/"

    if review_id is None:
        review = None
        repository_arg = req.getParameter("repository", "")
        if repository_arg:
            repository = gitutils.Repository.fromParameter(db, repository_arg)
        else:
            repository = gitutils.Repository.fromSHA1(db, sha1)
    else:
        review = dbutils.Review.fromId(db, review_id)
        repository = review.repository

    document = htmlutils.Document(req)

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

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

    document.addExternalStylesheet("resource/showfile.css")
    document.addInternalStylesheet(
        htmlutils.stripStylesheet(
            user.getResource(db, "syntax.css")[1], compact))

    commit = gitutils.Commit.fromSHA1(db, repository, sha1)
    file_sha1 = commit.getFileSHA1(full_path)
    file_id = dbutils.find_file(db, path=path)

    if file_sha1 is None:
        raise page.utils.DisplayMessage(
            title="File does not exist",
            body=("<p>There is no file named <code>%s</code> in the commit "
                  "<a href='/showcommit?repository=%s&amp;sha1=%s'>"
                  "<code>%s</code></a>.</p>" %
                  (htmlutils.htmlify(textutils.escape(full_path)),
                   htmlutils.htmlify(repository.name), htmlutils.htmlify(sha1),
                   htmlutils.htmlify(sha1[:8]))),
            html=True)

    file = diff.File(file_id, path, None, file_sha1, repository)

    # A new file ID might have been added to the database, so need to commit.
    db.commit()

    if file.canHighlight():
        requestHighlights(repository,
                          {file.new_sha1: (file.path, file.getLanguage())})

    file.loadNewLines(True, request_highlight=True)

    if review:
        document.addInternalScript(user.getJS())
        document.addInternalScript(review.getJS())
        document.addInternalScript(
            "var changeset = { parent: { id: %(id)d, sha1: %(sha1)r }, child: { id: %(id)d, sha1: %(sha1)r } };"
            % {
                'id': commit.getId(db),
                'sha1': commit.sha1
            })
        document.addInternalScript(
            "var files = { %(id)d: { new_sha1: %(sha1)r }, %(sha1)r: { id: %(id)d, side: 'n' } };"
            % {
                'id': file_id,
                'sha1': file_sha1
            })
        document.addExternalStylesheet("resource/review.css")
        document.addExternalScript("resource/review.js")

        cursor.execute(
            """SELECT DISTINCT commentchains.id
                            FROM commentchains
                            JOIN commentchainlines ON (commentchainlines.chain=commentchains.id)
                           WHERE commentchains.review=%s
                             AND commentchains.file=%s
                             AND commentchainlines.sha1=%s
                             AND ((commentchains.state!='draft' OR commentchains.uid=%s)
                              AND commentchains.state!='empty')
                        GROUP BY commentchains.id""",
            (review.id, file_id, file_sha1, user.id))

        comment_chain_script = ""

        for (chain_id, ) in cursor.fetchall():
            chain = review_comment.CommentChain.fromId(db,
                                                       chain_id,
                                                       user,
                                                       review=review)
            chain.loadComments(db, user)

            comment_chain_script += "commentChains.push(%s);\n" % chain.getJSConstructor(
                file_sha1)

        if comment_chain_script:
            document.addInternalScript(comment_chain_script)

    document.addExternalStylesheet("resource/comment.css")
    document.addExternalScript("resource/comment.js")
    document.addExternalScript("resource/showfile.js")

    if tabify:
        document.addExternalStylesheet("resource/tabify.css")
        document.addExternalScript("resource/tabify.js")
        tabwidth = file.getTabWidth()
        indenttabsmode = file.getIndentTabsMode()

    if user.getPreference(db, "commit.diff.highlightIllegalWhitespace"):
        document.addInternalStylesheet(
            user.getResource(db, "whitespace.css")[1], compact)

    if first is not None:
        document.addInternalScript(
            "var firstSelectedLine = %d, lastSelectedLine = %d;" %
            (first, last))

    target = body.div("main")

    if tabify:
        target.script(type="text/javascript").text("calculateTabWidth();")

    table = target.table('file show expanded paleyellow',
                         align='center',
                         cellspacing=0)

    columns = table.colgroup()
    columns.col('edge')
    columns.col('linenr')
    columns.col('line')
    columns.col('middle')
    columns.col('middle')
    columns.col('line')
    columns.col('linenr')
    columns.col('edge')

    thead = table.thead()
    cell = thead.tr().td('h1', colspan=8)
    h1 = cell.h1()

    def make_url(url_path, path):
        params = {"sha1": sha1, "path": path}
        if review is None:
            params["repository"] = str(repository.id)
        else:
            params["review"] = str(review.id)
        return "%s?%s" % (url_path, urllib.urlencode(params))

    h1.a("root", href=make_url("showtree", "/")).text("root")
    h1.span().text('/')

    components = path.split("/")
    for index, component in enumerate(components[:-1]):
        h1.a(href=make_url("showtree", "/".join(components[:index + 1]))).text(
            component, escape=True)
        h1.span().text('/')

    if first is not None:
        h1.a(href=make_url("showfile", "/".join(components))).text(
            components[-1], escape=True)
    else:
        h1.text(components[-1], escape=True)

    h1.span("right").a(href=("/download/%s?repository=%s&sha1=%s" %
                             (urllib.quote(path), repository.name, file_sha1)),
                       download=urllib.quote(path)).text("[download]")
    h1.span("right").a(
        href=("/download/%s?repository=%s&sha1=%s" %
              (urllib.quote(path), repository.name, file_sha1))).text("[view]")

    table.tbody('spacer top').tr('spacer top').td(colspan=8).text()

    tbody = table.tbody("lines")

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

    for linenr, line in enumerate(file.newLines(True)):
        linenr = linenr + 1
        highlight_class = ""

        if first is not None:
            if not (first_with_context <= linenr <= last_with_context):
                continue
            if linenr == first:
                highlight_class += " first-selected"
            if linenr == last:
                highlight_class += " last-selected"

        if tabify:
            line = htmlutils.tabify(line, tabwidth, indenttabsmode)

        line = line.replace("\r", "<i class='cr'></i>")

        row = tbody.tr("line context single",
                       id="f%do%dn%d" % (file.id, linenr, linenr))
        row.td("edge").text()
        row.td("linenr old").text(linenr)
        row.td("line single whole%s" % highlight_class,
               id="f%dn%d" % (file.id, linenr),
               colspan=4).innerHTML(line)
        row.td("linenr new").text(linenr)
        row.td("edge").text()

        if linenr % 500:
            yield document.render(stop=tbody, pretty=not compact)

    table.tbody('spacer bottom').tr('spacer bottom').td(colspan=8).text()

    yield document.render(pretty=not compact)
Пример #17
0
            teams_per_modules.setdefault(frozenset(modules), set()).update(team)

        for modules, team in teams_per_modules.items():
            row = shared.tr("reviewers")

            cell = row.td("reviewers")
            members = sorted([dbutils.User.fromId(db, user_id).fullname for user_id in team])
            for member in members: cell.text(member).br()
            row.td("willreview").innerHTML("<span class='also'>also</span>&nbsp;review&nbsp;changes&nbsp;in")

            cell = row.td("files")
            for path in diff.File.eliminateCommonPrefixes(sorted(modules)):
                cell.span("file").innerHTML(path).br()

            directory_ids = "[ %s ]" % ", ".join([str(dbutils.find_directory(db, path=path[:-1])) for path in modules if path.endswith("/")])
            file_ids = "[ %s ]" % ", ".join([str(dbutils.find_file(db, path=path)) for path in modules if not path.endswith("/")])
            user_ids = "[ %s ]" % ", ".join(map(str, team))

            cell = row.td("buttons")
            cell.button("accept", critic_directory_ids=directory_ids, critic_file_ids=file_ids, critic_user_ids=user_ids).text("I will review this!")
            cell.button("deny", critic_directory_ids=directory_ids, critic_file_ids=file_ids, critic_user_ids=user_ids).text("They will review this!")

    yield flush(target)

    profiler.check("shared assignments")

    cursor.execute("SELECT batches.id, users.fullname, batches.comment, batches.time FROM batches JOIN users ON (users.id=batches.uid) WHERE batches.review=%s ORDER BY batches.id DESC", [review.id])
    rows = cursor.fetchall()

    if rows:
        notes = dict([(chain.id, chain) for chain in open_notes])