Showing preview only (4,254K chars total). Download the full file or copy to clipboard to get everything.
Repository: jensl/critic
Branch: stable/1
Commit: c2d962b909ff
Files: 730
Total size: 3.9 MB
Directory structure:
gitextract_90xaov2p/
├── .gitignore
├── .gitmodules
├── CONTRIBUTORS
├── COPYING
├── INSTALL
├── README.md
├── documentation/
│ ├── concepts.txt
│ ├── tutorials.txt
│ └── user_faq.md
├── extend.py
├── install.py
├── installation/
│ ├── __init__.py
│ ├── admin.py
│ ├── config.py
│ ├── criticctl.py
│ ├── data/
│ │ ├── comments.pgsql
│ │ ├── dbschema.base.sql
│ │ ├── dbschema.changesets.sql
│ │ ├── dbschema.comments.sql
│ │ ├── dbschema.extensions.sql
│ │ ├── dbschema.filters.sql
│ │ ├── dbschema.git.sql
│ │ ├── dbschema.news.sql
│ │ ├── dbschema.preferences.sql
│ │ ├── dbschema.reviews.sql
│ │ ├── dbschema.trackedbranches.sql
│ │ └── dbschema.users.sql
│ ├── database.py
│ ├── extensions.py
│ ├── externals/
│ │ ├── .gitignore
│ │ ├── MIT-LICENSE.Chosen.md
│ │ └── MIT-LICENSE.jQuery.txt
│ ├── files.py
│ ├── git.py
│ ├── httpd.py
│ ├── initd.py
│ ├── input.py
│ ├── lifecycle.json
│ ├── migrate.py
│ ├── migrations/
│ │ ├── dbschema.altertable.branches.add.archived.py
│ │ ├── dbschema.altertable.changesets.parent.dropnotnull.py
│ │ ├── dbschema.altertable.commentchainchanges.addressed_by.py
│ │ ├── dbschema.altertable.commentchainchanges.drop.review.py
│ │ ├── dbschema.altertable.commentchainlines.drop.commit.py
│ │ ├── dbschema.altertable.comments.time.setdefaultnow.py
│ │ ├── dbschema.altertable.previousreachable.rebase.ondeletecascade.py
│ │ ├── dbschema.altertable.repositories.drop.branch.py
│ │ ├── dbschema.altertable.repositories.drop.relay.py
│ │ ├── dbschema.altertable.reviewfilechanges.rename-columns.py
│ │ ├── dbschema.altertable.reviewmergeconfirmations.add.tail.py
│ │ ├── dbschema.altertable.reviewrebases.add.equivalent_merge.py
│ │ ├── dbschema.altertable.reviewrebases.add.replayed_rebase.py
│ │ ├── dbschema.altertable.reviewrecipientfilters.uid-can-be-null.py
│ │ ├── dbschema.altertable.reviews.add.origin.py
│ │ ├── dbschema.altertable.systemidentities.add.installed_sha1.installed_at.py
│ │ ├── dbschema.altertable.systemidentities.url-prefix.py
│ │ ├── dbschema.altertable.usergitemails.py
│ │ ├── dbschema.altertable.usersessions.add.labels.py
│ │ ├── dbschema.createindex.misc.py
│ │ ├── dbschema.createtable.accesstokens.py
│ │ ├── dbschema.createtable.knownremotes.py
│ │ ├── dbschema.createtable.scheduledreviewbrancharchivals.py
│ │ ├── dbschema.createtable.timezones.py
│ │ ├── dbschema.createtable.useremails.py
│ │ ├── dbschema.createtable.usersessions.py
│ │ ├── dbschema.createtables.accesscontrol.py
│ │ ├── dbschema.droptable.knownhosts.py
│ │ ├── dbschema.extension-filterhook-role.py
│ │ ├── dbschema.external-authentication.py
│ │ ├── dbschema.files-and-directories.py
│ │ ├── dbschema.fixup-extensionroles.py
│ │ ├── dbschema.per-repository-or-filter-preferences.py
│ │ ├── dbschema.review-constraints-tweaking.py
│ │ ├── git.check-keepalive-references.py
│ │ ├── git.clean-up-temporary-references.py
│ │ ├── git.convert-replays-into-keepalives.py
│ │ ├── git.rename-keepalive-chain.py
│ │ ├── installation.config-pyc-file-permissions.py
│ │ ├── news.filter-system-rewrite.py
│ │ ├── news.review-branch-archival.py
│ │ ├── news.review-quick-search.py
│ │ └── preference.commit.diff.rulerColumn.py
│ ├── paths.py
│ ├── prefs.py
│ ├── prereqs.py
│ ├── process.py
│ ├── qs/
│ │ ├── __init__.py
│ │ ├── data.py
│ │ └── sqlite.py
│ ├── smtp.py
│ ├── system.py
│ ├── templates/
│ │ ├── apache/
│ │ │ ├── site.both
│ │ │ ├── site.http
│ │ │ └── site.https
│ │ ├── configuration/
│ │ │ ├── __init__.py
│ │ │ ├── auth.py
│ │ │ ├── base.py
│ │ │ ├── database.py
│ │ │ ├── debug.py
│ │ │ ├── executables.py
│ │ │ ├── extensions.py
│ │ │ ├── limits.py
│ │ │ ├── mimetypes.py
│ │ │ ├── paths.py
│ │ │ ├── services.py
│ │ │ ├── smtp-credentials.json
│ │ │ └── smtp.py
│ │ ├── criticctl
│ │ ├── initd
│ │ ├── nginx/
│ │ │ ├── site.both
│ │ │ ├── site.http
│ │ │ └── site.https
│ │ └── uwsgi/
│ │ ├── app.backend.ini
│ │ ├── app.frontend.ini.both
│ │ ├── app.frontend.ini.http
│ │ └── app.frontend.ini.https
│ └── utils.py
├── pylint.rc
├── pythonversion.py
├── quickstart.py
├── src/
│ ├── api/
│ │ ├── __init__.py
│ │ ├── accesscontrolprofile.py
│ │ ├── accesstoken.py
│ │ ├── apierror.py
│ │ ├── apiobject.py
│ │ ├── batch.py
│ │ ├── branch.py
│ │ ├── changeset.py
│ │ ├── comment.py
│ │ ├── commit.py
│ │ ├── commitset.py
│ │ ├── config.py
│ │ ├── critic.py
│ │ ├── extension.py
│ │ ├── file.py
│ │ ├── filechange.py
│ │ ├── filecontent.py
│ │ ├── filediff.py
│ │ ├── filters.py
│ │ ├── impl/
│ │ │ ├── __init__.py
│ │ │ ├── accesscontrolprofile.py
│ │ │ ├── accesstoken.py
│ │ │ ├── apiobject.py
│ │ │ ├── batch.py
│ │ │ ├── branch.py
│ │ │ ├── branch_unittest.py
│ │ │ ├── changeset.py
│ │ │ ├── changeset_unittest.py
│ │ │ ├── comment.py
│ │ │ ├── comment_unittest.py
│ │ │ ├── commit.py
│ │ │ ├── commit_unittest.py
│ │ │ ├── commitset.py
│ │ │ ├── commitset_unittest.py
│ │ │ ├── config_unittest.py
│ │ │ ├── critic.py
│ │ │ ├── extension.py
│ │ │ ├── file.py
│ │ │ ├── filechange.py
│ │ │ ├── filechange_unittest.py
│ │ │ ├── filecontent.py
│ │ │ ├── filediff.py
│ │ │ ├── filediff_unittest.py
│ │ │ ├── filters.py
│ │ │ ├── labeledaccesscontrolprofile.py
│ │ │ ├── log/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── partition.py
│ │ │ │ ├── partition_unittest.py
│ │ │ │ ├── rebase.py
│ │ │ │ └── rebase_unittest.py
│ │ │ ├── reply.py
│ │ │ ├── reply_unittest.py
│ │ │ ├── repository.py
│ │ │ ├── repository_unittest.py
│ │ │ ├── review.py
│ │ │ ├── review_unittest.py
│ │ │ ├── reviewablefilechange.py
│ │ │ ├── reviewsummary.py
│ │ │ ├── user.py
│ │ │ └── user_unittest.py
│ │ ├── labeledaccesscontrolprofile.py
│ │ ├── log/
│ │ │ ├── __init__.py
│ │ │ ├── partition.py
│ │ │ └── rebase.py
│ │ ├── preference.py
│ │ ├── reply.py
│ │ ├── repository.py
│ │ ├── review.py
│ │ ├── reviewablefilechange.py
│ │ ├── reviewsummary.py
│ │ ├── transaction/
│ │ │ ├── __init__.py
│ │ │ ├── accesscontrolprofile.py
│ │ │ ├── accesstoken.py
│ │ │ ├── comment.py
│ │ │ ├── filters.py
│ │ │ ├── labeledaccesscontrolprofile.py
│ │ │ ├── reply.py
│ │ │ ├── review.py
│ │ │ └── user.py
│ │ └── user.py
│ ├── auth/
│ │ ├── __init__.py
│ │ ├── accesscontrol.py
│ │ ├── database.py
│ │ ├── databases/
│ │ │ ├── __init__.py
│ │ │ ├── accesstokensdb.py
│ │ │ ├── internaldb.py
│ │ │ └── ldapdb.py
│ │ ├── oauth.py
│ │ ├── provider.py
│ │ ├── providers/
│ │ │ ├── __init__.py
│ │ │ ├── dummy.py
│ │ │ ├── github.py
│ │ │ └── google.py
│ │ └── session.py
│ ├── background/
│ │ ├── __init__.py
│ │ ├── branchtracker.py
│ │ ├── branchtrackerhook.py
│ │ ├── changeset.py
│ │ ├── daemon.py
│ │ ├── extensionrunner.py
│ │ ├── extensiontasks.py
│ │ ├── githook.py
│ │ ├── highlight.py
│ │ ├── maildelivery.py
│ │ ├── maintenance.py
│ │ ├── servicemanager.py
│ │ ├── utils.py
│ │ ├── wait-for-pidfiles.py
│ │ └── watchdog.py
│ ├── base.py
│ ├── base_unittest.py
│ ├── changeset/
│ │ ├── __init__.py
│ │ ├── client.py
│ │ ├── create.py
│ │ ├── detectmoves.py
│ │ ├── html.py
│ │ ├── load.py
│ │ ├── process.py
│ │ ├── text.py
│ │ └── utils.py
│ ├── cli.py
│ ├── communicate.py
│ ├── coverage.py
│ ├── critic.py
│ ├── data/
│ │ └── preferences.json
│ ├── dbaccess.py
│ ├── dbutils/
│ │ ├── __init__.py
│ │ ├── branch.py
│ │ ├── database.py
│ │ ├── database_unittest.py
│ │ ├── paths.py
│ │ ├── review.py
│ │ ├── session.py
│ │ ├── system.py
│ │ ├── timezones.py
│ │ ├── unittest.py
│ │ └── user.py
│ ├── diff/
│ │ ├── __init__.py
│ │ ├── analyze.py
│ │ ├── context.py
│ │ ├── html.py
│ │ ├── merge.py
│ │ └── parse.py
│ ├── diffutils.py
│ ├── extensions/
│ │ ├── __init__.py
│ │ ├── execute.py
│ │ ├── extension.py
│ │ ├── installation.py
│ │ ├── manifest.py
│ │ ├── resource.py
│ │ ├── role/
│ │ │ ├── __init__.py
│ │ │ ├── filterhook.py
│ │ │ ├── inject.py
│ │ │ ├── page.py
│ │ │ └── processcommits.py
│ │ ├── unittest.py
│ │ └── utils.py
│ ├── gitutils.py
│ ├── gitutils_unittest.py
│ ├── hooks/
│ │ └── pre-receive
│ ├── htmlutils.py
│ ├── htmlutils_unittest.py
│ ├── index.py
│ ├── inpututils.py
│ ├── jsonapi/
│ │ ├── __init__.py
│ │ ├── check.py
│ │ ├── documentation.py
│ │ └── v1/
│ │ ├── README.txt
│ │ ├── __init__.py
│ │ ├── accesscontrolprofiles.py
│ │ ├── accesstokens.py
│ │ ├── batches.py
│ │ ├── branches.py
│ │ ├── changesets.py
│ │ ├── comments.py
│ │ ├── commits.py
│ │ ├── documentation.py
│ │ ├── extensions.py
│ │ ├── filechanges.py
│ │ ├── filecontents.py
│ │ ├── filediffs.py
│ │ ├── files.py
│ │ ├── labeledaccesscontrolprofiles.py
│ │ ├── rebases.py
│ │ ├── replies.py
│ │ ├── repositories.py
│ │ ├── reviewablefilechanges.py
│ │ ├── reviews.py
│ │ ├── reviewsummaries.py
│ │ ├── sessions.py
│ │ └── users.py
│ ├── library/
│ │ └── js/
│ │ └── v8/
│ │ ├── critic-batch.js
│ │ ├── critic-branch.js
│ │ ├── critic-changeset.js
│ │ ├── critic-cli.js
│ │ ├── critic-comment.js
│ │ ├── critic-commitset.js
│ │ ├── critic-dashboard.js
│ │ ├── critic-file.js
│ │ ├── critic-filters.js
│ │ ├── critic-filterstransaction.js
│ │ ├── critic-git.js
│ │ ├── critic-html.js
│ │ ├── critic-launcher-fork.js
│ │ ├── critic-launcher.js
│ │ ├── critic-log.js
│ │ ├── critic-mail.js
│ │ ├── critic-review.js
│ │ ├── critic-statistics.js
│ │ ├── critic-storage.js
│ │ ├── critic-text.js
│ │ ├── critic-trackedbranch.js
│ │ ├── critic-user.js
│ │ └── critic.js
│ ├── linkify.py
│ ├── log/
│ │ ├── __init__.py
│ │ ├── commitset.py
│ │ └── html.py
│ ├── mailutils.py
│ ├── maintenance/
│ │ ├── __init__.py
│ │ ├── check-branches.py
│ │ ├── check-commits.py
│ │ ├── configtest.py
│ │ ├── criticctl.py
│ │ ├── dumppreferences.py
│ │ └── progress.py
│ ├── operation/
│ │ ├── __init__.py
│ │ ├── addrepository.py
│ │ ├── applyfilters.py
│ │ ├── autocompletedata.py
│ │ ├── basictypes.py
│ │ ├── basictypes_unittest.py
│ │ ├── blame.py
│ │ ├── brancharchiving.py
│ │ ├── checkrebase.py
│ │ ├── createcomment.py
│ │ ├── createreview.py
│ │ ├── draftchanges.py
│ │ ├── editresource.py
│ │ ├── extensioninstallation.py
│ │ ├── fetchlines.py
│ │ ├── manipulateassignments.py
│ │ ├── manipulatecomment.py
│ │ ├── manipulatefilters.py
│ │ ├── manipulatereview.py
│ │ ├── manipulateuser.py
│ │ ├── markfiles.py
│ │ ├── miscellaneous.py
│ │ ├── news.py
│ │ ├── rebasereview.py
│ │ ├── recipientfilter.py
│ │ ├── registeruser.py
│ │ ├── savesettings.py
│ │ ├── searchreview.py
│ │ ├── servicemanager.py
│ │ ├── trackedbranch.py
│ │ ├── typechecker.py
│ │ ├── typechecker_unittest.py
│ │ ├── unittest.py
│ │ └── usersession.py
│ ├── page/
│ │ ├── __init__.py
│ │ ├── addrepository.py
│ │ ├── basic.py
│ │ ├── branches.py
│ │ ├── checkbranch.py
│ │ ├── config.py
│ │ ├── confirmmerge.py
│ │ ├── createreview.py
│ │ ├── createuser.py
│ │ ├── dashboard.py
│ │ ├── editresource.py
│ │ ├── filterchanges.py
│ │ ├── home.py
│ │ ├── loadmanifest.py
│ │ ├── login.py
│ │ ├── manageextensions.py
│ │ ├── managereviewers.py
│ │ ├── news.py
│ │ ├── parameters.py
│ │ ├── processcommits.py
│ │ ├── rebasetrackingreview.py
│ │ ├── repositories.py
│ │ ├── search.py
│ │ ├── services.py
│ │ ├── showbatch.py
│ │ ├── showbranch.py
│ │ ├── showcomment.py
│ │ ├── showcommit.py
│ │ ├── showfile.py
│ │ ├── showfilters.py
│ │ ├── showreview.py
│ │ ├── showreviewlog.py
│ │ ├── showtree.py
│ │ ├── statistics.py
│ │ ├── tutorial.py
│ │ ├── utils.py
│ │ └── verifyemail.py
│ ├── profiling.py
│ ├── request.py
│ ├── resources/
│ │ ├── .gitattributes
│ │ ├── autocomplete.js
│ │ ├── basic.css
│ │ ├── basic.js
│ │ ├── branches.css
│ │ ├── branches.js
│ │ ├── changeset.css
│ │ ├── changeset.js
│ │ ├── checkbranch.css
│ │ ├── checkbranch.js
│ │ ├── comment.css
│ │ ├── comment.js
│ │ ├── config.css
│ │ ├── config.js
│ │ ├── confirmmerge.css
│ │ ├── confirmmerge.js
│ │ ├── createreview.css
│ │ ├── createreview.js
│ │ ├── createuser.css
│ │ ├── createuser.js
│ │ ├── dashboard.css
│ │ ├── dashboard.js
│ │ ├── diff.css
│ │ ├── editresource.css
│ │ ├── editresource.js
│ │ ├── filterchanges.css
│ │ ├── filterchanges.js
│ │ ├── home.css
│ │ ├── home.js
│ │ ├── log.css
│ │ ├── log.js
│ │ ├── login.css
│ │ ├── login.js
│ │ ├── manageextensions.css
│ │ ├── manageextensions.js
│ │ ├── managereviewers.css
│ │ ├── managereviewers.js
│ │ ├── message.css
│ │ ├── newrepository.css
│ │ ├── newrepository.js
│ │ ├── news.css
│ │ ├── news.js
│ │ ├── overrides.css
│ │ ├── rebasetrackingreview.css
│ │ ├── rebasetrackingreview.js
│ │ ├── repositories.css
│ │ ├── repositories.js
│ │ ├── review.css
│ │ ├── review.js
│ │ ├── reviewfilters.js
│ │ ├── ruler.js
│ │ ├── search.css
│ │ ├── search.js
│ │ ├── services.css
│ │ ├── services.js
│ │ ├── showbatch.css
│ │ ├── showbranch.css
│ │ ├── showcomment.js
│ │ ├── showfile.css
│ │ ├── showfile.js
│ │ ├── showreview.css
│ │ ├── showreview.js
│ │ ├── showreviewlog.css
│ │ ├── showtree.css
│ │ ├── statistics.css
│ │ ├── syntax.css
│ │ ├── tabify.css
│ │ ├── tabify.js
│ │ ├── third-party/
│ │ │ ├── chosen.css
│ │ │ ├── chosen.js
│ │ │ ├── jquery-ui-1.10.2.custom.css
│ │ │ └── jquery-ui-autocomplete-html.js
│ │ ├── tutorial.css
│ │ ├── tutorial.js
│ │ └── whitespace.css
│ ├── reviewing/
│ │ ├── __init__.py
│ │ ├── comment/
│ │ │ ├── __init__.py
│ │ │ └── propagate.py
│ │ ├── filters.py
│ │ ├── html.py
│ │ ├── mail.py
│ │ ├── rebase.py
│ │ └── utils.py
│ ├── run_unittest.py
│ ├── syntaxhighlight/
│ │ ├── __init__.py
│ │ ├── clexer.py
│ │ ├── context.py
│ │ ├── cpp.py
│ │ ├── generate.py
│ │ ├── generic.py
│ │ └── request.py
│ ├── textformatting.py
│ ├── textutils.py
│ ├── textutils_unittest.py
│ ├── tutorials/
│ │ ├── administration.txt
│ │ ├── archival.txt
│ │ ├── checkbranch.txt
│ │ ├── customization.txt
│ │ ├── extensions-api.txt
│ │ ├── extensions.txt
│ │ ├── external-authentication.txt
│ │ ├── filters.txt
│ │ ├── rebasing.txt
│ │ ├── reconfiguring.txt
│ │ ├── repository.txt
│ │ ├── requesting.txt
│ │ ├── reviewing.txt
│ │ └── search.txt
│ ├── urlutils.py
│ ├── wsgi.py
│ └── wsgistartup.py
├── testing/
│ ├── USAGE.md
│ ├── __init__.py
│ ├── __main__.py
│ ├── expect.py
│ ├── findtests.py
│ ├── flags/
│ │ ├── addrepository-has-mirror-parameter.flag
│ │ ├── fixed-batch-preview.flag
│ │ ├── is-testing.flag
│ │ ├── pwd-independence.flag
│ │ ├── reliable-admin-newswriter.flag
│ │ ├── reliable-git-emails.flag
│ │ ├── system-recipients.flag
│ │ └── web-server-integration.flag
│ ├── frontend.py
│ ├── input/
│ │ ├── SystemExtension/
│ │ │ ├── MANIFEST
│ │ │ ├── check.js
│ │ │ └── resources/
│ │ │ └── HelloWorld.txt
│ │ ├── TestExtension/
│ │ │ ├── MANIFEST
│ │ │ ├── MailTransaction.js
│ │ │ ├── Review.list.js
│ │ │ ├── echo.js
│ │ │ ├── empty.js
│ │ │ ├── error.compilation.js
│ │ │ ├── error.runtime.js
│ │ │ ├── evaluate.js
│ │ │ ├── filterhook.js
│ │ │ ├── inject.js
│ │ │ ├── nothandled.js
│ │ │ ├── processcommits.js
│ │ │ ├── resources/
│ │ │ │ ├── hello.world.js
│ │ │ │ ├── helloworld.css
│ │ │ │ └── helloworld.html
│ │ │ ├── restrictions.js
│ │ │ └── version.js
│ │ ├── binary
│ │ ├── customization/
│ │ │ ├── githook.py
│ │ │ └── linktypes.py
│ │ ├── empty.txt
│ │ ├── service_log_filter.py
│ │ ├── service_synchronization_helper.py
│ │ └── syntaxhighlight/
│ │ └── example.cpp
│ ├── local.py
│ ├── mailbox.py
│ ├── main.py
│ ├── password-invalid
│ ├── password-testing
│ ├── quickstart.py
│ ├── repository.py
│ ├── tests/
│ │ └── 001-main/
│ │ ├── 000-install.py
│ │ ├── 001-empty/
│ │ │ ├── 001-anonymous/
│ │ │ │ ├── 001-dashboard.py
│ │ │ │ ├── 002-branches.py
│ │ │ │ ├── 003-search.py
│ │ │ │ ├── 004-config.py
│ │ │ │ ├── 005-tutorial.py
│ │ │ │ ├── 006-news.py
│ │ │ │ ├── 007-home.py
│ │ │ │ ├── 008-repositories.py
│ │ │ │ ├── 009-services.py
│ │ │ │ ├── 010-createreview.py
│ │ │ │ ├── 011-manageextensions.py
│ │ │ │ ├── 012-statistics.py
│ │ │ │ ├── 013-static-resource.py
│ │ │ │ └── 100-preferences/
│ │ │ │ ├── 001-commit.diff.rulerColumn.py
│ │ │ │ ├── 002-review.defaultOptOut.py
│ │ │ │ ├── 003-timezone.py
│ │ │ │ └── __init__.py
│ │ │ ├── 002-authenticated/
│ │ │ │ ├── 001-dashboard.py
│ │ │ │ ├── 002-branches.py
│ │ │ │ ├── 003-search.py
│ │ │ │ ├── 004-config.py
│ │ │ │ ├── 005-tutorial.py
│ │ │ │ ├── 006-news.py
│ │ │ │ ├── 007-home.py
│ │ │ │ ├── 008-repositories.py
│ │ │ │ ├── 009-services.py
│ │ │ │ ├── 010-createreview.py
│ │ │ │ ├── 011-manageextensions.py
│ │ │ │ ├── 012-statistics.py
│ │ │ │ └── 100-preferences/
│ │ │ │ ├── 001-commit.diff.rulerColumn.py
│ │ │ │ ├── 002-review.defaultOptOut.py
│ │ │ │ ├── 003-timezone.py
│ │ │ │ └── __init__.py
│ │ │ ├── 003-criticctl/
│ │ │ │ ├── 001-basic.py
│ │ │ │ ├── 002-adduser-deluser.py
│ │ │ │ ├── 003-addrole-delrole.py
│ │ │ │ ├── 004-listusers.py
│ │ │ │ ├── 005-configtest.py
│ │ │ │ └── 006-restart.py
│ │ │ └── 004-mixed/
│ │ │ ├── 001-newswriter.py
│ │ │ ├── 002-email.py
│ │ │ ├── 003-oauth.py
│ │ │ ├── 004-password.py
│ │ │ ├── 005-accesstoken.py
│ │ │ ├── 006-accesscontrol-http.py
│ │ │ ├── 007-json-session.py
│ │ │ └── __init__.py
│ │ ├── 002-createrepository.py
│ │ ├── 003-self/
│ │ │ ├── 001-rulerColumn.py
│ │ │ ├── 002-emptyfile.py
│ │ │ ├── 003-binaryfile.py
│ │ │ ├── 004-createreview.py
│ │ │ ├── 004-first-review-created/
│ │ │ │ ├── 001-addreviewfilters-bogus.py
│ │ │ │ ├── 002-review-archival.py
│ │ │ │ └── __init__.py
│ │ │ ├── 005-checkbranch.py
│ │ │ ├── 006-showreview-reviewfilter.py
│ │ │ ├── 007-http-backend.py
│ │ │ ├── 008-initial-commit-diff.py
│ │ │ ├── 009-fetchremotebranch.py
│ │ │ ├── 010-linkification.py
│ │ │ ├── 011-linkification-custom.py
│ │ │ ├── 012-createreview-recipients.py
│ │ │ ├── 012-replayrebase.py
│ │ │ ├── 014-non-ascii-filenames.py
│ │ │ ├── 015-non-ascii-line-diff.py
│ │ │ ├── 016-showcommit-ranges.py
│ │ │ ├── 017-showcommit-merge-replay.py
│ │ │ ├── 018-detect-moves-no-moved-code.py
│ │ │ ├── 019-showtree-showfile-bogus.py
│ │ │ ├── 020-fixup-review-via-push.py
│ │ │ ├── 020-reviewrebase.py
│ │ │ ├── 021-updatereview-bogus.py
│ │ │ ├── 022-removereviewfilter-bogus.py
│ │ │ ├── 024-customizations.githook.py
│ │ │ ├── 025-trackedbranch.py
│ │ │ ├── 026-searchreview.py
│ │ │ ├── 027-whitespace-filenames.py
│ │ │ ├── 028-gitemails.py
│ │ │ ├── 029-log-bogus.py
│ │ │ ├── 030-trackingreview.py
│ │ │ ├── 031-fetchlines-bom.py
│ │ │ ├── 032-download.py
│ │ │ ├── 033-propagation-vs-rebase.py
│ │ │ ├── 100-reviewing/
│ │ │ │ ├── 001-comments.basic.py
│ │ │ │ └── __init__.py
│ │ │ ├── 101-keepalives.py
│ │ │ ├── 200-json/
│ │ │ │ ├── 001-users.py
│ │ │ │ ├── 002-branches.py
│ │ │ │ ├── 003-repositories.py
│ │ │ │ ├── 004-review.py
│ │ │ │ ├── 005-commits.py
│ │ │ │ ├── 006-changesets.py
│ │ │ │ ├── 006-comments.py
│ │ │ │ ├── 007-filechanges.py
│ │ │ │ ├── 007-replies.py
│ │ │ │ ├── 008-batches.py
│ │ │ │ └── __init__.py
│ │ │ └── __init__.py
│ │ ├── 004-extensions/
│ │ │ ├── 001-enable.py
│ │ │ ├── 002-tests/
│ │ │ │ ├── 001-tutorial.py
│ │ │ │ ├── 002-manageextensions.py
│ │ │ │ ├── 003-install-TestExtension.py
│ │ │ │ ├── 004-TestExtension/
│ │ │ │ │ ├── 001-echo.py
│ │ │ │ │ ├── 002-nothandled.py
│ │ │ │ │ ├── 003-empty.py
│ │ │ │ │ ├── 004-Review.list.py
│ │ │ │ │ ├── 005-MailTransaction.py
│ │ │ │ │ ├── 006-inject.py
│ │ │ │ │ ├── 007-version.py
│ │ │ │ │ ├── 008-processcommits.py
│ │ │ │ │ ├── 009-error-messages.py
│ │ │ │ │ ├── 010-restrictions.py
│ │ │ │ │ ├── 011-User.py
│ │ │ │ │ ├── 012-resources.py
│ │ │ │ │ ├── 013-storage.py
│ │ │ │ │ ├── 014-Repository.run.py
│ │ │ │ │ ├── 015-filterhook.py
│ │ │ │ │ ├── 016-accesscontrol.py
│ │ │ │ │ └── 999-missing.py
│ │ │ │ ├── 005-install-SystemExtension.py
│ │ │ │ └── 006-manifest-checks.py
│ │ │ └── __init__.py
│ │ ├── 005-unittests/
│ │ │ ├── 001-local/
│ │ │ │ ├── 001-independence.py
│ │ │ │ ├── 002-operation.py
│ │ │ │ ├── 005-dbutils.database.py
│ │ │ │ └── __init__.py
│ │ │ ├── 002-api/
│ │ │ │ ├── 001-commit.py
│ │ │ │ ├── 002-review.py
│ │ │ │ ├── 003-user.py
│ │ │ │ ├── 004-config.py
│ │ │ │ ├── 005-log.partition.py
│ │ │ │ ├── 006-log.rebase.py
│ │ │ │ ├── 007-repository.py
│ │ │ │ ├── 008-branch.py
│ │ │ │ ├── 009-commitset.py
│ │ │ │ ├── 010-comment.py
│ │ │ │ ├── 011-reply.py
│ │ │ │ ├── 012-changeset.py
│ │ │ │ ├── 013-filechange.py
│ │ │ │ └── 014-filediff.py
│ │ │ └── 003-other/
│ │ │ ├── 001-dbutils.database.py
│ │ │ └── __init__.py
│ │ └── 900-uninstall-reinstall.py
│ ├── tools/
│ │ ├── __init__.py
│ │ ├── install.py
│ │ └── upgrade.py
│ ├── utils.py
│ └── virtualbox.py
├── uninstall.py
└── upgrade.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.install.data
.installed
*.pyc
*.pyo
*~
testing/cache
================================================
FILE: .gitmodules
================================================
[submodule "installation/externals/chosen"]
path = installation/externals/chosen
url = ../chosen.git
[submodule "installation/externals/v8-jsshell"]
path = installation/externals/v8-jsshell
url = ../v8-jsshell.git
================================================
FILE: CONTRIBUTORS
================================================
Author:
Jens Lindström <jl@critic-review.org>
Contributors:
Rafał Chłodnicki
Philip Jägenstedt
Leif Arne Storset
Alexey Feldgendler
Michał Gawron
James Graham
Martin Olsson
Daniel Bratell
Odin Hørthe Omdal
Fredrik Öhrn
Peter Krefting
Pengfei Xue
Johan Herland
Ryan Fowler
Jacob Rask
Felix Ekblom
Andreas Tolfsen
================================================
FILE: COPYING
================================================
Copyright 2012-2014 the Critic contributors, Opera Software ASA
The Critic code review system is licensed under the Apache License, version 2.0,
with exceptions noted below. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
An list of contributors can be found in the CONTRIBUTORS file.
Third-party software
====================
The following third-party software is distributed with Critic (checked into
Critic's Git repository.)
jQuery
------
The jQuery library is licensed under the MIT License, available in the file
installation/externals/MIT-LICENSE.jQuery.txt. These files distributed with
Critic are part of jQuery:
installation/externals/MIT-LICENSE.jQuery.txt
resources/jquery-2.0.0.min.js
resources/jquery-ui-1.10.2.custom.css
resources/jquery-ui-1.10.2.custom.min.js
resources/images/ui-*.png
For more information, see:
http://jquery.org/
Chosen
------
The Chosen library is licensed under the MIT License, available in the file
installation/externals/MIT-LICENSE.Chosen.md. These files distributed with
Critic are part of Chosen:
installation/externals/MIT-LICENSE.Chosen.md
resources/chosen*.js
resources/chosen*.css
resources/chosen-*.png
For more information, see:
http://harvesthq.github.io/chosen/
Critic's version of Chosen is built from slightly modified fork of the main
GitHub repository:
https://github.com/jensl/chosen
================================================
FILE: INSTALL
================================================
Installation
============
To install Critic, run the script install.py as root. It will ask a
number of question and then perform the installation. In short, what
it does is:
* Check for and/or install required software packages.
* Create a system user (typically named "critic") and group (also
typically named "critic").
* Generate system configuration into /etc/critic/.
* Install the source code into /usr/share/critic/.
* Create a PostgreSQL user and database, both named "critic".
* Create a System-V style init script, /etc/init.d/critic-main, and
create links to it in the /etc/rcN.d/ directories.
* Enable the Apache modules mod_expires and mod_wsgi.
* Create an Apache site named "critic-main" and enable it.
Required Software Packages
--------------------------
Critic depends on the following software packages:
* PostgreSQL (9.1 or later), both client and server parts
* Apache (2.2 or later)
* Git
* Python (2.7 or later; 3.x not supported)
* Non-standard Python modules:
- passlib (if Critic does user authentication)
- psycopg2
- pygments
Note that on Debian/Ubuntu systems, the install.py script can install
all of these software packages automatically.
================================================
FILE: README.md
================================================
Critic
======
This is the code review system, Critic.
Critic has a few [concepts][concepts] that might be useful to know.
Installation
------------
To install Critic, run the script `install.py` as root:
# python install.py
It will ask a number of questions and then perform the installation.
You should probably read the [INSTALL file][install] for all the information.
[install]: https://github.com/jensl/critic/blob/master/INSTALL
[concepts]: https://github.com/jensl/critic/blob/master/documentation/concepts.txt
Adding a repository
-------------------
After installing you should be able to navigate to the hostname you
specified during installtion and see Critic running. When using the
administrator account you will also see 'Repositories' and 'Services'
as top level menu items, in addition to the usual menu items. To add
a new repository, click the 'Repositories' menu item and then the
'Add Repository' button in the top right corner.
If Critic only has ssh access to the upstream of your repository, you must
set up the 'critic' system user (or whatever user name was chosen during
installation) to have ssh access without the need of a password. You can do
that by creating an ssh key without a password and using 'ssh-copy-id' to
copy the key across to the server. If you need to connect to the upstream
server using a different user name, you need to create a 'config' file in
the 'critic' system user's '.ssh' directory containing:
Host <upstream-host-name>
User <upstream-user-name>
Make sure to verify that you can access the repository from the 'critic'
user by running something like this:
su -s /bin/bash -c "ssh -v <upstream-host-name>" critic
This should also ensure that the upstream server key is stored in the
'critic' user's 'known_hosts' file.
This needs only to be done once per upstream server.
Adding users
------------
If you are using the 'host' authentication system, users authenticated by
the web server will be added automatically to the Critic user database. If
you are using the 'critic' authentication system you can use the 'critcctl'
tool to add users beyond the administrative user created by the install.py
script:
sudo criticctl adduser
Only the users added with this method will be able to sign in to the system
when using the 'critic' authentication system.
Adding push rights
------------------
Before a user can push review branches to the newly created Critic repository
their system account must be a member of the 'critic' system group (or whatever
group name was chosen during installation). In Debian/Ubuntu this can be done
using:
usermod -a -G critic <user-who-wants-push-rights>
Setting up reviewers and requesting a review
--------------------------------------------
The developers responsible for performing the code review can subscribe
to new review requests either for a specific set of subdirectories or for
the entire source tree. This configuration is done by each reviewer under
the 'Home' top level menu item.
For information about how to request a new code review, click the 'Tutorial'
top level menu item, and then select 'Requesting a Review'.
See also
--------
The [Critic user FAQ][faq] answers some common questions and gives some useful
tips on how to use Critic efficiently.
There is a tutorial on basic system administration tasks available in the
installed Critic system; click the 'Tutorial' top level menu item and select
'Administration'.
[faq]: https://github.com/jensl/critic/blob/master/documentation/user_faq.md
================================================
FILE: documentation/concepts.txt
================================================
Critic(al) Concepts
===================
Branches
--------
Critic maintains a view of branches that is slightly different from git's. In
addition to knowing the head of the branch, that is, the most recent commit, it
also keeps track of (after basically inventing the information itself) a base
branch and a "tail" commit. A branch is considered to "contain" all commits
that are reachable from its head commit, except all commits that are reachable
from the base branch.
This view of a branch is useful when the purpose is (possibly) to review the
work done on the branch. In this case, one needs to limit the scope to where
the branch started, since in git's view, the branch contains everything back to
the beginning of time, which is not what one means to review.
It's important to note, however, that the "base" of a branch is not something
that is stored in git, and thus Critic needs to resort to fairly simple
heuristics in determining the base of a branch, and can get it wrong. In
particular, it will reverse the relationship between related branches in some
cases. If a branch A is created from master, and then later a branch B is
created from branch A, and branches A and B diverge, the "correct" relationships
are that A's base branch is master and B's base branch is A. However, if B is
pushed to Critic's repository before A, Critic's will think that B's base branch
is master and A's base branch is B. If branches are pushed to Critic's
repository in the order which they are created, then Critic will get it right,
though.
Reviews
-------
A review in Critic is a branch in Critic's repository, and the changes to be
reviewed are the commits (that, according to Critic, are) contained on that
branch. There are two basic ways to start a review: push a branch to Critic's
repository and create a review of all the changes on the branch, or select one
or more commits and have Critic create a branch containing exactly those
commits. In practice, the difference between the two alternatives is quite
insignificant.
The branch is like any other git branch. It can be fetched from Critic's
repository into a local work repository, and additional commits can be pushed
back to Critic's repository. Commits pushed to Critic's repository are
automatically added to the review, as changes that need reviewing.
At this time, non-fast forward updates of review branches in Critic's repository
are not possible.
Reviewers
---------
Reviewers are users of Critic that have registered themselves as reviewers of
parts of the source code tree. When changes are scheduled for review, reviewers
are automatically assigned, based on this configuration. Thus the user
requesting the review needn't assign reviewers manually.
Chunks
------
Each commit scheduled to be reviewed as part of a review is split into
individual change "chunks" (N lines deleted, M lines added,) individually
recorded in Critic's database along with a status. Each such chunk of changes
needs to be approved by a registered reviewer for the modified file. The
low-level details is typically hidden from the reviewers, however. They don't
need to explicitly approve each chunk individually, for instance.
"Approval" of chunks of changes is not thought to be final, and thus not
standing in conflict with not accepting the changes as-is. (And thus the term
"approve" is slightly misleading; "read" or "reviewed" would be perhaps more
appropriate.)
Any chunk of changes not approved yet blocks the review from being "accepted".
Comments
--------
A vital part of reviewing is commenting specific lines of code. In Critic,
there are two types of comments; "issues" and "notes". An "issue" is a comment
that must be addressed, one way or another, before the review can be "accepted."
A "note" is simply a note; it has no formal significance.
When a new version of the file that is commented is created (by adding
additional commits to the review,) one of two things may happen to existing
comments: they can be transferred to the new version, if all commented lines are
identical in the new version of the file, or marked as "addressed," if any
commented line was modified. When a comment is automatically marked as
"addressed," it could be because it was in fact properly addressed, or it could
be because some unrelated change was made to the commented lines. In the latter
case, the author of the comment (or anyone else, for that matter) may "reopen"
the comment by manually transferring the comment to a sequence of lines in the
new version of the file.
It may seem as if "issue" comments might easily be "lost" by unrelated changes
touching the commented lines, but everyone involved in the comment (its author
and anyone who replied to it) will be notified that the comment was marked as
addressed, and of course, the new changes in the file have to be reviewed as any
other changes; the fact that they "addressed" a comment does not automatically
mark the changes themselves as approved.
"Issue" comments can also be explicitly closed their authors (or reviewers of
the file in which the comment was made) after discussion, if the agreement is
that no changes to the commented code needs to be made.
Review Progress
---------------
The ultimate goal of a review is to close it. A review can only be closed when
it is in an "accepted" state, which, in turn, it is when each and every chunk of
changes have been approved by reviewers, and every "issue" comment has been
marked either as addressed or closed.
Reviews can also be dropped, meaning the changes are not meant to be merged in
their current change. To drop a currently accepted (but not closed) review,
you need to create an issue to "un-accept" it. It is suitable to explain
why the review will be dropped in that issue.
================================================
FILE: documentation/tutorials.txt
================================================
Critic Tutorials
================
Most of Critic's documentation is available as tutorials available in the
installed system, accessed via the "Tutorial" link at the top of every page.
This documentation can also be read without installing Critic first, in the
public Critic system used to review Critic itself:
https://critic-review.org/tutorial
They can also be found in source form in the tutorials/ directory. The source
is in custom text-based format similar to the Markdown markup language.
================================================
FILE: documentation/user_faq.md
================================================
Critic User FAQ
===============
### How can I create a code review for a subset of my topic branch? ###
Suppose that you've done 5 commits on a topic branch and that you
want to submit the first 3 to code review now and then continue work
on the topic branch. After you've pushed the branch to Critic you
find it under the 'Branches' menu item in the top level menu. Critic
will now show all the commits on your topic branch and there is a
button called 'Create Review', in the top right corner, that you
can use if you want to push the entire branch into code review.
If you want to push just a single commit into code review, you can
click that commit, and then click 'Create Review' on the subsequent
page.
However, at the branch page it's also possible to select a range of
commits to be pushed into review. This is done by selecting
the desired commits using the mouse (i.e. click the first commit, hold
down the mouse and release over the last commit in the range).
### When reviewing code, how can I select some snippet or function name etc from the code and copy it to the clipboard? (i.e. it's not possible to select text because clicking to select triggers the 'New Issue' dialog) ###
Hold down the CTRL button while selecting.
### Can Critic provide some statistics for how much is submitted/reviewed by whom etc? ###
Yes, there is a basic statistics page available at <code>http://your.critic.domain.tld/statistics</code>
### How can I see a list of users that have registered as reviewers/watchers for a particular directory? ###
Navigate to: <code>http://your.critic.domain.tld/showfilters?repository=INSERT_REPO_NAME&path=INSERT_PATH</code>
See for example: https://critic-review.org/showfilters?repository=critic&path=/
================================================
FILE: extend.py
================================================
# -*- mode: python; encoding: utf-8 -*-
#
# Copyright 2012 Jens Lindström, Opera Software ASA
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
import os
import sys
# To avoid accidentally creating files owned by root.
sys.dont_write_bytecode = True
# Python version check is done before imports below so that python
# 2.6/2.5 users can see the error message.
import pythonversion
pythonversion.check()
import argparse
import subprocess
import multiprocessing
import tempfile
import pwd
from distutils.version import LooseVersion
import installation
parser = argparse.ArgumentParser(description="Critic extension support installation script",
epilog="""\
Critic extension support is activated by simply running (as root):
# python extend.py
For finer control over the script's operation you can invoke it with one
or more of the action arguments:
--prereqs, --fetch, --build, --install and --enable
This can for instance be used to build the v8-jsshell executable on a
system where Critic has not been installed.""",
formatter_class=argparse.RawDescriptionHelpFormatter)
# Uses default values for everything that has a default value (and isn't
# overridden by other command-line arguments) and signals an error for anything
# that doesn't have a default value and isn't set by a command-line argument.
parser.add_argument("--headless", help=argparse.SUPPRESS, action="store_true")
class DefaultBinDir:
pass
v8_url = "git://github.com/v8/v8.git"
depot_tools_url = "https://chromium.googlesource.com/chromium/tools/depot_tools.git"
basic = parser.add_argument_group("basic options")
basic.add_argument("--etc-dir", help="directory where the Critic system configuration is stored [default=/etc/critic]", action="store", default="/etc/critic")
basic.add_argument("--identity", help="system identity to upgrade [default=main]", action="store", default="main")
basic.add_argument("--bin-dir", help="directory where the extension host executable is installed [default=/usr/lib/critic/$IDENTITY/bin]", action="store", default=DefaultBinDir)
basic.add_argument("--no-compiler-check", help="disable compiler version check", action="store_true")
basic.add_argument("--dry-run", "-n", help="produce output but don't modify the system at all", action="store_true")
basic.add_argument("--libcurl-flavor", help="libcurl flavor (openssl, gnutls or nss) or install", choices=["openssl", "gnutls", "nss"])
actions = parser.add_argument_group("actions")
actions.add_argument("--prereqs", help="(check for and) install prerequisite software", action="store_true")
actions.add_argument("--fetch", help="fetch the extension host source code", action="store_true")
actions.add_argument("--build", help="build the extension host executable", action="store_true")
actions.add_argument("--install", help="install the extension host executable", action="store_true")
actions.add_argument("--enable", help="enable extension support in Critic's configuration", action="store_true")
actions.add_argument("--with-v8-jsshell", help="v8-jsshell repository URL [default=../v8-jsshell.git]", metavar="URL")
actions.add_argument("--with-v8", help="v8 repository URL [default=%s]" % v8_url, metavar="URL")
actions.add_argument("--with-depot_tools", help="depot_tools repository URL [default=%s]" % depot_tools_url, metavar="URL")
# Useful to speed up repeated building from clean repositories; used
# by the testing framework.
actions.add_argument("--export-v8-dependencies", help=argparse.SUPPRESS)
actions.add_argument("--import-v8-dependencies", help=argparse.SUPPRESS)
arguments = parser.parse_args()
if arguments.headless:
installation.input.headless = True
import installation
is_root = os.getuid() == 0
prereqs = arguments.prereqs
fetch = arguments.fetch
build = arguments.build
install = arguments.install
enable = arguments.enable
if not any([prereqs, fetch, build, install, enable]) \
and arguments.export_v8_dependencies is None \
and arguments.import_v8_dependencies is None:
prereqs = fetch = build = install = enable = True
libcurl = False
if any([prereqs, install, enable]) and not is_root:
print """
ERROR: You need to run this script as root.
"""
sys.exit(1)
git = os.environ.get("GIT", "git")
if install or enable:
data = installation.utils.read_install_data(arguments)
if data is not None:
git = data["installation.prereqs.git"]
installed_sha1 = data["sha1"]
current_sha1 = installation.utils.run_git([git, "rev-parse", "HEAD"],
cwd=installation.root_dir).strip()
if installed_sha1 != current_sha1:
print """
ERROR: You should to run upgrade.py to upgrade to the current commit before
using this script to enable extension support.
"""
sys.exit(1)
if arguments.bin_dir is DefaultBinDir:
bin_dir = os.path.join("/usr/lib/critic", arguments.identity, "bin")
else:
bin_dir = arguments.bin_dir
if "CXX" in os.environ:
compiler = os.environ["CXX"]
try:
subprocess.check_output([compiler, "--help"])
except OSError as error:
print """
ERROR: %r (from $CXX) does not appear to be a valid compiler.
""" % compiler
sys.exit(1)
else:
compiler = "g++"
def check_libcurl():
fd, empty_cc = tempfile.mkstemp(".cc")
os.close(fd)
try:
subprocess.check_output([compiler, "-include", "curl/curl.h", "-c", empty_cc, "-o", "/dev/null"],
stderr=subprocess.STDOUT)
return True
except subprocess.CalledProcessError as error:
if "curl/curl.h" in error.output:
return False
raise
finally:
os.unlink(empty_cc)
def missing_packages():
packages = []
if not installation.prereqs.find_executable("svn"):
packages.append("subversion")
if not installation.prereqs.find_executable("make"):
packages.append("make")
if "CXX" not in os.environ and not installation.prereqs.find_executable("g++"):
packages.append("g++")
pg_config = installation.prereqs.find_executable("pg_config")
if pg_config:
try:
subprocess.check_output(["pg_config"], stderr=subprocess.STDOUT)
except subprocess.CalledProcessError:
# Just installing the PostgreSQL database server might install
# a dummy pg_config that just outputs an error message.
pg_config = None
if not pg_config:
packages.append("libpq-dev")
return packages
if prereqs:
packages = missing_packages()
if packages:
installation.prereqs.install_packages(*packages)
if not check_libcurl():
if arguments.libcurl_flavor:
installation.prereqs.install_packages(
"libcurl4-%s-dev" % arguments.libcurl_flavor)
else:
print """
No version of libcurl-dev appears to be installed. There are usually multiple
versions available to install using different libraries (openssl, gnutls or nss)
for secure communication. If curl is already installed, you probably need to
install a matching version of libcurl-dev.
This script can install any one of them, or build the extension host executable
without URL loading support ("none").
Available choices are: "openssl", "gnutls", "nss"
Also: "none", "abort"
"""
def check(string):
if string not in ("openssl", "gnutls", "nss", "none", "abort"):
return 'please answer "openssl", "gnutls", "nss", "none" or "abort"'
choice = installation.input.string("Install libcurl-dev version?", "none")
if choice in ("openssl", "gnutls", "nss"):
installation.prereqs.install_packages("libcurl4-%s-dev" % choice)
elif choice == "abort":
print """
ERROR: Installation aborted.
"""
sys.exit(1)
env = os.environ.copy()
if build and not arguments.no_compiler_check:
version = subprocess.check_output([compiler, "--version"])
if version.startswith("g++"):
version = subprocess.check_output([compiler, "-dumpversion"]).strip()
if LooseVersion(version) < LooseVersion("4.7"):
print """
ERROR: GCC version 4.7 or later required to build v8-jsshell.
HINT: Set $CXX to use a different compiler than '%s', or use
--no-compiler-check to try to build anyway.
""" % compiler
sys.exit(1)
else:
if "clang" in version:
note_clang = "NOTE: CLang (version 3.2 and earlier) is known not to work.\n"
else:
note_clang = ""
print """
ERROR: GCC (version 4.7 or later) required to build v8-jsshell.
%sHINT: Set $CXX to use a different compiler than '%s', or use
--no-compiler-check to try to build anyway.
""" % (note_clang, compiler)
sys.exit(1)
env["compiler"] = compiler
env["v8static"] = "yes"
env["postgresql"] = "yes"
if check_libcurl():
env["libcurl"] = "yes"
env["PATH"] = (os.path.join(os.getcwd(), "installation/externals/depot_tools") +
":" + os.environ["PATH"])
root = os.path.dirname(os.path.abspath(sys.argv[0]))
v8_jsshell = os.path.join(root, "installation/externals/v8-jsshell")
def do_unprivileged_work():
global depot_tools_url
if is_root:
stat = os.stat(sys.argv[0])
os.environ["USER"] = pwd.getpwuid(stat.st_uid).pw_name
os.environ["HOME"] = pwd.getpwuid(stat.st_uid).pw_dir
os.setgid(stat.st_gid)
os.setuid(stat.st_uid)
if fetch:
if arguments.with_depot_tools:
depot_tools_url = arguments.with_depot_tools
if os.path.isdir('installation/externals/depot_tools'):
subprocess.check_call(
[git, "pull"],
cwd="installation/externals/depot_tools")
else:
subprocess.check_call(
[git, "clone", depot_tools_url],
cwd="installation/externals")
def fetch_submodule(cwd, submodule, url=None):
subprocess.check_call(
[git, "submodule", "init", submodule],
cwd=cwd)
if url:
subprocess.check_call(
[git, "config", "submodule.%s.url" % submodule, url],
cwd=cwd)
subprocess.check_call(
[git, "submodule", "update", submodule],
cwd=cwd)
fetch_submodule(root, "installation/externals/v8-jsshell",
arguments.with_v8_jsshell)
fetch_submodule(v8_jsshell, "v8", arguments.with_v8)
if arguments.import_v8_dependencies or arguments.export_v8_dependencies:
argv = ["make", "v8dependencies"]
if arguments.import_v8_dependencies:
argv.append("v8importdepsfrom=" + arguments.import_v8_dependencies)
if arguments.export_v8_dependencies:
argv.append("v8exportdepsto=" + arguments.export_v8_dependencies)
subprocess.check_call(argv, cwd=v8_jsshell)
if build:
subprocess.check_call(
["make", "-j%d" % multiprocessing.cpu_count()],
cwd=v8_jsshell, env=env)
def checked_unprivileged_work(result):
try:
do_unprivileged_work()
except:
result.put(False)
raise
else:
result.put(True)
if fetch or build \
or arguments.import_v8_dependencies \
or arguments.export_v8_dependencies:
if is_root:
unprivileged_result = multiprocessing.Queue()
unprivileged = multiprocessing.Process(target=checked_unprivileged_work,
args=(unprivileged_result,))
unprivileged.start()
unprivileged.join()
if not unprivileged_result.get():
sys.exit(1)
else:
do_unprivileged_work()
if install or enable:
etc_path = os.path.join(arguments.etc_dir, arguments.identity)
sys.path.insert(0, etc_path)
import configuration
executable = configuration.extensions.FLAVORS.get("js/v8", {}).get("executable")
if not executable or not os.access(executable, os.X_OK):
executable = os.path.join(bin_dir, "v8-jsshell")
if install:
if not os.path.isdir(os.path.dirname(executable)):
os.makedirs(os.path.dirname(executable))
subprocess.check_call(
["install", os.path.join(v8_jsshell, "out", "jsshell"), executable])
if enable and not configuration.extensions.ENABLED:
try:
subprocess.check_output(
["su", "-s", "/bin/bash",
"-c", "psql -q -c 'SELECT 1 FROM extensions LIMIT 1'",
configuration.base.SYSTEM_USER_NAME],
stderr=subprocess.STDOUT)
except subprocess.CalledProcessError:
installation.database.psql_import(
"installation/data/dbschema.extensions.sql",
configuration.base.SYSTEM_USER_NAME)
data = { "installation.system.username": configuration.base.SYSTEM_USER_NAME,
"installation.system.groupname": configuration.base.SYSTEM_GROUP_NAME,
"installation.extensions.enabled": True,
"installation.extensions.critic_v8_jsshell": executable,
"installation.extensions.default_flavor": "js/v8" }
installation.system.fetch_uid_gid()
installation.paths.mkdir(configuration.extensions.INSTALL_DIR)
installation.paths.mkdir(configuration.extensions.WORKCOPY_DIR)
compilation_failed = []
if installation.config.update_file(os.path.join(etc_path, "configuration"),
"extensions.py", data, arguments,
compilation_failed):
if compilation_failed:
print
print "ERROR: Update aborted."
print
installation.config.undo()
sys.exit(1)
subprocess.check_call(["criticctl", "restart"])
================================================
FILE: install.py
================================================
# -*- mode: python; encoding: utf-8 -*-
#
# Copyright 2012 Jens Lindström, Opera Software ASA
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
import os
import sys
import stat
# To avoid accidentally creating files owned by root.
sys.dont_write_bytecode = True
# Python version check is done before imports below so
# that python 2.6/2.5 users can see the error message.
import pythonversion
pythonversion.check("""\
NOTE: This script must be run in the Python interpreter that will be
used to run Critic.
""")
if sys.flags.optimize > 0:
print """
ERROR: Please run this script without -O or -OO options.
"""
sys.exit(1)
import argparse
import subprocess
import traceback
import installation
parser = argparse.ArgumentParser(description="Critic installation script")
# Uses default values for everything that has a default value (and isn't
# overridden by other command-line arguments) and signals an error for anything
# that doesn't have a default value and isn't set by a command-line argument.
parser.add_argument("--headless", help=argparse.SUPPRESS, action="store_true")
parser.add_argument("--etc-dir", help="directory where the Critic system configuration is stored", action="store")
parser.add_argument("--install-dir", help="directory where the Critic source code is installed", action="store")
parser.add_argument("--data-dir", help="directory where Critic's persistent data files are stored", action="store")
parser.add_argument("--cache-dir", help="directory where Critic's temporary data files are stored", action="store")
parser.add_argument("--git-dir", help="directory where the main Git repositories are stored", action="store")
parser.add_argument("--log-dir", help="directory where Critic's log files are stored", action="store")
parser.add_argument("--run-dir", help="directory where Critic's runtime files are stored", action="store")
for module in installation.modules:
if hasattr(module, "add_arguments"):
module.add_arguments("install", parser)
arguments = parser.parse_args()
if os.getuid() != 0:
print """
ERROR: This script must be run as root.
"""
sys.exit(1)
if os.path.exists(os.path.join(installation.root_dir, ".installed")):
print """
ERROR: Found an .installed file in the directory you're installing from.
This typically means that Critic is already installed on this system, and if so
then the upgrade.py script should be used to upgrade the installation rather than
re-running install.py.
"""
sys.exit(1)
if arguments.headless:
installation.input.headless = True
def abort():
print
print "ERROR: Installation aborted."
print
for module in reversed(installation.modules):
try:
if hasattr(module, "undo"):
module.undo()
except:
print >>sys.stderr, "FAILED: %s.undo()" % module.__name__
traceback.print_exc()
sys.exit(1)
try:
lifecycle = installation.utils.read_lifecycle()
if not lifecycle["stable"]:
print """
WARNING: You're about to install an unstable development version of Critic.
If you're setting up a production server, you're most likely better off
installing from the latest stable branch.
The latest stable branch is the default branch (i.e. HEAD) in Critic's GitHub
repository at
https://github.com/jensl/critic.git
To interrogate it from the command-line, run
$ git ls-remote --symref https://github.com/jensl/critic.git HEAD
"""
if not installation.input.yes_or_no(
"Do you want to continue installing the unstable version?",
default=True):
print
print "Installation aborted."
print
sys.exit(1)
sha1 = "0" * 40
# If Git is already installed, check for local modifications. If Git isn't
# installed (no 'git' executable in $PATH) then presumably we're not
# installing from a repository clone, but from an exported tree, and in that
# case we can't check for local modifications anyway.
if installation.prereqs.git.check():
git = installation.prereqs.git.path
try:
if installation.utils.run_git([git, "status", "--porcelain"],
cwd=installation.root_dir).strip():
print """
ERROR: This Git repository has local modifications.
Installing from a Git repository with local changes is not supported.
Please commit or stash the changes and then try again.
"""
sys.exit(1)
sha1 = installation.utils.run_git([git, "rev-parse", "HEAD"],
cwd=installation.root_dir).strip()
except subprocess.CalledProcessError:
# Probably not a Git repository at all.
pass
data = { "sha1": sha1 }
for module in installation.modules:
try:
if hasattr(module, "prepare") and not module.prepare("install", arguments, data):
abort()
except KeyboardInterrupt:
abort()
except SystemExit:
raise
except:
print >>sys.stderr, "FAILED: %s.prepare()" % module.__name__
traceback.print_exc()
abort()
print
installed_file = os.path.join(installation.root_dir, ".installed")
with open(installed_file, "w"):
pass
install_py_stat = os.stat(os.path.join(installation.root_dir, "install.py"))
os.chown(installed_file, install_py_stat.st_uid, install_py_stat.st_gid)
for module in installation.modules:
try:
if hasattr(module, "install") and not module.install(data):
abort()
except KeyboardInterrupt:
abort()
except SystemExit:
raise
except:
print >>sys.stderr, "FAILED: %s.install()" % module.__name__
traceback.print_exc()
abort()
for module in installation.modules:
try:
if hasattr(module, "finish"):
module.finish("install", arguments, data)
except:
print >>sys.stderr, "WARNING: %s.finish() failed" % module.__name__
traceback.print_exc()
installation.utils.write_install_data(arguments, data)
installation.utils.clean_root_pyc_files()
print
print "SUCCESS: Installation complete!"
print
except SystemExit:
raise
except:
traceback.print_exc()
abort()
================================================
FILE: installation/__init__.py
================================================
# -*- mode: python; encoding: utf-8 -*-
#
# Copyright 2012 Jens Lindström, Opera Software ASA
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
__doc__ = "Installation utilities."
import os
import sys
quiet = False
is_quick_start = False
root_dir = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
sys.path.insert(0, os.path.join(root_dir, "src"))
# Helpers.
import input
import process
import utils
# Modules.
import prereqs
import system
import paths
import files
import database
import smtp
import config
import httpd
import criticctl
import admin
import initd
import prefs
import git
import migrate
import extensions
modules = [prereqs,
system,
paths,
files,
database,
extensions,
config,
httpd,
criticctl,
admin,
smtp,
initd,
git,
migrate,
prefs]
================================================
FILE: installation/admin.py
================================================
# -*- mode: python; encoding: utf-8 -*-
#
# Copyright 2012 Jens Lindström, Opera Software ASA
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
import subprocess
import installation
username = None
email = None
fullname = None
password = None
system_recipients = None
def add_arguments(mode, parser):
if mode != "install":
return
parser.add_argument("--admin-username", action="store",
help="name of Critic administrator user")
parser.add_argument("--admin-email", action="store",
help="email address to Critic administrator user")
parser.add_argument("--admin-fullname", action="store",
help="Critic administrator user's full name")
parser.add_argument("--admin-password", action="store",
help="Critic administrator user's password")
def prepare(mode, arguments, data):
global username, email, fullname, password
if mode == "install":
print """
Critic Installation: Administrator
==================================
An administrator user is a Critic user with some special privileges;
they can do various things using the Web interface that other users
are not allowed to do. Additional administrator users can be added
post-installation using the 'criticctl' utility.
This user does not need to match a system user on this machine.
"""
if arguments.admin_username: username = arguments.admin_username
else: username = installation.input.string(prompt="Administrator user name:")
if arguments.admin_email: email = arguments.admin_email
else: email = installation.input.string(prompt="Administrator email address:")
if arguments.admin_fullname: fullname = arguments.admin_fullname
else: fullname = installation.input.string(prompt="Administrator full name:")
if installation.config.auth_mode == "critic":
if arguments.admin_password: password = arguments.admin_password
else: password = installation.input.password("Password for '%s':" % username)
print """
Critic Installation: System Messages
====================================
Critic sends out email notifications when unexpected errors (crashes)
occur, and in various other cases when things happen that the system
administrators might need to know about right away.
"""
if arguments.system_recipients:
system_recipients = arguments.system_recipients
else:
system_recipient = installation.input.string(
prompt="Where should system messages be sent?",
default="%s <%s>" % (fullname, email))
system_recipients = [system_recipient]
data["installation.admin.email"] = email
else:
import configuration
try:
system_recipients = configuration.base.SYSTEM_RECIPIENTS
except AttributeError:
system_recipients = ["%(fullname)s <%(email)s>" % admin
for admin in configuration.base.ADMINISTRATORS]
# The --system-recipients argument, on upgrade, is mostly intended to be
# used by the testing framework. It is checked after the code above has
# run for testing purpose; making sure the code above ever runs while
# testing is meaningful.
if arguments.system_recipients:
system_recipients = arguments.system_recipients
data["installation.system.recipients"] = system_recipients
return True
def install(data):
global password
try:
criticctl_argv = [installation.criticctl.criticctl_path, "adduser",
"--name", username,
"--email", email,
"--fullname", fullname]
if not password:
criticctl_argv.extend(["--no-password"])
else:
criticctl_argv.extend(["--password", password])
subprocess.check_output(criticctl_argv)
for role in ["administrator", "repositories", "newswriter"]:
subprocess.check_output(
[installation.criticctl.criticctl_path, "addrole",
"--name", username,
"--role", role])
except subprocess.CalledProcessError:
return False
return True
================================================
FILE: installation/config.py
================================================
# -*- mode: python; encoding: utf-8 -*-
#
# Copyright 2012 Jens Lindström, Opera Software ASA
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
import sys
import os
import os.path
import py_compile
import argparse
import multiprocessing
import installation
auth_mode = "host"
session_type = None
allow_anonymous_user = None
web_server_integration = None
access_scheme = None
repository_url_types = ["http"]
allow_user_registration = None
verify_email_addresses = True
archive_review_branches = True
password_hash_schemes = ["pbkdf2_sha256", "bcrypt"]
default_password_hash_scheme = "pbkdf2_sha256"
minimum_password_hash_time = 0.25
minimum_rounds = {}
auth_database = "internal"
enable_access_tokens = True
ldap_url = "ldap://ldap.example.com:389"
ldap_search_base = "dc=example,dc=com"
ldap_create_user = True
ldap_username_attribute = "uid"
ldap_fullname_attribute = "cn"
ldap_email_attribute = "mail"
ldap_cache_max_age = 600
is_development = False
is_testing = False
coverage_dir = None
class Provider(object):
def __init__(self, name):
self.name = name
self.enabled = False
self.allow_user_registration = False
self.verify_email_addresses = False
self.client_id = None
self.client_secret = None
self.redirect_uri = None
self.bypass_createuser = False
def load(self, settings):
if self.name not in settings:
return
settings = settings[self.name]
self.enabled = settings.get("enabled", self.enabled)
self.allow_user_registration = settings.get("allow_user_registration",
self.allow_user_registration)
self.verify_email_addresses = settings.get("verify_email_addresses",
self.verify_email_addresses)
self.client_id = settings.get("client_id", self.client_id)
self.client_secret = settings.get("client_secret", self.client_secret)
self.redirect_uri = settings.get("redirect_uri", self.redirect_uri)
self.bypass_createuser = settings.get("bypass_createuser",
self.bypass_createuser)
def readargs(self, arguments):
def getarg(name, default):
value = getattr(arguments, name, None)
if value is None:
return default
return value
self.enabled = getarg(
"provider_%s_enabled" % self.name, self.enabled)
self.allow_user_registration = getarg(
"provider_%s_user_registration" % self.name,
self.allow_user_registration)
self.verify_email_addresses = getarg(
"provider_%s_verify_email_addresses" % self.name,
self.verify_email_addresses)
self.client_id = getarg(
"provider_%s_client_id" % self.name, self.client_id)
self.client_secret = getarg(
"provider_%s_client_secret" % self.name, self.client_secret)
self.redirect_uri = getarg(
"provider_%s_redirect_uri" % self.name, self.redirect_uri)
def store(self, data):
base = "installation.config.provider_%s." % self.name
data[base + "enabled"] = self.enabled
data[base + "allow_user_registration"] = self.allow_user_registration
data[base + "verify_email_addresses"] = self.verify_email_addresses
data[base + "client_id"] = self.client_id
data[base + "client_secret"] = self.client_secret
data[base + "redirect_uri"] = self.redirect_uri
data[base + "bypass_createuser"] = self.bypass_createuser
def scrub(self, data):
base = "installation.config.provider_%s." % self.name
del data[base + "client_id"]
del data[base + "client_secret"]
providers = []
default_provider_names = ["github", "google"]
def calibrate_minimum_rounds():
import time
import passlib.context
min_rounds_name = "%s__min_rounds" % default_password_hash_scheme
min_rounds_value = 100
while True:
calibration_context = passlib.context.CryptContext(
schemes=[default_password_hash_scheme],
default=default_password_hash_scheme,
**{ min_rounds_name: min_rounds_value })
before = time.time()
calibration_context.encrypt("password")
# It's possible encryption was fast enough to measure as zero, or some
# other ridiculously small number. "Round" it up to at least one
# millisecond for sanity.
hash_time = max(0.001, time.time() - before)
if hash_time >= minimum_password_hash_time:
break
# Multiplication factor. Make it at least 1.2, to ensure we actually
# ever finish this loop, and at most 10, to ensure we don't over-shoot
# by too much.
factor = max(1.2, min(10.0, minimum_password_hash_time / hash_time))
min_rounds_value = int(factor * min_rounds_value)
# If we're upgrading and have a current calibrated value, only change it if
# the new value is significantly higher, indicating that the system's
# performance has increased, or the hash implementation has gotten faster.
if default_password_hash_scheme in minimum_rounds:
current_value = minimum_rounds[default_password_hash_scheme]
if current_value * 1.5 > min_rounds_value:
return
minimum_rounds[default_password_hash_scheme] = min_rounds_value
def add_arguments(mode, parser):
def H(help_string):
# Wrapper to hide arguments when upgrading, but still supporting them.
# Primarily we need to support arguments on upgrade for testing, which
# might upgrade from a commit that doesn't support an argument, and thus
# needs to provide the argument when upgrading to the tested commit.
if mode == "install":
return help_string
else:
return argparse.SUPPRESS
parser.add_argument(
"--auth-mode", choices=["host", "critic"],
help=H("user authentication mode"))
parser.add_argument(
"--session-type", choices=["httpauth", "cookie"],
help=H("session type"))
parser.add_argument(
"--allow-anonymous-user", dest="anonymous", action="store_const",
const=True, help=H("allow limited unauthenticated access"))
parser.add_argument(
"--no-allow-anonymous-user", dest="anonymous", action="store_const",
const=False, help=H("do not allow unauthenticated access"))
parser.add_argument(
"--allow-user-registration", dest="user_registration",
action="store_const", const=True,
help=H("allow unattended user registration"))
parser.add_argument(
"--no-allow-user-registration", dest="user_registration",
action="store_const", const=False,
help=H("do not allow unattended user registration"))
parser.add_argument(
"--web-server-integration", choices=["apache", "nginx+uwsgi",
"uwsgi", "none"],
help=H("web server to set up and integrate with"))
parser.add_argument(
"--access-scheme", choices=["http", "https", "both"],
help=H("scheme used to access Critic"))
parser.add_argument(
"--repository-url-types", default="http",
help=H("comma-separated list of supported repository URL types "
"(valid types: git, http, ssh and host)"))
for provider_name in default_provider_names:
if mode == "install":
group = parser.add_argument_group(
"'%s' authentication provider" % provider_name)
else:
group = parser
group.add_argument(
"--provider-%s-enabled" % provider_name, action="store_const",
const=True, help=H("enable authentication provider"))
group.add_argument(
"--provider-%s-disabled" % provider_name, action="store_const",
const=False, dest="provider_%s_enabled" % provider_name,
help=H("disable authentication provider"))
group.add_argument(
"--provider-%s-user-registration" % provider_name,
action="store_const", const=True,
help=H("enable new user registration"))
group.add_argument(
"--provider-%s-no-user-registration" % provider_name,
action="store_const", const=False,
dest="provider_%s_user_registration" % provider_name,
help=H("disable new user registration"))
group.add_argument(
"--provider-%s-client-id" % provider_name, action="store",
help=H("OAuth2 client id"))
group.add_argument(
"--provider-%s-client-secret" % provider_name, action="store",
help=H("OAuth2 client secret"))
group.add_argument(
"--provider-%s-redirect-uri" % provider_name, action="store",
help=H("OAuth2 authentication callback URI"))
parser.add_argument(
"--minimum-password-hash-time",
help=H("approximate minimum time to spend hashing a single password"))
# Using argparse.SUPPRESS to not include these in --help output; they are
# not something a typical installer ought to want to use.
parser.add_argument(
"--is-development", action="store_true", help=argparse.SUPPRESS)
parser.add_argument(
"--is-testing", action="store_true", help=argparse.SUPPRESS)
parser.add_argument(
"--coverage-dir", help=argparse.SUPPRESS)
default_encodings = ["utf-8", "latin-1"]
def prepare(mode, arguments, data):
global auth_mode, session_type, allow_anonymous_user
global web_server_integration, access_scheme
global repository_url_types, default_encodings, allow_user_registration
global verify_email_addresses, archive_review_branches
global password_hash_schemes, default_password_hash_scheme
global minimum_password_hash_time, minimum_rounds, auth_database
global enable_access_tokens
global is_development, is_testing, coverage_dir
global ldap_url, ldap_search_base, ldap_create_user, ldap_username_attribute
global ldap_fullname_attribute, ldap_email_attribute, ldap_cache_max_age
header_printed = False
if mode == "install":
if arguments.minimum_password_hash_time is not None:
try:
minimum_password_hash_time = float(arguments.minimum_password_hash_time)
except ValueError:
print ("Invalid --minimum-password-hash-time argument: %s (must be a number)."
% arguments.minimum_password_hash_time)
return False
if arguments.repository_url_types:
repository_url_types = filter(
None, arguments.repository_url_types.split(","))
invalid_url_types = []
for url_type in repository_url_types:
if url_type not in ["git", "http", "ssh", "host"]:
invalid_url_types.append(url_type)
if invalid_url_types or not repository_url_types:
print ("Invalid --repository-url-types argument: %s"
% arguments.repository_url_types)
if invalid_url_types:
print ("These types are invalid: %s"
% ",".join(invalid_url_types))
if not repository_url_types:
print "No URL types specified!"
return False
def check_auth_mode(value):
if value.strip() not in ("host", "critic"):
return "must be one of 'host' and 'critic'"
if arguments.auth_mode:
error = check_auth_mode(arguments.auth_mode)
if error:
print "Invalid --auth-mode argument: %s." % arguments.auth_mode
return False
auth_mode = arguments.auth_mode
else:
header_printed = True
print """
Critic Installation: Authentication
===================================
Critic needs to identify (via HTTP authentication) users who access
the Web front-end. This can be handled in two different ways:
host The Web server (Apache) handles authentication and Critic
only makes use of the user name that it reports via the
WSGI API.
critic Critic implements HTTP authentication itself using passwords
stored (encrypted) in its database.
"""
auth_mode = installation.input.string(
"Which authentication mode should be used?",
default="critic", check=check_auth_mode)
is_development = arguments.is_development
is_testing = arguments.is_testing
coverage_dir = arguments.coverage_dir
else:
import configuration
auth_mode = configuration.base.AUTHENTICATION_MODE
try: session_type = configuration.base.SESSION_TYPE
except AttributeError: pass
try: allow_anonymous_user = configuration.base.ALLOW_ANONYMOUS_USER
except AttributeError: pass
try: web_server_integration = configuration.base.WEB_SERVER_INTEGRATION
except AttributeError: web_server_integration = "apache"
try: access_scheme = configuration.base.ACCESS_SCHEME
except AttributeError: pass
try: repository_url_types = configuration.base.REPOSITORY_URL_TYPES
except AttributeError: pass
try: default_encodings = configuration.base.DEFAULT_ENCODINGS
except AttributeError: pass
try:
password_hash_schemes = configuration.auth.PASSWORD_HASH_SCHEMES
default_password_hash_scheme = configuration.auth.DEFAULT_PASSWORD_HASH_SCHEME
minimum_password_hash_time = configuration.auth.MINIMUM_PASSWORD_HASH_TIME
minimum_rounds = configuration.auth.MINIMUM_ROUNDS
except AttributeError:
pass
try:
auth_database = configuration.auth.DATABASE
except AttributeError:
pass
try:
enable_access_tokens = configuration.auth.ENABLE_ACCESS_TOKENS
except AttributeError:
pass
try: is_development = configuration.debug.IS_DEVELOPMENT
except AttributeError:
# Was moved from configuration.base to configuration.debug.
try: is_development = configuration.base.IS_DEVELOPMENT
except AttributeError: pass
try: is_testing = configuration.debug.IS_TESTING
except AttributeError: is_testing = arguments.is_testing
try: coverage_dir = configuration.debug.COVERAGE_DIR
except AttributeError: pass
try: allow_user_registration = configuration.base.ALLOW_USER_REGISTRATION
except AttributeError: pass
try: verify_email_addresses = configuration.base.VERIFY_EMAIL_ADDRESSES
except AttributeError: pass
try: archive_review_branches = configuration.base.ARCHIVE_REVIEW_BRANCHES
except AttributeError: pass
try:
ldap = configuration.auth.DATABASES["ldap"]
except (AttributeError, KeyError):
pass
else:
ldap_url = ldap.get("ldap_url", ldap_url)
ldap_search_base = ldap.get("ldap_search_base", ldap_search_base)
ldap_create_user = ldap.get("ldap_create_user", ldap_create_user)
ldap_username_attribute = ldap.get("ldap_username_attribute",
ldap_username_attribute)
ldap_fullname_attribute = ldap.get("ldap_fullname_attribute",
ldap_fullname_attribute)
ldap_email_attribute = ldap.get("ldap_email_attribute",
ldap_email_attribute)
ldap_cache_max_age = ldap.get("ldap_cache_max_age",
ldap_cache_max_age)
if auth_mode == "critic":
if session_type is None:
def check_session_type(value):
if value.strip() not in ("httpauth", "cookie"):
return "must be one of 'http' and 'cookie'"
if arguments.session_type:
error = check_session_type(arguments.session_type)
if error:
print "Invalid --session_type argument: %s." % arguments.session_type
return False
session_type = arguments.session_type
else:
if not header_printed:
header_printed = True
print """
Critic Installation: Authentication
==================================="""
print """
Critic can authenticate users either via HTTP authentication or via a
"Sign in" form and session cookies. The major difference is that HTTP
authentication requires a valid login to access any page whereas the
other type of authentication supports limited anonymous access.
httpauth Use HTTP authentication.
cookie Use session cookie based authentication.
"""
session_type = installation.input.string(
"Which session type should be used?",
default="cookie", check=check_session_type)
if allow_anonymous_user is None:
if session_type == "httpauth":
allow_anonymous_user = False
elif arguments.anonymous is not None:
allow_anonymous_user = arguments.anonymous
else:
if not header_printed:
header_printed = True
print """
Critic Installation: Authentication
==================================="""
print """
With cookie based authentication, Critic can support anonymous access.
Users still have to sign in in order to make any changes (such as
write comments in reviews) but will be able to view most information
in the system without signin in.
"""
allow_anonymous_user = installation.input.yes_or_no(
"Do you want to allow anonymous access?", default=True)
if allow_user_registration is None:
if session_type == "httpauth":
allow_user_registration = False
elif arguments.user_registration is not None:
allow_user_registration = arguments.user_registration
else:
if not header_printed:
header_printed = True
print """
Critic Installation: Authentication
==================================="""
print """
With cookie based authentication, Critic can support unattended user
registration. With this enabled, the "Sign in" page has a link to a
page where a new user can register a Critic user without needing to
contact the system administrator(s).
"""
allow_user_registration = installation.input.yes_or_no(
"Do you want to allow user registration?", default=False)
else:
session_type = "cookie"
if web_server_integration is None:
if arguments.web_server_integration:
web_server_integration = arguments.web_server_integration
else:
print """
Critic Installation: Web Server Integration
===========================================
This installation script can install and do basic configuration of a
few different host web servers. Supported web servers are:
1) nginx + uWSGI
Use the nginx web server together with uWSGI as the WSGI
application server to actually run Critic.
This is the recommended option for new installs.
2) uWSGI
Use uWSGI as both HTTP(S) front-end and as the WSGI application
server to actually run Critic.
3) Apache + mod_wsgi
Use the Apache web server and its third-party WSGI module
(mod_wsgi) to actually run Critic. This is the traditional
configuration used to run Critic, but mod_wsgi is not actively
maintained, and has some known issues.
4) no integration
Don't configure any web server. The installation performed by
this script will be incomplete and the system administrator will
need to set the integration up themselves.
"""
def check_web_server_integration(value):
if value not in ("1", "nginx+uwsgi",
"2", "uwsgi",
"3", "apache",
"4", "none"):
return ("must be one of '1'/'nginx+uwsgi', '2'/'uwsgi', "
"'3'/'apache' and '4'/'none'")
web_server_integration = installation.input.string(
"What web server should be set up?", default="nginx+uwsgi",
check=check_web_server_integration)
aliases = { "1": "nginx+uwsgi",
"2": "uwsgi",
"3": "apache",
"4": "none" }
if web_server_integration in aliases:
web_server_integration = aliases[web_server_integration]
if access_scheme is None:
if arguments.access_scheme:
access_scheme = arguments.access_scheme
else:
print """
Critic Installation: Scheme
===========================
Critic can be set up to be accessed over HTTP, HTTPS, or both. This
installation script will not do the actual configuration of the host
web server (Apache) necessary for it to support the desired schemes
(in particular HTTPS, which is non-trivial,) but can at least set up
Critic's Apache site declaration appropriately.
You have three choices:
http Critic will be accessible only over HTTP.
https Critic will be accessible only over HTTPS.
both Critic will be accessible over both HTTP and HTTPS.
If you choose "both", Critic will redirect all authenticated accesses
to HTTPS, to avoid sending credentials over plain text connections."""
if allow_anonymous_user:
print """\
Anonymous users will be allowed to access the site over HTTP, though.
If this is not desirable, you should select "https" and configure the
web server to redirect all HTTP accesses to HTTPS.
"""
else:
print
def check_access_scheme(value):
if value not in ("http", "https", "both"):
return "must be one of 'http', 'https' and 'both'"
access_scheme = installation.input.string(
"How will Critic be accessed?", default="http",
check=check_access_scheme)
if mode == "upgrade" \
and hasattr(configuration, "auth") \
and hasattr(configuration.auth, "PROVIDERS"):
for provider_name in configuration.auth.PROVIDERS:
provider = Provider(provider_name)
provider.load(configuration.auth.PROVIDERS)
providers.append(provider)
else:
providers.extend(Provider(provider_name)
for provider_name in default_provider_names)
if access_scheme == "http":
base_url = "http"
else:
base_url = "https"
base_url += "://%s/oauth/" % installation.system.hostname
for provider in providers:
provider.readargs(arguments)
if provider.redirect_uri is None:
provider.redirect_uri = base_url + provider.name
data["installation.config.auth_mode"] = auth_mode
data["installation.config.session_type"] = session_type
data["installation.config.allow_anonymous_user"] = allow_anonymous_user
data["installation.config.web_server_integration"] = web_server_integration
data["installation.config.access_scheme"] = access_scheme
data["installation.config.repository_url_types"] = repository_url_types
data["installation.config.default_encodings"] = default_encodings
data["installation.config.allow_user_registration"] = allow_user_registration
data["installation.config.verify_email_addresses"] = verify_email_addresses
data["installation.config.archive_review_branches"] = archive_review_branches
data["installation.config.password_hash_schemes"] = password_hash_schemes
data["installation.config.default_password_hash_scheme"] = default_password_hash_scheme
data["installation.config.minimum_password_hash_time"] = minimum_password_hash_time
data["installation.config.auth_database"] = auth_database
data["installation.config.enable_access_tokens"] = enable_access_tokens
data["installation.config.is_quickstart"] = False
data["installation.config.is_development"] = is_development
data["installation.config.is_testing"] = is_testing
data["installation.config.coverage_dir"] = coverage_dir
if mode == "upgrade":
data["installation.config.highlight.max_workers"] = \
configuration.services.HIGHLIGHT["max_workers"]
data["installation.config.changeset.max_workers"] = \
configuration.services.CHANGESET["max_workers"]
else:
cpu_count = multiprocessing.cpu_count()
data["installation.config.highlight.max_workers"] = cpu_count
data["installation.config.changeset.max_workers"] = max(1, cpu_count / 2)
for provider in providers:
provider.store(data)
data["installation.config.ldap_url"] = ldap_url
data["installation.config.ldap_search_base"] = ldap_search_base
data["installation.config.ldap_create_user"] = ldap_create_user
data["installation.config.ldap_username_attribute"] = ldap_username_attribute
data["installation.config.ldap_fullname_attribute"] = ldap_fullname_attribute
data["installation.config.ldap_email_attribute"] = ldap_email_attribute
data["installation.config.ldap_cache_max_age"] = ldap_cache_max_age
return True
created_file = []
created_dir = []
renamed = []
modified_files = 0
def compile_file(filename):
global created_file
try:
path = os.path.join(installation.paths.etc_dir, "main", filename)
with installation.utils.as_critic_system_user():
py_compile.compile(path, doraise=True)
except py_compile.PyCompileError as error:
print """
ERROR: Failed to compile %s:\n%s
""" % (filename, error)
return False
else:
created_file.append(path + "c")
return True
def set_file_mode_and_owner(path):
uid = installation.system.uid
gid = installation.system.gid
filename = os.path.basename(path)
if filename in ("database.py", "auth.py", "smtp-credentials.json"):
# May contain sensitive information.
mode = 0600
if filename == "smtp-credentials.json":
uid = gid = 0
else:
mode = 0640
os.chmod(path, mode)
if not installation.is_quick_start:
os.chown(path, uid, gid)
def copy_file_mode_and_owner(src_path, dst_path):
status = os.stat(src_path)
os.chmod(dst_path, status.st_mode)
os.chown(dst_path, status.st_uid, status.st_gid)
def install(data):
if auth_mode == "critic":
calibrate_minimum_rounds()
data["installation.config.minimum_rounds"] = minimum_rounds
source_dir = os.path.join(installation.root_dir, "installation", "templates", "configuration")
target_dir = os.path.join(installation.paths.etc_dir, "main", "configuration")
compilation_failed = False
os.mkdir(target_dir, 0750)
created_dir.append(target_dir)
os.chown(target_dir, installation.system.uid, installation.system.gid)
for entry in os.listdir(source_dir):
source_path = os.path.join(source_dir, entry)
target_path = os.path.join(target_dir, entry)
with open(target_path, "w") as target:
created_file.append(target_path)
with open(source_path, "r") as source:
target.write((source.read().decode("utf-8") % data).encode("utf-8"))
set_file_mode_and_owner(target_path)
if entry.endswith(".py"):
path = os.path.join("configuration", entry)
if not compile_file(path):
compilation_failed = True
else:
copy_file_mode_and_owner(target_path, target_path + "c")
if compilation_failed:
return False
# Make the newly written 'configuration' module available to the rest of the
# installation script(s).
sys.path.insert(0, os.path.join(installation.paths.etc_dir, "main"))
return True
def update_file(target_dir, entry, data, arguments, compilation_failed):
global modified_files
import configuration
source_dir = os.path.join(installation.root_dir, "installation", "templates", "configuration")
compilation_failed = False
source_path = os.path.join(source_dir, entry)
target_path = os.path.join(target_dir, entry)
backup_path = os.path.join(target_dir, "_" + entry)
source = open(source_path, "r").read().decode("utf-8") % data
if not os.path.isfile(target_path):
write_target = True
else:
if open(target_path).read().decode("utf-8") == source:
return False
def generateVersion(label, path):
if label == "updated":
with open(path, "w") as target:
target.write(source.encode("utf-8"))
update_query = installation.utils.UpdateModifiedFile(
arguments,
message="""\
A configuration file is about to be updated. Please check that no
local modifications are being overwritten.
Current version: %(current)s
Updated version: %(updated)s
Please note that if any configuration options were added in the
updated version, the system will most likely break if you do not
either install the updated version or manually transfer the new
configuration options to the existing version.
""",
versions={ "current": target_path,
"updated": target_path + ".new" },
options=[ ("i", "install the updated version"),
("k", "keep the current version"),
("d", ("current", "updated")) ],
generateVersion=generateVersion)
write_target = update_query.prompt() == "i"
if write_target:
print "Updated file: %s" % target_path
if not arguments.dry_run:
if os.path.isfile(target_path):
os.rename(target_path, backup_path)
renamed.append((target_path, backup_path))
with open(target_path, "w") as target:
created_file.append(target_path)
target.write(source.encode("utf-8"))
set_file_mode_and_owner(target_path)
if target_path.endswith(".py"):
path = os.path.join("configuration", entry)
if not compile_file(path):
compilation_failed.append(path)
else:
copy_file_mode_and_owner(target_path, target_path + "c")
# The module's name (relative the 'configuration' package)
# is the base name minus the trailing ".py".
module_name = os.path.basename(target_path)[:-3]
if module_name != "__init__" \
and hasattr(configuration, module_name):
# Reload the updated module so that code executing later
# sees added configuration options. (It will also see
# removed configuration options, but that is unlikely to
# be a problem.)
reload(getattr(configuration, module_name))
modified_files += 1
return True
def upgrade(arguments, data):
global modified_files
import configuration
if auth_mode == "critic":
calibrate_minimum_rounds()
data["installation.config.minimum_rounds"] = minimum_rounds
source_dir = os.path.join(installation.root_dir, "installation", "templates", "configuration")
target_dir = os.path.join(data["installation.paths.etc_dir"], arguments.identity, "configuration")
compilation_failed = []
no_changes = True
for entry in os.listdir(source_dir):
if update_file(target_dir, entry, data, arguments, compilation_failed):
no_changes = False
if compilation_failed:
return False
if no_changes:
print "No changed configuration files."
if modified_files:
reload(configuration)
return True
def undo():
map(os.unlink, reversed(created_file))
map(os.rmdir, reversed(created_dir))
for target, backup in renamed: os.rename(backup, target)
def finish(mode, arguments, data):
for target, backup in renamed: os.unlink(backup)
for provider in providers:
provider.scrub(data)
================================================
FILE: installation/criticctl.py
================================================
# -*- mode: python; encoding: utf-8 -*-
#
# Copyright 2012 Jens Lindström, Opera Software ASA
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
import installation
import os
import os.path
criticctl_path = None
created_file = []
renamed = []
def install(data):
global criticctl_path
source_path = os.path.join(installation.root_dir, "installation", "templates", "criticctl")
target_path = criticctl_path = os.path.join(installation.paths.bin_dir, "criticctl")
with open(target_path, "w") as target:
created_file.append(target_path)
os.chmod(target_path, 0755)
with open(source_path, "r") as source:
target.write((source.read().decode("utf-8") % data).encode("utf-8"))
return True
def upgrade(arguments, data):
target_path = os.path.join(installation.paths.bin_dir, "criticctl")
backup_path = installation.utils.update_from_template(
arguments, data,
template_path="installation/templates/criticctl",
target_path=target_path,
message="""\
The criticctl utility is about to be updated. Please check that no local
modifications are being overwritten.
%(versions)s
Please note that if the modifications are not installed, the criticctl utility
is likely to stop working.
""")
if backup_path:
created_file.append(target_path)
renamed.append((target_path, backup_path))
return True
def undo():
map(os.unlink, created_file)
for target, backup in renamed:
os.rename(backup, target)
def finish(mode, arguments, data):
for target, backup in renamed:
os.unlink(backup)
================================================
FILE: installation/data/comments.pgsql
================================================
-- -*- mode: sql -*-
--
-- Copyright 2012 Jens Lindström, Opera Software ASA
--
-- Licensed under the Apache License, Version 2.0 (the "License"); you may not
-- use this file except in compliance with the License. You may obtain a copy of
-- the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- License for the specific language governing permissions and limitations under
-- the License.
CREATE OR REPLACE FUNCTION chaincomments(chain_id INTEGER) RETURNS INTEGER AS
$$
DECLARE
result INTEGER;
BEGIN
SELECT COUNT(*) INTO STRICT result FROM comments WHERE chain=chain_id AND state='current';
RETURN result;
END;
$$
LANGUAGE 'plpgsql';
CREATE OR REPLACE FUNCTION chainunread(chain_id INTEGER, user_id INTEGER) RETURNS INTEGER AS
$$
DECLARE
result INTEGER;
BEGIN
SELECT COUNT(*) INTO STRICT result FROM commentstoread JOIN comments ON (comments.id=commentstoread.comment) WHERE comments.chain=chain_id AND comments.state='current' AND commentstoread.uid=user_id;
RETURN result;
END;
$$
LANGUAGE 'plpgsql';
================================================
FILE: installation/data/dbschema.base.sql
================================================
-- -*- mode: sql -*-
--
-- Copyright 2015 the Critic contributors, Opera Software ASA
--
-- Licensed under the Apache License, Version 2.0 (the "License"); you may not
-- use this file except in compliance with the License. You may obtain a copy of
-- the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- License for the specific language governing permissions and limitations under
-- the License.
-- Disable notices about implicitly created indexes and sequences.
SET client_min_messages TO WARNING;
CREATE TABLE systemidentities
( key VARCHAR(32) PRIMARY KEY,
name VARCHAR(64) UNIQUE,
anonymous_scheme VARCHAR(5) NOT NULL,
authenticated_scheme VARCHAR(5) NOT NULL,
hostname VARCHAR(265) NOT NULL,
description VARCHAR(256) NOT NULL,
installed_sha1 CHAR(40) NOT NULL,
installed_at TIMESTAMP DEFAULT NOW() NOT NULL );
CREATE TABLE files
( id SERIAL PRIMARY KEY,
path TEXT NOT NULL );
-- Index used to enforce uniqueness, and for quick lookup of single
-- paths (using "SELECT id FROM files WHERE MD5(path)=MD5(...)".
CREATE UNIQUE INDEX files_path_md5 ON files (MD5(path));
-- Index used for path searches, for instance when searching for
-- reviews that touch files in a certain directory.
CREATE INDEX files_path_gin ON files USING gin (STRING_TO_ARRAY(path, '/'));
CREATE TABLE knownremotes
( url VARCHAR(256) PRIMARY KEY,
-- True if this remote has a post-update hook (or similar) that contacts the
-- branchtrackerhook service and triggers immediate updates of tracked
-- branches.
pushing BOOLEAN NOT NULL
);
CREATE TABLE timezones
( name VARCHAR(256) PRIMARY KEY,
abbrev VARCHAR(16) NOT NULL,
utc_offset INTERVAL NOT NULL );
INSERT INTO timezones (name, abbrev, utc_offset)
VALUES ('Universal/UTC', 'UTC', INTERVAL '0');
================================================
FILE: installation/data/dbschema.changesets.sql
================================================
-- -*- mode: sql -*-
--
-- Copyright 2015 the Critic contributors, Opera Software ASA
--
-- Licensed under the Apache License, Version 2.0 (the "License"); you may not
-- use this file except in compliance with the License. You may obtain a copy of
-- the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- License for the specific language governing permissions and limitations under
-- the License.
-- Disable notices about implicitly created indexes and sequences.
SET client_min_messages TO WARNING;
CREATE TYPE changesettype AS ENUM
( 'direct', -- Plain diff between immediate parent and child (including
-- cases where the child commit has other parents.)
'custom', -- Plain diff between any other two commits.
'merge', -- Relevance filtered merge diff between immediate parent and
-- child where child has other parents.
'conflicts'); -- Diff between two merge commits, one automatically generated
-- and one "real." The automatically generated merge commit
-- is created without resolving any conflicts (the conflict
-- markers inserted by "git merge" are committed as-is.)
CREATE TABLE changesets
( id SERIAL PRIMARY KEY,
parent INTEGER REFERENCES commits ON DELETE CASCADE,
child INTEGER NOT NULL REFERENCES commits ON DELETE CASCADE,
type changesettype NOT NULL,
UNIQUE (parent, child, type) );
CREATE INDEX changesets_child ON changesets (child);
CREATE TABLE customchangesets
( changeset INTEGER PRIMARY KEY REFERENCES changesets ON DELETE CASCADE,
time TIMESTAMP );
CREATE TABLE mergereplays
( original INTEGER PRIMARY KEY REFERENCES commits ON DELETE CASCADE,
replay INTEGER NOT NULL REFERENCES commits ON DELETE CASCADE );
CREATE TABLE fileversions
( changeset INTEGER NOT NULL REFERENCES changesets ON DELETE CASCADE,
file INTEGER NOT NULL REFERENCES files,
old_sha1 CHAR(40),
new_sha1 CHAR(40),
old_mode CHAR(6),
new_mode CHAR(6),
PRIMARY KEY (changeset, file) );
CREATE INDEX fileversions_old_sha1 ON fileversions (file, old_sha1);
CREATE INDEX fileversions_new_sha1 ON fileversions (file, new_sha1);
CREATE TABLE chunks
( id SERIAL PRIMARY KEY,
changeset INTEGER NOT NULL REFERENCES changesets ON DELETE CASCADE,
file INTEGER NOT NULL REFERENCES files,
deleteOffset INTEGER NOT NULL,
deleteCount INTEGER NOT NULL,
insertOffset INTEGER NOT NULL,
insertCount INTEGER NOT NULL,
analysis TEXT,
whitespace INTEGER NOT NULL );
CREATE INDEX chunks_changeset_file ON chunks (changeset, file);
CREATE TABLE codecontexts
( sha1 CHAR(40),
context VARCHAR(256) NOT NULL,
first_line INTEGER NOT NULL,
last_line INTEGER NOT NULL );
CREATE INDEX codecontexts_sha1_first_last ON codecontexts (sha1, first_line, last_line);
================================================
FILE: installation/data/dbschema.comments.sql
================================================
-- -*- mode: sql -*-
--
-- Copyright 2012 Jens Lindström, Opera Software ASA
--
-- Licensed under the Apache License, Version 2.0 (the "License"); you may not
-- use this file except in compliance with the License. You may obtain a copy of
-- the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- License for the specific language governing permissions and limitations under
-- the License.
-- Disable notices about implicitly created indexes and sequences.
SET client_min_messages TO WARNING;
CREATE TYPE commentchaintype AS ENUM
( 'issue', -- The comment chain, while open, blocks the review.
'note' -- The comment chain doesn't block the review.
);
CREATE TYPE commentchainstate AS ENUM
( 'draft', -- The comment chain (and all it's comments) are drafts.
'open', -- The comment chain is open.
'addressed',-- The commented code was changed by a later commit.
'closed', -- The comment chain is closed.
'empty' -- The comment chain has no comments.
);
CREATE TYPE commentchainorigin AS ENUM
( 'old', -- The user commented the old/left-hand side in a diff.
'new' -- The user commented the new/right-hand side in a diff.
);
CREATE TABLE commentchains
( id SERIAL PRIMARY KEY,
review INTEGER NOT NULL REFERENCES reviews,
batch INTEGER REFERENCES batches ON DELETE CASCADE,
uid INTEGER NOT NULL REFERENCES users,
time TIMESTAMP NOT NULL DEFAULT NOW(),
type commentchaintype NOT NULL DEFAULT 'issue',
state commentchainstate NOT NULL DEFAULT 'draft',
origin commentchainorigin,
file INTEGER REFERENCES files,
first_commit INTEGER REFERENCES commits,
last_commit INTEGER REFERENCES commits,
closed_by INTEGER REFERENCES users,
addressed_by INTEGER REFERENCES commits,
first_comment INTEGER ); -- Foreign key constraint "REFERENCES comments" set up later.
CREATE INDEX commentchains_review_file ON commentchains(review, file);
CREATE INDEX commentchains_review_type_state ON commentchains(review, type, state);
CREATE INDEX commentchains_batch ON commentchains(batch);
-- FIXME: This circular relation is unnecessary. Should have a separate table
-- for mapping batches to comments intead.
ALTER TABLE batches ADD CONSTRAINT batches_comment_fkey FOREIGN KEY (comment) REFERENCES commentchains ON DELETE CASCADE;
CREATE TYPE commentchainchangestate AS ENUM
( 'draft', -- This change hasn't been performed yet.
'performed', -- The change has been performed.
'rejected' -- The change was rejected; affected comment chain wasn't in
-- expected state.
);
CREATE TABLE commentchainchanges
( batch INTEGER REFERENCES batches ON DELETE CASCADE,
uid INTEGER NOT NULL REFERENCES users ON DELETE CASCADE,
chain INTEGER NOT NULL REFERENCES commentchains ON DELETE CASCADE,
time TIMESTAMP NOT NULL DEFAULT NOW(),
state commentchainchangestate NOT NULL DEFAULT 'draft',
from_type commentchaintype,
to_type commentchaintype,
from_state commentchainstate,
to_state commentchainstate,
from_last_commit INTEGER REFERENCES commits,
to_last_commit INTEGER REFERENCES commits,
from_addressed_by INTEGER REFERENCES commits,
to_addressed_by INTEGER REFERENCES commits );
CREATE INDEX commentchainchanges_batch ON commentchainchanges(batch);
CREATE INDEX commentchainchanges_chain ON commentchainchanges(chain);
CREATE TYPE commentchainlinesstate AS ENUM
( 'draft',
'current'
);
CREATE TABLE commentchainlines
( chain INTEGER NOT NULL REFERENCES commentchains ON DELETE CASCADE,
uid INTEGER REFERENCES users,
time TIMESTAMP NOT NULL DEFAULT NOW(),
state commentchainlinesstate NOT NULL DEFAULT 'draft',
sha1 CHAR(40) NOT NULL,
first_line INTEGER NOT NULL,
last_line INTEGER NOT NULL,
-- This UNIQUE constraint is a bit fishy; it means two different users
-- can't have a draft "reopening" of the commentchain at the same time,
-- which strictly speaking wouldn't necessarily be a problem.
UNIQUE (chain, sha1) );
CREATE INDEX commentchainlines_chain_sha1 ON commentchainlines(chain, sha1);
CREATE TABLE commentchainusers
( chain INTEGER NOT NULL REFERENCES commentchains ON DELETE CASCADE,
uid INTEGER NOT NULL REFERENCES users,
PRIMARY KEY (chain, uid) );
CREATE TYPE commentstate AS ENUM
( 'draft', -- The comment is a draft.
'current', -- The comment is currently displayed.
'edited', -- The comment was edited (that is, replaced by another
-- comment whose 'edit_of' field references this.)
'deleted' -- The comment was deleted and is not displayed.
);
CREATE TABLE comments
( id SERIAL PRIMARY KEY,
chain INTEGER NOT NULL REFERENCES commentchains ON DELETE CASCADE,
batch INTEGER REFERENCES batches ON DELETE CASCADE,
uid INTEGER NOT NULL REFERENCES users,
time TIMESTAMP NOT NULL DEFAULT NOW(),
state commentstate NOT NULL,
comment TEXT,
code TEXT );
CREATE INDEX comments_chain_uid_state ON comments (chain, uid, state);
CREATE INDEX comments_batch ON comments(batch);
CREATE INDEX comments_id_chain ON comments(id, chain);
-- FIXME: This is an unfortunate circular relation. It's here to optimize
-- accessing a group of comment chains and their first comment (i.e. accessing
-- comments but not their replies.) This matters (supposedly) when loading
-- review front-pages, but it's questionable whether this is really necessary.
ALTER TABLE commentchains ADD CONSTRAINT commentchains_first_comment_fkey FOREIGN KEY (first_comment) REFERENCES comments;
CREATE TABLE commentstoread
( uid INTEGER NOT NULL REFERENCES users ON DELETE CASCADE,
comment INTEGER NOT NULL REFERENCES comments ON DELETE CASCADE,
PRIMARY KEY (uid, comment) );
CREATE INDEX commentstoread_comment ON commentstoread(comment);
CREATE TABLE commentmessageids
( uid INTEGER NOT NULL REFERENCES users ON DELETE CASCADE,
comment INTEGER NOT NULL REFERENCES comments ON DELETE CASCADE,
messageid CHAR(24) NOT NULL,
PRIMARY KEY (uid, comment) );
CREATE INDEX commentmessageids_comment ON commentmessageids(comment);
================================================
FILE: installation/data/dbschema.extensions.sql
================================================
-- -*- mode: sql -*-
--
-- Copyright 2012 Jens Lindström, Opera Software ASA
--
-- Licensed under the Apache License, Version 2.0 (the "License"); you may not
-- use this file except in compliance with the License. You may obtain a copy of
-- the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- License for the specific language governing permissions and limitations under
-- the License.
-- Disable notices about implicitly created indexes and sequences.
SET client_min_messages TO WARNING;
CREATE TABLE extensions
( id SERIAL PRIMARY KEY,
author INTEGER REFERENCES users, -- NULL means system extension
name VARCHAR(64) NOT NULL,
UNIQUE (author, name) );
CREATE TABLE extensionversions
( id SERIAL PRIMARY KEY,
extension INTEGER NOT NULL REFERENCES extensions,
name VARCHAR(256) NOT NULL,
sha1 CHAR(40) NOT NULL,
UNIQUE (sha1) );
-- Installed extensions.
-- If uid=NULL, it is a "universal install" (affecting all users.)
-- If version=NULL, the "LIVE" version is installed.
CREATE TABLE extensioninstalls
( id SERIAL PRIMARY KEY,
uid INTEGER REFERENCES users,
extension INTEGER NOT NULL REFERENCES extensions,
version INTEGER REFERENCES extensionversions,
UNIQUE (uid, extension) );
CREATE TABLE extensionroles
( id SERIAL PRIMARY KEY,
version INTEGER NOT NULL REFERENCES extensionversions,
script VARCHAR(64) NOT NULL,
function VARCHAR(64) NOT NULL );
CREATE TABLE extensionpageroles
( role INTEGER NOT NULL REFERENCES extensionroles ON DELETE CASCADE,
path VARCHAR(64) NOT NULL );
CREATE VIEW extensionroles_page AS
SELECT version, path, script, function
FROM extensionroles
JOIN extensionpageroles ON (role=id);
CREATE TABLE extensioninjectroles
( role INTEGER NOT NULL REFERENCES extensionroles ON DELETE CASCADE,
path VARCHAR(64) NOT NULL );
CREATE VIEW extensionroles_inject AS
SELECT version, path, script, function
FROM extensionroles
JOIN extensioninjectroles ON (role=id);
CREATE TABLE extensionprocesscommitsroles
( role INTEGER NOT NULL REFERENCES extensionroles ON DELETE CASCADE );
CREATE TABLE extensionfilterhookroles
( role INTEGER NOT NULL REFERENCES extensionroles ON DELETE CASCADE,
name VARCHAR(64) NOT NULL,
title VARCHAR(64) NOT NULL,
role_description TEXT,
data_description TEXT );
CREATE TABLE extensionhookfilters
( id SERIAL PRIMARY KEY,
uid INTEGER NOT NULL REFERENCES users ON DELETE CASCADE,
extension INTEGER NOT NULL REFERENCES extensions ON DELETE CASCADE,
repository INTEGER NOT NULL REFERENCES repositories ON DELETE CASCADE,
name VARCHAR(64) NOT NULL,
path TEXT NOT NULL,
data TEXT );
CREATE INDEX extensionhookfilters_uid_extension
ON extensionhookfilters (uid, extension);
CREATE INDEX extensionhookfilters_repository
ON extensionhookfilters (repository);
CREATE TABLE extensionfilterhookevents
( id SERIAL PRIMARY KEY,
filter INTEGER NOT NULL REFERENCES extensionhookfilters ON DELETE CASCADE,
review INTEGER NOT NULL REFERENCES reviews ON DELETE CASCADE,
uid INTEGER NOT NULL REFERENCES users ON DELETE CASCADE,
data TEXT );
CREATE TABLE extensionfilterhookcommits
( event INTEGER NOT NULL REFERENCES extensionfilterhookevents ON DELETE CASCADE,
commit INTEGER NOT NULL REFERENCES commits );
CREATE INDEX extensionfilterhookcommits_event
ON extensionfilterhookcommits (event);
CREATE TABLE extensionfilterhookfiles
( event INTEGER NOT NULL REFERENCES extensionfilterhookevents ON DELETE CASCADE,
file INTEGER NOT NULL REFERENCES files );
CREATE INDEX extensionfilterhookfiles_event
ON extensionfilterhookfiles (event);
CREATE TABLE extensionstorage
( extension INTEGER NOT NULL REFERENCES extensions,
uid INTEGER NOT NULL REFERENCES users,
key VARCHAR(64) NOT NULL,
text TEXT NOT NULL,
PRIMARY KEY (extension, uid, key) );
CREATE TABLE extensionlog
( extension INTEGER NOT NULL REFERENCES extensions,
uid INTEGER NOT NULL REFERENCES users,
category VARCHAR(64) NOT NULL DEFAULT 'default',
time TIMESTAMP NOT NULL DEFAULT NOW(),
text TEXT NOT NULL );
CREATE INDEX extensionlog_extension_uid_category ON extensionlog(extension, uid, category);
CREATE TYPE extensionaccesstype AS ENUM
( 'install',
'execute' );
CREATE TABLE accesscontrol_extensions
( id SERIAL PRIMARY KEY,
-- The profile this exception belongs to.
profile INTEGER NOT NULL REFERENCES accesscontrolprofiles ON DELETE CASCADE,
-- Type of extension access. NULL means "any type".
access_type extensionaccesstype,
-- Extension key: <auther username>/<extension name> for user extensions and
-- <extension name> for system extensions. NULL means "any extension".
extension_key TEXT );
CREATE INDEX accesscontrol_extensions_profile
ON accesscontrol_extensions (profile);
================================================
FILE: installation/data/dbschema.filters.sql
================================================
-- -*- mode: sql -*-
--
-- Copyright 2015 the Critic contributors, Opera Software ASA
--
-- Licensed under the Apache License, Version 2.0 (the "License"); you may not
-- use this file except in compliance with the License. You may obtain a copy of
-- the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- License for the specific language governing permissions and limitations under
-- the License.
-- Disable notices about implicitly created indexes and sequences.
SET client_min_messages TO WARNING;
CREATE TYPE filtertype AS ENUM
( 'reviewer',
'watcher',
'ignored' );
CREATE TABLE filters
( id SERIAL PRIMARY KEY,
uid INTEGER NOT NULL REFERENCES users,
repository INTEGER NOT NULL REFERENCES repositories ON DELETE CASCADE,
path TEXT NOT NULL,
type filtertype NOT NULL,
delegate TEXT );
-- Index used to enforce uniqueness.
CREATE UNIQUE INDEX filters_uid_repository_path_md5 ON filters (uid, repository, MD5(path));
================================================
FILE: installation/data/dbschema.git.sql
================================================
-- -*- mode: sql -*-
--
-- Copyright 2015 the Critic contributors, Opera Software ASA
--
-- Licensed under the Apache License, Version 2.0 (the "License"); you may not
-- use this file except in compliance with the License. You may obtain a copy of
-- the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- License for the specific language governing permissions and limitations under
-- the License.
-- Disable notices about implicitly created indexes and sequences.
SET client_min_messages TO WARNING;
CREATE TABLE repositories
( id SERIAL PRIMARY KEY,
parent INTEGER REFERENCES repositories,
name VARCHAR(64) NOT NULL UNIQUE,
path VARCHAR(256) NOT NULL UNIQUE );
CREATE TABLE gitusers
( id SERIAL PRIMARY KEY,
email VARCHAR(256) NOT NULL,
fullname VARCHAR(256) NOT NULL,
UNIQUE (email, fullname) );
CREATE TABLE commits
( id SERIAL PRIMARY KEY,
sha1 CHAR(40) NOT NULL UNIQUE,
author_gituser INTEGER NOT NULL REFERENCES gitusers,
commit_gituser INTEGER NOT NULL REFERENCES gitusers,
author_time TIMESTAMP NOT NULL,
commit_time TIMESTAMP NOT NULL );
CREATE TABLE edges
( parent INTEGER NOT NULL REFERENCES commits ON DELETE CASCADE,
child INTEGER NOT NULL REFERENCES commits ON DELETE CASCADE );
CREATE INDEX edges_parent ON edges (parent);
CREATE INDEX edges_child ON edges (child);
CREATE TYPE branchtype AS ENUM
( 'normal',
'review' );
CREATE TABLE branches
( id SERIAL PRIMARY KEY,
name VARCHAR(256) NOT NULL,
repository INTEGER NOT NULL REFERENCES repositories ON DELETE CASCADE,
head INTEGER NOT NULL REFERENCES commits,
base INTEGER REFERENCES branches,
tail INTEGER REFERENCES commits,
type branchtype NOT NULL DEFAULT 'normal',
archived BOOLEAN NOT NULL DEFAULT FALSE,
UNIQUE (repository, name) );
CREATE TABLE reachable
( branch INTEGER NOT NULL REFERENCES branches ON DELETE CASCADE,
commit INTEGER NOT NULL REFERENCES commits,
PRIMARY KEY (branch, commit) );
CREATE INDEX reachable_branch ON reachable (branch);
CREATE INDEX reachable_commit ON reachable (commit);
CREATE TABLE tags
( id SERIAL PRIMARY KEY,
name VARCHAR(256) NOT NULL,
repository INTEGER NOT NULL REFERENCES repositories ON DELETE CASCADE,
sha1 CHAR(40) NOT NULL,
UNIQUE (repository, name) );
CREATE INDEX tags_repository_sha1 ON tags (repository, sha1);
-- Cached result of 'git merge-base <all parents>' for commits.
CREATE TABLE mergebases
( commit INTEGER PRIMARY KEY REFERENCES commits ON DELETE CASCADE,
mergebase CHAR(40) );
-- Cached per-file-and-parent "relevant" commits, for a merge commit.
--
-- Each row says that for the merge commit |commit|'s |parent|th parent and the
-- file |file|, |relevant| is a commit between the merge-base and the merge that
-- also modifies the file, and that isn't an ancestor of that parent.
CREATE TABLE relevantcommits
( commit INTEGER REFERENCES commits ON DELETE CASCADE,
parent SMALLINT NOT NULL,
file INTEGER REFERENCES files,
relevant INTEGER REFERENCES commits ON DELETE CASCADE,
PRIMARY KEY (commit, parent, file, relevant) );
CREATE TYPE repositoryaccesstype AS ENUM
( 'read',
'modify' );
CREATE TABLE accesscontrol_repositories
( id SERIAL PRIMARY KEY,
-- The profile this exception belongs to.
profile INTEGER NOT NULL REFERENCES accesscontrolprofiles ON DELETE CASCADE,
-- Type of access. NULL means "any type".
access_type repositoryaccesstype,
-- Repository to access. NULL means "any repository".
repository INTEGER REFERENCES repositories ON DELETE CASCADE );
CREATE INDEX accesscontrol_repositories_profile
ON accesscontrol_repositories (profile);
================================================
FILE: installation/data/dbschema.news.sql
================================================
-- -*- mode: sql -*-
--
-- Copyright 2015 the Critic contributors, Opera Software ASA
--
-- Licensed under the Apache License, Version 2.0 (the "License"); you may not
-- use this file except in compliance with the License. You may obtain a copy of
-- the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- License for the specific language governing permissions and limitations under
-- the License.
-- Disable notices about implicitly created indexes and sequences.
SET client_min_messages TO WARNING;
CREATE TABLE newsitems
( id SERIAL PRIMARY KEY,
date DATE DEFAULT NOW(),
text TEXT NOT NULL );
CREATE TABLE newsread
( item INTEGER NOT NULL REFERENCES newsitems ON DELETE CASCADE,
uid INTEGER NOT NULL REFERENCES users ON DELETE CASCADE );
================================================
FILE: installation/data/dbschema.preferences.sql
================================================
-- -*- mode: sql -*-
--
-- Copyright 2015 the Critic contributors, Opera Software ASA
--
-- Licensed under the Apache License, Version 2.0 (the "License"); you may not
-- use this file except in compliance with the License. You may obtain a copy of
-- the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- License for the specific language governing permissions and limitations under
-- the License.
-- Disable notices about implicitly created indexes and sequences.
SET client_min_messages TO WARNING;
CREATE TYPE preferencetype AS ENUM
( 'boolean',
'integer',
'string' );
CREATE TABLE preferences
( item VARCHAR(64) PRIMARY KEY,
type preferencetype NOT NULL,
description TEXT NOT NULL,
-- If TRUE, this preference is relevant to configure per system (IOW
-- globally), per user, per repository and/or per filter. This controls
-- whether the preference is displayed on the corresponding /config page
-- variant.
per_system BOOLEAN NOT NULL DEFAULT TRUE,
per_user BOOLEAN NOT NULL DEFAULT TRUE,
per_repository BOOLEAN NOT NULL DEFAULT FALSE,
per_filter BOOLEAN NOT NULL DEFAULT FALSE );
CREATE TABLE userpreferences
( item VARCHAR(64) NOT NULL REFERENCES preferences,
uid INTEGER REFERENCES users ON DELETE CASCADE,
repository INTEGER REFERENCES repositories ON DELETE CASCADE,
filter INTEGER REFERENCES filters ON DELETE CASCADE,
integer INTEGER,
string TEXT,
-- Invariant: If 'filter' is not NULL, then 'uid' must not be NULL.
CONSTRAINT check_uid_filter CHECK (filter IS NULL OR uid IS NOT NULL),
-- Invariant: At least one of 'repository' and 'filter' must be NULL.
CONSTRAINT check_repository_filter CHECK (repository IS NULL OR filter IS NULL) );
-- These indexes are primarily used to enforce uniqueness. The three columns
-- 'uid', 'repository' and 'filter' can all be NULL (in various configurations)
-- and from a uniqueness point of view, we want those NULL to behave as if they
-- compared equal.
CREATE UNIQUE INDEX userpreferences_item
ON userpreferences (item)
WHERE uid IS NULL
AND repository IS NULL
AND filter IS NULL;
CREATE UNIQUE INDEX userpreferences_item_uid
ON userpreferences (item, uid)
WHERE uid IS NOT NULL
AND repository IS NULL
AND filter IS NULL;
CREATE UNIQUE INDEX userpreferences_item_repository
ON userpreferences (item, repository)
WHERE uid IS NULL
AND repository IS NOT NULL
AND filter IS NULL;
CREATE UNIQUE INDEX userpreferences_item_uid_repository
ON userpreferences (item, uid, repository)
WHERE uid IS NOT NULL
AND repository IS NOT NULL
AND filter IS NULL;
CREATE UNIQUE INDEX userpreferences_item_uid_filter
ON userpreferences (item, uid, filter)
WHERE uid IS NOT NULL
AND repository IS NULL
AND filter IS NOT NULL;
================================================
FILE: installation/data/dbschema.reviews.sql
================================================
-- -*- mode: sql -*-
--
-- Copyright 2015 the Critic contributors, Opera Software ASA
--
-- Licensed under the Apache License, Version 2.0 (the "License"); you may not
-- use this file except in compliance with the License. You may obtain a copy of
-- the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- License for the specific language governing permissions and limitations under
-- the License.
-- Disable notices about implicitly created indexes and sequences.
SET client_min_messages TO WARNING;
CREATE TYPE reviewtype AS ENUM
( 'official',
'rfc',
'ad-hoc' );
CREATE TYPE reviewstate AS ENUM
( 'draft',
'open',
'closed',
'dropped' );
CREATE TABLE reviews
( id SERIAL PRIMARY KEY,
type reviewtype NOT NULL,
-- The review branch.
branch INTEGER NOT NULL REFERENCES branches,
-- The (non-review) branch from which this review was created, if any.
origin INTEGER REFERENCES branches ON DELETE SET NULL,
state reviewstate NOT NULL,
serial INTEGER NOT NULL DEFAULT 0,
closed_by INTEGER REFERENCES users,
dropped_by INTEGER REFERENCES users,
applyfilters BOOLEAN NOT NULL,
applyparentfilters BOOLEAN NOT NULL,
summary TEXT,
description TEXT );
CREATE INDEX reviews_branch ON reviews (branch);
CREATE TABLE scheduledreviewbrancharchivals
( review INTEGER PRIMARY KEY REFERENCES reviews (id),
deadline TIMESTAMP NOT NULL );
CREATE TABLE reviewfilters
( id SERIAL PRIMARY KEY,
review INTEGER NOT NULL REFERENCES reviews ON DELETE CASCADE,
uid INTEGER NOT NULL REFERENCES users ON DELETE CASCADE,
path TEXT NOT NULL,
type filtertype NOT NULL,
creator INTEGER NOT NULL REFERENCES users ON DELETE CASCADE );
-- Index used to enforce uniqueness.
CREATE UNIQUE INDEX reviewfilters_review_uid_path_md5 ON reviewfilters (review, uid, MD5(path));
CREATE TABLE batches
( id SERIAL PRIMARY KEY,
review INTEGER NOT NULL REFERENCES reviews ON DELETE CASCADE,
uid INTEGER NOT NULL REFERENCES users ON DELETE CASCADE,
comment INTEGER, -- REFERENCES commentchains,
time TIMESTAMP NOT NULL DEFAULT NOW() );
CREATE INDEX batches_review_uid ON batches (review, uid);
CREATE TYPE reviewusertype AS ENUM
( 'automatic',
'manual' );
CREATE TABLE reviewusers
( review INTEGER NOT NULL,
uid INTEGER NOT NULL,
owner BOOLEAN NOT NULL DEFAULT FALSE,
type reviewusertype NOT NULL DEFAULT 'automatic',
PRIMARY KEY (review, uid),
FOREIGN KEY (review) REFERENCES reviews(id) ON DELETE CASCADE,
FOREIGN KEY (uid) REFERENCES users(id) );
CREATE INDEX reviewusers_uid ON reviewusers (uid);
CREATE TABLE reviewchangesets
( review INTEGER NOT NULL REFERENCES reviews ON DELETE CASCADE,
changeset INTEGER NOT NULL REFERENCES changesets,
PRIMARY KEY (review, changeset) );
CREATE TABLE reviewrebases
( id SERIAL PRIMARY KEY,
review INTEGER NOT NULL REFERENCES reviews ON DELETE CASCADE,
old_head INTEGER NOT NULL REFERENCES commits,
new_head INTEGER REFERENCES commits,
old_upstream INTEGER REFERENCES commits,
new_upstream INTEGER REFERENCES commits,
equivalent_merge INTEGER REFERENCES commits,
replayed_rebase INTEGER REFERENCES commits,
uid INTEGER NOT NULL REFERENCES users,
branch VARCHAR(256),
UNIQUE (review, old_head) );
CREATE TABLE previousreachable
( rebase INTEGER NOT NULL REFERENCES reviewrebases ON DELETE CASCADE,
commit INTEGER NOT NULL REFERENCES commits );
CREATE INDEX previousreachable_rebase ON previousreachable (rebase);
CREATE TYPE reviewfilestate AS ENUM
( 'pending', -- No one has said anything.
'reviewed' -- The file has been reviewed.
);
CREATE TABLE reviewfiles
( id SERIAL PRIMARY KEY,
review INTEGER NOT NULL REFERENCES reviews ON DELETE CASCADE,
changeset INTEGER NOT NULL REFERENCES changesets ON DELETE CASCADE,
file INTEGER NOT NULL REFERENCES files ON DELETE CASCADE,
deleted INTEGER NOT NULL,
inserted INTEGER NOT NULL,
state reviewfilestate NOT NULL DEFAULT 'pending',
reviewer INTEGER REFERENCES users ON DELETE SET NULL,
time TIMESTAMP,
FOREIGN KEY (review, changeset) REFERENCES reviewchangesets ON DELETE CASCADE,
FOREIGN KEY (changeset, file) REFERENCES fileversions ON DELETE CASCADE );
CREATE INDEX reviewfiles_review_changeset ON reviewfiles (review, changeset);
CREATE INDEX reviewfiles_review_state ON reviewfiles (review, state);
CREATE TABLE reviewassignmentstransactions
( id SERIAL PRIMARY KEY,
review INTEGER NOT NULL REFERENCES reviews ON DELETE CASCADE,
assigner INTEGER NOT NULL REFERENCES users,
note TEXT,
time TIMESTAMP DEFAULT NOW() );
CREATE TABLE reviewassignmentchanges
( transaction INTEGER NOT NULL REFERENCES reviewassignmentstransactions,
file INTEGER NOT NULL REFERENCES reviewfiles ON DELETE CASCADE,
uid INTEGER NOT NULL REFERENCES users,
assigned BOOLEAN NOT NULL,
PRIMARY KEY (transaction, file, uid) );
CREATE TABLE reviewfilterchanges
( transaction INTEGER NOT NULL REFERENCES reviewassignmentstransactions ON DELETE CASCADE,
uid INTEGER NOT NULL REFERENCES users ON DELETE CASCADE,
path TEXT NOT NULL,
type filtertype NOT NULL,
created BOOLEAN NOT NULL );
CREATE TABLE reviewuserfiles
( file INTEGER NOT NULL REFERENCES reviewfiles ON DELETE CASCADE,
uid INTEGER NOT NULL REFERENCES users,
time TIMESTAMP DEFAULT NOW(),
PRIMARY KEY (file, uid) );
CREATE INDEX reviewuserfiles_uid ON reviewuserfiles (uid);
CREATE VIEW reviewfilesharing
AS SELECT reviewfiles.review AS review, reviewfiles.id AS file, COUNT(reviewuserfiles.uid) AS reviewers
FROM reviewfiles
JOIN reviewuserfiles ON (reviewfiles.id=reviewuserfiles.file)
JOIN users ON (users.id=reviewuserfiles.uid)
WHERE users.status='current'
GROUP BY reviewfiles.review, reviewfiles.id;
CREATE TYPE reviewfilechangestate AS ENUM
( 'draft', -- This change hasn't been performed yet.
'performed', -- The change has been performed.
'rejected' -- The change was rejected; affected file wasn't in expected
-- state (concurrent update.)
);
CREATE TABLE reviewfilechanges
( batch INTEGER REFERENCES batches,
file INTEGER NOT NULL REFERENCES reviewfiles,
uid INTEGER NOT NULL REFERENCES users,
time TIMESTAMP NOT NULL DEFAULT NOW(),
state reviewfilechangestate NOT NULL DEFAULT 'draft',
from_state reviewfilestate NOT NULL,
to_state reviewfilestate NOT NULL,
FOREIGN KEY (file, uid) REFERENCES reviewuserfiles ON DELETE CASCADE );
CREATE INDEX reviewfilechanges_batch ON reviewfilechanges (batch);
CREATE INDEX reviewfilechanges_file ON reviewfilechanges (file);
CREATE INDEX reviewfilechanges_uid_state ON reviewfilechanges (uid, state);
CREATE INDEX reviewfilechanges_time ON reviewfilechanges (time);
CREATE TABLE lockedreviews
( review INTEGER PRIMARY KEY REFERENCES reviews );
CREATE VIEW fullreviewuserfiles
AS SELECT reviewfiles.review as review,
reviewfiles.changeset as changeset,
reviewfiles.file as file,
reviewfiles.deleted as deleted,
reviewfiles.inserted as inserted,
reviewfiles.state as state,
reviewfiles.reviewer as reviewer,
reviewuserfiles.uid as assignee
FROM reviewfiles
JOIN reviewuserfiles ON (reviewuserfiles.file=reviewfiles.id);
CREATE TABLE reviewmessageids
( uid INTEGER NOT NULL REFERENCES users ON DELETE CASCADE,
review INTEGER NOT NULL REFERENCES reviews ON DELETE CASCADE,
messageid CHAR(24) NOT NULL,
PRIMARY KEY (uid, review) );
CREATE INDEX reviewmessageids_review ON reviewmessageids (review);
CREATE TABLE reviewmergeconfirmations
( id SERIAL PRIMARY KEY,
review INTEGER NOT NULL REFERENCES reviews ON DELETE CASCADE,
uid INTEGER NOT NULL REFERENCES users ON DELETE CASCADE,
merge INTEGER NOT NULL REFERENCES commits ON DELETE CASCADE,
tail INTEGER REFERENCES commits ON DELETE CASCADE,
confirmed BOOLEAN NOT NULL DEFAULT FALSE,
UNIQUE (review, uid, merge) );
CREATE TABLE reviewmergecontributions
( id INTEGER NOT NULL REFERENCES reviewmergeconfirmations ON DELETE CASCADE,
merged INTEGER NOT NULL REFERENCES commits ON DELETE CASCADE,
PRIMARY KEY (id, merged) );
CREATE TABLE reviewrecipientfilters
( review INTEGER NOT NULL REFERENCES reviews,
uid INTEGER REFERENCES users,
include BOOLEAN NOT NULL,
UNIQUE (review, uid) );
CREATE TABLE checkbranchnotes
( repository INTEGER NOT NULL REFERENCES repositories ON DELETE CASCADE,
branch VARCHAR(256) NOT NULL,
upstream VARCHAR(256) NOT NULL,
sha1 CHAR(40) NOT NULL,
uid INTEGER NOT NULL REFERENCES users,
review INTEGER REFERENCES reviews ON DELETE SET NULL,
text TEXT,
PRIMARY KEY (repository, branch, upstream, sha1) );
================================================
FILE: installation/data/dbschema.trackedbranches.sql
================================================
-- -*- mode: sql -*-
--
-- Copyright 2015 the Critic contributors, Opera Software ASA
--
-- Licensed under the Apache License, Version 2.0 (the "License"); you may not
-- use this file except in compliance with the License. You may obtain a copy of
-- the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- License for the specific language governing permissions and limitations under
-- the License.
-- Disable notices about implicitly created indexes and sequences.
SET client_min_messages TO WARNING;
CREATE TABLE trackedbranches
( id SERIAL PRIMARY KEY,
repository INTEGER NOT NULL REFERENCES repositories,
local_name VARCHAR(256) NOT NULL,
remote VARCHAR(256) NOT NULL,
remote_name VARCHAR(256) NOT NULL,
forced BOOLEAN NOT NULL,
disabled BOOLEAN NOT NULL DEFAULT FALSE,
updating BOOLEAN NOT NULL DEFAULT FALSE,
delay INTERVAL NOT NULL,
previous TIMESTAMP,
next TIMESTAMP,
UNIQUE (repository, local_name) );
CREATE TABLE trackedbranchusers
( branch INTEGER NOT NULL REFERENCES trackedbranches ON DELETE CASCADE,
uid INTEGER NOT NULL REFERENCES users,
PRIMARY KEY (branch, uid) );
CREATE TABLE trackedbranchlog
( branch INTEGER NOT NULL REFERENCES trackedbranches ON DELETE CASCADE,
time TIMESTAMP NOT NULL DEFAULT NOW(),
from_sha1 CHAR(40),
to_sha1 CHAR(40) NOT NULL,
hook_output TEXT NOT NULL,
successful BOOLEAN NOT NULL );
CREATE INDEX trackedbranchlog_branch ON trackedbranchlog (branch);
================================================
FILE: installation/data/dbschema.users.sql
================================================
-- -*- mode: sql -*-
--
-- Copyright 2015 the Critic contributors, Opera Software ASA
--
-- Licensed under the Apache License, Version 2.0 (the "License"); you may not
-- use this file except in compliance with the License. You may obtain a copy of
-- the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-- WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-- License for the specific language governing permissions and limitations under
-- the License.
-- Disable notices about implicitly created indexes and sequences.
SET client_min_messages TO WARNING;
CREATE TABLE roles
( name VARCHAR(64) PRIMARY KEY,
description TEXT );
INSERT INTO roles (name, description)
VALUES ('administrator', 'Almighty system administrator.'),
('repositories', 'Allowed to add and configure repositories.'),
('developer', 'System developer.'),
('newswriter', 'Allowed to add and edit news items.');
CREATE TYPE userstatus AS ENUM
( 'unknown',
'current',
'absent',
'retired' );
CREATE TABLE users
( id SERIAL PRIMARY KEY,
name VARCHAR(64) NOT NULL UNIQUE,
fullname VARCHAR(256),
password VARCHAR(256),
email INTEGER, -- Foreign key constraint "REFERENCES useremails" set up later.
status userstatus NOT NULL DEFAULT 'unknown' );
CREATE TABLE useremails
( id SERIAL PRIMARY KEY,
uid INTEGER NOT NULL REFERENCES users ON DELETE CASCADE,
email VARCHAR(256) NOT NULL,
verified BOOLEAN,
verification_token VARCHAR(256),
UNIQUE (uid, email) );
-- FIXME: This circular relation is unnecessary. Should have a separate table
-- for mapping a user's selected email, or just store it as a boolean in the
-- useremails table instead.
ALTER TABLE users ADD CONSTRAINT users_email_fkey FOREIGN KEY (email) REFERENCES useremails;
CREATE TABLE usersessions
( key CHAR(28) PRIMARY KEY,
uid INTEGER NOT NULL REFERENCES users,
labels VARCHAR(256),
atime TIMESTAMP DEFAULT NOW() );
CREATE TABLE usergitemails
( email VARCHAR(256),
uid INTEGER REFERENCES users ON DELETE CASCADE,
PRIMARY KEY (email, uid) );
CREATE INDEX usergitemails_uid ON usergitemails (uid);
CREATE TABLE userabsence
( uid INTEGER NOT NULL REFERENCES users,
until DATE );
CREATE INDEX userabsence_uid_until ON userabsence (uid, until);
CREATE TABLE userroles
( uid INTEGER NOT NULL REFERENCES users,
role VARCHAR(64) NOT NULL REFERENCES roles );
CREATE TABLE userresources
( uid INTEGER NOT NULL REFERENCES users ON DELETE CASCADE,
name VARCHAR(32) NOT NULL,
revision INTEGER NOT NULL DEFAULT 0,
source TEXT NOT NULL,
PRIMARY KEY (uid, name, revision) );
CREATE TABLE externalusers
( id SERIAL PRIMARY KEY,
uid INTEGER REFERENCES users,
provider VARCHAR(16) NOT NULL,
account VARCHAR(256) NOT NULL,
email VARCHAR(256),
token VARCHAR(256),
UNIQUE (provider, account) );
CREATE TABLE oauthstates
( state VARCHAR(64) PRIMARY KEY,
url TEXT,
time TIMESTAMP NOT NULL DEFAULT NOW() );
CREATE TYPE systemaccesstype AS ENUM
( -- The system is accessed as a named user.
'user',
-- The system is accessed by a system service or similar.
'system',
-- The system is accessed anonymously.
'anonymous' );
CREATE TABLE accesstokens
( id SERIAL PRIMARY KEY,
-- The type of access granted by this access token.
access_type systemaccesstype NOT NULL DEFAULT 'user',
-- The user (when access_type='user') or NULL.
uid INTEGER REFERENCES users ON DELETE CASCADE,
-- First part of access token ("username").
part1 VARCHAR(32) NOT NULL,
-- Second part of access token ("password").
part2 VARCHAR(32) NOT NULL,
-- Access token title.
title VARCHAR(256),
UNIQUE (part1, part2),
CONSTRAINT valid_user CHECK ((access_type='user' AND uid IS NOT NULL) OR
(access_type!='user' AND uid IS NULL)) );
CREATE TYPE accesscontrolrule AS ENUM
( 'allow',
'deny' );
CREATE TABLE accesscontrolprofiles
( id SERIAL PRIMARY KEY,
title TEXT,
-- Access token that this profile belongs to.
access_token INTEGER REFERENCES accesstokens ON DELETE CASCADE,
http accesscontrolrule NOT NULL DEFAULT 'allow',
repositories accesscontrolrule NOT NULL DEFAULT 'allow',
extensions accesscontrolrule NOT NULL DEFAULT 'allow',
UNIQUE (access_token) );
CREATE TYPE httprequestmethod AS ENUM
( 'GET',
'HEAD',
'OPTIONS',
'POST',
'PUT',
'DELETE' );
-- Exceptions for HTTP requests.
CREATE TABLE accesscontrol_http
( id SERIAL PRIMARY KEY,
-- The profile this exception belongs to.
profile INTEGER NOT NULL REFERENCES accesscontrolprofiles ON DELETE CASCADE,
-- HTTP request method. NULL means "all methods".
request_method httprequestmethod,
-- Python regular expression that must match the entire path. NULL means
-- "all paths".
path_pattern TEXT );
CREATE INDEX accesscontrol_http_profile
ON accesscontrol_http (profile);
CREATE TABLE useraccesscontrolprofiles
( -- The type of access that is controlled.
access_type systemaccesstype NOT NULL DEFAULT 'user',
-- The user (when access_type='user') or NULL. If access_type='user' and
-- this is NULL, then this is the default profile association.
uid INTEGER REFERENCES users,
-- Access control profile.
profile INTEGER NOT NULL REFERENCES accesscontrolprofiles ON DELETE CASCADE,
CONSTRAINT valid_user CHECK (access_type='user' OR uid IS NULL) );
CREATE INDEX useraccesscontrolprofiles_uid
ON useraccesscontrolprofiles (uid);
CREATE TABLE labeledaccesscontrolprofiles
( -- Authentication labels from user authentication, typically indicating some
-- type of group memberships. Labels should be sorted lexicographically and
-- separated by pipe ('|') characters.
labels VARCHAR(256) PRIMARY KEY,
-- Access control profile.
profile INTEGER NOT NULL REFERENCES accesscontrolprofiles ON DELETE CASCADE );
================================================
FILE: installation/database.py
================================================
# -*- mode: python; encoding: utf-8 -*-
#
# Copyright 2012 Jens Lindström, Opera Software ASA
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
import tempfile
import shutil
import os
import time
import errno
import subprocess
import installation
user_created = False
database_created = False
language_created = False
def psql_import(sql_file, as_user=None):
if as_user is None:
as_user = installation.system.username
temp_file = tempfile.mkstemp()[1]
shutil.copy(os.path.join(installation.root_dir, sql_file), temp_file)
# Make sure file is readable by postgres user
os.chmod(temp_file, 0644)
subprocess.check_output(
["su", "-s", "/bin/sh", "-c", "psql -v ON_ERROR_STOP=1 -f %s" % temp_file, as_user])
os.unlink(temp_file)
def add_arguments(mode, parser):
if mode == "upgrade":
parser.add_argument("--backup-database", dest="database_backup", action="store_const", const=True,
help="backup database to default location without asking")
parser.add_argument("--no-backup-database", dest="database_backup", action="store_const", const=False,
help="do not backup database before upgrading")
def prepare(mode, arguments, data):
if mode == "upgrade":
default_path = os.path.join(data["installation.paths.data_dir"],
"backups",
time.strftime("%Y%m%d_%H%M.dump", time.localtime()))
if arguments.database_backup is False:
backup_database = False
elif arguments.database_backup is True:
backup_database = True
backup_path = default_path
else:
if installation.migrate.will_modify_dbschema(data):
print """
The database schema will be modified by the upgrade. Creating a
backup of the database first is strongly recommended.
"""
default_backup = True
else:
default_backup = False
if installation.input.yes_or_no("Do you want to create a backup of the database?",
default=default_backup):
backup_database = True
backup_path = installation.input.string("Where should the backup be stored?",
default=default_path)
else:
backup_database = False
if backup_database:
try: os.makedirs(os.path.dirname(backup_path), 0750)
except OSError as error:
if error.errno == errno.EEXIST: pass
else: raise
print
print "Dumping database ..."
with open(backup_path, "w") as output_file:
subprocess.check_call(
["su", "-s", "/bin/sh", "-c", "pg_dump -Fc critic",
data["installation.system.username"]],
stdout=output_file)
data["installation.database.driver"] = "postgresql"
data["installation.database.parameters"] = { "database": "critic",
"user": data["installation.system.username"] }
return True
SCHEMA_FILES = [
# No dependencies.
"installation/data/dbschema.base.sql",
"installation/data/dbschema.users.sql",
# Depends on: base[files].
"installation/data/dbschema.git.sql",
# Depends on: users.
"installation/data/dbschema.news.sql",
# Depends on: git, users.
"installation/data/dbschema.trackedbranches.sql",
# Depends on: base[files], git.
"installation/data/dbschema.changesets.sql",
# Depends on: git, users.
"installation/data/dbschema.filters.sql",
# Depends on: git, users, filters.
"installation/data/dbschema.preferences.sql",
# Depends on: base[files], git, users, changesets.
"installation/data/dbschema.reviews.sql",
# Depends on: base[files], git, users, reviews.
"installation/data/dbschema.comments.sql",
# Depends on: base[files], git, users, reviews.
"installation/data/dbschema.extensions.sql",
]
PGSQL_FILES = ["installation/data/comments.pgsql"]
def install(data):
global user_created, database_created, language_created
postgresql_version_output = subprocess.check_output(
[installation.prereqs.psql.path, "--version"])
postgresql_version = postgresql_version_output.splitlines()[0].split()[-1]
postgresql_version_components = postgresql_version.split(".")
postgresql_major = postgresql_version_components[0]
postgresql_minor = postgresql_version_components[1]
if postgresql_major < 9 or (postgresql_major == 9 and postgresql_minor < 1):
print
print """\
Unsupported PostgreSQL version: %s
ERROR: Critic requires PostgreSQL 9.1.x or later!
""" % postgresql_version
return False
print "Creating database ..."
# Several subsequent commands will run as Critic system user or "postgres"
# user, and these users typically don't have read access to the installation
# 'root_dir', so set cwd to something that Critic system / "postgres" users
# has access to.
with installation.utils.temporary_cwd():
subprocess.check_output(["su", "-c", "psql -v ON_ERROR_STOP=1 -c 'CREATE USER \"%s\";'" % installation.system.username, "postgres"])
user_created = True
subprocess.check_output(["su", "-c", "psql -v ON_ERROR_STOP=1 -c 'CREATE DATABASE \"critic\";'", "postgres"])
database_created = True
try:
subprocess.check_output(["su", "-c", "createlang plpgsql critic", "postgres"],
stderr=subprocess.STDOUT)
language_created = True
except subprocess.CalledProcessError:
# The 'createlang' command fails if the language is already enabled
# in the database, and we want to ignore such failures. It might
# also fail for other reasons, that we really don't mean to ignore,
# but in that case importing the *.pgsql files below would fail,
# since they define PL/pgSQL functions.
pass
subprocess.check_output(["su", "-c", "psql -v ON_ERROR_STOP=1 -c 'GRANT ALL ON DATABASE \"critic\" TO \"%s\";'" % installation.system.username, "postgres"])
for schema_file in SCHEMA_FILES:
psql_import(schema_file)
for pgsql_file in PGSQL_FILES:
psql_import(pgsql_file)
import psycopg2
def adapt(value): return psycopg2.extensions.adapt(value).getquoted()
if installation.config.access_scheme in ("http", "https"):
anonymous_scheme = authenticated_scheme = installation.config.access_scheme
else:
anonymous_scheme = "http"
authenticated_scheme = "https"
add_systemidentity_query = (
"""INSERT INTO systemidentities (key, name, anonymous_scheme,
authenticated_scheme, hostname,
description, installed_sha1)
VALUES ('main', 'main', %s, %s, %s, 'Main', %s);"""
% (adapt(anonymous_scheme), adapt(authenticated_scheme),
adapt(installation.system.hostname), adapt(data["sha1"])))
installation.process.check_input(
["su", "-s", "/bin/sh", "-c", "psql -q -v ON_ERROR_STOP=1 -f -", installation.system.username],
stdin=add_systemidentity_query)
return True
def upgrade(arguments, data):
git = data["installation.prereqs.git"]
old_sha1 = data["sha1"]
new_sha1 = installation.utils.run_git([git, "rev-parse", "HEAD"],
cwd=installation.root_dir).strip()
for pgsql_file in PGSQL_FILES:
old_file_sha1 = installation.utils.get_file_sha1(
git, old_sha1, pgsql_file)
new_file_sha1 = installation.utils.get_file_sha1(
git, new_sha1, pgsql_file)
if old_file_sha1 == new_file_sha1:
continue
with installation.utils.temporary_cwd():
# We assume that these files use CREATE OR REPLACE syntax, so that
# we can simply re-import them when they change, and they'll update.
# If they need more than that to update (for instance if a function
# is removed) we'll need to use a migration script for that.
print "Reloading: %s" % pgsql_file
if not arguments.dry_run:
psql_import(pgsql_file)
return True
def undo():
if language_created:
subprocess.check_output(["su", "-c", "droplang plpgsql critic", "postgres"])
if database_created:
subprocess.check_output(["su", "-c", "psql -v ON_ERROR_STOP=1 -c 'DROP DATABASE \"critic\";'", "postgres"])
if user_created:
subprocess.check_output(["su", "-c", "psql -v ON_ERROR_STOP=1 -c 'DROP USER \"%s\";'" % installation.system.username, "postgres"])
================================================
FILE: installation/extensions.py
================================================
# -*- mode: python; encoding: utf-8 -*-
#
# Copyright 2012 Jens Lindström, Opera Software ASA
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
def prepare(mode, arguments, data):
data["installation.extensions.enabled"] = False
data["installation.extensions.critic_v8_jsshell"] = "NOT_INSTALLED"
data["installation.extensions.default_flavor"] = "js/v8"
if mode == "upgrade":
import configuration
data["installation.extensions.enabled"] = \
configuration.extensions.ENABLED
try:
data["installation.extensions.critic_v8_jsshell"] = \
configuration.extensions.FLAVORS["js/v8"]["executable"]
except (KeyError, AttributeError):
pass
try:
data["installation.extensions.default_flavor"] = \
configuration.extensions.DEFAULT_FLAVOR
except AttributeError:
pass
return True
================================================
FILE: installation/externals/.gitignore
================================================
depot_tools/
================================================
FILE: installation/externals/MIT-LICENSE.Chosen.md
================================================
#### Chosen
- by Patrick Filler for [Harvest](http://getharvest.com)
- Copyright (c) 2011-2013 by Harvest
Available for use under the [MIT License](http://en.wikipedia.org/wiki/MIT_License)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================
FILE: installation/externals/MIT-LICENSE.jQuery.txt
================================================
Copyright 2012 jQuery Foundation and other contributors
http://jquery.com/
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: installation/files.py
================================================
# -*- mode: python; encoding: utf-8 -*-
#
# Copyright 2012 Jens Lindström, Opera Software ASA
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
import sys
import os
import shutil
import errno
import py_compile
import installation
created_dir = []
created_file = []
renamed = []
copied_files = 0
modified_files = 0
sources_modified = False
resources_modified = False
def compile_file(filename):
global created_file
if not filename.endswith(".py"):
return True
try:
path = os.path.join(installation.paths.install_dir, filename)
with installation.utils.as_critic_system_user():
py_compile.compile(path, doraise=True)
except py_compile.PyCompileError as error:
print """
ERROR: Failed to compile %s:\n%s
""" % (filename, error)
return False
else:
created_file.append(path + "c")
return True
def copyfile(source, destination):
if os.path.islink(source):
if os.path.lexists(destination):
os.unlink(destination)
os.symlink(os.readlink(source), destination)
else:
shutil.copyfile(source, destination)
def skip(path):
filename = os.path.basename(path)
if filename == "unittest.py" or filename.endswith("_unittest.py"):
return not installation.config.is_testing
return False
def install(data):
source_dir = os.path.join(installation.root_dir, "src")
target_dir = installation.paths.install_dir
# Note: this is an array since it's modified in a nested scope.
compilation_failed = []
def copy(path):
global copied_files
source = os.path.join(source_dir, path)
target = os.path.join(target_dir, path)
if os.path.isdir(source):
os.mkdir(target, 0755)
os.chown(target, installation.system.uid, installation.system.gid)
created_dir.append(target)
return True
else:
copyfile(source, target)
created_file.append(target)
if not os.path.islink(target):
if path.startswith("hooks/"):
mode = 0755
else:
mode = 0644
os.chmod(target, mode)
os.lchown(target, installation.system.uid, installation.system.gid)
copied_files += 1
if not compile_file(path):
compilation_failed.append(path)
return False
def process(path=""):
for entry in os.listdir(os.path.join(source_dir, path)):
name = os.path.join(path, entry)
if skip(name):
continue
if copy(name):
process(name)
process()
sys.path.insert(0, installation.paths.install_dir)
if compilation_failed:
return False
print "Copied %d files into %s ..." % (copied_files, target_dir)
return True
def upgrade(arguments, data):
source_dir = installation.root_dir
target_dir = data["installation.paths.install_dir"]
# Note: this is an array since it's modified in a nested scope.
compilation_failed = []
uid = installation.system.uid
gid = installation.system.gid
def chown(directory):
os.chown(directory, uid, gid)
for name in os.listdir(directory):
path = os.path.join(directory, name)
if os.path.isdir(path):
chown(path)
elif path.endswith(".pyc"):
os.chown(path, uid, gid)
elif path.endswith(".pyo"):
os.unlink(path)
chown(target_dir)
git = data["installation.prereqs.git"]
old_sha1 = data["sha1"]
new_sha1 = installation.utils.run_git([git, "rev-parse", "HEAD"],
cwd=installation.root_dir).strip()
old_has_src = installation.utils.get_tree_sha1(git, old_sha1, "src")
def isResource(path):
return path.endswith(".css") or path.endswith(".js") or path.endswith(".txt")
def remove(old_source_path, target_path):
full_target_path = os.path.join(target_dir, target_path)
backup_path = os.path.join(os.path.dirname(full_target_path),
"_" + os.path.basename(target_path))
if not os.path.isfile(full_target_path):
return
old_file_sha1 = installation.utils.get_file_sha1(
git, old_sha1, old_source_path)
current_file_sha1 = installation.utils.hash_file(
git, full_target_path)
assert old_file_sha1 is not None
if old_file_sha1 != current_file_sha1:
def generateVersion(label, path):
if label == "installed":
source = installation.utils.run_git(
[git, "cat-file", "blob", old_file_sha1],
cwd=installation.root_dir)
with open(path, "w") as target:
target.write(source)
update_query = installation.utils.UpdateModifiedFile(
arguments,
message="""\
A source file is about to be removed, but the existing source file
appears to have been edited since it was installed.
Installed version: %(installed)s
Current version : %(current)s
Not removing the file can cause unpredictable results.
""",
versions={ "installed": full_target_path + ".org",
"current": full_target_path },
options=[ ("r", "remove the file"),
("k", "keep the file"),
("d", ("installed", "current")) ],
generateVersion=generateVersion)
if update_query.prompt() == "r":
remove_file = True
else:
remove_file = False
else:
remove_file = True
if remove_file:
print "Removing file: %s" % target_path
if not arguments.dry_run:
os.rename(full_target_path, backup_path)
renamed.append((full_target_path, backup_path))
if target_path.endswith(".py"):
if os.path.isfile(full_target_path + "c"):
os.unlink(full_target_path + "c")
if os.path.isfile(full_target_path + "o"):
os.unlink(full_target_path + "o")
def copy(old_source_path, new_source_path, target_path):
global copied_files, modified_files
global resources_modified, sources_modified
full_source_path = os.path.join(source_dir, new_source_path)
full_target_path = os.path.join(target_dir, target_path)
backup_path = os.path.join(os.path.dirname(full_target_path),
"_" + os.path.basename(target_path))
if skip(new_source_path) or not os.path.isfile(full_source_path):
remove(old_source_path, target_path)
return
if os.path.isfile(full_source_path) and os.path.isdir(full_target_path):
print """
The directory
%s
is about to be deleted because a file is about to be installed in its
place. Please make sure it doesn't contain anything that shouldn't be
deleted.
""" % full_target_path
if not installation.input.yes_or_no("Do you want to delete the directory?", default=False):
return False
print "Removing directory: %s" % target_path
if not arguments.dry_run:
os.rename(full_target_path, backup_path)
renamed.append((full_target_path, backup_path))
if not os.path.isfile(full_target_path):
print "New file: %s" % target_path
if not arguments.dry_run:
try: os.makedirs(os.path.dirname(full_target_path), 0755)
except OSError as error:
if error.errno == errno.EEXIST: pass
else: raise
copyfile(full_source_path, full_target_path)
created_file.append(full_target_path)
copied_files += 1
if isResource(target_path):
resources_modified = True
else:
sources_modified = True
else:
old_file_sha1 = installation.utils.get_file_sha1(
git, old_sha1, old_source_path)
new_file_sha1 = installation.utils.get_file_sha1(
git, new_sha1, new_source_path)
assert old_file_sha1 is not None
assert new_file_sha1 is not None
current_file_sha1 = installation.utils.hash_file(
git, full_target_path)
if current_file_sha1 != new_file_sha1:
if current_file_sha1 != old_file_sha1:
def generateVersion(label, path):
if label == "installed":
source = installation.utils.run_git(
[git, "cat-file", "blob", old_file_sha1],
cwd=installation.root_dir)
with open(full_target_path + ".org", "w") as target:
target.write(source)
elif label == "updated":
copyfile(full_source_path,
full_target_path + ".new")
update_query = installation.utils.UpdateModifiedFile(
arguments,
message="""\
A source file is about to be updated, but the existing source file
appears to have been edited since it was installed.
Installed version: %(installed)s
Current version : %(current)s
Updated version : %(updated)s
Not installing the updated version can cause unpredictable results.
""",
versions={ "installed": full_target_path + ".org",
"current": full_target_path,
"updated": full_target_path + ".new" },
options=[ ("i", "install the updated version"),
("k", "keep the current version"),
("do", ("installed", "current")),
("dn", ("current", "updated")) ],
generateVersion=generateVersion)
install_file = update_query.prompt() == "i"
else:
install_file = True
if install_file:
print "Updated file: %s" % target_path
if not arguments.dry_run:
os.rename(full_target_path, backup_path)
renamed.append((full_target_path, backup_path))
copyfile(full_source_path, full_target_path)
created_file.append(full_target_path)
if not compile_file(target_path):
compilation_failed.append(target_path)
modified_files += 1
if isResource(target_path):
resources_modified = True
else:
sources_modified = True
if target_path.startswith("hooks/"):
mode = 0755
else:
mode = 0644
if not arguments.dry_run:
if not os.path.islink(full_target_path):
os.chmod(full_target_path, mode)
os.lchown(full_target_path, installation.system.uid, installation.system.gid)
differences = installation.utils.run_git(
[git, "diff", "--numstat", "%s..%s" % (old_sha1, new_sha1)],
cwd=installation.root_dir)
changed_paths = set()
for line in differences.splitlines():
_, _, path = map(str.strip, line.split(None, 2))
if path.startswith("src/"):
changed_paths.add(path[len("src/"):])
elif not old_has_src:
if os.path.isfile(os.path.join(target_dir, path)):
changed_paths.add(path)
for path in sorted(changed_paths):
if old_has_src:
old_source_path = os.path.join("src", path)
else:
old_source_path = path
if copy(old_source_path=old_source_path,
new_source_path=os.path.join("src", path),
target_path=path) is False:
return False
if compilation_failed:
return False
if copied_files == 0 and modified_files == 0:
print "No new or modified source files."
return True
def undo():
map(os.unlink, reversed(created_file))
map(os.rmdir, reversed(created_dir))
for target, backup in renamed:
os.rename(backup, target)
def finish(mode, arguments, data):
for target, backup in renamed:
if os.path.isdir(backup): shutil.rmtree(backup)
else: os.unlink(backup)
================================================
FILE: installation/git.py
================================================
# -*- mode: python; encoding: utf-8 -*-
#
# Copyright 2012 Jens Lindström, Opera Software ASA
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
import os
import subprocess
import installation
def install(data):
socket_path = os.path.join(installation.paths.run_dir,
"main", "sockets", "githook.unix")
subprocess.check_call([installation.prereqs.git.path,
"config", "--system", "critic.socket", socket_path])
return True
================================================
FILE: installation/httpd.py
================================================
# -*- mode: python; encoding: utf-8 -*-
#
# Copyright 2015 the Critic contributors, Opera Software ASA
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
import os
import re
import subprocess
import time
import installation
arguments = None
instance = None
created_file = []
renamed = []
def backup_path(path):
return os.path.join(os.path.dirname(path), "_" + os.path.basename(path))
def undoable_remove(path):
os.rename(path, backup_path(path))
renamed.append((path, backup_path(path)))
def process_configuration_file(
mode, data, template_path, target_path, message=None):
global created_file, renamed
with open(template_path, "r") as template_file:
template = template_file.read().decode("utf-8")
source = template % data
if mode == "install":
write_target = True
else:
with open(target_path, "r") as target_file:
target = target_file.read().decode("utf-8")
if source != target:
def generateVersion(label, path):
if label == "updated":
with open(path, "w") as target:
target.write(source.encode("utf-8"))
update_query = installation.utils.UpdateModifiedFile(
arguments,
message=message,
versions={ "current": target_path,
"updated": target_path + ".new" },
options=[ ("i", "install the updated version"),
("k", "keep the current version"),
("d", ("current", "updated")) ],
generateVersion=generateVersion)
write_target = update_query.prompt() == "i"
else:
write_target = False
if write_target:
if not getattr(arguments, "dry_run", False):
undoable_remove(target_path)
print "Updated file: %s" % target_path
if write_target and not getattr(arguments, "dry_run", False):
with open(target_path, "w") as target_file:
created_file.append(target_path)
os.chmod(target_path, 0640)
target_file.write(source.encode("utf-8"))
class Service(object):
def __init__(self):
self.stopped = False
def service_command(self, command, errors_are_fatal):
print
try:
subprocess.check_call(["service", self.service_name, command])
except subprocess.CalledProcessError:
print "WARNING: The %s service failed to %s." % (self.display_name,
command)
if errors_are_fatal:
print """
You can now either abort this Critic installation/upgrade, or you can
go ahead anyway, fix the configuration problem manually (now or
later), and then make sure the %(name)s service is running yourself
using the command
service %(name)s (start|restart)
Note that if you don't abort, the Critic system will most likely not
be accessible until the configuration problem has been fixed.
""" % { "name": self.service_name }
return not installation.input.yes_or_no(
"Do you want to abort this Critic installation/upgrade?")
return True
def start(self, errors_are_fatal=True):
print
if not self.service_command("start", errors_are_fatal):
return False
self.stopped = False
return True
def stop(self, errors_are_fatal=False):
print
if not self.service_command("stop", errors_are_fatal):
return False
self.stopped = True
return True
def restart(self):
print
if not self.stop():
return False
return self.start()
def prepare(self, mode, arguments, data):
return True
def install(self, data):
return True
def upgrade(self, arguments, data):
return True
def undo(self):
if self.stopped:
self.start()
class Apache(Service):
display_name = "Apache"
service_name = "apache2"
etc_dir = "/etc/apache2"
template_dir = "installation/templates/apache"
def __init__(self):
self.template_path = os.path.join(
installation.root_dir, self.template_dir,
"site.%s" % installation.config.access_scheme)
self.site_enabled = False
self.default_site_disabled = False
def get_version(self):
output = subprocess.check_output([installation.prereqs.apache2ctl.path, "-v"])
match = re.search("Server version:\s*Apache/([^\s\n]*)", output, re.M)
if not match:
return None
return match.group(1)
def prepare(self, mode, arguments, data):
if installation.config.auth_mode == "critic":
pass_auth = "On"
else:
pass_auth = "Off"
data["installation.apache.pass_auth"] = pass_auth
return True
def restart(self):
if not self.stop():
return False
time.sleep(1)
return self.start()
def setup(self):
version = self.get_version()
if version and version.startswith("2.2."):
self.site_suffix = ""
self.default_site = "default"
else:
self.site_suffix = ".conf"
self.default_site = "000-default"
self.target_path = os.path.join(
self.etc_dir, "sites-available", "critic-main%s" % self.site_suffix)
def install(self, data):
self.setup()
process_configuration_file(
"install", data, self.template_path, self.target_path)
subprocess.check_call([installation.prereqs.a2enmod.path, "expires"])
subprocess.check_call([installation.prereqs.a2enmod.path, "rewrite"])
subprocess.check_call([installation.prereqs.a2enmod.path, "wsgi"])
subprocess.check_call([installation.prereqs.a2ensite.path, "critic-main"])
self.site_enabled = True
output = subprocess.check_output(
[installation.prereqs.a2dissite.path, self.default_site],
env={ "LANG": "C" })
if ("Site %s disabled." % self.default_site) in output:
self.default_site_disabled = True
return self.restart()
def upgrade(self, arguments, data):
self.setup()
# If the configuration file doesn't exist, we're probably migrating the
# system from one web server to another, so run the whole installation
# procedure instead.
if not os.path.isfile(self.target_path):
return install(data)
process_configuration_file(
"upgrade", data, self.template_path, self.target_path, """\
The Apache site definition is about to be updated. Please check that no local
modifications are being overwritten.
Current version: %(current)s
Updated version: %(updated)s
Please note that if the modifications are not installed, the system is likely
to break.
""")
return True
def undo(self):
if self.site_enabled:
subprocess.check_call(
[installation.prereqs.a2dissite.path, "critic-main"])
if self.default_site_disabled:
subprocess.check_call(
[installation.prereqs.a2ensite.path, self.default_site])
self.restart()
class nginx(Service):
display_name = service_name = "nginx"
etc_dir = "/etc/nginx"
template_dir = "installation/templates/nginx"
def __init__(self):
self.site_enabled = False
self.default_site_disabled = False
self.template_path = os.path.join(
installation.root_dir, self.template_dir,
"site.%s" % installation.config.access_scheme)
self.target_path = os.path.join(
self.etc_dir, "sites-available/critic-main")
self.enabled_path = os.path.join(
self.etc_dir, "sites-enabled/critic-main")
self.default_site_path = os.path.join(
self.etc_dir, "sites-enabled/default")
def install(self, data):
process_configuration_file(
"install", data, self.template_path, self.target_path)
os.symlink(self.target_path, self.enabled_path)
self.site_enabled = True
if os.path.islink(self.default_site_path):
os.unlink(self.default_site_path)
self.default_site_disabled = True
return self.restart()
def upgrade(self, arguments, data):
# If the configuration file doesn't exist, we're probably migrating the
# system from one web server to another, so run the whole installation
# procedure instead.
if not os.path.isfile(self.target_path):
return install(data)
process_configuration_file(
"upgrade", data, self.template_path, self.target_path, """\
The nginx site definition is about to be updated. Please check that no local
modifications are being overwritten.
Current version: %(current)s
Updated version: %(updated)s
Please note that if the modifications are not installed, the system is likely
to break.
""")
return True
def undo(self):
if self.site_enabled:
os.unlink(self.enabled_path)
if self.default_site_disabled:
os.symlink(
os.path.join(self.etc_dir, "sites-available/default"),
self.default_site_path)
self.restart()
class uWSGIBackend(Service):
display_name = "uWSGI"
service_name = "uwsgi"
etc_dir = "/etc/uwsgi"
template_dir = "installation/templates/uwsgi"
def __init__(self):
self.app_enabled = False
self.template_path = os.path.join(
installation.root_dir, self.template_dir, "app.backend.ini")
self.target_path = os.path.join(
self.etc_dir, "apps-available/critic-backend-main.ini")
self.enabled_path = os.path.join(
self.etc_dir, "apps-enabled/critic-backend-main.ini")
def install(self, data):
process_configuration_file(
"install", data, self.template_path, self.target_path)
os.symlink(self.target_path, self.enabled_path)
self.app_enabled = True
return self.restart()
def upgrade(self, arguments, data):
# If the configuration file doesn't exist, we're probably migrating the
# system from one web server to another, so run the whole installation
# procedure instead.
if not os.path.isfile(self.target_path):
return install(data)
process_configuration_file(
"upgrade", data, self.template_path, self.target_path, """\
The uWSGI back-end app definition is about to be updated. Please check that
no local modifications are being overwritten.
Current version: %(current)s
Updated version: %(updated)s
Please note that if the modifications are not installed, the system is likely
to break.
""")
return True
def undo(self):
if self.app_enabled:
os.unlink(self.enabled_path)
self.restart()
class uWSGIFrontend(Service):
display_name = "uWSGI"
service_name = "uwsgi"
etc_dir = "/etc/uwsgi"
template_dir = "installation/templates/uwsgi"
def __init__(self):
self.app_enabled = False
self.template_path = os.path.join(
installation.root_dir, self.template_dir,
"app.frontend.ini.%s" % installation.config.access_scheme)
self.target_path = os.path.join(
self.etc_dir, "apps-available/critic-frontend-main.ini")
self.enabled_path = os.path.join(
self.etc_dir, "apps-enabled/critic-frontend-main.ini")
def install(self, data):
process_configuration_file(
"install", data, self.template_path, self.target_path)
os.symlink(self.target_path, self.enabled_path)
self.app_enabled = True
return self.restart()
def upgrade(self, arguments, data):
# If the configuration file doesn't exist, we're probably migrating the
# system from one web server to another, so run the whole installation
# procedure instead.
if not os.path.isfile(self.target_path):
return install(data)
process_configuration_file(
"upgrade", data, self.template_path, self.target_path, """\
The uWSGI front-end app definition is about to be updated. Please check that
no local modifications are being overwritten.
Current version: %(current)s
Updated version: %(updated)s
Please note that if the modifications are not installed, the system is likely
to break.
""")
return True
def undo(self):
if self.app_enabled:
os.unlink(self.enabled_path)
self.restart()
class Multiple():
def __init__(self, *services):
self.services = services
def prepare(self, *args):
return all(service.prepare(*args) for service in self.services)
def install(self, *args):
return all(service.install(*args) for service in self.services)
def upgrade(self, *args):
return all(service.upgrade(*args) for service in self.services)
def undo(self):
for service in self.services:
service.undo()
def start(self):
return all(service.start() for service in self.services)
def stop(self):
return all(service.stop() for service in self.services)
def restart(self):
return all(service.restart() for service in self.services)
def prepare(mode, args, data):
global arguments, instance
arguments = args
data["installation.httpd.username"] = "www-data"
data["installation.httpd.groupname"] = "www-data"
if installation.config.web_server_integration == "apache":
instance = Apache()
backend_service = Apache.service_name
elif installation.config.web_server_integration == "uwsgi":
instance = Multiple(uWSGIFrontend(), uWSGIBackend())
backend_service = uWSGIBackend.service_name
elif installation.config.web_server_integration == "nginx+uwsgi":
instance = Multiple(nginx(), uWSGIBackend())
backend_service = uWSGIBackend.service_name
else:
return True
data["installation.httpd.backend_service"] = backend_service
return instance.prepare(mode, arguments, data)
def install(data):
if instance:
return instance.install(data)
return True
def upgrade(arguments, data):
if instance:
return instance.upgrade(arguments, data)
return True
def undo():
if instance:
instance.undo()
map(os.unlink, created_file)
for target, backup in renamed:
os.rename(backup, target)
def finish(mode, arguments, data):
for target, backup in renamed:
os.unlink(backup)
def start():
if instance:
return instance.start()
return True
def stop():
if instance:
return instance.stop()
return True
================================================
FILE: installation/initd.py
================================================
# -*- mode: python; encoding: utf-8 -*-
#
# Copyright 2012 Jens Lindström, Opera Software ASA
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
import os
import os.path
import pwd
import grp
import subprocess
import installation
created_file = []
renamed = []
rclinks_added = False
servicemanager_started = False
servicemanager_stopped = False
def stop(identity="main"):
global servicemanager_stopped
servicemanager_stopped = True
print
try:
subprocess.check_call(["service", "critic-%s" % identity, "stop"])
except subprocess.CalledProcessError:
return False
return True
def start(identity="main"):
print
try:
subprocess.check_call(["service", "critic-%s" % identity, "start"])
except subprocess.CalledProcessError:
return False
global servicemanager_started
servicemanager_started = True
return True
def restart(identity="main"):
print
try:
subprocess.check_call(["service", "critic-%s" % identity, "restart"])
except subprocess.CalledProcessError:
return False
return True
def install(data):
global servicemanager_started, rclinks_added
source_path = os.path.join(installation.root_dir, "installation", "templates", "initd")
target_path = os.path.join("/etc", "init.d", "critic-main")
with open(target_path, "w") as target:
created_file.append(target_path)
os.chmod(target_path, 0755)
os.chown(target_path, installation.system.uid, installation.system.gid)
with open(source_path, "r") as source:
target.write((source.read().decode("utf-8") % data).encode("utf-8"))
subprocess.check_call(["update-rc.d", "critic-main", "defaults"])
rclinks_added = True
start()
return True
def upgrade(arguments, data):
source_path = os.path.join(installation.root_dir, "installation", "templates", "initd")
target_path = os.path.join("/etc", "init.d", "critic-main")
backup_path = os.path.join(os.path.dirname(target_path), "_" + os.path.basename(target_path))
source = open(source_path, "r").read().decode("utf-8") % data
target = open(target_path, "r").read().decode("utf-8")
system_uid = pwd.getpwnam(data["installation.system.username"]).pw_uid
system_gid = grp.getgrnam(data["installation.system.groupname"]).gr_gid
if source != target:
def generateVersion(label, path):
if label == "updated":
with open(path, "w") as target:
target.write(source.encode("utf-8"))
update_query = installation.utils.UpdateModifiedFile(
arguments,
message="""\
The SysV init script is about to be updated. Please check that no local
modifications are being overwritten.
Current version: %(current)s
Updated version: %(updated)s
Please note that if the modifications are not installed, the system is
likely to break.
""",
versions={ "current": target_path,
"updated": target_path + ".new" },
options=[ ("i", "install the updated version"),
("k", "keep the current version"),
("d", ("current", "updated")) ],
generateVersion=generateVersion)
write_target = update_query.prompt() == "i"
else:
write_target = False
if write_target:
print "Updated file: %s" % target_path
if not arguments.dry_run:
os.rename(target_path, backup_path)
renamed.append((target_path, backup_path))
with open(target_path, "w") as target:
created_file.append(target_path)
os.chmod(target_path, 0755)
os.chown(target_path, system_uid, system_gid)
target.write(source.encode("utf-8"))
return True
def undo():
if servicemanager_started:
stop()
elif servicemanager_stopped:
start()
map(os.unlink, created_file)
for target, backup in renamed: os.rename(backup, target)
if rclinks_added:
subprocess.check_call(["update-rc.d", "critic-main", "remove"])
def finish(mode, arguments, data):
for target, backup in renamed: os.unlink(backup)
================================================
FILE: installation/input.py
================================================
# -*- mode: python; encoding: utf-8 -*-
#
# Copyright 2012 Jens Lindström, Opera Software ASA
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
import sys
import inpututils
headless = False
def yes_or_no(prompt, default=None):
if headless:
if default is None:
print """
ERROR: yes/no input requested in headless mode!
Prompt: %s
""" % prompt
sys.exit(1)
else:
print "%s %s" % (prompt, "y" if default else "n")
return default
return inpututils.yes_or_no(prompt, default)
def string(prompt, default=None, check=None):
if headless:
if default is None:
print """
ERROR: string input requested in headless mode!
Prompt: %s
""" % prompt
sys.exit(1)
else:
print "%s %s" % (prompt, default)
if not check or inpututils.apply_check(check, default):
return default
else:
sys.exit(1)
return inpututils.string(prompt, default, check)
def password(prompt, default=None, twice=True):
if headless:
if default is None:
print """
ERROR: password input requested in headless mode!
Prompt: %s
""" % prompt
sys.exit(1)
else:
print "%s %s" % (prompt, "****")
return default
return inpututils.password(prompt, default, twice)
================================================
FILE: installation/lifecycle.json
================================================
{
"branch": "stable/1",
"stable": true
}
================================================
FILE: installation/migrate.py
================================================
# -*- mode: python; encoding: utf-8 -*-
#
# Copyright 2012 Jens Lindström, Opera Software ASA
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
import os
import sys
import json
import installation
def scripts_to_run(data):
git = data["installation.prereqs.git"]
old_sha1 = data["sha1"]
performed_migrations = data.get("migrations", [])
scripts = []
if os.path.exists("installation/migrations"):
for script in os.listdir("installation/migrations"):
if not script.endswith(".py"):
continue
if script in performed_migrations:
continue
script_path = os.path.join("installation/migrations", script)
if installation.utils.get_file_sha1(git, old_sha1, script_path) is not None:
# The migration script already existed when Critic was installed
# and there's thus no point in running it now.
continue
date_added = installation.utils.get_initial_commit_date(git, script_path)
scripts.append((date_added, script))
scripts.sort()
scripts = [script for (date_added, script) in scripts]
return scripts
def will_modify_dbschema(data):
for script in scripts_to_run(data):
if script.startswith("dbschema."):
return True
return False
def upgrade(arguments, data):
if "migrations" not in data:
data["migrations"] = []
for script in scripts_to_run(data):
script_path = os.path.join("installation/migrations", script)
print
print "Running %s ..." % script
if arguments.dry_run:
continue
env = os.environ.copy()
# This is "/etc/critic/main", set by upgrade.py, or something else
# if the --etc-dir/--identity arguments were used.
env["PYTHONPATH"] = sys.path[0] + ":" + installation.root_dir
installation.process.check_input([sys.executable, script_path,
"--uid=%s" % installation.system.uid,
"--gid=%d" % installation.system.gid],
stdin=json.dumps(data), env=env)
data["migrations"].append(script)
return True
================================================
FILE: installation/migrations/dbschema.altertable.branches.add.archived.py
================================================
# -*- mode: python; encoding: utf-8 -*-
#
# Copyright 2014 the Critic contributors, Opera Software ASA
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
import psycopg2
import argparse
import os
parser = argparse.ArgumentParser()
parser.add_argument("--uid", type=int)
parser.add_argument("--gid", type=int)
arguments = parser.parse_args()
os.setgid(arguments.gid)
os.setuid(arguments.uid)
import configuration
db = psycopg2.connect(**configuration.database.PARAMETERS)
cursor = db.cursor()
try:
# Check if the 'archived' column already exists.
cursor.execute("SELECT archived FROM branches")
except psycopg2.ProgrammingError:
db.rollback()
cursor.execute("""ALTER TABLE branches
ADD archived BOOLEAN NOT NULL DEFAULT FALSE""")
db.commit()
db.close()
================================================
FILE: installation/migrations/dbschema.altertable.changesets.parent.dropnotnull.py
================================================
# -*- mode: python; encoding: utf-8 -*-
#
# Copyright 2012 Jens Lindström, Opera Software ASA
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
import sys
import psycopg2
import json
import argparse
import os
parser = argparse.ArgumentParser()
parser.add_argument("--uid", type=int)
parser.add_argument("--gid", type=int)
arguments = parser.parse_args()
os.setgid(arguments.gid)
os.setuid(arguments.uid)
data = json.load(sys.stdin)
import configuration
db = psycopg2.connect(**configuration.database.PARAMETERS)
cursor = db.cursor()
# This command doesn't fail if the column already doesn't have a NOT
# NULL constraint, so no reason to catch errors or try to determine
# whether the constraint is there.
cursor.execute("ALTER TABLE changesets ALTER parent DROP NOT NULL")
db.commit()
db.close()
================================================
FILE: installation/migrations/dbschema.altertable.commentchainchanges.addressed_by.py
================================================
# -*- mode: python; encoding: utf-8 -*-
#
# Copyright 2012 Jens Lindström, Opera Software ASA
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
import sys
import psycopg2
import json
import argparse
import os
parser = argparse.ArgumentParser()
parser.add_argument("--uid", type=int)
parser.add_argument("--gid", type=int)
arguments = parser.parse_args()
os.setgid(arguments.gid)
os.setuid(arguments.uid)
data = json.load(sys.stdin)
db = psycopg2.connect(database="critic")
cursor = db.cursor()
try:
# Make sure the columns don't already exist.
cursor.execute("SELECT from_addressed_by, to_addressed_by FROM commentchainchanges")
# Above statement should have thrown a psycopg2.ProgrammingError, but it
# didn't, so just exit.
sys.exit(0)
except psycopg2.ProgrammingError:
db.rollback()
except:
raise
cursor.execute("""ALTER TABLE commentchainchanges
ADD from_addressed_by INTEGER REFERENCES commits,
ADD to_addressed_by INTEGER REFERENCES commits""")
db.commit()
db.close()
================================================
FILE: installation/migrations/dbschema.altertable.commentchainchanges.drop.review.py
================================================
# -*- mode: python; encoding: utf-8 -*-
#
# Copyright 2014 the Critic contributors, Opera Software ASA
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
import sys
import psycopg2
import json
import argparse
import os
parser = argparse.ArgumentParser()
parser.add_argument("--uid", type=int)
parser.add_argument("--gid", type=int)
arguments = parser.parse_args()
os.setgid(arguments.gid)
os.setuid(arguments.uid)
data = json.load(sys.stdin)
db = psycopg2.connect(database="critic")
cursor = db.cursor()
cursor.execute("""ALTER TABLE commentchainchanges
DROP COLUMN IF EXISTS review CASCADE""")
db.commit()
db.close()
================================================
FILE: installation/migrations/dbschema.altertable.commentchainlines.drop.commit.py
================================================
# -*- mode: python; encoding: utf-8 -*-
#
# Copyright 2012 Jens Lindström, Opera Software ASA
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
import sys
import psycopg2
import json
import argparse
import os
parser = argparse.ArgumentParser()
parser.add_argument("--uid", type=int)
parser.add_argument("--gid", type=int)
arguments = parser.parse_args()
os.setgid(arguments.gid)
os.setuid(arguments.uid)
data = json.load(sys.stdin)
db = psycopg2.connect(database="critic")
cursor = db.cursor()
try:
# Check if the 'commit' column already doesn't exist.
cursor.execute("SELECT commit FROM commentchainlines")
except psycopg2.ProgrammingError:
# Seems it doesn't, so just exit.
sys.exit(0)
cursor.execute("""ALTER TABLE commentchainlines DROP commit""")
db.commit()
db.close()
================================================
FILE: installation/migrations/dbschema.altertable.comments.time.setdefaultnow.py
================================================
# -*- mode: python; encoding: utf-8 -*-
#
# Copyright 2016 the Critic contributors, Opera Software ASA
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
import sys
import psycopg2
import json
import argparse
import os
parser = argparse.ArgumentParser()
parser.add_argument("--uid", type=int)
parser.add_argument("--gid", type=int)
arguments = parser.parse_args()
os.setgid(arguments.gid)
os.setuid(arguments.uid)
data = json.load(sys.stdin)
import configuration
db = psycopg2.connect(**configuration.database.PARAMETERS)
cursor = db.cursor()
# This command doesn't fail if the column already has a DEFAULT, so no reason to
# catch errors or try to determine whether the constraint is there.
cursor.execute("ALTER TABLE comments ALTER time SET DEFAULT NOW()")
db.commit()
db.close()
================================================
FILE: installation/migrations/dbschema.altertable.previousreachable.rebase.ondeletecascade.py
================================================
# -*- mode: python; encoding: utf-8 -*-
#
# Copyright 2012 Jens Lindström, Opera Software ASA
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
import sys
import psycopg2
import json
import argparse
import os
parser = argparse.ArgumentParser()
parser.add_argument("--uid", type=int)
parser.add_argument("--gid", type=int)
arguments = parser.parse_args()
os.setgid(arguments.gid)
os.setuid(arguments.uid)
data = json.load(sys.stdin)
db = psycopg2.connect(database="critic")
cursor = db.cursor()
# This command doesn't fail if the foreign key constraint already has
# "on delete cascade", and there's really no reason to try to figure
# if it has; easier to just drop it and re-add it.
cursor.execute("""ALTER TABLE previousreachable
DROP CONSTRAINT previousreachable_rebase_fkey,
ADD FOREIGN KEY (rebase) REFERENCES reviewrebases (id) ON DELETE CASCADE""")
db.commit()
db.close()
================================================
FILE: installation/migrations/dbschema.altertable.repositories.drop.branch.py
================================================
# -*- mode: python; encoding: utf-8 -*-
#
# Copyright 2014 the Critic contributors, Opera Software ASA
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
import sys
import psycopg2
import json
import argparse
import os
parser = argparse.ArgumentParser()
parser.add_argument("--uid", type=int)
parser.add_argument("--gid", type=int)
arguments = parser.parse_args()
os.setgid(arguments.gid)
os.setuid(arguments.uid)
data = json.load(sys.stdin)
db = psycopg2.connect(database="critic")
cursor = db.cursor()
try:
# Check if the 'branch' column already doesn't exist.
cursor.execute("SELECT branch FROM repositories")
except psycopg2.ProgrammingError:
# Seems it doesn't, so just exit.
sys.exit(0)
cursor.execute("""ALTER TABLE repositories DROP branch""")
db.commit()
db.close()
================================================
FILE: installation/migrations/dbschema.altertable.repositories.drop.relay.py
================================================
# -*- mode: python; encoding: utf-8 -*-
#
# Copyright 2013 Jens Lindström, Opera Software ASA
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
import sys
import psycopg2
import argparse
import os
import shutil
parser = argparse.ArgumentParser()
parser.add_argument("--uid", type=int)
parser.add_argument("--gid", type=int)
arguments = parser.parse_args()
os.setgid(arguments.gid)
os.setuid(arguments.uid)
import configuration
db = psycopg2.connect(**configuration.database.PARAMETERS)
cursor = db.cursor()
try:
# Check if the 'relay' column already doesn't exist (and also fetch all the
# relay paths for use below.)
cursor.execute("SELECT relay FROM repositories")
except psycopg2.ProgrammingError:
# Seems it doesn't exist, so just exit.
sys.exit(0)
failed = False
for (relay_path,) in cursor:
try:
shutil.rmtree(relay_path)
except OSError as error:
print ("WARNING: Failed to remove directory: %s\n Error: %s"
% (relay_path, error))
failed = True
if failed:
print """
Some obsolete directories could not be removed. They will no longer be used by
Critic, so you probably want to look into deleting them manually.
"""
cursor.execute("ALTER TABLE repositories DROP relay")
db.commit()
db.close()
================================================
FILE: installation/migrations/dbschema.altertable.reviewfilechanges.rename-columns.py
================================================
# -*- mode: python; encoding: utf-8 -*-
#
# Copyright 2013 Jens Lindström, Opera Software ASA
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
import sys
import psycopg2
import json
import argparse
import os
parser = argparse.ArgumentParser()
parser.add_argument("--uid", type=int)
parser.add_argument("--gid", type=int)
arguments = parser.parse_args()
os.setgid(arguments.gid)
os.setuid(arguments.uid)
data = json.load(sys.stdin)
db = psycopg2.connect(database="critic")
cursor = db.cursor()
try:
# Make sure the columns don't already exist.
cursor.execute("SELECT from_state, to_state FROM reviewfilechanges")
# Above statement should have thrown a psycopg2.ProgrammingError, but it
# didn't, so just exit.
sys.exit(0)
except psycopg2.ProgrammingError:
db.rollback()
except:
raise
cursor.execute("""ALTER TABLE reviewfilechanges
RENAME "from" TO from_state""")
cursor.execute("""ALTER TABLE reviewfilechanges
RENAME "to" TO to_state""")
db.commit()
db.close()
================================================
FILE: installation/migrations/dbschema.altertable.reviewmergeconfirmations.add.tail.py
================================================
# -*- mode: python; encoding: utf-8 -*-
#
# Copyright 2013 Jens Lindström
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
import psycopg2
import argparse
import os
parser = argparse.ArgumentParser()
parser.add_argument("--uid", type=int)
parser.add_argument("--gid", type=int)
arguments = parser.parse_args()
os.setgid(arguments.gid)
os.setuid(arguments.uid)
import configuration
db = psycopg2.connect(**configuration.database.PARAMETERS)
cursor = db.cursor()
try:
# Check if the 'tail' column already exists.
cursor.execute("SELECT tail FROM reviewmergeconfirmations")
except psycopg2.ProgrammingError:
db.rollback()
cursor.execute("""ALTER TABLE reviewmergeconfirmations
ADD tail INTEGER REFERENCES commits ON DELETE CASCADE""")
db.commit()
db.close()
================================================
FILE: installation/migrations/dbschema.altertable.reviewrebases.add.equivalent_merge.py
================================================
# -*- mode: python; encoding: utf-8 -*-
#
# Copyright 2014 the Critic contributors, Opera Software ASA
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
import sys
import psycopg2
import argparse
import os
import subprocess
parser = argparse.ArgumentParser()
parser.add_argument("--uid", type=int)
parser.add_argument("--gid", type=int)
arguments = parser.parse_args()
os.setgid(arguments.gid)
os.setuid(arguments.uid)
import configuration
db = psycopg2.connect(**configuration.database.PARAMETERS)
cursor = db.cursor()
try:
# Check if the 'equivalent_merge' column already exists.
cursor.execute("SELECT equivalent_merge FROM reviewrebases")
except psycopg2.ProgrammingError:
db.rollback()
else:
# No error; change appears to have been made already.
db.close()
sys.exit(0)
def fetch_commit_sha1(commit_id):
cursor.execute("SELECT sha1 FROM commits WHERE id=%s", (commit_id,))
(sha1,) = cursor.fetchone()
return sha1
def get_parent_sha1s(repository_path, sha1):
output = subprocess.check_output(
[configuration.executables.GIT, "log", "-1", "--format=%P", sha1],
cwd=repository_path)
return output.strip().split()
def is_ancestor_of(repository_path, ancestor_sha1, descendant_sha1):
try:
merge_base_sha1 = subprocess.check_output(
[configuration.executables.GIT, "merge-base",
ancestor_sha1, descendant_sha1],
cwd=repository_path).strip()
except subprocess.CalledProcessError:
return False
else:
return merge_base_sha1 == ancestor_sha1
cursor.execute("""ALTER TABLE reviewrebases
ADD equivalent_merge INTEGER REFERENCES commits""")
#
# Move all references to equivalent merges stored in the |old_head| column of
# existing review rebases over to the new |equivalent_merge| column, and restore
# the value of the |old_head| to be the actual head of the review branch bef
gitextract_90xaov2p/ ├── .gitignore ├── .gitmodules ├── CONTRIBUTORS ├── COPYING ├── INSTALL ├── README.md ├── documentation/ │ ├── concepts.txt │ ├── tutorials.txt │ └── user_faq.md ├── extend.py ├── install.py ├── installation/ │ ├── __init__.py │ ├── admin.py │ ├── config.py │ ├── criticctl.py │ ├── data/ │ │ ├── comments.pgsql │ │ ├── dbschema.base.sql │ │ ├── dbschema.changesets.sql │ │ ├── dbschema.comments.sql │ │ ├── dbschema.extensions.sql │ │ ├── dbschema.filters.sql │ │ ├── dbschema.git.sql │ │ ├── dbschema.news.sql │ │ ├── dbschema.preferences.sql │ │ ├── dbschema.reviews.sql │ │ ├── dbschema.trackedbranches.sql │ │ └── dbschema.users.sql │ ├── database.py │ ├── extensions.py │ ├── externals/ │ │ ├── .gitignore │ │ ├── MIT-LICENSE.Chosen.md │ │ └── MIT-LICENSE.jQuery.txt │ ├── files.py │ ├── git.py │ ├── httpd.py │ ├── initd.py │ ├── input.py │ ├── lifecycle.json │ ├── migrate.py │ ├── migrations/ │ │ ├── dbschema.altertable.branches.add.archived.py │ │ ├── dbschema.altertable.changesets.parent.dropnotnull.py │ │ ├── dbschema.altertable.commentchainchanges.addressed_by.py │ │ ├── dbschema.altertable.commentchainchanges.drop.review.py │ │ ├── dbschema.altertable.commentchainlines.drop.commit.py │ │ ├── dbschema.altertable.comments.time.setdefaultnow.py │ │ ├── dbschema.altertable.previousreachable.rebase.ondeletecascade.py │ │ ├── dbschema.altertable.repositories.drop.branch.py │ │ ├── dbschema.altertable.repositories.drop.relay.py │ │ ├── dbschema.altertable.reviewfilechanges.rename-columns.py │ │ ├── dbschema.altertable.reviewmergeconfirmations.add.tail.py │ │ ├── dbschema.altertable.reviewrebases.add.equivalent_merge.py │ │ ├── dbschema.altertable.reviewrebases.add.replayed_rebase.py │ │ ├── dbschema.altertable.reviewrecipientfilters.uid-can-be-null.py │ │ ├── dbschema.altertable.reviews.add.origin.py │ │ ├── dbschema.altertable.systemidentities.add.installed_sha1.installed_at.py │ │ ├── dbschema.altertable.systemidentities.url-prefix.py │ │ ├── dbschema.altertable.usergitemails.py │ │ ├── dbschema.altertable.usersessions.add.labels.py │ │ ├── dbschema.createindex.misc.py │ │ ├── dbschema.createtable.accesstokens.py │ │ ├── dbschema.createtable.knownremotes.py │ │ ├── dbschema.createtable.scheduledreviewbrancharchivals.py │ │ ├── dbschema.createtable.timezones.py │ │ ├── dbschema.createtable.useremails.py │ │ ├── dbschema.createtable.usersessions.py │ │ ├── dbschema.createtables.accesscontrol.py │ │ ├── dbschema.droptable.knownhosts.py │ │ ├── dbschema.extension-filterhook-role.py │ │ ├── dbschema.external-authentication.py │ │ ├── dbschema.files-and-directories.py │ │ ├── dbschema.fixup-extensionroles.py │ │ ├── dbschema.per-repository-or-filter-preferences.py │ │ ├── dbschema.review-constraints-tweaking.py │ │ ├── git.check-keepalive-references.py │ │ ├── git.clean-up-temporary-references.py │ │ ├── git.convert-replays-into-keepalives.py │ │ ├── git.rename-keepalive-chain.py │ │ ├── installation.config-pyc-file-permissions.py │ │ ├── news.filter-system-rewrite.py │ │ ├── news.review-branch-archival.py │ │ ├── news.review-quick-search.py │ │ └── preference.commit.diff.rulerColumn.py │ ├── paths.py │ ├── prefs.py │ ├── prereqs.py │ ├── process.py │ ├── qs/ │ │ ├── __init__.py │ │ ├── data.py │ │ └── sqlite.py │ ├── smtp.py │ ├── system.py │ ├── templates/ │ │ ├── apache/ │ │ │ ├── site.both │ │ │ ├── site.http │ │ │ └── site.https │ │ ├── configuration/ │ │ │ ├── __init__.py │ │ │ ├── auth.py │ │ │ ├── base.py │ │ │ ├── database.py │ │ │ ├── debug.py │ │ │ ├── executables.py │ │ │ ├── extensions.py │ │ │ ├── limits.py │ │ │ ├── mimetypes.py │ │ │ ├── paths.py │ │ │ ├── services.py │ │ │ ├── smtp-credentials.json │ │ │ └── smtp.py │ │ ├── criticctl │ │ ├── initd │ │ ├── nginx/ │ │ │ ├── site.both │ │ │ ├── site.http │ │ │ └── site.https │ │ └── uwsgi/ │ │ ├── app.backend.ini │ │ ├── app.frontend.ini.both │ │ ├── app.frontend.ini.http │ │ └── app.frontend.ini.https │ └── utils.py ├── pylint.rc ├── pythonversion.py ├── quickstart.py ├── src/ │ ├── api/ │ │ ├── __init__.py │ │ ├── accesscontrolprofile.py │ │ ├── accesstoken.py │ │ ├── apierror.py │ │ ├── apiobject.py │ │ ├── batch.py │ │ ├── branch.py │ │ ├── changeset.py │ │ ├── comment.py │ │ ├── commit.py │ │ ├── commitset.py │ │ ├── config.py │ │ ├── critic.py │ │ ├── extension.py │ │ ├── file.py │ │ ├── filechange.py │ │ ├── filecontent.py │ │ ├── filediff.py │ │ ├── filters.py │ │ ├── impl/ │ │ │ ├── __init__.py │ │ │ ├── accesscontrolprofile.py │ │ │ ├── accesstoken.py │ │ │ ├── apiobject.py │ │ │ ├── batch.py │ │ │ ├── branch.py │ │ │ ├── branch_unittest.py │ │ │ ├── changeset.py │ │ │ ├── changeset_unittest.py │ │ │ ├── comment.py │ │ │ ├── comment_unittest.py │ │ │ ├── commit.py │ │ │ ├── commit_unittest.py │ │ │ ├── commitset.py │ │ │ ├── commitset_unittest.py │ │ │ ├── config_unittest.py │ │ │ ├── critic.py │ │ │ ├── extension.py │ │ │ ├── file.py │ │ │ ├── filechange.py │ │ │ ├── filechange_unittest.py │ │ │ ├── filecontent.py │ │ │ ├── filediff.py │ │ │ ├── filediff_unittest.py │ │ │ ├── filters.py │ │ │ ├── labeledaccesscontrolprofile.py │ │ │ ├── log/ │ │ │ │ ├── __init__.py │ │ │ │ ├── partition.py │ │ │ │ ├── partition_unittest.py │ │ │ │ ├── rebase.py │ │ │ │ └── rebase_unittest.py │ │ │ ├── reply.py │ │ │ ├── reply_unittest.py │ │ │ ├── repository.py │ │ │ ├── repository_unittest.py │ │ │ ├── review.py │ │ │ ├── review_unittest.py │ │ │ ├── reviewablefilechange.py │ │ │ ├── reviewsummary.py │ │ │ ├── user.py │ │ │ └── user_unittest.py │ │ ├── labeledaccesscontrolprofile.py │ │ ├── log/ │ │ │ ├── __init__.py │ │ │ ├── partition.py │ │ │ └── rebase.py │ │ ├── preference.py │ │ ├── reply.py │ │ ├── repository.py │ │ ├── review.py │ │ ├── reviewablefilechange.py │ │ ├── reviewsummary.py │ │ ├── transaction/ │ │ │ ├── __init__.py │ │ │ ├── accesscontrolprofile.py │ │ │ ├── accesstoken.py │ │ │ ├── comment.py │ │ │ ├── filters.py │ │ │ ├── labeledaccesscontrolprofile.py │ │ │ ├── reply.py │ │ │ ├── review.py │ │ │ └── user.py │ │ └── user.py │ ├── auth/ │ │ ├── __init__.py │ │ ├── accesscontrol.py │ │ ├── database.py │ │ ├── databases/ │ │ │ ├── __init__.py │ │ │ ├── accesstokensdb.py │ │ │ ├── internaldb.py │ │ │ └── ldapdb.py │ │ ├── oauth.py │ │ ├── provider.py │ │ ├── providers/ │ │ │ ├── __init__.py │ │ │ ├── dummy.py │ │ │ ├── github.py │ │ │ └── google.py │ │ └── session.py │ ├── background/ │ │ ├── __init__.py │ │ ├── branchtracker.py │ │ ├── branchtrackerhook.py │ │ ├── changeset.py │ │ ├── daemon.py │ │ ├── extensionrunner.py │ │ ├── extensiontasks.py │ │ ├── githook.py │ │ ├── highlight.py │ │ ├── maildelivery.py │ │ ├── maintenance.py │ │ ├── servicemanager.py │ │ ├── utils.py │ │ ├── wait-for-pidfiles.py │ │ └── watchdog.py │ ├── base.py │ ├── base_unittest.py │ ├── changeset/ │ │ ├── __init__.py │ │ ├── client.py │ │ ├── create.py │ │ ├── detectmoves.py │ │ ├── html.py │ │ ├── load.py │ │ ├── process.py │ │ ├── text.py │ │ └── utils.py │ ├── cli.py │ ├── communicate.py │ ├── coverage.py │ ├── critic.py │ ├── data/ │ │ └── preferences.json │ ├── dbaccess.py │ ├── dbutils/ │ │ ├── __init__.py │ │ ├── branch.py │ │ ├── database.py │ │ ├── database_unittest.py │ │ ├── paths.py │ │ ├── review.py │ │ ├── session.py │ │ ├── system.py │ │ ├── timezones.py │ │ ├── unittest.py │ │ └── user.py │ ├── diff/ │ │ ├── __init__.py │ │ ├── analyze.py │ │ ├── context.py │ │ ├── html.py │ │ ├── merge.py │ │ └── parse.py │ ├── diffutils.py │ ├── extensions/ │ │ ├── __init__.py │ │ ├── execute.py │ │ ├── extension.py │ │ ├── installation.py │ │ ├── manifest.py │ │ ├── resource.py │ │ ├── role/ │ │ │ ├── __init__.py │ │ │ ├── filterhook.py │ │ │ ├── inject.py │ │ │ ├── page.py │ │ │ └── processcommits.py │ │ ├── unittest.py │ │ └── utils.py │ ├── gitutils.py │ ├── gitutils_unittest.py │ ├── hooks/ │ │ └── pre-receive │ ├── htmlutils.py │ ├── htmlutils_unittest.py │ ├── index.py │ ├── inpututils.py │ ├── jsonapi/ │ │ ├── __init__.py │ │ ├── check.py │ │ ├── documentation.py │ │ └── v1/ │ │ ├── README.txt │ │ ├── __init__.py │ │ ├── accesscontrolprofiles.py │ │ ├── accesstokens.py │ │ ├── batches.py │ │ ├── branches.py │ │ ├── changesets.py │ │ ├── comments.py │ │ ├── commits.py │ │ ├── documentation.py │ │ ├── extensions.py │ │ ├── filechanges.py │ │ ├── filecontents.py │ │ ├── filediffs.py │ │ ├── files.py │ │ ├── labeledaccesscontrolprofiles.py │ │ ├── rebases.py │ │ ├── replies.py │ │ ├── repositories.py │ │ ├── reviewablefilechanges.py │ │ ├── reviews.py │ │ ├── reviewsummaries.py │ │ ├── sessions.py │ │ └── users.py │ ├── library/ │ │ └── js/ │ │ └── v8/ │ │ ├── critic-batch.js │ │ ├── critic-branch.js │ │ ├── critic-changeset.js │ │ ├── critic-cli.js │ │ ├── critic-comment.js │ │ ├── critic-commitset.js │ │ ├── critic-dashboard.js │ │ ├── critic-file.js │ │ ├── critic-filters.js │ │ ├── critic-filterstransaction.js │ │ ├── critic-git.js │ │ ├── critic-html.js │ │ ├── critic-launcher-fork.js │ │ ├── critic-launcher.js │ │ ├── critic-log.js │ │ ├── critic-mail.js │ │ ├── critic-review.js │ │ ├── critic-statistics.js │ │ ├── critic-storage.js │ │ ├── critic-text.js │ │ ├── critic-trackedbranch.js │ │ ├── critic-user.js │ │ └── critic.js │ ├── linkify.py │ ├── log/ │ │ ├── __init__.py │ │ ├── commitset.py │ │ └── html.py │ ├── mailutils.py │ ├── maintenance/ │ │ ├── __init__.py │ │ ├── check-branches.py │ │ ├── check-commits.py │ │ ├── configtest.py │ │ ├── criticctl.py │ │ ├── dumppreferences.py │ │ └── progress.py │ ├── operation/ │ │ ├── __init__.py │ │ ├── addrepository.py │ │ ├── applyfilters.py │ │ ├── autocompletedata.py │ │ ├── basictypes.py │ │ ├── basictypes_unittest.py │ │ ├── blame.py │ │ ├── brancharchiving.py │ │ ├── checkrebase.py │ │ ├── createcomment.py │ │ ├── createreview.py │ │ ├── draftchanges.py │ │ ├── editresource.py │ │ ├── extensioninstallation.py │ │ ├── fetchlines.py │ │ ├── manipulateassignments.py │ │ ├── manipulatecomment.py │ │ ├── manipulatefilters.py │ │ ├── manipulatereview.py │ │ ├── manipulateuser.py │ │ ├── markfiles.py │ │ ├── miscellaneous.py │ │ ├── news.py │ │ ├── rebasereview.py │ │ ├── recipientfilter.py │ │ ├── registeruser.py │ │ ├── savesettings.py │ │ ├── searchreview.py │ │ ├── servicemanager.py │ │ ├── trackedbranch.py │ │ ├── typechecker.py │ │ ├── typechecker_unittest.py │ │ ├── unittest.py │ │ └── usersession.py │ ├── page/ │ │ ├── __init__.py │ │ ├── addrepository.py │ │ ├── basic.py │ │ ├── branches.py │ │ ├── checkbranch.py │ │ ├── config.py │ │ ├── confirmmerge.py │ │ ├── createreview.py │ │ ├── createuser.py │ │ ├── dashboard.py │ │ ├── editresource.py │ │ ├── filterchanges.py │ │ ├── home.py │ │ ├── loadmanifest.py │ │ ├── login.py │ │ ├── manageextensions.py │ │ ├── managereviewers.py │ │ ├── news.py │ │ ├── parameters.py │ │ ├── processcommits.py │ │ ├── rebasetrackingreview.py │ │ ├── repositories.py │ │ ├── search.py │ │ ├── services.py │ │ ├── showbatch.py │ │ ├── showbranch.py │ │ ├── showcomment.py │ │ ├── showcommit.py │ │ ├── showfile.py │ │ ├── showfilters.py │ │ ├── showreview.py │ │ ├── showreviewlog.py │ │ ├── showtree.py │ │ ├── statistics.py │ │ ├── tutorial.py │ │ ├── utils.py │ │ └── verifyemail.py │ ├── profiling.py │ ├── request.py │ ├── resources/ │ │ ├── .gitattributes │ │ ├── autocomplete.js │ │ ├── basic.css │ │ ├── basic.js │ │ ├── branches.css │ │ ├── branches.js │ │ ├── changeset.css │ │ ├── changeset.js │ │ ├── checkbranch.css │ │ ├── checkbranch.js │ │ ├── comment.css │ │ ├── comment.js │ │ ├── config.css │ │ ├── config.js │ │ ├── confirmmerge.css │ │ ├── confirmmerge.js │ │ ├── createreview.css │ │ ├── createreview.js │ │ ├── createuser.css │ │ ├── createuser.js │ │ ├── dashboard.css │ │ ├── dashboard.js │ │ ├── diff.css │ │ ├── editresource.css │ │ ├── editresource.js │ │ ├── filterchanges.css │ │ ├── filterchanges.js │ │ ├── home.css │ │ ├── home.js │ │ ├── log.css │ │ ├── log.js │ │ ├── login.css │ │ ├── login.js │ │ ├── manageextensions.css │ │ ├── manageextensions.js │ │ ├── managereviewers.css │ │ ├── managereviewers.js │ │ ├── message.css │ │ ├── newrepository.css │ │ ├── newrepository.js │ │ ├── news.css │ │ ├── news.js │ │ ├── overrides.css │ │ ├── rebasetrackingreview.css │ │ ├── rebasetrackingreview.js │ │ ├── repositories.css │ │ ├── repositories.js │ │ ├── review.css │ │ ├── review.js │ │ ├── reviewfilters.js │ │ ├── ruler.js │ │ ├── search.css │ │ ├── search.js │ │ ├── services.css │ │ ├── services.js │ │ ├── showbatch.css │ │ ├── showbranch.css │ │ ├── showcomment.js │ │ ├── showfile.css │ │ ├── showfile.js │ │ ├── showreview.css │ │ ├── showreview.js │ │ ├── showreviewlog.css │ │ ├── showtree.css │ │ ├── statistics.css │ │ ├── syntax.css │ │ ├── tabify.css │ │ ├── tabify.js │ │ ├── third-party/ │ │ │ ├── chosen.css │ │ │ ├── chosen.js │ │ │ ├── jquery-ui-1.10.2.custom.css │ │ │ └── jquery-ui-autocomplete-html.js │ │ ├── tutorial.css │ │ ├── tutorial.js │ │ └── whitespace.css │ ├── reviewing/ │ │ ├── __init__.py │ │ ├── comment/ │ │ │ ├── __init__.py │ │ │ └── propagate.py │ │ ├── filters.py │ │ ├── html.py │ │ ├── mail.py │ │ ├── rebase.py │ │ └── utils.py │ ├── run_unittest.py │ ├── syntaxhighlight/ │ │ ├── __init__.py │ │ ├── clexer.py │ │ ├── context.py │ │ ├── cpp.py │ │ ├── generate.py │ │ ├── generic.py │ │ └── request.py │ ├── textformatting.py │ ├── textutils.py │ ├── textutils_unittest.py │ ├── tutorials/ │ │ ├── administration.txt │ │ ├── archival.txt │ │ ├── checkbranch.txt │ │ ├── customization.txt │ │ ├── extensions-api.txt │ │ ├── extensions.txt │ │ ├── external-authentication.txt │ │ ├── filters.txt │ │ ├── rebasing.txt │ │ ├── reconfiguring.txt │ │ ├── repository.txt │ │ ├── requesting.txt │ │ ├── reviewing.txt │ │ └── search.txt │ ├── urlutils.py │ ├── wsgi.py │ └── wsgistartup.py ├── testing/ │ ├── USAGE.md │ ├── __init__.py │ ├── __main__.py │ ├── expect.py │ ├── findtests.py │ ├── flags/ │ │ ├── addrepository-has-mirror-parameter.flag │ │ ├── fixed-batch-preview.flag │ │ ├── is-testing.flag │ │ ├── pwd-independence.flag │ │ ├── reliable-admin-newswriter.flag │ │ ├── reliable-git-emails.flag │ │ ├── system-recipients.flag │ │ └── web-server-integration.flag │ ├── frontend.py │ ├── input/ │ │ ├── SystemExtension/ │ │ │ ├── MANIFEST │ │ │ ├── check.js │ │ │ └── resources/ │ │ │ └── HelloWorld.txt │ │ ├── TestExtension/ │ │ │ ├── MANIFEST │ │ │ ├── MailTransaction.js │ │ │ ├── Review.list.js │ │ │ ├── echo.js │ │ │ ├── empty.js │ │ │ ├── error.compilation.js │ │ │ ├── error.runtime.js │ │ │ ├── evaluate.js │ │ │ ├── filterhook.js │ │ │ ├── inject.js │ │ │ ├── nothandled.js │ │ │ ├── processcommits.js │ │ │ ├── resources/ │ │ │ │ ├── hello.world.js │ │ │ │ ├── helloworld.css │ │ │ │ └── helloworld.html │ │ │ ├── restrictions.js │ │ │ └── version.js │ │ ├── binary │ │ ├── customization/ │ │ │ ├── githook.py │ │ │ └── linktypes.py │ │ ├── empty.txt │ │ ├── service_log_filter.py │ │ ├── service_synchronization_helper.py │ │ └── syntaxhighlight/ │ │ └── example.cpp │ ├── local.py │ ├── mailbox.py │ ├── main.py │ ├── password-invalid │ ├── password-testing │ ├── quickstart.py │ ├── repository.py │ ├── tests/ │ │ └── 001-main/ │ │ ├── 000-install.py │ │ ├── 001-empty/ │ │ │ ├── 001-anonymous/ │ │ │ │ ├── 001-dashboard.py │ │ │ │ ├── 002-branches.py │ │ │ │ ├── 003-search.py │ │ │ │ ├── 004-config.py │ │ │ │ ├── 005-tutorial.py │ │ │ │ ├── 006-news.py │ │ │ │ ├── 007-home.py │ │ │ │ ├── 008-repositories.py │ │ │ │ ├── 009-services.py │ │ │ │ ├── 010-createreview.py │ │ │ │ ├── 011-manageextensions.py │ │ │ │ ├── 012-statistics.py │ │ │ │ ├── 013-static-resource.py │ │ │ │ └── 100-preferences/ │ │ │ │ ├── 001-commit.diff.rulerColumn.py │ │ │ │ ├── 002-review.defaultOptOut.py │ │ │ │ ├── 003-timezone.py │ │ │ │ └── __init__.py │ │ │ ├── 002-authenticated/ │ │ │ │ ├── 001-dashboard.py │ │ │ │ ├── 002-branches.py │ │ │ │ ├── 003-search.py │ │ │ │ ├── 004-config.py │ │ │ │ ├── 005-tutorial.py │ │ │ │ ├── 006-news.py │ │ │ │ ├── 007-home.py │ │ │ │ ├── 008-repositories.py │ │ │ │ ├── 009-services.py │ │ │ │ ├── 010-createreview.py │ │ │ │ ├── 011-manageextensions.py │ │ │ │ ├── 012-statistics.py │ │ │ │ └── 100-preferences/ │ │ │ │ ├── 001-commit.diff.rulerColumn.py │ │ │ │ ├── 002-review.defaultOptOut.py │ │ │ │ ├── 003-timezone.py │ │ │ │ └── __init__.py │ │ │ ├── 003-criticctl/ │ │ │ │ ├── 001-basic.py │ │ │ │ ├── 002-adduser-deluser.py │ │ │ │ ├── 003-addrole-delrole.py │ │ │ │ ├── 004-listusers.py │ │ │ │ ├── 005-configtest.py │ │ │ │ └── 006-restart.py │ │ │ └── 004-mixed/ │ │ │ ├── 001-newswriter.py │ │ │ ├── 002-email.py │ │ │ ├── 003-oauth.py │ │ │ ├── 004-password.py │ │ │ ├── 005-accesstoken.py │ │ │ ├── 006-accesscontrol-http.py │ │ │ ├── 007-json-session.py │ │ │ └── __init__.py │ │ ├── 002-createrepository.py │ │ ├── 003-self/ │ │ │ ├── 001-rulerColumn.py │ │ │ ├── 002-emptyfile.py │ │ │ ├── 003-binaryfile.py │ │ │ ├── 004-createreview.py │ │ │ ├── 004-first-review-created/ │ │ │ │ ├── 001-addreviewfilters-bogus.py │ │ │ │ ├── 002-review-archival.py │ │ │ │ └── __init__.py │ │ │ ├── 005-checkbranch.py │ │ │ ├── 006-showreview-reviewfilter.py │ │ │ ├── 007-http-backend.py │ │ │ ├── 008-initial-commit-diff.py │ │ │ ├── 009-fetchremotebranch.py │ │ │ ├── 010-linkification.py │ │ │ ├── 011-linkification-custom.py │ │ │ ├── 012-createreview-recipients.py │ │ │ ├── 012-replayrebase.py │ │ │ ├── 014-non-ascii-filenames.py │ │ │ ├── 015-non-ascii-line-diff.py │ │ │ ├── 016-showcommit-ranges.py │ │ │ ├── 017-showcommit-merge-replay.py │ │ │ ├── 018-detect-moves-no-moved-code.py │ │ │ ├── 019-showtree-showfile-bogus.py │ │ │ ├── 020-fixup-review-via-push.py │ │ │ ├── 020-reviewrebase.py │ │ │ ├── 021-updatereview-bogus.py │ │ │ ├── 022-removereviewfilter-bogus.py │ │ │ ├── 024-customizations.githook.py │ │ │ ├── 025-trackedbranch.py │ │ │ ├── 026-searchreview.py │ │ │ ├── 027-whitespace-filenames.py │ │ │ ├── 028-gitemails.py │ │ │ ├── 029-log-bogus.py │ │ │ ├── 030-trackingreview.py │ │ │ ├── 031-fetchlines-bom.py │ │ │ ├── 032-download.py │ │ │ ├── 033-propagation-vs-rebase.py │ │ │ ├── 100-reviewing/ │ │ │ │ ├── 001-comments.basic.py │ │ │ │ └── __init__.py │ │ │ ├── 101-keepalives.py │ │ │ ├── 200-json/ │ │ │ │ ├── 001-users.py │ │ │ │ ├── 002-branches.py │ │ │ │ ├── 003-repositories.py │ │ │ │ ├── 004-review.py │ │ │ │ ├── 005-commits.py │ │ │ │ ├── 006-changesets.py │ │ │ │ ├── 006-comments.py │ │ │ │ ├── 007-filechanges.py │ │ │ │ ├── 007-replies.py │ │ │ │ ├── 008-batches.py │ │ │ │ └── __init__.py │ │ │ └── __init__.py │ │ ├── 004-extensions/ │ │ │ ├── 001-enable.py │ │ │ ├── 002-tests/ │ │ │ │ ├── 001-tutorial.py │ │ │ │ ├── 002-manageextensions.py │ │ │ │ ├── 003-install-TestExtension.py │ │ │ │ ├── 004-TestExtension/ │ │ │ │ │ ├── 001-echo.py │ │ │ │ │ ├── 002-nothandled.py │ │ │ │ │ ├── 003-empty.py │ │ │ │ │ ├── 004-Review.list.py │ │ │ │ │ ├── 005-MailTransaction.py │ │ │ │ │ ├── 006-inject.py │ │ │ │ │ ├── 007-version.py │ │ │ │ │ ├── 008-processcommits.py │ │ │ │ │ ├── 009-error-messages.py │ │ │ │ │ ├── 010-restrictions.py │ │ │ │ │ ├── 011-User.py │ │ │ │ │ ├── 012-resources.py │ │ │ │ │ ├── 013-storage.py │ │ │ │ │ ├── 014-Repository.run.py │ │ │ │ │ ├── 015-filterhook.py │ │ │ │ │ ├── 016-accesscontrol.py │ │ │ │ │ └── 999-missing.py │ │ │ │ ├── 005-install-SystemExtension.py │ │ │ │ └── 006-manifest-checks.py │ │ │ └── __init__.py │ │ ├── 005-unittests/ │ │ │ ├── 001-local/ │ │ │ │ ├── 001-independence.py │ │ │ │ ├── 002-operation.py │ │ │ │ ├── 005-dbutils.database.py │ │ │ │ └── __init__.py │ │ │ ├── 002-api/ │ │ │ │ ├── 001-commit.py │ │ │ │ ├── 002-review.py │ │ │ │ ├── 003-user.py │ │ │ │ ├── 004-config.py │ │ │ │ ├── 005-log.partition.py │ │ │ │ ├── 006-log.rebase.py │ │ │ │ ├── 007-repository.py │ │ │ │ ├── 008-branch.py │ │ │ │ ├── 009-commitset.py │ │ │ │ ├── 010-comment.py │ │ │ │ ├── 011-reply.py │ │ │ │ ├── 012-changeset.py │ │ │ │ ├── 013-filechange.py │ │ │ │ └── 014-filediff.py │ │ │ └── 003-other/ │ │ │ ├── 001-dbutils.database.py │ │ │ └── __init__.py │ │ └── 900-uninstall-reinstall.py │ ├── tools/ │ │ ├── __init__.py │ │ ├── install.py │ │ └── upgrade.py │ ├── utils.py │ └── virtualbox.py ├── uninstall.py └── upgrade.py
Showing preview only (320K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (4368 symbols across 470 files)
FILE: extend.py
class DefaultBinDir (line 58) | class DefaultBinDir:
function check_libcurl (line 153) | def check_libcurl():
function missing_packages (line 168) | def missing_packages():
function check (line 214) | def check(string):
function do_unprivileged_work (line 267) | def do_unprivileged_work():
function checked_unprivileged_work (line 321) | def checked_unprivileged_work(result):
FILE: install.py
function abort (line 84) | def abort():
FILE: installation/admin.py
function add_arguments (line 28) | def add_arguments(mode, parser):
function prepare (line 41) | def prepare(mode, arguments, data):
function install (line 108) | def install(data):
FILE: installation/config.py
class Provider (line 55) | class Provider(object):
method __init__ (line 56) | def __init__(self, name):
method load (line 66) | def load(self, settings):
method readargs (line 81) | def readargs(self, arguments):
method store (line 103) | def store(self, data):
method scrub (line 114) | def scrub(self, data):
function calibrate_minimum_rounds (line 123) | def calibrate_minimum_rounds():
function add_arguments (line 165) | def add_arguments(mode, parser):
function prepare (line 256) | def prepare(mode, arguments, data):
function compile_file (line 664) | def compile_file(filename):
function set_file_mode_and_owner (line 679) | def set_file_mode_and_owner(path):
function copy_file_mode_and_owner (line 697) | def copy_file_mode_and_owner(src_path, dst_path):
function install (line 703) | def install(data):
function update_file (line 745) | def update_file(target_dir, entry, data, arguments, compilation_failed):
function upgrade (line 830) | def upgrade(arguments, data):
function undo (line 860) | def undo():
function finish (line 866) | def finish(mode, arguments, data):
FILE: installation/criticctl.py
function install (line 25) | def install(data):
function upgrade (line 41) | def upgrade(arguments, data):
function undo (line 63) | def undo():
function finish (line 69) | def finish(mode, arguments, data):
FILE: installation/data/dbschema.base.sql
type systemidentities (line 20) | CREATE TABLE systemidentities
type files (line 30) | CREATE TABLE files
type files_path_md5 (line 36) | CREATE UNIQUE INDEX files_path_md5 ON files (MD5(path))
type files_path_gin (line 40) | CREATE INDEX files_path_gin ON files USING gin (STRING_TO_ARRAY(path, '/'))
type knownremotes (line 42) | CREATE TABLE knownremotes
type timezones (line 50) | CREATE TABLE timezones
FILE: installation/data/dbschema.changesets.sql
type changesets (line 30) | CREATE TABLE changesets
type changesets_child (line 37) | CREATE INDEX changesets_child ON changesets (child)
type customchangesets (line 39) | CREATE TABLE customchangesets
type mergereplays (line 43) | CREATE TABLE mergereplays
type fileversions (line 47) | CREATE TABLE fileversions
type fileversions_old_sha1 (line 56) | CREATE INDEX fileversions_old_sha1 ON fileversions (file, old_sha1)
type fileversions_new_sha1 (line 57) | CREATE INDEX fileversions_new_sha1 ON fileversions (file, new_sha1)
type chunks (line 59) | CREATE TABLE chunks
type chunks_changeset_file (line 70) | CREATE INDEX chunks_changeset_file ON chunks (changeset, file)
type codecontexts (line 72) | CREATE TABLE codecontexts
type codecontexts_sha1_first_last (line 77) | CREATE INDEX codecontexts_sha1_first_last ON codecontexts (sha1, first_l...
FILE: installation/data/dbschema.comments.sql
type commentchains (line 36) | CREATE TABLE commentchains
type commentchains_review_file (line 51) | CREATE INDEX commentchains_review_file ON commentchains(review, file)
type commentchains_review_type_state (line 52) | CREATE INDEX commentchains_review_type_state ON commentchains(review, ty...
type commentchains_batch (line 53) | CREATE INDEX commentchains_batch ON commentchains(batch)
type commentchainchanges (line 65) | CREATE TABLE commentchainchanges
type commentchainchanges_batch (line 79) | CREATE INDEX commentchainchanges_batch ON commentchainchanges(batch)
type commentchainchanges_chain (line 80) | CREATE INDEX commentchainchanges_chain ON commentchainchanges(chain)
type commentchainlines (line 87) | CREATE TABLE commentchainlines
type commentchainlines_chain_sha1 (line 100) | CREATE INDEX commentchainlines_chain_sha1 ON commentchainlines(chain, sha1)
type commentchainusers (line 102) | CREATE TABLE commentchainusers
type comments (line 115) | CREATE TABLE comments
type comments_chain_uid_state (line 125) | CREATE INDEX comments_chain_uid_state ON comments (chain, uid, state)
type comments_batch (line 126) | CREATE INDEX comments_batch ON comments(batch)
type comments_id_chain (line 127) | CREATE INDEX comments_id_chain ON comments(id, chain)
type commentstoread (line 135) | CREATE TABLE commentstoread
type commentstoread_comment (line 140) | CREATE INDEX commentstoread_comment ON commentstoread(comment)
type commentmessageids (line 142) | CREATE TABLE commentmessageids
type commentmessageids_comment (line 148) | CREATE INDEX commentmessageids_comment ON commentmessageids(comment)
FILE: installation/data/dbschema.extensions.sql
type extensions (line 20) | CREATE TABLE extensions
type extensionversions (line 27) | CREATE TABLE extensionversions
type extensioninstalls (line 38) | CREATE TABLE extensioninstalls
type extensionroles (line 46) | CREATE TABLE extensionroles
type extensionpageroles (line 52) | CREATE TABLE extensionpageroles
type extensionroles_page (line 56) | CREATE VIEW extensionroles_page AS
type extensioninjectroles (line 61) | CREATE TABLE extensioninjectroles
type extensionroles_inject (line 65) | CREATE VIEW extensionroles_inject AS
type extensionprocesscommitsroles (line 70) | CREATE TABLE extensionprocesscommitsroles
type extensionfilterhookroles (line 73) | CREATE TABLE extensionfilterhookroles
type extensionhookfilters (line 80) | CREATE TABLE extensionhookfilters
type extensionhookfilters_uid_extension (line 88) | CREATE INDEX extensionhookfilters_uid_extension
type extensionhookfilters_repository (line 90) | CREATE INDEX extensionhookfilters_repository
type extensionfilterhookevents (line 93) | CREATE TABLE extensionfilterhookevents
type extensionfilterhookcommits (line 99) | CREATE TABLE extensionfilterhookcommits
type extensionfilterhookcommits_event (line 102) | CREATE INDEX extensionfilterhookcommits_event
type extensionfilterhookfiles (line 104) | CREATE TABLE extensionfilterhookfiles
type extensionfilterhookfiles_event (line 107) | CREATE INDEX extensionfilterhookfiles_event
type extensionstorage (line 110) | CREATE TABLE extensionstorage
type extensionlog (line 118) | CREATE TABLE extensionlog
type extensionlog_extension_uid_category (line 124) | CREATE INDEX extensionlog_extension_uid_category ON extensionlog(extensi...
type accesscontrol_extensions (line 130) | CREATE TABLE accesscontrol_extensions
type accesscontrol_extensions_profile (line 141) | CREATE INDEX accesscontrol_extensions_profile
FILE: installation/data/dbschema.filters.sql
type filters (line 24) | CREATE TABLE filters
type filters_uid_repository_path_md5 (line 33) | CREATE UNIQUE INDEX filters_uid_repository_path_md5 ON filters (uid, rep...
FILE: installation/data/dbschema.git.sql
type repositories (line 20) | CREATE TABLE repositories
type gitusers (line 26) | CREATE TABLE gitusers
type commits (line 33) | CREATE TABLE commits
type edges (line 41) | CREATE TABLE edges
type edges_parent (line 44) | CREATE INDEX edges_parent ON edges (parent)
type edges_child (line 45) | CREATE INDEX edges_child ON edges (child)
type branches (line 50) | CREATE TABLE branches
type reachable (line 62) | CREATE TABLE reachable
type reachable_branch (line 67) | CREATE INDEX reachable_branch ON reachable (branch)
type reachable_commit (line 68) | CREATE INDEX reachable_commit ON reachable (commit)
type tags (line 70) | CREATE TABLE tags
type tags_repository_sha1 (line 77) | CREATE INDEX tags_repository_sha1 ON tags (repository, sha1)
type mergebases (line 80) | CREATE TABLE mergebases
type relevantcommits (line 89) | CREATE TABLE relevantcommits
type accesscontrol_repositories (line 101) | CREATE TABLE accesscontrol_repositories
type accesscontrol_repositories_profile (line 111) | CREATE INDEX accesscontrol_repositories_profile
FILE: installation/data/dbschema.news.sql
type newsitems (line 20) | CREATE TABLE newsitems
type newsread (line 25) | CREATE TABLE newsread
FILE: installation/data/dbschema.preferences.sql
type preferences (line 24) | CREATE TABLE preferences
type userpreferences (line 38) | CREATE TABLE userpreferences
type userpreferences_item (line 57) | CREATE UNIQUE INDEX userpreferences_item
type userpreferences_item_uid (line 62) | CREATE UNIQUE INDEX userpreferences_item_uid
type userpreferences_item_repository (line 67) | CREATE UNIQUE INDEX userpreferences_item_repository
type userpreferences_item_uid_repository (line 72) | CREATE UNIQUE INDEX userpreferences_item_uid_repository
type userpreferences_item_uid_filter (line 77) | CREATE UNIQUE INDEX userpreferences_item_uid_filter
FILE: installation/data/dbschema.reviews.sql
type reviews (line 29) | CREATE TABLE reviews
type reviews_branch (line 45) | CREATE INDEX reviews_branch ON reviews (branch)
type scheduledreviewbrancharchivals (line 47) | CREATE TABLE scheduledreviewbrancharchivals
type reviewfilters (line 51) | CREATE TABLE reviewfilters
type reviewfilters_review_uid_path_md5 (line 61) | CREATE UNIQUE INDEX reviewfilters_review_uid_path_md5 ON reviewfilters (...
type batches (line 63) | CREATE TABLE batches
type batches_review_uid (line 69) | CREATE INDEX batches_review_uid ON batches (review, uid)
type reviewusers (line 74) | CREATE TABLE reviewusers
type reviewusers_uid (line 83) | CREATE INDEX reviewusers_uid ON reviewusers (uid)
type reviewchangesets (line 85) | CREATE TABLE reviewchangesets
type reviewrebases (line 91) | CREATE TABLE reviewrebases
type previousreachable (line 105) | CREATE TABLE previousreachable
type previousreachable_rebase (line 108) | CREATE INDEX previousreachable_rebase ON previousreachable (rebase)
type reviewfiles (line 114) | CREATE TABLE reviewfiles
type reviewfiles_review_changeset (line 131) | CREATE INDEX reviewfiles_review_changeset ON reviewfiles (review, change...
type reviewfiles_review_state (line 132) | CREATE INDEX reviewfiles_review_state ON reviewfiles (review, state)
type reviewassignmentstransactions (line 134) | CREATE TABLE reviewassignmentstransactions
type reviewassignmentchanges (line 143) | CREATE TABLE reviewassignmentchanges
type reviewfilterchanges (line 152) | CREATE TABLE reviewfilterchanges
type reviewuserfiles (line 160) | CREATE TABLE reviewuserfiles
type reviewuserfiles_uid (line 168) | CREATE INDEX reviewuserfiles_uid ON reviewuserfiles (uid)
type reviewfilesharing (line 170) | CREATE VIEW reviewfilesharing
type reviewfilechanges (line 184) | CREATE TABLE reviewfilechanges
type reviewfilechanges_batch (line 196) | CREATE INDEX reviewfilechanges_batch ON reviewfilechanges (batch)
type reviewfilechanges_file (line 197) | CREATE INDEX reviewfilechanges_file ON reviewfilechanges (file)
type reviewfilechanges_uid_state (line 198) | CREATE INDEX reviewfilechanges_uid_state ON reviewfilechanges (uid, state)
type reviewfilechanges_time (line 199) | CREATE INDEX reviewfilechanges_time ON reviewfilechanges (time)
type lockedreviews (line 201) | CREATE TABLE lockedreviews
type fullreviewuserfiles (line 204) | CREATE VIEW fullreviewuserfiles
type reviewmessageids (line 216) | CREATE TABLE reviewmessageids
type reviewmessageids_review (line 223) | CREATE INDEX reviewmessageids_review ON reviewmessageids (review)
type reviewmergeconfirmations (line 225) | CREATE TABLE reviewmergeconfirmations
type reviewmergecontributions (line 235) | CREATE TABLE reviewmergecontributions
type reviewrecipientfilters (line 241) | CREATE TABLE reviewrecipientfilters
type checkbranchnotes (line 248) | CREATE TABLE checkbranchnotes
FILE: installation/data/dbschema.trackedbranches.sql
type trackedbranches (line 20) | CREATE TABLE trackedbranches
type trackedbranchusers (line 35) | CREATE TABLE trackedbranchusers
type trackedbranchlog (line 41) | CREATE TABLE trackedbranchlog
type trackedbranchlog_branch (line 48) | CREATE INDEX trackedbranchlog_branch ON trackedbranchlog (branch)
FILE: installation/data/dbschema.users.sql
type roles (line 20) | CREATE TABLE roles
type users (line 36) | CREATE TABLE users
type useremails (line 44) | CREATE TABLE useremails
type usersessions (line 58) | CREATE TABLE usersessions
type usergitemails (line 64) | CREATE TABLE usergitemails
type usergitemails_uid (line 69) | CREATE INDEX usergitemails_uid ON usergitemails (uid)
type userabsence (line 71) | CREATE TABLE userabsence
type userabsence_uid_until (line 74) | CREATE INDEX userabsence_uid_until ON userabsence (uid, until)
type userroles (line 76) | CREATE TABLE userroles
type userresources (line 80) | CREATE TABLE userresources
type externalusers (line 88) | CREATE TABLE externalusers
type oauthstates (line 98) | CREATE TABLE oauthstates
type accesstokens (line 111) | CREATE TABLE accesstokens
type accesscontrolprofiles (line 136) | CREATE TABLE accesscontrolprofiles
type accesscontrol_http (line 158) | CREATE TABLE accesscontrol_http
type accesscontrol_http_profile (line 169) | CREATE INDEX accesscontrol_http_profile
type useraccesscontrolprofiles (line 172) | CREATE TABLE useraccesscontrolprofiles
type useraccesscontrolprofiles_uid (line 184) | CREATE INDEX useraccesscontrolprofiles_uid
type labeledaccesscontrolprofiles (line 187) | CREATE TABLE labeledaccesscontrolprofiles
FILE: installation/database.py
function psql_import (line 30) | def psql_import(sql_file, as_user=None):
function add_arguments (line 41) | def add_arguments(mode, parser):
function prepare (line 48) | def prepare(mode, arguments, data):
function install (line 133) | def install(data):
function upgrade (line 210) | def upgrade(arguments, data):
function undo (line 238) | def undo():
FILE: installation/extensions.py
function prepare (line 17) | def prepare(mode, arguments, data):
FILE: installation/files.py
function compile_file (line 33) | def compile_file(filename):
function copyfile (line 50) | def copyfile(source, destination):
function skip (line 58) | def skip(path):
function install (line 64) | def install(data):
function upgrade (line 117) | def upgrade(arguments, data):
function undo (line 364) | def undo():
function finish (line 371) | def finish(mode, arguments, data):
FILE: installation/git.py
function install (line 22) | def install(data):
FILE: installation/httpd.py
function backup_path (line 30) | def backup_path(path):
function undoable_remove (line 33) | def undoable_remove(path):
function process_configuration_file (line 37) | def process_configuration_file(
class Service (line 83) | class Service(object):
method __init__ (line 84) | def __init__(self):
method service_command (line 87) | def service_command(self, command, errors_are_fatal):
method start (line 111) | def start(self, errors_are_fatal=True):
method stop (line 118) | def stop(self, errors_are_fatal=False):
method restart (line 125) | def restart(self):
method prepare (line 131) | def prepare(self, mode, arguments, data):
method install (line 133) | def install(self, data):
method upgrade (line 135) | def upgrade(self, arguments, data):
method undo (line 138) | def undo(self):
class Apache (line 142) | class Apache(Service):
method __init__ (line 149) | def __init__(self):
method get_version (line 156) | def get_version(self):
method prepare (line 163) | def prepare(self, mode, arguments, data):
method restart (line 173) | def restart(self):
method setup (line 179) | def setup(self):
method install (line 191) | def install(self, data):
method upgrade (line 212) | def upgrade(self, arguments, data):
method undo (line 235) | def undo(self):
class nginx (line 246) | class nginx(Service):
method __init__ (line 252) | def __init__(self):
method install (line 265) | def install(self, data):
method upgrade (line 278) | def upgrade(self, arguments, data):
method undo (line 299) | def undo(self):
class uWSGIBackend (line 310) | class uWSGIBackend(Service):
method __init__ (line 317) | def __init__(self):
method install (line 326) | def install(self, data):
method upgrade (line 335) | def upgrade(self, arguments, data):
method undo (line 356) | def undo(self):
class uWSGIFrontend (line 361) | class uWSGIFrontend(Service):
method __init__ (line 368) | def __init__(self):
method install (line 378) | def install(self, data):
method upgrade (line 387) | def upgrade(self, arguments, data):
method undo (line 408) | def undo(self):
class Multiple (line 413) | class Multiple():
method __init__ (line 414) | def __init__(self, *services):
method prepare (line 417) | def prepare(self, *args):
method install (line 420) | def install(self, *args):
method upgrade (line 423) | def upgrade(self, *args):
method undo (line 426) | def undo(self):
method start (line 430) | def start(self):
method stop (line 432) | def stop(self):
method restart (line 434) | def restart(self):
function prepare (line 437) | def prepare(mode, args, data):
function install (line 461) | def install(data):
function upgrade (line 466) | def upgrade(arguments, data):
function undo (line 471) | def undo():
function finish (line 480) | def finish(mode, arguments, data):
function start (line 484) | def start():
function stop (line 489) | def stop():
FILE: installation/initd.py
function stop (line 32) | def stop(identity="main"):
function start (line 43) | def start(identity="main"):
function restart (line 55) | def restart(identity="main"):
function install (line 64) | def install(data):
function upgrade (line 86) | def upgrade(arguments, data):
function undo (line 141) | def undo():
function finish (line 154) | def finish(mode, arguments, data):
FILE: installation/input.py
function yes_or_no (line 23) | def yes_or_no(prompt, default=None):
function string (line 37) | def string(prompt, default=None, check=None):
function password (line 54) | def password(prompt, default=None, twice=True):
FILE: installation/migrate.py
function scripts_to_run (line 23) | def scripts_to_run(data):
function will_modify_dbschema (line 52) | def will_modify_dbschema(data):
function upgrade (line 58) | def upgrade(arguments, data):
FILE: installation/migrations/dbschema.altertable.reviewrebases.add.equivalent_merge.py
function fetch_commit_sha1 (line 47) | def fetch_commit_sha1(commit_id):
function get_parent_sha1s (line 52) | def get_parent_sha1s(repository_path, sha1):
function is_ancestor_of (line 58) | def is_ancestor_of(repository_path, ancestor_sha1, descendant_sha1):
FILE: installation/migrations/dbschema.createindex.misc.py
function create_index (line 37) | def create_index(table, columns):
FILE: installation/migrations/dbschema.extension-filterhook-role.py
function table_exists (line 37) | def table_exists(table_name):
function createtable (line 48) | def createtable(statement):
function createindex (line 56) | def createindex(statement):
function run_statements (line 63) | def run_statements(statements):
FILE: installation/migrations/dbschema.external-authentication.py
function create (line 35) | def create(table_name, statement):
FILE: installation/migrations/dbschema.files-and-directories.py
function column_exists (line 39) | def column_exists(table, column):
FILE: installation/migrations/dbschema.per-repository-or-filter-preferences.py
function column_exists (line 36) | def column_exists(table, column):
FILE: installation/migrations/git.check-keepalive-references.py
function add_keepalive (line 77) | def add_keepalive(sha1, message):
FILE: installation/paths.py
function prepare (line 31) | def prepare(mode, arguments, data):
function mkdir (line 171) | def mkdir(path, mode=0750):
function mkdirs (line 184) | def mkdirs():
function install (line 204) | def install(data):
function upgrade (line 208) | def upgrade(arguments, data):
function undo (line 212) | def undo():
FILE: installation/prefs.py
function add_preference (line 24) | def add_preference(db, item, data, silent=False):
function update_preference (line 48) | def update_preference(db, item, data, type_changed):
function remove_preference (line 91) | def remove_preference(db, item):
function load_preferences (line 96) | def load_preferences(db):
function install (line 116) | def install(data):
function upgrade (line 137) | def upgrade(arguments, data):
FILE: installation/prereqs.py
function find_executable (line 27) | def find_executable(name):
function blankline (line 44) | def blankline():
function install_packages (line 50) | def install_packages(*packages):
class Prerequisite (line 90) | class Prerequisite(object):
method __init__ (line 91) | def __init__(self, name, packages, message):
method install (line 98) | def install(self):
class Executable (line 117) | class Executable(Prerequisite):
method __init__ (line 118) | def __init__(self, name, packages, message):
method check (line 122) | def check(self):
method install (line 127) | def install(self):
class PythonLibrary (line 135) | class PythonLibrary(Prerequisite):
method __init__ (line 136) | def __init__(self, name, packages, message):
method check (line 140) | def check(self):
method install (line 151) | def install(self):
class CustomCheck (line 159) | class CustomCheck(Prerequisite):
method __init__ (line 162) | def __init__(self, callback, name, packages, message):
method check (line 167) | def check(self):
method install (line 173) | def install(self):
function check_mod_wsgi (line 232) | def check_mod_wsgi():
function resolve_prerequisites (line 291) | def resolve_prerequisites():
function prepare (line 302) | def prepare(mode, arguments, data):
function install (line 307) | def install(data):
function upgrade (line 331) | def upgrade(arguments, data):
FILE: installation/process.py
function check_input (line 19) | def check_input(args, stdin, **kwargs):
FILE: installation/qs/data.py
function config (line 11) | def config(key):
function system (line 13) | def system(key):
function admin (line 15) | def admin(key):
function database (line 17) | def database(key):
function prereqs (line 19) | def prereqs(key):
function paths (line 21) | def paths(key):
function smtp (line 23) | def smtp(key):
function extensions (line 25) | def extensions(key):
function username (line 28) | def username():
function groupname (line 30) | def groupname():
function which (line 33) | def which(name):
function generate (line 36) | def generate(arguments, database_path):
FILE: installation/qs/sqlite.py
function convert_date (line 12) | def convert_date(value):
function convert_datetime (line 18) | def convert_datetime(value):
function convert_interval (line 24) | def convert_interval(value):
function convert_boolean (line 30) | def convert_boolean(value):
function sqltokens (line 38) | def sqltokens(command):
function sqlcommands (line 41) | def sqlcommands(filename):
function replace (line 53) | def replace(query, old, new):
class Cursor (line 81) | class Cursor(object):
method __init__ (line 82) | def __init__(self, connection):
method massage (line 85) | def massage(self, query, parameters):
method execute (line 135) | def execute(self, query, parameters=()):
method executemany (line 147) | def executemany(self, query, parameters=()):
method fetchone (line 160) | def fetchone(self):
method fetchall (line 162) | def fetchall(self):
method __iter__ (line 165) | def __iter__(self):
function regexp (line 168) | def regexp(pattern, string):
function interval_seconds (line 171) | def interval_seconds(string):
class Connection (line 189) | class Connection(object):
method __init__ (line 190) | def __init__(self, **parameters):
method cursor (line 201) | def cursor(self):
method commit (line 203) | def commit(self):
method rollback (line 205) | def rollback(self):
method close (line 207) | def close(self):
function connect (line 210) | def connect(**parameters):
function import_schema (line 213) | def import_schema(database_path, filenames, quiet=False, verbose=False):
FILE: installation/smtp.py
function add_arguments (line 29) | def add_arguments(mode, parser):
function prepare (line 54) | def prepare(mode, arguments, data):
function finish (line 249) | def finish(mode, arguments, data):
FILE: installation/system.py
function fetch_uid_gid (line 37) | def fetch_uid_gid():
function add_arguments (line 43) | def add_arguments(mode, parser):
function prepare (line 68) | def prepare(mode, arguments, data):
function install (line 172) | def install(data):
function undo (line 193) | def undo():
FILE: installation/templates/configuration/services.py
function service (line 20) | def service(name, address=0, module=0, pidfile_path=0, logfile_path=0, l...
FILE: installation/utils.py
class UpdateModifiedFile (line 29) | class UpdateModifiedFile:
method __init__ (line 30) | def __init__(self, arguments, message, versions, options, generateVers...
method printMessage (line 52) | def printMessage(self):
method printOptions (line 55) | def printOptions(self):
method displayDifferences (line 68) | def displayDifferences(self, from_version, to_version):
method prompt (line 78) | def prompt(self):
function run_git (line 113) | def run_git(args, **kwargs):
function update_from_template (line 118) | def update_from_template(arguments, data, template_path, target_path, me...
function write_file (line 182) | def write_file(path, source):
function copy_file (line 188) | def copy_file(source_path, target_path):
function hash_file (line 198) | def hash_file(git, path):
function get_entry_sha1 (line 206) | def get_entry_sha1(git, commit_sha1, path, entry_type):
function get_file_sha1 (line 220) | def get_file_sha1(git, commit_sha1, path):
function get_tree_sha1 (line 223) | def get_tree_sha1(git, commit_sha1, path):
function read_file (line 226) | def read_file(git, commit_sha1, path):
function get_initial_commit_date (line 233) | def get_initial_commit_date(git, path):
function clean_root_pyc_files (line 238) | def clean_root_pyc_files():
function temporary_cwd (line 247) | def temporary_cwd():
function as_critic_system_user (line 256) | def as_critic_system_user():
function as_effective_user_from_path (line 273) | def as_effective_user_from_path(path):
function deunicode (line 283) | def deunicode(v):
function read_install_data (line 289) | def read_install_data(arguments, fail_softly=False):
function write_install_data (line 340) | def write_install_data(arguments, install_data):
function start_migration (line 350) | def start_migration():
class DatabaseSchema (line 364) | class DatabaseSchema(object):
method __init__ (line 369) | def __init__(self):
method table_exists (line 375) | def table_exists(self, table_name):
method column_exists (line 388) | def column_exists(self, table_name, column_name):
method create_table (line 402) | def create_table(self, statement):
method create_index (line 412) | def create_index(self, statement):
method create_column (line 422) | def create_column(self, table_name, column_name, column_definition):
method type_exists (line 429) | def type_exists(self, type_name):
method create_type (line 442) | def create_type(self, statement):
method update (line 452) | def update(self, statements):
function read_lifecycle (line 475) | def read_lifecycle(git=None, sha1=None):
FILE: pythonversion.py
function check (line 19) | def check(message=None):
FILE: quickstart.py
function handle_interrupt (line 84) | def handle_interrupt(signum, frame):
class CriticWSGIRequestHandler (line 103) | class CriticWSGIRequestHandler(wsgiref.simple_server.WSGIRequestHandler):
method log_message (line 104) | def log_message(self, *args, **kwargs):
class CompilationFailed (line 182) | class CompilationFailed(Exception):
function compile_all_sources (line 185) | def compile_all_sources():
function activity (line 206) | def activity(what):
function startTheSystem (line 307) | def startTheSystem():
function stopTheSystem (line 333) | def stopTheSystem():
function restartTheSystem (line 342) | def restartTheSystem():
function getNewestModificationTime (line 347) | def getNewestModificationTime():
function handle_sigusr1 (line 420) | def handle_sigusr1(signum, frame):
FILE: src/api/accesscontrolprofile.py
class AccessControlProfileError (line 19) | class AccessControlProfileError(api.APIError):
class InvalidAccessControlProfileId (line 24) | class InvalidAccessControlProfileId(AccessControlProfileError):
method __init__ (line 27) | def __init__(self, value):
class AccessControlProfile (line 33) | class AccessControlProfile(api.APIObject):
method id (line 39) | def id(self):
method title (line 44) | def title(self):
method access_token (line 49) | def access_token(self):
class Category (line 53) | class Category(object):
method __init__ (line 61) | def __init__(self, rule, exceptions):
class HTTPException (line 65) | class HTTPException(object):
method __init__ (line 74) | def __init__(self, exception_id, request_method, path_pattern):
method http (line 80) | def http(self):
class RepositoryException (line 88) | class RepositoryException(object):
method __init__ (line 96) | def __init__(self, exception_id, access_type, repository):
method repositories (line 102) | def repositories(self):
class ExtensionException (line 112) | class ExtensionException(object):
method __init__ (line 120) | def __init__(self, exception_id, access_type, extension):
method extensions (line 126) | def extensions(self):
function fetch (line 135) | def fetch(critic, profile_id):
function fetchAll (line 141) | def fetchAll(critic, title=None):
FILE: src/api/accesstoken.py
class AccessTokenError (line 19) | class AccessTokenError(api.APIError):
class InvalidAccessTokenId (line 23) | class InvalidAccessTokenId(AccessTokenError):
method __init__ (line 26) | def __init__(self, value):
class AccessToken (line 32) | class AccessToken(api.APIObject):
method access_type (line 36) | def access_type(self):
method id (line 41) | def id(self):
method user (line 46) | def user(self):
method part1 (line 51) | def part1(self):
method part2 (line 56) | def part2(self):
method title (line 61) | def title(self):
method profile (line 66) | def profile(self):
function fetch (line 70) | def fetch(critic, token_id):
function fetchAll (line 76) | def fetchAll(critic, user=None):
FILE: src/api/apierror.py
class APIError (line 17) | class APIError(Exception):
class PermissionDenied (line 22) | class PermissionDenied(Exception):
method raiseUnlessAdministrator (line 27) | def raiseUnlessAdministrator(critic):
method raiseUnlessUser (line 33) | def raiseUnlessUser(critic, required_user):
class TransactionError (line 37) | class TransactionError(APIError):
class ResultDelayedError (line 41) | class ResultDelayedError(Exception):
FILE: src/api/apiobject.py
class APIObject (line 17) | class APIObject(object):
method __init__ (line 25) | def __init__(self, critic, impl):
method __int__ (line 29) | def __int__(self):
method __hash__ (line 31) | def __hash__(self):
method __eq__ (line 33) | def __eq__(self, other):
method critic (line 37) | def critic(self):
method _impl (line 42) | def _impl(self):
method _set_impl (line 49) | def _set_impl(self, impl):
FILE: src/api/batch.py
class BatchError (line 19) | class BatchError(api.APIError):
class InvalidBatchId (line 22) | class InvalidBatchId(BatchError):
method __init__ (line 25) | def __init__(self, batch_id):
class Batch (line 29) | class Batch(api.APIObject):
method id (line 31) | def id(self):
method is_empty (line 36) | def is_empty(self):
method review (line 41) | def review(self):
method author (line 46) | def author(self):
method timestamp (line 53) | def timestamp(self):
method comment (line 60) | def comment(self):
method created_comments (line 68) | def created_comments(self):
method written_replies (line 75) | def written_replies(self):
method resolved_issues (line 82) | def resolved_issues(self):
method reopened_issues (line 93) | def reopened_issues(self):
method morphed_comments (line 104) | def morphed_comments(self):
method reviewed_file_changes (line 114) | def reviewed_file_changes(self):
method unreviewed_file_changes (line 125) | def unreviewed_file_changes(self):
function fetch (line 134) | def fetch(critic, batch_id):
function fetchAll (line 141) | def fetchAll(critic, review=None, author=None):
function fetchUnpublished (line 155) | def fetchUnpublished(critic, review):
FILE: src/api/branch.py
class BranchError (line 19) | class BranchError(api.APIError):
class InvalidBranchId (line 23) | class InvalidBranchId(BranchError):
method __init__ (line 26) | def __init__(self, branch_id):
class InvalidBranchName (line 31) | class InvalidBranchName(BranchError):
method __init__ (line 34) | def __init__(self, name):
class Branch (line 39) | class Branch(api.APIObject):
method id (line 47) | def id(self):
method name (line 52) | def name(self):
method repository (line 57) | def repository(self):
method head (line 64) | def head(self):
method commits (line 69) | def commits(self):
function fetch (line 80) | def fetch(critic, branch_id=None, repository=None, name=None):
function fetchAll (line 89) | def fetchAll(critic, repository=None):
FILE: src/api/changeset.py
class ChangesetError (line 19) | class ChangesetError(api.APIError):
class ChangesetBackgroundServiceError (line 22) | class ChangesetBackgroundServiceError(ChangesetError):
class InvalidChangesetId (line 25) | class InvalidChangesetId(ChangesetError):
class NotImplementedError (line 28) | class NotImplementedError(ChangesetError):
class ChangesetDelayed (line 31) | class ChangesetDelayed(api.ResultDelayedError):
class AutomaticChangesetEmpty (line 34) | class AutomaticChangesetEmpty(ChangesetError):
class Changeset (line 38) | class Changeset(api.APIObject):
method __str__ (line 54) | def __str__(self):
method id (line 58) | def id(self):
method repository (line 62) | def repository(self):
method type (line 67) | def type(self):
method from_commit (line 71) | def from_commit(self):
method to_commit (line 75) | def to_commit(self):
method files (line 79) | def files(self):
method contributing_commits (line 83) | def contributing_commits(self):
function fetch (line 86) | def fetch(critic, repository, changeset_id=None, from_commit=None,
FILE: src/api/comment.py
class CommentError (line 19) | class CommentError(api.APIError):
class InvalidCommentId (line 22) | class InvalidCommentId(CommentError):
method __init__ (line 25) | def __init__(self, comment_id):
class InvalidCommentIds (line 31) | class InvalidCommentIds(CommentError):
method __init__ (line 34) | def __init__(self, comment_ids):
class InvalidLocation (line 40) | class InvalidLocation(CommentError):
class Comment (line 45) | class Comment(api.APIObject):
method id (line 49) | def id(self):
method type (line 54) | def type(self):
method is_draft (line 61) | def is_draft(self):
method review (line 68) | def review(self):
method author (line 76) | def author(self):
method timestamp (line 83) | def timestamp(self):
method location (line 90) | def location(self):
method text (line 101) | def text(self):
method replies (line 106) | def replies(self):
class DraftChanges (line 112) | class DraftChanges(object):
method __init__ (line 115) | def __init__(self, author, is_draft, reply, new_type):
method author (line 122) | def author(self):
method is_draft (line 129) | def is_draft(self):
method reply (line 134) | def reply(self):
method new_type (line 142) | def new_type(self):
method draft_changes (line 150) | def draft_changes(self):
class Issue (line 161) | class Issue(Comment):
method type (line 165) | def type(self):
method state (line 169) | def state(self):
method addressed_by (line 176) | def addressed_by(self):
method resolved_by (line 184) | def resolved_by(self):
class DraftChanges (line 191) | class DraftChanges(Comment.DraftChanges):
method __init__ (line 194) | def __init__(self, author, is_draft, reply, new_type, new_state,
method new_state (line 202) | def new_state(self):
method new_location (line 211) | def new_location(self):
class Note (line 223) | class Note(Comment):
method type (line 225) | def type(self):
class Location (line 228) | class Location(api.APIObject):
method __len__ (line 231) | def __len__(self):
method type (line 236) | def type(self):
method first_line (line 243) | def first_line(self):
method last_line (line 250) | def last_line(self):
class CommitMessageLocation (line 256) | class CommitMessageLocation(Location):
method type (line 258) | def type(self):
method commit (line 262) | def commit(self):
method make (line 267) | def make(critic, first_line, last_line, commit):
class FileVersionLocation (line 271) | class FileVersionLocation(Location):
method type (line 273) | def type(self):
method changeset (line 277) | def changeset(self):
method side (line 300) | def side(self):
method commit (line 309) | def commit(self):
method file (line 323) | def file(self):
method is_translated (line 328) | def is_translated(self):
method translateTo (line 332) | def translateTo(self, changeset=None, commit=None):
method make (line 359) | def make(critic, first_line, last_line, file, changeset=None, side=None,
function fetch (line 373) | def fetch(critic, comment_id):
function fetchMany (line 380) | def fetchMany(critic, comment_ids):
function fetchAll (line 388) | def fetchAll(critic, review=None, author=None, comment_type=None, state=...
FILE: src/api/commit.py
class CommitError (line 19) | class CommitError(api.APIError):
class InvalidCommitId (line 22) | class InvalidCommitId(CommitError):
method __init__ (line 24) | def __init__(self, commit_id):
class InvalidSHA1 (line 28) | class InvalidSHA1(CommitError):
method __init__ (line 30) | def __init__(self, sha1):
class NotAFile (line 34) | class NotAFile(CommitError):
method __init__ (line 36) | def __init__(self, path):
class Commit (line 40) | class Commit(api.APIObject):
method __str__ (line 43) | def __str__(self):
method __repr__ (line 45) | def __repr__(self):
method __hash__ (line 47) | def __hash__(self):
method __eq__ (line 49) | def __eq__(self, other):
method id (line 53) | def id(self):
method repository (line 58) | def repository(self):
method sha1 (line 63) | def sha1(self):
method tree (line 68) | def tree(self):
method summary (line 73) | def summary(self):
method message (line 84) | def message(self):
method parents (line 89) | def parents(self):
method description (line 96) | def description(self):
class UserAndTimestamp (line 104) | class UserAndTimestamp(object):
method __init__ (line 107) | def __init__(self, name, email, timestamp):
method author (line 113) | def author(self):
method committer (line 118) | def committer(self):
method isAncestorOf (line 122) | def isAncestorOf(self, commit):
class FileInformation (line 130) | class FileInformation(object):
method __init__ (line 133) | def __init__(self, file, mode, sha1, size):
method file (line 140) | def file(self):
method mode (line 145) | def mode(self):
method sha1 (line 152) | def sha1(self):
method size (line 157) | def size(self):
method getFileInformation (line 161) | def getFileInformation(self, file):
method getFileContents (line 170) | def getFileContents(self, file):
method getFileLines (line 179) | def getFileLines(self, file):
function fetch (line 191) | def fetch(repository, commit_id=None, sha1=None, ref=None):
function fetchMany (line 203) | def fetchMany(repository, commit_ids=None, sha1s=None):
FILE: src/api/commitset.py
class InvalidCommitRange (line 19) | class InvalidCommitRange(Exception):
class CommitSet (line 27) | class CommitSet(api.APIObject):
method __iter__ (line 30) | def __iter__(self):
method __len__ (line 32) | def __len__(self):
method __contains__ (line 34) | def __contains__(self, item):
method __hash__ (line 36) | def __hash__(self):
method __eq__ (line 38) | def __eq__(self, other):
method __nonzero__ (line 41) | def __nonzero__(self):
method __repr__ (line 43) | def __repr__(self):
method date_ordered (line 47) | def date_ordered(self):
method topo_ordered (line 56) | def topo_ordered(self):
method heads (line 69) | def heads(self):
method tails (line 79) | def tails(self):
method filtered_tails (line 89) | def filtered_tails(self):
method getChildrenOf (line 101) | def getChildrenOf(self, commit):
method getParentsOf (line 108) | def getParentsOf(self, commit):
method getDescendantsOf (line 116) | def getDescendantsOf(self, commit, include_self=False):
method getAncestorsOf (line 133) | def getAncestorsOf(self, commit, include_self=False):
method union (line 149) | def union(self, commits):
method __or__ (line 153) | def __or__(self, commits):
method intersection (line 156) | def intersection(self, commits):
method __and__ (line 160) | def __and__(self, commits):
method difference (line 163) | def difference(self, commits):
method __sub__ (line 167) | def __sub__(self, commits):
method symmetric_difference (line 170) | def symmetric_difference(self, commits):
method __xor__ (line 174) | def __xor__(self, commits):
function create (line 177) | def create(critic, commits):
function calculateFromRange (line 186) | def calculateFromRange(critic, from_commit, to_commit):
FILE: src/api/config.py
class ConfigurationError (line 19) | class ConfigurationError(api.APIError):
class InvalidGroup (line 22) | class InvalidGroup(ConfigurationError):
method __init__ (line 23) | def __init__(self, name):
class InvalidKey (line 27) | class InvalidKey(ConfigurationError):
method __init__ (line 28) | def __init__(self, group, name):
class WrongType (line 32) | class WrongType(ConfigurationError):
method __init__ (line 33) | def __init__(self, group, name, read_as):
function getValue (line 37) | def getValue(group, key):
function getBoolean (line 46) | def getBoolean(group, key):
function getInteger (line 52) | def getInteger(group, key):
function getString (line 58) | def getString(group, key):
FILE: src/api/critic.py
class Critic (line 19) | class Critic(object):
method __init__ (line 20) | def __init__(self, impl):
method effective_user (line 24) | def effective_user(self):
method actual_user (line 28) | def actual_user(self):
method access_token (line 32) | def access_token(self):
method database (line 37) | def database(self):
method getDatabaseCursor (line 40) | def getDatabaseCursor(self):
method getUpdatingDatabaseCursor (line 46) | def getUpdatingDatabaseCursor(self, *tables):
method setActualUser (line 59) | def setActualUser(self, user):
method setAccessToken (line 64) | def setAccessToken(self, access_token):
function startSession (line 69) | def startSession(for_user=False, for_system=False, for_testing=False):
FILE: src/api/extension.py
class ExtensionError (line 19) | class ExtensionError(api.APIError):
class InvalidExtensionId (line 23) | class InvalidExtensionId(ExtensionError):
method __init__ (line 26) | def __init__(self, value):
class InvalidExtensionKey (line 32) | class InvalidExtensionKey(ExtensionError):
method __init__ (line 35) | def __init__(self, value):
class Extension (line 41) | class Extension(api.APIObject):
method id (line 45) | def id(self):
method name (line 50) | def name(self):
method key (line 55) | def key(self):
method publisher (line 64) | def publisher(self):
method default_version (line 74) | def default_version(self):
function fetch (line 81) | def fetch(critic, extension_id=None, key=None):
function fetchAll (line 97) | def fetchAll(critic, publisher=None, installed_by=None):
FILE: src/api/file.py
class FileError (line 19) | class FileError(api.APIError):
class InvalidFileId (line 22) | class InvalidFileId(FileError):
method __init__ (line 25) | def __init__(self, file_id):
class InvalidPath (line 30) | class InvalidPath(FileError):
method __init__ (line 33) | def __init__(self, path):
class File (line 38) | class File(api.APIObject):
method __str__ (line 39) | def __str__(self):
method id (line 43) | def id(self):
method path (line 48) | def path(self):
function fetch (line 52) | def fetch(critic, file_id=None, path=None, create=False):
function fetchMany (line 67) | def fetchMany(critic, file_ids=None, paths=None, create=False):
FILE: src/api/filechange.py
class FileChangeError (line 19) | class FileChangeError(api.APIError):
class InvalidFileChangeId (line 22) | class InvalidFileChangeId(FileChangeError):
method __init__ (line 23) | def __init__(self, changeset_id, file_id):
class FileChange (line 27) | class FileChange(api.APIObject):
method __hash__ (line 30) | def __hash__(self):
method __eq__ (line 32) | def __eq__(self, other):
method file (line 36) | def file(self):
method changeset (line 40) | def changeset(self):
method old_sha1 (line 44) | def old_sha1(self):
method old_mode (line 48) | def old_mode(self):
method new_sha1 (line 52) | def new_sha1(self):
method new_mode (line 56) | def new_mode(self):
function fetch (line 59) | def fetch(critic, changeset, file):
function fetchAll (line 65) | def fetchAll(critic, changeset):
FILE: src/api/filecontent.py
class FilecontentError (line 19) | class FilecontentError(api.APIError):
class Filecontent (line 22) | class Filecontent(api.APIObject):
method getLines (line 25) | def getLines(self, first_row=None, last_row=None):
class Line (line 31) | class Line:
method __init__ (line 33) | def __init__(self, parts, offset):
method parts (line 38) | def parts(self):
method offset (line 42) | def offset(self):
function fetch (line 45) | def fetch(critic, repository, blob_sha1, file_obj):
FILE: src/api/filediff.py
class FilediffError (line 19) | class FilediffError(api.APIError):
class FilediffParserError (line 22) | class FilediffParserError(api.APIError):
class FilediffDelayed (line 25) | class FilediffDelayed(api.ResultDelayedError):
class Filediff (line 28) | class Filediff(api.APIObject):
method __hash__ (line 34) | def __hash__(self):
method __eq__ (line 36) | def __eq__(self, other):
method filechange (line 40) | def filechange(self):
method old_count (line 44) | def old_count(self):
method new_count (line 48) | def new_count(self):
method getMacroChunks (line 51) | def getMacroChunks(self, context_lines, comments=None, ignore_chunks=F...
class MacroChunk (line 61) | class MacroChunk(object):
method __init__ (line 75) | def __init__(self, impl_macro_chunk):
method chunks (line 79) | def chunks(self):
method old_offset (line 83) | def old_offset(self):
method new_offset (line 87) | def new_offset(self):
method old_count (line 91) | def old_count(self):
method new_count (line 95) | def new_count(self):
method lines (line 99) | def lines(self):
class Line (line 102) | class Line(object):
method __init__ (line 120) | def __init__(self, impl_line):
method type (line 124) | def type(self):
method old_offset (line 128) | def old_offset(self):
method new_offset (line 132) | def new_offset(self):
method content (line 136) | def content(self):
method is_whitespace (line 140) | def is_whitespace(self):
method analysis (line 144) | def analysis(self):
method type_string (line 148) | def type_string(self):
class Part (line 151) | class Part(object):
method __init__ (line 162) | def __init__(self, impl_part):
method type (line 166) | def type(self):
method content (line 170) | def content(self):
method state (line 174) | def state(self):
function fetch (line 177) | def fetch(critic, filechange):
function fetchAll (line 183) | def fetchAll(critic, changeset):
FILE: src/api/filters.py
class FilterError (line 19) | class FilterError(api.APIError):
class Filter (line 23) | class Filter(api.APIObject):
method subject (line 27) | def subject(self):
method type (line 34) | def type(self):
method path (line 41) | def path(self):
class InvalidRepositoryFilterId (line 45) | class InvalidRepositoryFilterId(FilterError):
method __init__ (line 48) | def __init__(self, value):
class RepositoryFilter (line 54) | class RepositoryFilter(Filter):
method id (line 61) | def id(self):
method repository (line 66) | def repository(self):
method delegates (line 71) | def delegates(self):
function fetchRepositoryFilter (line 79) | def fetchRepositoryFilter(critic, filter_id):
class ReviewFilter (line 84) | class ReviewFilter(Filter):
method id (line 90) | def id(self):
method review (line 95) | def review(self):
method creator (line 100) | def creator(self):
FILE: src/api/impl/accesscontrolprofile.py
class AccessControlProfile (line 27) | class AccessControlProfile(apiobject.APIObject):
method __init__ (line 30) | def __init__(self, profile_id, title, token_id, *rules):
method getAccessToken (line 38) | def getAccessToken(self, critic):
method getHTTP (line 43) | def getHTTP(self, critic):
method getRepositories (line 55) | def getRepositories(self, critic):
method getExtensions (line 69) | def getExtensions(self, critic):
method refresh (line 87) | def refresh(critic, tables, cached_profiles):
function fetch (line 99) | def fetch(critic, profile_id):
function fetchAll (line 111) | def fetchAll(critic, title):
FILE: src/api/impl/accesstoken.py
class AccessToken (line 20) | class AccessToken(apiobject.APIObject):
method __init__ (line 23) | def __init__(self, token_id, access_type, user_id, part1, part2, title):
method getUser (line 32) | def getUser(self, critic):
method getProfile (line 37) | def getProfile(self, critic):
method refresh (line 51) | def refresh(critic, tables, cached_tokens):
function fetch (line 63) | def fetch(critic, token_id):
function fetchAll (line 75) | def fetchAll(critic, user):
FILE: src/api/impl/apiobject.py
class APIObject (line 17) | class APIObject(object):
method wrap (line 18) | def wrap(self, critic):
method create (line 22) | def create(Implementation, critic, *args):
method get_cached (line 26) | def get_cached(Implementation, critic, item_id):
method add_cached (line 30) | def add_cached(Implementation, critic, item_id, item):
method make (line 34) | def make(Implementation, critic, args_list, ignored_errors=(),
method cached (line 50) | def cached(Implementation, InvalidIdError=None,
method cachedMany (line 71) | def cachedMany(Implementation, InvalidIdsError,
method allCached (line 97) | def allCached(Implementation, critic):
method refresh (line 107) | def refresh(critic, tables, cached_objects):
method updateAll (line 116) | def updateAll(Implementation, critic, query, cached_objects):
FILE: src/api/impl/batch.py
class ModifiedComment (line 20) | class ModifiedComment(object):
method __init__ (line 21) | def __init__(self, comment_id, new_type, new_state):
class Batch (line 26) | class Batch(apiobject.APIObject):
method __init__ (line 29) | def __init__(self, batch_id, review_id, author_id, comment_id, timesta...
method isEmpty (line 41) | def isEmpty(self, critic):
method getReview (line 50) | def getReview(self, critic):
method getAuthor (line 53) | def getAuthor(self, critic):
method getComment (line 58) | def getComment(self, critic):
method getCreatedComments (line 63) | def getCreatedComments(self, critic):
method getWrittenReplies (line 68) | def getWrittenReplies(self, critic):
method getResolvedIssues (line 73) | def getResolvedIssues(self, critic):
method getReopenedIssues (line 81) | def getReopenedIssues(self, critic):
method getMorphedComments (line 89) | def getMorphedComments(self, critic):
method getReviewedFileChanges (line 103) | def getReviewedFileChanges(self, critic):
method getUnreviewedFileChanges (line 109) | def getUnreviewedFileChanges(self, critic):
method __queryCondition (line 115) | def __queryCondition(self):
method loadCommentChanges (line 124) | def loadCommentChanges(self, critic):
method loadFileChanges (line 165) | def loadFileChanges(self, critic):
function fetch (line 190) | def fetch(critic, batch_id):
function fetchAll (line 198) | def fetchAll(critic, review, author):
function fetchUnpublished (line 214) | def fetchUnpublished(critic, review):
FILE: src/api/impl/branch.py
class Branch (line 20) | class Branch(apiobject.APIObject):
method __init__ (line 23) | def __init__(self, branch_id, name, repository_id, head_id):
method getRepository (line 31) | def getRepository(self, critic):
method getHead (line 34) | def getHead(self, critic):
method getCommits (line 40) | def getCommits(self, critic):
function fetch (line 54) | def fetch(critic, branch_id, repository, name):
function fetchAll (line 75) | def fetchAll(critic, repository):
FILE: src/api/impl/branch_unittest.py
function basic (line 1) | def basic(arguments):
function main (line 57) | def main(argv):
FILE: src/api/impl/changeset.py
class Changeset (line 26) | class Changeset(apiobject.APIObject):
method __init__ (line 29) | def __init__(self, id, changeset_type, from_commit_id, to_commit_id, f...
method getFromCommit (line 37) | def getFromCommit(self):
method getToCommit (line 43) | def getToCommit(self):
method getContributingCommits (line 49) | def getContributingCommits(self, critic):
function fetch (line 59) | def fetch(critic, repository, changeset_id, from_commit, to_commit,
function fetch_by_id (line 120) | def fetch_by_id(critic, repository, changeset_id):
function get_changeset_id (line 160) | def get_changeset_id(critic, repository, from_commit, to_commit):
function request_changeset_creation (line 181) | def request_changeset_creation(critic,
FILE: src/api/impl/changeset_unittest.py
function pre (line 291) | def pre():
function post (line 305) | def post():
function is_empty_changeset (line 318) | def is_empty_changeset(changeset, changeset_type):
function check_types (line 323) | def check_types(changeset):
function custom_changeset (line 329) | def custom_changeset(phase, api, critic, repository):
function direct_changeset (line 362) | def direct_changeset(phase, api, critic, repository):
function root_changeset (line 425) | def root_changeset(phase, api, critic, repository):
function bad_changesets (line 449) | def bad_changesets(phase, api, critic, repository):
FILE: src/api/impl/comment.py
class Comment (line 21) | class Comment(apiobject.APIObject):
method __translateState (line 35) | def __translateState(state):
method __init__ (line 38) | def __init__(self, chain_id, review_id, batch_id, author_id, comment_t...
method getReview (line 62) | def getReview(self, critic):
method getAuthor (line 65) | def getAuthor(self, critic):
method getLocation (line 68) | def getLocation(self, critic):
method getReplies (line 110) | def getReplies(self, critic):
method getAddressedBy (line 113) | def getAddressedBy(self, critic):
method getResolvedBy (line 119) | def getResolvedBy(self, critic):
method getDraftChanges (line 124) | def getDraftChanges(self, critic):
method refresh (line 177) | def refresh(critic, tables, cached_comments):
function fetch (line 193) | def fetch(critic, comment_id):
function fetchMany (line 207) | def fetchMany(critic, comment_ids):
function fetchAll (line 220) | def fetchAll(critic, review, author, comment_type, state, location_type,
class Location (line 313) | class Location(apiobject.APIObject):
method __init__ (line 314) | def __init__(self, first_line, last_line):
class CommitMessageLocation (line 318) | class CommitMessageLocation(Location):
method __init__ (line 321) | def __init__(self, first_line, last_line, repository, commit_id):
method getCommit (line 326) | def getCommit(self, critic):
function makeCommitMessageLocation (line 329) | def makeCommitMessageLocation(critic, first_line, last_line, commit):
class FileVersionLocation (line 343) | class FileVersionLocation(Location):
method __init__ (line 346) | def __init__(self, comment, first_line, last_line, repository, file_id,
method getChangeset (line 364) | def getChangeset(self, critic):
method getCommit (line 378) | def getCommit(self, critic):
method getFile (line 385) | def getFile(self, critic):
method translateTo (line 388) | def translateTo(self, critic, changeset, commit):
function makeFileVersionLocation (line 431) | def makeFileVersionLocation(critic, first_line, last_line, file, changeset,
FILE: src/api/impl/comment_unittest.py
function basic (line 4) | def basic(arguments):
function main (line 121) | def main(argv):
FILE: src/api/impl/commit.py
class Commit (line 30) | class Commit(apiobject.APIObject):
method __init__ (line 33) | def __init__(self, repository, internal):
method getId (line 40) | def getId(self, critic):
method getSummary (line 43) | def getSummary(self):
method getParents (line 50) | def getParents(self, critic):
method getDescription (line 54) | def getDescription(self, critic):
method getAuthor (line 57) | def getAuthor(self, critic):
method getCommitter (line 64) | def getCommitter(self, critic):
method isAncestorOf (line 71) | def isAncestorOf(self, commit):
method getFileInformation (line 74) | def getFileInformation(self, file):
method getFileContents (line 84) | def getFileContents(self, file):
method getFileLines (line 90) | def getFileLines(self, file):
method create (line 97) | def create(critic, repository, commit_id, sha1):
function fetch (line 108) | def fetch(repository, commit_id, sha1, ref):
function fetchMany (line 161) | def fetchMany(repository, commit_ids, sha1s):
FILE: src/api/impl/commit_unittest.py
function basic (line 33) | def basic():
FILE: src/api/impl/commitset.py
class CommitSet (line 20) | class CommitSet(apiobject.APIObject):
method __init__ (line 23) | def __init__(self, commits):
method __iter__ (line 36) | def __iter__(self):
method __len__ (line 38) | def __len__(self):
method __contains__ (line 40) | def __contains__(self, item):
method __hash__ (line 42) | def __hash__(self):
method __eq__ (line 44) | def __eq__(self, other):
method getFilteredTails (line 47) | def getFilteredTails(self, critic):
method getDateOrdered (line 75) | def getDateOrdered(self):
method getTopoOrdered (line 100) | def getTopoOrdered(self):
method getChildrenOf (line 128) | def getChildrenOf(self, commit):
method getParentsOf (line 131) | def getParentsOf(self, commit):
method getDescendantsOf (line 135) | def getDescendantsOf(self, commits, include_self):
method getAncestorsOf (line 150) | def getAncestorsOf(self, commits, include_self):
method union (line 163) | def union(self, critic, commits):
method intersection (line 165) | def intersection(self, critic, commits):
method difference (line 167) | def difference(self, critic, commits):
method symmetric_difference (line 169) | def symmetric_difference(self, critic, commits):
function create (line 172) | def create(critic, commits):
function calculateFromRange (line 181) | def calculateFromRange(critic, from_commit, to_commit):
FILE: src/api/impl/commitset_unittest.py
function basic (line 1) | def basic(arguments):
function main (line 147) | def main(argv):
FILE: src/api/impl/config_unittest.py
function basic (line 1) | def basic():
FILE: src/api/impl/critic.py
class NoKey (line 20) | class NoKey(object):
class Critic (line 23) | class Critic(object):
method __init__ (line 24) | def __init__(self):
method setDatabase (line 30) | def setDatabase(self, database):
method getEffectiveUser (line 33) | def getEffectiveUser(self, critic):
method lookup (line 38) | def lookup(self, cls, key=NoKey):
method assign (line 44) | def assign(self, cls, key, value):
method transactionEnded (line 48) | def transactionEnded(critic, tables):
function startSession (line 54) | def startSession(for_user, for_system, for_testing):
FILE: src/api/impl/extension.py
class Extension (line 22) | class Extension(apiobject.APIObject):
method __init__ (line 25) | def __init__(self, extension_id, name, publisher_id):
method getKey (line 30) | def getKey(self, critic):
method getPublisher (line 36) | def getPublisher(self, critic):
function fetch (line 42) | def fetch(critic, extension_id, key):
function fetchAll (line 78) | def fetchAll(critic, publisher, installed_by):
FILE: src/api/impl/file.py
class File (line 21) | class File(apiobject.APIObject):
method __init__ (line 24) | def __init__(self, file_id, path):
function _fetch_by_ids (line 28) | def _fetch_by_ids(critic, file_ids):
function _fetch_by_paths (line 38) | def _fetch_by_paths(critic, paths, create):
function fetch (line 50) | def fetch(critic, file_id, path, create):
function fetchMany (line 57) | def fetchMany(critic, file_ids, paths, create):
FILE: src/api/impl/filechange.py
class FileChange (line 21) | class FileChange(apiobject.APIObject):
method __init__ (line 24) | def __init__(self, changeset,
method getFile (line 33) | def getFile(self, critic):
function fetch (line 38) | def fetch(critic, changeset, file):
function fetchAll (line 51) | def fetchAll(critic, changeset):
FILE: src/api/impl/filechange_unittest.py
function pre (line 4) | def pre():
function post (line 17) | def post():
function assert_valid_filechanges (line 31) | def assert_valid_filechanges(filechanges):
function root_filechange (line 47) | def root_filechange(phase, api, critic, repository):
function custom_filechange (line 72) | def custom_filechange(phase, api, critic, repository):
function single_filechange (line 94) | def single_filechange(phase, api, critic, repository):
FILE: src/api/impl/filecontent.py
class Filecontent (line 24) | class Filecontent(apiobject.APIObject):
method __init__ (line 27) | def __init__(self, critic, repository, blob_sha1, file_obj):
method getLines (line 35) | def getLines(self, first_row, last_row):
function fetch (line 53) | def fetch(critic, repository, blob_sha1, file_obj):
FILE: src/api/impl/filediff.py
class Filediff (line 27) | class Filediff(apiobject.APIObject):
method __init__ (line 30) | def __init__(self, filechange):
method cache_key (line 44) | def cache_key(filechange):
method __getChunks (line 47) | def __getChunks(self, critic):
method __getLegacyFile (line 84) | def __getLegacyFile(self, critic):
method getMacroChunks (line 92) | def getMacroChunks(self, critic, context_lines, comments, ignore_chunks):
class MacroChunk (line 170) | class MacroChunk(object):
method __init__ (line 171) | def __init__(self, critic, legacy_macro_chunk):
method getLines (line 179) | def getLines(self):
class Line (line 188) | class Line(object):
method from_legacy_line (line 198) | def from_legacy_line(self, legacy_line):
method from_changed_line (line 207) | def from_changed_line(self, original_line, old_content_replacement,
method type_string (line 216) | def type_string(self):
method getContent (line 225) | def getContent(self):
class Part (line 248) | class Part(object):
method __init__ (line 249) | def __init__(self, part_type, content, state=None):
method copy (line 254) | def copy(self):
method with_state (line 257) | def with_state(self, state):
class SkinnyCommentChain (line 261) | class SkinnyCommentChain(object):
method __init__ (line 262) | def __init__(self, critic, location):
function fetch (line 279) | def fetch(critic, filechange):
function fetchAll (line 289) | def fetchAll(critic, changeset):
function parts_from_html (line 296) | def parts_from_html(content):
class Parts (line 303) | class Parts(object):
method __init__ (line 304) | def __init__(self, parts):
method extract (line 308) | def extract(self, length):
method skip (line 321) | def skip(self, length):
function perform_detailed_operations (line 325) | def perform_detailed_operations(operations, old_content, new_content):
function perform_basic_operations (line 374) | def perform_basic_operations(line_type, old_content, new_content):
FILE: src/api/impl/filediff_unittest.py
function pre1 (line 3) | def pre1():
function pre2 (line 20) | def pre2():
function post (line 43) | def post():
FILE: src/api/impl/filters.py
class RepositoryFilter (line 20) | class RepositoryFilter(apiobject.APIObject):
method __init__ (line 23) | def __init__(self, filter_id, subject_id, filter_type, path, repositor...
method getSubject (line 35) | def getSubject(self, critic):
method getRepository (line 40) | def getRepository(self, critic):
method getDelegates (line 46) | def getDelegates(self, critic):
method refresh (line 54) | def refresh(critic, tables, cached_filters):
function fetchRepositoryFilter (line 65) | def fetchRepositoryFilter(critic, filter_id):
class ReviewFilter (line 76) | class ReviewFilter(object):
method __init__ (line 79) | def __init__(self, subject_id, filter_type, path, filter_id, review_id,
method getSubject (line 91) | def getSubject(self, critic):
method getReview (line 96) | def getReview(self, critic):
method getCreator (line 101) | def getCreator(self, critic):
FILE: src/api/impl/labeledaccesscontrolprofile.py
class LabeledAccessControlProfile (line 24) | class LabeledAccessControlProfile(apiobject.APIObject):
method __init__ (line 27) | def __init__(self, labels, profile_id):
method getAccessControlProfile (line 31) | def getAccessControlProfile(self, critic):
function fetch (line 35) | def fetch(critic, labels):
function fetchAll (line 46) | def fetchAll(critic, profile):
FILE: src/api/impl/log/partition.py
class Partition (line 3) | class Partition(object):
method __init__ (line 4) | def __init__(self, commits):
method wrap (line 11) | def wrap(self, critic):
function create (line 14) | def create(critic, commits, rebases):
FILE: src/api/impl/log/partition_unittest.py
function basic (line 1) | def basic():
FILE: src/api/impl/log/rebase.py
class Rebase (line 4) | class Rebase(apiobject.APIObject):
method __init__ (line 7) | def __init__(self, rebase_id, review_id, creator_id,
method getReview (line 25) | def getReview(self, critic):
method getRepository (line 28) | def getRepository(self, critic):
method getOldHead (line 31) | def getOldHead(self, critic):
method getNewHead (line 35) | def getNewHead(self, critic):
method getOldUpstream (line 42) | def getOldUpstream(self, critic):
method getNewUpstream (line 46) | def getNewUpstream(self, critic):
method getEquivalentMerge (line 50) | def getEquivalentMerge(self, critic):
method getReplayedRebase (line 57) | def getReplayedRebase(self, critic):
method getCreator (line 64) | def getCreator(self, critic):
function fetch (line 68) | def fetch(critic, rebase_id):
function fetchAll (line 82) | def fetchAll(critic, review, pending):
FILE: src/api/impl/log/rebase_unittest.py
function basic (line 1) | def basic():
FILE: src/api/impl/reply.py
class Reply (line 20) | class Reply(apiobject.APIObject):
method __init__ (line 23) | def __init__(self, reply_id, state, comment_id, batch_id, author_id,
method __cmp__ (line 33) | def __cmp__(self, other):
method getComment (line 36) | def getComment(self, critic):
method getAuthor (line 39) | def getAuthor(self, critic):
method refresh (line 43) | def refresh(critic, tables, cached_replies):
function fetch (line 55) | def fetch(critic, reply_id):
function fetchMany (line 68) | def fetchMany(critic, reply_ids):
function fetchForComment (line 80) | def fetchForComment(critic, chain_id):
FILE: src/api/impl/reply_unittest.py
function basic (line 4) | def basic(arguments):
function main (line 77) | def main(argv):
FILE: src/api/impl/repository.py
class Repository (line 28) | class Repository(apiobject.APIObject):
method __init__ (line 31) | def __init__(self, repository_id, name, path):
method getInternal (line 38) | def getInternal(self, critic):
method getURL (line 44) | def getURL(self, critic):
method run (line 48) | def run(self, *args):
method resolveRef (line 61) | def resolveRef(self, ref, expect, short):
method listCommits (line 76) | def listCommits(self, repository, include, exclude, args, paths):
method create (line 86) | def create(Repository, critic, repository_id, name, path):
function fetch (line 93) | def fetch(critic, repository_id, name, path):
function fetchAll (line 120) | def fetchAll(critic):
function fetchHighlighted (line 128) | def fetchHighlighted(critic, user):
FILE: src/api/impl/repository_unittest.py
function basic (line 1) | def basic(arguments):
function main (line 116) | def main(argv):
FILE: src/api/impl/review.py
class Review (line 23) | class Review(apiobject.APIObject):
method __init__ (line 26) | def __init__(self, review_id, repository_id, branch_id, state, summary,
method getRepository (line 47) | def getRepository(self, critic):
method getBranch (line 50) | def getBranch(self, critic):
method __fetchOwners (line 53) | def __fetchOwners(self, critic):
method getOwners (line 63) | def getOwners(self, critic):
method __fetchAssignedReviewers (line 68) | def __fetchAssignedReviewers(self, critic):
method getAssignedReviewers (line 80) | def getAssignedReviewers(self, critic):
method __fetchActiveReviewers (line 85) | def __fetchActiveReviewers(self, critic):
method getActiveReviewers (line 97) | def getActiveReviewers(self, critic):
method __fetchWatchers (line 102) | def __fetchWatchers(self, critic):
method getWatchers (line 117) | def getWatchers(self, critic):
method getFilters (line 122) | def getFilters(self, critic):
method getCommits (line 134) | def getCommits(self, critic):
method getRebases (line 166) | def getRebases(self, wrapper):
method getPendingRebase (line 169) | def getPendingRebase(self, wrapper):
method getIssues (line 176) | def getIssues(self, wrapper):
method getOpenIssues (line 182) | def getOpenIssues(self, wrapper):
method getNotes (line 190) | def getNotes(self, wrapper):
method isReviewableCommit (line 196) | def isReviewableCommit(self, critic, commit):
method getTotalProgress (line 207) | def getTotalProgress(self, critic):
method getProgressPerCommit (line 238) | def getProgressPerCommit(self, critic):
method create (line 276) | def create(Review, critic, *args):
function fetch (line 283) | def fetch(critic, review_id, branch):
function fetchMany (line 307) | def fetchMany(critic, review_ids):
function fetchAll (line 320) | def fetchAll(critic, repository, state):
FILE: src/api/impl/review_unittest.py
function basic (line 1) | def basic():
FILE: src/api/impl/reviewablefilechange.py
class ReviewableFileChange (line 20) | class ReviewableFileChange(apiobject.APIObject):
method __init__ (line 23) | def __init__(self, filechange_id, review_id, changeset_id, file_id,
method getReview (line 37) | def getReview(self, critic):
method getChangeset (line 40) | def getChangeset(self, critic):
method getFile (line 45) | def getFile(self, critic):
method getReviewedBy (line 48) | def getReviewedBy(self, critic):
method getAssignedReviewers (line 53) | def getAssignedReviewers(self, critic):
method getDraftChanges (line 84) | def getDraftChanges(self, critic):
method refresh (line 131) | def refresh(critic, tables, cached_filechanges):
function fetch (line 146) | def fetch(critic, filechange_id):
function fetchMany (line 157) | def fetchMany(critic, filechange_ids):
function fetchAll (line 166) | def fetchAll(critic, review, changeset, file, assignee, is_reviewed):
FILE: src/api/impl/reviewsummary.py
class ReviewSummaryContainer (line 25) | class ReviewSummaryContainer(apiobject.APIObject):
method __init__ (line 27) | def __init__(self, review_summaries, more):
class ReviewSummary (line 31) | class ReviewSummary(apiobject.APIObject):
method __init__ (line 33) | def __init__(self, review, latest_change):
function fetchMany (line 37) | def fetchMany(critic, search_type, user, count, offset):
FILE: src/api/impl/user.py
class User (line 22) | class User(apiobject.APIObject):
method __init__ (line 25) | def __init__(self, user_id, name, fullname, status, email):
method isAnonymous (line 35) | def isAnonymous(self):
method getInternal (line 38) | def getInternal(self, critic):
method getPrimaryEmails (line 46) | def getPrimaryEmails(self, critic):
method getGitEmails (line 60) | def getGitEmails(self, critic):
method getRepositoryFilters (line 68) | def getRepositoryFilters(self, critic):
method hasRole (line 93) | def hasRole(self, critic, role):
method getPreference (line 106) | def getPreference(self, critic, item, user, repository):
method refresh (line 157) | def refresh(critic, tables, cached_users):
function fetch (line 172) | def fetch(critic, user_id, name):
function fetchMany (line 182) | def fetchMany(critic, user_ids, names):
function fetchAll (line 220) | def fetchAll(critic, status):
function anonymous (line 238) | def anonymous(critic):
FILE: src/api/impl/user_unittest.py
function basic (line 1) | def basic(arguments):
function preferences (line 249) | def preferences():
function main (line 313) | def main(argv):
FILE: src/api/labeledaccesscontrolprofile.py
class LabeledAccessControlProfileError (line 19) | class LabeledAccessControlProfileError(api.APIError):
class InvalidAccessControlProfileLabels (line 24) | class InvalidAccessControlProfileLabels(LabeledAccessControlProfileError):
method __init__ (line 27) | def __init__(self, value):
class LabeledAccessControlProfile (line 33) | class LabeledAccessControlProfile(api.APIObject):
method __str__ (line 38) | def __str__(self):
method __hash__ (line 40) | def __hash__(self):
method __eq__ (line 42) | def __eq__(self, other):
method labels (line 46) | def labels(self):
method profile (line 51) | def profile(self):
function fetch (line 55) | def fetch(critic, labels):
function fetchAll (line 62) | def fetchAll(critic, profile=None):
FILE: src/api/log/partition.py
class PartitionError (line 3) | class PartitionError(api.APIError):
class Partition (line 7) | class Partition(api.APIObject):
class Edge (line 16) | class Edge(object):
method __init__ (line 19) | def __init__(self, rebase, partition):
method rebase (line 24) | def rebase(self):
method partition (line 29) | def partition(self):
method preceding (line 34) | def preceding(self):
method following (line 39) | def following(self):
method commits (line 44) | def commits(self):
function create (line 50) | def create(critic, commits, rebases=[]):
FILE: src/api/log/rebase.py
class RebaseError (line 3) | class RebaseError(api.APIError):
class InvalidRebaseId (line 7) | class InvalidRebaseId(RebaseError):
method __init__ (line 10) | def __init__(self, value):
class Rebase (line 15) | class Rebase(api.APIObject):
method id (line 19) | def id(self):
method review (line 23) | def review(self):
method old_head (line 27) | def old_head(self):
method new_head (line 31) | def new_head(self):
method creator (line 35) | def creator(self):
class HistoryRewrite (line 38) | class HistoryRewrite(Rebase):
class MoveRebase (line 47) | class MoveRebase(Rebase):
method old_upstream (line 54) | def old_upstream(self):
method new_upstream (line 58) | def new_upstream(self):
method equivalent_merge (line 62) | def equivalent_merge(self):
method replayed_rebase (line 66) | def replayed_rebase(self):
function fetch (line 69) | def fetch(critic, rebase_id):
function fetchAll (line 75) | def fetchAll(critic, review=None, pending=False):
FILE: src/api/preference.py
class InvalidPreferenceItem (line 19) | class InvalidPreferenceItem(api.APIError):
method __init__ (line 22) | def __init__(self, item):
class Preference (line 27) | class Preference(object):
method __init__ (line 28) | def __init__(self, item, value, user, repository):
method __bool__ (line 34) | def __bool__(self):
method __int__ (line 36) | def __int__(self):
method __str__ (line 38) | def __str__(self):
method item (line 42) | def item(self):
method value (line 46) | def value(self):
method user (line 50) | def user(self):
method repository (line 54) | def repository(self):
FILE: src/api/reply.py
class ReplyError (line 19) | class ReplyError(api.APIError):
class InvalidReplyId (line 22) | class InvalidReplyId(ReplyError):
method __init__ (line 25) | def __init__(self, reply_id):
class InvalidReplyIds (line 31) | class InvalidReplyIds(ReplyError):
method __init__ (line 34) | def __init__(self, reply_ids):
class Reply (line 40) | class Reply(api.APIObject):
method id (line 42) | def id(self):
method is_draft (line 47) | def is_draft(self):
method comment (line 54) | def comment(self):
method author (line 61) | def author(self):
method timestamp (line 68) | def timestamp(self):
method text (line 75) | def text(self):
function fetch (line 79) | def fetch(critic, reply_id):
function fetchMany (line 86) | def fetchMany(critic, reply_ids):
FILE: src/api/repository.py
class RepositoryError (line 19) | class RepositoryError(api.APIError):
class InvalidRepositoryId (line 23) | class InvalidRepositoryId(RepositoryError):
method __init__ (line 26) | def __init__(self, repository_id):
class InvalidRepositoryName (line 31) | class InvalidRepositoryName(RepositoryError):
method __init__ (line 34) | def __init__(self, name):
class InvalidRepositoryPath (line 39) | class InvalidRepositoryPath(RepositoryError):
method __init__ (line 42) | def __init__(self, path):
class InvalidRef (line 47) | class InvalidRef(RepositoryError):
method __init__ (line 50) | def __init__(self, ref):
class GitCommandError (line 55) | class GitCommandError(RepositoryError):
method __init__ (line 58) | def __init__(self, argv, returncode, stdout, stderr):
class Repository (line 64) | class Repository(api.APIObject):
method id (line 68) | def id(self):
method name (line 73) | def name(self):
method path (line 78) | def path(self):
method relative_path (line 83) | def relative_path(self):
method url (line 91) | def url(self):
method resolveRef (line 98) | def resolveRef(self, ref, expect=None, short=False):
method listCommits (line 114) | def listCommits(self, include=None, exclude=None, args=None, paths=None):
function fetch (line 142) | def fetch(critic, repository_id=None, name=None, path=None):
function fetchAll (line 149) | def fetchAll(critic):
function fetchHighlighted (line 157) | def fetchHighlighted(critic, user):
FILE: src/api/review.py
class ReviewError (line 19) | class ReviewError(api.APIError):
class InvalidReviewId (line 23) | class InvalidReviewId(ReviewError):
method __init__ (line 26) | def __init__(self, review_id):
class InvalidReviewBranch (line 31) | class InvalidReviewBranch(ReviewError):
method __init__ (line 34) | def __init__(self, branch):
class Review (line 39) | class Review(api.APIObject):
method id (line 45) | def id(self):
method state (line 50) | def state(self):
method summary (line 55) | def summary(self):
method description (line 60) | def description(self):
method repository (line 65) | def repository(self):
method branch (line 72) | def branch(self):
method owners (line 79) | def owners(self):
method assigned_reviewers (line 86) | def assigned_reviewers(self):
method active_reviewers (line 97) | def active_reviewers(self):
method watchers (line 107) | def watchers(self):
method filters (line 117) | def filters(self):
method commits (line 125) | def commits(self):
method rebases (line 136) | def rebases(self):
method pending_rebase (line 144) | def pending_rebase(self):
method issues (line 152) | def issues(self):
method open_issues (line 159) | def open_issues(self):
method notes (line 166) | def notes(self):
method first_partition (line 173) | def first_partition(self):
method isReviewableCommit (line 177) | def isReviewableCommit(self, commit):
method total_progress (line 187) | def total_progress(self):
method progress_per_commit (line 195) | def progress_per_commit(self):
class CommitChangeCount (line 202) | class CommitChangeCount:
method __init__ (line 203) | def __init__(self, commit_id, total_changes, reviewed_changes):
function fetch (line 208) | def fetch(critic, review_id=None, branch=None):
function fetchMany (line 217) | def fetchMany(critic, review_ids):
function fetchAll (line 227) | def fetchAll(critic, repository=None, state=None):
FILE: src/api/reviewablefilechange.py
class ReviewableFileChangeError (line 19) | class ReviewableFileChangeError(api.APIError):
class InvalidReviewableFileChangeId (line 22) | class InvalidReviewableFileChangeId(ReviewableFileChangeError):
method __init__ (line 24) | def __init__(self, filechange_id):
class InvalidReviewableFileChangeIds (line 29) | class InvalidReviewableFileChangeIds(ReviewableFileChangeError):
method __init__ (line 31) | def __init__(self, filechange_ids):
class InvalidChangeset (line 37) | class InvalidChangeset(ReviewableFileChangeError):
method __init__ (line 39) | def __init__(self, changeset):
class ReviewableFileChange (line 44) | class ReviewableFileChange(api.APIObject):
method id (line 48) | def id(self):
method review (line 52) | def review(self):
method changeset (line 56) | def changeset(self):
method file (line 66) | def file(self):
method deleted_lines (line 73) | def deleted_lines(self):
method inserted_lines (line 81) | def inserted_lines(self):
method is_reviewed (line 89) | def is_reviewed(self):
method reviewed_by (line 94) | def reviewed_by(self):
method assigned_reviewers (line 102) | def assigned_reviewers(self):
class DraftChanges (line 108) | class DraftChanges(object):
method __init__ (line 111) | def __init__(self, author, new_reviewed_by):
method author (line 117) | def author(self):
method new_is_reviewed (line 124) | def new_is_reviewed(self):
method new_reviewed_by (line 129) | def new_reviewed_by(self):
method draft_changes (line 134) | def draft_changes(self):
function fetch (line 142) | def fetch(critic, filechange_id):
function fetchMany (line 148) | def fetchMany(critic, filechange_ids):
function fetchAll (line 156) | def fetchAll(critic, review, changeset=None, file=None, assignee=None,
FILE: src/api/reviewsummary.py
class ReviewSummaryError (line 20) | class ReviewSummaryError(api.APIError):
class ReviewSummaryContainer (line 23) | class ReviewSummaryContainer(api.APIObject):
method reviews (line 27) | def reviews(self):
method more (line 31) | def more(self):
class ReviewSummary (line 34) | class ReviewSummary(api.APIObject):
method review (line 40) | def review(self):
method latest_change (line 44) | def latest_change(self):
function fetchMany (line 47) | def fetchMany(critic, search_type, user, count, offset):
FILE: src/api/transaction/__init__.py
class Transaction (line 19) | class Transaction(object):
method __init__ (line 20) | def __init__(self, critic):
method modifyUser (line 26) | def modifyUser(self, subject):
method modifyAccessToken (line 32) | def modifyAccessToken(self, access_token):
method createAccessControlProfile (line 39) | def createAccessControlProfile(self, callback=None):
method modifyAccessControlProfile (line 44) | def modifyAccessControlProfile(self, profile):
method createLabeledAccessControlProfile (line 51) | def createLabeledAccessControlProfile(self, labels, profile, callback=...
method modifyLabeledAccessControlProfile (line 60) | def modifyLabeledAccessControlProfile(self, labeled_profile):
method modifyReview (line 69) | def modifyReview(self, review):
method __enter__ (line 74) | def __enter__(self):
method __exit__ (line 77) | def __exit__(self, exc_type, exc_val, exc_tb):
method __commit (line 82) | def __commit(self):
class Query (line 94) | class Query(object):
method __init__ (line 95) | def __init__(self, statement, *values, **kwargs):
method merge (line 100) | def merge(self, query):
method values (line 109) | def values(self):
method __call__ (line 121) | def __call__(self, critic, cursor):
class Queries (line 130) | class Queries(list):
method append (line 131) | def append(self, query):
method extend (line 136) | def extend(self, queries):
class LazyValue (line 139) | class LazyValue(object):
method evaluate (line 140) | def evaluate(self):
class LazyInt (line 143) | class LazyInt(LazyValue):
method __init__ (line 144) | def __init__(self, source):
method evaluate (line 146) | def evaluate(self):
class LazyStr (line 149) | class LazyStr(LazyValue):
method __init__ (line 150) | def __init__(self, source):
method evaluate (line 152) | def evaluate(self):
class LazyObject (line 155) | class LazyObject(LazyValue):
method __init__ (line 156) | def __init__(self, callback=None):
method __call__ (line 159) | def __call__(self, object_id):
method id (line 164) | def id(self):
method evaluate (line 166) | def evaluate(self):
class LazyAPIObject (line 170) | class LazyAPIObject(LazyObject):
method __init__ (line 171) | def __init__(self, critic, fetch, callback=None):
method fetch (line 177) | def fetch(self):
method callback_wrapper (line 180) | def callback_wrapper(self):
FILE: src/api/transaction/accesscontrolprofile.py
class InvalidRuleValue (line 19) | class InvalidRuleValue(api.TransactionError):
class InvalidRequestMethod (line 22) | class InvalidRequestMethod(api.TransactionError):
class InvalidPathPattern (line 25) | class InvalidPathPattern(api.TransactionError):
class InvalidRepositoryAccessType (line 28) | class InvalidRepositoryAccessType(api.TransactionError):
class InvalidExtensionAccessType (line 31) | class InvalidExtensionAccessType(api.TransactionError):
class ModifyExceptions (line 34) | class ModifyExceptions(object):
method __init__ (line 35) | def __init__(self, transaction, profile):
method __addTable (line 39) | def __addTable(self):
method delete (line 42) | def delete(self, exception_id):
method deleteAll (line 52) | def deleteAll(self):
method add (line 61) | def add(self, *values):
class ModifyHTTPExceptions (line 72) | class ModifyHTTPExceptions(ModifyExceptions):
method add (line 76) | def add(self, request_method, path_pattern):
class ModifyRepositoriesExceptions (line 94) | class ModifyRepositoriesExceptions(ModifyExceptions):
method add (line 98) | def add(self, access_type, repository):
class ModifyExtensionsExceptions (line 110) | class ModifyExtensionsExceptions(ModifyExceptions):
method add (line 114) | def add(self, access_type, extension):
class ModifyAccessControlProfile (line 126) | class ModifyAccessControlProfile(object):
method __init__ (line 127) | def __init__(self, transaction, profile):
method setTitle (line 131) | def setTitle(self, value):
method setRule (line 140) | def setRule(self, category, value):
method modifyExceptions (line 153) | def modifyExceptions(self, category):
method delete (line 162) | def delete(self):
method create (line 172) | def create(transaction, callback=None):
class CreatedAccessControlProfile (line 189) | class CreatedAccessControlProfile(api.transaction.LazyAPIObject):
method __init__ (line 190) | def __init__(self, critic, access_token, callback=None):
FILE: src/api/transaction/accesstoken.py
class ModifyAccessToken (line 19) | class ModifyAccessToken(object):
method __init__ (line 20) | def __init__(self, transaction, access_token):
method setTitle (line 24) | def setTitle(self, value):
method delete (line 33) | def delete(self):
method modifyProfile (line 42) | def modifyProfile(self):
class CreatedAccessToken (line 48) | class CreatedAccessToken(api.transaction.LazyAPIObject):
method __init__ (line 49) | def __init__(self, critic, user, callback=None):
FILE: src/api/transaction/comment.py
class ModifyComment (line 19) | class ModifyComment(object):
method __init__ (line 20) | def __init__(self, transaction, comment):
method __raiseUnlessDraft (line 24) | def __raiseUnlessDraft(self, action):
method setText (line 29) | def setText(self, text):
method addReply (line 42) | def addReply(self, author, text, callback=None):
method modifyReply (line 73) | def modifyReply(self, reply):
method resolveIssue (line 83) | def resolveIssue(self):
method reopenIssue (line 126) | def reopenIssue(self):
method delete (line 165) | def delete(self):
class CreatedReply (line 180) | class CreatedReply(api.transaction.LazyAPIObject):
method __init__ (line 181) | def __init__(self, critic, comment, callback=None):
FILE: src/api/transaction/filters.py
class ModifyRepositoryFilter (line 19) | class ModifyRepositoryFilter(object):
method __init__ (line 20) | def __init__(self, transaction, repository_filter):
method setDelegates (line 24) | def setDelegates(self, value):
method delete (line 35) | def delete(self):
FILE: src/api/transaction/labeledaccesscontrolprofile.py
class ModifyLabeledAccessControlProfile (line 19) | class ModifyLabeledAccessControlProfile(object):
method __init__ (line 20) | def __init__(self, transaction, labeled_profile):
method delete (line 24) | def delete(self):
method create (line 34) | def create(transaction, labels, profile, callback=None):
class CreatedLabeledAccessControlProfile (line 51) | class CreatedLabeledAccessControlProfile(api.transaction.LazyAPIObject):
method __init__ (line 52) | def __init__(self, critic, callback=None):
FILE: src/api/transaction/reply.py
class ModifyReply (line 19) | class ModifyReply(object):
method __init__ (line 20) | def __init__(self, transaction, reply):
method __raiseUnlessDraft (line 24) | def __raiseUnlessDraft(self, action):
method setText (line 29) | def setText(self, text):
method delete (line 43) | def delete(self):
FILE: src/api/transaction/review.py
class ModifyReview (line 24) | class ModifyReview(object):
method __init__ (line 25) | def __init__(self, transaction, review):
method createComment (line 29) | def createComment(self, comment_type, author, text, location=None,
method modifyComment (line 124) | def modifyComment(self, comment):
method prepareRebase (line 136) | def prepareRebase(self, user, new_upstream=None, history_rewrite=None,...
method cancelRebase (line 208) | def cancelRebase(self, rebase):
method submitChanges (line 219) | def submitChanges(self, batch_comment, callback):
method markChangeAsReviewed (line 428) | def markChangeAsReviewed(self, filechange):
method markChangeAsPending (line 467) | def markChangeAsPending(self, filechange):
class CreatedComment (line 506) | class CreatedComment(api.transaction.LazyAPIObject):
method __init__ (line 507) | def __init__(self, critic, review, callback=None):
class CreatedRebase (line 512) | class CreatedRebase(api.transaction.LazyAPIObject):
method __init__ (line 513) | def __init__(self, critic, review, callback=None):
class CreatedBatch (line 518) | class CreatedBatch(api.transaction.LazyAPIObject):
method __init__ (line 519) | def __init__(self, critic, review):
FILE: src/api/transaction/user.py
class ModifyUser (line 19) | class ModifyUser(object):
method __init__ (line 20) | def __init__(self, transaction, user):
method setFullname (line 24) | def setFullname(self, value):
method createFilter (line 36) | def createFilter(self, filter_type, repository, path, delegates,
method modifyFilter (line 59) | def modifyFilter(self, repository_filter):
method createAccessToken (line 67) | def createAccessToken(self, access_type, title, callback=None):
method modifyAccessToken (line 107) | def modifyAccessToken(self, access_token):
FILE: src/api/user.py
class UserError (line 19) | class UserError(api.APIError):
class InvalidUserIds (line 23) | class InvalidUserIds(UserError):
method __init__ (line 26) | def __init__(self, values):
class InvalidUserId (line 31) | class InvalidUserId(InvalidUserIds):
method __init__ (line 34) | def __init__(self, value):
class InvalidUserNames (line 40) | class InvalidUserNames(UserError):
method __init__ (line 43) | def __init__(self, values):
class InvalidUserName (line 49) | class InvalidUserName(InvalidUserNames):
method __init__ (line 52) | def __init__(self, value):
class InvalidRole (line 58) | class InvalidRole(UserError):
method __init__ (line 61) | def __init__(self, role):
class User (line 66) | class User(api.APIObject):
method id (line 72) | def id(self):
method name (line 77) | def name(self):
method fullname (line 82) | def fullname(self):
method status (line 87) | def status(self):
method is_anonymous (line 98) | def is_anonymous(self):
method email (line 103) | def email(self):
class PrimaryEmail (line 110) | class PrimaryEmail(object):
method __init__ (line 123) | def __init__(self, address, selected, verified):
method primary_emails (line 129) | def primary_emails(self):
method git_emails (line 136) | def git_emails(self):
method repository_filters (line 147) | def repository_filters(self):
method internal (line 155) | def internal(self):
method hasRole (line 161) | def hasRole(self, role):
method getPreference (line 168) | def getPreference(self, item, repository=None):
function fetch (line 182) | def fetch(critic, user_id=None, name=None):
function fetchMany (line 196) | def fetchMany(critic, user_ids=None, names=None):
function fetchAll (line 216) | def fetchAll(critic, status=None):
function anonymous (line 232) | def anonymous(critic):
FILE: src/auth/__init__.py
class CheckFailed (line 24) | class CheckFailed(Exception): pass
class NoSuchUser (line 25) | class NoSuchUser(CheckFailed): pass
class WrongPassword (line 26) | class WrongPassword(CheckFailed): pass
function createCryptContext (line 28) | def createCryptContext():
function checkPassword (line 61) | def checkPassword(db, username, password):
function hashPassword (line 86) | def hashPassword(password):
function getToken (line 89) | def getToken(encode=base64.b64encode, length=20):
class InvalidUserName (line 92) | class InvalidUserName(Exception): pass
function validateUserName (line 94) | def validateUserName(name):
function isValidUserName (line 105) | def isValidUserName(name):
class InvalidRequest (line 112) | class InvalidRequest(Exception):
class Failure (line 115) | class Failure(Exception):
FILE: src/auth/accesscontrol.py
class AccessDenied (line 23) | class AccessDenied(Exception):
class AccessControlError (line 27) | class AccessControlError(Exception):
class HTTPException (line 31) | class HTTPException(object):
method __init__ (line 32) | def __init__(self, request_method, path_pattern):
method applies (line 37) | def applies(self, req):
class RepositoryException (line 46) | class RepositoryException(object):
method __init__ (line 47) | def __init__(self, access_type, repository_id):
method applies (line 51) | def applies(self, access_type, repository_id):
class ExtensionException (line 60) | class ExtensionException(object):
method __init__ (line 61) | def __init__(self, access_type, extension_key):
method applies (line 65) | def applies(self, access_type, extension):
function _isAllowed (line 74) | def _isAllowed(rule, exceptions, *args):
class AccessControlProfile (line 81) | class AccessControlProfile(object):
method __init__ (line 82) | def __init__(self, *rules):
method isAllowedHTTP (line 95) | def isAllowedHTTP(profiles, req):
method isAllowedRepository (line 100) | def isAllowedRepository(profiles, access_type, repository_id):
method isAllowedExtension (line 107) | def isAllowedExtension(profiles, access_type, extension):
method forUser (line 114) | def forUser(db, user, authentication_labels=()):
method fromId (line 161) | def fromId(db, profile_id):
class AccessControl (line 198) | class AccessControl(object):
method forRequest (line 200) | def forRequest(db, req):
method accessHTTP (line 210) | def accessHTTP(db, req):
class Repository (line 214) | class Repository(object):
method __init__ (line 215) | def __init__(self, repository_id, path):
method accessRepository (line 220) | def accessRepository(db, access_type, repository):
method accessExtension (line 227) | def accessExtension(db, access_type, extension):
FILE: src/auth/database.py
class AuthenticationError (line 19) | class AuthenticationError(Exception):
class AuthenticationFailed (line 30) | class AuthenticationFailed(Exception):
class Database (line 42) | class Database(object):
method __init__ (line 43) | def __init__(self, name):
method getFields (line 47) | def getFields(self):
method authenticate (line 69) | def authenticate(self, db, fields):
method getAuthenticationLabels (line 84) | def getAuthenticationLabels(self, user):
method supportsHTTPAuthentication (line 87) | def supportsHTTPAuthentication(self):
method performHTTPAuthentication (line 99) | def performHTTPAuthentication(self, db, username, password):
method supportsPasswordChange (line 107) | def supportsPasswordChange(self):
method changePassword (line 111) | def changePassword(self, db, user, current_pw, new_pw):
FILE: src/auth/databases/accesstokensdb.py
class AccessTokens (line 21) | class AccessTokens(auth.Database):
method __init__ (line 22) | def __init__(self, authdb):
method getFields (line 26) | def getFields(self):
method authenticate (line 29) | def authenticate(self, db, fields):
method getAuthenticationLabels (line 32) | def getAuthenticationLabels(self, user):
method supportsHTTPAuthentication (line 35) | def supportsHTTPAuthentication(self):
method performHTTPAuthentication (line 39) | def performHTTPAuthentication(self, db, username, password):
method supportsPasswordChange (line 77) | def supportsPasswordChange(self):
method changePassword (line 80) | def changePassword(self, db, user, current_pw, new_pw):
FILE: src/auth/databases/internaldb.py
class Internal (line 20) | class Internal(auth.Database):
method __init__ (line 21) | def __init__(self):
method getFields (line 24) | def getFields(self):
method authenticate (line 28) | def authenticate(self, db, values):
method supportsPasswordChange (line 43) | def supportsPasswordChange(self):
method changePassword (line 46) | def changePassword(self, db, user, current_pw, new_pw):
FILE: src/auth/databases/ldapdb.py
function escaped (line 25) | def escaped(fields, fn):
class LDAPCache (line 29) | class LDAPCache(object):
method __init__ (line 30) | def __init__(self, max_age):
method __key (line 37) | def __key(fields):
method get (line 40) | def get(self, fields):
method set (line 54) | def set(self, fields, value):
class LDAP (line 64) | class LDAP(auth.Database):
method __init__ (line 65) | def __init__(self):
method __startConnection (line 69) | def __startConnection(self):
method __isMemberOfGroup (line 76) | def __isMemberOfGroup(self, connection, group, fields):
method getFields (line 94) | def getFields(self):
method authenticate (line 97) | def authenticate(self, db, fields):
method getAuthenticationLabels (line 194) | def getAuthenticationLabels(self, user):
FILE: src/auth/oauth.py
class OAuthProvider (line 24) | class OAuthProvider(auth.Provider):
method start (line 25) | def start(self, db, req, target_url=None):
method finish (line 43) | def finish(self, db, req):
method validateToken (line 149) | def validateToken(self, db, account, token):
FILE: src/auth/provider.py
class Provider (line 19) | class Provider(object):
method __init__ (line 20) | def __init__(self, name):
method getTitle (line 24) | def getTitle(self):
method getAccountIdDescription (line 28) | def getAccountIdDescription(self):
method start (line 32) | def start(self, db, req, target_url=None):
method finish (line 35) | def finish(self, db, req):
FILE: src/auth/providers/dummy.py
class DummyOAuthProvider (line 23) | class DummyOAuthProvider(auth.OAuthProvider):
method __init__ (line 26) | def __init__(self, name):
method getTitle (line 30) | def getTitle(self):
method getAccountIdDescription (line 34) | def getAccountIdDescription(self):
method getAccountURL (line 37) | def getAccountURL(self, name):
method getAuthorizeURL (line 40) | def getAuthorizeURL(self, state):
method getAccessToken (line 44) | def getAccessToken(self, code):
method getUserData (line 50) | def getUserData(self, access_token):
function createProvider (line 59) | def createProvider(name, allow_user_registration, verify_email_addresses,
FILE: src/auth/providers/github.py
class GitHubAuthentication (line 23) | class GitHubAuthentication(auth.OAuthProvider):
method __init__ (line 24) | def __init__(self):
method getTitle (line 31) | def getTitle(self):
method getAccountIdDescription (line 35) | def getAccountIdDescription(self):
method getAccountURL (line 38) | def getAccountURL(self, name):
method getAuthorizeURL (line 41) | def getAuthorizeURL(self, state):
method getAccessToken (line 48) | def getAccessToken(self, code):
method getUserData (line 70) | def getUserData(self, access_token):
FILE: src/auth/providers/google.py
class GoogleAuthentication (line 23) | class GoogleAuthentication(auth.OAuthProvider):
method __init__ (line 24) | def __init__(self):
method getTitle (line 31) | def getTitle(self):
method getAccountIdDescription (line 35) | def getAccountIdDescription(self):
method getAccountURL (line 38) | def getAccountURL(self, name):
method getAuthorizeURL (line 41) | def getAuthorizeURL(self, state):
method getAccessToken (line 50) | def getAccessToken(self, code):
method getUserData (line 75) | def getUserData(self, access_token):
FILE: src/auth/session.py
function isInsecurePath (line 22) | def isInsecurePath(req):
function getUserEmailAddress (line 43) | def getUserEmailAddress(_username):
function createSessionId (line 46) | def createSessionId(db, req, user, authentication_labels=None):
function deleteSessionId (line 61) | def deleteSessionId(db, req, user):
function checkSession (line 90) | def checkSession(db, req):
FILE: src/background/branchtracker.py
class BranchTracker (line 38) | class BranchTracker(background.utils.BackgroundProcess):
method __init__ (line 39) | def __init__(self):
method update (line 42) | def update(self, trackedbranch_id, repository_id, local_name, remote, ...
method run (line 193) | def run(self):
function start_service (line 285) | def start_service():
FILE: src/background/branchtrackerhook.py
class BranchTrackerHook (line 79) | class BranchTrackerHook(PeerServer):
class WaitForUpdate (line 80) | class WaitForUpdate(PeerServer.ChildProcess):
method __init__ (line 81) | def __init__(self, client, branch_id, timeout, log_offset):
method handle_input (line 88) | def handle_input(self, _file, data):
class Client (line 104) | class Client(PeerServer.SocketPeer):
method __init__ (line 105) | def __init__(self, server, peersocket, peeraddress):
method handle_input (line 109) | def handle_input(self, _file, data):
method __init__ (line 231) | def __init__(self):
method handle_peer (line 234) | def handle_peer(self, peersocket, peeraddress):
FILE: src/background/changeset.py
function perform_job (line 32) | def perform_job():
function describeRequest (line 61) | def describeRequest(request):
class ChangesetServer (line 67) | class ChangesetServer(JSONJobServer):
method __init__ (line 68) | def __init__(self):
method execute_command (line 77) | def execute_command(self, client, command):
method request_started (line 87) | def request_started(self, job, request):
method request_finished (line 92) | def request_finished(self, job, request, result):
method __purge (line 102) | def __purge(self):
function start_service (line 126) | def start_service():
FILE: src/background/daemon.py
function detach (line 20) | def detach(parent_exit_hook=lambda: 0):
FILE: src/background/extensionrunner.py
class ExtensionRunner (line 29) | class ExtensionRunner(background.utils.PeerServer):
class Extension (line 30) | class Extension(background.utils.PeerServer.SpawnedProcess):
method __init__ (line 31) | def __init__(self, server, client, process, timeout):
method handle_input (line 38) | def handle_input(self, pipe, data):
method timed_out (line 45) | def timed_out(self):
method check_result (line 50) | def check_result(self):
class Client (line 53) | class Client(background.utils.PeerServer.SocketPeer):
method __init__ (line 54) | def __init__(self, server, peersocket):
method handle_input (line 57) | def handle_input(self, _file, data):
method finished (line 69) | def finished(self, process):
method __init__ (line 95) | def __init__(self):
method run (line 103) | def run(self):
method handle_peer (line 112) | def handle_peer(self, peersocket, peeraddress):
method peer_destroyed (line 115) | def peer_destroyed(self, peer):
method signal_idle_state (line 118) | def signal_idle_state(self):
method get_process (line 122) | def get_process(self, flavor):
method __fill_cache (line 132) | def __fill_cache(self):
method __cache_process (line 136) | def __cache_process(self):
function start_service (line 146) | def start_service():
FILE: src/background/extensiontasks.py
class ExtensionTasks (line 28) | class ExtensionTasks(background.utils.BackgroundProcess):
method __init__ (line 29) | def __init__(self):
method run (line 34) | def run(self):
function start_service (line 86) | def start_service():
FILE: src/background/githook.py
function getUserEmailAddress (line 33) | def getUserEmailAddress(_username):
function getUser (line 36) | def getUser(db, user_name):
function slave (line 50) | def slave():
class GitHookServer (line 191) | class GitHookServer(background.utils.PeerServer):
class ChildProcess (line 192) | class ChildProcess(background.utils.PeerServer.ChildProcess):
method __init__ (line 193) | def __init__(self, server, client):
method handle_input (line 197) | def handle_input(self, _file, data):
class Client (line 224) | class Client(background.utils.PeerServer.SocketPeer):
method handle_input (line 225) | def handle_input(self, _file, data):
method destroy (line 258) | def destroy(self):
method __init__ (line 263) | def __init__(self):
method startup (line 266) | def startup(self):
method handle_peer (line 271) | def handle_peer(self, peersocket, peeraddress):
function start_service (line 274) | def start_service():
FILE: src/background/highlight.py
function perform_job (line 28) | def perform_job():
class HighlightServer (line 48) | class HighlightServer(background.utils.JSONJobServer):
method __init__ (line 49) | def __init__(self):
method request_result (line 60) | def request_result(self, request):
method request_started (line 66) | def request_started(self, job, request):
method request_finished (line 71) | def request_finished(self, job, request, result):
method execute_command (line 82) | def execute_command(self, client, command):
method __compact (line 95) | def __compact(self):
function start_service (line 179) | def start_service():
FILE: src/background/maildelivery.py
class User (line 32) | class User:
method __init__ (line 33) | def __init__(self, *args):
class MailDelivery (line 39) | class MailDelivery(background.utils.PeerServer):
method __init__ (line 40) | def __init__(self, credentials):
method __sendAdministratorMessage (line 68) | def __sendAdministratorMessage(self):
method run (line 102) | def run(self):
method __connect (line 180) | def __connect(self):
method __disconnect (line 218) | def __disconnect(self):
method __send (line 227) | def __send(self, message_id, parent_message_id, headers, from_user, to...
method __cleanup (line 308) | def __cleanup(self):
function start_service (line 325) | def start_service():
FILE: src/background/maintenance.py
class Maintenance (line 29) | class Maintenance(background.utils.BackgroundProcess):
method __init__ (line 30) | def __init__(self):
method run (line 38) | def run(self):
method __maintenance (line 49) | def __maintenance(self):
function start_service (line 144) | def start_service():
FILE: src/background/servicemanager.py
class ServiceManager (line 33) | class ServiceManager(background.utils.PeerServer):
class Service (line 38) | class Service(object):
class Process (line 39) | class Process(background.utils.PeerServer.ChildProcess):
method __init__ (line 40) | def __init__(self, service, input_data):
method handle_input (line 51) | def handle_input(self, _file, data):
method destroy (line 54) | def destroy(self):
method __init__ (line 58) | def __init__(self, manager, service_data):
method signal_callbacks (line 66) | def signal_callbacks(self, event):
method start (line 69) | def start(self, input_data):
method restart (line 77) | def restart(self, callback=None):
method stop (line 82) | def stop(self, callback=None):
method stopped (line 89) | def stopped(self, returncode, output):
class Client (line 109) | class Client(background.utils.PeerServer.SocketPeer):
method __init__ (line 110) | def __init__(self, manager, peersocket):
method send_response (line 114) | def send_response(self, value):
method handle_input (line 118) | def handle_input(self, _file, data):
method __init__ (line 166) | def __init__(self, input_data):
method handle_peer (line 175) | def handle_peer(self, peersocket, peeraddress):
method startup (line 178) | def startup(self):
method shutdown (line 190) | def shutdown(self):
method requestRestart (line 196) | def requestRestart(self):
function start_service (line 202) | def start_service():
function mkdir (line 238) | def mkdir(path, mode):
function wait_for_startup_sync (line 281) | def wait_for_startup_sync():
function terminated (line 306) | def terminated(signum, frame):
FILE: src/background/utils.py
function freeze (line 35) | def freeze(d):
function thaw (line 37) | def thaw(f):
class AdministratorMailHandler (line 40) | class AdministratorMailHandler(logging.Handler):
method __init__ (line 41) | def __init__(self, logfile_path):
method emit (line 45) | def emit(self, record):
class BackgroundProcess (line 58) | class BackgroundProcess(object):
method __init__ (line 62) | def __init__(self, service, send_administrator_mails=True):
method __handle_SIGHUP (line 102) | def __handle_SIGHUP(self, signum, frame):
method __handle_SIGTERM (line 104) | def __handle_SIGTERM(self, signum, frame):
method __handle_SIGUSR1 (line 106) | def __handle_SIGUSR1(self, signum, frame):
method __handle_SIGUSR2 (line 113) | def __handle_SIGUSR2(self, signum, frame):
method __create_pidfile (line 121) | def __create_pidfile(self):
method __delete_pidfile (line 131) | def __delete_pidfile(self):
method __signal_started (line 136) | def __signal_started(self):
method __stopped (line 145) | def __stopped(self):
method start (line 149) | def start(self):
method startup (line 172) | def startup(self):
method shutdown (line 174) | def shutdown(self):
method signal_idle_state (line 177) | def signal_idle_state(self):
method error (line 185) | def error(self, message):
method warning (line 188) | def warning(self, message):
method info (line 191) | def info(self, message):
method debug (line 194) | def debug(self, message):
method exception (line 197) | def exception(self, message=None, as_warning=False):
method register_maintenance (line 206) | def register_maintenance(self, hour, minute, callback):
method run_maintenance (line 210) | def run_maintenance(self):
method run (line 255) | def run(self):
method requestRestart (line 272) | def requestRestart(self):
class PeerServer (line 275) | class PeerServer(BackgroundProcess):
class Peer (line 276) | class Peer(object):
method __init__ (line 277) | def __init__(self, server, writing, *reading, **kwargs):
method timed_out (line 299) | def timed_out(self):
method is_finished (line 304) | def is_finished(self):
method writing (line 307) | def writing(self):
method write (line 311) | def write(self, data):
method close (line 316) | def close(self):
method do_write (line 321) | def do_write(self):
method reading (line 338) | def reading(self):
method read (line 343) | def read(self):
method do_read (line 348) | def do_read(self, index):
method writing_done (line 360) | def writing_done(self, writing):
method reading_done (line 363) | def reading_done(self, reading):
method destroy (line 366) | def destroy(self):
class SocketPeer (line 369) | class SocketPeer(Peer):
method __init__ (line 370) | def __init__(self, server, clientsocket):
method reading_done (line 373) | def reading_done(self, reading):
method writing_done (line 376) | def writing_done(self, writing):
method handle_input (line 379) | def handle_input(self, _file, data):
class SpawnedProcess (line 382) | class SpawnedProcess(Peer):
method __init__ (line 383) | def __init__(self, server, process, **kwargs):
method kill (line 391) | def kill(self, signal):
method destroy (line 394) | def destroy(self):
method timed_out (line 399) | def timed_out(self):
method check_result (line 403) | def check_result(self):
class ChildProcess (line 409) | class ChildProcess(SpawnedProcess):
method __init__ (line 410) | def __init__(self, server, args, **kwargs):
method __init__ (line 416) | def __init__(self, service, **kwargs):
method __create_listening_socket (line 422) | def __create_listening_socket(self):
method __destroy_listening_socket (line 469) | def __destroy_listening_socket(self):
method run (line 477) | def run(self):
method add_peer (line 604) | def add_peer(self, peer):
method handle_peer (line 607) | def handle_peer(self, peersocket, peeraddress):
method peer_destroyed (line 610) | def peer_destroyed(self, peer):
method startup (line 613) | def startup(self):
method shutdown (line 616) | def shutdown(self):
class SlaveProcessServer (line 627) | class SlaveProcessServer(PeerServer):
class SlaveChildProcess (line 628) | class SlaveChildProcess(PeerServer.ChildProcess):
method __init__ (line 629) | def __init__(self, server, client):
method handle_input (line 633) | def handle_input(self, _file, value):
class SlaveClient (line 637) | class SlaveClient(PeerServer.SocketPeer):
method __init__ (line 638) | def __init__(self, server, peersocket):
method handle_input (line 641) | def handle_input(self, _file, value):
method handle_peer (line 648) | def handle_peer(self, peersocket, peeraddress):
class JSONJobServer (line 651) | class JSONJobServer(PeerServer):
class Job (line 652) | class Job(PeerServer.ChildProcess):
method __init__ (line 653) | def __init__(self, server, client, request):
method handle_input (line 660) | def handle_input(self, _file, value):
class JobClient (line 669) | class JobClient(PeerServer.SocketPeer):
method handle_input (line 670) | def handle_input(self, _file, value):
method has_requests (line 684) | def has_requests(self):
method get_request (line 687) | def get_request(self):
method add_result (line 690) | def add_result(self, result):
method __init__ (line 700) | def __init__(self, service):
method __startJobs (line 706) | def __startJobs(self):
method add_requests (line 742) | def add_requests(self, client):
method execute_command (line 747) | def execute_command(self, client, command):
method handle_peer (line 751) | def handle_peer(self, peersocket, peeraddress):
method peer_destroyed (line 754) | def peer_destroyed(self, peer):
method request_result (line 757) | def request_result(self, request):
method request_started (line 759) | def request_started(self, job, request):
method request_finished (line 761) | def request_finished(self, job, request, result):
function call (line 764) | def call(context, fn, *args, **kwargs):
FILE: src/background/watchdog.py
function getRSS (line 31) | def getRSS(pid):
class Watchdog (line 42) | class Watchdog(background.utils.BackgroundProcess):
method __init__ (line 43) | def __init__(self):
method run (line 54) | def run(self):
function start_service (line 163) | def start_service():
FILE: src/base.py
class Error (line 17) | class Error(Exception):
class ImplementationError (line 20) | class ImplementationError(Error):
FILE: src/base_unittest.py
function independence (line 1) | def independence():
FILE: src/changeset/client.py
class ChangesetBackgroundServiceError (line 23) | class ChangesetBackgroundServiceError(base.ImplementationError):
method __init__ (line 24) | def __init__(self, message):
function requestChangesets (line 28) | def requestChangesets(requests, async=False):
FILE: src/changeset/create.py
function createChangeset (line 22) | def createChangeset(db, request):
FILE: src/changeset/detectmoves.py
class Line (line 27) | class Line:
method __init__ (line 28) | def __init__(self, string):
method __str__ (line 32) | def __str__(self):
method __eq__ (line 35) | def __eq__(self, other):
method __ne__ (line 38) | def __ne__(self, other):
method __hash__ (line 41) | def __hash__(self):
function compareChunks (line 44) | def compareChunks(source_file, source_chunk, target_file, target_chunk, ...
function findSourceChunk (line 126) | def findSourceChunk(db, changeset, source_file_ids, target_file, target_...
function detectMoves (line 157) | def detectMoves(db, changeset, source_file_ids=None, target_file_ids=None):
FILE: src/changeset/html.py
class CodeContexts (line 38) | class CodeContexts:
class Context (line 39) | class Context:
method __init__ (line 40) | def __init__(self, first_line, last_line, description):
method __cmp__ (line 45) | def __cmp__(self, index):
method __init__ (line 48) | def __init__(self, db, sha1, first_line, last_line):
method find (line 59) | def find(self, linenr):
function expandHTML (line 67) | def expandHTML(db, file, old_offset, new_offset, lines, target):
function generateDataScript (line 84) | def generateDataScript(db, user, changeset, review, file_id_format, comp...
function render (line 201) | def render(db, target, user, repository, changeset, review=None, review_...
function renderFile (line 278) | def renderFile(db, target, user, review, file, first_file=False, options...
function addResources (line 789) | def addResources(db, user, repository, review, compact, tabify, target):
FILE: src/changeset/load.py
function loadChangeset (line 21) | def loadChangeset(db, repository, changeset_id, filtered_file_ids=None, ...
function loadChangesetsForCommits (line 27) | def loadChangesetsForCommits(db, repository, commits, filtered_file_ids=...
function loadChangesets (line 43) | def loadChangesets(db, repository, changesets, filtered_file_ids=None, l...
FILE: src/changeset/process.py
function joinPaths (line 20) | def joinPaths(dirname, basename):
class ChangedPath (line 23) | class ChangedPath:
method __init__ (line 24) | def __init__(self, path, oldEntry, newEntry):
function removedTree (line 29) | def removedTree(repository, path, sha1):
function removedEntry (line 36) | def removedEntry(repository, path, entry):
function addedTree (line 45) | def addedTree(repository, path, sha1):
function addedEntry (line 52) | def addedEntry(repository, path, entry):
function diffTrees (line 61) | def diffTrees(repository, path, oldTree, newTree):
function diffCommits (line 104) | def diffCommits(repository, commitA, commitB):
FILE: src/changeset/text.py
function unified (line 22) | def unified(db, changeset, context_lines=3):
FILE: src/changeset/utils.py
function createFullMergeChangeset (line 37) | def createFullMergeChangeset(db, user, repository, commit, **kwargs):
function createChangesets (line 52) | def createChangesets(db, repository, commits):
function createChangeset (line 70) | def createChangeset(db, user, repository, commit=None, from_commit=None,...
function getCodeContext (line 233) | def getCodeContext(db, sha1, line, minimized=False):
FILE: src/cli.py
function init (line 34) | def init(user_id, authentication_labels):
function finish (line 46) | def finish():
function abort (line 54) | def abort():
function sendCustomMail (line 62) | def sendCustomMail(from_user, recipients, subject, headers, body, review):
function propagateComment (line 95) | def propagateComment(data):
function checkRepositoryAccess (line 135) | def checkRepositoryAccess(data):
function main (line 162) | def main():
FILE: src/communicate.py
class ProcessTimeout (line 24) | class ProcessTimeout(Exception):
method __init__ (line 25) | def __init__(self, timeout):
class ProcessError (line 30) | class ProcessError(Exception):
method __init__ (line 31) | def __init__(self, process, stderr):
function setnonblocking (line 37) | def setnonblocking(fd):
class Communicate (line 40) | class Communicate(object):
method __init__ (line 41) | def __init__(self, process):
method setTimeout (line 50) | def setTimeout(self, timeout):
method setInput (line 54) | def setInput(self, data):
method setCallbacks (line 57) | def setCallbacks(self, stdout=None, stdout_line=None, stderr=None, std...
method __read (line 63) | def __read(self, source, target, callbacks):
method run (line 85) | def run(self):
FILE: src/coverage.py
function call (line 26) | def call(context, fn, *args, **kwargs):
FILE: src/critic.py
function getUserEmailAddress (line 105) | def getUserEmailAddress(_username):
function setContentTypeFromPath (line 113) | def setContentTypeFromPath(req):
function handleStaticResource (line 120) | def handleStaticResource(req):
function handleDownload (line 151) | def handleDownload(db, req, user):
function findreview (line 182) | def findreview(req, db):
function handleException (line 364) | def handleException(db, req, user, as_html=False):
class WrappedResult (line 424) | class WrappedResult(object):
method __init__ (line 425) | def __init__(self, db, req, user, result):
method __iter__ (line 435) | def __iter__(self):
method next (line 438) | def next(self):
function handleRepositoryPath (line 475) | def handleRepositoryPath(db, req, user, suffix):
function handleDisplayMessage (line 511) | def handleDisplayMessage(db, req, message):
function handleDisplayFormattedText (line 527) | def handleDisplayFormattedText(db, req, formatted_text):
function handleMissingWSGIRemoteUser (line 541) | def handleMissingWSGIRemoteUser(db, req):
function finishOAuth (line 587) | def finishOAuth(db, req, provider):
function process_request (line 598) | def process_request(environ, start_response):
function main (line 970) | def main(environ, start_response):
FILE: src/dbaccess.py
function connect (line 23) | def connect():
class TransactionRollbackError (line 39) | class TransactionRollbackError(Exception):
function connect (line 46) | def connect():
FILE: src/dbutils/branch.py
class Branch (line 17) | class Branch(object):
method __init__ (line 18) | def __init__(self, id, repository, name, head_sha1, base, tail_sha1, b...
method __eq__ (line 32) | def __eq__(self, other):
method __ne__ (line 35) | def __ne__(self, other):
method contains (line 38) | def contains(self, db, commit):
method getHead (line 47) | def getHead(self, db):
method getTail (line 53) | def getTail(self, db):
method getJSConstructor (line 59) | def getJSConstructor(self):
method getJS (line 66) | def getJS(self):
method getCommits (line 69) | def getCommits(self, db):
method rebase (line 82) | def rebase(self, db, base):
method archive (line 155) | def archive(self, db):
method resurrect (line 188) | def resurrect(self, db):
method fromId (line 200) | def fromId(db, branch_id, load_review=False, repository=None, for_upda...
method fromName (line 249) | def fromName(db, repository, name, **kwargs):
FILE: src/dbutils/database.py
class InvalidCursorError (line 26) | class InvalidCursorError(base.ImplementationError):
class FailedToLock (line 31) | class FailedToLock(Exception):
class NoWait (line 37) | class NoWait:
class _CursorIterator (line 41) | class _CursorIterator(object):
method __init__ (line 42) | def __init__(self, base):
method next (line 46) | def next(self):
method invalidate (line 51) | def invalidate(self):
class _CursorBase (line 54) | class _CursorBase(object):
method __init__ (line 55) | def __init__(self, db, cursor, profiling):
method __iter__ (line 62) | def __iter__(self):
method __getitem__ (line 72) | def __getitem__(self, index):
method description (line 79) | def description(self):
method fetchone (line 82) | def fetchone(self):
method fetchall (line 92) | def fetchall(self):
method execute (line 98) | def execute(self, query, params=(), for_update=False):
method executemany (line 124) | def executemany(self, query, params=()):
method mogrify (line 135) | def mogrify(self, *args):
method validate (line 138) | def validate(self, query, for_update):
class _UnsafeCursor (line 141) | class _UnsafeCursor(_CursorBase):
method validate (line 142) | def validate(self, query, for_update):
class _ReadOnlyCursor (line 150) | class _ReadOnlyCursor(_CursorBase):
method validate (line 151) | def validate(self, query, for_update):
class _UpdatingCursor (line 161) | class _UpdatingCursor(_ReadOnlyCursor):
method __init__ (line 162) | def __init__(self, tables, *args):
method disabled (line 168) | def disabled(self):
method validate (line 171) | def validate(self, query, for_update):
method disable (line 189) | def disable(self):
class Database (line 200) | class Database(Session):
method __init__ (line 201) | def __init__(self, critic=None, allow_unsafe_cursors=True):
method __call_transaction_callbacks (line 210) | def __call_transaction_callbacks(self, *args):
method cursor (line 217) | def cursor(self):
method readonly_cursor (line 222) | def readonly_cursor(self):
method updating_cursor (line 226) | def updating_cursor(self, *tables):
method commit (line 253) | def commit(self):
method rollback (line 263) | def rollback(self):
method close (line 273) | def close(self):
method closed (line 280) | def closed(self):
method __enter__ (line 283) | def __enter__(self):
method __exit__ (line 286) | def __exit__(self, *args):
method registerTransactionCallback (line 290) | def registerTransactionCallback(self, callback):
method analyzeQuery (line 294) | def analyzeQuery(query):
method forUser (line 330) | def forUser(critic=None):
method forSystem (line 334) | def forSystem(critic=None):
method forTesting (line 342) | def forTesting(critic):
function boolean (line 356) | def boolean(value):
FILE: src/dbutils/database_unittest.py
function cursors (line 1) | def cursors():
function analyzeQuery (line 189) | def analyzeQuery():
FILE: src/dbutils/paths.py
class InvalidFileId (line 17) | class InvalidFileId(Exception):
method __init__ (line 18) | def __init__(self, file_id):
class InvalidPath (line 21) | class InvalidPath(Exception):
class File (line 24) | class File(object):
method __init__ (line 25) | def __init__(self, file_id, path):
method __int__ (line 29) | def __int__(self):
method __str__ (line 31) | def __str__(self):
method fromId (line 35) | def fromId(db, file_id):
method fromPath (line 39) | def fromPath(db, path, insert=True):
function find_file (line 46) | def find_file(db, path, insert=True):
function find_files (line 68) | def find_files(db, files):
function describe_file (line 72) | def describe_file(db, file_id):
FILE: src/dbutils/review.py
function countDraftItems (line 21) | def countDraftItems(db, user, review):
class NoSuchReview (line 103) | class NoSuchReview(base.Error):
method __init__ (line 104) | def __init__(self, review_id):
class ReviewState (line 108) | class ReviewState(object):
method __init__ (line 109) | def __init__(self, review, accepted, pending, reviewed, issues):
method getPercentReviewed (line 116) | def getPercentReviewed(self):
method getProgress (line 122) | def getProgress(self):
method getIssues (line 138) | def getIssues(self):
method __str__ (line 142) | def __str__(self):
class ReviewRebase (line 152) | class ReviewRebase(object):
method __init__ (line 153) | def __init__(self, review, old_head, new_head, old_upstream, new_upstr...
class ReviewRebases (line 164) | class ReviewRebases(list):
method __init__ (line 165) | def __init__(self, db, review):
method fromOldHead (line 216) | def fromOldHead(self, commit):
method fromNewHead (line 219) | def fromNewHead(self, commit):
class ReviewTrackedBranch (line 222) | class ReviewTrackedBranch(object):
method __init__ (line 223) | def __init__(self, review, trackedbranch_id, remote, name, disabled):
class Review (line 230) | class Review(object):
method __init__ (line 231) | def __init__(self, review_id, owners, review_type, branch, state, seri...
method isAccepted (line 252) | def isAccepted(db, review_id):
method accepted (line 263) | def accepted(self, db):
method getReviewState (line 267) | def getReviewState(self, db):
method setPerformedRebase (line 294) | def setPerformedRebase(self, old_head, new_head, old_upstream, new_ups...
method getReviewRebases (line 299) | def getReviewRebases(self, db):
method getTrackedBranch (line 302) | def getTrackedBranch(self, db):
method getCommitSet (line 315) | def getCommitSet(self, db):
method containsCommit (line 334) | def containsCommit(self, db, commit, include_head_and_tails=False, inc...
method getJS (line 415) | def getJS(self):
method getETag (line 418) | def getETag(self, db, user=None):
method getURL (line 446) | def getURL(self, db, user=None, indent=0, separator="\n"):
method getRecipients (line 458) | def getRecipients(self, db):
method getDraftStatus (line 491) | def getDraftStatus(self, db, user):
method incrementSerial (line 496) | def incrementSerial(self, db):
method scheduleBranchArchival (line 500) | def scheduleBranchArchival(self, db, delay=None):
method cancelScheduledBranchArchival (line 546) | def cancelScheduledBranchArchival(self, db):
method close (line 552) | def close(self, db, user):
method drop (line 558) | def drop(self, db, user):
method reopen (line 564) | def reopen(self, db, user):
method disableTracking (line 571) | def disableTracking(self, db):
method setSummary (line 574) | def setSummary(self, db, summary):
method setDescription (line 579) | def setDescription(self, db, description):
method addOwner (line 584) | def addOwner(self, db, owner):
method removeOwner (line 604) | def removeOwner(self, db, owner):
method getReviewFilters (line 618) | def getReviewFilters(self, db):
method getFilteredTails (line 623) | def getFilteredTails(self, db):
method getRelevantFiles (line 628) | def getRelevantFiles(self, db, user):
method getUserAssociation (line 644) | def getUserAssociation(self, db, user):
method fromId (line 678) | def fromId(db, review_id, branch=None, profiler=None):
method fromBranch (line 731) | def fromBranch(db, branch):
method fromName (line 742) | def fromName(db, repository, name):
method fromArgument (line 747) | def fromArgument(db, argument):
method fromAPI (line 757) | def fromAPI(api_review):
FILE: src/dbutils/session.py
class Session (line 17) | class Session(object):
method __init__ (line 18) | def __init__(self, critic):
method atexit (line 33) | def atexit(self, fn):
method close (line 36) | def close(self):
method disableProfiling (line 42) | def disableProfiling(self):
method recordProfiling (line 45) | def recordProfiling(self, item, duration, rows=None, repetitions=1):
method user (line 62) | def user(self):
method authentication_labels (line 66) | def authentication_labels(self):
method profiles (line 70) | def profiles(self):
method setUser (line 73) | def setUser(self, user, authentication_labels=()):
method addProfile (line 84) | def addProfile(self, profile):
FILE: src/dbutils/system.py
function getInstalledSHA1 (line 17) | def getInstalledSHA1(db):
function getURLPrefix (line 24) | def getURLPrefix(db, user=None):
function getAdministratorContacts (line 38) | def getAdministratorContacts(db, indent=0, as_html=False):
FILE: src/dbutils/timezones.py
function loadTimezones (line 20) | def loadTimezones(db):
function updateTimezones (line 50) | def updateTimezones(db):
function __fetchTimezones (line 69) | def __fetchTimezones(db):
function sortedTimezones (line 86) | def sortedTimezones(db):
function __fetchUTCOffset (line 95) | def __fetchUTCOffset(db, timezone):
function adjustTimestamp (line 118) | def adjustTimestamp(db, timestamp, timezone):
function formatTimestamp (line 121) | def formatTimestamp(db, timestamp, timezone):
function validTimezone (line 128) | def validTimezone(db, timezone):
FILE: src/dbutils/unittest.py
function independence (line 1) | def independence():
FILE: src/dbutils/user.py
function _preferenceCacheKey (line 20) | def _preferenceCacheKey(item, repository, filter_id):
class InvalidUserId (line 28) | class InvalidUserId(base.Error):
method __init__ (line 29) | def __init__(self, user_id):
class NoSuchUser (line 33) | class NoSuchUser(base.Error):
method __init__ (line 34) | def __init__(self, name):
class User (line 38) | class User(object):
method __init__ (line 39) | def __init__(self, user_id, name, fullname, status, email, email_verif...
method __eq__ (line 49) | def __eq__(self, other):
method __ne__ (line 61) | def __ne__(self, other):
method __int__ (line 64) | def __int__(self):
method __str__ (line 68) | def __str__(self):
method __repr__ (line 72) | def __repr__(self):
method __hash__ (line 75) | def __hash__(self):
method isAnonymous (line 78) | def isAnonymous(self):
method isSystem (line 81) | def isSystem(self):
method hasRole (line 84) | def hasRole(self, db, role):
method loadPreferences (line 89) | def loadPreferences(self, db):
method fetchPreference (line 113) | def fetchPreference(db, item, user=None, repository=None, filter_id=No...
method storePreference (line 170) | def storePreference(db, item, value, user=None, repository=None, filte...
method getPreference (line 244) | def getPreference(self, db, item, repository=None, filter_id=None):
method setPreference (line 253) | def setPreference(self, db, item, value, repository=None, filter_id=No...
method getDefaultRepository (line 256) | def getDefaultRepository(self, db):
method getResource (line 270) | def getResource(self, db, name):
method adjustTimestamp (line 291) | def adjustTimestamp(self, db, timestamp):
method formatTimestamp (line 295) | def formatTimestamp(self, db, timestamp):
method getCriticURLs (line 299) | def getCriticURLs(self, db):
method getFirstName (line 320) | def getFirstName(self):
method getJSConstructor (line 323) | def getJSConstructor(self, db=None):
method getJS (line 337) | def getJS(self, db=None, name="user"):
method getJSON (line 340) | def getJSON(self):
method getAbsence (line 346) | def getAbsence(self, db):
method hasGitEmail (line 355) | def hasGitEmail(self, db, address):
method cache (line 365) | def cache(db, user):
method makeAnonymous (line 373) | def makeAnonymous():
method makeSystem (line 377) | def makeSystem():
method _fromQuery (line 383) | def _fromQuery(db, where, *values):
method fromId (line 394) | def fromId(db, user_id):
method fromIds (line 405) | def fromIds(db, user_ids):
method fromName (line 416) | def fromName(db, name):
method fromAPI (line 427) | def fromAPI(api_user):
method withRole (line 433) | def withRole(db, role):
method create (line 442) | def create(db, name, fullname, email, email_verified, password=None,
method sendUserCreatedMail (line 475) | def sendUserCreatedMail(self, source, external=None):
FILE: src/diff/__init__.py
class Chunk (line 35) | class Chunk:
method __init__ (line 36) | def __init__(self, delete_offset, delete_count, insert_offset, insert_...
method copy (line 65) | def copy(self):
method isBinary (line 72) | def isBinary(self):
method analyze (line 75) | def analyze(self, file, last_chunk=False, reanalyze=False):
method deleteEnd (line 90) | def deleteEnd(self):
method insertEnd (line 93) | def insertEnd(self):
method delta (line 96) | def delta(self):
method __str__ (line 99) | def __str__(self):
method __repr__ (line 102) | def __repr__(self):
method __eq__ (line 107) | def __eq__(self, other):
method getLines (line 110) | def getLines(self):
class Line (line 160) | class Line:
method __init__ (line 169) | def __init__(self, type, old_offset, old_value, new_offset, new_value,...
method __repr__ (line 190) | def __repr__(self):
method isConflictMarker (line 198) | def isConflictMarker(self):
class MacroChunk (line 204) | class MacroChunk:
method __init__ (line 205) | def __init__(self, chunks, lines):
class File (line 221) | class File:
method __init__ (line 222) | def __init__(self, id=None, path=None, old_sha1=None, new_sha1=None, r...
method clean (line 263) | def clean(self):
method cleanLines (line 268) | def cleanLines(self):
method __hash__ (line 274) | def __hash__(self):
method __int__ (line 277) | def __int__(self):
method __repr__ (line 280) | def __repr__(self):
method hasChanges (line 283) | def hasChanges(self):
method isEmptyChanges (line 286) | def isEmptyChanges(self):
method isEmptyFile (line 293) | def isEmptyFile(self):
method isBinaryChanges (line 302) | def isBinaryChanges(self):
method wasAdded (line 306) | def wasAdded(self):
method wasRemoved (line 310) | def wasRemoved(self):
method oldSize (line 314) | def oldSize(self):
method newSize (line 321) | def newSize(self):
method ensureHighlight (line 328) | def ensureHighlight(self, highlight_mode="legacy"):
method loadOldLines (line 349) | def loadOldLines(self, highlighted=False, request_highlight=False, hig...
method loadNewLines (line 382) | def loadNewLines(self, highlighted=False, request_highlight=False, hig...
method getOldLines (line 415) | def getOldLines(self, chunk, highlighted=False):
method getNewLines (line 420) | def getNewLines(self, chunk, highlighted=False):
method oldLines (line 425) | def oldLines(self, highlighted):
method oldCount (line 429) | def oldCount(self):
method newLines (line 433) | def newLines(self, highlighted):
method newCount (line 437) | def newCount(self):
method canHighlight (line 441) | def canHighlight(self):
method getLanguage (line 444) | def getLanguage(self, use_content=False):
method getInterpreter (line 498) | def getInterpreter(self, side="new"):
method getModeLine (line 515) | def getModeLine(self, side="new"):
method getTabWidth (line 531) | def getTabWidth(self, side="new", default=8):
method getIndentTabsMode (line 536) | def getIndentTabsMode(self, side="new", default=True):
method sorted (line 542) | def sorted(files, key=lambda file: file.path):
method eliminateCommonPrefixes (line 554) | def eliminateCommonPrefixes(files, text=False, getpath=None, setpath=N...
class Changeset (line 601) | class Changeset:
method __init__ (line 602) | def __init__(self, id, parent, child, type, files=None, commits=None):
method __hash__ (line 613) | def __hash__(self): return hash(self.id)
method __eq__ (line 614) | def __eq__(self, other): return self.id == other.id
method commits (line 616) | def commits(self, db):
method setCommits (line 626) | def setCommits(self, commits):
method getFile (line 629) | def getFile(self, file_id):
method getReviewFiles (line 635) | def getReviewFiles(self, db, user, review):
method fromId (line 680) | def fromId(db, repository, id):
FILE: src/diff/analyze.py
function analyzeChunk (line 27) | def analyzeChunk(deletedLines, insertedLines, moved=False):
function analyzeChunk1 (line 71) | def analyzeChunk1(deletedLines, insertedLines, offsetA=0, offsetB=0):
function offsetInLine (line 181) | def offsetInLine(words, offset):
function analyzeWhiteSpaceLine (line 186) | def analyzeWhiteSpaceLine(deletedLine, insertedLine):
function analyzeWhiteSpaceChanges (line 211) | def analyzeWhiteSpaceChanges(deletedLines, insertedLines, at_eof=False,
FILE: src/diff/context.py
class ContextLines (line 20) | class ContextLines:
method __init__ (line 21) | def __init__(self, file, chunks, chains=None, merge=False, conflicts=F...
method getMacroChunks (line 28) | def getMacroChunks(self, context_lines=3, minimum_gap=3, highlight=Tru...
FILE: src/diff/html.py
class Tag (line 25) | class Tag:
method __init__ (line 26) | def __init__(self, value): self.value = value
method __str__ (line 27) | def __str__(self): return self.value
method __nonzero__ (line 28) | def __nonzero__(self): return False
method __repr__ (line 29) | def __repr__(self): return "Tag(%r)" % self.value
function splitTags (line 31) | def splitTags(line):
function joinTags (line 47) | def joinTags(tags):
function insertTag (line 54) | def insertTag(tags, offset, newTag):
function lineDiffHTML (line 69) | def lineDiffHTML(ops, old, new):
FILE: src/diff/merge.py
function filterChunks (line 25) | def filterChunks(log, file_on_branch, file_in_merge, path):
function parseMergeDifferences (line 65) | def parseMergeDifferences(db, repository, commit):
FILE: src/diff/parse.py
function demunge (line 27) | def demunge(path):
function splitlines (line 49) | def splitlines(source):
function detectWhiteSpaceChanges (line 54) | def detectWhiteSpaceChanges(file, old_lines, begin_old_offset, end_old_o...
function isWhitespaceChange (line 81) | def isWhitespaceChange(deleted_line, inserted_line):
function createChunks (line 84) | def createChunks(delete_offset, deleted_lines, insert_offset, inserted_l...
function mergeChunks (line 127) | def mergeChunks(file):
function parseDifferences (line 174) | def parseDifferences(repository, commit=None, from_commit=None, to_commi...
FILE: src/diffutils.py
function expandWithContext (line 23) | def expandWithContext(chunks, old_lines, new_lines, context_lines, highl...
FILE: src/extensions/__init__.py
function getExtensionPath (line 19) | def getExtensionPath(author_name, extension_name):
function getExtensionInstallPath (line 22) | def getExtensionInstallPath(sha1):
FILE: src/extensions/execute.py
function startProcess (line 30) | def startProcess(flavor):
class ProcessException (line 41) | class ProcessException(Exception):
class ProcessError (line 44) | class ProcessError(ProcessException):
method __init__ (line 45) | def __init__(self, message):
class ProcessTimeout (line 49) | class ProcessTimeout(ProcessException):
method __init__ (line 50) | def __init__(self, timeout):
class ProcessFailure (line 54) | class ProcessFailure(ProcessException):
method __init__ (line 55) | def __init__(self, returncode, stderr):
function executeProcess (line 61) | def executeProcess(db, manifest, role_name, script, function, extension_id,
FILE: src/extensions/extension.py
class ExtensionError (line 27) | class ExtensionError(Exception):
method __init__ (line 28) | def __init__(self, message, extension=None):
class Extension (line 32) | class Extension(object):
method __init__ (line 33) | def __init__(self, author_name, extension_name):
method isSystemExtension (line 67) | def isSystemExtension(self):
method getAuthorName (line 70) | def getAuthorName(self):
method getName (line 75) | def getName(self):
method getTitle (line 78) | def getTitle(self, db, html=False):
method getKey (line 107) | def getKey(self):
method getPath (line 113) | def getPath(self):
method getVersions (line 116) | def getVersions(self):
method getManifest (line 134) | def getManifest(self, version=None, sha1=None):
method getCurrentSHA1 (line 168) | def getCurrentSHA1(self, version):
method prepareVersionSnapshot (line 176) | def prepareVersionSnapshot(self, version):
method getAuthor (line 193) | def getAuthor(self, db):
method getExtensionID (line 198) | def getExtensionID(self, db, create=False):
method getInstalledVersion (line 229) | def getInstalledVersion(self, db, user):
method fromId (line 269) | def fromId(db, extension_id):
method getInstalls (line 283) | def getInstalls(db, user):
method getUpdatedExtensions (line 330) | def getUpdatedExtensions(db, user):
method find (line 349) | def find(db):
FILE: src/extensions/installation.py
class InstallationError (line 21) | class InstallationError(Exception):
method __init__ (line 22) | def __init__(self, title, message, is_html=False):
function doInstallExtension (line 27) | def doInstallExtension(db, user, extension, version):
function doUninstallExtension (line 123) | def doUninstallExtension(db, user, extension):
function getExtension (line 142) | def getExtension(author_name, extension_name):
function installExtension (line 151) | def installExtension(db, user, author_name, extension_name, version):
function uninstallExtension (line 155) | def uninstallExtension(db, user, author_name, extension_name, version):
function reinstallExtension (line 159) | def reinstallExtension(db, user, author_name, extension_name, version):
FILE: src/extensions/manifest.py
class ManifestError (line 28) | class ManifestError(Exception):
class Role (line 31) | class Role:
method __init__ (line 32) | def __init__(self, location):
method install (line 38) | def install(self, db, version_id):
method process (line 46) | def process(self, name, value, location):
method check (line 59) | def check(self):
class URLRole (line 67) | class URLRole(Role):
method __init__ (line 68) | def __init__(self, location, pattern):
method check (line 75) | def check(self):
class PageRole (line 80) | class PageRole(URLRole):
method __init__ (line 81) | def __init__(self, location, pattern):
method name (line 84) | def name(self):
method install (line 87) | def install(self, db, version_id):
class InjectRole (line 95) | class InjectRole(URLRole):
method __init__ (line 96) | def __init__(self, location, pattern):
method name (line 99) | def name(self):
method process (line 102) | def process(self, name, value, location):
method install (line 110) | def install(self, db, version_id):
class ProcessCommitsRole (line 118) | class ProcessCommitsRole(Role):
method __init__ (line 119) | def __init__(self, location):
method name (line 122) | def name(self):
method install (line 125) | def install(self, db, version_id):
class FilterHookRole (line 133) | class FilterHookRole(Role):
method __init__ (line 134) | def __init__(self, location, name):
method name (line 140) | def name(self):
method process (line 143) | def process(self, name, value, location):
method check (line 154) | def check(self):
method install (line 161) | def install(self, db, version_id):
class ScheduledRole (line 172) | class ScheduledRole(Role):
method __init__ (line 173) | def __init__(self, location):
method name (line 178) | def name(self):
method install (line 181) | def install(self, db, version_id):
method process (line 189) | def process(self, name, value, location):
method check (line 203) | def check(self):
class Author (line 244) | class Author(object):
method __init__ (line 245) | def __init__(self, value):
class Manifest (line 253) | class Manifest(object):
method __init__ (line 254) | def __init__(self, path, source=None):
method isAuthor (line 266) | def isAuthor(self, db, user):
method getAuthors (line 273) | def getAuthors(self):
method read (line 276) | def read(self):
method load (line 386) | def load(extension_path):
FILE: src/extensions/resource.py
function get (line 22) | def get(req, db, user, path):
FILE: src/extensions/role/filterhook.py
function signalExtensionTasksService (line 32) | def signalExtensionTasksService():
function listFilterHooks (line 42) | def listFilterHooks(db, user):
function getFilterHookRole (line 90) | def getFilterHookRole(db, filter_id):
function queueFilterHookEvent (line 114) | def queueFilterHookEvent(db, filter_id, review, user, commits, file_ids):
function processFilterHookEvent (line 147) | def processFilterHookEvent(db, event_id, logfn):
FILE: src/extensions/role/inject.py
class InjectError (line 32) | class InjectError(Exception):
class InjectIgnored (line 34) | class InjectIgnored(Exception):
function processLine (line 37) | def processLine(paths, line):
function execute (line 152) | def execute(db, req, user, document, links, injected, profiler=None):
FILE: src/extensions/role/page.py
function execute (line 31) | def execute(db, req, user):
FILE: src/extensions/role/processcommits.py
function execute (line 30) | def execute(db, user, review, all_commits, old_head, new_head, output):
FILE: src/extensions/unittest.py
function independence (line 1) | def independence():
FILE: src/extensions/utils.py
function renderTutorial (line 21) | def renderTutorial(db, user, source):
FILE: src/gitutils.py
function same_filesystem (line 50) | def same_filesystem(pathA, pathB):
function getGitEnvironment (line 53) | def getGitEnvironment(author=True, committer=True):
class GitError (line 75) | class GitError(base.Error):
class GitReferenceError (line 78) | class GitReferenceError(GitError):
method __init__ (line 81) | def __init__(self, message, sha1=None, ref=None, repository=None):
class GitCommandError (line 87) | class GitCommandError(GitError):
method __init__ (line 90) | def __init__(self, cmdline, output, cwd):
class GitObject (line 96) | class GitObject:
method __init__ (line 97) | def __init__(self, sha1, type, size, data):
method __getitem__ (line 103) | def __getitem__(self, index):
class GitHttpBackendError (line 109) | class GitHttpBackendError(GitError):
method __init__ (line 110) | def __init__(self, returncode, stderr):
class GitHttpBackendNeedsUser (line 122) | class GitHttpBackendNeedsUser(GitError):
class NoSuchRepository (line 125) | class NoSuchRepository(base.Error):
method __init__ (line 128) | def __init__(self, value):
class Repository (line 132) | class Repository:
class FromParameter (line 133) | class FromParameter:
method __init__ (line 134) | def __init__(self, db): self.db = db
method __call__ (line 135) | def __call__(self, value): return Repository.fromParameter(self.db, ...
method __init__ (line 137) | def __init__(self, db=None, repository_id=None, parent=None, name=None...
method __str__ (line 157) | def __str__(self):
method getURL (line 160) | def getURL(self, db, user):
method constructURL (line 164) | def constructURL(db, user, path):
method enableBlobCache (line 183) | def enableBlobCache(self):
method disableCache (line 187) | def disableCache(self):
method checkAccess (line 190) | def checkAccess(self, db, access_type):
method fromId (line 196) | def fromId(db, repository_id, for_modify=False):
method fromName (line 216) | def fromName(db, name, for_modify=False):
method fromParameter (line 229) | def fromParameter(db, parameter):
method fromSHA1 (line 236) | def fromSHA1(db, sha1):
method fromPath (line 247) | def fromPath(db, path, for_modify=False):
method fromAPI (line 255) | def fromAPI(api_repository):
method __terminate (line 258) | def __terminate(self, db=None):
method __startBatch (line 261) | def __startBatch(self):
method __startBatchCheck (line 268) | def __startBatchCheck(self):
method stopBatch (line 275) | def stopBatch(self):
method forEach (line 290) | def forEach(db, fn):
method getJS (line 295) | def getJS(self):
method getModuleRepository (line 298) | def getModuleRepository(self, db, commit, path):
method fetch (line 329) | def fetch(self, sha1, fetchData=True):
method run (line 377) | def run(self, command, *arguments, **kwargs):
method runCustom (line 380) | def runCustom(self, cwd, command, *arguments, **kwargs):
method createBranch (line 407) | def createBranch(self, name, startpoint):
method deleteBranch (line 417) | def deleteBranch(self, name):
method mergebase (line 427) | def mergebase(self, commit_or_commits, db=None):
method getCommonAncestor (line 453) | def getCommonAncestor(self, commit_or_commits):
method revparse (line 464) | def revparse(self, name):
method revlist (line 472) | def revlist(self, included, excluded, *args, **kwargs):
method iscommit (line 481) | def iscommit(self, name):
method createref (line 489) | def createref(self, name, value):
method updateref (line 493) | def updateref(self, name, new_value, old_value=None):
method deleteref (line 500) | def deleteref(self, name, value=None):
method keepalive (line 507) | def keepalive(self, commit):
method packKeepaliveRefs (line 512) | def packKeepaliveRefs(self):
method temporaryref (line 602) | def temporaryref(self, commit=None):
method __copy (line 616) | def __copy(self, identifier, flavor):
method relaycopy (line 669) | def relaycopy(self, identifier):
method workcopy (line 672) | def workcopy(self, identifier):
method replaymerge (line 675) | def replaymerge(self, db, user, commit):
method getSignificantBranches (line 715) | def getSignificantBranches(self, db):
method getDefaultRemote (line 740) | def getDefaultRemote(self, db):
method updateBranchFromRemote (line 752) | def updateBranchFromRemote(self, db, remote, branch_name):
method fetchTemporaryFromRemote (line 780) | def fetchTemporaryFromRemote(self, db, remote, ref):
method readObject (line 800) | def readObject(repository_path, object_type, object_sha1):
method lsremote (line 810) | def lsremote(remote, include_heads=False, include_tags=False, pattern=...
method findInterestingTag (line 835) | def findInterestingTag(self, db, sha1):
method getHead (line 851) | def getHead(self, db):
method getHeadBranch (line 854) | def getHeadBranch(self, db):
method isEmpty (line 870) | def isEmpty(self):
method invokeGitHttpBackend (line 877) | def invokeGitHttpBackend(self, req, user, path):
method describe (line 947) | def describe(self, db, sha1):
class CommitUserTime (line 962) | class CommitUserTime(object):
method __init__ (line 963) | def __init__(self, name, email, time):
method __getIds (line 968) | def __getIds(self, db):
method getUserIds (line 998) | def getUserIds(self, db):
method getGitUserId (line 1001) | def getGitUserId(self, db):
method getFullname (line 1004) | def getFullname(self, db):
method __str__ (line 1012) | def __str__(self):
method fromValue (line 1017) | def fromValue(value):
class Commit (line 1023) | class Commit:
method __init__ (line 1024) | def __init__(self, repository, id, sha1, parents, author, committer, m...
method __cache (line 1035) | def __cache(self, db):
method fromGitObject (line 1041) | def fromGitObject(db, repository, gitobject, commit_id=None):
method fromSHA1 (line 1068) | def fromSHA1(db, repository, sha1, commit_id=None):
method fromId (line 1072) | def fromId(db, repository, commit_id):
method fromAPI (line 1082) | def fromAPI(api_commit):
method __hash__ (line 1087) | def __hash__(self): return hash(self.sha1)
method __eq__ (line 1088) | def __eq__(self, other): return self.sha1 == str(other)
method __ne__ (line 1089) | def __ne__(self, other): return self.sha1 != str(other)
method __str__ (line 1090) | def __str__(self): return self.sha1
method __repr__ (line 1091) | def __repr__(self):
method summary (line 1095) | def summary(self, maxlen=None):
method niceSummary (line 1101) | def niceSummary(self, include_tag=True):
method getId (line 1118) | def getId(self, db):
method findInterestingTag (line 1126) | def findInterestingTag(self, db):
method describe (line 1129) | def describe(self, db):
method oneline (line 1135) | def oneline(self, db, decorate=False):
method isAncestorOf (line 1153) | def isAncestorOf(self, other):
method getTree (line 1170) | def getTree(self, path):
method getFileEntry (line 1176) | def getFileEntry(self, path):
method getFileSHA1 (line 1182) | def getFileSHA1(self, path):
method isDirectory (line 1188) | def isDirectory(self, path):
class Tree (line 1195) | class Tree:
class Entry (line 1196) | class Entry:
class Mode (line 1197) | class Mode(int):
method __new__ (line 1198) | def __new__(cls, value):
method __str__ (line 1201) | def __str__(self):
method __init__ (line 1213) | def __init__(self, name, mode, type, sha1, size):
method __str__ (line 1223) | def __str__(self):
method __repr__ (line 1226) | def __repr__(self):
method __init__ (line 1229) | def __init__(self, entries, commit=None):
method __getitem__ (line 1233) | def __getitem__(self, item):
method __len__ (line 1239) | def __len__(self):
method __iter__ (line 1241) | def __iter__(self):
method keys (line 1244) | def keys(self):
method items (line 1246) | def items(self):
method values (line 1248) | def values(self):
method get (line 1250) | def get(self, key, default=None):
method fromPath (line 1254) | def fromPath(commit, path):
method fromSHA1 (line 1295) | def fromSHA1(repository, sha1):
function getTaggedCommit (line 1317) | def getTaggedCommit(repository, sha1):
class Blame (line 1334) | class Blame:
method __init__ (line 1335) | def __init__(self, from_commit, to_commit):
method blame (line 1344) | def blame(self, db, path, first_line, last_line):
class FetchCommits (line 1390) | class FetchCommits(threading.Thread):
method __init__ (line 1391) | def __init__(self, repository, sha1s):
method run (line 1403) | def run(self):
method getCommits (line 1436) | def getCommits(self, db):
FILE: src/gitutils_unittest.py
function keepalives (line 1) | def keepalives():
FILE: src/htmlutils.py
function htmlify (line 39) | def htmlify(text, attributeValue=False, pretty=False):
function jsify (line 51) | def jsify(what, as_json=False):
function tabify (line 66) | def tabify(line, tabwidth=8, indenttabsmode=True):
function isBlockElement (line 96) | def isBlockElement(name):
function isEmptyElement (line 99) | def isEmptyElement(name):
function mtime (line 102) | def mtime(path):
function base36 (line 106) | def base36(n):
function getStaticResourceURI (line 113) | def getStaticResourceURI(name):
class URL (line 120) | class URL(object):
method __init__ (line 121) | def __init__(self, path, fragment=None, **query):
method __str__ (line 131) | def __str__(self):
class MetaInformation (line 134) | class MetaInformation(object):
method __init__ (line 135) | def __init__(self):
method addExternalStylesheet (line 150) | def addExternalStylesheet(self, uri, use_static=True, order=0):
method addInternalStylesheet (line 158) | def addInternalStylesheet(self, text, order=0):
method addExternalScript (line 164) | def addExternalScript(self, uri, use_static=True, order=0):
method addInternalScript (line 172) | def addInternalScript(self, text, order=0):
method hasTitle (line 176) | def hasTitle(self):
method setTitle (line 179) | def setTitle(self, title):
method setLink (line 182) | def setLink(self, rel, href):
method setBase (line 185) | def setBase(self, base):
method setRequest (line 188) | def setRequest(self, req):
method getRequest (line 191) | def getRequest(self):
method render (line 194) | def render(self, target):
class PausedRendering (line 226) | class PausedRendering: pass
class Fragment (line 228) | class Fragment(object):
method __init__ (line 229) | def __init__(self, is_element=False, req=None):
method appendChild (line 233) | def appendChild(self, child):
method insertChild (line 237) | def insertChild(self, child, offset=0):
method removeChild (line 241) | def removeChild(self, child):
method metaInformation (line 245) | def metaInformation(self):
method __len__ (line 248) | def __len__(self): return len(self.__children)
method __getitem__ (line 249) | def __getitem__(self, index): return self.__children[index]
method __str__ (line 250) | def __str__(self): return "".join(map(str, self.__children))
method render (line 252) | def render(self, output, level=0, indent_before=True, stop=None, prett...
method deleteChildren (line 257) | def deleteChildren(self, count=None):
method hasChildren (line 261) | def hasChildren(self):
class Element (line 264) | class Element(Fragment):
method __init__ (line 265) | def __init__(self, name):
method setAttribute (line 275) | def setAttribute(self, name, value):
method addClass (line 278) | def addClass(self, *names):
method setPreFormatted (line 283) | def setPreFormatted(self):
method setMetaInformation (line 286) | def setMetaInformation(self, metaInformation):
method appendChild (line 289) | def appendChild(self, child):
method remove (line 293) | def remove(self):
method removeIfEmpty (line 295) | def removeIfEmpty(self):
method __str__ (line 298) | def __str__(self):
method render (line 305) | def render(self, output, level=0, indent_before=True, stop=None, prett...
method empty (line 359) | def empty(self):
class Text (line 362) | class Text(object):
method __init__ (line 363) | def __init__(self, value, preformatted=False, cdata=False):
method setPreFormatted (line 369) | def setPreFormatted(self):
method render (line 372) | def render(self, output, level=0, indent_before=True, stop=None, prett...
method __str__ (line 381) | def __str__(self):
class Comment (line 384) | class Comment(object):
method __init__ (line 385) | def __init__(self, value):
method setPreFormatted (line 388) | def setPreFormatted(self):
method render (line 391) | def render(self, output, level=0, indent_before=True, stop=None, prett...
method __str__ (line 400) | def __str__(self):
class HTML (line 403) | class HTML(object):
method __init__ (line 404) | def __init__(self, value):
method setPreFormatted (line 407) | def setPreFormatted(self):
method render (line 410) | def render(self, output, level=0, indent_before=True, stop=None, prett...
method __str__ (line 413) | def __str__(self):
function safestr (line 416) | def safestr(value):
class Generator (line 420) | class Generator(object):
method __init__ (line 421) | def __init__(self, target, metaInformation):
method __enter__ (line 425) | def __enter__(self):
method __exit__ (line 427) | def __exit__(self, *args):
method __eq__ (line 430) | def __eq__(self, other):
method __open (line 433) | def __open(self, __name, **attributes):
method __getattr__ (line 446) | def __getattr__(self, name):
method head (line 453) | def head(self, **attributes):
method append (line 461) | def append(self, fragment):
method remove (line 466) | def remove(self):
method removeIfEmpty (line 468) | def removeIfEmpty(self):
method text (line 471) | def text(self, value=None, preformatted=False, cdata=False, linkify=Fa...
method comment (line 503) | def comment(self, value):
method commentFirst (line 507) | def commentFirst(self, value):
method innerHTML (line 511) | def innerHTML(self, value=" "):
method setAttribute (line 515) | def setAttribute(self, name, value):
method addClass (line 519) | def addClass(self, *names):
method render (line 523) | def render(self, output, level=0, stop=None, pretty=True):
method empty (line 526) | def empty(self):
method preformatted (line 530) | def preformatted(self):
method addExternalStylesheet (line 534) | def addExternalStylesheet(self, uri, use_static=True, order=0):
method addInternalStylesheet (line 537) | def addInternalStylesheet(self, text, order=0):
method addExternalScript (line 540) | def addExternalScript(self, uri, use_static=True, order=0):
method addInternalScript (line 543) | def addInternalScript(self, text, here=False, order=0):
method hasTitle (line 549) | def hasTitle(self):
method setTitle (line 552) | def setTitle(self, title):
method setLink (line 555) | def setLink(self, rel, href):
method setBase (line 558) | def setBase(self, base):
method getRequest (line 561) | def getRequest(self):
class Document (line 564) | class Document(Generator):
method __init__ (line 565) | def __init__(self, req=None):
method render (line 575) | def render(self, plain=False, stop=None, pretty=True):
method __str__ (line 599) | def __str__(self):
function stripStylesheet (line 602) | def stripStylesheet(text, compact):
FILE: src/htmlutils_unittest.py
function independence (line 1) | def independence():
FILE: src/index.py
class Reject (line 42) | class Reject(Exception):
function update (line 44) | def update(_repository, _ref, _old, _new):
function reflow (line 47) | def reflow(message):
function timestamp (line 50) | def timestamp(time):
class IndexException (line 53) | class IndexException(Exception):
function processCommits (line 56) | def processCommits(db, repository, sha1):
function createBranches (line 132) | def createBranches(db, user, repository, branches, flags):
function createBranch (line 186) | def createBranch(db, user, repository, name, head, multiple, flags):
function updateBranch (line 392) | def updateBranch(db, user, repository, name, old, new, multiple, flags):
function deleteBranch (line 808) | def deleteBranch(db, user, repository, name, old):
function createTag (line 839) | def createTag(db, user, repository, name, sha1):
function updateTag (line 847) | def updateTag(db, user, repository, name, old_sha1, new_sha1):
function deleteTag (line 858) | def deleteTag(db, user, repository, name):
FILE: src/inpututils.py
function apply_check (line 28) | def apply_check(check, input):
function yes_or_no (line 41) | def yes_or_no(prompt, default=None):
function string (line 60) | def string(prompt, default=None, check=None):
function password (line 80) | def password(prompt, default=None, twice=True):
FILE: src/jsonapi/__init__.py
class Error (line 26) | class Error(Exception):
class PathError (line 29) | class PathError(Error):
class UsageError (line 40) | class UsageError(Error):
class InputError (line 52) | class InputError(Error):
class PermissionDenied (line 56) | class PermissionDenied(Error):
class ResultDelayed (line 60) | class ResultDelayed(Error):
class InternalRedirect (line 64) | class InternalRedirect(Exception):
method __init__ (line 65) | def __init__(self, resource_path, subresource_path=None,
class ResourceSkipped (line 72) | class ResourceSkipped(Exception):
function _process_fields (line 81) | def _process_fields(value):
class Parameters (line 95) | class Parameters(object):
method __init__ (line 96) | def __init__(self, critic, req):
method __prepareType (line 115) | def __prepareType(self, resource_type):
method hasField (line 122) | def hasField(self, resource_type, key):
method filtered (line 126) | def filtered(self, resource_type, resource_json):
method forResource (line 142) | def forResource(self, resource):
method getQueryParameter (line 148) | def getQueryParameter(self, name, converter=None, exceptions=()):
method getRange (line 163) | def getRange(self):
method setContext (line 179) | def setContext(self, key, value):
class Linked (line 187) | class Linked(object):
method __init__ (line 188) | def __init__(self, req=None):
method __getitem__ (line 195) | def __getitem__(self, resource_type):
method __setitem__ (line 197) | def __setitem__(self, resource_type, value):
method isEmpty (line 200) | def isEmpty(self):
method add (line 203) | def add(self, resource_path, *values):
method filter_referenced (line 212) | def filter_referenced(self, json):
method copy (line 227) | def copy(self):
function registerHandler (line 238) | def registerHandler(path, resource_class):
function PrimaryResource (line 247) | def PrimaryResource(resource_class):
function lookup (line 269) | def lookup(resource_path):
function find (line 284) | def find(resource_name):
function id_or_name (line 290) | def id_or_name(argument):
function numeric_id (line 296) | def numeric_id(argument):
function deduce (line 305) | def deduce(resource_path, parameters):
function from_parameter (line 312) | def from_parameter(resource_path, parameter_name, parameters):
function sorted_by_id (line 323) | def sorted_by_id(items):
function getAPIVersion (line 333) | def getAPIVersion(req):
function finishGET (line 348) | def finishGET(critic, req, parameters, resource_class, value, values):
function requireSignIn (line 452) | def requireSignIn(critic):
function finishPOST (line 456) | def finishPOST(critic, req, parameters, resource_class, value, values, d...
function finishPUT (line 483) | def finishPUT(critic, req, parameters, resource_class, value, values, da...
function finishDELETE (line 499) | def finishDELETE(critic, req, parameters, resource_class, value, values):
function handleRequestInternal (line 532) | def handleRequestInternal(critic, req):
function handleRequest (line 665) | def handleRequest(critic, req):
FILE: src/jsonapi/check.py
function ishashable (line 23) | def ishashable(value):
class TypeCheckerContext (line 31) | class TypeCheckerContext(object):
method __init__ (line 32) | def __init__(self, parameters):
method push (line 39) | def push(self, element):
method __str__ (line 47) | def __str__(self):
method review (line 51) | def review(self):
method review (line 55) | def review(self, review):
method repository (line 62) | def repository(self):
method repository (line 66) | def repository(self, repository):
class TypeChecker (line 70) | class TypeChecker(object):
method check_compatibility (line 73) | def check_compatibility(self, context, value):
method __call__ (line 78) | def __call__(self, context, value):
method __str__ (line 93) | def __str__(self):
method check (line 96) | def check(self, context, value):
method make (line 100) | def make(value):
class ListChecker (line 118) | class ListChecker(TypeChecker):
method __init__ (line 121) | def __init__(self, checker):
method convert (line 125) | def convert(self, context, value):
class VariantChecker (line 132) | class VariantChecker(TypeChecker):
method __init__ (line 133) | def __init__(self, checkers=None):
method check_compatibility (line 141) | def check_compatibility(self, context, value):
method convert (line 149) | def convert(self, context, value):
class ObjectChecker (line 155) | class ObjectChecker(TypeChecker):
method __init__ (line 159) | def __init__(self, attributes):
method convert (line 178) | def convert(self, context, value):
class IntegerChecker (line 204) | class IntegerChecker(TypeChecker):
class RestrictedInteger (line 208) | class RestrictedInteger(IntegerChecker):
method __init__ (line 209) | def __init__(self, minvalue=None, maxvalue=None):
method check (line 213) | def check(self, context, value):
class NonNegativeInteger (line 220) | class NonNegativeInteger(RestrictedInteger):
method __init__ (line 221) | def __init__(self):
class PositiveInteger (line 224) | class PositiveInteger(RestrictedInteger):
method __init__ (line 225) | def __init__(self):
class StringChecker (line 228) | class StringChecker(TypeChecker):
class RestrictedString (line 232) | class RestrictedString(StringChecker):
method __init__ (line 233) | def __init__(self, minlength=None, maxlength=None, regexp=None):
method check (line 238) | def check(self, context, value):
class RegularExpression (line 247) | class RegularExpression(StringChecker):
method check (line 248) | def check(self, context, value):
class EnumerationChecker (line 255) | class EnumerationChecker(StringChecker):
method __init__ (line 256) | def __init__(self, *values):
method check (line 259) | def check(self, context, value):
class BooleanChecker (line 266) | class BooleanChecker(TypeChecker):
class UserId (line 270) | class UserId(PositiveInteger):
method convert (line 272) | def convert(self, context, value):
class UserName (line 275) | class UserName(StringChecker):
method convert (line 277) | def convert(self, context, value):
class User (line 280) | class User(VariantChecker):
class RepositoryId (line 283) | class RepositoryId(PositiveInteger):
method convert (line 285) | def convert(self, context, value):
class RepositoryName (line 288) | class RepositoryName(StringChecker):
method convert (line 290) | def convert(self, context, value):
class Repository (line 293) | class Repository(VariantChecker):
method process (line 295) | def process(self, context, repository):
class Required (line 298) | class Required(TypeChecker):
method check (line 299) | def check(self, context, value):
class Review (line 304) | class Review(PositiveInteger):
method convert (line 306) | def convert(self, context, value):
method process (line 308) | def process(self, context, review):
class Comment (line 311) | class Comment(PositiveInteger):
method convert (line 313) | def convert(self, context, value):
method process (line 315) | def process(self, context, comment):
class Reply (line 318) | class Reply(PositiveInteger):
method convert (line 320) | def convert(self, context, value):
class CommitId (line 323) | class CommitId(PositiveInteger):
method convert (line 325) | def convert(self, context, value):
class CommitReference (line 328) | class CommitReference(StringChecker):
method convert (line 330) | def convert(self, context, value):
class Commit (line 333) | class Commit(VariantChecker, Repository.Required):
class FileId (line 336) | class FileId(PositiveInteger):
method convert (line 338) | def convert(self, context, value):
class FilePath (line 341) | class FilePath(StringChecker):
method convert (line 343) | def convert(self, context, value):
class File (line 346) | class File(VariantChecker):
class Changeset (line 349) | class Changeset(PositiveInteger, Repository.Required):
method convert (line 351) | def convert(self, context, value):
class ExtensionId (line 356) | class ExtensionId(PositiveInteger):
method convert (line 358) | def convert(self, context, value):
class ExtensionKey (line 361) | class ExtensionKey(StringChecker):
method convert (line 363) | def convert(self, context, value):
class Extension (line 366) | class Extension(VariantChecker):
class AccessControlProfile (line 369) | class AccessControlProfile(PositiveInteger):
method convert (line 371) | def convert(self, context, value):
function convert (line 389) | def convert(parameters, checker, value):
function ensure (line 393) | def ensure(data, path, ensured_value):
FILE: src/jsonapi/documentation.py
function describeRoot (line 19) | def describeRoot():
FILE: src/jsonapi/v1/__init__.py
function timestamp (line 22) | def timestamp(timestamp):
FILE: src/jsonapi/v1/accesscontrolprofiles.py
function updateProfile (line 62) | def updateProfile(profile_modifier, converted):
class AccessControlProfiles (line 85) | class AccessControlProfiles(object):
method json (line 99) | def json(value, parameters, linked):
method single (line 176) | def single(parameters, argument):
method multiple (line 188) | def multiple(parameters):
method deduce (line 199) | def deduce(parameters):
method create (line 212) | def create(parameters, value, values, data):
method update (line 267) | def update(parameters, value, values, data):
method delete (line 308) | def delete(parameters, value, values):
FILE: src/jsonapi/v1/accesstokens.py
function modifyAccessToken (line 26) | def modifyAccessToken(transaction, access_token):
class AccessTokens (line 35) | class AccessTokens(object):
method json (line 51) | def json(value, parameters):
method single (line 135) | def single(parameters, argument):
method multiple (line 152) | def multiple(parameters):
method create (line 165) | def create(parameters, value, values, data):
method update (line 241) | def update(parameters, value, values, data):
method delete (line 310) | def delete(parameters, value, values):
FILE: src/jsonapi/v1/batches.py
class Batches (line 21) | class Batches(object):
method json (line 30) | def json(value, parameters):
method single (line 80) | def single(parameters, argument):
method multiple (line 98) | def multiple(parameters):
method create (line 138) | def create(parameters, value, values, data):
method deduce (line 191) | def deduce(parameters):
method setAsContext (line 203) | def setAsContext(parameters, batch):
FILE: src/jsonapi/v1/branches.py
class Branches (line 21) | class Branches(object):
method json (line 30) | def json(value, parameters):
method single (line 45) | def single(parameters, argument):
method multiple (line 56) | def multiple(parameters):
method setAsContext (line 82) | def setAsContext(parameters, branch):
class BranchCommits (line 89) | class BranchCommits(object):
method multiple (line 105) | def multiple(parameters):
FILE: src/jsonapi/v1/changesets.py
class Changesets (line 24) | class Changesets(object):
method json (line 33) | def json(value, parameters):
method single (line 85) | def single(parameters, argument):
method multiple (line 109) | def multiple(parameters):
method deduce (line 208) | def deduce(parameters):
method setAsContext (line 227) | def setAsContext(parameters, changeset):
FILE: src/jsonapi/v1/comments.py
class Comments (line 21) | class Comments(object):
method json (line 30) | def json(value, parameters):
method single (line 162) | def single(parameters, argument):
method multiple (line 180) | def multiple(parameters):
method create (line 277) | def create(parameters, value, values, data):
method update (line 408) | def update(parameters, value, values, data):
method delete (line 449) | def delete(parameters, value, values):
method deduce (line 469) | def deduce(parameters):
method setAsContext (line 482) | def setAsContext(parameters, comment):
FILE: src/jsonapi/v1/commits.py
class Commits (line 24) | class Commits(object):
method json (line 33) | def json(value, parameters):
method single (line 81) | def single(parameters, argument):
method multiple (line 102) | def multiple(parameters):
method deduce (line 130) | def deduce(parameters):
method fromParameter (line 142) | def fromParameter(value, parameters):
method setAsContext (line 148) | def setAsContext(parameters, commit):
FILE: src/jsonapi/v1/documentation.py
function splitAndDeindentDocstring (line 23) | def splitAndDeindentDocstring(item, level, default=None):
function extractResourceSummary (line 38) | def extractResourceSummary(resource_class):
function popParagraph (line 46) | def popParagraph(lines, include_empty=False):
function copyParagraph (line 59) | def copyParagraph(destination, source, as_definition=False, include_empt...
function describeVersion (line 73) | def describeVersion():
function listAlternativePaths (line 104) | def listAlternativePaths(resource_class):
function describeResource (line 113) | def describeResource(resource_path):
FILE: src/jsonapi/v1/extensions.py
class Extensions (line 21) | class Extensions(object):
method json (line 30) | def json(value, parameters):
method single (line 46) | def single(parameters, argument):
method multiple (line 63) | def multiple(parameters):
FILE: src/jsonapi/v1/filechanges.py
class FileChanges (line 23) | class FileChanges(object):
method json (line 32) | def json(value, parameters):
method single (line 54) | def single(parameters, argument):
method multiple (line 77) | def multiple(parameters):
method deduce (line 92) | def deduce(parameters):
method setAsContext (line 110) | def setAsContext(parameters, filechange):
method resource_id (line 115) | def resource_id(value):
FILE: src/jsonapi/v1/filecontents.py
class Filecontents (line 21) | class Filecontents(object):
method json (line 30) | def json(value, parameters):
method multiple (line 55) | def multiple(parameters):
FILE: src/jsonapi/v1/filediffs.py
class Filediffs (line 21) | class Filediffs(object):
method json (line 30) | def json(value, parameters):
method single (line 103) | def single(parameters, argument):
method multiple (line 123) | def multiple(parameters):
method resource_id (line 140) | def resource_id(value):
FILE: src/jsonapi/v1/files.py
class Files (line 21) | class Files(object):
method json (line 29) | def json(value, parameters):
method single (line 40) | def single(parameters, argument):
method multiple (line 51) | def multiple(parameters):
method fromParameter (line 65) | def fromParameter(value, parameters):
method deduce (line 70) | def deduce(parameters):
method setAsContext (line 83) | def setAsContext(parameters, file_obj):
FILE: src/jsonapi/v1/labeledaccesscontrolprofiles.py
class LabeledAccessControlProfiles (line 25) | class LabeledAccessControlProfiles(object):
method json (line 34) | def json(value, parameters, linked):
method single (line 49) | def single(parameters, argument):
method multiple (line 62) | def multiple(parameters):
method create (line 74) | def create(parameters, value, values, data):
FILE: src/jsonapi/v1/rebases.py
class Rebases (line 21) | class Rebases(object):
method json (line 30) | def json(value, parameters):
method single (line 66) | def single(parameters, argument):
method multiple (line 77) | def multiple(parameters):
method create (line 89) | def create(parameters, value, values, data):
method delete (line 141) | def delete(parameters, value, values):
method setAsContext (line 155) | def setAsContext(parameters, rebase):
FILE: src/jsonapi/v1/replies.py
class Replies (line 21) | class Replies(object):
method json (line 30) | def json(value, parameters):
method single (line 48) | def single(parameters, argument):
method multiple (line 66) | def multiple(parameters):
method create (line 81) | def create(parameters, value, values, data):
method update (line 133) | def update(parameters, value, values, data):
method delete (line 163) | def delete(parameters, value, values):
method fromParameter (line 184) | def fromParameter(value, parameters):
FILE: src/jsonapi/v1/repositories.py
function from_argument (line 20) | def from_argument(parameters, argument):
class Repositories (line 26) | class Repositories(object):
method json (line 34) | def json(value, parameters):
method single (line 51) | def single(parameters, argument):
method multiple (line 62) | def multiple(parameters):
method deduce (line 96) | def deduce(parameters):
method fromParameter (line 113) | def fromParameter(value, parameters):
method setAsContext (line 118) | def setAsContext(parameters, repository):
FILE: src/jsonapi/v1/reviewablefilechanges.py
class ReviewableFileChanges (line 21) | class ReviewableFileChanges(object):
method json (line 30) | def json(value, parameters):
method single (line 76) | def single(parameters, argument):
method multiple (line 88) | def multiple(parameters):
method update (line 135) | def update(parameters, value, values, data):
FILE: src/jsonapi/v1/reviews.py
class Reviews (line 21) | class Reviews(object):
method json (line 30) | def json(value, parameters):
method single (line 106) | def single(parameters, argument):
method multiple (line 117) | def multiple(parameters):
method create (line 145) | def create(parameters, value, values, data):
method deduce (line 163) | def deduce(parameters):
method setAsContext (line 176) | def setAsContext(parameters, review):
FILE: src/jsonapi/v1/reviewsummaries.py
class ReviewSummaries (line 21) | class ReviewSummaries(object):
method json (line 29) | def json(value, parameters):
method multiple (line 56) | def multiple(parameters):
FILE: src/jsonapi/v1/sessions.py
class Session (line 22) | class Session(object):
method __init__ (line 23) | def __init__(self, user, session_type):
class SessionError (line 27) | class SessionError(jsonapi.Error):
class Sessions (line 32) | class Sessions(object):
method json (line 41) | def json(value, parameters):
method single (line 77) | def single(parameters, argument):
method create (line 97) | def create(parameters, value, values, data):
method delete (line 120) | def delete(parameters, value, values):
FILE: src/jsonapi/v1/users.py
class Users (line 23) | class Users(object):
method json (line 31) | def json(value, parameters):
method single (line 48) | def single(parameters, argument):
method multiple (line 66) | def multiple(parameters):
method update (line 112) | def update(parameters, value, values, data):
method deduce (line 131) | def deduce(parameters):
method fromParameter (line 143) | def fromParameter(value, parameters):
method setAsContext (line 148) | def setAsContext(parameters, user):
class Emails (line 153) | class Emails(object):
method json (line 169) | def json(value, parameters):
method single (line 182) | def single(parameters, argument):
method multiple (line 197) | def multiple(parameters):
class Filters (line 203) | class Filters(object):
method json (line 214) | def json(value, parameters):
method single (line 232) | def single(parameters, argument):
method multiple (line 250) | def multiple(parameters):
method create (line 269) | def create(parameters, value, values, data):
method update (line 338) | def update(parameters, value, values, data):
method delete (line 373) | def delete(parameters, value, values):
FILE: src/library/js/v8/critic-batch.js
function CriticBatch (line 24) | function CriticBatch(data)
function commitFromFileVersion (line 180) | function commitFromFileVersion(file_version)
function createCommentChain (line 191) | function createCommentChain(text, data, type)
function changeAssignments (line 565) | function changeAssignments(user, what, assigned)
function getReviewMessageId (line 763) | function getReviewMessageId(review, to_user)
function getCommentMessageId (line 773) | function getCommentMessageId(comment, to_user)
FILE: src/library/js/v8/critic-branch.js
function CriticBranch (line 21) | function CriticBranch(options)
function CriticCheckBranch (line 139) | function CriticCheckBranch(branch, upstream)
FILE: src/library/js/v8/critic-changeset.js
function CriticChangesetLine (line 32) | function CriticChangesetLine(type, old_index, old_lines, new_index, new_...
function CriticChangesetChunk (line 79) | function CriticChangesetChunk(changeset, file, delete_offset, delete_cou...
function CriticChangesetFile (line 169) | function CriticChangesetFile(changeset, file_id, old_sha1, new_sha1, old...
function CriticChangesetFileVersion (line 320) | function CriticChangesetFileVersion(changeset, file, mode, size, sha1)
function CriticChangeset (line 334) | function CriticChangeset(repository, data)
function CriticMergeChangeset (line 493) | function CriticMergeChangeset(changesets)
FILE: src/library/js/v8/critic-cli.js
function executeCLI (line 21) | function executeCLI(commands)
FILE: src/library/js/v8/critic-comment.js
function CriticComment (line 21) | function CriticComment(chain_id, batch_id, comment_id, user_id, time, st...
function CriticCommentChain (line 51) | function CriticCommentChain(result_or_chain_id, data)
FILE: src/library/js/v8/critic-commitset.js
function CriticCommitSet (line 21) | function CriticCommitSet(all)
function add (line 196) | function add(commit)
FILE: src/library/js/v8/critic-dashboard.js
function CriticDashboard (line 21) | function CriticDashboard(user)
FILE: src/library/js/v8/critic-file.js
function CriticFile (line 25) | function CriticFile(data)
function CriticFileVersion (line 99) | function CriticFileVersion(repository, file, mode, size, sha1, data)
FILE: src/library/js/v8/critic-filters.js
function CriticFilters (line 21) | function CriticFilters(data)
function getUserFileAssociation (line 82) | function getUserFileAssociation(filters, user_id, file_id)
FILE: src/library/js/v8/critic-filterstransaction.js
function CriticFiltersTransaction (line 24) | function CriticFiltersTransaction(repository)
function CriticFiltersTransaction_getInternals (line 38) | function CriticFiltersTransaction_getInternals(transaction)
function isNonConflicting (line 74) | function isNonConflicting(filter)
function isNonConflicting (line 119) | function isNonConflicting(filter)
FILE: src/library/js/v8/critic-git.js
function GitObject (line 25) | function GitObject(sha1, type, size, data)
function CriticCommitFileVersion (line 35) | function CriticCommitFileVersion(commit, path_or_id, data)
function CriticCommitDirectory (line 79) | function CriticCommitDirectory(commit, path)
function runGitCommand (line 178) | function runGitCommand(path, args)
function CriticRepository (line 233) | function CriticRepository(name_or_id)
function GitUserTime (line 417) | function GitUserTime(fullname, email, utc)
function CriticCommit (line 450) | function CriticCommit(repository, sha1)
function createChangeset (line 666) | function createChangeset(repository, type, parent, child)
function CriticRepositoryWorkCopy (line 830) | function CriticRepositoryWorkCopy(repository, branch)
FILE: src/library/js/v8/critic-html.js
function htmlify (line 34) | function htmlify(text)
function writeStandardHeader (line 39) | function writeStandardHeader(title, data)
function writeStandardFooter (line 119) | function writeStandardFooter(data)
function PaleYellowTable (line 131) | function PaleYellowTable(title)
FILE: src/library/js/v8/critic-launcher-fork.js
function Child (line 32) | function Child(socket)
FILE: src/library/js/v8/critic-launcher.js
function run (line 29) | function run()
FILE: src/library/js/v8/critic-log.js
function CriticLog (line 21) | function CriticLog(user)
FILE: src/library/js/v8/critic-mail.js
function sendMail (line 21) | function sendMail(filename)
function CriticMailTransaction (line 26) | function CriticMailTransaction()
FILE: src/library/js/v8/critic-review.js
function CriticReview_isCreated (line 23) | function CriticReview_isCreated(review)
function CriticReviewFilter (line 28) | function CriticReviewFilter(review, user_id, path, type, creator_id)
function CriticReviewRebase (line 63) | function CriticReviewRebase(review, user_id, old_head_id, new_head_id, n...
function CriticReviewCreated (line 77) | function CriticReviewCreated(review_id)
function CriticReview (line 82) | function CriticReview(arg)
function CriticPartition (line 526) | function CriticPartition(review, commits, rebase)
function setReviewState (line 612) | function setReviewState(review, user, new_state, verb)
FILE: src/library/js/v8/critic-statistics.js
function CriticStatistics (line 21) | function CriticStatistics()
function mangle (line 52) | function mangle(item, argument)
function getPerUser (line 305) | function getPerUser(user_id)
FILE: src/library/js/v8/critic-storage.js
function CriticStorage (line 21) | function CriticStorage(user)
FILE: src/library/js/v8/critic-text.js
function reflow (line 21) | function reflow(text, line_length, indent)
function repeat (line 86) | function repeat(s, n)
function spaces (line 91) | function spaces(n)
function renderFilesLines (line 97) | function renderFilesLines(items, indent)
FILE: src/library/js/v8/critic-trackedbranch.js
function signalBranchTracker (line 21) | function signalBranchTracker()
function CriticTrackedBranch (line 32) | function CriticTrackedBranch(id, data) {
FILE: src/library/js/v8/critic-user.js
function CriticFilter (line 21) | function CriticFilter(user, repository, data)
function CriticUser (line 47) | function CriticUser(data)
function CriticAnonymousUser (line 235) | function CriticAnonymousUser()
FILE: src/library/js/v8/critic.js
function CriticError (line 31) | function CriticError(message, exception)
function checked (line 74) | function checked(obj, name)
function describeCallSite (line 86) | function describeCallSite(callsite)
function setup (line 227) | function setup(data)
function shutdown (line 292) | function shutdown()
function connect (line 301) | function connect(data)
function reconnect (line 315) | function reconnect()
FILE: src/linkify.py
class Context (line 21) | class Context(object):
method __init__ (line 22) | def __init__(self, db=None, request=None, repository=None, review=None...
class LinkType (line 29) | class LinkType(object):
method __init__ (line 37) | def __init__(self, fragment):
method match (line 57) | def match(self, word):
method linkify (line 60) | def linkify(self, word):
class SimpleLinkType (line 73) | class SimpleLinkType(LinkType):
method __init__ (line 78) | def __init__(self, fragment, regexp=None):
method linkify (line 85) | def linkify(self, word, context):
class HTTP (line 91) | class HTTP(SimpleLinkType):
method __init__ (line 96) | def __init__(self):
class URL (line 99) | class URL(SimpleLinkType):
method __init__ (line 104) | def __init__(self):
class SHA1 (line 107) | class SHA1(LinkType):
method __init__ (line 120) | def __init__(self):
method linkify (line 123) | def linkify(self, word, context):
class Diff (line 136) | class Diff(LinkType):
method __init__ (line 144) | def __init__(self):
method linkify (line 147) | def linkify(self, word, context):
class Review (line 163) | class Review(LinkType):
method __init__ (line 171) | def __init__(self):
method linkify (line 174) | def linkify(self, word, context):
FILE: src/log/commitset.py
class CommitSet (line 19) | class CommitSet:
method __init__ (line 20) | def __init__(self, commits):
method __contains__ (line 42) | def __contains__(self, commit):
method __getitem__ (line 45) | def __getitem__(self, key):
method __len__ (line 48) | def __len__(self):
method __iter__ (line 51) | def __iter__(self):
method __repr__ (line 54) | def __repr__(self):
method get (line 57) | def get(self, key):
method getHeads (line 60) | def getHeads(self):
method getTails (line 63) | def getTails(self):
method getMerges (line 66) | def getMerges(self):
method getChildren (line 69) | def getChildren(self, commit):
method getParents (line 74) | def getParents(self, commit):
method getFilteredTails (line 77) | def getFilteredTails(self, repository):
method getTailsFrom (line 106) | def getTailsFrom(self, commit):
method getCommonAncestors (line 134) | def getCommonAncestors(self, commit):
method filtered (line 166) | def filtered(self, commits):
method without (line 179) | def without(self, commits):
method isAncestorOf (line 205) | def isAncestorOf(self, ancestor, commit):
method fromRange (line 222) | def
Condensed preview — 730 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (4,349K chars).
[
{
"path": ".gitignore",
"chars": 54,
"preview": ".install.data\n.installed\n*.pyc\n*.pyo\n*~\ntesting/cache\n"
},
{
"path": ".gitmodules",
"chars": 219,
"preview": "[submodule \"installation/externals/chosen\"]\n\tpath = installation/externals/chosen\n\turl = ../chosen.git\n\n[submodule \"inst"
},
{
"path": "CONTRIBUTORS",
"chars": 315,
"preview": "Author:\n\nJens Lindström <jl@critic-review.org>\n\nContributors:\n\nRafał Chłodnicki\nPhilip Jägenstedt\nLeif Arne Storset\nAlex"
},
{
"path": "COPYING",
"chars": 1423,
"preview": "Copyright 2012-2014 the Critic contributors, Opera Software ASA\n\nThe Critic code review system is licensed under the Apa"
},
{
"path": "INSTALL",
"chars": 1240,
"preview": "Installation\n============\n\nTo install Critic, run the script install.py as root. It will ask a\nnumber of question and t"
},
{
"path": "README.md",
"chars": 3560,
"preview": "Critic\n======\n\nThis is the code review system, Critic.\n\nCritic has a few [concepts][concepts] that might be useful to kn"
},
{
"path": "documentation/concepts.txt",
"chars": 5801,
"preview": "Critic(al) Concepts\n===================\n\nBranches\n--------\n\nCritic maintains a view of branches that is slightly differe"
},
{
"path": "documentation/tutorials.txt",
"chars": 504,
"preview": "Critic Tutorials\n================\n\nMost of Critic's documentation is available as tutorials available in the\ninstalled s"
},
{
"path": "documentation/user_faq.md",
"chars": 1750,
"preview": "Critic User FAQ\n===============\n\n### How can I create a code review for a subset of my topic branch? ###\n\nSuppose that y"
},
{
"path": "extend.py",
"chars": 14446,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "install.py",
"chars": 6932,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/__init__.py",
"chars": 1441,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/admin.py",
"chars": 4809,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/config.py",
"chars": 33311,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/criticctl.py",
"chars": 2119,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/data/comments.pgsql",
"chars": 1262,
"preview": "-- -*- mode: sql -*-\n--\n-- Copyright 2012 Jens Lindström, Opera Software ASA\n--\n-- Licensed under the Apache License, Ve"
},
{
"path": "installation/data/dbschema.base.sql",
"chars": 2052,
"preview": "-- -*- mode: sql -*-\n--\n-- Copyright 2015 the Critic contributors, Opera Software ASA\n--\n-- Licensed under the Apache Li"
},
{
"path": "installation/data/dbschema.changesets.sql",
"chars": 3102,
"preview": "-- -*- mode: sql -*-\n--\n-- Copyright 2015 the Critic contributors, Opera Software ASA\n--\n-- Licensed under the Apache Li"
},
{
"path": "installation/data/dbschema.comments.sql",
"chars": 6366,
"preview": "-- -*- mode: sql -*-\n--\n-- Copyright 2012 Jens Lindström, Opera Software ASA\n--\n-- Licensed under the Apache License, Ve"
},
{
"path": "installation/data/dbschema.extensions.sql",
"chars": 5138,
"preview": "-- -*- mode: sql -*-\n--\n-- Copyright 2012 Jens Lindström, Opera Software ASA\n--\n-- Licensed under the Apache License, Ve"
},
{
"path": "installation/data/dbschema.filters.sql",
"chars": 1200,
"preview": "-- -*- mode: sql -*-\n--\n-- Copyright 2015 the Critic contributors, Opera Software ASA\n--\n-- Licensed under the Apache Li"
},
{
"path": "installation/data/dbschema.git.sql",
"chars": 3944,
"preview": "-- -*- mode: sql -*-\n--\n-- Copyright 2015 the Critic contributors, Opera Software ASA\n--\n-- Licensed under the Apache Li"
},
{
"path": "installation/data/dbschema.news.sql",
"chars": 1006,
"preview": "-- -*- mode: sql -*-\n--\n-- Copyright 2015 the Critic contributors, Opera Software ASA\n--\n-- Licensed under the Apache Li"
},
{
"path": "installation/data/dbschema.preferences.sql",
"chars": 3321,
"preview": "-- -*- mode: sql -*-\n--\n-- Copyright 2015 the Critic contributors, Opera Software ASA\n--\n-- Licensed under the Apache Li"
},
{
"path": "installation/data/dbschema.reviews.sql",
"chars": 9117,
"preview": "-- -*- mode: sql -*-\n--\n-- Copyright 2015 the Critic contributors, Opera Software ASA\n--\n-- Licensed under the Apache Li"
},
{
"path": "installation/data/dbschema.trackedbranches.sql",
"chars": 1725,
"preview": "-- -*- mode: sql -*-\n--\n-- Copyright 2015 the Critic contributors, Opera Software ASA\n--\n-- Licensed under the Apache Li"
},
{
"path": "installation/data/dbschema.users.sql",
"chars": 6217,
"preview": "-- -*- mode: sql -*-\n--\n-- Copyright 2015 the Critic contributors, Opera Software ASA\n--\n-- Licensed under the Apache Li"
},
{
"path": "installation/database.py",
"chars": 9526,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/extensions.py",
"chars": 1423,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/externals/.gitignore",
"chars": 13,
"preview": "depot_tools/\n"
},
{
"path": "installation/externals/MIT-LICENSE.Chosen.md",
"chars": 1215,
"preview": "#### Chosen\n- by Patrick Filler for [Harvest](http://getharvest.com)\n- Copyright (c) 2011-2013 by Harvest\n\nAvailable for"
},
{
"path": "installation/externals/MIT-LICENSE.jQuery.txt",
"chars": 1099,
"preview": "Copyright 2012 jQuery Foundation and other contributors\nhttp://jquery.com/\n\nPermission is hereby granted, free of charge"
},
{
"path": "installation/files.py",
"chars": 13380,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/git.py",
"chars": 989,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/httpd.py",
"chars": 15520,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2015 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "installation/initd.py",
"chars": 4713,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/input.py",
"chars": 1874,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/lifecycle.json",
"chars": 43,
"preview": "{\n\t\"branch\": \"stable/1\",\n\t\"stable\": true\n}\n"
},
{
"path": "installation/migrate.py",
"chars": 2762,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/migrations/dbschema.altertable.branches.add.archived.py",
"chars": 1301,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "installation/migrations/dbschema.altertable.changesets.parent.dropnotnull.py",
"chars": 1301,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/migrations/dbschema.altertable.commentchainchanges.addressed_by.py",
"chars": 1560,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/migrations/dbschema.altertable.commentchainchanges.drop.review.py",
"chars": 1141,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "installation/migrations/dbschema.altertable.commentchainlines.drop.commit.py",
"chars": 1296,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/migrations/dbschema.altertable.comments.time.setdefaultnow.py",
"chars": 1287,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2016 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "installation/migrations/dbschema.altertable.previousreachable.rebase.ondeletecascade.py",
"chars": 1423,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/migrations/dbschema.altertable.repositories.drop.branch.py",
"chars": 1295,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "installation/migrations/dbschema.altertable.repositories.drop.relay.py",
"chars": 1779,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2013 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/migrations/dbschema.altertable.reviewfilechanges.rename-columns.py",
"chars": 1543,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2013 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/migrations/dbschema.altertable.reviewmergeconfirmations.add.tail.py",
"chars": 1306,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2013 Jens Lindström\n#\n# Licensed under the Apache License, Version"
},
{
"path": "installation/migrations/dbschema.altertable.reviewrebases.add.equivalent_merge.py",
"chars": 5051,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "installation/migrations/dbschema.altertable.reviewrebases.add.replayed_rebase.py",
"chars": 2741,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "installation/migrations/dbschema.altertable.reviewrecipientfilters.uid-can-be-null.py",
"chars": 1324,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/migrations/dbschema.altertable.reviews.add.origin.py",
"chars": 1826,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "installation/migrations/dbschema.altertable.systemidentities.add.installed_sha1.installed_at.py",
"chars": 1776,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2013 Martin Olsson\n#\n# Licensed under the Apache License, Version "
},
{
"path": "installation/migrations/dbschema.altertable.systemidentities.url-prefix.py",
"chars": 2949,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2013 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/migrations/dbschema.altertable.usergitemails.py",
"chars": 1520,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/migrations/dbschema.altertable.usersessions.add.labels.py",
"chars": 872,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2015 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "installation/migrations/dbschema.createindex.misc.py",
"chars": 1550,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/migrations/dbschema.createtable.accesstokens.py",
"chars": 1776,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2015 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "installation/migrations/dbschema.createtable.knownremotes.py",
"chars": 1486,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/migrations/dbschema.createtable.scheduledreviewbrancharchivals.py",
"chars": 2127,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "installation/migrations/dbschema.createtable.timezones.py",
"chars": 1763,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/migrations/dbschema.createtable.useremails.py",
"chars": 2481,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "installation/migrations/dbschema.createtable.usersessions.py",
"chars": 1560,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/migrations/dbschema.createtables.accesscontrol.py",
"chars": 4706,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2015 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "installation/migrations/dbschema.droptable.knownhosts.py",
"chars": 1207,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2013 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/migrations/dbschema.extension-filterhook-role.py",
"chars": 4355,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2013 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/migrations/dbschema.external-authentication.py",
"chars": 1904,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "installation/migrations/dbschema.files-and-directories.py",
"chars": 5214,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2013 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/migrations/dbschema.fixup-extensionroles.py",
"chars": 2234,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/migrations/dbschema.per-repository-or-filter-preferences.py",
"chars": 5769,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2013 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/migrations/dbschema.review-constraints-tweaking.py",
"chars": 1737,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2013 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/migrations/git.check-keepalive-references.py",
"chars": 5743,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/migrations/git.clean-up-temporary-references.py",
"chars": 1736,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/migrations/git.convert-replays-into-keepalives.py",
"chars": 1985,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/migrations/git.rename-keepalive-chain.py",
"chars": 2054,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/migrations/installation.config-pyc-file-permissions.py",
"chars": 2046,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2013 Martin Olsson\n#\n# Licensed under the Apache License, Version "
},
{
"path": "installation/migrations/news.filter-system-rewrite.py",
"chars": 1905,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2013 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/migrations/news.review-branch-archival.py",
"chars": 2349,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 Jens Widell, Opera Software ASA\n#\n# Licensed under the Apache"
},
{
"path": "installation/migrations/news.review-quick-search.py",
"chars": 1904,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2013 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/migrations/preference.commit.diff.rulerColumn.py",
"chars": 1463,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2013 Rafał Chłodnicki, Opera Software ASA\n#\n# Licensed under the A"
},
{
"path": "installation/paths.py",
"chars": 7794,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/prefs.py",
"chars": 11013,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/prereqs.py",
"chars": 11620,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/process.py",
"chars": 973,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/qs/__init__.py",
"chars": 703,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/qs/data.py",
"chars": 4837,
"preview": "import sys\nimport os\nimport pwd\nimport grp\nimport subprocess\nimport json\nimport multiprocessing\n\nimport installation\n\nde"
},
{
"path": "installation/qs/sqlite.py",
"chars": 10779,
"preview": "import sqlite3\nimport os\nimport re\nimport datetime\n\nimport installation\n\nIntegrityError = sqlite3.IntegrityError\nProgram"
},
{
"path": "installation/smtp.py",
"chars": 10245,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/system.py",
"chars": 7194,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/templates/apache/site.both",
"chars": 2454,
"preview": "WSGIApplicationGroup %%{GLOBAL}\nWSGIProcessGroup critic-main\nWSGIDaemonProcess critic-main processes=2 \\\n "
},
{
"path": "installation/templates/apache/site.http",
"chars": 1397,
"preview": "<VirtualHost *:80>\n\tServerAdmin %(installation.admin.email)s\n\tServerName %(installation.system.hostname)s\n\n\tWSGIApplicat"
},
{
"path": "installation/templates/apache/site.https",
"chars": 1763,
"preview": "<VirtualHost *:80>\n\tServerAdmin %(installation.admin.email)s\n\tServerName %(installation.system.hostname)s\n\n\tRewriteEngin"
},
{
"path": "installation/templates/configuration/__init__.py",
"chars": 803,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/templates/configuration/auth.py",
"chars": 8035,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2013 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/templates/configuration/base.py",
"chars": 5960,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/templates/configuration/database.py",
"chars": 905,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/templates/configuration/debug.py",
"chars": 1487,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2013 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/templates/configuration/executables.py",
"chars": 964,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/templates/configuration/extensions.py",
"chars": 1852,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/templates/configuration/limits.py",
"chars": 1632,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/templates/configuration/mimetypes.py",
"chars": 1132,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/templates/configuration/paths.py",
"chars": 1924,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/templates/configuration/services.py",
"chars": 3017,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/templates/configuration/smtp-credentials.json",
"chars": 92,
"preview": "{ \"username\": %(installation.smtp.username)s,\n \"password\": %(installation.smtp.password)s }"
},
{
"path": "installation/templates/configuration/smtp.py",
"chars": 818,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "installation/templates/criticctl",
"chars": 3122,
"preview": "#!%(installation.prereqs.python)s\n# -*- mode: python -*-\n\nimport sys\nimport argparse\nimport os\nimport pwd\nimport grp\n\n# "
},
{
"path": "installation/templates/initd",
"chars": 1478,
"preview": "#!/bin/sh\nset -e\n\n### BEGIN INIT INFO\n# Provides:\t\tcritic-main\n# Required-Start:\tpostgresql $local_fs $remote_fs $networ"
},
{
"path": "installation/templates/nginx/site.both",
"chars": 562,
"preview": "server {\n\tlisten 80;\n\tlisten [::]:80;\n\tlisten 443 ssl;\n\tlisten [::]:443 ssl;\n\n\tserver_name %(installation.system.hostnam"
},
{
"path": "installation/templates/nginx/site.http",
"chars": 383,
"preview": "server {\n\tlisten 80;\n\tlisten [::]:80;\n\n\tserver_name %(installation.system.hostname)s;\n\n\tlocation / {\n\t\tuwsgi_pass unix:/"
},
{
"path": "installation/templates/nginx/site.https",
"chars": 650,
"preview": "server {\n\tlisten 80;\n\tserver_name %(installation.system.hostname)s;\n\treturn 301 https://$server_name$request_uri;\n}\n\nser"
},
{
"path": "installation/templates/uwsgi/app.backend.ini",
"chars": 594,
"preview": "[uwsgi]\nplugins = python\n\nmaster = true\nsocket = %(installation.paths.run_dir)s/main/sockets/uwsgi.unix\n# Make %(install"
},
{
"path": "installation/templates/uwsgi/app.frontend.ini.both",
"chars": 453,
"preview": "[uwsgi]\nmaster = true\n\n# Use a shared socket to allow binding to a privileged port without running as\n# root.\nshared-soc"
},
{
"path": "installation/templates/uwsgi/app.frontend.ini.http",
"chars": 356,
"preview": "[uwsgi]\nmaster = true\n\n# Use a shared socket to allow binding to a privileged port without running as\n# root.\nshared-soc"
},
{
"path": "installation/templates/uwsgi/app.frontend.ini.https",
"chars": 462,
"preview": "[uwsgi]\nmaster = true\n\n# Use a shared socket to allow binding to a privileged port without running as\n# root.\nshared-soc"
},
{
"path": "installation/utils.py",
"chars": 16744,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2012 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "pylint.rc",
"chars": 7624,
"preview": "[MASTER]\n\n# Specify a configuration file.\n#rcfile=\n\n# Python code to execute, usually for sys.path manipulation such as\n"
},
{
"path": "pythonversion.py",
"chars": 936,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2013 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "quickstart.py",
"chars": 15375,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2013 Jens Lindström, Opera Software ASA\n#\n# Licensed under the Apa"
},
{
"path": "src/api/__init__.py",
"chars": 1263,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/accesscontrolprofile.py",
"chars": 5347,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2015 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/accesstoken.py",
"chars": 2788,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2015 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/apierror.py",
"chars": 1559,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/apiobject.py",
"chars": 1759,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/batch.py",
"chars": 6153,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2017 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/branch.py",
"chars": 3425,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/changeset.py",
"chars": 3751,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2017 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/comment.py",
"chars": 15453,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2017 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/commit.py",
"chars": 7802,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/commitset.py",
"chars": 7690,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/config.py",
"chars": 2045,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/critic.py",
"chars": 2538,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/extension.py",
"chars": 4012,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2015 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/file.py",
"chars": 2563,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2017 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/filechange.py",
"chars": 2115,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2017 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/filecontent.py",
"chars": 1655,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2017 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/filediff.py",
"chars": 5583,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2017 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/filters.py",
"chars": 3241,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/impl/__init__.py",
"chars": 1083,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/impl/accesscontrolprofile.py",
"chars": 5079,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2015 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/impl/accesstoken.py",
"chars": 2957,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2015 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/impl/apiobject.py",
"chars": 5084,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2015 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/impl/batch.py",
"chars": 8720,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2017 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/impl/branch.py",
"chars": 3227,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/impl/branch_unittest.py",
"chars": 2273,
"preview": "def basic(arguments):\n import api\n\n assert arguments.sha1 is not None, \"missing argument: --sha1\"\n assert argum"
},
{
"path": "src/api/impl/changeset.py",
"chars": 7055,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2017 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/impl/changeset_unittest.py",
"chars": 23005,
"preview": "FROM_SHA1 = \"573c5ff15ad95cfbc3e2f2efb0a638a4a78c17a7\"\nFROM_SINGLE_SHA1 = \"aabc2b10c930a9e72fe9587a6e8634087bb3efe1\"\nTO_"
},
{
"path": "src/api/impl/comment.py",
"chars": 18932,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2017 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/impl/comment_unittest.py",
"chars": 4687,
"preview": "import sys\nimport datetime\n\ndef basic(arguments):\n import api\n\n critic = api.critic.startSession(for_testing=True)"
},
{
"path": "src/api/impl/commit.py",
"chars": 6570,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/impl/commit_unittest.py",
"chars": 4749,
"preview": "import datetime\n\n# This is the commit that added the testing framework:\nCOMMIT_SHA1 = \"78d7849db854f3544d7291cce96a0a4fa"
},
{
"path": "src/api/impl/commitset.py",
"chars": 7185,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/impl/commitset_unittest.py",
"chars": 6948,
"preview": "def basic(arguments):\n import api\n\n assert arguments.prefix is not None, \"missing argument: --prefix\"\n\n critic "
},
{
"path": "src/api/impl/config_unittest.py",
"chars": 1586,
"preview": "def basic():\n import api\n\n assert api.config.getBoolean(\"debug\", \"IS_TESTING\") is True\n assert api.config.getBo"
},
{
"path": "src/api/impl/critic.py",
"chars": 1984,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/impl/extension.py",
"chars": 3854,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2015 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/impl/file.py",
"chars": 2141,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2017 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/impl/filechange.py",
"chars": 2354,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2017 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/impl/filechange_unittest.py",
"chars": 4429,
"preview": "from api.impl.changeset_unittest import ROOT_PATHLIST, ROOT_SHA1, FROM_SHA1,\\\nTO_SHA1, CUSTOM_PATHLIST\n\ndef pre():\n i"
},
{
"path": "src/api/impl/filecontent.py",
"chars": 1983,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2017 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/impl/filediff.py",
"chars": 13420,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2017 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/impl/filediff_unittest.py",
"chars": 3691,
"preview": "from api.impl.changeset_unittest import FROM_SHA1, TO_SHA1\n\ndef pre1():\n import api\n\n critic = api.critic.startSes"
},
{
"path": "src/api/impl/filters.py",
"chars": 3680,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/impl/labeledaccesscontrolprofile.py",
"chars": 2180,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2015 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/impl/log/__init__.py",
"chars": 31,
"preview": "import rebase\nimport partition\n"
},
{
"path": "src/api/impl/log/partition.py",
"chars": 1373,
"preview": "import api\n\nclass Partition(object):\n def __init__(self, commits):\n assert not commits or len(commits.heads) ="
},
{
"path": "src/api/impl/log/partition_unittest.py",
"chars": 4864,
"preview": "def basic():\n import api\n\n critic = api.critic.startSession(for_testing=True)\n repository = api.repository.fetc"
},
{
"path": "src/api/impl/log/rebase.py",
"chars": 3834,
"preview": "import api\nfrom .. import apiobject\n\nclass Rebase(apiobject.APIObject):\n wrapper_class = api.log.rebase.Rebase\n\n d"
},
{
"path": "src/api/impl/log/rebase_unittest.py",
"chars": 6458,
"preview": "def basic():\n import api\n\n critic = api.critic.startSession(for_testing=True)\n repository = api.repository.fetc"
},
{
"path": "src/api/impl/reply.py",
"chars": 3599,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2017 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/impl/reply_unittest.py",
"chars": 2795,
"preview": "import sys\nimport datetime\n\ndef basic(arguments):\n import api\n\n critic = api.critic.startSession(for_testing=True)"
},
{
"path": "src/api/impl/repository.py",
"chars": 5536,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/impl/repository_unittest.py",
"chars": 4522,
"preview": "def basic(arguments):\n import api\n\n assert arguments.sha1 is not None\n assert len(arguments.sha1) == 40\n\n as"
},
{
"path": "src/api/impl/review.py",
"chars": 13817,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/impl/review_unittest.py",
"chars": 4993,
"preview": "def basic():\n import api\n\n critic = api.critic.startSession(for_testing=True)\n review = api.review.fetch(critic"
},
{
"path": "src/api/impl/reviewablefilechange.py",
"chars": 10612,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2017 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/impl/reviewsummary.py",
"chars": 4365,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2017 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/impl/user.py",
"chars": 8644,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/impl/user_unittest.py",
"chars": 11703,
"preview": "def basic(arguments):\n import api\n\n critic = api.critic.startSession(for_testing=True)\n\n alice = api.user.fetch"
},
{
"path": "src/api/labeledaccesscontrolprofile.py",
"chars": 2502,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2015 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/log/__init__.py",
"chars": 31,
"preview": "import rebase\nimport partition\n"
},
{
"path": "src/api/log/partition.py",
"chars": 2025,
"preview": "import api\n\nclass PartitionError(api.APIError):\n \"\"\"Raised for incompatible commits/rebases arguments to create()\"\"\"\n"
},
{
"path": "src/api/log/rebase.py",
"chars": 2509,
"preview": "import api\n\nclass RebaseError(api.APIError):\n \"\"\"Base exception for all errors related to the Rebase class\"\"\"\n pas"
},
{
"path": "src/api/preference.py",
"chars": 1548,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/reply.py",
"chars": 2824,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2017 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/repository.py",
"chars": 6094,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/review.py",
"chars": 8114,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/reviewablefilechange.py",
"chars": 6721,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2017 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/reviewsummary.py",
"chars": 1943,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2017 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/transaction/__init__.py",
"chars": 6396,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2015 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/transaction/accesscontrolprofile.py",
"chars": 6816,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2015 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/transaction/accesstoken.py",
"chars": 2046,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2015 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/transaction/comment.py",
"chars": 6891,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2017 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/transaction/filters.py",
"chars": 1598,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2015 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/transaction/labeledaccesscontrolprofile.py",
"chars": 2224,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2015 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/transaction/reply.py",
"chars": 1723,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2017 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/transaction/review.py",
"chars": 21455,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2017 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/transaction/user.py",
"chars": 4499,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2015 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
},
{
"path": "src/api/user.py",
"chars": 8125,
"preview": "# -*- mode: python; encoding: utf-8 -*-\n#\n# Copyright 2014 the Critic contributors, Opera Software ASA\n#\n# Licensed unde"
}
]
// ... and 530 more files (download for full content)
About this extraction
This page contains the full source code of the jensl/critic GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 730 files (3.9 MB), approximately 1.1M tokens, and a symbol index with 4368 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.