diff --git a/resources/sql/patches/006.repository.sql b/resources/sql/patches/006.repository.sql new file mode 100644 index 0000000000..569437c2c1 --- /dev/null +++ b/resources/sql/patches/006.repository.sql @@ -0,0 +1,42 @@ +create table phabricator_repository.repository_commitdata ( + id int unsigned not null auto_increment primary key, + commitID int unsigned not null, + authorName varchar(255) not null, + commitMessage longblob not null, + unique key (commitID), + key (authorName) +); + +ALTER TABLE phabricator_worker.worker_task drop priority; +ALTER TABLE phabricator_worker.worker_task drop key leaseOwner; +ALTER TABLE phabricator_worker.worker_task drop key (leaseOwner(16)); + +create table phabricator_repository.repository_path ( + id int unsigned not null auto_increment primary key, + path varchar(512) not null, + unique key (path) +); + +create table phabricator_repository.repository_pathchange ( + repositoryID int unsigned NOT NULL, + pathID int unsigned NOT NULL, + commitID int unsigned NOT NULL, + targetPathID int unsigned, + targetCommitID int unsigned, + changeType int unsigned NOT NULL, + fileType int unsigned NOT NULL, + isDirect bool NOT NULL, + commitSequence int unsigned NOT NULL, + primary key (commitID, pathID), + key (repositoryID, pathID, commitSequence) +); + +create table phabricator_repository.repository_filesystem ( + repositoryID int unsigned not null, + parentID int unsigned not null, + svnCommit int unsigned not null, + pathID int unsigned not null, + existed bool not null, + fileType int unsigned not null, + primary key (repositoryID, parentID, svnCommit, pathID) +); diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 65be1069ec..5eef3533c0 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1,604 +1,628 @@ array( 'Aphront400Response' => 'aphront/response/400', 'Aphront404Response' => 'aphront/response/404', 'AphrontAjaxResponse' => 'aphront/response/ajax', 'AphrontApplicationConfiguration' => 'aphront/applicationconfiguration', 'AphrontController' => 'aphront/controller', 'AphrontDatabaseConnection' => 'storage/connection/base', 'AphrontDefaultApplicationConfiguration' => 'aphront/default/configuration', 'AphrontDefaultApplicationController' => 'aphront/default/controller', 'AphrontDialogResponse' => 'aphront/response/dialog', 'AphrontDialogView' => 'view/dialog', 'AphrontErrorView' => 'view/form/error', 'AphrontException' => 'aphront/exception/base', 'AphrontFileResponse' => 'aphront/response/file', 'AphrontFormCheckboxControl' => 'view/form/control/checkbox', 'AphrontFormControl' => 'view/form/control/base', 'AphrontFormDividerControl' => 'view/form/control/divider', 'AphrontFormFileControl' => 'view/form/control/file', 'AphrontFormMarkupControl' => 'view/form/control/markup', 'AphrontFormPasswordControl' => 'view/form/control/password', 'AphrontFormRecaptchaControl' => 'view/form/control/recaptcha', 'AphrontFormSelectControl' => 'view/form/control/select', 'AphrontFormStaticControl' => 'view/form/control/static', 'AphrontFormSubmitControl' => 'view/form/control/submit', 'AphrontFormTextAreaControl' => 'view/form/control/textarea', 'AphrontFormTextControl' => 'view/form/control/text', 'AphrontFormTokenizerControl' => 'view/form/control/tokenizer', 'AphrontFormView' => 'view/form/base', 'AphrontHeadsupActionListView' => 'view/layout/headsup/actionlist', 'AphrontHeadsupActionView' => 'view/layout/headsup/action', 'AphrontMySQLDatabaseConnection' => 'storage/connection/mysql', 'AphrontNullView' => 'view/null', 'AphrontPageView' => 'view/page/base', 'AphrontPanelView' => 'view/layout/panel', 'AphrontQueryConnectionException' => 'storage/exception/connection', 'AphrontQueryConnectionLostException' => 'storage/exception/connectionlost', 'AphrontQueryCountException' => 'storage/exception/count', 'AphrontQueryDuplicateKeyException' => 'storage/exception/duplicatekey', 'AphrontQueryException' => 'storage/exception/base', 'AphrontQueryObjectMissingException' => 'storage/exception/objectmissing', 'AphrontQueryParameterException' => 'storage/exception/parameter', 'AphrontQueryRecoverableException' => 'storage/exception/recoverable', 'AphrontRedirectException' => 'aphront/exception/redirect', 'AphrontRedirectResponse' => 'aphront/response/redirect', 'AphrontRequest' => 'aphront/request', 'AphrontRequestFailureView' => 'view/page/failure', 'AphrontResponse' => 'aphront/response/base', 'AphrontSideNavView' => 'view/layout/sidenav', 'AphrontTableView' => 'view/control/table', 'AphrontURIMapper' => 'aphront/mapper', 'AphrontView' => 'view/base', 'AphrontWebpageResponse' => 'aphront/response/webpage', 'CelerityAPI' => 'infrastructure/celerity/api', 'CelerityResourceController' => 'infrastructure/celerity/controller', 'CelerityResourceMap' => 'infrastructure/celerity/map', 'CelerityStaticResourceResponse' => 'infrastructure/celerity/response', 'ConduitAPIMethod' => 'applications/conduit/method/base', 'ConduitAPIRequest' => 'applications/conduit/protocol/request', 'ConduitAPI_conduit_connect_Method' => 'applications/conduit/method/conduit/connect', 'ConduitAPI_conduit_ping_Method' => 'applications/conduit/method/conduit/ping', 'ConduitAPI_differential_creatediff_Method' => 'applications/conduit/method/differential/creatediff', 'ConduitAPI_differential_createrevision_Method' => 'applications/conduit/method/differential/createrevision', 'ConduitAPI_differential_find_Method' => 'applications/conduit/method/differential/find', 'ConduitAPI_differential_getcommitmessage_Method' => 'applications/conduit/method/differential/getcommitmessage', 'ConduitAPI_differential_getcommitpaths_Method' => 'applications/conduit/method/differential/getcommitpaths', 'ConduitAPI_differential_getdiff_Method' => 'applications/conduit/method/differential/getdiff', 'ConduitAPI_differential_markcommitted_Method' => 'applications/conduit/method/differential/markcommitted', 'ConduitAPI_differential_parsecommitmessage_Method' => 'applications/conduit/method/differential/parsecommitmessage', 'ConduitAPI_differential_setdiffproperty_Method' => 'applications/conduit/method/differential/setdiffproperty', 'ConduitAPI_differential_updaterevision_Method' => 'applications/conduit/method/differential/updaterevision', 'ConduitAPI_file_upload_Method' => 'applications/conduit/method/file/upload', 'ConduitAPI_user_find_Method' => 'applications/conduit/method/user/find', 'ConduitException' => 'applications/conduit/protocol/exception', 'DarkConsole' => 'aphront/console/api', 'DarkConsoleConfigPlugin' => 'aphront/console/plugin/config', 'DarkConsoleController' => 'aphront/console/controller', 'DarkConsoleCore' => 'aphront/console/core', 'DarkConsoleErrorLogPlugin' => 'aphront/console/plugin/errorlog', 'DarkConsoleErrorLogPluginAPI' => 'aphront/console/plugin/errorlog/api', 'DarkConsolePlugin' => 'aphront/console/plugin/base', 'DarkConsoleRequestPlugin' => 'aphront/console/plugin/request', 'DarkConsoleServicesPlugin' => 'aphront/console/plugin/services', 'DarkConsoleServicesPluginAPI' => 'aphront/console/plugin/services/api', 'DarkConsoleXHProfPlugin' => 'aphront/console/plugin/xhprof', 'DarkConsoleXHProfPluginAPI' => 'aphront/console/plugin/xhprof/api', 'DifferentialAction' => 'applications/differential/constants/action', 'DifferentialAddCommentView' => 'applications/differential/view/addcomment', 'DifferentialAttachController' => 'applications/differential/controller/attach', 'DifferentialCCWelcomeMail' => 'applications/differential/mail/ccwelcome', 'DifferentialChangeType' => 'applications/differential/constants/changetype', 'DifferentialChangeset' => 'applications/differential/storage/changeset', 'DifferentialChangesetDetailView' => 'applications/differential/view/changesetdetailview', 'DifferentialChangesetListView' => 'applications/differential/view/changesetlistview', 'DifferentialChangesetParser' => 'applications/differential/parser/changeset', 'DifferentialChangesetViewController' => 'applications/differential/controller/changesetview', 'DifferentialComment' => 'applications/differential/storage/comment', 'DifferentialCommentEditor' => 'applications/differential/editor/comment', 'DifferentialCommentMail' => 'applications/differential/mail/comment', 'DifferentialCommentPreviewController' => 'applications/differential/controller/commentpreview', 'DifferentialCommentSaveController' => 'applications/differential/controller/commentsave', 'DifferentialCommitMessage' => 'applications/differential/parser/commitmessage', 'DifferentialCommitMessageData' => 'applications/differential/data/commitmessage', 'DifferentialCommitMessageParserException' => 'applications/differential/parser/commitmessage/exception', 'DifferentialController' => 'applications/differential/controller/base', 'DifferentialDAO' => 'applications/differential/storage/base', 'DifferentialDiff' => 'applications/differential/storage/diff', 'DifferentialDiffContentMail' => 'applications/differential/mail/diffcontent', 'DifferentialDiffCreateController' => 'applications/differential/controller/diffcreate', 'DifferentialDiffProperty' => 'applications/differential/storage/diffproperty', 'DifferentialDiffTableOfContentsView' => 'applications/differential/view/difftableofcontents', 'DifferentialDiffViewController' => 'applications/differential/controller/diffview', 'DifferentialHunk' => 'applications/differential/storage/hunk', 'DifferentialInlineComment' => 'applications/differential/storage/inlinecomment', 'DifferentialInlineCommentEditController' => 'applications/differential/controller/inlinecommentedit', 'DifferentialInlineCommentPreviewController' => 'applications/differential/controller/inlinecommentpreview', 'DifferentialInlineCommentView' => 'applications/differential/view/inlinecomment', 'DifferentialLintStatus' => 'applications/differential/constants/lintstatus', 'DifferentialMail' => 'applications/differential/mail/base', 'DifferentialMarkupEngineFactory' => 'applications/differential/parser/markup', 'DifferentialNewDiffMail' => 'applications/differential/mail/newdiff', 'DifferentialReviewRequestMail' => 'applications/differential/mail/reviewrequest', 'DifferentialRevision' => 'applications/differential/storage/revision', 'DifferentialRevisionCommentListView' => 'applications/differential/view/revisioncommentlist', 'DifferentialRevisionCommentView' => 'applications/differential/view/revisioncomment', 'DifferentialRevisionControlSystem' => 'applications/differential/constants/revisioncontrolsystem', 'DifferentialRevisionDetailView' => 'applications/differential/view/revisiondetail', 'DifferentialRevisionEditController' => 'applications/differential/controller/revisionedit', 'DifferentialRevisionEditor' => 'applications/differential/editor/revision', 'DifferentialRevisionListController' => 'applications/differential/controller/revisionlist', 'DifferentialRevisionListData' => 'applications/differential/data/revisionlist', 'DifferentialRevisionStatus' => 'applications/differential/constants/revisionstatus', 'DifferentialRevisionUpdateHistoryView' => 'applications/differential/view/revisionupdatehistory', 'DifferentialRevisionViewController' => 'applications/differential/controller/revisionview', 'DifferentialSubscribeController' => 'applications/differential/controller/subscribe', 'DifferentialUnitStatus' => 'applications/differential/constants/unitstatus', 'DiffusionBrowseController' => 'applications/diffusion/controller/browse', 'DiffusionBrowseFileController' => 'applications/diffusion/controller/file', 'DiffusionBrowseQuery' => 'applications/diffusion/query/browse/base', 'DiffusionBrowseTableView' => 'applications/diffusion/view/browsetable', + 'DiffusionCommitChangeTableView' => 'applications/diffusion/view/commitchangetable', + 'DiffusionCommitController' => 'applications/diffusion/controller/commit', 'DiffusionController' => 'applications/diffusion/controller/base', 'DiffusionFileContent' => 'applications/diffusion/data/filecontent', 'DiffusionFileContentQuery' => 'applications/diffusion/query/filecontent/base', 'DiffusionGitBrowseQuery' => 'applications/diffusion/query/browse/git', 'DiffusionGitFileContentQuery' => 'applications/diffusion/query/filecontent/git', 'DiffusionGitHistoryQuery' => 'applications/diffusion/query/history/git', 'DiffusionGitRequest' => 'applications/diffusion/request/git', 'DiffusionHistoryController' => 'applications/diffusion/controller/history', 'DiffusionHistoryQuery' => 'applications/diffusion/query/history/base', 'DiffusionHistoryTableView' => 'applications/diffusion/view/historytable', 'DiffusionHomeController' => 'applications/diffusion/controller/home', 'DiffusionPathChange' => 'applications/diffusion/data/pathchange', 'DiffusionRepositoryPath' => 'applications/diffusion/data/repositorypath', 'DiffusionRequest' => 'applications/diffusion/request/base', 'Javelin' => 'infrastructure/javelin/api', 'LiskDAO' => 'storage/lisk/dao', 'ManiphestController' => 'applications/maniphest/controller/base', 'ManiphestDAO' => 'applications/maniphest/storage/base', 'ManiphestTask' => 'applications/maniphest/storage/task', 'ManiphestTaskDetailController' => 'applications/maniphest/controller/taskdetail', 'ManiphestTaskEditController' => 'applications/maniphest/controller/taskedit', 'ManiphestTaskListController' => 'applications/maniphest/controller/tasklist', 'ManiphestTaskListView' => 'applications/maniphest/view/tasklist', 'ManiphestTaskPriority' => 'applications/maniphest/constants/priority', 'ManiphestTaskSelectorSearchController' => 'applications/maniphest/controller/taskselectorsearch', 'ManiphestTaskStatus' => 'applications/maniphest/constants/status', 'ManiphestTaskSummaryView' => 'applications/maniphest/view/tasksummary', 'ManiphestTransaction' => 'applications/maniphest/storage/transaction', 'ManiphestTransactionDetailView' => 'applications/maniphest/view/transactiondetail', 'ManiphestTransactionEditor' => 'applications/maniphest/editor/transaction', 'ManiphestTransactionListView' => 'applications/maniphest/view/transactionlist', 'ManiphestTransactionSaveController' => 'applications/maniphest/controller/transactionsave', 'ManiphestTransactionType' => 'applications/maniphest/constants/transactiontype', 'Phabricator404Controller' => 'applications/base/controller/404', 'PhabricatorAuthController' => 'applications/auth/controller/base', 'PhabricatorConduitAPIController' => 'applications/conduit/controller/api', 'PhabricatorConduitConnectionLog' => 'applications/conduit/storage/connectionlog', 'PhabricatorConduitConsoleController' => 'applications/conduit/controller/console', 'PhabricatorConduitController' => 'applications/conduit/controller/base', 'PhabricatorConduitDAO' => 'applications/conduit/storage/base', 'PhabricatorConduitLogController' => 'applications/conduit/controller/log', 'PhabricatorConduitMethodCallLog' => 'applications/conduit/storage/methodcalllog', 'PhabricatorController' => 'applications/base/controller/base', 'PhabricatorDaemon' => 'infrastructure/daemon/base', 'PhabricatorDaemonConsoleController' => 'applications/daemon/controller/console', 'PhabricatorDaemonController' => 'applications/daemon/controller/base', + 'PhabricatorDaemonTimelineConsoleController' => 'applications/daemon/controller/timeline', + 'PhabricatorDaemonTimelineEventController' => 'applications/daemon/controller/timelineevent', 'PhabricatorDirectoryCategory' => 'applications/directory/storage/category', 'PhabricatorDirectoryCategoryDeleteController' => 'applications/directory/controller/categorydelete', 'PhabricatorDirectoryCategoryEditController' => 'applications/directory/controller/categoryedit', 'PhabricatorDirectoryCategoryListController' => 'applications/directory/controller/categorylist', 'PhabricatorDirectoryController' => 'applications/directory/controller/base', 'PhabricatorDirectoryDAO' => 'applications/directory/storage/base', 'PhabricatorDirectoryItem' => 'applications/directory/storage/item', 'PhabricatorDirectoryItemDeleteController' => 'applications/directory/controller/itemdelete', 'PhabricatorDirectoryItemEditController' => 'applications/directory/controller/itemedit', 'PhabricatorDirectoryItemListController' => 'applications/directory/controller/itemlist', 'PhabricatorDirectoryMainController' => 'applications/directory/controller/main', 'PhabricatorDraft' => 'applications/draft/storage/draft', 'PhabricatorDraftDAO' => 'applications/draft/storage/base', 'PhabricatorEmailLoginController' => 'applications/auth/controller/email', 'PhabricatorEmailTokenController' => 'applications/auth/controller/emailtoken', 'PhabricatorEnv' => 'infrastructure/env', 'PhabricatorFile' => 'applications/files/storage/file', 'PhabricatorFileController' => 'applications/files/controller/base', 'PhabricatorFileDAO' => 'applications/files/storage/base', 'PhabricatorFileListController' => 'applications/files/controller/list', 'PhabricatorFileStorageBlob' => 'applications/files/storage/storageblob', 'PhabricatorFileURI' => 'applications/files/uri', 'PhabricatorFileUploadController' => 'applications/files/controller/upload', 'PhabricatorFileViewController' => 'applications/files/controller/view', 'PhabricatorGoodForNothingWorker' => 'infrastructure/daemon/workers/worker/goodfornothing', 'PhabricatorHandleObjectSelectorDataView' => 'applications/phid/handle/view/selector', 'PhabricatorLiskDAO' => 'applications/base/storage/lisk', 'PhabricatorLoginController' => 'applications/auth/controller/login', 'PhabricatorLogoutController' => 'applications/auth/controller/logout', 'PhabricatorMailImplementationAdapter' => 'applications/metamta/adapter/base', 'PhabricatorMailImplementationAmazonSESAdapter' => 'applications/metamta/adapter/amazonses', 'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'applications/metamta/adapter/phpmailerlite', 'PhabricatorMetaMTAController' => 'applications/metamta/controller/base', 'PhabricatorMetaMTADAO' => 'applications/metamta/storage/base', 'PhabricatorMetaMTADaemon' => 'applications/metamta/daemon/mta', 'PhabricatorMetaMTAListController' => 'applications/metamta/controller/list', 'PhabricatorMetaMTAMail' => 'applications/metamta/storage/mail', 'PhabricatorMetaMTAMailingList' => 'applications/metamta/storage/mailinglist', 'PhabricatorMetaMTAMailingListEditController' => 'applications/metamta/controller/mailinglistedit', 'PhabricatorMetaMTAMailingListsController' => 'applications/metamta/controller/mailinglists', 'PhabricatorMetaMTASendController' => 'applications/metamta/controller/send', 'PhabricatorMetaMTAViewController' => 'applications/metamta/controller/view', 'PhabricatorOAuthDefaultRegistrationController' => 'applications/auth/controller/oauthregistration/default', 'PhabricatorOAuthDiagnosticsController' => 'applications/auth/controller/oauthdiagnostics', 'PhabricatorOAuthFailureView' => 'applications/auth/view/oauthfailure', 'PhabricatorOAuthLoginController' => 'applications/auth/controller/oauth', 'PhabricatorOAuthProvider' => 'applications/auth/oauth/provider/base', 'PhabricatorOAuthProviderFacebook' => 'applications/auth/oauth/provider/facebook', 'PhabricatorOAuthProviderGithub' => 'applications/auth/oauth/provider/github', 'PhabricatorOAuthRegistrationController' => 'applications/auth/controller/oauthregistration/base', 'PhabricatorOAuthUnlinkController' => 'applications/auth/controller/unlink', 'PhabricatorObjectHandle' => 'applications/phid/handle', 'PhabricatorObjectHandleData' => 'applications/phid/handle/data', 'PhabricatorObjectSelectorDialog' => 'view/control/objectselector', 'PhabricatorPHID' => 'applications/phid/storage/phid', 'PhabricatorPHIDAllocateController' => 'applications/phid/controller/allocate', 'PhabricatorPHIDConstants' => 'applications/phid/constants', 'PhabricatorPHIDController' => 'applications/phid/controller/base', 'PhabricatorPHIDDAO' => 'applications/phid/storage/base', 'PhabricatorPHIDListController' => 'applications/phid/controller/list', 'PhabricatorPHIDLookupController' => 'applications/phid/controller/lookup', 'PhabricatorPHIDType' => 'applications/phid/storage/type', 'PhabricatorPHIDTypeEditController' => 'applications/phid/controller/typeedit', 'PhabricatorPHIDTypeListController' => 'applications/phid/controller/typelist', 'PhabricatorPeopleController' => 'applications/people/controller/base', 'PhabricatorPeopleEditController' => 'applications/people/controller/edit', 'PhabricatorPeopleListController' => 'applications/people/controller/list', 'PhabricatorPeopleProfileController' => 'applications/people/controller/profile', 'PhabricatorPeopleProfileEditController' => 'applications/people/controller/profileedit', 'PhabricatorProject' => 'applications/project/storage/project', 'PhabricatorProjectAffiliation' => 'applications/project/storage/affiliation', 'PhabricatorProjectAffiliationEditController' => 'applications/project/controller/editaffiliation', 'PhabricatorProjectController' => 'applications/project/controller/base', 'PhabricatorProjectDAO' => 'applications/project/storage/base', 'PhabricatorProjectEditController' => 'applications/project/controller/edit', 'PhabricatorProjectListController' => 'applications/project/controller/list', 'PhabricatorProjectProfile' => 'applications/project/storage/profile', 'PhabricatorProjectProfileController' => 'applications/project/controller/profile', 'PhabricatorRemarkupRuleDifferential' => 'infrastructure/markup/remarkup/markuprule/differential', 'PhabricatorRemarkupRuleManiphest' => 'infrastructure/markup/remarkup/markuprule/maniphest', 'PhabricatorRepository' => 'applications/repository/storage/repository', 'PhabricatorRepositoryCommit' => 'applications/repository/storage/commit', + 'PhabricatorRepositoryCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/base', + 'PhabricatorRepositoryCommitData' => 'applications/repository/storage/commitdata', 'PhabricatorRepositoryCommitDiscoveryDaemon' => 'applications/repository/daemon/commitdiscovery/base', - 'PhabricatorRepositoryCommitParserDaemon' => 'applications/repository/daemon/commitparser', + 'PhabricatorRepositoryCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/base', + 'PhabricatorRepositoryCommitParserWorker' => 'applications/repository/worker/base', + 'PhabricatorRepositoryCommitTaskDaemon' => 'applications/repository/daemon/committask', 'PhabricatorRepositoryController' => 'applications/repository/controller/base', 'PhabricatorRepositoryCreateController' => 'applications/repository/controller/create', 'PhabricatorRepositoryDAO' => 'applications/repository/storage/base', 'PhabricatorRepositoryDaemon' => 'applications/repository/daemon/base', 'PhabricatorRepositoryEditController' => 'applications/repository/controller/edit', + 'PhabricatorRepositoryGitCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/git', 'PhabricatorRepositoryGitCommitDiscoveryDaemon' => 'applications/repository/daemon/commitdiscovery/git', + 'PhabricatorRepositoryGitCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/git', 'PhabricatorRepositoryGitHubNotification' => 'applications/repository/storage/githubnotification', 'PhabricatorRepositoryGitHubPostReceiveController' => 'applications/repository/controller/github-post-receive', 'PhabricatorRepositoryGitPullDaemon' => 'applications/repository/daemon/gitpull', 'PhabricatorRepositoryListController' => 'applications/repository/controller/list', + 'PhabricatorRepositorySvnCommitDiscoveryDaemon' => 'applications/repository/daemon/commitdiscovery/svn', + 'PhabricatorRepositorySvnCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/svn', 'PhabricatorRepositoryType' => 'applications/repository/constants/repositorytype', 'PhabricatorSearchAbstractDocument' => 'applications/search/index/abstractdocument', 'PhabricatorSearchBaseController' => 'applications/search/controller/base', 'PhabricatorSearchController' => 'applications/search/controller/search', 'PhabricatorSearchDAO' => 'applications/search/storage/base', 'PhabricatorSearchDifferentialIndexer' => 'applications/search/index/indexer/differential', 'PhabricatorSearchDocument' => 'applications/search/storage/document/document', 'PhabricatorSearchDocumentField' => 'applications/search/storage/document/field', 'PhabricatorSearchDocumentIndexer' => 'applications/search/index/indexer/base', 'PhabricatorSearchDocumentRelationship' => 'applications/search/storage/document/relationship', 'PhabricatorSearchExecutor' => 'applications/search/execute/base', 'PhabricatorSearchField' => 'applications/search/constants/field', 'PhabricatorSearchManiphestIndexer' => 'applications/search/index/indexer/maniphest', 'PhabricatorSearchMySQLExecutor' => 'applications/search/execute/mysql', 'PhabricatorSearchQuery' => 'applications/search/storage/query', 'PhabricatorSearchRelationship' => 'applications/search/constants/relationship', 'PhabricatorStandardPageView' => 'view/page/standard', 'PhabricatorTaskmasterDaemon' => 'infrastructure/daemon/workers/taskmaster', 'PhabricatorTimelineCursor' => 'infrastructure/daemon/timeline/storage/cursor', 'PhabricatorTimelineDAO' => 'infrastructure/daemon/timeline/storage/base', 'PhabricatorTimelineEvent' => 'infrastructure/daemon/timeline/storage/event', 'PhabricatorTimelineEventData' => 'infrastructure/daemon/timeline/storage/eventdata', 'PhabricatorTimelineIterator' => 'infrastructure/daemon/timeline/cursor/iterator', 'PhabricatorTypeaheadCommonDatasourceController' => 'applications/typeahead/controller/common', 'PhabricatorTypeaheadDatasourceController' => 'applications/typeahead/controller/base', 'PhabricatorUser' => 'applications/people/storage/user', 'PhabricatorUserDAO' => 'applications/people/storage/base', 'PhabricatorUserOAuthInfo' => 'applications/people/storage/useroauthinfo', 'PhabricatorUserProfile' => 'applications/people/storage/profile', 'PhabricatorUserSettingsController' => 'applications/people/controller/settings', 'PhabricatorWorker' => 'infrastructure/daemon/workers/worker', 'PhabricatorWorkerDAO' => 'infrastructure/daemon/workers/storage/base', 'PhabricatorWorkerTask' => 'infrastructure/daemon/workers/storage/task', 'PhabricatorWorkerTaskData' => 'infrastructure/daemon/workers/storage/taskdata', 'PhabricatorXHProfController' => 'applications/xhprof/controller/base', 'PhabricatorXHProfProfileController' => 'applications/xhprof/controller/profile', 'PhabricatorXHProfProfileSymbolView' => 'applications/xhprof/view/symbol', 'PhabricatorXHProfProfileTopLevelView' => 'applications/xhprof/view/toplevel', ), 'function' => array( '_qsprintf_check_scalar_type' => 'storage/qsprintf', '_qsprintf_check_type' => 'storage/qsprintf', 'celerity_generate_unique_node_id' => 'infrastructure/celerity/api', 'celerity_register_resource_map' => 'infrastructure/celerity/map', 'javelin_render_tag' => 'infrastructure/javelin/markup', 'phabricator_format_relative_time' => 'view/utils', 'phabricator_format_timestamp' => 'view/utils', 'phabricator_format_units_generic' => 'view/utils', 'phabricator_render_form' => 'infrastructure/javelin/markup', 'qsprintf' => 'storage/qsprintf', 'queryfx' => 'storage/queryfx', 'queryfx_all' => 'storage/queryfx', 'queryfx_one' => 'storage/queryfx', 'require_celerity_resource' => 'infrastructure/celerity/api', 'vqsprintf' => 'storage/qsprintf', 'vqueryfx' => 'storage/queryfx', 'vqueryfx_all' => 'storage/queryfx', 'xsprintf_query' => 'storage/qsprintf', ), 'requires_class' => array( 'Aphront400Response' => 'AphrontResponse', 'Aphront404Response' => 'AphrontResponse', 'AphrontAjaxResponse' => 'AphrontResponse', 'AphrontDefaultApplicationConfiguration' => 'AphrontApplicationConfiguration', 'AphrontDefaultApplicationController' => 'AphrontController', 'AphrontDialogResponse' => 'AphrontResponse', 'AphrontDialogView' => 'AphrontView', 'AphrontErrorView' => 'AphrontView', 'AphrontFileResponse' => 'AphrontResponse', 'AphrontFormCheckboxControl' => 'AphrontFormControl', 'AphrontFormControl' => 'AphrontView', 'AphrontFormDividerControl' => 'AphrontFormControl', 'AphrontFormFileControl' => 'AphrontFormControl', 'AphrontFormMarkupControl' => 'AphrontFormControl', 'AphrontFormPasswordControl' => 'AphrontFormControl', 'AphrontFormRecaptchaControl' => 'AphrontFormControl', 'AphrontFormSelectControl' => 'AphrontFormControl', 'AphrontFormStaticControl' => 'AphrontFormControl', 'AphrontFormSubmitControl' => 'AphrontFormControl', 'AphrontFormTextAreaControl' => 'AphrontFormControl', 'AphrontFormTextControl' => 'AphrontFormControl', 'AphrontFormTokenizerControl' => 'AphrontFormControl', 'AphrontFormView' => 'AphrontView', 'AphrontHeadsupActionListView' => 'AphrontView', 'AphrontHeadsupActionView' => 'AphrontView', 'AphrontMySQLDatabaseConnection' => 'AphrontDatabaseConnection', 'AphrontNullView' => 'AphrontView', 'AphrontPageView' => 'AphrontView', 'AphrontPanelView' => 'AphrontView', 'AphrontQueryConnectionException' => 'AphrontQueryException', 'AphrontQueryConnectionLostException' => 'AphrontQueryRecoverableException', 'AphrontQueryCountException' => 'AphrontQueryException', 'AphrontQueryDuplicateKeyException' => 'AphrontQueryException', 'AphrontQueryObjectMissingException' => 'AphrontQueryException', 'AphrontQueryParameterException' => 'AphrontQueryException', 'AphrontQueryRecoverableException' => 'AphrontQueryException', 'AphrontRedirectException' => 'AphrontException', 'AphrontRedirectResponse' => 'AphrontResponse', 'AphrontRequestFailureView' => 'AphrontView', 'AphrontSideNavView' => 'AphrontView', 'AphrontTableView' => 'AphrontView', 'AphrontWebpageResponse' => 'AphrontResponse', 'CelerityResourceController' => 'AphrontController', 'ConduitAPI_conduit_connect_Method' => 'ConduitAPIMethod', 'ConduitAPI_conduit_ping_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_creatediff_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_createrevision_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_find_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_getcommitmessage_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_getcommitpaths_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_getdiff_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_markcommitted_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_parsecommitmessage_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_setdiffproperty_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_updaterevision_Method' => 'ConduitAPIMethod', 'ConduitAPI_file_upload_Method' => 'ConduitAPIMethod', 'ConduitAPI_user_find_Method' => 'ConduitAPIMethod', 'DarkConsoleConfigPlugin' => 'DarkConsolePlugin', 'DarkConsoleController' => 'PhabricatorController', 'DarkConsoleErrorLogPlugin' => 'DarkConsolePlugin', 'DarkConsoleRequestPlugin' => 'DarkConsolePlugin', 'DarkConsoleServicesPlugin' => 'DarkConsolePlugin', 'DarkConsoleXHProfPlugin' => 'DarkConsolePlugin', 'DifferentialAddCommentView' => 'AphrontView', 'DifferentialAttachController' => 'DifferentialController', 'DifferentialCCWelcomeMail' => 'DifferentialReviewRequestMail', 'DifferentialChangeset' => 'DifferentialDAO', 'DifferentialChangesetDetailView' => 'AphrontView', 'DifferentialChangesetListView' => 'AphrontView', 'DifferentialChangesetViewController' => 'DifferentialController', 'DifferentialComment' => 'DifferentialDAO', 'DifferentialCommentMail' => 'DifferentialMail', 'DifferentialCommentPreviewController' => 'DifferentialController', 'DifferentialCommentSaveController' => 'DifferentialController', 'DifferentialController' => 'PhabricatorController', 'DifferentialDAO' => 'PhabricatorLiskDAO', 'DifferentialDiff' => 'DifferentialDAO', 'DifferentialDiffContentMail' => 'DifferentialMail', 'DifferentialDiffCreateController' => 'DifferentialController', 'DifferentialDiffProperty' => 'DifferentialDAO', 'DifferentialDiffTableOfContentsView' => 'AphrontView', 'DifferentialDiffViewController' => 'DifferentialController', 'DifferentialHunk' => 'DifferentialDAO', 'DifferentialInlineComment' => 'DifferentialDAO', 'DifferentialInlineCommentEditController' => 'DifferentialController', 'DifferentialInlineCommentPreviewController' => 'DifferentialController', 'DifferentialInlineCommentView' => 'AphrontView', 'DifferentialNewDiffMail' => 'DifferentialReviewRequestMail', 'DifferentialReviewRequestMail' => 'DifferentialMail', 'DifferentialRevision' => 'DifferentialDAO', 'DifferentialRevisionCommentListView' => 'AphrontView', 'DifferentialRevisionCommentView' => 'AphrontView', 'DifferentialRevisionDetailView' => 'AphrontView', 'DifferentialRevisionEditController' => 'DifferentialController', 'DifferentialRevisionListController' => 'DifferentialController', 'DifferentialRevisionUpdateHistoryView' => 'AphrontView', 'DifferentialRevisionViewController' => 'DifferentialController', 'DifferentialSubscribeController' => 'DifferentialController', 'DiffusionBrowseController' => 'DiffusionController', 'DiffusionBrowseFileController' => 'DiffusionController', 'DiffusionBrowseTableView' => 'AphrontView', + 'DiffusionCommitChangeTableView' => 'AphrontView', + 'DiffusionCommitController' => 'DiffusionController', 'DiffusionController' => 'PhabricatorController', 'DiffusionGitBrowseQuery' => 'DiffusionBrowseQuery', 'DiffusionGitFileContentQuery' => 'DiffusionFileContentQuery', 'DiffusionGitHistoryQuery' => 'DiffusionHistoryQuery', 'DiffusionGitRequest' => 'DiffusionRequest', 'DiffusionHistoryController' => 'DiffusionController', 'DiffusionHistoryTableView' => 'AphrontView', 'DiffusionHomeController' => 'DiffusionController', 'ManiphestController' => 'PhabricatorController', 'ManiphestDAO' => 'PhabricatorLiskDAO', 'ManiphestTask' => 'ManiphestDAO', 'ManiphestTaskDetailController' => 'ManiphestController', 'ManiphestTaskEditController' => 'ManiphestController', 'ManiphestTaskListController' => 'ManiphestController', 'ManiphestTaskListView' => 'AphrontView', 'ManiphestTaskSelectorSearchController' => 'ManiphestController', 'ManiphestTaskSummaryView' => 'AphrontView', 'ManiphestTransaction' => 'ManiphestDAO', 'ManiphestTransactionDetailView' => 'AphrontView', 'ManiphestTransactionListView' => 'AphrontView', 'ManiphestTransactionSaveController' => 'ManiphestController', 'Phabricator404Controller' => 'PhabricatorController', 'PhabricatorAuthController' => 'PhabricatorController', 'PhabricatorConduitAPIController' => 'PhabricatorConduitController', 'PhabricatorConduitConnectionLog' => 'PhabricatorConduitDAO', 'PhabricatorConduitConsoleController' => 'PhabricatorConduitController', 'PhabricatorConduitController' => 'PhabricatorController', 'PhabricatorConduitDAO' => 'PhabricatorLiskDAO', 'PhabricatorConduitLogController' => 'PhabricatorConduitController', 'PhabricatorConduitMethodCallLog' => 'PhabricatorConduitDAO', 'PhabricatorController' => 'AphrontController', 'PhabricatorDaemon' => 'PhutilDaemon', 'PhabricatorDaemonConsoleController' => 'PhabricatorDaemonController', 'PhabricatorDaemonController' => 'PhabricatorController', + 'PhabricatorDaemonTimelineConsoleController' => 'PhabricatorDaemonController', + 'PhabricatorDaemonTimelineEventController' => 'PhabricatorDaemonController', 'PhabricatorDirectoryCategory' => 'PhabricatorDirectoryDAO', 'PhabricatorDirectoryCategoryDeleteController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryCategoryEditController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryCategoryListController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryController' => 'PhabricatorController', 'PhabricatorDirectoryDAO' => 'PhabricatorLiskDAO', 'PhabricatorDirectoryItem' => 'PhabricatorDirectoryDAO', 'PhabricatorDirectoryItemDeleteController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryItemEditController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryItemListController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryMainController' => 'PhabricatorDirectoryController', 'PhabricatorDraft' => 'PhabricatorDraftDAO', 'PhabricatorDraftDAO' => 'PhabricatorLiskDAO', 'PhabricatorEmailLoginController' => 'PhabricatorAuthController', 'PhabricatorEmailTokenController' => 'PhabricatorAuthController', 'PhabricatorFile' => 'PhabricatorFileDAO', 'PhabricatorFileController' => 'PhabricatorController', 'PhabricatorFileDAO' => 'PhabricatorLiskDAO', 'PhabricatorFileListController' => 'PhabricatorFileController', 'PhabricatorFileStorageBlob' => 'PhabricatorFileDAO', 'PhabricatorFileUploadController' => 'PhabricatorFileController', 'PhabricatorFileViewController' => 'PhabricatorFileController', 'PhabricatorGoodForNothingWorker' => 'PhabricatorWorker', 'PhabricatorLiskDAO' => 'LiskDAO', 'PhabricatorLoginController' => 'PhabricatorAuthController', 'PhabricatorLogoutController' => 'PhabricatorAuthController', 'PhabricatorMailImplementationAmazonSESAdapter' => 'PhabricatorMailImplementationPHPMailerLiteAdapter', 'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'PhabricatorMailImplementationAdapter', 'PhabricatorMetaMTAController' => 'PhabricatorController', 'PhabricatorMetaMTADAO' => 'PhabricatorLiskDAO', 'PhabricatorMetaMTAListController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAMail' => 'PhabricatorMetaMTADAO', 'PhabricatorMetaMTAMailingList' => 'PhabricatorMetaMTADAO', 'PhabricatorMetaMTAMailingListEditController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAMailingListsController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTASendController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAViewController' => 'PhabricatorMetaMTAController', 'PhabricatorOAuthDefaultRegistrationController' => 'PhabricatorOAuthRegistrationController', 'PhabricatorOAuthDiagnosticsController' => 'PhabricatorAuthController', 'PhabricatorOAuthFailureView' => 'AphrontView', 'PhabricatorOAuthLoginController' => 'PhabricatorAuthController', 'PhabricatorOAuthProviderFacebook' => 'PhabricatorOAuthProvider', 'PhabricatorOAuthProviderGithub' => 'PhabricatorOAuthProvider', 'PhabricatorOAuthRegistrationController' => 'PhabricatorAuthController', 'PhabricatorOAuthUnlinkController' => 'PhabricatorAuthController', 'PhabricatorPHID' => 'PhabricatorPHIDDAO', 'PhabricatorPHIDAllocateController' => 'PhabricatorPHIDController', 'PhabricatorPHIDController' => 'PhabricatorController', 'PhabricatorPHIDDAO' => 'PhabricatorLiskDAO', 'PhabricatorPHIDListController' => 'PhabricatorPHIDController', 'PhabricatorPHIDLookupController' => 'PhabricatorPHIDController', 'PhabricatorPHIDType' => 'PhabricatorPHIDDAO', 'PhabricatorPHIDTypeEditController' => 'PhabricatorPHIDController', 'PhabricatorPHIDTypeListController' => 'PhabricatorPHIDController', 'PhabricatorPeopleController' => 'PhabricatorController', 'PhabricatorPeopleEditController' => 'PhabricatorPeopleController', 'PhabricatorPeopleListController' => 'PhabricatorPeopleController', 'PhabricatorPeopleProfileController' => 'PhabricatorPeopleController', 'PhabricatorPeopleProfileEditController' => 'PhabricatorPeopleController', 'PhabricatorProject' => 'PhabricatorProjectDAO', 'PhabricatorProjectAffiliation' => 'PhabricatorProjectDAO', 'PhabricatorProjectAffiliationEditController' => 'PhabricatorProjectController', 'PhabricatorProjectController' => 'PhabricatorController', 'PhabricatorProjectDAO' => 'PhabricatorLiskDAO', 'PhabricatorProjectEditController' => 'PhabricatorProjectController', 'PhabricatorProjectListController' => 'PhabricatorProjectController', 'PhabricatorProjectProfile' => 'PhabricatorProjectDAO', 'PhabricatorProjectProfileController' => 'PhabricatorProjectController', 'PhabricatorRemarkupRuleDifferential' => 'PhutilRemarkupRule', 'PhabricatorRemarkupRuleManiphest' => 'PhutilRemarkupRule', 'PhabricatorRepository' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositoryCommit' => 'PhabricatorRepositoryDAO', + 'PhabricatorRepositoryCommitChangeParserWorker' => 'PhabricatorRepositoryCommitParserWorker', + 'PhabricatorRepositoryCommitData' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositoryCommitDiscoveryDaemon' => 'PhabricatorRepositoryDaemon', - 'PhabricatorRepositoryCommitParserDaemon' => 'PhabricatorRepositoryDaemon', + 'PhabricatorRepositoryCommitMessageParserWorker' => 'PhabricatorRepositoryCommitParserWorker', + 'PhabricatorRepositoryCommitParserWorker' => 'PhabricatorWorker', + 'PhabricatorRepositoryCommitTaskDaemon' => 'PhabricatorRepositoryDaemon', 'PhabricatorRepositoryController' => 'PhabricatorController', 'PhabricatorRepositoryCreateController' => 'PhabricatorController', 'PhabricatorRepositoryDAO' => 'PhabricatorLiskDAO', 'PhabricatorRepositoryDaemon' => 'PhabricatorDaemon', 'PhabricatorRepositoryEditController' => 'PhabricatorController', + 'PhabricatorRepositoryGitCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker', 'PhabricatorRepositoryGitCommitDiscoveryDaemon' => 'PhabricatorRepositoryCommitDiscoveryDaemon', + 'PhabricatorRepositoryGitCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker', 'PhabricatorRepositoryGitHubNotification' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositoryGitHubPostReceiveController' => 'PhabricatorRepositoryController', 'PhabricatorRepositoryGitPullDaemon' => 'PhabricatorRepositoryDaemon', 'PhabricatorRepositoryListController' => 'PhabricatorController', + 'PhabricatorRepositorySvnCommitDiscoveryDaemon' => 'PhabricatorRepositoryCommitDiscoveryDaemon', + 'PhabricatorRepositorySvnCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker', 'PhabricatorSearchBaseController' => 'PhabricatorController', 'PhabricatorSearchController' => 'PhabricatorSearchBaseController', 'PhabricatorSearchDAO' => 'PhabricatorLiskDAO', 'PhabricatorSearchDifferentialIndexer' => 'PhabricatorSearchDocumentIndexer', 'PhabricatorSearchDocument' => 'PhabricatorSearchDAO', 'PhabricatorSearchDocumentField' => 'PhabricatorSearchDAO', 'PhabricatorSearchDocumentRelationship' => 'PhabricatorSearchDAO', 'PhabricatorSearchManiphestIndexer' => 'PhabricatorSearchDocumentIndexer', 'PhabricatorSearchMySQLExecutor' => 'PhabricatorSearchExecutor', 'PhabricatorSearchQuery' => 'PhabricatorSearchDAO', 'PhabricatorStandardPageView' => 'AphrontPageView', 'PhabricatorTaskmasterDaemon' => 'PhabricatorDaemon', 'PhabricatorTimelineCursor' => 'PhabricatorTimelineDAO', 'PhabricatorTimelineDAO' => 'PhabricatorLiskDAO', 'PhabricatorTimelineEvent' => 'PhabricatorTimelineDAO', 'PhabricatorTimelineEventData' => 'PhabricatorTimelineDAO', 'PhabricatorTypeaheadCommonDatasourceController' => 'PhabricatorTypeaheadDatasourceController', 'PhabricatorTypeaheadDatasourceController' => 'PhabricatorController', 'PhabricatorUser' => 'PhabricatorUserDAO', 'PhabricatorUserDAO' => 'PhabricatorLiskDAO', 'PhabricatorUserOAuthInfo' => 'PhabricatorUserDAO', 'PhabricatorUserProfile' => 'PhabricatorUserDAO', 'PhabricatorUserSettingsController' => 'PhabricatorPeopleController', 'PhabricatorWorkerDAO' => 'PhabricatorLiskDAO', 'PhabricatorWorkerTask' => 'PhabricatorWorkerDAO', 'PhabricatorWorkerTaskData' => 'PhabricatorWorkerDAO', 'PhabricatorXHProfController' => 'PhabricatorController', 'PhabricatorXHProfProfileController' => 'PhabricatorXHProfController', 'PhabricatorXHProfProfileSymbolView' => 'AphrontView', 'PhabricatorXHProfProfileTopLevelView' => 'AphrontView', ), 'requires_interface' => array( ), )); diff --git a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php index 43c13010e4..aa07c7cbe1 100644 --- a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php +++ b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php @@ -1,310 +1,314 @@ getResourceURIMapRules() + array( '/' => array( '$' => 'PhabricatorDirectoryMainController', ), '/directory/' => array( 'item/$' => 'PhabricatorDirectoryItemListController', 'item/edit/(?:(?P\d+)/)?$' => 'PhabricatorDirectoryItemEditController', 'item/delete/(?P\d+)/' => 'PhabricatorDirectoryItemDeleteController', 'category/$' => 'PhabricatorDirectoryCategoryListController', 'category/edit/(?:(?P\d+)/)?$' => 'PhabricatorDirectoryCategoryEditController', 'category/delete/(?P\d+)/' => 'PhabricatorDirectoryCategoryDeleteController', ), '/file/' => array( '$' => 'PhabricatorFileListController', 'upload/$' => 'PhabricatorFileUploadController', '(?Pinfo)/(?P[^/]+)/' => 'PhabricatorFileViewController', '(?Pview)/(?P[^/]+)/' => 'PhabricatorFileViewController', '(?Pdownload)/(?P[^/]+)/' => 'PhabricatorFileViewController', ), '/phid/' => array( '$' => 'PhabricatorPHIDLookupController', 'list/$' => 'PhabricatorPHIDListController', 'type/$' => 'PhabricatorPHIDTypeListController', 'type/edit/(?:(?P\d+)/)?$' => 'PhabricatorPHIDTypeEditController', 'new/$' => 'PhabricatorPHIDAllocateController', ), '/people/' => array( '$' => 'PhabricatorPeopleListController', 'edit/(?:(?P\w+)/)?$' => 'PhabricatorPeopleEditController', ), '/p/(?P\w+)/$' => 'PhabricatorPeopleProfileController', '/profile/' => array( 'edit/$' => 'PhabricatorPeopleProfileEditController', ), '/conduit/' => array( '$' => 'PhabricatorConduitConsoleController', 'method/(?P[^/]+)$' => 'PhabricatorConduitConsoleController', 'log/$' => 'PhabricatorConduitLogController', ), '/api/(?P[^/]+)$' => 'PhabricatorConduitAPIController', '/D(?P\d+)' => 'DifferentialRevisionViewController', '/differential/' => array( '$' => 'DifferentialRevisionListController', 'filter/(?P\w+)/$' => 'DifferentialRevisionListController', 'diff/' => array( '(?P\d+)/$' => 'DifferentialDiffViewController', 'create/$' => 'DifferentialDiffCreateController', ), 'changeset/$' => 'DifferentialChangesetViewController', 'revision/edit/(?:(?P\d+)/)?$' => 'DifferentialRevisionEditController', 'comment/' => array( 'preview/(?P\d+)/$' => 'DifferentialCommentPreviewController', 'save/$' => 'DifferentialCommentSaveController', 'inline/' => array( 'preview/(?P\d+)/$' => 'DifferentialInlineCommentPreviewController', 'edit/(?P\d+)/$' => 'DifferentialInlineCommentEditController', ), ), 'attach/(?P\d+)/(?P\w+)/$' => 'DifferentialAttachController', 'subscribe/(?Padd|rem)/(?P\d+)/$' => 'DifferentialSubscribeController', ), '/typeahead/' => array( 'common/(?P\w+)/$' => 'PhabricatorTypeaheadCommonDatasourceController', ), '/mail/' => array( '$' => 'PhabricatorMetaMTAListController', 'send/$' => 'PhabricatorMetaMTASendController', 'view/(?P\d+)/$' => 'PhabricatorMetaMTAViewController', 'lists/$' => 'PhabricatorMetaMTAMailingListsController', 'lists/edit/(?:(?P\d+)/)?$' => 'PhabricatorMetaMTAMailingListEditController', ), '/login/' => array( '$' => 'PhabricatorLoginController', 'email/$' => 'PhabricatorEmailLoginController', 'etoken/(?P\w+)/$' => 'PhabricatorEmailTokenController', ), '/logout/$' => 'PhabricatorLogoutController', '/oauth/' => array( '(?Pgithub|facebook)/' => array( 'login/$' => 'PhabricatorOAuthLoginController', 'diagnose/$' => 'PhabricatorOAuthDiagnosticsController', 'unlink/$' => 'PhabricatorOAuthUnlinkController', ), ), '/xhprof/' => array( 'profile/(?P[^/]+)/$' => 'PhabricatorXHProfProfileController', ), '/~/' => 'DarkConsoleController', '/settings/' => array( '(?:page/(?P[^/]+)/)?$' => 'PhabricatorUserSettingsController', ), '/maniphest/' => array( '$' => 'ManiphestTaskListController', 'view/(?P\w+)/$' => 'ManiphestTaskListController', 'task/' => array( 'create/$' => 'ManiphestTaskEditController', 'edit/(?P\d+)/$' => 'ManiphestTaskEditController', ), 'transaction/' => array( 'save/' => 'ManiphestTransactionSaveController', ), 'select/search/$' => 'ManiphestTaskSelectorSearchController', ), '/T(?P\d+)$' => 'ManiphestTaskDetailController', '/github-post-receive/(?P\d+)/(?P[^/]+)/$' => 'PhabricatorRepositoryGitHubPostReceiveController', '/repository/' => array( '$' => 'PhabricatorRepositoryListController', 'create/$' => 'PhabricatorRepositoryCreateController', 'edit/(?P\d+)/(?:(?P\w+)?/)?$' => 'PhabricatorRepositoryEditController', 'delete/(?P\d+)/$' => 'PhabricatorRepositoryDeleteController', ), '/search/' => array( '$' => 'PhabricatorSearchController', '(?P\d+)/$' => 'PhabricatorSearchController', ), '/project/' => array( '$' => 'PhabricatorProjectListController', 'edit/(?:(?P\d+)/)?$' => 'PhabricatorProjectEditController', 'view/(?P\d+)/$' => 'PhabricatorProjectProfileController', 'affiliation/(?P\d+)/$' => 'PhabricatorProjectAffiliationEditController', ), + '/r(?P[A-Z]+)(?P[a-z0-9]+)$' + => 'DiffusionCommitController', '/diffusion/' => array( '$' => 'DiffusionHomeController', '(?P[A-Z]+)' => array( '/history/'. '(?P.*?)'. '(?:[;](?P[a-z0-9]+))?'. '$' => 'DiffusionHistoryController', '/browse/'. '(?P.*?)'. '(?:[;](?P[a-z0-9]+))?'. '(?:[$](?P\d+))?'. '$' => 'DiffusionBrowseController', ), ), '/daemon/' => array( + 'timeline/$' => 'PhabricatorDaemonTimelineConsoleController', + 'timeline/(?P\d+)/$' => 'PhabricatorDaemonTimelineEventController', '$' => 'PhabricatorDaemonConsoleController', ), ); } protected function getResourceURIMapRules() { return array( '/res/' => array( '(?Ppkg/)?(?P[a-f0-9]{8})/(?P.+\.(?:css|js))$' => 'CelerityResourceController', ), ); } public function buildRequest() { $request = new AphrontRequest($this->getHost(), $this->getPath()); $request->setRequestData($_GET + $_POST); $request->setApplicationConfiguration($this); return $request; } public function handleException(Exception $ex) { $class = phutil_escape_html(get_class($ex)); $message = phutil_escape_html($ex->getMessage()); $content = '
'. '

Unhandled Exception "'.$class.'": '.$message.'

'. ''.phutil_escape_html((string)$ex).''. '
'; $user = $this->getRequest()->getUser(); if (!$user) { // If we hit an exception very early, we won't have a user. $user = new PhabricatorUser(); } $dialog = new AphrontDialogView(); $dialog ->setTitle('Exception!') ->setClass('aphront-exception-dialog') ->setUser($user) ->appendChild($content) ->addCancelButton('/'); $response = new AphrontDialogResponse(); $response->setDialog($dialog); return $response; } public function willSendResponse(AphrontResponse $response) { $request = $this->getRequest(); if ($response instanceof AphrontDialogResponse) { if (!$request->isAjax()) { $view = new PhabricatorStandardPageView(); $view->setRequest($request); $view->appendChild( '
'. $response->buildResponseString(). '
'); $response = new AphrontWebpageResponse(); $response->setContent($view->render()); return $response; } else { return id(new AphrontAjaxResponse()) ->setContent(array( 'dialog' => $response->buildResponseString(), )); } } else if ($response instanceof AphrontRedirectResponse) { if ($request->isAjax()) { return id(new AphrontAjaxResponse()) ->setContent( array( 'redirect' => $response->getURI(), )); } } else if ($response instanceof Aphront404Response) { $failure = new AphrontRequestFailureView(); $failure->setHeader('404 Not Found'); $failure->appendChild( '

The page you requested was not found.

'); $view = new PhabricatorStandardPageView(); $view->setTitle('404 Not Found'); $view->setRequest($this->getRequest()); $view->appendChild($failure); $response = new AphrontWebpageResponse(); $response->setContent($view->render()); $response->setHTTPResponseCode(404); return $response; } return $response; } public function build404Controller() { return array(new Phabricator404Controller($this->getRequest()), array()); } } diff --git a/src/applications/daemon/controller/base/PhabricatorDaemonController.php b/src/applications/daemon/controller/base/PhabricatorDaemonController.php index 9892426fd0..c0ab524416 100644 --- a/src/applications/daemon/controller/base/PhabricatorDaemonController.php +++ b/src/applications/daemon/controller/base/PhabricatorDaemonController.php @@ -1,42 +1,46 @@ buildStandardPageView(); $page->setApplicationName('Daemon Console'); - $page->setBaseURI('/'); + $page->setBaseURI('/daemon/'); $page->setTitle(idx($data, 'title')); $page->setTabs( array( 'console' => array( 'href' => '/daemon/', 'name' => 'Console', ), + 'timeline' => array( + 'href' => '/daemon/timeline/', + 'name' => 'Timeline', + ), ), idx($data, 'tab')); $page->setGlyph("\xE2\x98\xAF"); $page->appendChild($view); $response = new AphrontWebpageResponse(); return $response->setContent($page->render()); } } diff --git a/src/applications/daemon/controller/console/PhabricatorDaemonConsoleController.php b/src/applications/daemon/controller/console/PhabricatorDaemonConsoleController.php index 9e40ae17b2..2a3a797ac7 100644 --- a/src/applications/daemon/controller/console/PhabricatorDaemonConsoleController.php +++ b/src/applications/daemon/controller/console/PhabricatorDaemonConsoleController.php @@ -1,70 +1,131 @@ getRequest(); - - if ($request->getStr('new')) { - $task = new PhabricatorWorkerTask(); - $task->setTaskClass('PhabricatorGoodForNothingWorker'); - $task->setPriority(4); - $task->setFailureCount(0); - $task->save(); - } - - $tasks = id(new PhabricatorWorkerTask()) - ->loadAll(); + $tasks = id(new PhabricatorWorkerTask())->loadAllWhere( + 'leaseOwner IS NOT NULL'); $rows = array(); foreach ($tasks as $task) { $rows[] = array( $task->getID(), $task->getTaskClass(), $task->getLeaseOwner(), - $task->getLeaseExpires(), - $task->getPriority(), + $task->getLeaseExpires() - time(), $task->getFailureCount(), ); } - $table = new AphrontTableView($rows); - $table->setHeaders( + $leased_table = new AphrontTableView($rows); + $leased_table->setHeaders( array( 'ID', 'Class', 'Owner', 'Expries', - 'Priority', + 'Failures', + )); + $leased_table->setColumnClasses( + array( + 'n', + 'wide', + '', + '', + 'n', + )); + $leased_table->setNoDataString('No tasks are leased by workers.'); + + $leased_panel = new AphrontPanelView(); + $leased_panel->setHeader('Leased Tasks'); + $leased_panel->appendChild($leased_table); + + $task_table = new PhabricatorWorkerTask(); + $queued = queryfx_all( + $task_table->establishConnection('r'), + 'SELECT taskClass, count(*) N FROM %T GROUP BY taskClass + ORDER BY N DESC', + $task_table->getTableName()); + + $rows = array(); + foreach ($queued as $row) { + $rows[] = array( + phutil_escape_html($row['taskClass']), + number_format($row['N']), + ); + } + + $queued_table = new AphrontTableView($rows); + $queued_table->setHeaders( + array( + 'Class', 'Count', )); + $queued_table->setColumnClasses( + array( + 'wide', + 'n', + )); + $queued_table->setNoDataString('Task queue is empty.'); + + $queued_panel = new AphrontPanelView(); + $queued_panel->setHeader('Queued Tasks'); + $queued_panel->appendChild($queued_table); + + $cursors = id(new PhabricatorTimelineCursor()) + ->loadAll(); + + $rows = array(); + foreach ($cursors as $cursor) { + $rows[] = array( + phutil_escape_html($cursor->getName()), + number_format($cursor->getPosition()), + ); + } + + $cursor_table = new AphrontTableView($rows); + $cursor_table->setHeaders( + array( + 'Name', + 'Position', + )); + $cursor_table->setColumnClasses( + array( + 'wide', + 'n', + )); + $cursor_table->setNoDataString('No timeline cursors exist.'); - $panel = new AphrontPanelView(); - $panel->setHeader('Tasks'); - $panel->appendChild($table); + $cursor_panel = new AphrontPanelView(); + $cursor_panel->setHeader('Timeline Cursors'); + $cursor_panel->appendChild($cursor_table); return $this->buildStandardPageResponse( - $panel, + array( + $leased_panel, + $queued_panel, + $cursor_panel, + ), array( 'title' => 'Console', 'tab' => 'console', )); } } diff --git a/src/applications/daemon/controller/console/__init__.php b/src/applications/daemon/controller/console/__init__.php index 28cdb0bf7a..c07c4dd43a 100644 --- a/src/applications/daemon/controller/console/__init__.php +++ b/src/applications/daemon/controller/console/__init__.php @@ -1,17 +1,20 @@ establishConnection('r'), + 'SELECT id, type FROM %T ORDER BY id DESC LIMIT 100', + $timeline_table->getTableName()); + + $rows = array(); + foreach ($events as $event) { + $rows[] = array( + phutil_render_tag( + 'a', + array( + 'href' => '/daemon/timeline/'.$event['id'].'/', + ), + $event['id']), + phutil_escape_html($event['type']), + ); + } + + $event_table = new AphrontTableView($rows); + $event_table->setHeaders( + array( + 'ID', + 'Type', + )); + $event_table->setColumnClasses( + array( + null, + 'wide', + )); + + $event_panel = new AphrontPanelView(); + $event_panel->setHeader('Timeline Events'); + $event_panel->appendChild($event_table); + + return $this->buildStandardPageResponse( + array( + $event_panel, + ), + array( + 'title' => 'Timeline', + 'tab' => 'timeline', + )); + } + +} diff --git a/src/applications/daemon/controller/console/__init__.php b/src/applications/daemon/controller/timeline/__init__.php similarity index 53% copy from src/applications/daemon/controller/console/__init__.php copy to src/applications/daemon/controller/timeline/__init__.php index 28cdb0bf7a..933eef2d80 100644 --- a/src/applications/daemon/controller/console/__init__.php +++ b/src/applications/daemon/controller/timeline/__init__.php @@ -1,17 +1,18 @@ id = $data['id']; + } + + public function processRequest() { + $event = id(new PhabricatorTimelineEvent('NULL'))->load($this->id); + if (!$event) { + return new Aphront404Response(); + } + + $request = $this->getRequest(); + $user = $request->getUser(); + + $data = id(new PhabricatorTimelineEventData())->loadOneWhere( + 'eventID = %d', + $event->getID()); + + if ($data) { + $data = json_encode($data->getEventData()); + } else { + $data = 'null'; + } + + $form = new AphrontFormView(); + $form + ->setUser($user) + ->appendChild( + id(new AphrontFormStaticControl()) + ->setLabel('ID') + ->setValue($event->getID())) + ->appendChild( + id(new AphrontFormStaticControl()) + ->setLabel('Type') + ->setValue($event->getType())) + ->appendChild( + id(new AphrontFormTextAreaControl()) + ->setDisabled(true) + ->setLabel('Data') + ->setValue($data)) + ->appendChild( + id(new AphrontFormSubmitControl()) + ->addCancelButton('/daemon/timeline/')); + + $panel = new AphrontPanelView(); + $panel->setHeader('Event'); + $panel->setWidth(AphrontPanelView::WIDTH_FORM); + $panel->appendChild($form); + + return $this->buildStandardPageResponse( + $panel, + array( + 'title' => 'Timeline Event', + )); + } + +} diff --git a/src/applications/daemon/controller/timelineevent/__init__.php b/src/applications/daemon/controller/timelineevent/__init__.php new file mode 100644 index 0000000000..5423d87959 --- /dev/null +++ b/src/applications/daemon/controller/timelineevent/__init__.php @@ -0,0 +1,20 @@ +diffusionRequest; + + + + + $detail_panel = new AphrontPanelView(); + $detail_panel->setHeader('Revision Detail'); + $detail_panel->appendChild('
'.$drequest->getCommit().'
'); + + $change_table = new DiffusionCommitChangeTableView(); + $change_table->setDiffusionRequest($drequest); + $change_table->setPathChanges(array()); + + $change_panel = new AphrontPanelView(); + $change_panel->setHeader('Changes'); + $change_panel->appendChild($change_table); + + $change_list = + '
'. + '(list of changes goes here)'. + '
'; + + return $this->buildStandardPageResponse( + array( + $detail_panel, + $change_panel, + $change_list, + ), + array( + 'title' => 'Diffusion', + )); + } + +} diff --git a/src/applications/diffusion/controller/commit/__init__.php b/src/applications/diffusion/controller/commit/__init__.php new file mode 100644 index 0000000000..8d10609002 --- /dev/null +++ b/src/applications/diffusion/controller/commit/__init__.php @@ -0,0 +1,14 @@ +request = $request; + return $this; + } + + public function setPathChanges(array $path_changes) { + $this->pathChanges = $path_changes; + return $this; + } + + public function render() { + $rows = array(); + foreach ($this->pathChanges as $change) { + $rows[] = array( + 'browse', + 'whatever', + $change->getPath(), // TODO: link + // TODO: etc etc + ); + } + + $view = new AphrontTableView($rows); + $view->setHeaders( + array( + 'History', + 'Change', + 'Path', + )); + $view->setColumnClasses( + array( + '', + '', + 'wide', + )); + $view->setNoDataString('This change has not been fully parsed yet.'); + + return $view->render(); + } + +} diff --git a/src/applications/repository/daemon/commitdiscovery/base/PhabricatorRepositoryCommitDiscoveryDaemon.php b/src/applications/repository/daemon/commitdiscovery/base/PhabricatorRepositoryCommitDiscoveryDaemon.php index 9defcdd53d..b3f42e094a 100644 --- a/src/applications/repository/daemon/commitdiscovery/base/PhabricatorRepositoryCommitDiscoveryDaemon.php +++ b/src/applications/repository/daemon/commitdiscovery/base/PhabricatorRepositoryCommitDiscoveryDaemon.php @@ -1,45 +1,96 @@ repository; } final public function run() { $this->repository = $this->loadRepository(); $sleep = 15; while (true) { $found = $this->discoverCommits(); if ($found) { $sleep = 15; } else { $sleep = min($sleep + 15, 60 * 15); } $this->sleep($sleep); } } + protected function isKnownCommit($target) { + if (isset($this->commitCache[$target])) { + return true; + } + + $commit = id(new PhabricatorRepositoryCommit())->loadOneWhere( + 'repositoryPHID = %s AND commitIdentifier = %s', + $this->getRepository()->getPHID(), + $target); + + if (!$commit) { + return false; + } + + $this->commitCache[$target] = true; + while (count($this->commitCache) > 16) { + array_shift($this->commitCache); + } + + return true; + } + + protected function recordCommit($commit_identifier, $epoch) { + $repository = $this->getRepository(); + + $commit = new PhabricatorRepositoryCommit(); + $commit->setRepositoryPHID($repository->getPHID()); + $commit->setCommitIdentifier($commit_identifier); + $commit->setEpoch($epoch); + + try { + $commit->save(); + $event = new PhabricatorTimelineEvent( + 'cmit', + array( + 'id' => $commit->getID(), + )); + $event->recordEvent(); + + $this->commitCache[$commit_identifier] = true; + } catch (AphrontQueryDuplicateKeyException $ex) { + // Ignore. This can happen because we discover the same new commit + // more than once when looking at history, or because of races or + // data inconsistency or cosmic radiation; in any case, we're still + // in a good state if we ignore the failure. + } + + $this->stillWorking(); + } + abstract protected function discoverCommits(); } diff --git a/src/applications/repository/daemon/commitdiscovery/base/__init__.php b/src/applications/repository/daemon/commitdiscovery/base/__init__.php index b48312c05a..cde21de298 100644 --- a/src/applications/repository/daemon/commitdiscovery/base/__init__.php +++ b/src/applications/repository/daemon/commitdiscovery/base/__init__.php @@ -1,12 +1,16 @@ getRepository(); - // TODO: this should be a constant somewhere - if ($repository->getVersionControlSystem() != 'git') { + $vcs = $repository->getVersionControlSystem(); + if ($vcs != PhabricatorRepositoryType::REPOSITORY_TYPE_GIT) { throw new Exception("Repository is not a git repository."); } $repository_phid = $repository->getPHID(); $repo_base = $repository->getDetail('local-path'); list($commit) = execx( '(cd %s && git log -n1 --pretty="%%H")', $repo_base); $commit = trim($commit); - if ($commit === $this->lastCommit || - $this->isKnownCommit($commit)) { + if ($this->isKnownCommit($commit)) { return false; } - $this->lastCommit = $commit; $this->discoverCommit($commit); return true; } private function discoverCommit($commit) { $discover = array(); $insert = array(); $repository = $this->getRepository(); $repo_base = $repository->getDetail('local-path'); $discover[] = $commit; $insert[] = $commit; while (true) { $target = array_pop($discover); list($parents) = execx( '(cd %s && git log -n1 --pretty="%%P" %s)', $repo_base, $target); $parents = array_filter(explode(' ', trim($parents))); foreach ($parents as $parent) { if (!$this->isKnownCommit($parent)) { $discover[] = $parent; $insert[] = $parent; } } if (empty($discover)) { break; } $this->stillWorking(); } while (true) { $target = array_pop($insert); list($epoch) = execx( '(cd %s && git log -n1 --pretty="%%at" %s)', $repo_base, $target); $epoch = trim($epoch); - $commit = new PhabricatorRepositoryCommit(); - $commit->setRepositoryPHID($this->getRepository()->getPHID()); - $commit->setCommitIdentifier($target); - $commit->setEpoch($epoch); - try { - $commit->save(); - $event = new PhabricatorTimelineEvent( - 'cmit', - array( - 'id' => $commit->getID(), - )); - $event->recordEvent(); - } catch (AphrontQueryDuplicateKeyException $ex) { - // Ignore. This can happen because we discover the same new commit - // more than once when looking at history, or because of races or - // data inconsistency or cosmic radiation; in any case, we're still - // in a good state if we ignore the failure. - } + $this->recordCommit($target, $epoch); + if (empty($insert)) { break; } - $this->stillWorking(); } } - private function isKnownCommit($target) { - if (isset($this->commitCache[$target])) { - return true; - } - - $commit = id(new PhabricatorRepositoryCommit())->loadOneWhere( - 'repositoryPHID = %s AND commitIdentifier = %s', - $this->getRepository()->getPHID(), - $target); - - if (!$commit) { - return false; - } - - $this->commitCache[$target] = true; - if (count($this->commitCache) > 16) { - array_shift($this->commitCache); - } - - return true; - } - } diff --git a/src/applications/repository/daemon/commitdiscovery/git/__init__.php b/src/applications/repository/daemon/commitdiscovery/git/__init__.php index 91b37d309a..4404f788e1 100644 --- a/src/applications/repository/daemon/commitdiscovery/git/__init__.php +++ b/src/applications/repository/daemon/commitdiscovery/git/__init__.php @@ -1,17 +1,15 @@ getRepository(); + + $vcs = $repository->getVersionControlSystem(); + if ($vcs != PhabricatorRepositoryType::REPOSITORY_TYPE_SVN) { + throw new Exception("Repository is not a svn repository."); + } + + $repository_phid = $repository->getPHID(); + + $uri = $repository->getDetail('remote-uri'); + list($xml) = execx( + 'svn log --xml --non-interactive --quiet --limit 1 %s@HEAD', + $uri); + + // TODO: We need to slam the XML output into valid UTF-8. + + $log = new SimpleXMLElement($xml); + $entry = $log->logentry[0]; + $commit = (int)$entry['revision']; + + if ($this->isKnownCommit($commit)) { + return false; + } + + $this->discoverCommit($commit); + + return true; + } + + private function discoverCommit($commit) { + $discover = array(); + $largest_known = $commit - 1; + while ($largest_known > 0 && !$this->isKnownCommit($largest_known)) { + $largest_known--; + } + + $repository = $this->getRepository(); + $uri = $repository->getDetail('remote-uri'); + + for ($ii = $largest_known + 1; $ii <= $commit; $ii++) { + list($xml) = execx( + 'svn log --xml --non-interactive --quiet --limit 1 %s@%d', + $uri, + $ii); + $log = new SimpleXMLElement($xml); + $entry = $log->logentry[0]; + + $identifier = (int)$entry['revision']; + $epoch = (int)strtotime((string)$entry->date[0]); + + $this->recordCommit($identifier, $epoch); + } + } + +} diff --git a/src/applications/repository/daemon/commitdiscovery/svn/__init__.php b/src/applications/repository/daemon/commitdiscovery/svn/__init__.php new file mode 100644 index 0000000000..61d4b5a2af --- /dev/null +++ b/src/applications/repository/daemon/commitdiscovery/svn/__init__.php @@ -0,0 +1,15 @@ +getData(); + + if (!$data) { + // TODO: This event can't be processed, provide some way to + // communicate that? + continue; + } + + $commit = id(new PhabricatorRepositoryCommit())->load($data['id']); + if (!$commit) { + // TODO: Same as above. + continue; + } + + // TODO: Cache these. + $repository = id(new PhabricatorRepository())->loadOneWhere( + 'phid = %s', + $commit->getRepositoryPHID()); + + $vcs = $repository->getVersionControlSystem(); + switch ($vcs) { + case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: + $class = 'PhabricatorRepositoryGitCommitMessageParserWorker'; + $task = new PhabricatorWorkerTask(); + $task->setTaskClass($class); + $task->setData($commit->getID()); + $task->save(); + break; + case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: + $class = 'PhabricatorRepositorySvnCommitMessageParserWorker'; + $task = new PhabricatorWorkerTask(); + $task->setTaskClass($class); + $task->setData($commit->getID()); + $task->save(); + break; + default: + throw new Exception("Unknown repository type."); + } + + $this->stillWorking(); + } + sleep(1); + $this->stillWorking(); + } while (true); + } + +} diff --git a/src/applications/repository/daemon/committask/__init__.php b/src/applications/repository/daemon/committask/__init__.php new file mode 100644 index 0000000000..3e85d352f5 --- /dev/null +++ b/src/applications/repository/daemon/committask/__init__.php @@ -0,0 +1,19 @@ + false, + ) + parent::getConfiguration(); + } } diff --git a/src/applications/repository/storage/commitdata/__init__.php b/src/applications/repository/storage/commitdata/__init__.php new file mode 100644 index 0000000000..57fe6d1dcf --- /dev/null +++ b/src/applications/repository/storage/commitdata/__init__.php @@ -0,0 +1,12 @@ + true, self::CONFIG_SERIALIZATION => array( 'details' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( PhabricatorPHIDConstants::PHID_TYPE_REPO); } public function getDetail($key, $default = null) { return idx($this->details, $key, $default); } public function setDetail($key, $value) { $this->details[$key] = $value; return $this; } } diff --git a/src/applications/repository/worker/base/PhabricatorRepositoryCommitParserWorker.php b/src/applications/repository/worker/base/PhabricatorRepositoryCommitParserWorker.php new file mode 100644 index 0000000000..04043e5e77 --- /dev/null +++ b/src/applications/repository/worker/base/PhabricatorRepositoryCommitParserWorker.php @@ -0,0 +1,54 @@ +getTaskData(); + if (!$commit_id) { + return; + } + + $commit = id(new PhabricatorRepositoryCommit())->load($commit_id); + + if (!$commit) { + // TODO: Communicate permanent failure? + return; + } + + $this->commit = $commit; + + $repository = id(new PhabricatorRepository())->loadOneWhere( + 'phid = %s', + $commit->getRepositoryPHID()); + + if (!$repository) { + return; + } + + return $this->parseCommit($repository, $commit); + } + + abstract protected function parseCommit( + PhabricatorRepository $repository, + PhabricatorRepositoryCommit $commit); + +} diff --git a/src/applications/repository/worker/base/__init__.php b/src/applications/repository/worker/base/__init__.php new file mode 100644 index 0000000000..2b6b8ed4d5 --- /dev/null +++ b/src/applications/repository/worker/base/__init__.php @@ -0,0 +1,16 @@ +establishConnection('w'); + + $result_map = $this->lookupPaths($paths); + + $missing_paths = array_fill_keys($paths, true); + $missing_paths = array_diff_key($missing_paths, $result_map); + $missing_paths = array_keys($missing_paths); + + if ($missing_paths) { + foreach (array_chunk($missing_paths, 512) as $path_chunk) { + $sql = array(); + foreach ($path_chunk as $path) { + $sql[] = qsprintf($conn_w, '(%s)', $path); + } + queryfx( + $conn_w, + 'INSERT INTO %T (path) VALUES %Q', + PhabricatorRepository::TABLE_PATH, + implode(', ', $sql)); + } + $result_map += $this->lookupPaths($missing_paths); + } + + return $result_map; + } + + private function lookupPaths(array $paths) { + $repository = new PhabricatorRepository(); + $conn_w = $repository->establishConnection('w'); + + $result_map = array(); + foreach (array_chunk($paths, 512) as $path_chunk) { + $chunk_map = queryfx_all( + $conn_w, + 'SELECT path, id FROM %T WHERE path IN (%Ls)', + PhabricatorRepository::TABLE_PATH, + $path_chunk); + foreach ($chunk_map as $row) { + $result_map[$row['path']] = $row['id']; + } + } + return $result_map; + } + + +} diff --git a/src/applications/repository/worker/commitchangeparser/base/__init__.php b/src/applications/repository/worker/commitchangeparser/base/__init__.php new file mode 100644 index 0000000000..08e8c51252 --- /dev/null +++ b/src/applications/repository/worker/commitchangeparser/base/__init__.php @@ -0,0 +1,15 @@ +getDetail('local-path'); + + list($raw) = execx( + '(cd %s && git log -n1 -M -C -B --find-copies-harder --raw -t '. + '--abbrev=40 --pretty=format: %s)', + $local_path, + $commit->getCommitIdentifier()); + + $changes = array(); + $move_away = array(); + $copy_away = array(); + $lines = explode("\n", $raw); + foreach ($lines as $line) { + if (!strlen(trim($line))) { + continue; + } + list($old_mode, $new_mode, + $old_hash, $new_hash, + $more_stuff) = preg_split('/ +/', $line); + + // We may only have two pieces here. + list($action, $src_path, $dst_path) = array_merge( + explode("\t", $more_stuff), + array(null)); + + $old_mode = intval($old_mode, 8); + $new_mode = intval($new_mode, 8); + + $file_type = DifferentialChangeType::FILE_NORMAL; + if ($new_mode & 040000) { + $file_type = DifferentialChangeType::FILE_DIRECTORY; + } else if ($new_mode & 0120000) { + $file_type = DifferentialChangeType::FILE_SYMLINK; + } + + // TODO: We can detect binary changes as git does, through a combination + // of running 'git check-attr' for stuff like 'binary', 'merge' or 'diff', + // and by falling back to inspecting the first 8,000 characters of the + // buffer for null bytes (this is seriously git's algorithm, see + // buffer_is_binary() in xdiff-interface.c). + + $change_type = null; + $change_path = $src_path; + $change_target = null; + + switch ($action[0]) { + case 'A': + $change_type = DifferentialChangeType::TYPE_ADD; + break; + case 'D': + $change_type = DifferentialChangeType::TYPE_DELETE; + break; + case 'C': + $change_type = DifferentialChangeType::TYPE_COPY_HERE; + $change_path = $dst_path; + $change_target = $src_path; + $copy_away[$change_target][] = $change_path; + break; + case 'R': + $change_type = DifferentialChangeType::TYPE_MOVE_HERE; + $change_path = $dst_path; + $change_target = $src_path; + $move_away[$change_target][] = $change_path; + break; + case 'M': + $change_type = DifferentialChangeType::TYPE_CHANGE; + break; + default: + throw new Exception("Failed to parse line '{$line}'."); + } + + $changes[$change_path] = array( + 'repositoryID' => $repository->getID(), + 'commitID' => $commit->getID(), + + 'path' => $change_path, + 'changeType' => $change_type, + 'fileType' => $file_type, + 'isDirect' => true, + 'commitSequence' => $commit->getEpoch(), + + 'targetPath' => $change_target, + 'targetCommitID' => $change_target ? $commit->getID() : null, + ); + } + + foreach ($copy_away as $change_path => $destinations) { + if (isset($move_away[$change_path])) { + $change_type = DifferentialChangeType::TYPE_MULTICOPY; + $is_direct = true; + unset($move_away[$change_path]); + } else { + $change_type = DifferentialChangeType::TYPE_COPY_AWAY; + $is_direct = false; + } + + $reference = $changes[reset($destinations)]; + + $changes[$change_path] = array( + 'repositoryID' => $repository->getID(), + 'commitID' => $commit->getID(), + + 'path' => $change_path, + 'changeType' => $change_type, + 'fileType' => $reference['fileType'], + 'isDirect' => $is_direct, + 'commitSequence' => $commit->getEpoch(), + + 'targetPath' => null, + 'targetCommitID' => null, + ); + } + + foreach ($move_away as $change_path => $destinations) { + $reference = $changes[reset($destinations)]; + + $changes[$change_path] = array( + 'repositoryID' => $repository->getID(), + 'commitID' => $commit->getID(), + + 'path' => $change_path, + 'changeType' => DifferentialChangeType::TYPE_MOVE_AWAY, + 'fileType' => $reference['fileType'], + 'isDirect' => true, + 'commitSequence' => $commit->getEpoch(), + + 'targetPath' => null, + 'targetCommitID' => null, + ); + } + + $paths = array(); + foreach ($changes as $change) { + $paths[$change['path']] = true; + if ($change['targetPath']) { + $paths[$change['targetPath']] = true; + } + } + + $path_map = $this->lookupOrCreatePaths(array_keys($paths)); + + foreach ($changes as $key => $change) { + $changes[$key]['pathID'] = $path_map[$change['path']]; + if ($change['targetPath']) { + $changes[$key]['targetPathID'] = $path_map[$change['targetPath']]; + } else { + $changes[$key]['targetPathID'] = null; + } + } + + $conn_w = $repository->establishConnection('w'); + + $changes_sql = array(); + foreach ($changes as $change) { + $values = array( + (int)$change['repositoryID'], + (int)$change['pathID'], + (int)$change['commitID'], + $change['targetPathID'] + ? (int)$change['targetPathID'] + : 'null', + $change['targetCommitID'] + ? (int)$change['targetCommitID'] + : 'null', + (int)$change['changeType'], + (int)$change['fileType'], + (int)$change['isDirect'], + (int)$change['commitSequence'], + ); + $changes_sql[] = '('.implode(', ', $values).')'; + } + + queryfx( + $conn_w, + 'DELETE FROM %T WHERE commitID = %d', + PhabricatorRepository::TABLE_PATHCHANGE, + $commit->getID()); + foreach (array_chunk($changes_sql, 256) as $sql_chunk) { + queryfx( + $conn_w, + 'INSERT INTO %T + (repositoryID, pathID, commitID, targetPathID, targetCommitID, + changeType, fileType, isDirect, commitSequence) + VALUES %Q', + PhabricatorRepository::TABLE_PATHCHANGE, + implode(', ', $sql_chunk)); + } + } + +} diff --git a/src/applications/repository/worker/commitchangeparser/git/__init__.php b/src/applications/repository/worker/commitchangeparser/git/__init__.php new file mode 100644 index 0000000000..6bc6d8d55e --- /dev/null +++ b/src/applications/repository/worker/commitchangeparser/git/__init__.php @@ -0,0 +1,17 @@ +commit; - public function getConfiguration() { - return array( - self::CONFIG_IDS => self::IDS_MANUAL, - self::CONFIG_TIMESTAMPS => false, - ) + parent::getConfiguration(); + $data = id(new PhabricatorRepositoryCommitData())->loadOneWhere( + 'commitID = %d', + $commit->getID()); + if (!$data) { + $data = new PhabricatorRepositoryCommitData(); + } + $data->setCommitID($commit->getID()); + $data->setAuthorName($author); + $data->setCommitMessage($message); + $data->save(); } } diff --git a/src/applications/repository/worker/commitmessageparser/base/__init__.php b/src/applications/repository/worker/commitmessageparser/base/__init__.php new file mode 100644 index 0000000000..1add9e0528 --- /dev/null +++ b/src/applications/repository/worker/commitmessageparser/base/__init__.php @@ -0,0 +1,15 @@ +getDetail('local-path'); + + list($info) = execx( + '(cd %s && git log -n 1 --pretty=format:%%an%%x00%%B %s)', + $local_path, + $commit->getCommitIdentifier()); + + // TODO: Need to slam UTF8? + + list($author, $message) = explode("\0", $info); + + $this->updateCommitData($author, $message); + + $task = new PhabricatorWorkerTask(); + $task->setTaskClass('PhabricatorRepositoryGitCommitChangeParserWorker'); + $task->setData($commit->getID()); + $task->save(); + } + +} diff --git a/src/applications/repository/worker/commitmessageparser/git/__init__.php b/src/applications/repository/worker/commitmessageparser/git/__init__.php new file mode 100644 index 0000000000..f139ac2819 --- /dev/null +++ b/src/applications/repository/worker/commitmessageparser/git/__init__.php @@ -0,0 +1,15 @@ +getDetail('remote-uri'); + + list($xml) = execx( + 'svn log --xml --limit 1 --non-interactive %s@%d', + $uri, + $commit->getCommitIdentifier()); + + // TODO: Need to slam UTF8. + + $log = new SimpleXMLElement($xml); + $entry = $log->logentry[0]; + + $author = (string)$entry->author; + $message = (string)$entry->msg; + + $this->updateCommitData($author, $message); + } + +} diff --git a/src/applications/repository/worker/commitmessageparser/svn/__init__.php b/src/applications/repository/worker/commitmessageparser/svn/__init__.php new file mode 100644 index 0000000000..e8bb732e78 --- /dev/null +++ b/src/applications/repository/worker/commitmessageparser/svn/__init__.php @@ -0,0 +1,14 @@ +cursorName = $cursor_name; $this->eventTypes = $event_types; } protected function loadEvents() { if (!$this->cursor) { $this->cursor = id(new PhabricatorTimelineCursor())->loadOneWhere( 'name = %s', $this->cursorName); if (!$this->cursor) { $cursor = new PhabricatorTimelineCursor(); $cursor->setName($this->cursorName); $cursor->setPosition(0); $cursor->save(); $this->cursor = $cursor; } } - $event = new PhabricatorTimelineEvent(); + $event = new PhabricatorTimelineEvent('NULL'); $event_data = new PhabricatorTimelineEventData(); $raw_data = queryfx_all( $event->establishConnection('r'), 'SELECT event.*, event_data.eventData eventData - FROM %T event WHERE event.id > %d AND event.type in (%Ls) + FROM %T event LEFT JOIN %T event_data ON event_data.eventID = event.id + WHERE event.id > %d AND event.type in (%Ls) ORDER BY event.id ASC LIMIT %d', $event->getTableName(), + $event_data->getTableName(), $this->cursor->getPosition(), $this->eventTypes, - $event_data->getTableName(), self::LOAD_CHUNK_SIZE); $events = $event->loadAllFromArray($raw_data); $events = mpull($events, null, 'getID'); $raw_data = ipull($raw_data, 'eventData', 'id'); foreach ($raw_data as $id => $data) { if ($data) { $decoded = json_decode($data, true); $events[$id]->setData($decoded); } } $this->events = $events; if ($this->events) { $this->events = array_values($this->events); $this->index = 0; } else { $this->cursor = null; } } public function current() { return $this->events[$this->index]; } public function key() { return $this->events[$this->index]->getID(); } public function next() { if ($this->valid()) { $this->cursor->setPosition($this->key()); $this->cursor->save(); } $this->index++; if (!$this->valid()) { $this->loadEvents(); } } public function valid() { return isset($this->events[$this->index]); } public function rewind() { if (!$this->valid()) { $this->loadEvents(); } } } diff --git a/src/infrastructure/daemon/timeline/storage/cursor/PhabricatorTimelineCursor.php b/src/infrastructure/daemon/timeline/storage/cursor/PhabricatorTimelineCursor.php index 6a1d379d5f..a55375c40b 100644 --- a/src/infrastructure/daemon/timeline/storage/cursor/PhabricatorTimelineCursor.php +++ b/src/infrastructure/daemon/timeline/storage/cursor/PhabricatorTimelineCursor.php @@ -1,31 +1,42 @@ self::IDS_MANUAL, self::CONFIG_TIMESTAMPS => false, ) + parent::getConfiguration(); } + public function shouldInsertWhenSaved() { + if ($this->position == 0) { + return true; + } + return false; + } + } diff --git a/src/infrastructure/daemon/workers/storage/task/PhabricatorWorkerTask.php b/src/infrastructure/daemon/workers/storage/task/PhabricatorWorkerTask.php index f41b3ceba2..9d980095db 100644 --- a/src/infrastructure/daemon/workers/storage/task/PhabricatorWorkerTask.php +++ b/src/infrastructure/daemon/workers/storage/task/PhabricatorWorkerTask.php @@ -1,60 +1,82 @@ false, ) + parent::getConfiguration(); } public function setServerTime($server_time) { $this->serverTime = $server_time; $this->localTime = time(); return $this; } public function setLeaseDuration($lease_duration) { $server_lease_expires = $this->serverTime + $lease_duration; $this->setLeaseExpires($server_lease_expires); return $this->save(); } public function save() { if ($this->leaseOwner) { $current_server_time = $this->serverTime + (time() - $this->localTime); if ($current_server_time >= $this->leaseExpires) { throw new Exception("Trying to update task after lease expiration!"); } } - return parent::save(); + $is_new = !$this->getID(); + if ($is_new) { + $this->failureCount = 0; + } + + $ret = parent::save(); + + if ($is_new && $this->data) { + $data = new PhabricatorWorkerTaskData(); + $data->setTaskID($this->getID()); + $data->setData($this->data); + $data->save(); + } + + return $ret; } + public function setData($data) { + $this->data = $data; + return $this; + } + + public function getData() { + return $this->data; + } } diff --git a/src/infrastructure/daemon/workers/storage/task/__init__.php b/src/infrastructure/daemon/workers/storage/task/__init__.php index 933817be3c..0a7539275a 100644 --- a/src/infrastructure/daemon/workers/storage/task/__init__.php +++ b/src/infrastructure/daemon/workers/storage/task/__init__.php @@ -1,12 +1,13 @@ getLeaseOwnershipName(); $task_table = new PhabricatorWorkerTask(); $taskdata_table = new PhabricatorWorkerTaskData(); $sleep = 0; do { $conn_w = $task_table->establishConnection('w'); queryfx( $conn_w, 'UPDATE %T SET leaseOwner = %s, leaseExpires = UNIX_TIMESTAMP() + 15 - WHERE leaseOwner IS NULL - OR leaseExpires < UNIX_TIMESTAMP() - ORDER BY leaseOwner IS NULL, failureCount, priority - LIMIT 1', + WHERE leaseOwner IS NULL LIMIT 1', $task_table->getTableName(), $lease_ownership_name); $rows = $conn_w->getAffectedRows(); + if (!$rows) { + $rows = queryfx( + $conn_w, + 'UPDATE %T SET leaseOwner = %s, leaseExpires = UNIX_TIMESTAMP() + 15 + WHERE leaseExpires < UNIX_TIMESTAMP() LIMIT 1', + $task_table->getTableName(), + $lease_ownership_name); + $rows = $conn_w->getAffectedRows(); + } + if ($rows) { $data = queryfx_all( $conn_w, 'SELECT task.*, taskdata.data _taskData, UNIX_TIMESTAMP() _serverTime FROM %T task LEFT JOIN %T taskdata ON taskdata.taskID = task.id WHERE leaseOwner = %s AND leaseExpires > UNIX_TIMESTAMP() LIMIT 1', $task_table->getTableName(), $taskdata_table->getTableName(), $lease_ownership_name); $tasks = $task_table->loadAllFromArray($data); $tasks = mpull($tasks, null, 'getID'); $task_data = array(); foreach ($data as $row) { $tasks[$row['id']]->setServerTime($row['_serverTime']); if ($row['_taskData']) { $task_data[$row['id']] = json_decode($row['_taskData'], true); } else { $task_data[$row['id']] = null; } } foreach ($tasks as $task) { // TODO: We should detect if we acquired a task with an expired lease // and log about it / bump up failure count. // TODO: We should detect if we acquired a task with an excessive // failure count and fail it permanently. $data = idx($task_data, $task->getID()); $class = $task->getTaskClass(); try { PhutilSymbolLoader::loadClass($class); if (!is_subclass_of($class, 'PhabricatorWorker')) { throw new Exception( "Task class '{$class}' does not extend PhabricatorWorker."); } $worker = newv($class, array($data)); $lease = $worker->getRequiredLeaseTime(); if ($lease !== null) { $task->setLeaseDuration($lease); } $worker->executeTask(); $task->delete(); if ($data !== null) { queryfx( $conn_w, 'DELETE FROM %T WHERE taskID = %d', - $taskdata_table, + $taskdata_table->getTableName(), $task->getID()); } } catch (Exception $ex) { $task->setFailureCount($task->getFailureCount() + 1); $task->save(); throw $ex; } } $sleep = 0; } else { $sleep = min($sleep + 1, 30); } $this->sleep($sleep); } while (true); } private function getLeaseOwnershipName() { static $name = null; if ($name === null) { $name = getmypid().':'.time().':'.php_uname('n'); } return $name; } }