Page MenuHomestyx hydra

No OneTemporary

diff --git a/resources/sql/patches/004.daemonrepos.sql b/resources/sql/patches/004.daemonrepos.sql
new file mode 100644
index 0000000000..9108c92cb8
--- /dev/null
+++ b/resources/sql/patches/004.daemonrepos.sql
@@ -0,0 +1,28 @@
+create table phabricator_repository.repository_commit (
+ id int unsigned not null auto_increment primary key,
+ repositoryPHID varchar(64) binary not null,
+ phid varchar(64) binary not null,
+ commitIdentifier varchar(40) binary not null,
+ epoch int unsigned not null,
+ unique key (phid),
+ unique key (repositoryPHID, commitIdentifier)
+);
+
+create database phabricator_timeline;
+create table phabricator_timeline.timeline_event (
+ id int unsigned not null auto_increment primary key,
+ type char(4) binary not null,
+ key (type, id)
+);
+
+create table phabricator_timeline.timeline_eventdata (
+ id int unsigned not null auto_increment primary key,
+ eventID int unsigned not null,
+ eventData longblob not null,
+ unique key (eventID)
+);
+
+create table phabricator_timeline.timeline_cursor (
+ name varchar(255) not null primary key,
+ position int unsigned not null
+);
\ No newline at end of file
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
index 41383b0a97..73762557b8 100644
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1,536 +1,560 @@
<?php
/**
* This file is automatically generated. Use 'phutil_mapper.php' to rebuild it.
* @generated
*/
phutil_register_library_map(array(
'class' =>
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',
'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',
'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',
'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',
+ 'PhabricatorRepositoryCommitDiscoveryDaemon' => 'applications/repository/daemon/commitdiscovery/base',
+ 'PhabricatorRepositoryCommitParserDaemon' => 'applications/repository/daemon/commitparser',
'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',
+ 'PhabricatorRepositoryGitCommitDiscoveryDaemon' => 'applications/repository/daemon/commitdiscovery/git',
'PhabricatorRepositoryGitHubNotification' => 'applications/repository/storage/githubnotification',
'PhabricatorRepositoryGitHubPostReceiveController' => 'applications/repository/controller/github-post-receive',
+ 'PhabricatorRepositoryGitPullDaemon' => 'applications/repository/daemon/gitpull',
'PhabricatorRepositoryListController' => 'applications/repository/controller/list',
+ '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',
+ 'PhabricatorTimelineCursor' => 'applications/timeline/storage/cursor',
+ 'PhabricatorTimelineDAO' => 'applications/timeline/storage/base',
+ 'PhabricatorTimelineEvent' => 'applications/timeline/storage/event',
+ 'PhabricatorTimelineEventData' => 'applications/timeline/storage/eventdata',
+ 'PhabricatorTimelineIterator' => 'applications/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',
'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',
'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',
'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',
'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',
+ 'PhabricatorRepositoryCommitDiscoveryDaemon' => 'PhabricatorRepositoryDaemon',
+ 'PhabricatorRepositoryCommitParserDaemon' => 'PhabricatorRepositoryDaemon',
'PhabricatorRepositoryController' => 'PhabricatorController',
'PhabricatorRepositoryCreateController' => 'PhabricatorController',
'PhabricatorRepositoryDAO' => 'PhabricatorLiskDAO',
+ 'PhabricatorRepositoryDaemon' => 'PhabricatorDaemon',
'PhabricatorRepositoryEditController' => 'PhabricatorController',
+ 'PhabricatorRepositoryGitCommitDiscoveryDaemon' => 'PhabricatorRepositoryCommitDiscoveryDaemon',
'PhabricatorRepositoryGitHubNotification' => 'PhabricatorRepositoryDAO',
'PhabricatorRepositoryGitHubPostReceiveController' => 'PhabricatorRepositoryController',
+ 'PhabricatorRepositoryGitPullDaemon' => 'PhabricatorRepositoryDaemon',
'PhabricatorRepositoryListController' => 'PhabricatorController',
'PhabricatorSearchBaseController' => 'PhabricatorController',
'PhabricatorSearchController' => 'PhabricatorSearchBaseController',
'PhabricatorSearchDAO' => 'PhabricatorLiskDAO',
'PhabricatorSearchDifferentialIndexer' => 'PhabricatorSearchDocumentIndexer',
'PhabricatorSearchDocument' => 'PhabricatorSearchDAO',
'PhabricatorSearchDocumentField' => 'PhabricatorSearchDAO',
'PhabricatorSearchDocumentRelationship' => 'PhabricatorSearchDAO',
'PhabricatorSearchManiphestIndexer' => 'PhabricatorSearchDocumentIndexer',
'PhabricatorSearchMySQLExecutor' => 'PhabricatorSearchExecutor',
'PhabricatorSearchQuery' => 'PhabricatorSearchDAO',
'PhabricatorStandardPageView' => 'AphrontPageView',
+ 'PhabricatorTimelineCursor' => 'PhabricatorTimelineDAO',
+ 'PhabricatorTimelineDAO' => 'PhabricatorLiskDAO',
+ 'PhabricatorTimelineEvent' => 'PhabricatorTimelineDAO',
+ 'PhabricatorTimelineEventData' => 'PhabricatorTimelineDAO',
'PhabricatorTypeaheadCommonDatasourceController' => 'PhabricatorTypeaheadDatasourceController',
'PhabricatorTypeaheadDatasourceController' => 'PhabricatorController',
'PhabricatorUser' => 'PhabricatorUserDAO',
'PhabricatorUserDAO' => 'PhabricatorLiskDAO',
'PhabricatorUserOAuthInfo' => 'PhabricatorUserDAO',
'PhabricatorUserProfile' => 'PhabricatorUserDAO',
'PhabricatorUserSettingsController' => 'PhabricatorPeopleController',
'PhabricatorXHProfController' => 'PhabricatorController',
'PhabricatorXHProfProfileController' => 'PhabricatorXHProfController',
'PhabricatorXHProfProfileSymbolView' => 'AphrontView',
'PhabricatorXHProfProfileTopLevelView' => 'AphrontView',
),
'requires_interface' =>
array(
),
));
diff --git a/src/aphront/console/plugin/errorlog/api/DarkConsoleErrorLogPluginAPI.php b/src/aphront/console/plugin/errorlog/api/DarkConsoleErrorLogPluginAPI.php
index bee9db704a..a6eea09524 100755
--- a/src/aphront/console/plugin/errorlog/api/DarkConsoleErrorLogPluginAPI.php
+++ b/src/aphront/console/plugin/errorlog/api/DarkConsoleErrorLogPluginAPI.php
@@ -1,48 +1,58 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* 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.
*/
class DarkConsoleErrorLogPluginAPI {
private static $errors = array();
+ private static $discardMode = false;
+
+ public static function enableDiscardMode() {
+ self::$discardMode = true;
+ }
+
public static function getErrors() {
return self::$errors;
}
public static function handleError($num, $str, $file, $line, $cxt) {
- self::$errors[] = array(
- 'event' => 'error',
- 'num' => $num,
- 'str' => $str,
- 'file' => $file,
- 'line' => $line,
- 'cxt' => $cxt,
- 'trace' => debug_backtrace(),
- );
+ if (!self::$discardMode) {
+ self::$errors[] = array(
+ 'event' => 'error',
+ 'num' => $num,
+ 'str' => $str,
+ 'file' => $file,
+ 'line' => $line,
+ 'cxt' => $cxt,
+ 'trace' => debug_backtrace(),
+ );
+ }
error_log("{$file}:{$line} {$str}");
}
public static function handleException($ex) {
- self::$errors[] = array(
- 'event' => 'exception',
- 'exception' => $ex,
- );
+ if (!self::$discardMode) {
+ self::$errors[] = array(
+ 'event' => 'exception',
+ 'exception' => $ex,
+ );
+ }
error_log($ex);
}
}
diff --git a/src/aphront/console/plugin/services/api/DarkConsoleServicesPluginAPI.php b/src/aphront/console/plugin/services/api/DarkConsoleServicesPluginAPI.php
index c652075a39..23163081a2 100755
--- a/src/aphront/console/plugin/services/api/DarkConsoleServicesPluginAPI.php
+++ b/src/aphront/console/plugin/services/api/DarkConsoleServicesPluginAPI.php
@@ -1,35 +1,43 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* 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.
*/
class DarkConsoleServicesPluginAPI {
const EVENT_QUERY = 'query';
const EVENT_CONNECT = 'connect';
private static $events = array();
+ private static $discardMode = false;
+
+ public static function enableDiscardMode() {
+ self::$discardMode = true;
+ }
+
public static function addEvent(array $event) {
- self::$events[] = $event;
+ if (!self::$discardMode) {
+ self::$events[] = $event;
+ }
}
public static function getEvents() {
return self::$events;
}
}
diff --git a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php
index e42fd40b41..06e1799733 100644
--- a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php
+++ b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php
@@ -1,288 +1,289 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* 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.
*/
/**
* @group aphront
*/
class AphrontDefaultApplicationConfiguration
extends AphrontApplicationConfiguration {
public function __construct() {
}
public function getApplicationName() {
return 'aphront-default';
}
public function getURIMap() {
return $this->getResourceURIMapRules() + array(
'/' => array(
'$' => 'PhabricatorDirectoryMainController',
),
'/directory/' => array(
'item/$'
=> 'PhabricatorDirectoryItemListController',
'item/edit/(?:(?P<id>\d+)/)?$'
=> 'PhabricatorDirectoryItemEditController',
'item/delete/(?P<id>\d+)/'
=> 'PhabricatorDirectoryItemDeleteController',
'category/$'
=> 'PhabricatorDirectoryCategoryListController',
'category/edit/(?:(?P<id>\d+)/)?$'
=> 'PhabricatorDirectoryCategoryEditController',
'category/delete/(?P<id>\d+)/'
=> 'PhabricatorDirectoryCategoryDeleteController',
),
'/file/' => array(
'$' => 'PhabricatorFileListController',
'upload/$' => 'PhabricatorFileUploadController',
'(?P<view>info)/(?P<phid>[^/]+)/' => 'PhabricatorFileViewController',
'(?P<view>view)/(?P<phid>[^/]+)/' => 'PhabricatorFileViewController',
'(?P<view>download)/(?P<phid>[^/]+)/' => 'PhabricatorFileViewController',
),
'/phid/' => array(
'$' => 'PhabricatorPHIDLookupController',
'list/$' => 'PhabricatorPHIDListController',
'type/$' => 'PhabricatorPHIDTypeListController',
'type/edit/(?:(?P<id>\d+)/)?$' => 'PhabricatorPHIDTypeEditController',
'new/$' => 'PhabricatorPHIDAllocateController',
),
'/people/' => array(
'$' => 'PhabricatorPeopleListController',
'edit/(?:(?P<username>\w+)/)?$' => 'PhabricatorPeopleEditController',
),
'/p/(?P<username>\w+)/$' => 'PhabricatorPeopleProfileController',
'/profile/' => array(
'edit/$' => 'PhabricatorPeopleProfileEditController',
),
'/conduit/' => array(
'$' => 'PhabricatorConduitConsoleController',
'method/(?P<method>[^/]+)$' => 'PhabricatorConduitConsoleController',
'log/$' => 'PhabricatorConduitLogController',
),
'/api/(?P<method>[^/]+)$' => 'PhabricatorConduitAPIController',
'/D(?P<id>\d+)' => 'DifferentialRevisionViewController',
'/differential/' => array(
'$' => 'DifferentialRevisionListController',
'filter/(?P<filter>\w+)/$' => 'DifferentialRevisionListController',
'diff/' => array(
'(?P<id>\d+)/$' => 'DifferentialDiffViewController',
'create/$' => 'DifferentialDiffCreateController',
),
'changeset/$' => 'DifferentialChangesetViewController',
'revision/edit/(?:(?P<id>\d+)/)?$'
=> 'DifferentialRevisionEditController',
'comment/' => array(
'preview/(?P<id>\d+)/$' => 'DifferentialCommentPreviewController',
'save/$' => 'DifferentialCommentSaveController',
'inline/' => array(
'preview/(?P<id>\d+)/$' =>
'DifferentialInlineCommentPreviewController',
'edit/(?P<id>\d+)/$' => 'DifferentialInlineCommentEditController',
),
),
'attach/(?P<id>\d+)/(?P<type>\w+)/$' => 'DifferentialAttachController',
'subscribe/(?P<action>add|rem)/(?P<id>\d+)/$'
=> 'DifferentialSubscribeController',
),
'/typeahead/' => array(
'common/(?P<type>\w+)/$'
=> 'PhabricatorTypeaheadCommonDatasourceController',
),
'/mail/' => array(
'$' => 'PhabricatorMetaMTAListController',
'send/$' => 'PhabricatorMetaMTASendController',
'view/(?P<id>\d+)/$' => 'PhabricatorMetaMTAViewController',
'lists/$' => 'PhabricatorMetaMTAMailingListsController',
'lists/edit/(?:(?P<id>\d+)/)?$'
=> 'PhabricatorMetaMTAMailingListEditController',
),
'/login/' => array(
'$' => 'PhabricatorLoginController',
'email/$' => 'PhabricatorEmailLoginController',
'etoken/(?P<token>\w+)/$' => 'PhabricatorEmailTokenController',
),
'/logout/$' => 'PhabricatorLogoutController',
'/oauth/' => array(
'(?P<provider>github|facebook)/' => array(
'login/$' => 'PhabricatorOAuthLoginController',
'diagnose/$' => 'PhabricatorOAuthDiagnosticsController',
'unlink/$' => 'PhabricatorOAuthUnlinkController',
),
),
'/xhprof/' => array(
'profile/(?P<phid>[^/]+)/$' => 'PhabricatorXHProfProfileController',
),
'/~/' => 'DarkConsoleController',
'/settings/' => array(
'(?:page/(?P<page>[^/]+)/)?$' => 'PhabricatorUserSettingsController',
),
'/maniphest/' => array(
'$' => 'ManiphestTaskListController',
'view/(?P<view>\w+)/$' => 'ManiphestTaskListController',
'task/' => array(
'create/$' => 'ManiphestTaskEditController',
'edit/(?P<id>\d+)/$' => 'ManiphestTaskEditController',
),
'transaction/' => array(
'save/' => 'ManiphestTransactionSaveController',
),
'select/search/$' => 'ManiphestTaskSelectorSearchController',
),
'/T(?P<id>\d+)$' => 'ManiphestTaskDetailController',
'/github-post-receive/(?P<id>\d+)/(?P<token>[^/]+)/$'
=> 'PhabricatorRepositoryGitHubPostReceiveController',
'/repository/' => array(
'$' => 'PhabricatorRepositoryListController',
'create/$' => 'PhabricatorRepositoryCreateController',
- 'edit/(?P<id>\d+)/$' => 'PhabricatorRepositoryEditController',
+ 'edit/(?P<id>\d+)/(?:(?P<view>\w+)?/)?$' =>
+ 'PhabricatorRepositoryEditController',
'delete/(?P<id>\d+)/$' => 'PhabricatorRepositoryDeleteController',
),
'/search/' => array(
'$' => 'PhabricatorSearchController',
'(?P<id>\d+)/$' => 'PhabricatorSearchController',
),
'/project/' => array(
'$' => 'PhabricatorProjectListController',
'edit/(?:(?P<id>\d+)/)?$' => 'PhabricatorProjectEditController',
'view/(?P<id>\d+)/$' => 'PhabricatorProjectProfileController',
'affiliation/(?P<id>\d+)/$'
=> 'PhabricatorProjectAffiliationEditController',
),
);
}
protected function getResourceURIMapRules() {
return array(
'/res/' => array(
'(?P<package>pkg/)?(?P<hash>[a-f0-9]{8})/(?P<path>.+\.(?: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 =
'<div class="aphront-unhandled-exception">'.
'<h1>Unhandled Exception "'.$class.'": '.$message.'</h1>'.
'<code>'.phutil_escape_html((string)$ex).'</code>'.
'</div>';
$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(
'<div style="padding: 2em 0;">'.
$response->buildResponseString().
'</div>');
$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(
'<p>The page you requested was not found.</p>');
$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/phid/constants/PhabricatorPHIDConstants.php b/src/applications/phid/constants/PhabricatorPHIDConstants.php
index e8363a9d71..30aa59dc1c 100644
--- a/src/applications/phid/constants/PhabricatorPHIDConstants.php
+++ b/src/applications/phid/constants/PhabricatorPHIDConstants.php
@@ -1,30 +1,32 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* 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.
*/
final class PhabricatorPHIDConstants {
const PHID_TYPE_USER = 'USER';
const PHID_TYPE_MLST = 'MLST';
const PHID_TYPE_DREV = 'DREV';
const PHID_TYPE_TASK = 'TASK';
const PHID_TYPE_FILE = 'FILE';
const PHID_TYPE_PROJ = 'PROJ';
const PHID_TYPE_UNKNOWN = '????';
const PHID_TYPE_MAGIC = '!!!!';
+ const PHID_TYPE_REPO = 'REPO';
+ const PHID_TYPE_CMIT = 'CMIT';
}
diff --git a/src/aphront/console/plugin/services/api/DarkConsoleServicesPluginAPI.php b/src/applications/repository/constants/repositorytype/PhabricatorRepositoryType.php
old mode 100755
new mode 100644
similarity index 67%
copy from src/aphront/console/plugin/services/api/DarkConsoleServicesPluginAPI.php
copy to src/applications/repository/constants/repositorytype/PhabricatorRepositoryType.php
index c652075a39..c3ab64784f
--- a/src/aphront/console/plugin/services/api/DarkConsoleServicesPluginAPI.php
+++ b/src/applications/repository/constants/repositorytype/PhabricatorRepositoryType.php
@@ -1,35 +1,24 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* 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.
*/
-class DarkConsoleServicesPluginAPI {
+final class PhabricatorRepositoryType {
- const EVENT_QUERY = 'query';
- const EVENT_CONNECT = 'connect';
-
- private static $events = array();
-
- public static function addEvent(array $event) {
- self::$events[] = $event;
- }
-
- public static function getEvents() {
- return self::$events;
- }
+ const REPOSITORY_TYPE_GIT = 'git';
+ const REPOSITORY_TYPE_SVN = 'svn';
}
-
diff --git a/src/applications/repository/constants/repositorytype/__init__.php b/src/applications/repository/constants/repositorytype/__init__.php
new file mode 100644
index 0000000000..0becebe43f
--- /dev/null
+++ b/src/applications/repository/constants/repositorytype/__init__.php
@@ -0,0 +1,10 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+
+phutil_require_source('PhabricatorRepositoryType.php');
diff --git a/src/applications/repository/controller/create/PhabricatorRepositoryCreateController.php b/src/applications/repository/controller/create/PhabricatorRepositoryCreateController.php
index bbab3011cf..c6b8b1769d 100644
--- a/src/applications/repository/controller/create/PhabricatorRepositoryCreateController.php
+++ b/src/applications/repository/controller/create/PhabricatorRepositoryCreateController.php
@@ -1,138 +1,138 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* 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.
*/
class PhabricatorRepositoryCreateController extends PhabricatorController {
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$e_name = true;
$e_callsign = true;
$repository = new PhabricatorRepository();
$type_map = array(
- 'svn' => 'Subversion',
'git' => 'Git',
+ 'svn' => 'Subversion',
);
$errors = array();
if ($request->isFormPost()) {
$repository->setName($request->getStr('name'));
$repository->setCallsign($request->getStr('callsign'));
$repository->setVersionControlSystem($request->getStr('type'));
if (!strlen($repository->getName())) {
$e_name = 'Required';
$errors[] = 'Repository name is required.';
} else {
$e_name = null;
}
if (!strlen($repository->getCallsign())) {
$e_callsign = 'Required';
$errors[] = 'Callsign is required.';
} else if (!preg_match('/^[A-Z]+$/', $repository->getCallsign())) {
$e_callsign = 'Invalid';
$errors[] = 'Callsign must be ALL UPPERCASE LETTERS.';
} else {
$e_callsign = null;
}
if (empty($type_map[$repository->getVersionControlSystem()])) {
$errors[] = 'Invalid version control system.';
}
if (!$errors) {
try {
$repository->save();
return id(new AphrontRedirectResponse())
->setURI('/repository/edit/'.$repository->getID().'/');
} catch (AphrontQueryDuplicateKeyException $ex) {
$e_callsign = 'Duplicate';
$errors[] = 'Callsign must be unique. Another repository already '.
'uses that callsign.';
}
}
}
$error_view = null;
if ($errors) {
$error_view = new AphrontErrorView();
$error_view->setErrors($errors);
$error_view->setTitle('Form Errors');
}
$form = new AphrontFormView();
$form
->setUser($user)
->setAction('/repository/create/')
->appendChild(
id(new AphrontFormTextControl())
->setLabel('Name')
->setName('name')
->setValue($repository->getName())
->setError($e_name)
->setCaption('Human-readable repository name.'))
->appendChild(
'<p class="aphront-form-instructions">Select a "Callsign" &mdash; a '.
'short, uppercase string to identify revisions in this repository. If '.
'you choose "EX", revisions in this repository will be identified '.
'with the prefix "rEX".</p>')
->appendChild(
id(new AphrontFormTextControl())
->setLabel('Callsign')
->setName('callsign')
->setValue($repository->getCallsign())
->setError($e_callsign)
->setCaption(
'Short, UPPERCASE identifier. Once set, it can not be changed.'))
->appendChild(
id(new AphrontFormSelectControl())
->setLabel('Type')
->setName('type')
->setOptions($type_map)
->setValue($repository->getVersionControlSystem()))
->appendChild(
id(new AphrontFormSubmitControl())
->setValue('Create Repository')
->addCancelButton('/repository/'));
$panel = new AphrontPanelView();
$panel->setHeader('Create Repository');
$panel->appendChild($form);
$panel->setWidth(AphrontPanelView::WIDTH_FORM);
return $this->buildStandardPageResponse(
array(
$error_view,
$panel,
),
array(
'title' => 'Create Repository',
));
}
}
diff --git a/src/applications/repository/controller/edit/PhabricatorRepositoryEditController.php b/src/applications/repository/controller/edit/PhabricatorRepositoryEditController.php
index 7eac802e03..50964bd660 100644
--- a/src/applications/repository/controller/edit/PhabricatorRepositoryEditController.php
+++ b/src/applications/repository/controller/edit/PhabricatorRepositoryEditController.php
@@ -1,192 +1,405 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* 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.
*/
class PhabricatorRepositoryEditController extends PhabricatorController {
private $id;
+ private $view;
+ private $repository;
+ private $sideNav;
public function willProcessRequest(array $data) {
- $this->id = idx($data, 'id');
+ $this->id = $data['id'];
+ $this->view = idx($data, 'view');
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$repository = id(new PhabricatorRepository())->load($this->id);
if (!$repository) {
return new Aphront404Response();
}
+ $views = array(
+ 'basic' => 'Basics',
+ 'tracking' => 'Tracking',
+ );
+
$vcs = $repository->getVersionControlSystem();
if ($vcs == DifferentialRevisionControlSystem::GIT) {
if (!$repository->getDetail('github-token')) {
$token = substr(base64_encode(Filesystem::readRandomBytes(8)), 0, 8);
$repository->setDetail('github-token', $token);
$repository->save();
}
+
+ $views['github'] = 'Github';
}
- $e_name = true;
+ $this->repository = $repository;
+
+ if (!isset($views[$this->view])) {
+ reset($views);
+ $this->view = key($views);
+ }
+
+ $nav = new AphrontSideNavView();
+ foreach ($views as $view => $name) {
+ $nav->addNavItem(
+ phutil_render_tag(
+ 'a',
+ array(
+ 'class' => ($view == $this->view
+ ? 'aphront-side-nav-selected'
+ : null),
+ 'href' => '/repository/edit/'.$repository->getID().'/'.$view.'/',
+ ),
+ phutil_escape_html($name)));
+ }
+
+ $this->sideNav = $nav;
+
+ switch ($this->view) {
+ case 'basic':
+ return $this->processBasicRequest();
+ case 'tracking':
+ return $this->processTrackingRequest();
+ case 'github':
+ return $this->processGithubRequest();
+ default:
+ throw new Exception("Unknown view.");
+ }
+ }
+
+ protected function processBasicRequest() {
+ $request = $this->getRequest();
+ $user = $request->getUser();
+ $repository = $this->repository;
+ $repository_id = $repository->getID();
$type_map = array(
'svn' => 'Subversion',
'git' => 'Git',
);
+
$errors = array();
+ $e_name = true;
+
if ($request->isFormPost()) {
$repository->setName($request->getStr('name'));
if (!strlen($repository->getName())) {
$e_name = 'Required';
$errors[] = 'Repository name is required.';
} else {
$e_name = null;
}
if (!$errors) {
$repository->save();
return id(new AphrontRedirectResponse())
- ->setURI('/repository/');
+ ->setURI('/repository/edit/'.$repository_id.'/basic/?saved=true');
}
-
}
$error_view = null;
if ($errors) {
$error_view = new AphrontErrorView();
$error_view->setErrors($errors);
$error_view->setTitle('Form Errors');
+ } else if ($request->getStr('saved')) {
+ $error_view = new AphrontErrorView();
+ $error_view->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
+ $error_view->setTitle('Changes Saved');
+ $error_view->appendChild(
+ 'Repository changes were saved.');
}
-
$form = new AphrontFormView();
$form
->setUser($user)
->setAction('/repository/edit/'.$repository->getID().'/')
->appendChild(
id(new AphrontFormTextControl())
->setLabel('Name')
->setName('name')
->setValue($repository->getName())
->setError($e_name)
->setCaption('Human-readable repository name.'))
->appendChild(
id(new AphrontFormStaticControl())
->setLabel('Callsign')
->setName('callsign')
->setValue($repository->getCallsign()))
->appendChild(
id(new AphrontFormStaticControl())
->setLabel('Type')
->setName('type')
- ->setValue($repository->getVersionControlSystem()));
+ ->setValue($repository->getVersionControlSystem()))
+ ->appendChild(
+ id(new AphrontFormStaticControl())
+ ->setLabel('PHID')
+ ->setName('phid')
+ ->setValue($repository->getPHID()))
+ ->appendChild(
+ id(new AphrontFormSubmitControl())
+ ->setValue('Save'));
+
+ $panel = new AphrontPanelView();
+ $panel->setHeader('Edit Repository');
+ $panel->appendChild($form);
+ $panel->setWidth(AphrontPanelView::WIDTH_FORM);
+
+
+ $nav = $this->sideNav;
+
+ $nav->appendChild($error_view);
+ $nav->appendChild($panel);
+
+ return $this->buildStandardPageResponse(
+ $nav,
+ array(
+ 'title' => 'Edit Repository',
+ ));
+ }
+
+ private function processTrackingRequest() {
+ $request = $this->getRequest();
+ $user = $request->getUser();
+ $repository = $this->repository;
+ $repository_id = $repository->getID();
+
+ $errors = array();
+
+ $e_uri = null;
+ $e_path = null;
+
+ if ($request->isFormPost()) {
+ $tracking = ($request->getStr('tracking') == 'enabled' ? true : false);
+ $repository->setDetail('tracking-enabled', $tracking);
+ $repository->setDetail('remote-uri', $request->getStr('uri'));
+ $repository->setDetail('local-path', $request->getStr('path'));
+ $repository->setDetail(
+ 'pull-frequency',
+ max(1, $request->getInt('frequency')));
+
+ if ($tracking) {
+ if (!$repository->getDetail('remote-uri')) {
+ $e_uri = 'Required';
+ $errors[] = "Repository URI is required.";
+ }
+ if (!$repository->getDetail('local-path')) {
+ $e_path = 'Required';
+ $errors[] = "Local path is required.";
+ }
+ }
+ if (!$errors) {
+ $repository->save();
+ return id(new AphrontRedirectResponse())
+ ->setURI('/repository/edit/'.$repository_id.'/tracking/?saved=true');
+ }
+ }
+ $error_view = null;
+ if ($errors) {
+ $error_view = new AphrontErrorView();
+ $error_view->setErrors($errors);
+ $error_view->setTitle('Form Errors');
+ } else if ($request->getStr('saved')) {
+ $error_view = new AphrontErrorView();
+ $error_view->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
+ $error_view->setTitle('Changes Saved');
+ $error_view->appendChild(
+ 'Tracking changes were saved. You may need to restart the daemon '.
+ 'before changes will take effect.');
+ }
+
+ $uri_caption = null;
+ $path_caption = null;
+ switch ($repository->getVersionControlSystem()) {
+ case 'git':
+ $uri_caption =
+ 'The user the tracking daemon runs as must have permission to '.
+ '<tt>git clone</tt> from this URI.';
+ $path_caption =
+ 'Directory where the daemon should look to find a copy of the '.
+ 'repository (or create one if it does not yet exist). The daemon '.
+ 'will regularly pull remote changes into this working copy.';
+ break;
+ case 'svn':
+ $uri_caption =
+ 'The user the tracking daemon runs as must have permission to '.
+ '<tt>svn log</tt> from this URI.';
+ break;
+ }
+
+ $form = new AphrontFormView();
$form
+ ->setUser($user)
+ ->setAction('/repository/edit/'.$repository->getID().'/tracking/')
+ ->appendChild(
+ '<p class="aphront-form-instructions">Phabricator can track '.
+ 'repositories, importing commits as they happen and notifying '.
+ 'Differential, Diffusion, Herald, and other services. To enable '.
+ 'tracking for a repository, configure it here and then start (or '.
+ 'restart) the PhabricatorRepositoryTrackingDaemon.</p>')
+ ->appendChild(
+ id(new AphrontFormStaticControl())
+ ->setLabel('Repository')
+ ->setValue($repository->getName()))
+ ->appendChild(
+ id(new AphrontFormSelectControl())
+ ->setName('tracking')
+ ->setLabel('Tracking')
+ ->setOptions(array(
+ 'disabled' => 'Disabled',
+ 'enabled' => 'Enabled',
+ ))
+ ->setValue(
+ $repository->getDetail('tracking-enabled')
+ ? 'enabled'
+ : 'disabled'))
+ ->appendChild(
+ id(new AphrontFormTextControl())
+ ->setName('uri')
+ ->setLabel('URI')
+ ->setValue($repository->getDetail('remote-uri'))
+ ->setError($e_uri)
+ ->setCaption($uri_caption))
+ ->appendChild(
+ id(new AphrontFormTextControl())
+ ->setName('path')
+ ->setLabel('Local Path')
+ ->setValue($repository->getDetail('local-path'))
+ ->setError($e_path)
+ ->setCaption($path_caption))
+ ->appendChild(
+ id(new AphrontFormTextControl())
+ ->setName('frequency')
+ ->setLabel('Pull Frequency')
+ ->setValue($repository->getDetail('pull-frequency', 15))
+ ->setCaption(
+ 'Number of seconds daemon should sleep between requests. Larger '.
+ 'numbers reduce load but also decrease responsiveness.'))
->appendChild(
id(new AphrontFormSubmitControl())
- ->setValue('Save')
- ->addCancelButton('/repository/'));
+ ->setValue('Save'));
$panel = new AphrontPanelView();
- $panel->setHeader('Edit Repository');
+ $panel->setHeader('Repository Tracking');
$panel->appendChild($form);
$panel->setWidth(AphrontPanelView::WIDTH_FORM);
- $phid = $repository->getID();
+ $nav = $this->sideNav;
+ $nav->appendChild($error_view);
+ $nav->appendChild($panel);
+
+ return $this->buildStandardPageResponse(
+ $nav,
+ array(
+ 'title' => 'Edit Repository Tracking',
+ ));
+ }
+
+
+ private function processGithubRequest() {
+ $request = $this->getRequest();
+ $user = $request->getUser();
+ $repository = $this->repository;
+ $repository_id = $repository->getID();
+
$token = $repository->getDetail('github-token');
- $path = '/github-post-receive/'.$phid.'/'.$token.'/';
+ $path = '/github-post-receive/'.$repository_id.'/'.$token.'/';
$post_uri = PhabricatorEnv::getURI($path);
$gitform = new AphrontFormView();
$gitform
->setUser($user)
- ->setAction('/repository/edit/'.$repository->getID().'/')
->appendChild(
'<p class="aphront-form-instructions">You can configure GitHub to '.
'notify Phabricator after changes are pushed. Log into GitHub, go '.
'to "Admin" &rarr; "Service Hooks" &rarr; "Post-Receive URLs", and '.
'add this URL to the list. Obviously, this will only work if your '.
'Phabricator installation is accessible from the internet.</p>')
->appendChild(
'<p class="aphront-form-instructions"> If things are working '.
'properly, push notifications should appear below once you make some '.
'commits.</p>')
->appendChild(
id(new AphrontFormTextControl())
->setLabel('URL')
->setCaption('Set this as a GitHub "Post-Receive URL".')
->setValue($post_uri))
->appendChild('<br /><br />')
->appendChild('<h1>Recent Commit Notifications</h1>');
$notifications = id(new PhabricatorRepositoryGitHubNotification())
->loadAllWhere(
'repositoryPHID = %s ORDER BY id DESC limit 10',
$repository->getPHID());
$rows = array();
foreach ($notifications as $notification) {
$rows[] = array(
phutil_escape_html($notification->getRemoteAddress()),
phabricator_format_timestamp($notification->getDateCreated()),
$notification->getPayload()
? phutil_escape_html(substr($notification->getPayload(), 0, 32).'...')
: 'Empty',
);
}
$notification_table = new AphrontTableView($rows);
$notification_table->setHeaders(
array(
'Remote Address',
'Received',
'Payload',
));
$notification_table->setColumnClasses(
array(
null,
null,
'wide',
));
$notification_table->setNoDataString(
'Phabricator has not yet received any commit notifications for this '.
'repository from GitHub.');
$gitform->appendChild($notification_table);
$github = new AphrontPanelView();
$github->setHeader('GitHub Integration');
$github->appendChild($gitform);
$github->setWidth(AphrontPanelView::WIDTH_FORM);
+ $nav = $this->sideNav;
+ $nav->appendChild($github);
+
return $this->buildStandardPageResponse(
+ $nav,
array(
- $error_view,
- $panel,
- $github,
- ),
- array(
- 'title' => 'Edit Repository',
+ 'title' => 'Repository Github Integration',
));
}
-
}
diff --git a/src/applications/repository/controller/edit/__init__.php b/src/applications/repository/controller/edit/__init__.php
index 96c6efbc23..32113a75bc 100644
--- a/src/applications/repository/controller/edit/__init__.php
+++ b/src/applications/repository/controller/edit/__init__.php
@@ -1,29 +1,29 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'aphront/response/404');
phutil_require_module('phabricator', 'aphront/response/redirect');
phutil_require_module('phabricator', 'applications/base/controller/base');
phutil_require_module('phabricator', 'applications/differential/constants/revisioncontrolsystem');
phutil_require_module('phabricator', 'applications/repository/storage/githubnotification');
phutil_require_module('phabricator', 'applications/repository/storage/repository');
phutil_require_module('phabricator', 'infrastructure/env');
phutil_require_module('phabricator', 'view/control/table');
phutil_require_module('phabricator', 'view/form/base');
-phutil_require_module('phabricator', 'view/form/control/static');
phutil_require_module('phabricator', 'view/form/control/submit');
phutil_require_module('phabricator', 'view/form/error');
phutil_require_module('phabricator', 'view/layout/panel');
+phutil_require_module('phabricator', 'view/layout/sidenav');
phutil_require_module('phabricator', 'view/utils');
phutil_require_module('phutil', 'filesystem');
phutil_require_module('phutil', 'markup');
phutil_require_module('phutil', 'utils');
phutil_require_source('PhabricatorRepositoryEditController.php');
diff --git a/src/aphront/console/plugin/services/api/DarkConsoleServicesPluginAPI.php b/src/applications/repository/daemon/base/PhabricatorRepositoryDaemon.php
old mode 100755
new mode 100644
similarity index 57%
copy from src/aphront/console/plugin/services/api/DarkConsoleServicesPluginAPI.php
copy to src/applications/repository/daemon/base/PhabricatorRepositoryDaemon.php
index c652075a39..e9f2a3531a
--- a/src/aphront/console/plugin/services/api/DarkConsoleServicesPluginAPI.php
+++ b/src/applications/repository/daemon/base/PhabricatorRepositoryDaemon.php
@@ -1,35 +1,38 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* 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.
*/
-class DarkConsoleServicesPluginAPI {
+abstract class PhabricatorRepositoryDaemon extends PhabricatorDaemon {
- const EVENT_QUERY = 'query';
- const EVENT_CONNECT = 'connect';
+ protected function loadRepository() {
+ $argv = $this->getArgv();
+ if (count($argv) !== 1) {
+ throw new Exception("No repository PHID provided!");
+ }
- private static $events = array();
+ $repository = id(new PhabricatorRepository())->loadOneWhere(
+ 'phid = %s',
+ $argv[0]);
- public static function addEvent(array $event) {
- self::$events[] = $event;
- }
+ if (!$repository) {
+ throw new Exception("No such repository exists!");
+ }
- public static function getEvents() {
- return self::$events;
+ return $repository;
}
}
-
diff --git a/src/applications/repository/storage/repository/__init__.php b/src/applications/repository/daemon/base/__init__.php
similarity index 59%
copy from src/applications/repository/storage/repository/__init__.php
copy to src/applications/repository/daemon/base/__init__.php
index 1fea420fa4..97230a3be2 100644
--- a/src/applications/repository/storage/repository/__init__.php
+++ b/src/applications/repository/daemon/base/__init__.php
@@ -1,15 +1,15 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
-phutil_require_module('phabricator', 'applications/phid/storage/phid');
-phutil_require_module('phabricator', 'applications/repository/storage/base');
+phutil_require_module('phabricator', 'applications/repository/storage/repository');
+phutil_require_module('phabricator', 'infrastructure/daemon/base');
phutil_require_module('phutil', 'utils');
-phutil_require_source('PhabricatorRepository.php');
+phutil_require_source('PhabricatorRepositoryDaemon.php');
diff --git a/src/aphront/console/plugin/services/api/DarkConsoleServicesPluginAPI.php b/src/applications/repository/daemon/commitdiscovery/base/PhabricatorRepositoryCommitDiscoveryDaemon.php
old mode 100755
new mode 100644
similarity index 53%
copy from src/aphront/console/plugin/services/api/DarkConsoleServicesPluginAPI.php
copy to src/applications/repository/daemon/commitdiscovery/base/PhabricatorRepositoryCommitDiscoveryDaemon.php
index c652075a39..9defcdd53d
--- a/src/aphront/console/plugin/services/api/DarkConsoleServicesPluginAPI.php
+++ b/src/applications/repository/daemon/commitdiscovery/base/PhabricatorRepositoryCommitDiscoveryDaemon.php
@@ -1,35 +1,45 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* 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.
*/
-class DarkConsoleServicesPluginAPI {
+abstract class PhabricatorRepositoryCommitDiscoveryDaemon
+ extends PhabricatorRepositoryDaemon {
- const EVENT_QUERY = 'query';
- const EVENT_CONNECT = 'connect';
+ private $repository;
- private static $events = array();
-
- public static function addEvent(array $event) {
- self::$events[] = $event;
+ final protected function getRepository() {
+ return $this->repository;
}
- public static function getEvents() {
- return self::$events;
+ 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);
+ }
}
-}
+ abstract protected function discoverCommits();
+}
diff --git a/src/applications/repository/daemon/commitdiscovery/base/__init__.php b/src/applications/repository/daemon/commitdiscovery/base/__init__.php
new file mode 100644
index 0000000000..b48312c05a
--- /dev/null
+++ b/src/applications/repository/daemon/commitdiscovery/base/__init__.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phabricator', 'applications/repository/daemon/base');
+
+
+phutil_require_source('PhabricatorRepositoryCommitDiscoveryDaemon.php');
diff --git a/src/applications/repository/daemon/commitdiscovery/git/PhabricatorRepositoryGitCommitDiscoveryDaemon.php b/src/applications/repository/daemon/commitdiscovery/git/PhabricatorRepositoryGitCommitDiscoveryDaemon.php
new file mode 100644
index 0000000000..e70695d92e
--- /dev/null
+++ b/src/applications/repository/daemon/commitdiscovery/git/PhabricatorRepositoryGitCommitDiscoveryDaemon.php
@@ -0,0 +1,138 @@
+<?php
+
+/*
+ * Copyright 2011 Facebook, Inc.
+ *
+ * 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.
+ */
+
+class PhabricatorRepositoryGitCommitDiscoveryDaemon
+ extends PhabricatorRepositoryCommitDiscoveryDaemon {
+
+ private $lastCommit;
+ private $commitCache = array();
+
+ protected function discoverCommits() {
+ // NOTE: PhabricatorRepositoryGitPullDaemon does the actual pulls, this
+ // just parses HEAD.
+
+ $repository = $this->getRepository();
+
+ // TODO: this should be a constant somewhere
+ if ($repository->getVersionControlSystem() != '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)) {
+ 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)) {
+ echo "{$target} has parent {$parent}\n";
+ $discover[] = $parent;
+ $insert[] = $parent;
+ }
+ }
+ if (empty($discover)) {
+ break;
+ }
+ }
+
+ 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.
+ }
+ if (empty($insert)) {
+ break;
+ }
+ }
+ }
+
+ 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
new file mode 100644
index 0000000000..91b37d309a
--- /dev/null
+++ b/src/applications/repository/daemon/commitdiscovery/git/__init__.php
@@ -0,0 +1,17 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phabricator', 'applications/repository/daemon/commitdiscovery/base');
+phutil_require_module('phabricator', 'applications/repository/storage/commit');
+phutil_require_module('phabricator', 'applications/timeline/storage/event');
+
+phutil_require_module('phutil', 'future/exec');
+phutil_require_module('phutil', 'utils');
+
+
+phutil_require_source('PhabricatorRepositoryGitCommitDiscoveryDaemon.php');
diff --git a/src/aphront/console/plugin/services/api/DarkConsoleServicesPluginAPI.php b/src/applications/repository/daemon/commitparser/PhabricatorRepositoryCommitParserDaemon.php
old mode 100755
new mode 100644
similarity index 66%
copy from src/aphront/console/plugin/services/api/DarkConsoleServicesPluginAPI.php
copy to src/applications/repository/daemon/commitparser/PhabricatorRepositoryCommitParserDaemon.php
index c652075a39..d2cf1c9765
--- a/src/aphront/console/plugin/services/api/DarkConsoleServicesPluginAPI.php
+++ b/src/applications/repository/daemon/commitparser/PhabricatorRepositoryCommitParserDaemon.php
@@ -1,35 +1,22 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* 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.
*/
-class DarkConsoleServicesPluginAPI {
-
- const EVENT_QUERY = 'query';
- const EVENT_CONNECT = 'connect';
-
- private static $events = array();
-
- public static function addEvent(array $event) {
- self::$events[] = $event;
- }
-
- public static function getEvents() {
- return self::$events;
- }
+class PhabricatorRepositoryCommitParserDaemon
+ extends PhabricatorRepositoryDaemon {
}
-
diff --git a/src/applications/repository/daemon/commitparser/__init__.php b/src/applications/repository/daemon/commitparser/__init__.php
new file mode 100644
index 0000000000..73440750a7
--- /dev/null
+++ b/src/applications/repository/daemon/commitparser/__init__.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phabricator', 'applications/repository/daemon/base');
+
+
+phutil_require_source('PhabricatorRepositoryCommitParserDaemon.php');
diff --git a/src/applications/repository/daemon/gitpull/PhabricatorRepositoryGitPullDaemon.php b/src/applications/repository/daemon/gitpull/PhabricatorRepositoryGitPullDaemon.php
new file mode 100644
index 0000000000..279e77fc29
--- /dev/null
+++ b/src/applications/repository/daemon/gitpull/PhabricatorRepositoryGitPullDaemon.php
@@ -0,0 +1,55 @@
+<?php
+
+/*
+ * Copyright 2011 Facebook, Inc.
+ *
+ * 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.
+ */
+
+class PhabricatorRepositoryGitPullDaemon
+ extends PhabricatorRepositoryDaemon {
+
+ public function run() {
+ $repository = $this->loadRepository();
+
+ if ($repository->getVersionControlSystem() != 'git') {
+ throw new Exception("Not a git repository!");
+ }
+
+ $tracked = $repository->getDetail('tracking-enabled');
+ if (!$tracked) {
+ throw new Exception("Tracking is not enabled for this repository.");
+ }
+
+ $local_path = $repository->getDetail('local-path');
+ $remote_uri = $repository->getDetail('remote-uri');
+
+ if (!$local_path) {
+ throw new Exception("No local path is available for this repository.");
+ }
+
+ while (true) {
+ if (!Filesystem::pathExists($local_path)) {
+ if (!$remote_uri) {
+ throw new Exception("No remote URI is available.");
+ }
+ execx('mkdir -p %s', dirname($local_path));
+ execx('git clone %s %s', $remote_uri, rtrim($local_path, '/'));
+ } else {
+ execx('(cd %s && git pull)', $local_path);
+ }
+ $this->sleep($repository->getDetail('pull-frequency', 15));
+ }
+ }
+
+}
diff --git a/src/applications/repository/daemon/gitpull/__init__.php b/src/applications/repository/daemon/gitpull/__init__.php
new file mode 100644
index 0000000000..19e3eb4519
--- /dev/null
+++ b/src/applications/repository/daemon/gitpull/__init__.php
@@ -0,0 +1,15 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phabricator', 'applications/repository/daemon/base');
+
+phutil_require_module('phutil', 'filesystem');
+phutil_require_module('phutil', 'future/exec');
+
+
+phutil_require_source('PhabricatorRepositoryGitPullDaemon.php');
diff --git a/src/applications/repository/storage/repository/PhabricatorRepository.php b/src/applications/repository/storage/commit/PhabricatorRepositoryCommit.php
similarity index 57%
copy from src/applications/repository/storage/repository/PhabricatorRepository.php
copy to src/applications/repository/storage/commit/PhabricatorRepositoryCommit.php
index 375b957d1c..b0efefaf63 100644
--- a/src/applications/repository/storage/repository/PhabricatorRepository.php
+++ b/src/applications/repository/storage/commit/PhabricatorRepositoryCommit.php
@@ -1,50 +1,38 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* 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.
*/
-class PhabricatorRepository extends PhabricatorRepositoryDAO {
+class PhabricatorRepositoryCommit extends PhabricatorRepositoryDAO {
+ protected $repositoryPHID;
protected $phid;
- protected $name;
- protected $callsign;
-
- protected $versionControlSystem;
- protected $details = array();
+ protected $commitIdentifier;
+ protected $epoch;
public function getConfiguration() {
return array(
- self::CONFIG_AUX_PHID => true,
- self::CONFIG_SERIALIZATION => array(
- 'details' => self::SERIALIZATION_JSON,
- ),
+ self::CONFIG_AUX_PHID => true,
+ self::CONFIG_TIMESTAMPS => false,
) + parent::getConfiguration();
}
public function generatePHID() {
- return PhabricatorPHID::generateNewPHID('REPO');
- }
-
- public function getDetail($key, $default = null) {
- return idx($this->details, $key, $default);
- }
-
- public function setDetail($key, $value) {
- $this->details[$key] = $value;
- return $this;
+ return PhabricatorPHID::generateNewPHID(
+ PhabricatorPHIDConstants::PHID_TYPE_CMIT);
}
}
diff --git a/src/applications/repository/storage/repository/__init__.php b/src/applications/repository/storage/commit/__init__.php
similarity index 66%
copy from src/applications/repository/storage/repository/__init__.php
copy to src/applications/repository/storage/commit/__init__.php
index 1fea420fa4..9d410d797e 100644
--- a/src/applications/repository/storage/repository/__init__.php
+++ b/src/applications/repository/storage/commit/__init__.php
@@ -1,15 +1,14 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
+phutil_require_module('phabricator', 'applications/phid/constants');
phutil_require_module('phabricator', 'applications/phid/storage/phid');
phutil_require_module('phabricator', 'applications/repository/storage/base');
-phutil_require_module('phutil', 'utils');
-
-phutil_require_source('PhabricatorRepository.php');
+phutil_require_source('PhabricatorRepositoryCommit.php');
diff --git a/src/applications/repository/storage/repository/PhabricatorRepository.php b/src/applications/repository/storage/repository/PhabricatorRepository.php
index 375b957d1c..0301ddf1ec 100644
--- a/src/applications/repository/storage/repository/PhabricatorRepository.php
+++ b/src/applications/repository/storage/repository/PhabricatorRepository.php
@@ -1,50 +1,51 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* 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.
*/
class PhabricatorRepository extends PhabricatorRepositoryDAO {
protected $phid;
protected $name;
protected $callsign;
protected $versionControlSystem;
protected $details = array();
public function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
self::CONFIG_SERIALIZATION => array(
'details' => self::SERIALIZATION_JSON,
),
) + parent::getConfiguration();
}
public function generatePHID() {
- return PhabricatorPHID::generateNewPHID('REPO');
+ 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/storage/repository/__init__.php b/src/applications/repository/storage/repository/__init__.php
index 1fea420fa4..6480f38dac 100644
--- a/src/applications/repository/storage/repository/__init__.php
+++ b/src/applications/repository/storage/repository/__init__.php
@@ -1,15 +1,16 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
+phutil_require_module('phabricator', 'applications/phid/constants');
phutil_require_module('phabricator', 'applications/phid/storage/phid');
phutil_require_module('phabricator', 'applications/repository/storage/base');
phutil_require_module('phutil', 'utils');
phutil_require_source('PhabricatorRepository.php');
diff --git a/src/applications/timeline/cursor/iterator/PhabricatorTimelineIterator.php b/src/applications/timeline/cursor/iterator/PhabricatorTimelineIterator.php
new file mode 100644
index 0000000000..1b13cf21d8
--- /dev/null
+++ b/src/applications/timeline/cursor/iterator/PhabricatorTimelineIterator.php
@@ -0,0 +1,115 @@
+<?php
+
+/*
+ * Copyright 2011 Facebook, Inc.
+ *
+ * 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.
+ */
+
+class PhabricatorTimelineIterator implements Iterator {
+
+ protected $cursorName;
+ protected $eventTypes;
+
+ protected $cursor;
+
+ protected $index = -1;
+ protected $events = array();
+
+ const LOAD_CHUNK_SIZE = 128;
+
+ public function __construct($cursor_name, array $event_types) {
+ $this->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_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)
+ LEFT JOIN %T event_data ON event_data.eventID = event.id
+ ORDER BY event.id ASC LIMIT %d',
+ $event->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/applications/timeline/cursor/iterator/__init__.php b/src/applications/timeline/cursor/iterator/__init__.php
new file mode 100644
index 0000000000..3b881a2988
--- /dev/null
+++ b/src/applications/timeline/cursor/iterator/__init__.php
@@ -0,0 +1,17 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phabricator', 'applications/timeline/storage/cursor');
+phutil_require_module('phabricator', 'applications/timeline/storage/event');
+phutil_require_module('phabricator', 'applications/timeline/storage/eventdata');
+phutil_require_module('phabricator', 'storage/queryfx');
+
+phutil_require_module('phutil', 'utils');
+
+
+phutil_require_source('PhabricatorTimelineIterator.php');
diff --git a/src/aphront/console/plugin/services/api/DarkConsoleServicesPluginAPI.php b/src/applications/timeline/storage/base/PhabricatorTimelineDAO.php
old mode 100755
new mode 100644
similarity index 67%
copy from src/aphront/console/plugin/services/api/DarkConsoleServicesPluginAPI.php
copy to src/applications/timeline/storage/base/PhabricatorTimelineDAO.php
index c652075a39..406a3a861a
--- a/src/aphront/console/plugin/services/api/DarkConsoleServicesPluginAPI.php
+++ b/src/applications/timeline/storage/base/PhabricatorTimelineDAO.php
@@ -1,35 +1,25 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* 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.
*/
-class DarkConsoleServicesPluginAPI {
+class PhabricatorTimelineDAO extends PhabricatorLiskDAO {
- const EVENT_QUERY = 'query';
- const EVENT_CONNECT = 'connect';
-
- private static $events = array();
-
- public static function addEvent(array $event) {
- self::$events[] = $event;
- }
-
- public static function getEvents() {
- return self::$events;
+ public function getApplicationName() {
+ return 'timeline';
}
}
-
diff --git a/src/applications/timeline/storage/base/__init__.php b/src/applications/timeline/storage/base/__init__.php
new file mode 100644
index 0000000000..f97de4a9ad
--- /dev/null
+++ b/src/applications/timeline/storage/base/__init__.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phabricator', 'applications/base/storage/lisk');
+
+
+phutil_require_source('PhabricatorTimelineDAO.php');
diff --git a/src/aphront/console/plugin/services/api/DarkConsoleServicesPluginAPI.php b/src/applications/timeline/storage/cursor/PhabricatorTimelineCursor.php
old mode 100755
new mode 100644
similarity index 67%
copy from src/aphront/console/plugin/services/api/DarkConsoleServicesPluginAPI.php
copy to src/applications/timeline/storage/cursor/PhabricatorTimelineCursor.php
index c652075a39..6a1d379d5f
--- a/src/aphront/console/plugin/services/api/DarkConsoleServicesPluginAPI.php
+++ b/src/applications/timeline/storage/cursor/PhabricatorTimelineCursor.php
@@ -1,35 +1,31 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* 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.
*/
-class DarkConsoleServicesPluginAPI {
+class PhabricatorTimelineCursor extends PhabricatorTimelineDAO {
- const EVENT_QUERY = 'query';
- const EVENT_CONNECT = 'connect';
+ protected $name;
+ protected $position;
- private static $events = array();
-
- public static function addEvent(array $event) {
- self::$events[] = $event;
- }
-
- public static function getEvents() {
- return self::$events;
+ public function getConfiguration() {
+ return array(
+ self::CONFIG_IDS => self::IDS_MANUAL,
+ self::CONFIG_TIMESTAMPS => false,
+ ) + parent::getConfiguration();
}
}
-
diff --git a/src/applications/timeline/storage/cursor/__init__.php b/src/applications/timeline/storage/cursor/__init__.php
new file mode 100644
index 0000000000..486c4acd51
--- /dev/null
+++ b/src/applications/timeline/storage/cursor/__init__.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phabricator', 'applications/timeline/storage/base');
+
+
+phutil_require_source('PhabricatorTimelineCursor.php');
diff --git a/src/applications/timeline/storage/event/PhabricatorTimelineEvent.php b/src/applications/timeline/storage/event/PhabricatorTimelineEvent.php
new file mode 100644
index 0000000000..966fa4e94d
--- /dev/null
+++ b/src/applications/timeline/storage/event/PhabricatorTimelineEvent.php
@@ -0,0 +1,65 @@
+<?php
+
+/*
+ * Copyright 2011 Facebook, Inc.
+ *
+ * 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.
+ */
+
+class PhabricatorTimelineEvent extends PhabricatorTimelineDAO {
+
+ protected $type;
+ private $data;
+
+ public function __construct($type, $data = null) {
+ parent::__construct();
+
+ if (strlen($type) !== 4) {
+ throw new Exception("Event types must be exactly 4 characters long.");
+ }
+
+ $this->type = $type;
+ $this->data = $data;
+ }
+
+ public function getConfiguration() {
+ return array(
+ self::CONFIG_TIMESTAMPS => false,
+ ) + parent::getConfiguration();
+ }
+
+ public function recordEvent() {
+ if ($this->getID()) {
+ throw new Exception("Event has already been recorded!");
+ }
+
+ $this->save();
+
+ if ($this->data !== null) {
+ $data = new PhabricatorTimelineEventData();
+ $data->setEventID($this->getID());
+ $data->setEventData($this->data);
+ $data->save();
+ }
+ }
+
+ public function setData($data) {
+ $this->data = $data;
+ return $this;
+ }
+
+ public function getData() {
+ return $this->data;
+ }
+
+}
diff --git a/src/applications/timeline/storage/event/__init__.php b/src/applications/timeline/storage/event/__init__.php
new file mode 100644
index 0000000000..f1769381d5
--- /dev/null
+++ b/src/applications/timeline/storage/event/__init__.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phabricator', 'applications/timeline/storage/base');
+phutil_require_module('phabricator', 'applications/timeline/storage/eventdata');
+
+
+phutil_require_source('PhabricatorTimelineEvent.php');
diff --git a/src/aphront/console/plugin/services/api/DarkConsoleServicesPluginAPI.php b/src/applications/timeline/storage/eventdata/PhabricatorTimelineEventData.php
old mode 100755
new mode 100644
similarity index 63%
copy from src/aphront/console/plugin/services/api/DarkConsoleServicesPluginAPI.php
copy to src/applications/timeline/storage/eventdata/PhabricatorTimelineEventData.php
index c652075a39..0bcf9d3035
--- a/src/aphront/console/plugin/services/api/DarkConsoleServicesPluginAPI.php
+++ b/src/applications/timeline/storage/eventdata/PhabricatorTimelineEventData.php
@@ -1,35 +1,33 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* 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.
*/
-class DarkConsoleServicesPluginAPI {
-
- const EVENT_QUERY = 'query';
- const EVENT_CONNECT = 'connect';
-
- private static $events = array();
-
- public static function addEvent(array $event) {
- self::$events[] = $event;
- }
-
- public static function getEvents() {
- return self::$events;
+class PhabricatorTimelineEventData extends PhabricatorTimelineDAO {
+
+ protected $eventID;
+ protected $eventData;
+
+ public function getConfiguration() {
+ return array(
+ self::CONFIG_SERIALIZATION => array(
+ 'eventData' => self::SERIALIZATION_JSON,
+ ),
+ self::CONFIG_TIMESTAMPS => false,
+ ) + parent::getConfiguration();
}
}
-
diff --git a/src/applications/timeline/storage/eventdata/__init__.php b/src/applications/timeline/storage/eventdata/__init__.php
new file mode 100644
index 0000000000..bd5c020d24
--- /dev/null
+++ b/src/applications/timeline/storage/eventdata/__init__.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phabricator', 'applications/timeline/storage/base');
+
+
+phutil_require_source('PhabricatorTimelineEventData.php');
diff --git a/src/aphront/console/plugin/services/api/DarkConsoleServicesPluginAPI.php b/src/infrastructure/daemon/base/PhabricatorDaemon.php
old mode 100755
new mode 100644
similarity index 54%
copy from src/aphront/console/plugin/services/api/DarkConsoleServicesPluginAPI.php
copy to src/infrastructure/daemon/base/PhabricatorDaemon.php
index c652075a39..b1362e2806
--- a/src/aphront/console/plugin/services/api/DarkConsoleServicesPluginAPI.php
+++ b/src/infrastructure/daemon/base/PhabricatorDaemon.php
@@ -1,35 +1,33 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* 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.
*/
-class DarkConsoleServicesPluginAPI {
+abstract class PhabricatorDaemon extends PhutilDaemon {
- const EVENT_QUERY = 'query';
- const EVENT_CONNECT = 'connect';
+ protected function willRun() {
+ parent::willRun();
- private static $events = array();
+ // Both of these store unbounded amounts of log data; make them discard it
+ // instead so that daemons do not require unbounded amounts of memory.
+ DarkConsoleServicesPluginAPI::enableDiscardMode();
+ DarkConsoleErrorLogPluginAPI::enableDiscardMode();
- public static function addEvent(array $event) {
- self::$events[] = $event;
+ $phabricator = phutil_get_library_root('phabricator');
+ $root = dirname($phabricator);
+ require_once $root.'/scripts/__init_env__.php';
}
-
- public static function getEvents() {
- return self::$events;
- }
-
}
-
diff --git a/src/infrastructure/daemon/base/__init__.php b/src/infrastructure/daemon/base/__init__.php
new file mode 100644
index 0000000000..3bfdf6bd72
--- /dev/null
+++ b/src/infrastructure/daemon/base/__init__.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * This file is automatically generated. Lint this module to rebuild it.
+ * @generated
+ */
+
+
+
+phutil_require_module('phabricator', 'aphront/console/plugin/errorlog/api');
+phutil_require_module('phabricator', 'aphront/console/plugin/services/api');
+
+phutil_require_module('phutil', 'daemon/base');
+phutil_require_module('phutil', 'moduleutils');
+
+
+phutil_require_source('PhabricatorDaemon.php');
diff --git a/src/storage/connection/mysql/AphrontMySQLDatabaseConnection.php b/src/storage/connection/mysql/AphrontMySQLDatabaseConnection.php
index 3729954f5a..1463f6ef4f 100644
--- a/src/storage/connection/mysql/AphrontMySQLDatabaseConnection.php
+++ b/src/storage/connection/mysql/AphrontMySQLDatabaseConnection.php
@@ -1,248 +1,258 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* 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.
*/
/**
* @group storage
*/
class AphrontMySQLDatabaseConnection extends AphrontDatabaseConnection {
private $config;
private $connection;
private static $connectionCache = array();
public function __construct(array $configuration) {
$this->configuration = $configuration;
}
public function escapeString($string) {
$this->requireConnection();
return mysql_real_escape_string($string, $this->connection);
}
public function escapeColumnName($name) {
return '`'.str_replace('`', '\\`', $name).'`';
}
public function escapeMultilineComment($comment) {
// These can either terminate a comment, confuse the hell out of the parser,
// make MySQL execute the comment as a query, or, in the case of semicolon,
// are quasi-dangerous because the semicolon could turn a broken query into
// a working query plus an ignored query.
static $map = array(
'--' => '(DOUBLEDASH)',
'*/' => '(STARSLASH)',
'//' => '(SLASHSLASH)',
'#' => '(HASH)',
'!' => '(BANG)',
';' => '(SEMICOLON)',
);
$comment = str_replace(
array_keys($map),
array_values($map),
$comment);
// For good measure, kill anything else that isn't a nice printable
// character.
$comment = preg_replace('/[^\x20-\x7F]+/', ' ', $comment);
return '/* '.$comment.' */';
}
public function escapeStringForLikeClause($value) {
$value = $this->escapeString($value);
// Ideally the query shouldn't be modified after safely escaping it,
// but we need to escape _ and % within LIKE terms.
$value = str_replace(
// Even though we've already escaped, we need to replace \ with \\
// because MYSQL unescapes twice inside a LIKE clause. See note
// at mysql.com. However, if the \ is being used to escape a single
// quote ('), then the \ should not be escaped. Thus, after all \
// are replaced with \\, we need to revert instances of \\' back to
// \'.
array('\\', '\\\\\'', '_', '%'),
array('\\\\', '\\\'', '\_', '\%'),
$value);
return $value;
}
private function getConfiguration($key, $default = null) {
return idx($this->configuration, $key, $default);
}
private function closeConnection() {
if ($this->connection) {
$this->connection = null;
$key = $this->getConnectionCacheKey();
unset(self::$connectionCache[$key]);
}
}
private function getConnectionCacheKey() {
$user = $this->getConfiguration('user');
$host = $this->getConfiguration('host');
$database = $this->getConfiguration('database');
return "{$user}:{$host}:{$database}";
}
private function establishConnection() {
$this->closeConnection();
$user = $this->getConfiguration('user');
$host = $this->getConfiguration('host');
$database = $this->getConfiguration('database');
$key = $this->getConnectionCacheKey();
if (isset(self::$connectionCache[$key])) {
$this->connection = self::$connectionCache[$key];
return;
}
$start = microtime(true);
+ if (!function_exists('mysql_connect')) {
+ // We have to '@' the actual call since it can spew all sorts of silly
+ // noise, but it will also silence fatals caused by not having MySQL
+ // installed, which has bitten me on three separate occasions. Make sure
+ // such failures are explicit and loud.
+ throw new Exception(
+ "About to call mysql_connect(), but the PHP MySQL extension is not ".
+ "available!");
+ }
+
$conn = @mysql_connect(
$host,
$user,
$this->getConfiguration('pass'),
$new_link = true,
$flags = 0);
if (!$conn) {
$errno = mysql_errno();
$error = mysql_error();
throw new AphrontQueryConnectionException(
"Attempt to connect to {$user}@{$host} failed with error #{$errno}: ".
"{$error}.");
}
$ret = @mysql_select_db($database, $conn);
if (!$ret) {
$this->throwQueryException($conn);
}
$end = microtime(true);
DarkConsoleServicesPluginAPI::addEvent(
array(
'event' => DarkConsoleServicesPluginAPI::EVENT_CONNECT,
'host' => $host,
'database' => $database,
'start' => $start,
'end' => $end,
));
self::$connectionCache[$key] = $conn;
$this->connection = $conn;
}
public function getInsertID() {
return mysql_insert_id($this->requireConnection());
}
public function getAffectedRows() {
return mysql_affected_rows($this->requireConnection());
}
public function getTransactionKey() {
return (int)$this->requireConnection();
}
private function requireConnection() {
if (!$this->connection) {
$this->establishConnection();
}
return $this->connection;
}
public function selectAllResults() {
$result = array();
$res = $this->lastResult;
if ($res == null) {
throw new Exception('No query result to fetch from!');
}
while (($row = mysql_fetch_assoc($res)) !== false) {
$result[] = $row;
}
return $result;
}
public function executeRawQuery($raw_query) {
$this->lastResult = null;
$retries = 3;
while ($retries--) {
try {
$this->requireConnection();
$start = microtime(true);
$result = @mysql_query($raw_query, $this->connection);
$end = microtime(true);
DarkConsoleServicesPluginAPI::addEvent(
array(
'event' => DarkConsoleServicesPluginAPI::EVENT_QUERY,
'query' => $raw_query,
'start' => $start,
'end' => $end,
));
if ($result) {
$this->lastResult = $result;
break;
}
$this->throwQueryException($this->connection);
} catch (AphrontQueryConnectionLostException $ex) {
if (!$retries) {
throw $ex;
}
if ($this->isInsideTransaction()) {
throw $ex;
}
$this->closeConnection();
}
}
}
private function throwQueryException($connection) {
$errno = mysql_errno($connection);
$error = mysql_error($connection);
switch ($errno) {
case 2013: // Connection Dropped
case 2006: // Gone Away
throw new AphrontQueryConnectionLostException("#{$errno}: {$error}");
case 1213: // Deadlock
case 1205: // Lock wait timeout exceeded
throw new AphrontQueryRecoverableException("#{$errno}: {$error}");
case 1062: // Duplicate Key
// NOTE: In some versions of MySQL we get a key name back here, but
// older versions just give us a key index ("key 2") so it's not
// portable to parse the key out of the error and attach it to the
// exception.
throw new AphrontQueryDuplicateKeyException("{$errno}: {$error}");
default:
// TODO: 1064 is syntax error, and quite terrible in production.
throw new AphrontQueryException("#{$errno}: {$error}");
}
}
}

File Metadata

Mime Type
text/x-diff
Expires
Mon, Jul 28, 4:24 PM (1 w, 3 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
187112
Default Alt Text
(122 KB)

Event Timeline