コード例 #1
0
ファイル: review.py プロジェクト: Tigge/critic
    def getURL(self, db, user=None, indent=0):
        import dbutils

        indent = " " * indent

        if db and user:
            url_prefixes = user.getCriticURLs(db)
        else:
            url_prefixes = [dbutils.getURLPrefix(db)]

        return "\n".join(["%s%s/r/%d" % (indent, url_prefix, self.id) for url_prefix in url_prefixes])
コード例 #2
0
    def getURL(self, db, user=None, indent=0, separator="\n"):
        import dbutils

        indent = " " * indent

        if user:
            url_prefixes = user.getCriticURLs(db)
        else:
            url_prefixes = [dbutils.getURLPrefix(db)]

        return separator.join(["%s%s/r/%d" % (indent, url_prefix, self.id) for url_prefix in url_prefixes])
コード例 #3
0
ファイル: gitutils.py プロジェクト: Manishearth/critic
    def constructURL(db, user, path):
        path = os.path.relpath(path, configuration.paths.GIT_DIR)
        url_type = user.getPreference(db, "repository.urlType")

        if url_type == "git":
            url_format = "git://%s/%s"
        elif url_type in ("ssh", "host"):
            if url_type == "ssh":
                prefix = "ssh://%s"
            else:
                prefix = "%s:"
            url_format = prefix + os.path.join(configuration.paths.GIT_DIR, "%s")
        else:
            import dbutils
            url_prefix = dbutils.getURLPrefix(db, user)
            return "%s/%s" % (url_prefix, path)

        return url_format % (configuration.base.HOSTNAME, path)
コード例 #4
0
ファイル: manageextensions.py プロジェクト: ryfow/critic
        def renderItem(target):
            span = target.span("name")
            span.b().text(extension.getName())
            span.text(" by %s" % author.fullname)

            span = target.span("details")
            span.b().text("Details: ")
            select = span.select("details", critic_author=extension.getAuthorName(), critic_extension=extension.getName())
            select.option(value='', selected="selected" if selected_version is False else None).text("Select version")
            versions = extension.getVersions()
            if versions:
                optgroup = select.optgroup(label="Official Versions")
                for version in extension.getVersions():
                    optgroup.option(value="version/%s" % version, selected="selected" if selected_version == version else None).text("%s" % version.upper())
            optgroup = select.optgroup(label="Development")
            optgroup.option(value='live', selected="selected" if selected_version is None else None).text("LIVE")

            if manifest:
                is_installed = manifest.status in ("partial", "installed") or installed_version is not False

                if is_installed:
                    target.span("installed").text(" [installed]")

                target.div("description").preformatted().text(manifest.description, linkify=True)
            else:
                is_installed = False

                target.div("description broken").preformatted().a(href="loadmanifest?author=%s&name=%s" % (extension.getAuthorName(), extension.getName())).text("[This extension has an invalid MANIFEST file]")

            if selected_version is False:
                return

            pages = []
            injects = []
            processcommits = []
            processchanges = []
            scheduled = []

            if manifest:
                for role in manifest.roles:
                    if isinstance(role, PageRole):
                        pages.append(role)
                    elif isinstance(role, InjectRole):
                        injects.append(role)
                    elif isinstance(role, ProcessCommitsRole):
                        processcommits.append(role)
                    elif isinstance(role, ProcessChangesRole):
                        processchanges.append(role)
                    elif isinstance(role, ScheduledRole):
                        scheduled.append(role)

            role_table = target.table("roles")

            if pages:
                role_table.tr().th(colspan=2).text("Pages")

                for role in pages:
                    row = role_table.tr()
                    url = "%s/%s" % (dbutils.getURLPrefix(db), role.pattern)
                    if is_installed and role.installed and "*" not in url:
                        row.td("pattern").a(href=url).text(url)
                    else:
                        row.td("pattern").text(url)
                    td = row.td("description")
                    td.text(role.description)

                    if is_installed and not role.installed:
                        td.text(" ")
                        td.span("inactive").text("[Not active!]")

            if injects:
                role_table.tr().th(colspan=2).text("Page Injections")

                for role in injects:
                    row = role_table.tr()
                    row.td("pattern").text("%s/%s" % (dbutils.getURLPrefix(db), role.pattern))
                    td = row.td("description")
                    td.text(role.description)

                    if is_installed and not role.installed:
                        td.text(" ")
                        td.span("inactive").text("[Not active!]")

            if processcommits:
                role_table.tr().th(colspan=2).text("ProcessCommits hooks")
                ul = role_table.tr().td(colspan=2).ul()

                for role in processcommits:
                    li = ul.li()
                    li.text(role.description)

                    if is_installed and not role.installed:
                        li.text(" ")
                        li.span("inactive").text("[Not active!]")

            if processchanges:
                role_table.tr().th(colspan=2).text("ProcessChanges hooks")
                ul = role_table.tr().td(colspan=2).ul()

                for role in processchanges:
                    li = ul.li()
                    li.text(role.description)

                    if is_installed and not role.installed:
                        li.text(" ")
                        li.span("inactive").text("[Not active!]")

            if scheduled:
                role_table.tr().th(colspan=2).text("Scheduled hooks")

                for role in scheduled:
                    row = role_table.tr()
                    row.td("pattern").text("%s @ %s" % (role.frequency, role.at))
                    td = row.td("description")
                    td.text(role.description)

                    if is_installed and not role.installed:
                        td.text(" ")
                        td.span("inactive").text("[Not active!]")
コード例 #5
0
def createBranch(user, repository, name, head):
    processCommits(repository.name, head)

    cursor = db.cursor()

    def commit_id(sha1):
        cursor.execute("SELECT id FROM commits WHERE sha1=%s", [sha1])
        return cursor.fetchone()[0]

    components = name.split("/")
    for index in range(1, len(components)):
        try:
            repository.revparse("refs/heads/%s" % "/".join(components[:index]))
        except:
            continue

        message = (
            "Cannot create branch with name '%s' since there is already a branch named '%s' in the repository."
            % (name, "/".join(components[:index])))
        raise IndexException, textutils.reflow(message,
                                               line_length=80 -
                                               len("remote: "))

    if name.startswith("r/"):
        try:
            review_id = int(name[2:])

            cursor.execute(
                "SELECT branches.name FROM reviews JOIN branches ON (branches.id=reviews.branch) WHERE reviews.id=%s",
                (review_id, ))
            row = cursor.fetchone()

            message = "Refusing to create review named as a number."

            if row:
                message += "\nDid you mean to push to the branch '%s', perhaps?" % row[
                    0]

            raise IndexException, message
        except ValueError:
            pass

        if user.getPreference(db, "review.createViaPush"):
            the_commit = gitutils.Commit.fromSHA1(db, repository, head,
                                                  commit_id(head))
            all_commits = [the_commit]
            review = review_utils.createReview(db,
                                               user,
                                               repository,
                                               all_commits,
                                               name,
                                               the_commit.summary(),
                                               None,
                                               via_push=True)

            print "Submitted review: %s/r/%d" % (dbutils.getURLPrefix(db),
                                                 review.id)

            if review.reviewers:
                print "  Reviewers:"
                for reviewer in review.reviewers:
                    print "    %s <%s>" % (reviewer.fullname, reviewer.email)

            if review.watchers:
                print "  Watchers:"
                for watcher in review.watchers:
                    print "    %s <%s>" % (watcher.fullname, watcher.email)

            if configuration.extensions.ENABLED:
                if extensions.executeProcessCommits(db, user, review,
                                                    all_commits, None,
                                                    the_commit, stdout):
                    print

            print "Thank you!"
            return True
        else:
            raise IndexException, "Refusing to create review; user preference 'review.createViaPush' is not enabled."

    sha1 = head
    base = None
    tail = None

    cursor.execute(
        """SELECT 1
                        FROM reachable
                        JOIN branches ON (branches.id=reachable.branch)
                        JOIN repositories ON (repositories.id=branches.repository)
                       WHERE repositories.id=%s
                       LIMIT 1""", (repository.id, ))

    if cursor.fetchone():

        def reachable(sha1):
            cursor.execute(
                """SELECT branches.id
                                FROM branches
                                JOIN reachable ON (reachable.branch=branches.id)
                                JOIN commits ON (commits.id=reachable.commit)
                               WHERE branches.repository=%s
                                 AND branches.type='normal'
                                 AND commits.sha1=%s
                            ORDER BY reachable.branch ASC
                               LIMIT 1""", (repository.id, sha1))
            return cursor.fetchone()
    else:

        def reachable(sha1):
            return None

    commit_map = {}
    commit_list = []

    row = reachable(sha1)
    if row:
        # Head of branch is reachable from an existing branch.  Could be because
        # this branch is actually empty (just created with no "own" commits) or
        # it could have been merged into some other already existing branch.  We
        # can't tell, so we just record it as empty.

        base = row[0]
        tail = sha1
    else:
        stack = []

        while True:
            if sha1 not in commit_map:
                commit = gitutils.Commit.fromSHA1(db, repository, sha1)
                commit_map[sha1] = commit
                commit_list.append(commit)

                for sha1 in commit.parents:
                    if sha1 not in commit_map:
                        row = reachable(sha1)
                        if not row:
                            stack.append(sha1)
                        elif base is None:
                            base = row[0]
                            tail = sha1

                            base_chain = [base]

                            while True:
                                cursor.execute(
                                    "SELECT base FROM branches WHERE id=%s",
                                    (base_chain[-1], ))
                                next = cursor.fetchone()[0]
                                if next is None: break
                                else: base_chain.append(next)

                            def reachable(sha1):
                                cursor.execute(
                                    """SELECT 1
                                                    FROM reachable
                                                    JOIN commits ON (commits.id=reachable.commit)
                                                   WHERE reachable.branch=ANY (%s)
                                                     AND commits.sha1=%s""",
                                    (base_chain, sha1))
                                return cursor.fetchone()

            if stack: sha1 = stack.pop(0)
            else: break

        if len(commit_list) % 10000 > 1000:
            stdout.write("\n")
            stdout.flush()

    if not base:
        cursor.execute(
            "INSERT INTO branches (repository, name, head) VALUES (%s, %s, %s) RETURNING id",
            (repository.id, name, commit_id(head)))
        branch_id = cursor.fetchone()[0]
    else:
        cursor.execute(
            "INSERT INTO branches (repository, name, head, base, tail) VALUES (%s, %s, %s, %s, %s) RETURNING id",
            (repository.id, name, commit_id(head), base, commit_id(tail)))
        branch_id = cursor.fetchone()[0]

        cursor.execute("SELECT name FROM branches WHERE id=%s", [base])

        print "Added branch based on %s containing %d commit%s:" % (
            cursor.fetchone()[0], len(commit_list),
            "s" if len(commit_list) > 1 else "")
        print "  %s/log?repository=%d&branch=%s" % (dbutils.getURLPrefix(db),
                                                    repository.id, name)
        if len(commit_list) > 1:
            print "To create a review of all %d commits:" % len(commit_list)
        else:
            print "To create a review of the commit:"
        print "  %s/createreview?repository=%d&branch=%s" % (
            dbutils.getURLPrefix(db), repository.id, name)

    reachable_values = [(branch_id, commit.sha1) for commit in commit_list]
    cursor.executemany(
        "INSERT INTO reachable (branch, commit) SELECT %s, id FROM commits WHERE sha1=%s",
        reachable_values)

    if isinstance(user, str): user_name = user
    else: user_name = user.name

    if not repository.hasMainBranch(
    ) and user_name == configuration.base.SYSTEM_USER_NAME:
        cursor.execute("UPDATE repositories SET branch=%s WHERE id=%s",
                       (branch_id, repository.id))
コード例 #6
0
ファイル: showcommit.py プロジェクト: KurSh/critic
def commitRangeFromReview(db, user, review, filter, file_ids):
    edges = cursor = db.cursor()

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

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

        edges = set()

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

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

    listed_commits = set()
    with_pending = set()

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

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

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

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

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

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

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

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

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

                paths.append((tail, paths_in_upstream))

            overlapping_changes = paths_in_review & paths_in_upstreams

            if overlapping_changes:
                candidates = []

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

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

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

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

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

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

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

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

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

        return tails.pop(), review.branch.head.sha1, all_commits, listed_commits
コード例 #7
0
            yield str(document)
            return
        except:
            error_message = traceback.format_exc()

            environ["wsgi.errors"].write(error_message)

            db.rollback()

            if not user or user.hasRole(db, "developer"):
                title = "You broke the system again:"
                body = error_message
                body_html = "<pre>%s</pre>" % htmlify(body)
            else:
                prefix = dbutils.getURLPrefix(db)

                x_forwarded_host = req.getRequestHeader("X-Forwarded-Host")
                if x_forwarded_host: prefix = "https://" + x_forwarded_host

                url = "%s/%s?%s" % (prefix, req.path, req.query)

                mailutils.sendExceptionMessage("wsgi", (
                    "User:   %s\nMethod: %s\nPath:   %s\nQuery:  %s\nURL:    %s\n\n%s"
                    % (req.user, req.method, req.path, req.query, url,
                       error_message)))

                title = "Darn! It seems we have a problem..."
                body = "A message has been sent to the system administrator(s) with details about the problem."
                body_html = body
コード例 #8
0
def renderFormatted(db, table, lines, toc=False):
    re_h1 = re.compile("^=+$")
    re_h2 = re.compile("^-+$")
    data = {"configuration.URL": dbutils.getURLPrefix(db)}

    blocks = []
    block = []

    for line in lines:
        if line.strip():
            block.append(line % data)
        elif block:
            blocks.append(block)
            block = []
    else:
        if block:
            blocks.append(block)

    text = None

    for block in blocks:

        def textToId(text):
            return text.lower().replace(' ', '_')

        if len(block) == 2:
            if re_h1.match(block[1]):
                table.setTitle(block[0])
                table.tr("h1").td("h1").h1(id=textToId(block[0])).text(
                    block[0])
                text = None
                if toc:
                    toc = table.tr("toc").td("toc").div().table("toc")
                    toc.tr("heading").th().text("Table of contents")
                continue
            elif re_h2.match(block[1]):
                if toc:
                    toc.tr("h2").td().a(href="#" + textToId(block[0])).text(
                        block[0])
                table.tr("h2").td("h2").div().h2(id=textToId(block[0])).text(
                    block[0])
                text = None
                continue

        if len(block) == 1 and block[0] == "[repositories]":
            text = None

            repositories = table.tr("repositories").td("repositories").table(
                "repositories", align="center", cellspacing=0)
            headings = repositories.tr("headings")
            headings.th("name").text("Short name")
            headings.th("path").text("Repository path")

            cursor = db.cursor()
            cursor.execute(
                "SELECT name, path FROM repositories ORDER BY id ASC")

            first = " first"

            for name, path in cursor:
                row = repositories.tr("repository" + first)
                row.td("name").text(name)
                row.td("path").text("%s:%s" %
                                    (configuration.base.HOSTNAME, path))
                first = ""

            continue

        if not text:
            text = table.tr("text").td("text")

        def translateConfigLinks(text):
            def linkify(match):
                item = match.group(1)
                return "<a href='config?highlight=%s'>%s</a>" % (item, item)

            return re.sub("CONFIG\\(([^)]+)\\)", linkify, text)

        def processText(lines):
            for index, line in enumerate(lines):
                if line.startswith("  http"):
                    lines[index] = "<a href='%s'>%s</a>" % (line.strip(),
                                                            line.strip())
            return translateConfigLinks("\n".join(lines)).replace(
                "--", "&mdash;")

        if len(block) > 2 and re_h2.match(block[1]):
            if toc:
                toc.tr("h3").td().a(href="#" + textToId(block[0])).text(
                    block[0])
            div = text.div()
            div.h3(id=textToId(block[0])).text(block[0])
            block = block[2:]

        if block[0].startswith("|"):
            pre = table.tr("pre").td("pre").div().table(
                "pre").tr().td().preformatted()
            pre.text("\n".join([line[2:] for line in block]))
            text = None
            continue
        elif block[0].startswith("* ") or block[0].startswith("1 "):
            if block[0].startswith("* "):
                items = text.div().ul()
            else:
                items = text.div().ol()
            item = []
            for line in block:
                if line[:2] != '  ':
                    if item: items.li().text("\n".join(item), cdata=True)
                    item = []
                else:
                    assert line[:2] == "  "
                item.append(line[2:])
            if item: items.li().text("\n".join(item), cdata=True)
        elif block[0].startswith("? "):
            items = text.div().dl()
            term = []
            definition = None
            for line in block:
                if line[:2] == '? ':
                    if definition:
                        items.dt().text(" ".join(term))
                        items.dd().text(processText(definition))
                        definition = None
                    term = [line[2:]]
                elif line[:2] == '= ':
                    assert term
                    assert definition is None
                    definition = [line[2:]]
                elif definition is None:
                    term.append(line[2:])
                else:
                    definition.append(line[2:])
            items.dt().text(" ".join(term))
            items.dd().text(processText(definition))
        elif block[0].startswith("  "):
            text_data = translateConfigLinks("\n".join(block))
            if block[0].startswith("  <code>"):
                className = "example"
            else:
                className = "hint"
                text_data = text_data.replace("--", "&mdash;")
            text.div().div(className).text(text_data, cdata=True)
        else:
            text.div().text(processText(block), cdata=True)
コード例 #9
0
def addCommitsToReview(db,
                       user,
                       review,
                       commits,
                       new_review=False,
                       commitset=None,
                       pending_mails=None,
                       silent_if_empty=set(),
                       full_merges=set(),
                       replayed_rebases={},
                       tracked_branch=False):
    cursor = db.cursor()

    if not new_review:
        import index

        new_commits = log_commitset.CommitSet(commits)
        old_commits = log_commitset.CommitSet(review.branch.commits)
        merges = new_commits.getMerges()

        for merge in merges:
            # We might have stripped it in a previous pass.
            if not merge in new_commits: continue

            tails = filter(
                lambda sha1: sha1 not in old_commits and sha1 not in merge.
                parents, new_commits.getTailsFrom(merge))

            if tails:
                if tracked_branch:
                    raise index.IndexException("""\
Merge %s adds merged-in commits.  Please push the merge manually
and follow the instructions.""" % merge.sha1[:8])

                cursor.execute(
                    "SELECT id, confirmed, tail FROM reviewmergeconfirmations WHERE review=%s AND uid=%s AND merge=%s",
                    (review.id, user.id, merge.getId(db)))

                row = cursor.fetchone()

                if not row or not row[1]:
                    if not row:
                        cursor.execute(
                            "INSERT INTO reviewmergeconfirmations (review, uid, merge) VALUES (%s, %s, %s) RETURNING id",
                            (review.id, user.id, merge.getId(db)))
                        confirmation_id = cursor.fetchone()[0]

                        merged = set()

                        for tail_sha1 in tails:
                            children = new_commits.getChildren(tail_sha1)

                            while children:
                                child = children.pop()
                                if child not in merged and new_commits.isAncestorOf(
                                        child, merge):
                                    merged.add(child)
                                    children.update(
                                        new_commits.getChildren(child) -
                                        merged)

                        merged_values = [(confirmation_id, commit.getId(db))
                                         for commit in merged]
                        cursor.executemany(
                            "INSERT INTO reviewmergecontributions (id, merged) VALUES (%s, %s)",
                            merged_values)
                        db.commit()
                    else:
                        confirmation_id = row[0]

                    message = "Merge %s adds merged-in commits:" % merge.sha1[:
                                                                              8]

                    for tail_sha1 in tails:
                        for parent_sha1 in merge.parents:
                            if parent_sha1 in new_commits:
                                parent = new_commits.get(parent_sha1)
                                if tail_sha1 in new_commits.getTailsFrom(
                                        parent):
                                    message += "\n  %s..%s" % (tail_sha1[:8],
                                                               parent_sha1[:8])

                    message += """
Please confirm that this is intended by loading:
  %s/confirmmerge?id=%d""" % (dbutils.getURLPrefix(db, user), confirmation_id)

                    raise index.IndexException(message)
                elif row[2] is not None:
                    if row[2] == merge.getId(db):
                        cursor.execute(
                            "SELECT merged FROM reviewmergecontributions WHERE id=%s",
                            (row[0], ))

                        for (merged_id, ) in cursor:
                            merged = gitutils.Commit.fromId(
                                db, review.repository, merged_id)
                            if merged.sha1 in merge.parents:
                                new_commits = new_commits.without([merged])
                                break
                    else:
                        tail = gitutils.Commit.fromId(db, review.repository,
                                                      row[2])
                        cut = [
                            gitutils.Commit.fromSHA1(db, review.repository,
                                                     sha1)
                            for sha1 in tail.parents if sha1 in new_commits
                        ]
                        new_commits = new_commits.without(cut)

        if commitset:
            commitset &= set(new_commits)
            commits = [commit for commit in commits if commit in commitset]

    changesets, silent_commits, silent_changesets = \
        createChangesetsForCommits(db, commits, silent_if_empty, full_merges, replayed_rebases)

    if not new_review:
        print "Adding %d commit%s to the review at:\n  %s" % (
            len(commits), len(commits) > 1 and "s" or "", review.getURL(db))

    reviewchangesets_values = [(review.id, changeset.id)
                               for changeset in changesets]

    cursor.executemany(
        """INSERT INTO reviewchangesets (review, changeset) VALUES (%s, %s)""",
        reviewchangesets_values)
    cursor.executemany(
        """INSERT INTO reviewfiles (review, changeset, file, deleted, inserted)
                               SELECT reviewchangesets.review, reviewchangesets.changeset, fileversions.file,
                                      COALESCE(SUM(chunks.deleteCount), 0), COALESCE(SUM(chunks.insertCount), 0)
                                 FROM reviewchangesets
                                 JOIN fileversions USING (changeset)
                      LEFT OUTER JOIN chunks USING (changeset, file)
                                WHERE reviewchangesets.review=%s
                                  AND reviewchangesets.changeset=%s
                             GROUP BY reviewchangesets.review, reviewchangesets.changeset, fileversions.file""",
        reviewchangesets_values)

    new_reviewers, new_watchers = assignChanges(db,
                                                user,
                                                review,
                                                changesets=changesets)

    cursor.execute(
        "SELECT include FROM reviewrecipientfilters WHERE review=%s AND uid IS NULL",
        (review.id, ))

    try:
        opt_out = cursor.fetchone()[0] is True
    except:
        opt_out = True

    if not new_review:
        for user_id in new_reviewers:
            new_reviewuser = dbutils.User.fromId(db, user_id)
            print "Added reviewer: %s <%s>" % (new_reviewuser.fullname,
                                               new_reviewuser.email)

            if opt_out:
                # If the user has opted out from receiving e-mails about this
                # review while only watching it, clear the opt-out now that the
                # user becomes a reviewer.
                cursor.execute(
                    "DELETE FROM reviewrecipientfilters WHERE review=%s AND uid=%s AND include=FALSE",
                    (review.id, user_id))

        for user_id in new_watchers:
            new_reviewuser = dbutils.User.fromId(db, user_id)
            print "Added watcher:  %s <%s>" % (new_reviewuser.fullname,
                                               new_reviewuser.email)

        review.incrementSerial(db)

        reviewing.comment.propagateCommentChains(db, user, review, new_commits,
                                                 replayed_rebases)

    if pending_mails is None: pending_mails = []

    notify_commits = filter(lambda commit: commit not in silent_commits,
                            commits)
    notify_changesets = filter(
        lambda changeset: changeset not in silent_changesets, changesets)

    if not new_review and notify_changesets:
        recipients = review.getRecipients(db)
        for to_user in recipients:
            pending_mails.extend(
                mail.sendReviewAddedCommits(db,
                                            user,
                                            to_user,
                                            recipients,
                                            review,
                                            notify_commits,
                                            notify_changesets,
                                            tracked_branch=tracked_branch))

    mail.sendPendingMails(pending_mails)

    review.reviewers.extend(
        [User.fromId(db, user_id) for user_id in new_reviewers])

    for user_id in new_watchers:
        review.watchers[User.fromId(db, user_id)] = "automatic"

    return True
コード例 #10
0
ファイル: manageextensions.py プロジェクト: yanlimin9/critic
        def renderItem(target):
            target.span("name").innerHTML(extension.getTitle(db, html=True))

            if hosting_user:
                is_author = manifest and manifest.isAuthor(db, hosting_user)
                is_sole_author = is_author and len(manifest.authors) == 1
            else:
                is_sole_author = False

            if extension_error is None:
                span = target.span("details")
                span.b().text("Details: ")
                select = span.select("details", critic_author=extension.getAuthorName(), critic_extension=extension.getName())
                select.option(value='', selected="selected" if selected_version is False else None).text("Select version")
                versions = extension.getVersions()
                if versions:
                    optgroup = select.optgroup(label="Official Versions")
                    for version in versions:
                        optgroup.option(value="version/%s" % version, selected="selected" if selected_version == version else None).text("%s" % version.upper())
                optgroup = select.optgroup(label="Development")
                optgroup.option(value='live', selected="selected" if selected_version is None else None).text("LIVE")

            if manifest:
                is_installed = bool(installed_version)

                if is_installed:
                    target.span("installed").text(" [installed]")
                else:
                    is_installed = bool(universal_version)

                    if is_installed:
                        target.span("installed").text(" [installed (universal)]")

                target.div("description").preformatted().text(manifest.description, linkify=True)

                if not is_sole_author:
                    authors = target.div("authors")
                    authors.b().text("Author%s:" % ("s" if len(manifest.authors) > 1 else ""))
                    authors.text(", ".join(author.name for author in manifest.getAuthors()))
            else:
                is_installed = False

                div = target.div("description broken").preformatted()

                if extension_error is None:
                    anchor = div.a(href="loadmanifest?key=%s" % extension.getKey())
                    anchor.text("[This extension has an invalid MANIFEST file]")
                else:
                    div.text("[This extension has been deleted or has become inaccessible]")

            if selected_version is False:
                return

            pages = []
            injects = []
            processcommits = []
            filterhooks = []
            scheduled = []

            if manifest:
                for role in manifest.roles:
                    if isinstance(role, PageRole):
                        pages.append(role)
                    elif isinstance(role, InjectRole):
                        injects.append(role)
                    elif isinstance(role, ProcessCommitsRole):
                        processcommits.append(role)
                    elif isinstance(role, FilterHookRole):
                        filterhooks.append(role)
                    elif isinstance(role, ScheduledRole):
                        scheduled.append(role)

            role_table = target.table("roles")

            if pages:
                role_table.tr().th(colspan=2).text("Pages")

                for role in pages:
                    row = role_table.tr()
                    url = "%s/%s" % (dbutils.getURLPrefix(db, user), role.pattern)
                    if is_installed and "*" not in url:
                        row.td("pattern").a(href=url).text(url)
                    else:
                        row.td("pattern").text(url)
                    td = row.td("description")
                    td.text(role.description)

            if injects:
                role_table.tr().th(colspan=2).text("Page Injections")

                for role in injects:
                    row = role_table.tr()
                    row.td("pattern").text("%s/%s" % (dbutils.getURLPrefix(db, user), role.pattern))
                    td = row.td("description")
                    td.text(role.description)

            if processcommits:
                role_table.tr().th(colspan=2).text("ProcessCommits hooks")
                ul = role_table.tr().td(colspan=2).ul()

                for role in processcommits:
                    li = ul.li()
                    li.text(role.description)

            if filterhooks:
                role_table.tr().th(colspan=2).text("FilterHook hooks")

                for role in filterhooks:
                    row = role_table.tr()
                    row.td("title").text(role.title)
                    row.td("description").text(role.description)

            if scheduled:
                role_table.tr().th(colspan=2).text("Scheduled hooks")

                for role in scheduled:
                    row = role_table.tr()
                    row.td("pattern").text("%s @ %s" % (role.frequency, role.at))
                    td = row.td("description")
                    td.text(role.description)
コード例 #11
0
ファイル: textformatting.py プロジェクト: ryfow/critic
def renderFormatted(db, user, table, lines, toc=False, title_right=None):
    re_h1 = re.compile("^=+$")
    re_h2 = re.compile("^-+$")
    data = {
        "configuration.URL": dbutils.getURLPrefix(db),
        "configuration.base.HOSTNAME": configuration.base.HOSTNAME,
        "configuration.base.SYSTEM_USER_NAME": configuration.base.SYSTEM_USER_NAME,
        "configuration.base.SYSTEM_GROUP_NAME": configuration.base.SYSTEM_GROUP_NAME,
        "configuration.paths.CONFIG_DIR": configuration.paths.CONFIG_DIR,
        "configuration.paths.INSTALL_DIR": configuration.paths.INSTALL_DIR,
        "configuration.paths.GIT_DIR": configuration.paths.GIT_DIR,
    }

    blocks = []
    block = []

    for line in lines:
        if line.strip():
            block.append(line % data)
        elif block:
            blocks.append(block)
            block = []
    else:
        if block:
            blocks.append(block)

    text = None

    for block in blocks:

        def textToId(text):
            return text.lower().replace(" ", "_")

        if len(block) == 2:
            if re_h1.match(block[1]):
                table.setTitle(block[0])
                h1 = table.tr("h1").td("h1").h1(id=textToId(block[0]))
                h1.text(block[0])
                if title_right:
                    span_right = h1.span("right")
                    if callable(title_right):
                        title_right(span_right)
                    else:
                        span_right.text(title_right)
                text = None
                if toc:
                    toc = table.tr("toc").td("toc").div().table("toc")
                    toc.tr("heading").th().text("Table of contents")
                continue
            elif re_h2.match(block[1]):
                if toc:
                    toc.tr("h2").td().a(href="#" + textToId(block[0])).text(block[0])
                table.tr("h2").td("h2").div().h2(id=textToId(block[0])).text(block[0])
                text = None
                continue

        if len(block) == 1 and block[0] == "[repositories]":
            text = None

            repositories = (
                table.tr("repositories").td("repositories").table("repositories", align="center", cellspacing=0)
            )
            headings = repositories.tr("headings")
            headings.th("name").text("Short name")
            headings.th("path").text("Repository path")

            cursor = db.cursor()
            cursor.execute("SELECT name, path FROM repositories ORDER BY id ASC")

            first = " first"

            for name, path in cursor:
                row = repositories.tr("repository" + first)
                row.td("name").text(name)
                row.td("path").text(gitutils.Repository.constructURL(db, user, path))
                first = ""

            continue

        if not text:
            text = table.tr("text").td("text")

        def translateConfigLinks(text):
            def linkify(match):
                item = match.group(1)
                return "<a href='config?highlight=%s'>%s</a>" % (item, item)

            return re.sub("CONFIG\\(([^)]+)\\)", linkify, text)

        def processText(lines):
            for index, line in enumerate(lines):
                if line.startswith("  http"):
                    lines[index] = "<a href='%s'>%s</a>" % (line.strip(), line.strip())
            return translateConfigLinks("\n".join(lines)).replace("--", "&mdash;")

        if len(block) > 2 and re_h2.match(block[1]):
            if toc:
                toc.tr("h3").td().a(href="#" + textToId(block[0])).text(block[0])
            div = text.div()
            div.h3(id=textToId(block[0])).text(block[0])
            block = block[2:]

        if block[0].startswith("|"):
            pre = text.div().table("pre").tr().td().preformatted()
            pre.text("\n".join([line[2:] for line in block]))
        elif block[0].startswith("* ") or block[0].startswith("1 "):
            if block[0].startswith("* "):
                items = text.div().ul()
            else:
                items = text.div().ol()
            item = []
            for line in block:
                if line[:2] != "  ":
                    if item:
                        items.li().text("\n".join(item), cdata=True)
                    item = []
                else:
                    assert line[:2] == "  "
                item.append(line[2:])
            if item:
                items.li().text("\n".join(item), cdata=True)
        elif block[0].startswith("? "):
            items = text.div().dl()
            term = []
            definition = None
            for line in block:
                if line[:2] == "? ":
                    if definition:
                        items.dt().text(" ".join(term))
                        items.dd().text(processText(definition))
                        definition = None
                    term = [line[2:]]
                elif line[:2] == "= ":
                    assert term
                    assert definition is None
                    definition = [line[2:]]
                elif definition is None:
                    term.append(line[2:])
                else:
                    definition.append(line[2:])
            items.dt().text(" ".join(term))
            items.dd().text(processText(definition), cdata=True)
        elif block[0].startswith("  "):
            text_data = translateConfigLinks("\n".join(block))
            if block[0].startswith("  <code>"):
                className = "example"
            else:
                className = "hint"
                text_data = text_data.replace("--", "&mdash;")
            text.div().div(className).text(text_data, cdata=True)
        else:
            text.div().text(processText(block), cdata=True)
コード例 #12
0
def createCommentChain(db,
                       user,
                       review,
                       chain_type,
                       commit_id=None,
                       origin=None,
                       file_id=None,
                       parent_id=None,
                       child_id=None,
                       old_sha1=None,
                       new_sha1=None,
                       offset=None,
                       count=None):
    if chain_type == "issue" and review.state != "open":
        raise OperationFailure(
            code="reviewclosed",
            title="Review is closed!",
            message=
            "You need to reopen the review before you can raise new issues.")

    cursor = db.cursor()

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

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

            rows = cursor.fetchall()

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

                rows = cursor.fetchall()

            parent = child = None

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

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

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

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

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

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

        children_returned = set()

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

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

        row = cursor.fetchone()

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

            row = cursor.fetchone()

        primary_changeset_id = row[0]

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

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

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

        commentchainlines_values = []
        processed = set()

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

        first_line = offset
        last_line = offset + count - 1

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    return chain_id
コード例 #13
0
ファイル: critic.py プロジェクト: ctesting/critic
            yield str(document)
            return
        except:
            error_message = traceback.format_exc()

            environ["wsgi.errors"].write(error_message)

            db.rollback()

            if not user or user.hasRole(db, "developer"):
                title = "You broke the system again:"
                body = error_message
                body_html = "<pre>%s</pre>" % htmlify(body)
            else:
                prefix = dbutils.getURLPrefix(db)

                x_forwarded_host = req.getRequestHeader("X-Forwarded-Host")
                if x_forwarded_host: prefix = "https://" + x_forwarded_host

                url = "%s/%s?%s" % (prefix, req.path, req.query)

                mailutils.sendExceptionMessage("wsgi", ("User:   %s\nMethod: %s\nPath:   %s\nQuery:  %s\nURL:    %s\n\n%s"
                                                        % (req.user, req.method, req.path, req.query, url, error_message)))

                title = "Darn! It seems we have a problem..."
                body = "A message has been sent to the system administrator(s) with details about the problem."
                body_html = body

            if not req.isStarted():
                req.setStatus(500)
コード例 #14
0
def renderFormatted(db, user, table, lines, toc=False, title_right=None):
    re_h1 = re.compile("^=+$")
    re_h2 = re.compile("^-+$")
    data = {
        "configuration.URL": dbutils.getURLPrefix(db, user),
        "configuration.base.HOSTNAME": configuration.base.HOSTNAME,
        "configuration.base.SYSTEM_USER_NAME":
        configuration.base.SYSTEM_USER_NAME,
        "configuration.base.SYSTEM_GROUP_NAME":
        configuration.base.SYSTEM_GROUP_NAME,
        "configuration.paths.CONFIG_DIR": configuration.paths.CONFIG_DIR,
        "configuration.paths.INSTALL_DIR": configuration.paths.INSTALL_DIR,
        "configuration.paths.DATA_DIR": configuration.paths.DATA_DIR,
        "configuration.paths.GIT_DIR": configuration.paths.GIT_DIR
    }

    references = {}
    blocks = []
    block = []

    for line in lines:
        match = re.match(r'\[(.*?)\]: (.*?)(?: "(.*?)")?$', line)
        if match:
            name, url, title = match.groups()
            references[name] = (url, title)
            continue

        if line.strip():
            block.append(line % data)
        elif block:
            blocks.append(block)
            block = []
    else:
        if block:
            blocks.append(block)

    text = None

    for block in blocks:

        def textToId(text):
            return text.lower().replace(' ', '_')

        if len(block) == 2:
            if re_h1.match(block[1]):
                table.setTitle(block[0])
                h1 = table.tr("h1").td("h1").h1(id=textToId(block[0]))
                h1.text(block[0])
                if title_right:
                    span_right = h1.span("right")
                    if callable(title_right):
                        title_right(span_right)
                    else:
                        span_right.text(title_right)
                text = None
                if toc:
                    toc = table.tr("toc").td("toc").div().table("toc callout")
                    toc.tr("heading").th().text("Table of contents")
                continue
            elif re_h2.match(block[1]):
                if toc:
                    toc.tr("h2").td().a(href="#" + textToId(block[0])).text(
                        block[0])
                table.tr("h2").td("h2").div().h2(id=textToId(block[0])).text(
                    block[0])
                text = None
                continue

        if len(block) == 1 and block[0] == "[repositories]":
            text = None

            repositories = table.tr().td().table("repositories callout")
            headings = repositories.thead().tr()
            headings.th("name").text("Short name")
            headings.th("path").text("Repository path")

            repositories.tr().td(colspan=2)

            cursor = db.cursor()
            cursor.execute(
                "SELECT name, path FROM repositories ORDER BY id ASC")

            for name, path in cursor:
                row = repositories.tr("repository")
                row.td("name").text(name)
                row.td("path").text(
                    gitutils.Repository.constructURL(db, user, path))

            continue

        if not text:
            text = table.tr("text").td("text")

        def translateLinks(text):
            def linkify(match):
                config_item, reference_text, reference_name = match.groups()

                if config_item:
                    url = "/config?highlight=%s" % config_item
                    text = config_item
                    title = None
                else:
                    reference_name = re.sub(r"\s+", " ", reference_name)
                    assert reference_name in references, reference_name
                    url, title = references[reference_name]
                    text = reference_text

                link = "<a href=%s" % htmlutils.htmlify(url, True)

                if title:
                    link += " title=%s" % htmlutils.htmlify(title, True)

                return link + ">%s</a>" % htmlutils.htmlify(text)

            return re.sub(r"CONFIG\(([^)]+)\)|\[(.*?)\]\n?\[(.*?)\]",
                          linkify,
                          text,
                          flags=re.DOTALL)

        def processText(lines):
            if isinstance(lines, basestring):
                lines = [lines]
            for index, line in enumerate(lines):
                if line.startswith("  http"):
                    lines[index] = "<a href='%s'>%s</a>" % (line.strip(),
                                                            line.strip())
            text = translateLinks("\n".join(lines))

            # Replace double dashes with &mdash;, but only if they are
            # surrounded by either spaces or word characters on both sides.
            #
            # We don't want to translate the double dashes in a
            # --command-line-argument used in the text.
            text = re.sub(r"(^| )--( |$)",
                          r"\1&mdash;\2",
                          text,
                          flags=re.MULTILINE)
            text = re.sub(r"(\w)--(\w)", r"\1&mdash;\2", text)

            return text

        if len(block) > 2 and re_h2.match(block[1]):
            if toc:
                toc.tr("h3").td().a(href="#" + textToId(block[0])).text(
                    block[0])
            div = text.div()
            div.h3(id=textToId(block[0])).text(block[0])
            block = block[2:]

        if block[0].startswith("|"):
            pre = text.div().table("pre callout").tr().td().preformatted()
            contents = "\n".join([line[2:] for line in block])
            if block[0].startswith("||"):
                pre.innerHTML(contents)
            else:
                pre.text(contents)
        elif block[0].startswith("* ") or block[0].startswith("1 "):
            if block[0].startswith("* "):
                items = text.div().ul()
            else:
                items = text.div().ol()
            item = []
            for line in block:
                if line[:2] != '  ':
                    if item:
                        items.li().text(processText(item), cdata=True)
                    item = []
                else:
                    assert line[:2] == "  "
                item.append(line[2:])
            if item:
                items.li().text(processText(item), cdata=True)
        elif block[0].startswith("? "):
            items = text.div().dl()
            term = []
            definition = None
            for line in block:
                if line[:2] == '? ':
                    if definition:
                        items.dt().text(processText(" ".join(term)),
                                        cdata=True)
                        items.dd().text(processText(definition), cdata=True)
                        definition = None
                    term = [line[2:]]
                elif line[:2] == '= ':
                    assert term
                    assert definition is None
                    definition = [line[2:]]
                elif definition is None:
                    term.append(line[2:])
                else:
                    definition.append(line[2:])
            items.dt().text(processText(" ".join(term)), cdata=True)
            items.dd().text(processText(definition), cdata=True)
        elif block[0].startswith("  "):
            text_data = translateLinks("\n".join(block))
            if block[0].startswith("  <code>"):
                className = "example"
            else:
                className = "hint"
                text_data = text_data.replace("--", "&mdash;")
            text.div().div(className).text(text_data, cdata=True)
        else:
            text.div().text(processText(block), cdata=True)
コード例 #15
0
ファイル: __init__.py プロジェクト: aparan/critic
def createCommentChain(db, user, review, chain_type, commit_id=None, origin=None, file_id=None, parent_id=None, child_id=None, old_sha1=None, new_sha1=None, offset=None, count=None):
    if chain_type == "issue" and review.state != "open":
        raise OperationFailure(code="reviewclosed",
                               title="Review is closed!",
                               message="You need to reopen the review before you can raise new issues.")

    cursor = db.cursor()

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

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

            rows = cursor.fetchall()

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

                rows = cursor.fetchall()

            parent = child = None

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

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

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

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

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

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

        children_returned = set()

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

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

        row = cursor.fetchone()

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

            row = cursor.fetchone()

        primary_changeset_id = row[0]

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

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

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

        commentchainlines_values = []
        processed = set()

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

        first_line = offset
        last_line = offset + count - 1

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    return chain_id
コード例 #16
0
def commitRangeFromReview(db, user, review, filter, file_ids):
    edges = cursor = db.cursor()

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

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

        edges = set()

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

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

    listed_commits = set()
    with_pending = set()

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

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

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

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

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

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

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

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

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

                paths.append((tail, paths_in_upstream))

            overlapping_changes = paths_in_review & paths_in_upstreams

            if overlapping_changes:
                candidates = []

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

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

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

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

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

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

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

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

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

        return tails.pop(), review.branch.head.sha1, all_commits, listed_commits
コード例 #17
0
ファイル: index.py プロジェクト: KurSh/critic
def createBranch(user, repository, name, head):
    processCommits(repository.name, head)

    cursor = db.cursor()

    def commit_id(sha1):
        cursor.execute("SELECT id FROM commits WHERE sha1=%s", [sha1])
        return cursor.fetchone()[0]

    components = name.split("/")
    for index in range(1, len(components)):
        try: repository.revparse("refs/heads/%s" % "/".join(components[:index]))
        except: continue

        message = ("Cannot create branch with name '%s' since there is already a branch named '%s' in the repository." %
                   (name, "/".join(components[:index])))
        raise IndexException, textutils.reflow(message, line_length=80 - len("remote: "))

    if name.startswith("r/"):
        try:
            review_id = int(name[2:])

            cursor.execute("SELECT branches.name FROM reviews JOIN branches ON (branches.id=reviews.branch) WHERE reviews.id=%s", (review_id,))
            row = cursor.fetchone()

            message = "Refusing to create review named as a number."

            if row:
                message += "\nDid you mean to push to the branch '%s', perhaps?" % row[0]

            raise IndexException, message
        except ValueError:
            pass

        if user.getPreference(db, "review.createViaPush"):
            the_commit = gitutils.Commit.fromSHA1(db, repository, head, commit_id(head))
            all_commits = [the_commit]
            review = review_utils.createReview(db, user, repository, all_commits, name, the_commit.summary(), None, via_push=True)

            print "Submitted review: %s/r/%d" % (dbutils.getURLPrefix(db), review.id)

            if review.reviewers:
                print "  Reviewers:"
                for reviewer in review.reviewers:
                    print "    %s <%s>" % (reviewer.fullname, reviewer.email)

            if review.watchers:
                print "  Watchers:"
                for watcher in review.watchers:
                    print "    %s <%s>" % (watcher.fullname, watcher.email)

            if configuration.extensions.ENABLED:
                if extensions.executeProcessCommits(db, user, review, all_commits, None, the_commit, stdout):
                    print

            print "Thank you!"
            return True
        else:
            raise IndexException, "Refusing to create review; user preference 'review.createViaPush' is not enabled."

    sha1 = head
    base = None
    tail = None

    cursor.execute("""SELECT 1
                        FROM reachable
                        JOIN branches ON (branches.id=reachable.branch)
                        JOIN repositories ON (repositories.id=branches.repository)
                       WHERE repositories.id=%s
                       LIMIT 1""",
                   (repository.id,))

    if cursor.fetchone():
        def reachable(sha1):
            cursor.execute("""SELECT branches.id
                                FROM branches
                                JOIN reachable ON (reachable.branch=branches.id)
                                JOIN commits ON (commits.id=reachable.commit)
                               WHERE branches.repository=%s
                                 AND branches.type='normal'
                                 AND commits.sha1=%s
                            ORDER BY reachable.branch ASC
                               LIMIT 1""",
                           (repository.id, sha1))
            return cursor.fetchone()
    else:
        def reachable(sha1):
            return None

    commit_map = {}
    commit_list = []

    row = reachable(sha1)
    if row:
        # Head of branch is reachable from an existing branch.  Could be because
        # this branch is actually empty (just created with no "own" commits) or
        # it could have been merged into some other already existing branch.  We
        # can't tell, so we just record it as empty.

        base = row[0]
        tail = sha1
    else:
        stack = []

        while True:
            if sha1 not in commit_map:
                commit = gitutils.Commit.fromSHA1(db, repository, sha1)
                commit_map[sha1] = commit
                commit_list.append(commit)

                for sha1 in commit.parents:
                    if sha1 not in commit_map:
                        row = reachable(sha1)
                        if not row:
                            stack.append(sha1)
                        elif base is None:
                            base = row[0]
                            tail = sha1

                            base_chain = [base]

                            while True:
                                cursor.execute("SELECT base FROM branches WHERE id=%s", (base_chain[-1],))
                                next = cursor.fetchone()[0]
                                if next is None: break
                                else: base_chain.append(next)

                            def reachable(sha1):
                                cursor.execute("""SELECT 1
                                                    FROM reachable
                                                    JOIN commits ON (commits.id=reachable.commit)
                                                   WHERE reachable.branch=ANY (%s)
                                                     AND commits.sha1=%s""",
                                               (base_chain, sha1))
                                return cursor.fetchone()

            if stack: sha1 = stack.pop(0)
            else: break

        if len(commit_list) % 10000 > 1000:
            stdout.write("\n")
            stdout.flush()

    if not base:
        cursor.execute("INSERT INTO branches (repository, name, head) VALUES (%s, %s, %s) RETURNING id", (repository.id, name, commit_id(head)))
        branch_id = cursor.fetchone()[0]
    else:
        cursor.execute("INSERT INTO branches (repository, name, head, base, tail) VALUES (%s, %s, %s, %s, %s) RETURNING id", (repository.id, name, commit_id(head), base, commit_id(tail)))
        branch_id = cursor.fetchone()[0]

        cursor.execute("SELECT name FROM branches WHERE id=%s", [base])

        print "Added branch based on %s containing %d commit%s:" % (cursor.fetchone()[0], len(commit_list), "s" if len(commit_list) > 1 else "")
        print "  %s/log?repository=%d&branch=%s" % (dbutils.getURLPrefix(db), repository.id, name)
        if len(commit_list) > 1:
            print "To create a review of all %d commits:" % len(commit_list)
        else:
            print "To create a review of the commit:"
        print "  %s/createreview?repository=%d&branch=%s" % (dbutils.getURLPrefix(db), repository.id, name)

    reachable_values = [(branch_id, commit.sha1) for commit in commit_list]
    cursor.executemany("INSERT INTO reachable (branch, commit) SELECT %s, id FROM commits WHERE sha1=%s", reachable_values)

    if isinstance(user, str): user_name = user
    else: user_name = user.name

    if not repository.hasMainBranch() and user_name == configuration.base.SYSTEM_USER_NAME:
        cursor.execute("UPDATE repositories SET branch=%s WHERE id=%s", (branch_id, repository.id))
コード例 #18
0
ファイル: textformatting.py プロジェクト: Haster2004/critic
def renderFormatted(db, user, table, lines, toc=False, title_right=None):
    re_h1 = re.compile("^=+$")
    re_h2 = re.compile("^-+$")
    data = { "configuration.URL": dbutils.getURLPrefix(db, user),
             "configuration.base.HOSTNAME": configuration.base.HOSTNAME,
             "configuration.base.SYSTEM_USER_NAME": configuration.base.SYSTEM_USER_NAME,
             "configuration.base.SYSTEM_GROUP_NAME": configuration.base.SYSTEM_GROUP_NAME,
             "configuration.paths.CONFIG_DIR": configuration.paths.CONFIG_DIR,
             "configuration.paths.INSTALL_DIR": configuration.paths.INSTALL_DIR,
             "configuration.paths.DATA_DIR": configuration.paths.DATA_DIR,
             "configuration.paths.GIT_DIR": configuration.paths.GIT_DIR }

    references = {}
    blocks = []
    block = []

    for line in lines:
        match = re.match(r'\[(.*?)\]: (.*?)(?: "(.*?)")?$', line)
        if match:
            name, url, title = match.groups()
            references[name] = (url, title)
            continue

        if line.strip():
            block.append(line % data)
        elif block:
            blocks.append(block)
            block = []
    else:
        if block:
            blocks.append(block)

    text = None

    for block in blocks:
        def textToId(text):
            return text.lower().replace(' ', '_')

        if len(block) == 2:
            if re_h1.match(block[1]):
                table.setTitle(block[0])
                h1 = table.tr("h1").td("h1").h1(id=textToId(block[0]))
                h1.text(block[0])
                if title_right:
                    span_right = h1.span("right")
                    if callable(title_right):
                        title_right(span_right)
                    else:
                        span_right.text(title_right)
                text = None
                if toc:
                    toc = table.tr("toc").td("toc").div().table("toc callout")
                    toc.tr("heading").th().text("Table of contents")
                continue
            elif re_h2.match(block[1]):
                if toc: toc.tr("h2").td().a(href="#" + textToId(block[0])).text(block[0])
                table.tr("h2").td("h2").div().h2(id=textToId(block[0])).text(block[0])
                text = None
                continue

        if len(block) == 1 and block[0] == "[repositories]":
            text = None

            repositories = table.tr().td().table("repositories callout")
            headings = repositories.thead().tr()
            headings.th("name").text("Short name")
            headings.th("path").text("Repository path")

            repositories.tr().td(colspan=2)

            cursor = db.cursor()
            cursor.execute("SELECT name, path FROM repositories ORDER BY id ASC")

            for name, path in cursor:
                row = repositories.tr("repository")
                row.td("name").text(name)
                row.td("path").text(gitutils.Repository.constructURL(db, user, path))

            continue

        if not text:
            text = table.tr("text").td("text")

        def translateLinks(text):
            def linkify(match):
                config_item, reference_text, reference_name = match.groups()

                if config_item:
                    url = "/config?highlight=%s" % config_item
                    text = config_item
                    title = None
                else:
                    reference_name = re.sub(r"\s+", " ", reference_name)
                    assert reference_name in references, reference_name
                    url, title = references[reference_name]
                    text = reference_text

                link = "<a href=%s" % htmlutils.htmlify(url, True)

                if title:
                    link += " title=%s" % htmlutils.htmlify(title, True)

                return link + ">%s</a>" % htmlutils.htmlify(text)

            return re.sub(r"CONFIG\(([^)]+)\)|\[(.*?)\]\n?\[(.*?)\]", linkify, text, flags=re.DOTALL)

        def processText(lines):
            if isinstance(lines, basestring):
                lines = [lines]
            for index, line in enumerate(lines):
                if line.startswith("  http"):
                    lines[index] = "<a href='%s'>%s</a>" % (line.strip(), line.strip())
            text = translateLinks("\n".join(lines))

            # Replace double dashes with &mdash;, but only if they are
            # surrounded by either spaces or word characters on both sides.
            #
            # We don't want to translate the double dashes in a
            # --command-line-argument used in the text.
            text = re.sub(r"(^| )--( |$)", r"\1&mdash;\2", text, flags=re.MULTILINE)
            text = re.sub(r"(\w)--(\w)", r"\1&mdash;\2", text)

            return text

        if len(block) > 2 and re_h2.match(block[1]):
            if toc: toc.tr("h3").td().a(href="#" + textToId(block[0])).text(block[0])
            div = text.div()
            div.h3(id=textToId(block[0])).text(block[0])
            block = block[2:]

        if block[0].startswith("|"):
            pre = text.div().table("pre callout").tr().td().preformatted()
            pre.text("\n".join([line[2:] for line in block]))
        elif block[0].startswith("* ") or block[0].startswith("1 "):
            if block[0].startswith("* "):
                items = text.div().ul()
            else:
                items = text.div().ol()
            item = []
            for line in block:
                if line[:2] != '  ':
                    if item:
                        items.li().text(processText(item), cdata=True)
                    item = []
                else:
                    assert line[:2] == "  "
                item.append(line[2:])
            if item:
                items.li().text(processText(item), cdata=True)
        elif block[0].startswith("? "):
            items = text.div().dl()
            term = []
            definition = None
            for line in block:
                if line[:2] == '? ':
                    if definition:
                        items.dt().text(processText(" ".join(term)), cdata=True)
                        items.dd().text(processText(definition), cdata=True)
                        definition = None
                    term = [line[2:]]
                elif line[:2] == '= ':
                    assert term
                    assert definition is None
                    definition = [line[2:]]
                elif definition is None:
                    term.append(line[2:])
                else:
                    definition.append(line[2:])
            items.dt().text(processText(" ".join(term)), cdata=True)
            items.dd().text(processText(definition), cdata=True)
        elif block[0].startswith("  "):
            text_data = translateLinks("\n".join(block))
            if block[0].startswith("  <code>"):
                className = "example"
            else:
                className = "hint"
                text_data = text_data.replace("--", "&mdash;")
            text.div().div(className).text(text_data, cdata=True)
        else:
            text.div().text(processText(block), cdata=True)
コード例 #19
0
ファイル: utils.py プロジェクト: ahockersten/critic
def addCommitsToReview(db, user, review, commits, new_review=False, commitset=None, pending_mails=None, silent_if_empty=set(), full_merges=set(), replayed_rebases={}, tracked_branch=False):
    cursor = db.cursor()

    if not new_review:
        import index

        new_commits = log_commitset.CommitSet(commits)
        old_commits = log_commitset.CommitSet(review.branch.commits)
        merges = new_commits.getMerges()

        for merge in merges:
            # We might have stripped it in a previous pass.
            if not merge in new_commits: continue

            tails = filter(lambda sha1: sha1 not in old_commits and sha1 not in merge.parents, new_commits.getTailsFrom(merge))

            if tails:
                if tracked_branch:
                    raise index.IndexException("""\
Merge %s adds merged-in commits.  Please push the merge manually
and follow the instructions.""" % merge.sha1[:8])

                cursor.execute("SELECT id, confirmed, tail FROM reviewmergeconfirmations WHERE review=%s AND uid=%s AND merge=%s", (review.id, user.id, merge.getId(db)))

                row = cursor.fetchone()

                if not row or not row[1]:
                    if not row:
                        cursor.execute("INSERT INTO reviewmergeconfirmations (review, uid, merge) VALUES (%s, %s, %s) RETURNING id", (review.id, user.id, merge.getId(db)))
                        confirmation_id = cursor.fetchone()[0]

                        merged = set()

                        for tail_sha1 in tails:
                            children = new_commits.getChildren(tail_sha1)

                            while children:
                                child = children.pop()
                                if child not in merged and new_commits.isAncestorOf(child, merge):
                                    merged.add(child)
                                    children.update(new_commits.getChildren(child) - merged)

                        merged_values = [(confirmation_id, commit.getId(db)) for commit in merged]
                        cursor.executemany("INSERT INTO reviewmergecontributions (id, merged) VALUES (%s, %s)", merged_values)
                        db.commit()
                    else:
                        confirmation_id = row[0]

                    message = "Merge %s adds merged-in commits:" % merge.sha1[:8]

                    for tail_sha1 in tails:
                        for parent_sha1 in merge.parents:
                            if parent_sha1 in new_commits:
                                parent = new_commits.get(parent_sha1)
                                if tail_sha1 in new_commits.getTailsFrom(parent):
                                    message += "\n  %s..%s" % (tail_sha1[:8], parent_sha1[:8])

                    message += """
Please confirm that this is intended by loading:
  %s/confirmmerge?id=%d""" % (dbutils.getURLPrefix(db, user), confirmation_id)

                    raise index.IndexException(message)
                elif row[2] is not None:
                    if row[2] == merge.getId(db):
                        cursor.execute("SELECT merged FROM reviewmergecontributions WHERE id=%s",
                                       (row[0],))

                        for (merged_id,) in cursor:
                            merged = gitutils.Commit.fromId(db, review.repository, merged_id)
                            if merged.sha1 in merge.parents:
                                new_commits = new_commits.without([merged])
                                break
                    else:
                        tail = gitutils.Commit.fromId(db, review.repository, row[2])
                        cut = [gitutils.Commit.fromSHA1(db, review.repository, sha1)
                               for sha1 in tail.parents if sha1 in new_commits]
                        new_commits = new_commits.without(cut)

        if commitset:
            commitset &= set(new_commits)
            commits = [commit for commit in commits if commit in commitset]

    changesets = []
    silent_commits = set()
    silent_changesets = set()

    simple_commits = []
    for commit in commits:
        if commit not in full_merges and commit not in replayed_rebases:
            simple_commits.append(commit)
    if simple_commits:
        changeset_utils.createChangesets(db, review.repository, simple_commits)

    for commit in commits:
        if commit in full_merges:
            commit_changesets = changeset_utils.createFullMergeChangeset(
                db, user, review.repository, commit, do_highlight=False)
        elif commit in replayed_rebases:
            commit_changesets = changeset_utils.createChangeset(
                db, user, review.repository,
                from_commit=commit, to_commit=replayed_rebases[commit],
                conflicts=True, do_highlight=False)
        else:
            commit_changesets = changeset_utils.createChangeset(
                db, user, review.repository, commit, do_highlight=False)

        if commit in silent_if_empty:
            for commit_changeset in commit_changesets:
                if commit_changeset.files:
                    break
            else:
                silent_commits.add(commit)
                silent_changesets.update(commit_changesets)

        changesets.extend(commit_changesets)

    if not new_review:
        print "Adding %d commit%s to the review at:\n  %s" % (len(commits), len(commits) > 1 and "s" or "", review.getURL(db))

    reviewchangesets_values = [(review.id, changeset.id) for changeset in changesets]

    cursor.executemany("""INSERT INTO reviewchangesets (review, changeset) VALUES (%s, %s)""", reviewchangesets_values)
    cursor.executemany("""INSERT INTO reviewfiles (review, changeset, file, deleted, inserted)
                               SELECT reviewchangesets.review, reviewchangesets.changeset, fileversions.file,
                                      COALESCE(SUM(chunks.deleteCount), 0), COALESCE(SUM(chunks.insertCount), 0)
                                 FROM reviewchangesets
                                 JOIN fileversions USING (changeset)
                      LEFT OUTER JOIN chunks USING (changeset, file)
                                WHERE reviewchangesets.review=%s
                                  AND reviewchangesets.changeset=%s
                             GROUP BY reviewchangesets.review, reviewchangesets.changeset, fileversions.file""",
                       reviewchangesets_values)

    new_reviewers, new_watchers = assignChanges(db, user, review, changesets=changesets)

    cursor.execute("SELECT include FROM reviewrecipientfilters WHERE review=%s AND uid IS NULL", (review.id,))

    try: opt_out = cursor.fetchone()[0] is True
    except: opt_out = True

    if not new_review:
        for user_id in new_reviewers:
            new_reviewuser = dbutils.User.fromId(db, user_id)
            print "Added reviewer: %s <%s>" % (new_reviewuser.fullname, new_reviewuser.email)

            if opt_out:
                # If the user has opted out from receiving e-mails about this
                # review while only watching it, clear the opt-out now that the
                # user becomes a reviewer.
                cursor.execute("DELETE FROM reviewrecipientfilters WHERE review=%s AND uid=%s AND include=FALSE", (review.id, user_id))

        for user_id in new_watchers:
            new_reviewuser = dbutils.User.fromId(db, user_id)
            print "Added watcher:  %s <%s>" % (new_reviewuser.fullname, new_reviewuser.email)

        review.incrementSerial(db)

        reviewing.comment.propagateCommentChains(db, user, review, new_commits, replayed_rebases)

    if pending_mails is None: pending_mails = []

    notify_commits = filter(lambda commit: commit not in silent_commits, commits)
    notify_changesets = filter(lambda changeset: changeset not in silent_changesets, changesets)

    if not new_review and notify_changesets:
        recipients = review.getRecipients(db)
        for to_user in recipients:
            pending_mails.extend(mail.sendReviewAddedCommits(
                    db, user, to_user, recipients, review, notify_commits,
                    notify_changesets, tracked_branch=tracked_branch))

    mail.sendPendingMails(pending_mails)

    review.reviewers.extend([User.fromId(db, user_id) for user_id in new_reviewers])

    for user_id in new_watchers:
        review.watchers[User.fromId(db, user_id)] = "automatic"

    return True
コード例 #20
0
        def renderItem(target):
            span = target.span("name")
            span.b().text(extension.getName())
            span.text(" by %s" % author.fullname)

            span = target.span("details")
            span.b().text("Details: ")
            select = span.select("details",
                                 critic_author=extension.getAuthorName(),
                                 critic_extension=extension.getName())
            select.option(value='',
                          selected="selected" if selected_version is False else
                          None).text("Select version")
            versions = extension.getVersions()
            if versions:
                optgroup = select.optgroup(label="Official Versions")
                for version in extension.getVersions():
                    optgroup.option(value="version/%s" % version,
                                    selected="selected" if selected_version
                                    == version else None).text("%s" %
                                                               version.upper())
            optgroup = select.optgroup(label="Development")
            optgroup.option(value='live',
                            selected="selected"
                            if selected_version is None else None).text("LIVE")

            if manifest:
                is_installed = manifest.status in (
                    "partial", "installed") or installed_version is not False

                if is_installed:
                    target.span("installed").text(" [installed]")

                target.div("description").preformatted().text(
                    manifest.description)
            else:
                is_installed = False

                target.div("description broken").preformatted().a(
                    href="loadmanifest?author=%s&name=%s" %
                    (extension.getAuthorName(), extension.getName())).text(
                        "[This extension has an invalid MANIFEST file]")

            if selected_version is False:
                return

            pages = []
            injects = []
            processcommits = []
            processchanges = []

            if manifest:
                for role in manifest.roles:
                    if isinstance(role, extensions.PageRole):
                        pages.append(role)
                    elif isinstance(role, extensions.InjectRole):
                        injects.append(role)
                    elif isinstance(role, extensions.ProcessCommitsRole):
                        processcommits.append(role)
                    elif isinstance(role, extensions.ProcessChangesRole):
                        processchanges.append(role)

            role_table = target.table("roles")

            if pages:
                role_table.tr().th(colspan=2).text("Pages")

                for role in pages:
                    row = role_table.tr()
                    row.td("pattern").text(
                        "%s/%s" % (dbutils.getURLPrefix(db), role.pattern))
                    td = row.td("description")
                    td.text(role.description)

                    if is_installed and not role.installed:
                        td.text(" ")
                        td.span("inactive").text("[Not active!]")

            if injects:
                role_table.tr().th(colspan=2).text("Page Injections")

                for role in injects:
                    row = role_table.tr()
                    row.td("pattern").text(
                        "%s/%s" % (dbutils.getURLPrefix(db), role.pattern))
                    td = row.td("description")
                    td.text(role.description)

                    if is_installed and not role.installed:
                        td.text(" ")
                        td.span("inactive").text("[Not active!]")

            if processcommits:
                role_table.tr().th(colspan=2).text("ProcessCommits hooks")
                ul = role_table.tr().td(colspan=2).ul()

                for role in processcommits:
                    li = ul.li()
                    li.text(role.description)

                    if is_installed and not role.installed:
                        li.text(" ")
                        li.span("inactive").text("[Not active!]")

            if processchanges:
                role_table.tr().th(colspan=2).text("ProcessChanges hooks")
                ul = role_table.tr().td(colspan=2).ul()

                for role in processchanges:
                    li = ul.li()
                    li.text(role.description)

                    if is_installed and not role.installed:
                        li.text(" ")
                        li.span("inactive").text("[Not active!]")