Merge branch 'master' into blender-tweaks

This commit is contained in:
2018-08-02 14:26:08 +02:00
218 changed files with 5336 additions and 729 deletions

View File

@@ -9,10 +9,10 @@ return array(
'names' => array(
'conpherence.pkg.css' => 'e68cf1fa',
'conpherence.pkg.js' => '15191c65',
'core.pkg.css' => '70cc8c80',
'core.pkg.js' => 'e1f0f7bd',
'core.pkg.css' => '84d8ab9a',
'core.pkg.js' => '2058ec09',
'differential.pkg.css' => '06dc617c',
'differential.pkg.js' => 'c2ca903a',
'differential.pkg.js' => 'ef19e026',
'diffusion.pkg.css' => 'a2d17c7d',
'diffusion.pkg.js' => '6134c5a1',
'maniphest.pkg.css' => '4845691a',
@@ -111,7 +111,7 @@ return array(
'rsrc/css/application/tokens/tokens.css' => '3d0f239e',
'rsrc/css/application/uiexample/example.css' => '528b19de',
'rsrc/css/core/core.css' => '62fa3ace',
'rsrc/css/core/remarkup.css' => 'bff43c81',
'rsrc/css/core/remarkup.css' => 'b182076e',
'rsrc/css/core/syntax.css' => 'e9c95dd4',
'rsrc/css/core/z-index.css' => '9d8f7c4b',
'rsrc/css/diviner/diviner-shared.css' => '896f1d43',
@@ -144,7 +144,7 @@ return array(
'rsrc/css/phui/phui-cms.css' => '504b4b23',
'rsrc/css/phui/phui-comment-form.css' => 'ac68149f',
'rsrc/css/phui/phui-comment-panel.css' => 'f50152ad',
'rsrc/css/phui/phui-crumbs-view.css' => '6ece3bbb',
'rsrc/css/phui/phui-crumbs-view.css' => '10728aaa',
'rsrc/css/phui/phui-curtain-view.css' => '2bdaf026',
'rsrc/css/phui/phui-document-pro.css' => '8af7ea27',
'rsrc/css/phui/phui-document-summary.css' => '9ca48bdf',
@@ -154,7 +154,7 @@ return array(
'rsrc/css/phui/phui-form-view.css' => 'b446e8ff',
'rsrc/css/phui/phui-form.css' => '7aaa04e3',
'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f',
'rsrc/css/phui/phui-header-view.css' => '31dc6c72',
'rsrc/css/phui/phui-header-view.css' => 'edeb9252',
'rsrc/css/phui/phui-hovercard.css' => 'f0592bcf',
'rsrc/css/phui/phui-icon-set-selector.css' => '87db8fee',
'rsrc/css/phui/phui-icon.css' => 'cf24ceec',
@@ -167,7 +167,7 @@ return array(
'rsrc/css/phui/phui-object-box.css' => '9cff003c',
'rsrc/css/phui/phui-pager.css' => 'edcbc226',
'rsrc/css/phui/phui-pinboard-view.css' => '2495140e',
'rsrc/css/phui/phui-property-list-view.css' => 'de4754d8',
'rsrc/css/phui/phui-property-list-view.css' => '546a04ae',
'rsrc/css/phui/phui-remarkup-preview.css' => '54a34863',
'rsrc/css/phui/phui-segment-bar-view.css' => 'b1d1b892',
'rsrc/css/phui/phui-spacing.css' => '042804d6',
@@ -261,7 +261,7 @@ return array(
'rsrc/externals/javelin/lib/__tests__/URI.js' => '1e45fda9',
'rsrc/externals/javelin/lib/__tests__/behavior.js' => '1ea62783',
'rsrc/externals/javelin/lib/behavior.js' => '61cbc29a',
'rsrc/externals/javelin/lib/control/tokenizer/Tokenizer.js' => '8d3bc1b2',
'rsrc/externals/javelin/lib/control/tokenizer/Tokenizer.js' => 'bb6e5c16',
'rsrc/externals/javelin/lib/control/typeahead/Typeahead.js' => '70baed2f',
'rsrc/externals/javelin/lib/control/typeahead/normalizer/TypeaheadNormalizer.js' => '185bbd53',
'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadCompositeSource.js' => '503e17fd',
@@ -375,7 +375,7 @@ return array(
'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '453c5375',
'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => 'd4eecc63',
'rsrc/js/application/diff/DiffChangeset.js' => 'b49b59d6',
'rsrc/js/application/diff/DiffChangesetList.js' => 'e74b7517',
'rsrc/js/application/diff/DiffChangesetList.js' => 'f0ffe8c3',
'rsrc/js/application/diff/DiffInline.js' => 'e83d28f3',
'rsrc/js/application/diff/behavior-preview-link.js' => '051c7832',
'rsrc/js/application/differential/behavior-comment-preview.js' => '51c5ad07',
@@ -390,10 +390,10 @@ return array(
'rsrc/js/application/diffusion/behavior-pull-lastmodified.js' => 'f01586dc',
'rsrc/js/application/doorkeeper/behavior-doorkeeper-tag.js' => '1db13e70',
'rsrc/js/application/drydock/drydock-live-operation-status.js' => '901935ef',
'rsrc/js/application/files/behavior-document-engine.js' => 'ee0deff8',
'rsrc/js/application/files/behavior-document-engine.js' => '3935d8c4',
'rsrc/js/application/files/behavior-icon-composer.js' => '8499b6ab',
'rsrc/js/application/files/behavior-launch-icon-composer.js' => '48086888',
'rsrc/js/application/harbormaster/behavior-harbormaster-log.js' => '191b4909',
'rsrc/js/application/harbormaster/behavior-harbormaster-log.js' => '549459b8',
'rsrc/js/application/herald/HeraldRuleEditor.js' => 'dca75c0e',
'rsrc/js/application/herald/PathTypeahead.js' => '662e9cea',
'rsrc/js/application/herald/herald-rule-editor.js' => '7ebaeed3',
@@ -602,7 +602,7 @@ return array(
'javelin-behavior-diffusion-commit-graph' => '75b83cbb',
'javelin-behavior-diffusion-locate-file' => '6d3e1947',
'javelin-behavior-diffusion-pull-lastmodified' => 'f01586dc',
'javelin-behavior-document-engine' => 'ee0deff8',
'javelin-behavior-document-engine' => '3935d8c4',
'javelin-behavior-doorkeeper-tag' => '1db13e70',
'javelin-behavior-drydock-live-operation-status' => '901935ef',
'javelin-behavior-durable-column' => '2ae077e1',
@@ -611,7 +611,7 @@ return array(
'javelin-behavior-event-all-day' => 'b41537c9',
'javelin-behavior-fancy-datepicker' => 'ecf4e799',
'javelin-behavior-global-drag-and-drop' => '960f6a39',
'javelin-behavior-harbormaster-log' => '191b4909',
'javelin-behavior-harbormaster-log' => '549459b8',
'javelin-behavior-herald-rule-editor' => '7ebaeed3',
'javelin-behavior-high-security-warning' => 'a464fe03',
'javelin-behavior-history-install' => '7ee2b591',
@@ -712,7 +712,7 @@ return array(
'javelin-scrollbar' => '9065f639',
'javelin-sound' => '949c0fe5',
'javelin-stratcom' => '327f418a',
'javelin-tokenizer' => '8d3bc1b2',
'javelin-tokenizer' => 'bb6e5c16',
'javelin-typeahead' => '70baed2f',
'javelin-typeahead-composite-source' => '503e17fd',
'javelin-typeahead-normalizer' => '185bbd53',
@@ -754,7 +754,7 @@ return array(
'phabricator-darkmessage' => 'c48cccdd',
'phabricator-dashboard-css' => 'fe5b1869',
'phabricator-diff-changeset' => 'b49b59d6',
'phabricator-diff-changeset-list' => 'e74b7517',
'phabricator-diff-changeset-list' => 'f0ffe8c3',
'phabricator-diff-inline' => 'e83d28f3',
'phabricator-drag-and-drop-file-upload' => '58dea2fa',
'phabricator-draggable-list' => 'bea6e7f4',
@@ -774,7 +774,7 @@ return array(
'phabricator-object-selector-css' => '85ee8ce6',
'phabricator-phtize' => 'd254d646',
'phabricator-prefab' => '77b0ae28',
'phabricator-remarkup-css' => 'bff43c81',
'phabricator-remarkup-css' => 'b182076e',
'phabricator-search-results-css' => '505dd8cf',
'phabricator-shaped-request' => '7cbe244b',
'phabricator-slowvote-css' => 'a94b7230',
@@ -813,7 +813,7 @@ return array(
'phui-cms-css' => '504b4b23',
'phui-comment-form-css' => 'ac68149f',
'phui-comment-panel-css' => 'f50152ad',
'phui-crumbs-view-css' => '6ece3bbb',
'phui-crumbs-view-css' => '10728aaa',
'phui-curtain-view-css' => '2bdaf026',
'phui-document-summary-view-css' => '9ca48bdf',
'phui-document-view-css' => '878c2f52',
@@ -824,7 +824,7 @@ return array(
'phui-form-css' => '7aaa04e3',
'phui-form-view-css' => 'b446e8ff',
'phui-head-thing-view-css' => 'fd311e5f',
'phui-header-view-css' => '31dc6c72',
'phui-header-view-css' => 'edeb9252',
'phui-hovercard' => '1bd28176',
'phui-hovercard-view-css' => 'f0592bcf',
'phui-icon-set-selector-css' => '87db8fee',
@@ -845,7 +845,7 @@ return array(
'phui-oi-simple-ui-css' => 'a8beebea',
'phui-pager-css' => 'edcbc226',
'phui-pinboard-view-css' => '2495140e',
'phui-property-list-view-css' => 'de4754d8',
'phui-property-list-view-css' => '546a04ae',
'phui-remarkup-preview-css' => '54a34863',
'phui-segment-bar-view-css' => 'b1d1b892',
'phui-spacing-css' => '042804d6',
@@ -960,9 +960,6 @@ return array(
'185bbd53' => array(
'javelin-install',
),
'191b4909' => array(
'javelin-behavior',
),
'1ad0a787' => array(
'javelin-install',
'javelin-reactor',
@@ -1083,6 +1080,11 @@ return array(
'javelin-dom',
'javelin-vector',
),
'3935d8c4' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
),
'3ab51e2c' => array(
'javelin-behavior',
'javelin-behavior-device',
@@ -1257,6 +1259,9 @@ return array(
'javelin-vector',
'javelin-typeahead-static-source',
),
'549459b8' => array(
'javelin-behavior',
),
'54b612ba' => array(
'javelin-color',
'javelin-install',
@@ -1571,12 +1576,6 @@ return array(
'javelin-stratcom',
'javelin-behavior',
),
'8d3bc1b2' => array(
'javelin-dom',
'javelin-util',
'javelin-stratcom',
'javelin-install',
),
'8d4a8c72' => array(
'javelin-install',
'javelin-dom',
@@ -1846,6 +1845,12 @@ return array(
'javelin-uri',
'phabricator-notification',
),
'bb6e5c16' => array(
'javelin-dom',
'javelin-util',
'javelin-stratcom',
'javelin-install',
),
'bcaccd64' => array(
'javelin-behavior',
'javelin-behavior-device',
@@ -2066,10 +2071,6 @@ return array(
'javelin-behavior',
'javelin-dom',
),
'e74b7517' => array(
'javelin-install',
'phuix-button-view',
),
'e83d28f3' => array(
'javelin-dom',
),
@@ -2108,11 +2109,6 @@ return array(
'javelin-behavior',
'javelin-uri',
),
'ee0deff8' => array(
'javelin-behavior',
'javelin-dom',
'javelin-stratcom',
),
'efe49472' => array(
'javelin-install',
'javelin-util',
@@ -2124,6 +2120,10 @@ return array(
'javelin-workflow',
'javelin-json',
),
'f0ffe8c3' => array(
'javelin-install',
'phuix-button-view',
),
'f1ff5494' => array(
'phui-button-css',
'phui-button-simple-css',

View File

@@ -0,0 +1,8 @@
CREATE TABLE {$NAMESPACE}_metamta.metamta_mailproperties (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
objectPHID VARBINARY(64) NOT NULL,
mailProperties LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT},
dateCreated INT UNSIGNED NOT NULL,
dateModified INT UNSIGNED NOT NULL,
UNIQUE KEY `key_object` (objectPHID)
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};

View File

@@ -0,0 +1,14 @@
CREATE TABLE {$NAMESPACE}_repository.repository_identity (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
phid VARBINARY(64) NOT NULL,
dateCreated INT UNSIGNED NOT NULL,
dateModified INT UNSIGNED NOT NULL,
automaticGuessedUserPHID VARBINARY(64) DEFAULT NULL,
manuallySetUserPHID VARBINARY(64) DEFAULT NULL,
currentEffectiveUserPHID VARBINARY(64) DEFAULT NULL,
identityNameHash BINARY(12) NOT NULL,
identityNameRaw LONGBLOB NOT NULL,
identityNameEncoding VARCHAR(16) DEFAULT NULL COLLATE {$COLLATE_TEXT},
UNIQUE KEY `key_phid` (phid),
UNIQUE KEY `key_identity` (identityNameHash)
) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE={$COLLATE_TEXT};

View File

@@ -0,0 +1,26 @@
<?php
$packages_table = new PhabricatorOwnersPackage();
$packages_conn = $packages_table->establishConnection('w');
$packages_name = $packages_table->getTableName();
$properties_table = new PhabricatorMetaMTAMailProperties();
$conn = $properties_table->establishConnection('w');
$iterator = new LiskRawMigrationIterator($packages_conn, $packages_name);
foreach ($iterator as $package) {
queryfx(
$conn,
'INSERT IGNORE INTO %T
(objectPHID, mailProperties, dateCreated, dateModified)
VALUES
(%s, %s, %d, %d)',
$properties_table->getTableName(),
$package['phid'],
phutil_json_encode(
array(
'mailKey' => $package['mailKey'],
)),
PhabricatorTime::getNow(),
PhabricatorTime::getNow());
}

View File

@@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_owners.owners_package
DROP mailKey;

View File

@@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_owners.owners_package
ADD properties LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT};

View File

@@ -0,0 +1,2 @@
UPDATE {$NAMESPACE}_owners.owners_package
SET properties = '{}' WHERE properties = '';

View File

@@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_repository.repository_identity
ADD COLUMN authorPHID VARBINARY(64) NOT NULL;

View File

@@ -0,0 +1,19 @@
CREATE TABLE {$NAMESPACE}_repository.repository_identitytransaction (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
phid VARBINARY(64) NOT NULL,
authorPHID VARBINARY(64) NOT NULL,
objectPHID VARBINARY(64) NOT NULL,
viewPolicy VARBINARY(64) NOT NULL,
editPolicy VARBINARY(64) NOT NULL,
commentPHID VARBINARY(64) DEFAULT NULL,
commentVersion INT UNSIGNED NOT NULL,
transactionType VARCHAR(32) NOT NULL,
oldValue LONGTEXT NOT NULL,
newValue LONGTEXT NOT NULL,
contentSource LONGTEXT NOT NULL,
metadata LONGTEXT NOT NULL,
dateCreated INT UNSIGNED NOT NULL,
dateModified INT UNSIGNED NOT NULL,
UNIQUE KEY `key_phid` (`phid`),
KEY `key_object` (`objectPHID`)
) ENGINE=InnoDB DEFAULT CHARSET={$CHARSET} COLLATE {$COLLATE_TEXT};

View File

@@ -0,0 +1,3 @@
ALTER TABLE {$NAMESPACE}_repository.repository_commit
ADD COLUMN authorIdentityPHID VARBINARY(64) DEFAULT NULL,
ADD COLUMN committerIdentityPHID VARBINARY(64) DEFAULT NULL;

View File

@@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_phriction.phriction_document
ADD spacePHID VARBINARY(64) DEFAULT NULL;

View File

@@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_project.project
ADD COLUMN spacePHID VARBINARY(64) DEFAULT NULL;

View File

@@ -432,6 +432,7 @@ phutil_register_library_map(array(
'DifferentialChangesSinceLastUpdateField' => 'applications/differential/customfield/DifferentialChangesSinceLastUpdateField.php',
'DifferentialChangeset' => 'applications/differential/storage/DifferentialChangeset.php',
'DifferentialChangesetDetailView' => 'applications/differential/view/DifferentialChangesetDetailView.php',
'DifferentialChangesetEngine' => 'applications/differential/engine/DifferentialChangesetEngine.php',
'DifferentialChangesetFileTreeSideNavBuilder' => 'applications/differential/view/DifferentialChangesetFileTreeSideNavBuilder.php',
'DifferentialChangesetHTMLRenderer' => 'applications/differential/render/DifferentialChangesetHTMLRenderer.php',
'DifferentialChangesetListController' => 'applications/differential/controller/DifferentialChangesetListController.php',
@@ -814,8 +815,16 @@ phutil_register_library_map(array(
'DiffusionHistoryTableView' => 'applications/diffusion/view/DiffusionHistoryTableView.php',
'DiffusionHistoryView' => 'applications/diffusion/view/DiffusionHistoryView.php',
'DiffusionHovercardEngineExtension' => 'applications/diffusion/engineextension/DiffusionHovercardEngineExtension.php',
'DiffusionIdentityAssigneeDatasource' => 'applications/diffusion/typeahead/DiffusionIdentityAssigneeDatasource.php',
'DiffusionIdentityAssigneeEditField' => 'applications/diffusion/editfield/DiffusionIdentityAssigneeEditField.php',
'DiffusionIdentityAssigneeSearchField' => 'applications/diffusion/searchfield/DiffusionIdentityAssigneeSearchField.php',
'DiffusionIdentityEditController' => 'applications/diffusion/controller/DiffusionIdentityEditController.php',
'DiffusionIdentityListController' => 'applications/diffusion/controller/DiffusionIdentityListController.php',
'DiffusionIdentityUnassignedDatasource' => 'applications/diffusion/typeahead/DiffusionIdentityUnassignedDatasource.php',
'DiffusionIdentityViewController' => 'applications/diffusion/controller/DiffusionIdentityViewController.php',
'DiffusionInlineCommentController' => 'applications/diffusion/controller/DiffusionInlineCommentController.php',
'DiffusionInlineCommentPreviewController' => 'applications/diffusion/controller/DiffusionInlineCommentPreviewController.php',
'DiffusionInternalAncestorsConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionInternalAncestorsConduitAPIMethod.php',
'DiffusionInternalGitRawDiffQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionInternalGitRawDiffQueryConduitAPIMethod.php',
'DiffusionLastModifiedController' => 'applications/diffusion/controller/DiffusionLastModifiedController.php',
'DiffusionLastModifiedQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionLastModifiedQueryConduitAPIMethod.php',
@@ -935,6 +944,8 @@ phutil_register_library_map(array(
'DiffusionRepositoryEditUpdateController' => 'applications/diffusion/controller/DiffusionRepositoryEditUpdateController.php',
'DiffusionRepositoryFunctionDatasource' => 'applications/diffusion/typeahead/DiffusionRepositoryFunctionDatasource.php',
'DiffusionRepositoryHistoryManagementPanel' => 'applications/diffusion/management/DiffusionRepositoryHistoryManagementPanel.php',
'DiffusionRepositoryIdentityEditor' => 'applications/diffusion/editor/DiffusionRepositoryIdentityEditor.php',
'DiffusionRepositoryIdentitySearchEngine' => 'applications/diffusion/query/DiffusionRepositoryIdentitySearchEngine.php',
'DiffusionRepositoryListController' => 'applications/diffusion/controller/DiffusionRepositoryListController.php',
'DiffusionRepositoryManageController' => 'applications/diffusion/controller/DiffusionRepositoryManageController.php',
'DiffusionRepositoryManagePanelsController' => 'applications/diffusion/controller/DiffusionRepositoryManagePanelsController.php',
@@ -1430,6 +1441,7 @@ phutil_register_library_map(array(
'HeraldActionGroup' => 'applications/herald/action/HeraldActionGroup.php',
'HeraldActionRecord' => 'applications/herald/storage/HeraldActionRecord.php',
'HeraldAdapter' => 'applications/herald/adapter/HeraldAdapter.php',
'HeraldAdapterDatasource' => 'applications/herald/typeahead/HeraldAdapterDatasource.php',
'HeraldAlwaysField' => 'applications/herald/field/HeraldAlwaysField.php',
'HeraldAnotherRuleField' => 'applications/herald/field/HeraldAnotherRuleField.php',
'HeraldApplicationActionGroup' => 'applications/herald/action/HeraldApplicationActionGroup.php',
@@ -1485,12 +1497,17 @@ phutil_register_library_map(array(
'HeraldRemarkupFieldValue' => 'applications/herald/value/HeraldRemarkupFieldValue.php',
'HeraldRemarkupRule' => 'applications/herald/remarkup/HeraldRemarkupRule.php',
'HeraldRule' => 'applications/herald/storage/HeraldRule.php',
'HeraldRuleAdapter' => 'applications/herald/adapter/HeraldRuleAdapter.php',
'HeraldRuleAdapterField' => 'applications/herald/field/rule/HeraldRuleAdapterField.php',
'HeraldRuleController' => 'applications/herald/controller/HeraldRuleController.php',
'HeraldRuleDatasource' => 'applications/herald/typeahead/HeraldRuleDatasource.php',
'HeraldRuleEditor' => 'applications/herald/editor/HeraldRuleEditor.php',
'HeraldRuleField' => 'applications/herald/field/rule/HeraldRuleField.php',
'HeraldRuleFieldGroup' => 'applications/herald/field/rule/HeraldRuleFieldGroup.php',
'HeraldRuleListController' => 'applications/herald/controller/HeraldRuleListController.php',
'HeraldRulePHIDType' => 'applications/herald/phid/HeraldRulePHIDType.php',
'HeraldRuleQuery' => 'applications/herald/query/HeraldRuleQuery.php',
'HeraldRuleReplyHandler' => 'applications/herald/mail/HeraldRuleReplyHandler.php',
'HeraldRuleSearchEngine' => 'applications/herald/query/HeraldRuleSearchEngine.php',
'HeraldRuleSerializer' => 'applications/herald/editor/HeraldRuleSerializer.php',
'HeraldRuleTestCase' => 'applications/herald/storage/__tests__/HeraldRuleTestCase.php',
@@ -1498,6 +1515,8 @@ phutil_register_library_map(array(
'HeraldRuleTransactionComment' => 'applications/herald/storage/HeraldRuleTransactionComment.php',
'HeraldRuleTranscript' => 'applications/herald/storage/transcript/HeraldRuleTranscript.php',
'HeraldRuleTypeConfig' => 'applications/herald/config/HeraldRuleTypeConfig.php',
'HeraldRuleTypeDatasource' => 'applications/herald/typeahead/HeraldRuleTypeDatasource.php',
'HeraldRuleTypeField' => 'applications/herald/field/rule/HeraldRuleTypeField.php',
'HeraldRuleViewController' => 'applications/herald/controller/HeraldRuleViewController.php',
'HeraldSchemaSpec' => 'applications/herald/storage/HeraldSchemaSpec.php',
'HeraldSelectFieldValue' => 'applications/herald/value/HeraldSelectFieldValue.php',
@@ -2521,6 +2540,7 @@ phutil_register_library_map(array(
'PhabricatorChatLogDAO' => 'applications/chatlog/storage/PhabricatorChatLogDAO.php',
'PhabricatorChatLogEvent' => 'applications/chatlog/storage/PhabricatorChatLogEvent.php',
'PhabricatorChatLogQuery' => 'applications/chatlog/query/PhabricatorChatLogQuery.php',
'PhabricatorCheckboxesEditField' => 'applications/transactions/editfield/PhabricatorCheckboxesEditField.php',
'PhabricatorChunkedFileStorageEngine' => 'applications/files/engine/PhabricatorChunkedFileStorageEngine.php',
'PhabricatorClassConfigType' => 'applications/config/type/PhabricatorClassConfigType.php',
'PhabricatorClusterConfigOptions' => 'applications/config/option/PhabricatorClusterConfigOptions.php',
@@ -2863,6 +2883,7 @@ phutil_register_library_map(array(
'PhabricatorDifferentialExtractWorkflow' => 'applications/differential/management/PhabricatorDifferentialExtractWorkflow.php',
'PhabricatorDifferentialManagementWorkflow' => 'applications/differential/management/PhabricatorDifferentialManagementWorkflow.php',
'PhabricatorDifferentialMigrateHunkWorkflow' => 'applications/differential/management/PhabricatorDifferentialMigrateHunkWorkflow.php',
'PhabricatorDifferentialRebuildChangesetsWorkflow' => 'applications/differential/management/PhabricatorDifferentialRebuildChangesetsWorkflow.php',
'PhabricatorDifferentialRevisionTestDataGenerator' => 'applications/differential/lipsum/PhabricatorDifferentialRevisionTestDataGenerator.php',
'PhabricatorDiffusionApplication' => 'applications/diffusion/application/PhabricatorDiffusionApplication.php',
'PhabricatorDiffusionBlameSetting' => 'applications/settings/setting/PhabricatorDiffusionBlameSetting.php',
@@ -2877,6 +2898,7 @@ phutil_register_library_map(array(
'PhabricatorDocumentRef' => 'applications/files/document/PhabricatorDocumentRef.php',
'PhabricatorDocumentRenderingEngine' => 'applications/files/document/render/PhabricatorDocumentRenderingEngine.php',
'PhabricatorDoorkeeperApplication' => 'applications/doorkeeper/application/PhabricatorDoorkeeperApplication.php',
'PhabricatorDoubleExportField' => 'infrastructure/export/field/PhabricatorDoubleExportField.php',
'PhabricatorDraft' => 'applications/draft/storage/PhabricatorDraft.php',
'PhabricatorDraftDAO' => 'applications/draft/storage/PhabricatorDraftDAO.php',
'PhabricatorDraftEngine' => 'applications/transactions/draft/PhabricatorDraftEngine.php',
@@ -3350,6 +3372,7 @@ phutil_register_library_map(array(
'PhabricatorMailOutboundRoutingSelfEmailHeraldAction' => 'applications/metamta/herald/PhabricatorMailOutboundRoutingSelfEmailHeraldAction.php',
'PhabricatorMailOutboundRoutingSelfNotificationHeraldAction' => 'applications/metamta/herald/PhabricatorMailOutboundRoutingSelfNotificationHeraldAction.php',
'PhabricatorMailOutboundStatus' => 'applications/metamta/constants/PhabricatorMailOutboundStatus.php',
'PhabricatorMailPropertiesDestructionEngineExtension' => 'applications/metamta/engineextension/PhabricatorMailPropertiesDestructionEngineExtension.php',
'PhabricatorMailReceiver' => 'applications/metamta/receiver/PhabricatorMailReceiver.php',
'PhabricatorMailReceiverTestCase' => 'applications/metamta/receiver/__tests__/PhabricatorMailReceiverTestCase.php',
'PhabricatorMailReplyHandler' => 'applications/metamta/replyhandler/PhabricatorMailReplyHandler.php',
@@ -3407,6 +3430,8 @@ phutil_register_library_map(array(
'PhabricatorMetaMTAMailHasRecipientEdgeType' => 'applications/metamta/edge/PhabricatorMetaMTAMailHasRecipientEdgeType.php',
'PhabricatorMetaMTAMailListController' => 'applications/metamta/controller/PhabricatorMetaMTAMailListController.php',
'PhabricatorMetaMTAMailPHIDType' => 'applications/metamta/phid/PhabricatorMetaMTAMailPHIDType.php',
'PhabricatorMetaMTAMailProperties' => 'applications/metamta/storage/PhabricatorMetaMTAMailProperties.php',
'PhabricatorMetaMTAMailPropertiesQuery' => 'applications/metamta/query/PhabricatorMetaMTAMailPropertiesQuery.php',
'PhabricatorMetaMTAMailQuery' => 'applications/metamta/query/PhabricatorMetaMTAMailQuery.php',
'PhabricatorMetaMTAMailSearchEngine' => 'applications/metamta/query/PhabricatorMetaMTAMailSearchEngine.php',
'PhabricatorMetaMTAMailSection' => 'applications/metamta/view/PhabricatorMetaMTAMailSection.php',
@@ -3565,6 +3590,7 @@ phutil_register_library_map(array(
'PhabricatorOwnersPackageFerretEngine' => 'applications/owners/search/PhabricatorOwnersPackageFerretEngine.php',
'PhabricatorOwnersPackageFulltextEngine' => 'applications/owners/search/PhabricatorOwnersPackageFulltextEngine.php',
'PhabricatorOwnersPackageFunctionDatasource' => 'applications/owners/typeahead/PhabricatorOwnersPackageFunctionDatasource.php',
'PhabricatorOwnersPackageIgnoredTransaction' => 'applications/owners/xaction/PhabricatorOwnersPackageIgnoredTransaction.php',
'PhabricatorOwnersPackageNameNgrams' => 'applications/owners/storage/PhabricatorOwnersPackageNameNgrams.php',
'PhabricatorOwnersPackageNameTransaction' => 'applications/owners/xaction/PhabricatorOwnersPackageNameTransaction.php',
'PhabricatorOwnersPackageOwnerDatasource' => 'applications/owners/typeahead/PhabricatorOwnersPackageOwnerDatasource.php',
@@ -3860,6 +3886,7 @@ phutil_register_library_map(array(
'PhabricatorPolicyRequestExceptionHandler' => 'aphront/handler/PhabricatorPolicyRequestExceptionHandler.php',
'PhabricatorPolicyRule' => 'applications/policy/rule/PhabricatorPolicyRule.php',
'PhabricatorPolicySearchEngineExtension' => 'applications/policy/engineextension/PhabricatorPolicySearchEngineExtension.php',
'PhabricatorPolicyStrengthConstants' => 'applications/policy/constants/PhabricatorPolicyStrengthConstants.php',
'PhabricatorPolicyTestCase' => 'applications/policy/__tests__/PhabricatorPolicyTestCase.php',
'PhabricatorPolicyTestObject' => 'applications/policy/__tests__/PhabricatorPolicyTestObject.php',
'PhabricatorPolicyType' => 'applications/policy/constants/PhabricatorPolicyType.php',
@@ -4003,7 +4030,9 @@ phutil_register_library_map(array(
'PhabricatorProjectWorkboardBackgroundTransaction' => 'applications/project/xaction/PhabricatorProjectWorkboardBackgroundTransaction.php',
'PhabricatorProjectWorkboardProfileMenuItem' => 'applications/project/menuitem/PhabricatorProjectWorkboardProfileMenuItem.php',
'PhabricatorProjectWorkboardTransaction' => 'applications/project/xaction/PhabricatorProjectWorkboardTransaction.php',
'PhabricatorProjectsAllPolicyRule' => 'applications/project/policyrule/PhabricatorProjectsAllPolicyRule.php',
'PhabricatorProjectsAncestorsSearchEngineAttachment' => 'applications/project/engineextension/PhabricatorProjectsAncestorsSearchEngineAttachment.php',
'PhabricatorProjectsBasePolicyRule' => 'applications/project/policyrule/PhabricatorProjectsBasePolicyRule.php',
'PhabricatorProjectsCurtainExtension' => 'applications/project/engineextension/PhabricatorProjectsCurtainExtension.php',
'PhabricatorProjectsEditEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsEditEngineExtension.php',
'PhabricatorProjectsEditField' => 'applications/transactions/editfield/PhabricatorProjectsEditField.php',
@@ -4020,6 +4049,7 @@ phutil_register_library_map(array(
'PhabricatorPygmentSetupCheck' => 'applications/config/check/PhabricatorPygmentSetupCheck.php',
'PhabricatorQuery' => 'infrastructure/query/PhabricatorQuery.php',
'PhabricatorQueryConstraint' => 'infrastructure/query/constraint/PhabricatorQueryConstraint.php',
'PhabricatorQueryIterator' => 'infrastructure/storage/lisk/PhabricatorQueryIterator.php',
'PhabricatorQueryOrderItem' => 'infrastructure/query/order/PhabricatorQueryOrderItem.php',
'PhabricatorQueryOrderTestCase' => 'infrastructure/query/order/__tests__/PhabricatorQueryOrderTestCase.php',
'PhabricatorQueryOrderVector' => 'infrastructure/query/order/PhabricatorQueryOrderVector.php',
@@ -4070,6 +4100,16 @@ phutil_register_library_map(array(
'PhabricatorRepositoryGitLFSRefQuery' => 'applications/repository/query/PhabricatorRepositoryGitLFSRefQuery.php',
'PhabricatorRepositoryGraphCache' => 'applications/repository/graphcache/PhabricatorRepositoryGraphCache.php',
'PhabricatorRepositoryGraphStream' => 'applications/repository/daemon/PhabricatorRepositoryGraphStream.php',
'PhabricatorRepositoryIdentity' => 'applications/repository/storage/PhabricatorRepositoryIdentity.php',
'PhabricatorRepositoryIdentityAssignTransaction' => 'applications/repository/xaction/PhabricatorRepositoryIdentityAssignTransaction.php',
'PhabricatorRepositoryIdentityChangeWorker' => 'applications/repository/worker/PhabricatorRepositoryIdentityChangeWorker.php',
'PhabricatorRepositoryIdentityEditEngine' => 'applications/repository/engine/PhabricatorRepositoryIdentityEditEngine.php',
'PhabricatorRepositoryIdentityFerretEngine' => 'applications/repository/search/PhabricatorRepositoryIdentityFerretEngine.php',
'PhabricatorRepositoryIdentityPHIDType' => 'applications/repository/phid/PhabricatorRepositoryIdentityPHIDType.php',
'PhabricatorRepositoryIdentityQuery' => 'applications/repository/query/PhabricatorRepositoryIdentityQuery.php',
'PhabricatorRepositoryIdentityTransaction' => 'applications/repository/storage/PhabricatorRepositoryIdentityTransaction.php',
'PhabricatorRepositoryIdentityTransactionQuery' => 'applications/repository/query/PhabricatorRepositoryIdentityTransactionQuery.php',
'PhabricatorRepositoryIdentityTransactionType' => 'applications/repository/xaction/PhabricatorRepositoryIdentityTransactionType.php',
'PhabricatorRepositoryManagementCacheWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementCacheWorkflow.php',
'PhabricatorRepositoryManagementClusterizeWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementClusterizeWorkflow.php',
'PhabricatorRepositoryManagementDiscoverWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementDiscoverWorkflow.php',
@@ -4084,6 +4124,7 @@ phutil_register_library_map(array(
'PhabricatorRepositoryManagementMovePathsWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementMovePathsWorkflow.php',
'PhabricatorRepositoryManagementParentsWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementParentsWorkflow.php',
'PhabricatorRepositoryManagementPullWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementPullWorkflow.php',
'PhabricatorRepositoryManagementRebuildIdentitiesWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementRebuildIdentitiesWorkflow.php',
'PhabricatorRepositoryManagementRefsWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementRefsWorkflow.php',
'PhabricatorRepositoryManagementReparseWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementReparseWorkflow.php',
'PhabricatorRepositoryManagementThawWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementThawWorkflow.php',
@@ -4415,6 +4456,7 @@ phutil_register_library_map(array(
'PhabricatorSystemDAO' => 'applications/system/storage/PhabricatorSystemDAO.php',
'PhabricatorSystemDestructionGarbageCollector' => 'applications/system/garbagecollector/PhabricatorSystemDestructionGarbageCollector.php',
'PhabricatorSystemDestructionLog' => 'applications/system/storage/PhabricatorSystemDestructionLog.php',
'PhabricatorSystemObjectController' => 'applications/system/controller/PhabricatorSystemObjectController.php',
'PhabricatorSystemReadOnlyController' => 'applications/system/controller/PhabricatorSystemReadOnlyController.php',
'PhabricatorSystemRemoveDestroyWorkflow' => 'applications/system/management/PhabricatorSystemRemoveDestroyWorkflow.php',
'PhabricatorSystemRemoveLogWorkflow' => 'applications/system/management/PhabricatorSystemRemoveLogWorkflow.php',
@@ -4992,6 +5034,7 @@ phutil_register_library_map(array(
'PhrictionDocumentMoveToTransaction' => 'applications/phriction/xaction/PhrictionDocumentMoveToTransaction.php',
'PhrictionDocumentPHIDType' => 'applications/phriction/phid/PhrictionDocumentPHIDType.php',
'PhrictionDocumentPathHeraldField' => 'applications/phriction/herald/PhrictionDocumentPathHeraldField.php',
'PhrictionDocumentPolicyCodex' => 'applications/phriction/codex/PhrictionDocumentPolicyCodex.php',
'PhrictionDocumentQuery' => 'applications/phriction/query/PhrictionDocumentQuery.php',
'PhrictionDocumentSearchConduitAPIMethod' => 'applications/phriction/conduit/PhrictionDocumentSearchConduitAPIMethod.php',
'PhrictionDocumentSearchEngine' => 'applications/phriction/query/PhrictionDocumentSearchEngine.php',
@@ -5718,6 +5761,7 @@ phutil_register_library_map(array(
'PhabricatorDestructibleInterface',
),
'DifferentialChangesetDetailView' => 'AphrontView',
'DifferentialChangesetEngine' => 'Phobject',
'DifferentialChangesetFileTreeSideNavBuilder' => 'Phobject',
'DifferentialChangesetHTMLRenderer' => 'DifferentialChangesetRenderer',
'DifferentialChangesetListController' => 'DifferentialController',
@@ -6138,8 +6182,16 @@ phutil_register_library_map(array(
'DiffusionHistoryTableView' => 'DiffusionHistoryView',
'DiffusionHistoryView' => 'DiffusionView',
'DiffusionHovercardEngineExtension' => 'PhabricatorHovercardEngineExtension',
'DiffusionIdentityAssigneeDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
'DiffusionIdentityAssigneeEditField' => 'PhabricatorTokenizerEditField',
'DiffusionIdentityAssigneeSearchField' => 'PhabricatorSearchTokenizerField',
'DiffusionIdentityEditController' => 'DiffusionController',
'DiffusionIdentityListController' => 'DiffusionController',
'DiffusionIdentityUnassignedDatasource' => 'PhabricatorTypeaheadDatasource',
'DiffusionIdentityViewController' => 'DiffusionController',
'DiffusionInlineCommentController' => 'PhabricatorInlineCommentController',
'DiffusionInlineCommentPreviewController' => 'PhabricatorInlineCommentPreviewController',
'DiffusionInternalAncestorsConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
'DiffusionInternalGitRawDiffQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
'DiffusionLastModifiedController' => 'DiffusionController',
'DiffusionLastModifiedQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
@@ -6258,6 +6310,8 @@ phutil_register_library_map(array(
'DiffusionRepositoryEditUpdateController' => 'DiffusionRepositoryManageController',
'DiffusionRepositoryFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
'DiffusionRepositoryHistoryManagementPanel' => 'DiffusionRepositoryManagementPanel',
'DiffusionRepositoryIdentityEditor' => 'PhabricatorApplicationTransactionEditor',
'DiffusionRepositoryIdentitySearchEngine' => 'PhabricatorApplicationSearchEngine',
'DiffusionRepositoryListController' => 'DiffusionController',
'DiffusionRepositoryManageController' => 'DiffusionController',
'DiffusionRepositoryManagePanelsController' => 'DiffusionRepositoryManageController',
@@ -6854,6 +6908,7 @@ phutil_register_library_map(array(
'HeraldActionGroup' => 'HeraldGroup',
'HeraldActionRecord' => 'HeraldDAO',
'HeraldAdapter' => 'Phobject',
'HeraldAdapterDatasource' => 'PhabricatorTypeaheadDatasource',
'HeraldAlwaysField' => 'HeraldField',
'HeraldAnotherRuleField' => 'HeraldField',
'HeraldApplicationActionGroup' => 'HeraldActionGroup',
@@ -6922,12 +6977,17 @@ phutil_register_library_map(array(
'PhabricatorDestructibleInterface',
'PhabricatorSubscribableInterface',
),
'HeraldRuleAdapter' => 'HeraldAdapter',
'HeraldRuleAdapterField' => 'HeraldRuleField',
'HeraldRuleController' => 'HeraldController',
'HeraldRuleDatasource' => 'PhabricatorTypeaheadDatasource',
'HeraldRuleEditor' => 'PhabricatorApplicationTransactionEditor',
'HeraldRuleField' => 'HeraldField',
'HeraldRuleFieldGroup' => 'HeraldFieldGroup',
'HeraldRuleListController' => 'HeraldController',
'HeraldRulePHIDType' => 'PhabricatorPHIDType',
'HeraldRuleQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'HeraldRuleReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler',
'HeraldRuleSearchEngine' => 'PhabricatorApplicationSearchEngine',
'HeraldRuleSerializer' => 'Phobject',
'HeraldRuleTestCase' => 'PhabricatorTestCase',
@@ -6935,6 +6995,8 @@ phutil_register_library_map(array(
'HeraldRuleTransactionComment' => 'PhabricatorApplicationTransactionComment',
'HeraldRuleTranscript' => 'Phobject',
'HeraldRuleTypeConfig' => 'Phobject',
'HeraldRuleTypeDatasource' => 'PhabricatorTypeaheadDatasource',
'HeraldRuleTypeField' => 'HeraldRuleField',
'HeraldRuleViewController' => 'HeraldController',
'HeraldSchemaSpec' => 'PhabricatorConfigSchemaSpec',
'HeraldSelectFieldValue' => 'HeraldFieldValue',
@@ -8129,6 +8191,7 @@ phutil_register_library_map(array(
'PhabricatorPolicyInterface',
),
'PhabricatorChatLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorCheckboxesEditField' => 'PhabricatorEditField',
'PhabricatorChunkedFileStorageEngine' => 'PhabricatorFileStorageEngine',
'PhabricatorClassConfigType' => 'PhabricatorTextConfigType',
'PhabricatorClusterConfigOptions' => 'PhabricatorApplicationConfigOptions',
@@ -8513,6 +8576,7 @@ phutil_register_library_map(array(
'PhabricatorDifferentialExtractWorkflow' => 'PhabricatorDifferentialManagementWorkflow',
'PhabricatorDifferentialManagementWorkflow' => 'PhabricatorManagementWorkflow',
'PhabricatorDifferentialMigrateHunkWorkflow' => 'PhabricatorDifferentialManagementWorkflow',
'PhabricatorDifferentialRebuildChangesetsWorkflow' => 'PhabricatorDifferentialManagementWorkflow',
'PhabricatorDifferentialRevisionTestDataGenerator' => 'PhabricatorTestDataGenerator',
'PhabricatorDiffusionApplication' => 'PhabricatorApplication',
'PhabricatorDiffusionBlameSetting' => 'PhabricatorInternalSetting',
@@ -8527,6 +8591,7 @@ phutil_register_library_map(array(
'PhabricatorDocumentRef' => 'Phobject',
'PhabricatorDocumentRenderingEngine' => 'Phobject',
'PhabricatorDoorkeeperApplication' => 'PhabricatorApplication',
'PhabricatorDoubleExportField' => 'PhabricatorExportField',
'PhabricatorDraft' => 'PhabricatorDraftDAO',
'PhabricatorDraftDAO' => 'PhabricatorLiskDAO',
'PhabricatorDraftEngine' => 'Phobject',
@@ -9049,6 +9114,7 @@ phutil_register_library_map(array(
'PhabricatorMailOutboundRoutingSelfEmailHeraldAction' => 'PhabricatorMailOutboundRoutingHeraldAction',
'PhabricatorMailOutboundRoutingSelfNotificationHeraldAction' => 'PhabricatorMailOutboundRoutingHeraldAction',
'PhabricatorMailOutboundStatus' => 'Phobject',
'PhabricatorMailPropertiesDestructionEngineExtension' => 'PhabricatorDestructionEngineExtension',
'PhabricatorMailReceiver' => 'Phobject',
'PhabricatorMailReceiverTestCase' => 'PhabricatorTestCase',
'PhabricatorMailReplyHandler' => 'Phobject',
@@ -9117,6 +9183,11 @@ phutil_register_library_map(array(
'PhabricatorMetaMTAMailHasRecipientEdgeType' => 'PhabricatorEdgeType',
'PhabricatorMetaMTAMailListController' => 'PhabricatorMetaMTAController',
'PhabricatorMetaMTAMailPHIDType' => 'PhabricatorPHIDType',
'PhabricatorMetaMTAMailProperties' => array(
'PhabricatorMetaMTADAO',
'PhabricatorPolicyInterface',
),
'PhabricatorMetaMTAMailPropertiesQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorMetaMTAMailQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorMetaMTAMailSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhabricatorMetaMTAMailSection' => 'Phobject',
@@ -9305,6 +9376,7 @@ phutil_register_library_map(array(
'PhabricatorOwnersPackageFerretEngine' => 'PhabricatorFerretEngine',
'PhabricatorOwnersPackageFulltextEngine' => 'PhabricatorFulltextEngine',
'PhabricatorOwnersPackageFunctionDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
'PhabricatorOwnersPackageIgnoredTransaction' => 'PhabricatorOwnersPackageTransactionType',
'PhabricatorOwnersPackageNameNgrams' => 'PhabricatorSearchNgrams',
'PhabricatorOwnersPackageNameTransaction' => 'PhabricatorOwnersPackageTransactionType',
'PhabricatorOwnersPackageOwnerDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
@@ -9655,6 +9727,7 @@ phutil_register_library_map(array(
'PhabricatorPolicyRequestExceptionHandler' => 'PhabricatorRequestExceptionHandler',
'PhabricatorPolicyRule' => 'Phobject',
'PhabricatorPolicySearchEngineExtension' => 'PhabricatorSearchEngineExtension',
'PhabricatorPolicyStrengthConstants' => 'PhabricatorPolicyConstants',
'PhabricatorPolicyTestCase' => 'PhabricatorTestCase',
'PhabricatorPolicyTestObject' => array(
'Phobject',
@@ -9690,6 +9763,7 @@ phutil_register_library_map(array(
'PhabricatorFerretInterface',
'PhabricatorConduitResultInterface',
'PhabricatorColumnProxyInterface',
'PhabricatorSpacesInterface',
),
'PhabricatorProjectAddHeraldAction' => 'PhabricatorProjectHeraldAction',
'PhabricatorProjectApplication' => 'PhabricatorApplication',
@@ -9834,7 +9908,9 @@ phutil_register_library_map(array(
'PhabricatorProjectWorkboardBackgroundTransaction' => 'PhabricatorProjectTransactionType',
'PhabricatorProjectWorkboardProfileMenuItem' => 'PhabricatorProfileMenuItem',
'PhabricatorProjectWorkboardTransaction' => 'PhabricatorProjectTransactionType',
'PhabricatorProjectsAllPolicyRule' => 'PhabricatorProjectsBasePolicyRule',
'PhabricatorProjectsAncestorsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
'PhabricatorProjectsBasePolicyRule' => 'PhabricatorPolicyRule',
'PhabricatorProjectsCurtainExtension' => 'PHUICurtainExtension',
'PhabricatorProjectsEditEngineExtension' => 'PhabricatorEditEngineExtension',
'PhabricatorProjectsEditField' => 'PhabricatorTokenizerEditField',
@@ -9843,7 +9919,7 @@ phutil_register_library_map(array(
'PhabricatorProjectsMailEngineExtension' => 'PhabricatorMailEngineExtension',
'PhabricatorProjectsMembersSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
'PhabricatorProjectsMembershipIndexEngineExtension' => 'PhabricatorIndexEngineExtension',
'PhabricatorProjectsPolicyRule' => 'PhabricatorPolicyRule',
'PhabricatorProjectsPolicyRule' => 'PhabricatorProjectsBasePolicyRule',
'PhabricatorProjectsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
'PhabricatorProjectsSearchEngineExtension' => 'PhabricatorSearchEngineExtension',
'PhabricatorProjectsWatchersSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
@@ -9851,6 +9927,7 @@ phutil_register_library_map(array(
'PhabricatorPygmentSetupCheck' => 'PhabricatorSetupCheck',
'PhabricatorQuery' => 'Phobject',
'PhabricatorQueryConstraint' => 'Phobject',
'PhabricatorQueryIterator' => 'PhutilBufferedIterator',
'PhabricatorQueryOrderItem' => 'Phobject',
'PhabricatorQueryOrderTestCase' => 'PhabricatorTestCase',
'PhabricatorQueryOrderVector' => array(
@@ -9944,6 +10021,20 @@ phutil_register_library_map(array(
'PhabricatorRepositoryGitLFSRefQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorRepositoryGraphCache' => 'Phobject',
'PhabricatorRepositoryGraphStream' => 'Phobject',
'PhabricatorRepositoryIdentity' => array(
'PhabricatorRepositoryDAO',
'PhabricatorPolicyInterface',
'PhabricatorApplicationTransactionInterface',
),
'PhabricatorRepositoryIdentityAssignTransaction' => 'PhabricatorRepositoryIdentityTransactionType',
'PhabricatorRepositoryIdentityChangeWorker' => 'PhabricatorWorker',
'PhabricatorRepositoryIdentityEditEngine' => 'PhabricatorEditEngine',
'PhabricatorRepositoryIdentityFerretEngine' => 'PhabricatorFerretEngine',
'PhabricatorRepositoryIdentityPHIDType' => 'PhabricatorPHIDType',
'PhabricatorRepositoryIdentityQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorRepositoryIdentityTransaction' => 'PhabricatorModularTransaction',
'PhabricatorRepositoryIdentityTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhabricatorRepositoryIdentityTransactionType' => 'PhabricatorModularTransactionType',
'PhabricatorRepositoryManagementCacheWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
'PhabricatorRepositoryManagementClusterizeWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
'PhabricatorRepositoryManagementDiscoverWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
@@ -9958,6 +10049,7 @@ phutil_register_library_map(array(
'PhabricatorRepositoryManagementMovePathsWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
'PhabricatorRepositoryManagementParentsWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
'PhabricatorRepositoryManagementPullWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
'PhabricatorRepositoryManagementRebuildIdentitiesWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
'PhabricatorRepositoryManagementRefsWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
'PhabricatorRepositoryManagementReparseWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
'PhabricatorRepositoryManagementThawWorkflow' => 'PhabricatorRepositoryManagementWorkflow',
@@ -10328,6 +10420,7 @@ phutil_register_library_map(array(
'PhabricatorSystemDAO' => 'PhabricatorLiskDAO',
'PhabricatorSystemDestructionGarbageCollector' => 'PhabricatorGarbageCollector',
'PhabricatorSystemDestructionLog' => 'PhabricatorSystemDAO',
'PhabricatorSystemObjectController' => 'PhabricatorController',
'PhabricatorSystemReadOnlyController' => 'PhabricatorController',
'PhabricatorSystemRemoveDestroyWorkflow' => 'PhabricatorSystemRemoveWorkflow',
'PhabricatorSystemRemoveLogWorkflow' => 'PhabricatorSystemRemoveWorkflow',
@@ -11047,6 +11140,8 @@ phutil_register_library_map(array(
'PhabricatorProjectInterface',
'PhabricatorApplicationTransactionInterface',
'PhabricatorConduitResultInterface',
'PhabricatorPolicyCodexInterface',
'PhabricatorSpacesInterface',
),
'PhrictionDocumentAuthorHeraldField' => 'PhrictionDocumentHeraldField',
'PhrictionDocumentContentHeraldField' => 'PhrictionDocumentHeraldField',
@@ -11063,6 +11158,7 @@ phutil_register_library_map(array(
'PhrictionDocumentMoveToTransaction' => 'PhrictionDocumentTransactionType',
'PhrictionDocumentPHIDType' => 'PhabricatorPHIDType',
'PhrictionDocumentPathHeraldField' => 'PhrictionDocumentHeraldField',
'PhrictionDocumentPolicyCodex' => 'PhabricatorPolicyCodex',
'PhrictionDocumentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhrictionDocumentSearchConduitAPIMethod' => 'PhabricatorSearchEngineAPIMethod',
'PhrictionDocumentSearchEngine' => 'PhabricatorApplicationSearchEngine',

View File

@@ -54,7 +54,16 @@ abstract class AphrontResponse extends Phobject {
public function getContentIterator() {
return array($this->buildResponseString());
// By default, make sure responses are truly returning a string, not some
// kind of object that behaves like a string.
// We're going to remove the execution time limit before dumping the
// response into the sink, and want any rendering that's going to occur
// to happen BEFORE we release the limit.
return array(
(string)$this->buildResponseString(),
);
}
public function buildResponseString() {

View File

@@ -112,6 +112,23 @@ abstract class AphrontHTTPSink extends Phobject {
$response->getHTTPResponseMessage());
$this->writeHeaders($all_headers);
// Allow clients an unlimited amount of time to download the response.
// This allows clients to perform a "slow loris" attack, where they
// download a large response very slowly to tie up process slots. However,
// concurrent connection limits and "RequestReadTimeout" already prevent
// this attack. We could add our own minimum download rate here if we want
// to make this easier to configure eventually.
// For normal page responses, we've fully rendered the page into a string
// already so all that's left is writing it to the client.
// For unusual responses (like large file downloads) we may still be doing
// some meaningful work, but in theory that work is intrinsic to streaming
// the response.
set_time_limit(0);
$abort = false;
foreach ($data as $block) {
if (!$this->isWritable()) {

View File

@@ -217,6 +217,7 @@ abstract class PhabricatorAphlictManagementWorkflow
'index "%s"). You should manually create this directory or '.
'choose a different logfile location. %s',
$dir,
$index,
$ex->getMessage()));
}
}

View File

@@ -53,6 +53,10 @@ final class PhabricatorCommitSearchEngine
$query->withUnreachable($map['unreachable']);
}
if ($map['ancestorsOf']) {
$query->withAncestorsOf($map['ancestorsOf']);
}
return $query;
}
@@ -103,6 +107,13 @@ final class PhabricatorCommitSearchEngine
pht(
'Find or exclude unreachable commits which are not ancestors of '.
'any branch, tag, or ref.')),
id(new PhabricatorSearchStringListField())
->setLabel(pht('Ancestors Of'))
->setKey('ancestorsOf')
->setDescription(
pht(
'Find commits which are ancestors of a particular ref, '.
'like "master".')),
);
}

View File

@@ -70,12 +70,6 @@ final class PhabricatorAuthSSHKey
return parent::save();
}
public function getMailKey() {
// NOTE: We don't actually receive mail for these objects. It's OK for
// the mail key to be predictable until we do.
return PhabricatorHash::digestForIndex($this->getPHID());
}
public function toPublicKey() {
return PhabricatorAuthSSHPublicKey::newFromStoredKey($this);
}

View File

@@ -143,7 +143,7 @@ final class PhabricatorOpcodeCacheSpec extends PhabricatorCacheSpec {
$this
->newIssue('extension.opcache.devmode')
->setShortName(pht('OPcache Config'))
->setName(pht('OPCache Not Configured for Development'))
->setName(pht('OPcache Not Configured for Development'))
->setSummary($summary)
->setMessage($message)
->addPHPConfig('opcache.validate_timestamps')

View File

@@ -211,9 +211,14 @@ final class PhabricatorConduitAPIController
->withIsActive(true)
->executeOne();
if (!$stored_key) {
$key_summary = id(new PhutilUTF8StringTruncator())
->setMaximumBytes(64)
->truncateString($raw_key);
return array(
'ERR-INVALID-AUTH',
pht('No user or device is associated with that public key.'),
pht(
'No user or device is associated with the public key "%s".',
$key_summary),
);
}

View File

@@ -15,7 +15,7 @@ final class PhabricatorConfigApplication extends PhabricatorApplication {
}
public function getTitleGlyph() {
return "\xE2\x98\xBA";
return "\xE2\x9C\xA8";
}
public function getApplicationGroup() {

View File

@@ -231,7 +231,6 @@ final class PhabricatorConfigEditController
$box_header[] = $key;
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Config'), $this->getApplicationURI());
if ($group) {
$crumbs->addTextCrumb($group->getName(), $group_uri);
}

View File

@@ -30,7 +30,7 @@ final class PhabricatorConfigGroupController
$view = $this->buildConfigBoxView($box_header, $list);
$crumbs = $this->buildApplicationCrumbs()
->addTextCrumb($group_name, $this->getApplicationURI($group_uri))
->addTextCrumb($group_name, $group_uri)
->addTextCrumb($options->getName())
->setBorder(true);

View File

@@ -445,7 +445,7 @@ final class PhabricatorSetupIssueView extends AphrontView {
'p',
array(),
pht(
'You can find more information about configuring OPCache in '.
'You can find more information about configuring OPcache in '.
'the %s.',
phutil_tag(
'a',
@@ -453,7 +453,7 @@ final class PhabricatorSetupIssueView extends AphrontView {
'href' => 'http://php.net/manual/opcache.configuration.php',
'target' => '_blank',
),
pht('PHP OPCache Documentation'))));
pht('PHP OPcache Documentation'))));
}
$info[] = phutil_tag(

View File

@@ -72,7 +72,7 @@ final class PhabricatorDaemonBulkJobMonitorController
->appendParagraph(
pht(
'This job is waiting for confirmation before work begins.'))
->addCancelButotn($job->getManageURI(), pht('Details'));
->addCancelButton($job->getManageURI(), pht('Details'));
}
}

View File

@@ -44,13 +44,16 @@ abstract class PhabricatorDashboardProfileController
}
protected function buildApplicationCrumbs() {
$dashboard = $this->getDashboard();
$id = $dashboard->getID();
$dashboard_uri = $this->getApplicationURI("/view/{$id}/");
$crumbs = parent::buildApplicationCrumbs();
$crumbs->addTextCrumb($dashboard->getName(), $dashboard_uri);
$crumbs->setBorder(true);
$dashboard = $this->getDashboard();
if ($dashboard) {
$id = $dashboard->getID();
$dashboard_uri = $this->getApplicationURI("/view/{$id}/");
$crumbs->addTextCrumb($dashboard->getName(), $dashboard_uri);
}
return $crumbs;
}

View File

@@ -20,13 +20,22 @@ final class PhabricatorDashboardPanelDatasource
return $this->filterResultsAgainstTokens($results);
}
protected function renderSpecialTokens(array $values) {
return $this->renderTokensFromResults($this->buildResults(), $values);
}
public function buildResults() {
$query = id(new PhabricatorDashboardPanelQuery());
$query = new PhabricatorDashboardPanelQuery();
$raw_query = $this->getRawQuery();
if (preg_match('/^[wW]\d+\z/', $raw_query)) {
$id = trim($raw_query, 'wW');
$id = (int)$id;
$query->withIDs(array($id));
} else {
$query->withNameNgrams($raw_query);
}
$panels = $this->executeQuery($query);
$results = array();

View File

@@ -43,7 +43,10 @@ final class PhabricatorDifferentialApplication extends PhabricatorApplication {
public function getRoutes() {
return array(
'/D(?P<id>[1-9]\d*)' => 'DifferentialRevisionViewController',
'/D(?P<id>[1-9]\d*)' => array(
'' => 'DifferentialRevisionViewController',
'/(?P<filter>new)/' => 'DifferentialRevisionViewController',
),
'/differential/' => array(
'(?:query/(?P<queryKey>[^/]+)/)?'
=> 'DifferentialRevisionListController',

View File

@@ -76,6 +76,16 @@ abstract class DifferentialController extends PhabricatorController {
$repository_phid,
$changeset_path);
// If this particular changeset is generated code and the package does
// not match generated code, remove it from the list.
if ($changeset->isGeneratedChangeset()) {
foreach ($packages as $key => $package) {
if ($package->getMustMatchUngeneratedPaths()) {
unset($packages[$key]);
}
}
}
$this->pathPackageMap[$changeset_path] = $packages;
foreach ($packages as $package) {
$this->packageChangesetMap[$package->getPHID()][] = $changeset;

View File

@@ -1,22 +1,45 @@
<?php
final class DifferentialRevisionViewController extends DifferentialController {
final class DifferentialRevisionViewController
extends DifferentialController {
private $revisionID;
private $veryLargeDiff;
private $changesetCount;
private $hiddenChangesets;
private $warnings = array();
public function shouldAllowPublic() {
return true;
}
public function isLargeDiff() {
return ($this->getChangesetCount() > $this->getLargeDiffLimit());
}
public function isVeryLargeDiff() {
return $this->veryLargeDiff;
return ($this->getChangesetCount() > $this->getVeryLargeDiffLimit());
}
public function getLargeDiffLimit() {
return 100;
}
public function getVeryLargeDiffLimit() {
return 1000;
}
public function getChangesetCount() {
if ($this->changesetCount === null) {
throw new PhutilInvalidStateException('setChangesetCount');
}
return $this->changesetCount;
}
public function setChangesetCount($count) {
$this->changesetCount = $count;
return $this;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
$this->revisionID = $request->getURIData('id');
@@ -46,9 +69,17 @@ final class DifferentialRevisionViewController extends DifferentialController {
$revision->attachActiveDiff(last($diffs));
$diff_vs = $request->getInt('vs');
$target_id = $request->getInt('id');
$target = idx($diffs, $target_id, end($diffs));
$diff_vs = $this->getOldDiffID($revision, $diffs);
if ($diff_vs instanceof AphrontResponse) {
return $diff_vs;
}
$target_id = $this->getNewDiffID($revision, $diffs);
if ($target_id instanceof AphrontResponse) {
return $target_id;
}
$target = $diffs[$target_id];
$target_manual = $target;
if (!$target_id) {
@@ -59,10 +90,6 @@ final class DifferentialRevisionViewController extends DifferentialController {
}
}
if (empty($diffs[$diff_vs])) {
$diff_vs = null;
}
$repository = null;
$repository_phid = $target->getRepositoryPHID();
if ($repository_phid) {
@@ -82,9 +109,7 @@ final class DifferentialRevisionViewController extends DifferentialController {
idx($diffs, $diff_vs),
$repository);
if (count($rendering_references) > $this->getVeryLargeDiffLimit()) {
$this->veryLargeDiff = true;
}
$this->setChangesetCount(count($rendering_references));
if ($request->getExists('download')) {
return $this->buildRawDiffResponse(
@@ -150,33 +175,54 @@ final class DifferentialRevisionViewController extends DifferentialController {
}
$handles = $this->loadViewerHandles($object_phids);
$warnings = $this->warnings;
$request_uri = $request->getRequestURI();
$limit = 100;
$large = $request->getStr('large');
if (count($changesets) > $limit && !$large) {
$count = count($changesets);
$warning = new PHUIInfoView();
$warning->setTitle(pht('Large Diff'));
$warning->setSeverity(PHUIInfoView::SEVERITY_WARNING);
$warning->appendChild(hsprintf(
'%s <strong>%s</strong>',
pht(
'This diff is large and affects %s files. '.
'You may load each file individually or ',
new PhutilNumber($count)),
phutil_tag(
'a',
array(
'class' => 'button button-grey',
'href' => $request_uri
->alter('large', 'true')
->setFragment('toc'),
),
pht('Show All Files Inline'))));
$warning = $warning->render();
$large_warning =
($this->isLargeDiff()) &&
(!$this->isVeryLargeDiff()) &&
(!$large);
if ($large_warning) {
$count = $this->getChangesetCount();
$expand_uri = $request_uri
->alter('large', 'true')
->setFragment('toc');
$message = array(
pht(
'This large diff affects %s files. Files without inline '.
'comments have been collapsed.',
new PhutilNumber($count)),
' ',
phutil_tag(
'strong',
array(),
phutil_tag(
'a',
array(
'href' => $expand_uri,
),
pht('Expand All Files'))),
);
$warnings[] = id(new PHUIInfoView())
->setTitle(pht('Large Diff'))
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
->appendChild($message);
$folded_changesets = $changesets;
} else {
$folded_changesets = array();
}
// Don't hide or fold changesets which have inline comments.
$hidden_changesets = $this->hiddenChangesets;
if ($hidden_changesets || $folded_changesets) {
$old = array_select_keys($changesets, $old_ids);
$new = array_select_keys($changesets, $new_ids);
@@ -191,16 +237,47 @@ final class DifferentialRevisionViewController extends DifferentialController {
$new,
$revision);
$visible_changesets = array();
foreach ($inlines as $inline) {
$changeset_id = $inline->getChangesetID();
if (isset($changesets[$changeset_id])) {
$visible_changesets[$changeset_id] = $changesets[$changeset_id];
if (!isset($changesets[$changeset_id])) {
continue;
}
unset($hidden_changesets[$changeset_id]);
unset($folded_changesets[$changeset_id]);
}
} else {
$warning = null;
$visible_changesets = $changesets;
}
// If we would hide only one changeset, don't hide anything. The notice
// we'd render about it is about the same size as the changeset.
if (count($hidden_changesets) < 2) {
$hidden_changesets = array();
}
// Update the set of hidden changesets, since we may have just un-hidden
// some of them.
if ($hidden_changesets) {
$warnings[] = id(new PHUIInfoView())
->setTitle(pht('Showing Only Differences'))
->setSeverity(PHUIInfoView::SEVERITY_NOTICE)
->appendChild(
pht(
'This revision modifies %s more files that are hidden because '.
'they were not modified between selected diffs and they have no '.
'inline comments.',
phutil_count($hidden_changesets)));
}
// Compute the unfolded changesets. By default, everything is unfolded.
$unfolded_changesets = $changesets;
foreach ($folded_changesets as $changeset_id => $changeset) {
unset($unfolded_changesets[$changeset_id]);
}
// Throw away any hidden changesets.
foreach ($hidden_changesets as $changeset_id => $changeset) {
unset($changesets[$changeset_id]);
unset($unfolded_changesets[$changeset_id]);
}
$commit_hashes = mpull($diffs, 'getSourceControlBaseRevision');
@@ -236,7 +313,7 @@ final class DifferentialRevisionViewController extends DifferentialController {
if ($repository) {
$symbol_indexes = $this->buildSymbolIndexes(
$repository,
$visible_changesets);
$unfolded_changesets);
} else {
$symbol_indexes = array();
}
@@ -297,7 +374,7 @@ final class DifferentialRevisionViewController extends DifferentialController {
} else {
$changeset_view = id(new DifferentialChangesetListView())
->setChangesets($changesets)
->setVisibleChangesets($visible_changesets)
->setVisibleChangesets($unfolded_changesets)
->setStandaloneURI('/differential/changeset/')
->setRawFileURIs(
'/differential/changeset/?view=old',
@@ -357,23 +434,33 @@ final class DifferentialRevisionViewController extends DifferentialController {
$other_view = $this->renderOtherRevisions($other_revisions);
}
$this->buildPackageMaps($changesets);
if ($this->isVeryLargeDiff()) {
$toc_view = null;
// When rendering a "very large" diff, we skip computation of owners
// that own no files because it is significantly expensive and not very
// valuable.
foreach ($revision->getReviewers() as $reviewer) {
// Give each reviewer a dummy nonempty value so the UI does not render
// the "(Owns No Changed Paths)" note. If that behavior becomes more
// sophisticated in the future, this behavior might also need to.
$reviewer->attachChangesets($changesets);
}
} else {
$this->buildPackageMaps($changesets);
$toc_view = $this->buildTableOfContents(
$changesets,
$visible_changesets,
$unfolded_changesets,
$target->loadCoverageMap($viewer));
}
// Attach changesets to each reviewer so we can show which Owners package
// reviewers own no files.
foreach ($revision->getReviewers() as $reviewer) {
$reviewer_phid = $reviewer->getReviewerPHID();
$reviewer_changesets = $this->getPackageChangesets($reviewer_phid);
$reviewer->attachChangesets($reviewer_changesets);
// Attach changesets to each reviewer so we can show which Owners package
// reviewers own no files.
foreach ($revision->getReviewers() as $reviewer) {
$reviewer_phid = $reviewer->getReviewerPHID();
$reviewer_changesets = $this->getPackageChangesets($reviewer_phid);
$reviewer->attachChangesets($reviewer_changesets);
}
}
$tab_group = id(new PHUITabGroupView());
@@ -479,7 +566,7 @@ final class DifferentialRevisionViewController extends DifferentialController {
$footer[] = array(
$anchor,
$warning,
$warnings,
$tab_view,
$changeset_view,
);
@@ -766,6 +853,7 @@ final class DifferentialRevisionViewController extends DifferentialController {
DifferentialDiff $target,
DifferentialDiff $diff_vs = null,
PhabricatorRepository $repository = null) {
$viewer = $this->getViewer();
$load_diffs = array($target);
if ($diff_vs) {
@@ -773,7 +861,7 @@ final class DifferentialRevisionViewController extends DifferentialController {
}
$raw_changesets = id(new DifferentialChangesetQuery())
->setViewer($this->getRequest()->getUser())
->setViewer($viewer)
->withDiffs($load_diffs)
->execute();
$changeset_groups = mgroup($raw_changesets, 'getDiffID');
@@ -781,17 +869,19 @@ final class DifferentialRevisionViewController extends DifferentialController {
$changesets = idx($changeset_groups, $target->getID(), array());
$changesets = mpull($changesets, null, 'getID');
$refs = array();
$vs_map = array();
$refs = array();
$vs_map = array();
$vs_changesets = array();
$must_compare = array();
if ($diff_vs) {
$vs_id = $diff_vs->getID();
$vs_id = $diff_vs->getID();
$vs_changesets_path_map = array();
foreach (idx($changeset_groups, $vs_id, array()) as $changeset) {
$path = $changeset->getAbsoluteRepositoryPath($repository, $diff_vs);
$vs_changesets_path_map[$path] = $changeset;
$vs_changesets[$changeset->getID()] = $changeset;
}
foreach ($changesets as $key => $changeset) {
$path = $changeset->getAbsoluteRepositoryPath($repository, $target);
if (isset($vs_changesets_path_map[$path])) {
@@ -800,15 +890,20 @@ final class DifferentialRevisionViewController extends DifferentialController {
$refs[$changeset->getID()] =
$changeset->getID().'/'.$vs_changesets_path_map[$path]->getID();
unset($vs_changesets_path_map[$path]);
$must_compare[] = $changeset->getID();
} else {
$refs[$changeset->getID()] = $changeset->getID();
}
}
foreach ($vs_changesets_path_map as $path => $changeset) {
$changesets[$changeset->getID()] = $changeset;
$vs_map[$changeset->getID()] = -1;
$refs[$changeset->getID()] = $changeset->getID().'/-1';
$vs_map[$changeset->getID()] = -1;
$refs[$changeset->getID()] = $changeset->getID().'/-1';
}
} else {
foreach ($changesets as $changeset) {
$refs[$changeset->getID()] = $changeset->getID();
@@ -817,13 +912,25 @@ final class DifferentialRevisionViewController extends DifferentialController {
$changesets = msort($changesets, 'getSortKey');
// See T13137. When displaying the diff between two updates, hide any
// changesets which haven't actually changed.
$this->hiddenChangesets = array();
foreach ($must_compare as $changeset_id) {
$changeset = $changesets[$changeset_id];
$vs_changeset = $vs_changesets[$vs_map[$changeset_id]];
if ($changeset->hasSameEffectAs($vs_changeset)) {
$this->hiddenChangesets[$changeset_id] = $changesets[$changeset_id];
}
}
return array($changesets, $vs_map, $vs_changesets, $refs);
}
private function buildSymbolIndexes(
PhabricatorRepository $repository,
array $visible_changesets) {
assert_instances_of($visible_changesets, 'DifferentialChangeset');
array $unfolded_changesets) {
assert_instances_of($unfolded_changesets, 'DifferentialChangeset');
$engine = PhabricatorSyntaxHighlighter::newEngine();
@@ -848,7 +955,7 @@ final class DifferentialRevisionViewController extends DifferentialController {
$sources);
$indexed_langs = array_fill_keys($langs, true);
foreach ($visible_changesets as $key => $changeset) {
foreach ($unfolded_changesets as $key => $changeset) {
$lang = $engine->getLanguageFromFilename($changeset->getFilename());
if (empty($indexed_langs) || isset($indexed_langs[$lang])) {
$symbol_indexes[$key] = array(
@@ -1210,4 +1317,133 @@ final class DifferentialRevisionViewController extends DifferentialController {
->setShowViewAll(true);
}
private function getOldDiffID(DifferentialRevision $revision, array $diffs) {
assert_instances_of($diffs, 'DifferentialDiff');
$request = $this->getRequest();
$diffs = mpull($diffs, null, 'getID');
$is_new = ($request->getURIData('filter') === 'new');
$old_id = $request->getInt('vs');
// This is ambiguous, so just 404 rather than trying to figure out what
// the user expects.
if ($is_new && $old_id) {
return new Aphront404Response();
}
if ($is_new) {
$viewer = $this->getViewer();
$xactions = id(new DifferentialTransactionQuery())
->setViewer($viewer)
->withObjectPHIDs(array($revision->getPHID()))
->withAuthorPHIDs(array($viewer->getPHID()))
->setOrder('newest')
->setLimit(1)
->execute();
if (!$xactions) {
$this->warnings[] = id(new PHUIInfoView())
->setTitle(pht('No Actions'))
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
->appendChild(
pht(
'Showing all changes because you have never taken an '.
'action on this revision.'));
} else {
$xaction = head($xactions);
// Find the transactions which updated this revision. We want to
// figure out which diff was active when you last took an action.
$updates = id(new DifferentialTransactionQuery())
->setViewer($viewer)
->withObjectPHIDs(array($revision->getPHID()))
->withTransactionTypes(
array(
DifferentialRevisionUpdateTransaction::TRANSACTIONTYPE,
))
->setOrder('oldest')
->execute();
// Sort the diffs into two buckets: those older than your last action
// and those newer than your last action.
$older = array();
$newer = array();
foreach ($updates as $update) {
// If you updated the revision with "arc diff", try to count that
// update as "before your last action".
if ($update->getDateCreated() <= $xaction->getDateCreated()) {
$older[] = $update->getNewValue();
} else {
$newer[] = $update->getNewValue();
}
}
if (!$newer) {
$this->warnings[] = id(new PHUIInfoView())
->setTitle(pht('No Recent Updates'))
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
->appendChild(
pht(
'Showing all changes because the diff for this revision '.
'has not been updated since your last action.'));
} else {
$older = array_fuse($older);
// Find the most recent diff from before the last action.
$old = null;
foreach ($diffs as $diff) {
if (!isset($older[$diff->getPHID()])) {
break;
}
$old = $diff;
}
// It's possible we may not find such a diff: transactions may have
// been removed from the database, for example. If we miss, just
// fail into some reasonable state since 404'ing would be perplexing.
if ($old) {
$this->warnings[] = id(new PHUIInfoView())
->setTitle(pht('New Changes Shown'))
->setSeverity(PHUIInfoView::SEVERITY_NOTICE)
->appendChild(
pht(
'Showing changes since the last action you took on this '.
'revision.'));
$old_id = $old->getID();
}
}
}
}
if (isset($diffs[$old_id])) {
return $old_id;
}
return null;
}
private function getNewDiffID(DifferentialRevision $revision, array $diffs) {
assert_instances_of($diffs, 'DifferentialDiff');
$request = $this->getRequest();
$diffs = mpull($diffs, null, 'getID');
$is_new = ($request->getURIData('filter') === 'new');
$new_id = $request->getInt('id');
if ($is_new && $new_id) {
return new Aphront404Response();
}
if (isset($diffs[$new_id])) {
return $new_id;
}
return (int)last_key($diffs);
}
}

View File

@@ -33,7 +33,7 @@ final class DifferentialRevisionDependedOnByRevisionEdgeType
$add_edges) {
return pht(
'%s added %s dependent revision(s): %s.',
'%s added %s child revision(s): %s.',
$actor,
$add_count,
$add_edges);
@@ -45,7 +45,7 @@ final class DifferentialRevisionDependedOnByRevisionEdgeType
$rem_edges) {
return pht(
'%s removed %s dependent revision(s): %s.',
'%s removed %s child revision(s): %s.',
$actor,
$rem_count,
$rem_edges);
@@ -60,7 +60,7 @@ final class DifferentialRevisionDependedOnByRevisionEdgeType
$rem_edges) {
return pht(
'%s edited dependent revision(s), added %s: %s; removed %s: %s.',
'%s edited child revision(s), added %s: %s; removed %s: %s.',
$actor,
$add_count,
$add_edges,
@@ -75,7 +75,7 @@ final class DifferentialRevisionDependedOnByRevisionEdgeType
$add_edges) {
return pht(
'%s added %s dependent revision(s) for %s: %s.',
'%s added %s child revision(s) for %s: %s.',
$actor,
$add_count,
$object,
@@ -89,7 +89,7 @@ final class DifferentialRevisionDependedOnByRevisionEdgeType
$rem_edges) {
return pht(
'%s removed %s dependent revision(s) for %s: %s.',
'%s removed %s child revision(s) for %s: %s.',
$actor,
$rem_count,
$object,
@@ -106,7 +106,7 @@ final class DifferentialRevisionDependedOnByRevisionEdgeType
$rem_edges) {
return pht(
'%s edited dependent revision(s) for %s, added %s: %s; removed %s: %s.',
'%s edited child revision(s) for %s, added %s: %s; removed %s: %s.',
$actor,
$object,
$add_count,

View File

@@ -36,7 +36,7 @@ final class DifferentialRevisionDependsOnRevisionEdgeType
$add_edges) {
return pht(
'%s added %s dependencie(s): %s.',
'%s added %s parent revision(s): %s.',
$actor,
$add_count,
$add_edges);
@@ -48,7 +48,7 @@ final class DifferentialRevisionDependsOnRevisionEdgeType
$rem_edges) {
return pht(
'%s removed %s dependencie(s): %s.',
'%s removed %s parent revision(s): %s.',
$actor,
$rem_count,
$rem_edges);
@@ -63,7 +63,7 @@ final class DifferentialRevisionDependsOnRevisionEdgeType
$rem_edges) {
return pht(
'%s edited dependencie(s), added %s: %s; removed %s: %s.',
'%s edited parent revision(s), added %s: %s; removed %s: %s.',
$actor,
$add_count,
$add_edges,
@@ -78,7 +78,7 @@ final class DifferentialRevisionDependsOnRevisionEdgeType
$add_edges) {
return pht(
'%s added %s dependencie(s) for %s: %s.',
'%s added %s parent revision(s) for %s: %s.',
$actor,
$add_count,
$object,
@@ -92,7 +92,7 @@ final class DifferentialRevisionDependsOnRevisionEdgeType
$rem_edges) {
return pht(
'%s removed %s dependencie(s) for %s: %s.',
'%s removed %s parent revision(s) for %s: %s.',
$actor,
$rem_count,
$object,
@@ -109,7 +109,7 @@ final class DifferentialRevisionDependsOnRevisionEdgeType
$rem_edges) {
return pht(
'%s edited dependencie(s) for %s, added %s: %s; removed %s: %s.',
'%s edited parent revision(s) for %s, added %s: %s; removed %s: %s.',
$actor,
$object,
$add_count,

View File

@@ -7,11 +7,13 @@ final class DifferentialTransactionEditor
private $isCloseByCommit;
private $repositoryPHIDOverride = false;
private $didExpandInlineState = false;
private $affectedPaths;
private $firstBroadcast = false;
private $wasBroadcasting;
private $isDraftDemotion;
private $ownersDiff;
private $ownersChangesets;
public function getEditorApplicationClass() {
return 'PhabricatorDifferentialApplication';
}
@@ -590,12 +592,13 @@ final class DifferentialTransactionEditor
}
protected function buildMailTemplate(PhabricatorLiskDAO $object) {
$id = $object->getID();
$monogram = $object->getMonogram();
$title = $object->getTitle();
$subject = "D{$id}: {$title}";
return id(new PhabricatorMetaMTAMail())
->setSubject($subject);
->setSubject(pht('%s: %s', $monogram, $title))
->setMustEncryptSubject(pht('%s: Revision Updated', $monogram))
->setMustEncryptURI($object->getURI());
}
protected function getTransactionsForMail(
@@ -621,7 +624,9 @@ final class DifferentialTransactionEditor
$body = new PhabricatorMetaMTAMailBody();
$body->setViewer($this->requireActor());
$revision_uri = PhabricatorEnv::getProductionURI('/D'.$object->getID());
$revision_uri = $object->getURI();
$revision_uri = PhabricatorEnv::getProductionURI($revision_uri);
$new_uri = $revision_uri.'/new/';
$this->addHeadersAndCommentsToMailBody(
$body,
@@ -642,19 +647,6 @@ final class DifferentialTransactionEditor
$this->appendInlineCommentsForMail($object, $inlines, $body);
}
$changed_uri = $this->getChangedPriorToCommitURI();
if ($changed_uri) {
$body->addLinkSection(
pht('CHANGED PRIOR TO COMMIT'),
$changed_uri);
}
$this->addCustomFieldsToMailBody($body, $object, $xactions);
$body->addLinkSection(
pht('REVISION DETAIL'),
$revision_uri);
$update_xaction = null;
foreach ($xactions as $xaction) {
switch ($xaction->getTransactionType()) {
@@ -666,7 +658,28 @@ final class DifferentialTransactionEditor
if ($update_xaction) {
$diff = $this->requireDiff($update_xaction->getNewValue(), true);
} else {
$diff = null;
}
$changed_uri = $this->getChangedPriorToCommitURI();
if ($changed_uri) {
$body->addLinkSection(
pht('CHANGED PRIOR TO COMMIT'),
$changed_uri);
}
$this->addCustomFieldsToMailBody($body, $object, $xactions);
if (!$this->getIsNewObject()) {
$body->addLinkSection(pht('CHANGES SINCE LAST ACTION'), $new_uri);
}
$body->addLinkSection(
pht('REVISION DETAIL'),
$revision_uri);
if ($update_xaction) {
$body->addTextSection(
pht('AFFECTED FILES'),
$this->renderAffectedFilesForMail($diff));
@@ -680,8 +693,13 @@ final class DifferentialTransactionEditor
if ($config_inline || $config_attach) {
$body_limit = PhabricatorEnv::getEnvConfig('metamta.email-body-limit');
$patch = $this->buildPatchForMail($diff);
if ($config_inline) {
try {
$patch = $this->buildPatchForMail($diff, $body_limit);
} catch (ArcanistDiffByteSizeException $ex) {
$patch = null;
}
if (($patch !== null) && $config_inline) {
$lines = substr_count($patch, "\n");
$bytes = strlen($patch);
@@ -704,7 +722,7 @@ final class DifferentialTransactionEditor
}
}
if ($config_attach) {
if (($patch !== null) && $config_attach) {
// See T12033, T11767, and PHI55. This is a crude fix to stop the
// major concrete problems that lackluster email size limits cause.
if (strlen($patch) < $body_limit) {
@@ -968,13 +986,20 @@ final class DifferentialTransactionEditor
return array();
}
if (!$this->affectedPaths) {
$diff = $this->ownersDiff;
$changesets = $this->ownersChangesets;
$this->ownersDiff = null;
$this->ownersChangesets = null;
if (!$changesets) {
return array();
}
$packages = PhabricatorOwnersPackage::loadAffectedPackages(
$packages = PhabricatorOwnersPackage::loadAffectedPackagesForChangesets(
$repository,
$this->affectedPaths);
$diff,
$changesets);
if (!$packages) {
return array();
}
@@ -1255,9 +1280,12 @@ final class DifferentialTransactionEditor
$paths[] = $path_prefix.'/'.$changeset->getFilename();
}
// Save the affected paths; we'll use them later to query Owners. This
// uses the un-expanded paths.
$this->affectedPaths = $paths;
// If this change affected paths, save the changesets so we can apply
// Owners rules to them later.
if ($paths) {
$this->ownersDiff = $diff;
$this->ownersChangesets = $changesets;
}
// Mark this as also touching all parent paths, so you can see all pending
// changes to any file within a directory.
@@ -1399,13 +1427,14 @@ final class DifferentialTransactionEditor
array('style' => 'font-family: monospace;'), $patch);
}
private function buildPatchForMail(DifferentialDiff $diff) {
private function buildPatchForMail(DifferentialDiff $diff, $byte_limit) {
$format = PhabricatorEnv::getEnvConfig('metamta.differential.patch-format');
return id(new DifferentialRawDiffRenderer())
->setViewer($this->getActor())
->setFormat($format)
->setChangesets($diff->getChangesets())
->setByteLimit($byte_limit)
->buildPatch();
}

View File

@@ -0,0 +1,248 @@
<?php
final class DifferentialChangesetEngine extends Phobject {
public function rebuildChangesets(array $changesets) {
assert_instances_of($changesets, 'DifferentialChangeset');
foreach ($changesets as $changeset) {
$this->detectGeneratedCode($changeset);
$this->computeHashes($changeset);
}
$this->detectCopiedCode($changesets);
}
/* -( Generated Code )----------------------------------------------------- */
private function detectGeneratedCode(DifferentialChangeset $changeset) {
$is_generated_trusted = $this->isTrustedGeneratedCode($changeset);
if ($is_generated_trusted) {
$changeset->setTrustedChangesetAttribute(
DifferentialChangeset::ATTRIBUTE_GENERATED,
$is_generated_trusted);
}
$is_generated_untrusted = $this->isUntrustedGeneratedCode($changeset);
if ($is_generated_untrusted) {
$changeset->setUntrustedChangesetAttribute(
DifferentialChangeset::ATTRIBUTE_GENERATED,
$is_generated_untrusted);
}
}
private function isTrustedGeneratedCode(DifferentialChangeset $changeset) {
$filename = $changeset->getFilename();
$paths = PhabricatorEnv::getEnvConfig('differential.generated-paths');
foreach ($paths as $regexp) {
if (preg_match($regexp, $filename)) {
return true;
}
}
return false;
}
private function isUntrustedGeneratedCode(DifferentialChangeset $changeset) {
if ($changeset->getHunks()) {
$new_data = $changeset->makeNewFile();
if (strpos($new_data, '@'.'generated') !== false) {
return true;
}
}
return false;
}
/* -( Content Hashes )----------------------------------------------------- */
private function computeHashes(DifferentialChangeset $changeset) {
$effect_key = DifferentialChangeset::METADATA_EFFECT_HASH;
$effect_hash = $this->newEffectHash($changeset);
if ($effect_hash !== null) {
$changeset->setChangesetMetadata($effect_key, $effect_hash);
}
}
private function newEffectHash(DifferentialChangeset $changeset) {
if ($changeset->getHunks()) {
$new_data = $changeset->makeNewFile();
return PhabricatorHash::digestForIndex($new_data);
}
return null;
}
/* -( Copied Code )-------------------------------------------------------- */
private function detectCopiedCode(array $changesets) {
$min_width = 30;
$min_lines = 3;
$map = array();
$files = array();
$types = array();
foreach ($changesets as $changeset) {
$file = $changeset->getFilename();
foreach ($changeset->getHunks() as $hunk) {
$lines = $hunk->getStructuredOldFile();
foreach ($lines as $line => $info) {
$type = $info['type'];
if ($type == '\\') {
continue;
}
$types[$file][$line] = $type;
$text = $info['text'];
$text = trim($text);
$files[$file][$line] = $text;
if (strlen($text) >= $min_width) {
$map[$text][] = array($file, $line);
}
}
}
}
foreach ($changesets as $changeset) {
$copies = array();
foreach ($changeset->getHunks() as $hunk) {
$added = $hunk->getStructuredNewFile();
$atype = array();
foreach ($added as $line => $info) {
$atype[$line] = $info['type'];
$added[$line] = trim($info['text']);
}
$skip_lines = 0;
foreach ($added as $line => $code) {
if ($skip_lines) {
// We're skipping lines that we already processed because we
// extended a block above them downward to include them.
$skip_lines--;
continue;
}
if ($atype[$line] !== '+') {
// This line hasn't been changed in the new file, so don't try
// to figure out where it came from.
continue;
}
if (empty($map[$code])) {
// This line was too short to trigger copy/move detection.
continue;
}
if (count($map[$code]) > 16) {
// If there are a large number of identical lines in this diff,
// don't try to figure out where this block came from: the analysis
// is O(N^2), since we need to compare every line against every
// other line. Even if we arrive at a result, it is unlikely to be
// meaningful. See T5041.
continue;
}
$best_length = 0;
// Explore all candidates.
foreach ($map[$code] as $val) {
list($file, $orig_line) = $val;
$length = 1;
// Search backward and forward to find all of the adjacent lines
// which match.
foreach (array(-1, 1) as $direction) {
$offset = $direction;
while (true) {
if (isset($copies[$line + $offset])) {
// If we run into a block above us which we've already
// attributed to a move or copy from elsewhere, stop
// looking.
break;
}
if (!isset($added[$line + $offset])) {
// If we've run off the beginning or end of the new file,
// stop looking.
break;
}
if (!isset($files[$file][$orig_line + $offset])) {
// If we've run off the beginning or end of the original
// file, we also stop looking.
break;
}
$old = $files[$file][$orig_line + $offset];
$new = $added[$line + $offset];
if ($old !== $new) {
// If the old line doesn't match the new line, stop
// looking.
break;
}
$length++;
$offset += $direction;
}
}
if ($length < $best_length) {
// If we already know of a better source (more matching lines)
// for this move/copy, stick with that one. We prefer long
// copies/moves which match a lot of context over short ones.
continue;
}
if ($length == $best_length) {
if (idx($types[$file], $orig_line) != '-') {
// If we already know of an equally good source (same number
// of matching lines) and this isn't a move, stick with the
// other one. We prefer moves over copies.
continue;
}
}
$best_length = $length;
// ($offset - 1) contains number of forward matching lines.
$best_offset = $offset - 1;
$best_file = $file;
$best_line = $orig_line;
}
$file = ($best_file == $changeset->getFilename() ? '' : $best_file);
for ($i = $best_length; $i--; ) {
$type = idx($types[$best_file], $best_line + $best_offset - $i);
$copies[$line + $best_offset - $i] = ($best_length < $min_lines
? array() // Ignore short blocks.
: array($file, $best_line + $best_offset - $i, $type));
}
$skip_lines = $best_offset;
}
}
$copies = array_filter($copies);
if ($copies) {
$metadata = $changeset->getMetadata();
$metadata['copy:lines'] = $copies;
$changeset->setMetadata($metadata);
}
}
}
}

View File

@@ -120,9 +120,10 @@ final class HeraldDifferentialRevisionAdapter
$repository = $this->loadRepository();
if ($repository) {
$packages = PhabricatorOwnersPackage::loadAffectedPackages(
$packages = PhabricatorOwnersPackage::loadAffectedPackagesForChangesets(
$repository,
$this->loadAffectedPaths());
$this->getDiff(),
$this->loadChangesets());
$this->affectedPackages = $packages;
}
}

View File

@@ -48,10 +48,12 @@ final class PhabricatorDifferentialRevisionTestDataGenerator
public function generateDiff($author) {
$paste_generator = new PhabricatorPasteTestDataGenerator();
$languages = $paste_generator->supportedLanguages;
$lang = array_rand($languages);
$code = $paste_generator->generateContent($lang);
$altcode = $paste_generator->generateContent($lang);
$languages = $paste_generator->getSupportedLanguages();
$language = array_rand($languages);
$spec = $languages[$language];
$code = $paste_generator->generateContent($spec);
$altcode = $paste_generator->generateContent($spec);
$newcode = $this->randomlyModify($code, $altcode);
$diff = id(new PhabricatorDifferenceEngine())
->generateRawDiffFromFileContent($code, $newcode);

View File

@@ -0,0 +1,96 @@
<?php
final class PhabricatorDifferentialRebuildChangesetsWorkflow
extends PhabricatorDifferentialManagementWorkflow {
protected function didConstruct() {
$this
->setName('rebuild-changesets')
->setExamples('**rebuild-changesets** --revision __revision__')
->setSynopsis(pht('Rebuild changesets for a revision.'))
->setArguments(
array(
array(
'name' => 'revision',
'param' => 'revision',
'help' => pht('Revision to rebuild changesets for.'),
),
));
}
public function execute(PhutilArgumentParser $args) {
$viewer = $this->getViewer();
$revision_identifier = $args->getArg('revision');
if (!$revision_identifier) {
throw new PhutilArgumentUsageException(
pht('Specify a revision to rebuild changesets for with "--revision".'));
}
$revision = id(new PhabricatorObjectQuery())
->setViewer($viewer)
->withNames(array($revision_identifier))
->executeOne();
if ($revision) {
if (!($revision instanceof DifferentialRevision)) {
throw new PhutilArgumentUsageException(
pht(
'Object "%s" specified by "--revision" must be a Differential '.
'revision.'));
}
} else {
$revision = id(new DifferentialRevisionQuery())
->setViewer($viewer)
->withIDs(array($revision_identifier))
->executeOne();
}
if (!$revision) {
throw new PhutilArgumentUsageException(
pht(
'No revision "%s" exists.',
$revision_identifier));
}
$diffs = id(new DifferentialDiffQuery())
->setViewer($viewer)
->withRevisionIDs(array($revision->getID()))
->execute();
$changesets = id(new DifferentialChangesetQuery())
->setViewer($viewer)
->withDiffs($diffs)
->needHunks(true)
->execute();
$changeset_groups = mgroup($changesets, 'getDiffID');
foreach ($changeset_groups as $diff_id => $changesets) {
echo tsprintf(
"%s\n",
pht(
'Rebuilding %s changeset(s) for diff ID %d.',
phutil_count($changesets),
$diff_id));
foreach ($changesets as $changeset) {
echo tsprintf(
" %s\n",
$changeset->getFilename());
}
id(new DifferentialChangesetEngine())
->rebuildChangesets($changesets);
foreach ($changesets as $changeset) {
$changeset->save();
}
echo tsprintf(
"%s\n",
pht('Done.'));
}
}
}

View File

@@ -542,6 +542,12 @@ final class DifferentialChangesetParser extends Phobject {
PhutilEventEngine::dispatchEvent($event);
$generated = $event->getValue('is_generated');
$attribute = $this->changeset->isGeneratedChangeset();
if ($attribute) {
$generated = true;
}
$this->specialAttributes[self::ATTR_GENERATED] = $generated;
}
@@ -1413,167 +1419,6 @@ final class DifferentialChangesetParser extends Phobject {
return sprintf('%d%%', 100 * ($covered / ($covered + $not_covered)));
}
public function detectCopiedCode(
array $changesets,
$min_width = 30,
$min_lines = 3) {
assert_instances_of($changesets, 'DifferentialChangeset');
$map = array();
$files = array();
$types = array();
foreach ($changesets as $changeset) {
$file = $changeset->getFilename();
foreach ($changeset->getHunks() as $hunk) {
$lines = $hunk->getStructuredOldFile();
foreach ($lines as $line => $info) {
$type = $info['type'];
if ($type == '\\') {
continue;
}
$types[$file][$line] = $type;
$text = $info['text'];
$text = trim($text);
$files[$file][$line] = $text;
if (strlen($text) >= $min_width) {
$map[$text][] = array($file, $line);
}
}
}
}
foreach ($changesets as $changeset) {
$copies = array();
foreach ($changeset->getHunks() as $hunk) {
$added = $hunk->getStructuredNewFile();
$atype = array();
foreach ($added as $line => $info) {
$atype[$line] = $info['type'];
$added[$line] = trim($info['text']);
}
$skip_lines = 0;
foreach ($added as $line => $code) {
if ($skip_lines) {
// We're skipping lines that we already processed because we
// extended a block above them downward to include them.
$skip_lines--;
continue;
}
if ($atype[$line] !== '+') {
// This line hasn't been changed in the new file, so don't try
// to figure out where it came from.
continue;
}
if (empty($map[$code])) {
// This line was too short to trigger copy/move detection.
continue;
}
if (count($map[$code]) > 16) {
// If there are a large number of identical lines in this diff,
// don't try to figure out where this block came from: the analysis
// is O(N^2), since we need to compare every line against every
// other line. Even if we arrive at a result, it is unlikely to be
// meaningful. See T5041.
continue;
}
$best_length = 0;
// Explore all candidates.
foreach ($map[$code] as $val) {
list($file, $orig_line) = $val;
$length = 1;
// Search backward and forward to find all of the adjacent lines
// which match.
foreach (array(-1, 1) as $direction) {
$offset = $direction;
while (true) {
if (isset($copies[$line + $offset])) {
// If we run into a block above us which we've already
// attributed to a move or copy from elsewhere, stop
// looking.
break;
}
if (!isset($added[$line + $offset])) {
// If we've run off the beginning or end of the new file,
// stop looking.
break;
}
if (!isset($files[$file][$orig_line + $offset])) {
// If we've run off the beginning or end of the original
// file, we also stop looking.
break;
}
$old = $files[$file][$orig_line + $offset];
$new = $added[$line + $offset];
if ($old !== $new) {
// If the old line doesn't match the new line, stop
// looking.
break;
}
$length++;
$offset += $direction;
}
}
if ($length < $best_length) {
// If we already know of a better source (more matching lines)
// for this move/copy, stick with that one. We prefer long
// copies/moves which match a lot of context over short ones.
continue;
}
if ($length == $best_length) {
if (idx($types[$file], $orig_line) != '-') {
// If we already know of an equally good source (same number
// of matching lines) and this isn't a move, stick with the
// other one. We prefer moves over copies.
continue;
}
}
$best_length = $length;
// ($offset - 1) contains number of forward matching lines.
$best_offset = $offset - 1;
$best_file = $file;
$best_line = $orig_line;
}
$file = ($best_file == $changeset->getFilename() ? '' : $best_file);
for ($i = $best_length; $i--; ) {
$type = idx($types[$best_file], $best_line + $best_offset - $i);
$copies[$line + $best_offset - $i] = ($best_length < $min_lines
? array() // Ignore short blocks.
: array($file, $best_line + $best_offset - $i, $type));
}
$skip_lines = $best_offset;
}
}
$copies = array_filter($copies);
if ($copies) {
$metadata = $changeset->getMetadata();
$metadata['copy:lines'] = $copies;
$changeset->setMetadata($metadata);
}
}
return $changesets;
}
/**
* Build maps from lines comments appear on to actual lines.
*/

View File

@@ -68,7 +68,11 @@ final class DifferentialChangesetOneUpRenderer
$cells = array();
if ($is_old) {
if ($p['htype']) {
$class = 'left old';
if (empty($p['oline'])) {
$class = 'left old old-full';
} else {
$class = 'left old';
}
$aural = $aural_minus;
} else {
$class = 'left';
@@ -106,7 +110,11 @@ final class DifferentialChangesetOneUpRenderer
$cells[] = $no_coverage;
} else {
if ($p['htype']) {
$class = 'right new';
if (empty($p['oline'])) {
$class = 'right new new-full';
} else {
$class = 'right new';
}
$cells[] = phutil_tag('th', array('class' => $class));
$aural = $aural_plus;
} else {

View File

@@ -5,6 +5,7 @@ final class DifferentialRawDiffRenderer extends Phobject {
private $changesets;
private $format = 'unified';
private $viewer;
private $byteLimit;
public function setFormat($format) {
$this->format = $format;
@@ -35,6 +36,15 @@ final class DifferentialRawDiffRenderer extends Phobject {
return $this->viewer;
}
public function setByteLimit($byte_limit) {
$this->byteLimit = $byte_limit;
return $this;
}
public function getByteLimit() {
return $this->byteLimit;
}
public function buildPatch() {
$diff = new DifferentialDiff();
$diff->attachChangesets($this->getChangesets());
@@ -52,15 +62,18 @@ final class DifferentialRawDiffRenderer extends Phobject {
$bundle = ArcanistBundle::newFromChanges($changes);
$bundle->setLoadFileDataCallback(array($loader, 'loadFileData'));
$byte_limit = $this->getByteLimit();
if ($byte_limit) {
$bundle->setByteLimit($byte_limit);
}
$format = $this->getFormat();
switch ($format) {
case 'git':
return $bundle->toGitPatch();
break;
case 'unified':
default:
return $bundle->toUnifiedDiff();
break;
}
}
}

View File

@@ -12,7 +12,7 @@ final class DifferentialChangeset
protected $awayPaths;
protected $changeType;
protected $fileType;
protected $metadata;
protected $metadata = array();
protected $oldProperties;
protected $newProperties;
protected $addLines;
@@ -24,6 +24,12 @@ final class DifferentialChangeset
const TABLE_CACHE = 'differential_changeset_parse_cache';
const METADATA_TRUSTED_ATTRIBUTES = 'attributes.trusted';
const METADATA_UNTRUSTED_ATTRIBUTES = 'attributes.untrusted';
const METADATA_EFFECT_HASH = 'hash.effect';
const ATTRIBUTE_GENERATED = 'generated';
protected function getConfiguration() {
return array(
self::CONFIG_SERIALIZATION => array(
@@ -138,6 +144,48 @@ final class DifferentialChangeset
return $ret;
}
/**
* Test if this changeset and some other changeset put the affected file in
* the same state.
*
* @param DifferentialChangeset Changeset to compare against.
* @return bool True if the two changesets have the same effect.
*/
public function hasSameEffectAs(DifferentialChangeset $other) {
if ($this->getFilename() !== $other->getFilename()) {
return false;
}
$hash_key = self::METADATA_EFFECT_HASH;
$u_hash = $this->getChangesetMetadata($hash_key);
if ($u_hash === null) {
return false;
}
$v_hash = $other->getChangesetMetadata($hash_key);
if ($v_hash === null) {
return false;
}
if ($u_hash !== $v_hash) {
return false;
}
// Make sure the final states for the file properties (like the "+x"
// executable bit) match one another.
$u_props = $this->getNewProperties();
$v_props = $other->getNewProperties();
ksort($u_props);
ksort($v_props);
if ($u_props !== $v_props) {
return false;
}
return true;
}
public function getSortKey() {
$sort_key = $this->getFilename();
// Sort files with ".h" in them first, so headers (.h, .hpp) come before
@@ -266,6 +314,90 @@ final class DifferentialChangeset
return null;
}
public function setChangesetMetadata($key, $value) {
if (!is_array($this->metadata)) {
$this->metadata = array();
}
$this->metadata[$key] = $value;
return $this;
}
public function getChangesetMetadata($key, $default = null) {
if (!is_array($this->metadata)) {
return $default;
}
return idx($this->metadata, $key, $default);
}
private function setInternalChangesetAttribute($trusted, $key, $value) {
if ($trusted) {
$meta_key = self::METADATA_TRUSTED_ATTRIBUTES;
} else {
$meta_key = self::METADATA_UNTRUSTED_ATTRIBUTES;
}
$attributes = $this->getChangesetMetadata($meta_key, array());
$attributes[$key] = $value;
$this->setChangesetMetadata($meta_key, $attributes);
return $this;
}
private function getInternalChangesetAttributes($trusted) {
if ($trusted) {
$meta_key = self::METADATA_TRUSTED_ATTRIBUTES;
} else {
$meta_key = self::METADATA_UNTRUSTED_ATTRIBUTES;
}
return $this->getChangesetMetadata($meta_key, array());
}
public function setTrustedChangesetAttribute($key, $value) {
return $this->setInternalChangesetAttribute(true, $key, $value);
}
public function getTrustedChangesetAttributes() {
return $this->getInternalChangesetAttributes(true);
}
public function getTrustedChangesetAttribute($key, $default = null) {
$map = $this->getTrustedChangesetAttributes();
return idx($map, $key, $default);
}
public function setUntrustedChangesetAttribute($key, $value) {
return $this->setInternalChangesetAttribute(false, $key, $value);
}
public function getUntrustedChangesetAttributes() {
return $this->getInternalChangesetAttributes(false);
}
public function getUntrustedChangesetAttribute($key, $default = null) {
$map = $this->getUntrustedChangesetAttributes();
return idx($map, $key, $default);
}
public function getChangesetAttributes() {
// Prefer trusted values over untrusted values when both exist.
return
$this->getTrustedChangesetAttributes() +
$this->getUntrustedChangesetAttributes();
}
public function getChangesetAttribute($key, $default = null) {
$map = $this->getChangesetAttributes();
return idx($map, $key, $default);
}
public function isGeneratedChangeset() {
return $this->getChangesetAttribute(self::ATTRIBUTE_GENERATED);
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */

View File

@@ -230,17 +230,14 @@ final class DifferentialDiff
}
$diff->setLineCount($lines);
$parser = new DifferentialChangesetParser();
$changesets = $parser->detectCopiedCode(
$diff->getChangesets(),
$min_width = 30,
$min_lines = 3);
$diff->attachChangesets($changesets);
$changesets = $diff->getChangesets();
id(new DifferentialChangesetEngine())
->rebuildChangesets($changesets);
return $diff;
}
public function getDiffDict() {
$dict = array(
'id' => $this->getID(),
@@ -821,5 +818,4 @@ final class DifferentialDiff
);
}
}

View File

@@ -1148,6 +1148,10 @@ final class DifferentialRevision extends DifferentialDAO
->setKey('summary')
->setType('string')
->setDescription(pht('Revision summary.')),
id(new PhabricatorConduitSearchFieldSpecification())
->setKey('testPlan')
->setType('string')
->setDescription(pht('Revision test plan.')),
);
}
@@ -1167,6 +1171,7 @@ final class DifferentialRevision extends DifferentialDAO
'repositoryPHID' => $this->getRepositoryPHID(),
'diffPHID' => $this->getActiveDiffPHID(),
'summary' => $this->getSummary(),
'testPlan' => $this->getTestPlan(),
);
}

View File

@@ -307,7 +307,7 @@ final class DifferentialRevisionUpdateHistoryView extends AphrontView {
$content = phabricator_form(
$this->getUser(),
array(
'action' => '#toc',
'action' => '/D'.$revision_id.'#toc',
),
array(
$table,

View File

@@ -86,4 +86,12 @@ final class DifferentialRevisionAbandonTransaction
$this->renderObject());
}
public function getTransactionTypeForConduit($xaction) {
return 'abandon';
}
public function getFieldValuesForConduit($object, $data) {
return array();
}
}

View File

@@ -7,7 +7,7 @@ final class DifferentialRevisionAcceptTransaction
const ACTIONKEY = 'accept';
protected function getRevisionActionLabel() {
return pht("Accept Revision \xE2\x9C\x94");
return pht('Accept Revision');
}
protected function getRevisionActionDescription(
@@ -234,4 +234,12 @@ final class DifferentialRevisionAcceptTransaction
$this->renderObject());
}
public function getTransactionTypeForConduit($xaction) {
return 'accept';
}
public function getFieldValuesForConduit($object, $data) {
return array();
}
}

View File

@@ -154,5 +154,4 @@ final class DifferentialRevisionCloseTransaction
);
}
}

View File

@@ -87,4 +87,12 @@ final class DifferentialRevisionCommandeerTransaction
$this->renderObject());
}
public function getTransactionTypeForConduit($xaction) {
return 'commandeer';
}
public function getFieldValuesForConduit($object, $data) {
return array();
}
}

View File

@@ -119,4 +119,12 @@ final class DifferentialRevisionPlanChangesTransaction
return (bool)$this->getMetadataValue('draft.demote');
}
public function getTransactionTypeForConduit($xaction) {
return 'plan-changes';
}
public function getFieldValuesForConduit($object, $data) {
return array();
}
}

View File

@@ -85,4 +85,12 @@ final class DifferentialRevisionReclaimTransaction
$this->renderObject());
}
public function getTransactionTypeForConduit($xaction) {
return 'reclaim';
}
public function getFieldValuesForConduit($object, $data) {
return array();
}
}

View File

@@ -7,7 +7,7 @@ final class DifferentialRevisionRejectTransaction
const ACTIONKEY = 'reject';
protected function getRevisionActionLabel() {
return pht("Request Changes \xE2\x9C\x98");
return pht('Request Changes');
}
protected function getRevisionActionDescription(
@@ -99,4 +99,12 @@ final class DifferentialRevisionRejectTransaction
$this->renderObject());
}
public function getTransactionTypeForConduit($xaction) {
return 'request-changes';
}
public function getFieldValuesForConduit($object, $data) {
return array();
}
}

View File

@@ -72,4 +72,12 @@ final class DifferentialRevisionReopenTransaction
$this->renderObject());
}
public function getTransactionTypeForConduit($xaction) {
return 'reopen';
}
public function getFieldValuesForConduit($object, $data) {
return array();
}
}

View File

@@ -84,4 +84,12 @@ final class DifferentialRevisionRequestReviewTransaction
$this->renderObject());
}
public function getTransactionTypeForConduit($xaction) {
return 'request-review';
}
public function getFieldValuesForConduit($object, $data) {
return array();
}
}

View File

@@ -93,4 +93,12 @@ final class DifferentialRevisionResignTransaction
$this->renderObject());
}
public function getTransactionTypeForConduit($xaction) {
return 'resign';
}
public function getFieldValuesForConduit($object, $data) {
return array();
}
}

View File

@@ -124,6 +124,15 @@ final class PhabricatorDiffusionApplication extends PhabricatorApplication {
'(?P<repositoryCallsign>[A-Z]+)' => $repository_routes,
'(?P<repositoryID>[1-9]\d*)' => $repository_routes,
'identity/' => array(
$this->getQueryRoutePattern() =>
'DiffusionIdentityListController',
$this->getEditRoutePattern('edit/') =>
'DiffusionIdentityEditController',
'view/(?P<id>[^/]+)/' =>
'DiffusionIdentityViewController',
),
'inline/' => array(
'edit/(?P<phid>[^/]+)/' => 'DiffusionInlineCommentController',
'preview/(?P<phid>[^/]+)/'

View File

@@ -30,18 +30,31 @@ final class DiffusionBranchQueryConduitAPIMethod
$contains = $request->getValue('contains');
if (strlen($contains)) {
// See PHI720. If the standard "branch" field is provided, use it
// as the "pattern" argument to "git branch ..." to let callers test
// for reachability from a particular branch head.
$pattern = $request->getValue('branch');
if (strlen($pattern)) {
$pattern_argv = array($pattern);
} else {
$pattern_argv = array();
}
// NOTE: We can't use DiffusionLowLevelGitRefQuery here because
// `git for-each-ref` does not support `--contains`.
if ($repository->isWorkingCopyBare()) {
list($stdout) = $repository->execxLocalCommand(
'branch --verbose --no-abbrev --contains %s --',
$contains);
'branch --verbose --no-abbrev --contains %s -- %Ls',
$contains,
$pattern_argv);
$ref_map = DiffusionGitBranch::parseLocalBranchOutput(
$stdout);
} else {
list($stdout) = $repository->execxLocalCommand(
'branch -r --verbose --no-abbrev --contains %s --',
$contains);
'branch -r --verbose --no-abbrev --contains %s -- %Ls',
$contains,
$pattern_argv);
$ref_map = DiffusionGitBranch::parseRemoteBranchOutput(
$stdout,
DiffusionGitBranch::DEFAULT_GIT_REMOTE);

View File

@@ -0,0 +1,51 @@
<?php
final class DiffusionInternalAncestorsConduitAPIMethod
extends DiffusionQueryConduitAPIMethod {
public function isInternalAPI() {
return true;
}
public function getAPIMethodName() {
return 'diffusion.internal.ancestors';
}
public function getMethodDescription() {
return pht('Internal method for filtering ref ancestors.');
}
protected function defineReturnType() {
return 'list<string>';
}
protected function defineCustomParamTypes() {
return array(
'ref' => 'required string',
'commits' => 'required list<string>',
);
}
protected function getResult(ConduitAPIRequest $request) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$commits = $request->getValue('commits');
$ref = $request->getValue('ref');
$graph = new PhabricatorGitGraphStream($repository, $ref);
$keep = array();
foreach ($commits as $identifier) {
try {
$graph->getCommitDate($identifier);
$keep[] = $identifier;
} catch (Exception $ex) {
// Not an ancestor.
}
}
return $keep;
}
}

View File

@@ -22,6 +22,7 @@ final class DiffusionBranchTableController extends DiffusionController {
$params = array(
'offset' => $pager->getOffset(),
'limit' => $pager->getPageSize() + 1,
'branch' => null,
);
$contains = $drequest->getSymbolicCommit();

View File

@@ -22,6 +22,7 @@ final class DiffusionCommitBranchesController extends DiffusionController {
array(
'contains' => $drequest->getCommit(),
'limit' => $branch_limit + 1,
'branch' => null,
)));
$has_more_branches = (count($branches) > $branch_limit);

View File

@@ -0,0 +1,12 @@
<?php
final class DiffusionIdentityEditController
extends DiffusionController {
public function handleRequest(AphrontRequest $request) {
return id(new PhabricatorRepositoryIdentityEditEngine())
->setController($this)
->buildResponse();
}
}

View File

@@ -0,0 +1,22 @@
<?php
final class DiffusionIdentityListController
extends DiffusionController {
public function handleRequest(AphrontRequest $request) {
return id(new DiffusionRepositoryIdentitySearchEngine())
->setController($this)
->buildResponse();
}
protected function buildApplicationCrumbs() {
$crumbs = parent::buildApplicationCrumbs();
id(new PhabricatorRepositoryIdentityEditEngine())
->setViewer($this->getViewer())
->addActionToCrumbs($crumbs);
return $crumbs;
}
}

View File

@@ -0,0 +1,135 @@
<?php
final class DiffusionIdentityViewController
extends DiffusionController {
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
$id = $request->getURIData('id');
$identity = id(new PhabricatorRepositoryIdentityQuery())
->setViewer($viewer)
->withIDs(array($id))
->executeOne();
if (!$identity) {
return new Aphront404Response();
}
$title = pht('Identity %d', $identity->getID());
$curtain = $this->buildCurtain($identity);
$header = id(new PHUIHeaderView())
->setUser($viewer)
->setHeader($identity->getIdentityShortName())
->setHeaderIcon('fa-globe')
->setPolicyObject($identity);
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb($identity->getID());
$crumbs->setBorder(true);
$timeline = $this->buildTransactionTimeline(
$identity,
new PhabricatorRepositoryIdentityTransactionQuery());
$timeline->setShouldTerminate(true);
$properties = $this->buildPropertyList($identity);
$view = id(new PHUITwoColumnView())
->setHeader($header)
->setCurtain($curtain)
->setMainColumn(array(
$properties,
$timeline,
));
return $this->newPage()
->setTitle($title)
->setCrumbs($crumbs)
->appendChild(
array(
$view,
));
}
private function buildCurtain(PhabricatorRepositoryIdentity $identity) {
$viewer = $this->getViewer();
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$identity,
PhabricatorPolicyCapability::CAN_EDIT);
$id = $identity->getID();
$edit_uri = $this->getApplicationURI("identity/edit/{$id}/");
$curtain = $this->newCurtainView($identity);
$curtain->addAction(
id(new PhabricatorActionView())
->setIcon('fa-pencil')
->setName(pht('Edit Identity'))
->setHref($edit_uri)
->setWorkflow(!$can_edit)
->setDisabled(!$can_edit));
return $curtain;
}
private function buildPropertyList(
PhabricatorRepositoryIdentity $identity) {
$viewer = $this->getViewer();
$properties = id(new PHUIPropertyListView())
->setUser($viewer);
$effective_phid = $identity->getCurrentEffectiveUserPHID();
$automatic_phid = $identity->getAutomaticGuessedUserPHID();
$manual_phid = $identity->getManuallySetUserPHID();
if ($effective_phid) {
$tag = id(new PHUITagView())
->setType(PHUITagView::TYPE_SHADE)
->setColor('green')
->setIcon('fa-check')
->setName('Assigned');
} else {
$tag = id(new PHUITagView())
->setType(PHUITagView::TYPE_SHADE)
->setColor('indigo')
->setIcon('fa-bomb')
->setName('Unassigned');
}
$properties->addProperty(
pht('Effective User'),
$this->buildPropertyValue($effective_phid));
$properties->addProperty(
pht('Automatically Detected User'),
$this->buildPropertyValue($automatic_phid));
$properties->addProperty(
pht('Manually Set User'),
$this->buildPropertyValue($manual_phid));
$header = id(new PHUIHeaderView())
->setHeader(array(pht('Identity Assignments'), $tag));
return id(new PHUIObjectBoxView())
->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addPropertyList($properties);
}
private function buildPropertyValue($value) {
$viewer = $this->getViewer();
if ($value == DiffusionIdentityUnassignedDatasource::FUNCTION_TOKEN) {
return phutil_tag('em', array(), pht('Explicitly Unassigned'));
} else if (!$value) {
return null;
} else {
return $viewer->renderHandle($value);
}
}
}

View File

@@ -69,7 +69,7 @@ final class DiffusionDocumentRenderingEngine
return;
}
protected function willRenderRef(PhabricatorDocumentRef $ref) {
protected function willStageRef(PhabricatorDocumentRef $ref) {
$drequest = $this->getDiffusionRequest();
$blame_uri = (string)$drequest->generateURI(
@@ -78,9 +78,13 @@ final class DiffusionDocumentRenderingEngine
'stable' => true,
));
$ref
->setSymbolMetadata($this->getSymbolMetadata())
->setBlameURI($blame_uri);
$ref->setBlameURI($blame_uri);
}
protected function willRenderRef(PhabricatorDocumentRef $ref) {
$drequest = $this->getDiffusionRequest();
$ref->setSymbolMetadata($this->getSymbolMetadata());
$coverage = $drequest->loadCoverage();
if (strlen($coverage)) {

View File

@@ -0,0 +1,22 @@
<?php
final class DiffusionIdentityAssigneeEditField
extends PhabricatorTokenizerEditField {
protected function newDatasource() {
return new DiffusionIdentityAssigneeDatasource();
}
protected function newHTTPParameterType() {
return new AphrontUserListHTTPParameterType();
}
protected function newConduitParameterType() {
if ($this->getIsSingleValue()) {
return new ConduitUserParameterType();
} else {
return new ConduitUserListParameterType();
}
}
}

View File

@@ -0,0 +1,26 @@
<?php
final class DiffusionRepositoryIdentityEditor
extends PhabricatorApplicationTransactionEditor {
public function getEditorObjectsDescription() {
return pht('Repository Identity');
}
public function getCreateObjectTitle($author, $object) {
return pht('%s created this identity.', $author);
}
public function getCreateObjectTitleForFeed($author, $object) {
return pht('%s created %s.', $author, $object);
}
protected function supportsSearch() {
return true;
}
public function getEditorApplicationClass() {
return 'PhabricatorDiffusionApplication';
}
}

View File

@@ -37,6 +37,7 @@ final class DiffusionCommitHookEngine extends Phobject {
private $rejectDetails;
private $emailPHIDs = array();
private $changesets = array();
private $changesetsSize = 0;
/* -( Config )------------------------------------------------------------- */
@@ -1121,11 +1122,22 @@ final class DiffusionCommitHookEngine extends Phobject {
return;
}
// See T13142. Don't cache more than 64MB of changesets. For normal small
// pushes, caching everything here can let us hit the cache from Herald if
// we need to run content rules, which speeds things up a bit. For large
// pushes, we may not be able to hold everything in memory.
$cache_limit = 1024 * 1024 * 64;
foreach ($content_updates as $update) {
$identifier = $update->getRefNew();
try {
$changesets = $this->loadChangesetsForCommit($identifier);
$this->changesets[$identifier] = $changesets;
$info = $this->loadChangesetsForCommit($identifier);
list($changesets, $size) = $info;
if ($this->changesetsSize + $size <= $cache_limit) {
$this->changesets[$identifier] = $changesets;
$this->changesetsSize += $size;
}
} catch (Exception $ex) {
$this->changesets[$identifier] = $ex;
@@ -1200,14 +1212,18 @@ final class DiffusionCommitHookEngine extends Phobject {
if (!strlen($raw_diff)) {
// If the commit is actually empty, just return no changesets.
return array();
return array(array(), 0);
}
$parser = new ArcanistDiffParser();
$changes = $parser->parseDiff($raw_diff);
$diff = DifferentialDiff::newEphemeralFromRawChanges(
$changes);
return $diff->getChangesets();
$changesets = $diff->getChangesets();
$size = strlen($raw_diff);
return array($changesets, $size);
}
public function getChangesetsForCommit($identifier) {
@@ -1221,7 +1237,9 @@ final class DiffusionCommitHookEngine extends Phobject {
return $cached;
}
return $this->loadChangesetsForCommit($identifier);
$info = $this->loadChangesetsForCommit($identifier);
list($changesets, $size) = $info;
return $changesets;
}
public function loadCommitRefForCommit($identifier) {

View File

@@ -207,7 +207,7 @@ final class HeraldCommitAdapter
}
public static function getEnormousByteLimit() {
return 1024 * 1024 * 1024; // 1GB
return 256 * 1024 * 1024; // 256MB. See T13142 and T13143.
}
public static function getEnormousTimeLimit() {

View File

@@ -33,7 +33,24 @@ final class DiffusionSubversionWireProtocol extends Phobject {
$messages = array();
while (true) {
if ($this->state == 'item') {
if ($this->state == 'space') {
// Consume zero or more extra spaces after matching an item. The
// protocol requires at least one space, but allows more than one.
$matches = null;
if (!preg_match('/^(\s*)\S/', $this->buffer, $matches)) {
// Wait for more data.
break;
}
// We have zero or more spaces and then some other character, so throw
// the spaces away and continue parsing frames.
if (strlen($matches[1])) {
$this->buffer = substr($this->buffer, strlen($matches[1]));
}
$this->state = 'item';
} else if ($this->state == 'item') {
$match = null;
$result = null;
$buf = $this->buffer;
@@ -69,6 +86,12 @@ final class DiffusionSubversionWireProtocol extends Phobject {
);
$this->raw = '';
}
// Consume any extra whitespace after an item. If we're in the
// "bytes" state, we aren't looking for whitespace.
if ($this->state == 'item') {
$this->state = 'space';
}
} else {
// No matches yet, wait for more data.
break;
@@ -90,7 +113,7 @@ final class DiffusionSubversionWireProtocol extends Phobject {
// Strip off the terminal space.
$this->pushItem(substr($this->byteBuffer, 0, -1), 'string');
$this->byteBuffer = '';
$this->state = 'item';
$this->state = 'space';
}
} else {
throw new Exception(pht("Invalid state '%s'!", $this->state));

View File

@@ -59,6 +59,50 @@ final class DiffusionSubversionWireProtocolTestCase
),
),
));
// This is testing that multiple spaces are parsed correctly. See T13140
// for discussion.
$this->assertSameSubversionMessages(
'( get-file true false ) ',
// ^-- Note extra space!
array(
array(
array(
'type' => 'word',
'value' => 'get-file',
),
array(
'type' => 'word',
'value' => 'true',
),
array(
'type' => 'word',
'value' => 'false',
),
),
),
'( get-file true false ) ');
$this->assertSameSubversionMessages(
'( duck 5:quack moo ) ',
array(
array(
array(
'type' => 'word',
'value' => 'duck',
),
array(
'type' => 'string',
'value' => 'quack',
),
array(
'type' => 'word',
'value' => 'moo',
),
),
),
'( duck 5:quack moo ) ');
}
public function testSubversionWireProtocolPartialFrame() {
@@ -86,7 +130,11 @@ final class DiffusionSubversionWireProtocolTestCase
ipull($msg2, 'structure'));
}
private function assertSameSubversionMessages($string, array $structs) {
private function assertSameSubversionMessages(
$string,
array $structs,
$serial_string = null) {
$proto = new DiffusionSubversionWireProtocol();
// Verify that the wire message parses into the structs.
@@ -100,6 +148,13 @@ final class DiffusionSubversionWireProtocolTestCase
$serial[] = $proto->serializeStruct($struct);
}
$serial = implode('', $serial);
$this->assertEqual($string, $serial, 'serialize<'.$string.'>');
if ($serial_string === null) {
$expect_serial = $string;
} else {
$expect_serial = $serial_string;
}
$this->assertEqual($expect_serial, $serial, 'serialize<'.$string.'>');
}
}

View File

@@ -22,9 +22,14 @@ final class DiffusionCommitQuery
private $epochMin;
private $epochMax;
private $importing;
private $ancestorsOf;
private $needCommitData;
private $needDrafts;
private $needIdentities;
private $mustFilterRefs = false;
private $refRepository;
public function withIDs(array $ids) {
$this->ids = $ids;
@@ -92,7 +97,7 @@ final class DiffusionCommitQuery
}
public function withRepositoryIDs(array $repository_ids) {
$this->repositoryIDs = $repository_ids;
$this->repositoryIDs = array_unique($repository_ids);
return $this;
}
@@ -106,6 +111,11 @@ final class DiffusionCommitQuery
return $this;
}
public function needIdentities($need) {
$this->needIdentities = $need;
return $this;
}
public function needAuditRequests($need) {
$this->needAuditRequests = $need;
return $this;
@@ -152,6 +162,11 @@ final class DiffusionCommitQuery
return $this;
}
public function withAncestorsOf(array $refs) {
$this->ancestorsOf = $refs;
return $this;
}
public function getIdentifierMap() {
if ($this->identifierMap === null) {
throw new Exception(
@@ -307,6 +322,54 @@ final class DiffusionCommitQuery
protected function didFilterPage(array $commits) {
$viewer = $this->getViewer();
if ($this->mustFilterRefs) {
// If this flag is set, the query has an "Ancestors Of" constraint and
// at least one of the constraining refs had too many ancestors for us
// to apply the constraint with a big "commitIdentifier IN (%Ls)" clause.
// We're going to filter each page and hope we get a full result set
// before the query overheats.
$ancestor_list = mpull($commits, 'getCommitIdentifier');
$ancestor_list = array_values($ancestor_list);
foreach ($this->ancestorsOf as $ref) {
try {
$ancestor_list = DiffusionQuery::callConduitWithDiffusionRequest(
$viewer,
DiffusionRequest::newFromDictionary(
array(
'repository' => $this->refRepository,
'user' => $viewer,
)),
'diffusion.internal.ancestors',
array(
'ref' => $ref,
'commits' => $ancestor_list,
));
} catch (ConduitClientException $ex) {
throw new PhabricatorSearchConstraintException(
$ex->getMessage());
}
if (!$ancestor_list) {
break;
}
}
$ancestor_list = array_fuse($ancestor_list);
foreach ($commits as $key => $commit) {
$identifier = $commit->getCommitIdentifier();
if (!isset($ancestor_list[$identifier])) {
$this->didRejectResult($commit);
unset($commits[$key]);
}
}
if (!$commits) {
return $commits;
}
}
if ($this->needCommitData) {
$data = id(new PhabricatorRepositoryCommitData())->loadAllWhere(
'commitID in (%Ld)',
@@ -336,6 +399,24 @@ final class DiffusionCommitQuery
}
}
if ($this->needIdentities) {
$identity_phids = array_merge(
mpull($commits, 'getAuthorIdentityPHID'),
mpull($commits, 'getCommitterIdentityPHID'));
$data = id(new PhabricatorRepositoryIdentityQuery())
->withPHIDs($identity_phids)
->setViewer($this->getViewer())
->execute();
$data = mpull($data, null, 'getPHID');
foreach ($commits as $commit) {
$author_identity = idx($data, $commit->getAuthorIdentityPHID());
$committer_identity = idx($data, $commit->getCommitterIdentityPHID());
$commit->attachIdentities($author_identity, $committer_identity);
}
}
if ($this->needDrafts) {
PhabricatorDraftEngine::attachDrafts(
$viewer,
@@ -364,6 +445,95 @@ final class DiffusionCommitQuery
$this->withRepositoryIDs($repository_ids);
}
if ($this->ancestorsOf !== null) {
if (count($this->repositoryIDs) !== 1) {
throw new PhabricatorSearchConstraintException(
pht(
'To search for commits which are ancestors of particular refs, '.
'you must constrain the search to exactly one repository.'));
}
$repository_id = head($this->repositoryIDs);
$history_limit = $this->getRawResultLimit() * 32;
$viewer = $this->getViewer();
$repository = id(new PhabricatorRepositoryQuery())
->setViewer($viewer)
->withIDs(array($repository_id))
->executeOne();
if (!$repository) {
throw new PhabricatorEmptyQueryException();
}
if ($repository->isSVN()) {
throw new PhabricatorSearchConstraintException(
pht(
'Subversion does not support searching for ancestors of '.
'a particular ref. This operation is not meaningful in '.
'Subversion.'));
}
if ($repository->isHg()) {
throw new PhabricatorSearchConstraintException(
pht(
'Mercurial does not currently support searching for ancestors of '.
'a particular ref.'));
}
$can_constrain = true;
$history_identifiers = array();
foreach ($this->ancestorsOf as $key => $ref) {
try {
$raw_history = DiffusionQuery::callConduitWithDiffusionRequest(
$viewer,
DiffusionRequest::newFromDictionary(
array(
'repository' => $repository,
'user' => $viewer,
)),
'diffusion.historyquery',
array(
'commit' => $ref,
'limit' => $history_limit,
));
} catch (ConduitClientException $ex) {
throw new PhabricatorSearchConstraintException(
$ex->getMessage());
}
$ref_identifiers = array();
foreach ($raw_history['pathChanges'] as $change) {
$ref_identifiers[] = $change['commitIdentifier'];
}
// If this ref had fewer total commits than the limit, we're safe to
// apply the constraint as a large `IN (...)` query for a list of
// commit identifiers. This is efficient.
if ($history_limit) {
if (count($ref_identifiers) >= $history_limit) {
$can_constrain = false;
break;
}
}
$history_identifiers += array_fuse($ref_identifiers);
}
// If all refs had a small number of ancestors, we can just put the
// constraint into the query here and we're done. Otherwise, we need
// to filter each page after it comes out of the MySQL layer.
if ($can_constrain) {
$where[] = qsprintf(
$conn,
'commit.commitIdentifier IN (%Ls)',
$history_identifiers);
} else {
$this->mustFilterRefs = true;
$this->refRepository = $repository;
}
}
if ($this->ids !== null) {
$where[] = qsprintf(
$conn,

View File

@@ -0,0 +1,108 @@
<?php
final class DiffusionRepositoryIdentitySearchEngine
extends PhabricatorApplicationSearchEngine {
public function getResultTypeDescription() {
return pht('Repository Identities');
}
public function getApplicationClassName() {
return 'PhabricatorDiffusionApplication';
}
public function newQuery() {
return new PhabricatorRepositoryIdentityQuery();
}
protected function buildCustomSearchFields() {
return array(
id(new DiffusionIdentityAssigneeSearchField())
->setLabel(pht('Assigned To'))
->setKey('assignee')
->setDescription(pht('Search for identities by assignee.')),
id(new PhabricatorSearchTextField())
->setLabel(pht('Identity Contains'))
->setKey('match')
->setDescription(pht('Search for identities by substring.')),
id(new PhabricatorSearchThreeStateField())
->setLabel(pht('Is Assigned'))
->setKey('hasEffectivePHID')
->setOptions(
pht('(Show All)'),
pht('Show Only Assigned Identities'),
pht('Show Only Unassigned Identities')),
);
}
protected function buildQueryFromParameters(array $map) {
$query = $this->newQuery();
if ($map['hasEffectivePHID'] !== null) {
$query->withHasEffectivePHID($map['hasEffectivePHID']);
}
if ($map['match'] !== null) {
$query->withIdentityNameLike($map['match']);
}
if ($map['assignee']) {
$query->withAssigneePHIDs($map['assignee']);
}
return $query;
}
protected function getURI($path) {
return '/diffusion/identity/'.$path;
}
protected function getBuiltinQueryNames() {
$names = array(
'all' => pht('All Identities'),
);
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
switch ($query_key) {
case 'all':
return $query;
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
protected function renderResultList(
array $identities,
PhabricatorSavedQuery $query,
array $handles) {
assert_instances_of($identities, 'PhabricatorRepositoryIdentity');
$viewer = $this->requireViewer();
$list = new PHUIObjectItemListView();
$list->setUser($viewer);
foreach ($identities as $identity) {
$item = id(new PHUIObjectItemView())
->setObjectName(pht('Identity %d', $identity->getID()))
->setHeader($identity->getIdentityShortName())
->setHref($identity->getURI())
->setObject($identity);
$list->addItem($item);
}
$result = new PhabricatorApplicationSearchResultView();
$result->setObjectList($list);
$result->setNoDataString(pht('No Identities found.'));
return $result;
}
}

View File

@@ -0,0 +1,22 @@
<?php
final class DiffusionIdentityAssigneeSearchField
extends PhabricatorSearchTokenizerField {
protected function getDefaultValue() {
return array();
}
protected function getValueFromRequest(AphrontRequest $request, $key) {
return $this->getUsersFromRequest($request, $key);
}
protected function newDatasource() {
return new DiffusionIdentityAssigneeDatasource();
}
protected function newConduitParameterType() {
return new ConduitUserListParameterType();
}
}

View File

@@ -0,0 +1,21 @@
<?php
final class DiffusionIdentityAssigneeDatasource
extends PhabricatorTypeaheadCompositeDatasource {
public function getBrowseTitle() {
return pht('Browse Assignee');
}
public function getPlaceholderText() {
return pht('Type a username or function...');
}
public function getComponentDatasources() {
return array(
new PhabricatorPeopleDatasource(),
new DiffusionIdentityUnassignedDatasource(),
);
}
}

View File

@@ -0,0 +1,77 @@
<?php
final class DiffusionIdentityUnassignedDatasource
extends PhabricatorTypeaheadDatasource {
const FUNCTION_TOKEN = 'unassigned()';
public function getBrowseTitle() {
return pht('Browse Explicitly Unassigned');
}
public function getPlaceholderText() {
return pht('Type "unassigned"...');
}
public function getDatasourceApplicationClass() {
return 'PhabricatorDiffusionApplication';
}
public function getDatasourceFunctions() {
return array(
'unassigned' => array(
'name' => pht('Explicitly Unassigned'),
'summary' => pht('Find results which are not assigned.'),
'description' => pht(
"This function includes results which have been explicitly ".
"unassigned. Use a query like this to find explicitly ".
"unassigned results:\n\n%s\n\n".
"If you combine this function with other functions, the query will ".
"return results which match the other selectors //or// have no ".
"assignee. For example, this query will find results which are ".
"assigned to `alincoln`, and will also find results which have been ".
"unassigned:\n\n%s",
'> unassigned()',
'> alincoln, unassigned()'),
),
);
}
public function loadResults() {
$results = array(
$this->buildUnassignedResult(),
);
return $this->filterResultsAgainstTokens($results);
}
protected function evaluateFunction($function, array $argv_list) {
$results = array();
foreach ($argv_list as $argv) {
$results[] = self::FUNCTION_TOKEN;
}
return $results;
}
public function renderFunctionTokens($function, array $argv_list) {
$results = array();
foreach ($argv_list as $argv) {
$results[] = PhabricatorTypeaheadTokenView::newFromTypeaheadResult(
$this->buildUnassignedResult());
}
return $results;
}
private function buildUnassignedResult() {
$name = pht('Unassigned');
return $this->newFunctionResult()
->setName($name.' unassigned')
->setDisplayName($name)
->setIcon('fa-ban')
->setPHID('unassigned()')
->setUnique(true)
->addAttribute(pht('Select results with no owner.'));
}
}

View File

@@ -14,6 +14,8 @@ final class DiffusionPushLogListView extends AphrontView {
$logs = $this->logs;
$viewer = $this->getViewer();
$reject_herald = PhabricatorRepositoryPushLog::REJECT_HERALD;
$handle_phids = array();
foreach ($logs as $log) {
$handle_phids[] = $log->getPusherPHID();
@@ -21,9 +23,13 @@ final class DiffusionPushLogListView extends AphrontView {
if ($device_phid) {
$handle_phids[] = $device_phid;
}
if ($log->getPushEvent()->getRejectCode() == $reject_herald) {
$handle_phids[] = $log->getPushEvent()->getRejectDetails();
}
}
$handles = $viewer->loadHandles($handle_phids);
$viewer->loadHandles($handle_phids);
// Only administrators can view remote addresses.
$remotes_visible = $viewer->getIsAdmin();
@@ -74,10 +80,17 @@ final class DiffusionPushLogListView extends AphrontView {
$flag_names);
$reject_code = $log->getPushEvent()->getRejectCode();
$reject_label = idx(
$reject_map,
$reject_code,
pht('Unknown ("%s")', $reject_code));
if ($reject_code == $reject_herald) {
$rule_phid = $log->getPushEvent()->getRejectDetails();
$handle = $viewer->renderHandle($rule_phid);
$reject_label = pht('Blocked: %s', $handle);
} else {
$reject_label = idx(
$reject_map,
$reject_code,
pht('Unknown ("%s")', $reject_code));
}
$rows[] = array(
phutil_tag(

View File

@@ -88,12 +88,29 @@ final class PhabricatorFileDataController extends PhabricatorFileController {
$response->setMimeType($file->getViewableMimeType());
} else {
$is_post = $request->isHTTPPost();
$is_public = !$viewer->isLoggedIn();
// NOTE: Require POST to download files from the primary domain. If the
// request is not a POST request but arrives on the primary domain, we
// render a confirmation dialog. For discussion, see T13094.
$is_safe = ($is_alternate_domain || $is_lfs || $is_post);
// There are two exceptions to this rule:
// Git LFS requests can download with GET. This is safe (Git LFS won't
// execute files it downloads) and necessary to support Git LFS.
// Requests with no credentials may also download with GET. This
// primarily supports downloading files with `arc download` or other
// API clients. This is only "mostly" safe: if you aren't logged in, you
// are likely immune to XSS and CSRF. However, an attacker may still be
// able to set cookies on this domain (for example, to fixate your
// session). For now, we accept these risks because users running
// Phabricator in this mode are knowingly accepting a security risk
// against setup advice, and there's significant value in having
// API development against test and production installs work the same
// way.
$is_safe = ($is_alternate_domain || $is_post || $is_lfs || $is_public);
if (!$is_safe) {
return $this->newDialog()
->setSubmitURI($file->getDownloadURI())

View File

@@ -7,6 +7,7 @@ abstract class PhabricatorDocumentEngine
private $highlightedLines = array();
private $encodingConfiguration;
private $highlightingConfiguration;
private $blameConfiguration = true;
final public function setViewer(PhabricatorUser $viewer) {
$this->viewer = $viewer;
@@ -60,6 +61,19 @@ abstract class PhabricatorDocumentEngine
return $this->highlightingConfiguration;
}
final public function setBlameConfiguration($blame_configuration) {
$this->blameConfiguration = $blame_configuration;
return $this;
}
final public function getBlameConfiguration() {
return $this->blameConfiguration;
}
final protected function getBlameEnabled() {
return $this->blameConfiguration;
}
public function shouldRenderAsync(PhabricatorDocumentRef $ref) {
return false;
}

View File

@@ -119,11 +119,23 @@ final class PhabricatorDocumentRef
}
$snippet = $this->getSnippet();
if (!preg_match('/^\s*[{[]/', $snippet)) {
// If the file is longer than the snippet, we don't detect the content
// as JSON. We could use some kind of heuristic here if we wanted, but
// see PHI749 for a false positive.
if (strlen($snippet) < $this->getByteLength()) {
return false;
}
return phutil_is_utf8($snippet);
// If the snippet is the whole file, just check if the snippet is valid
// JSON. Note that `phutil_json_decode()` only accepts arrays and objects
// as JSON, so this won't misfire on files with content like "3".
try {
phutil_json_decode($snippet);
return true;
} catch (Exception $ex) {
return false;
}
}
public function getSnippet() {

View File

@@ -50,7 +50,7 @@ final class PhabricatorSourceDocumentEngine
}
$options = array();
if ($ref->getBlameURI()) {
if ($ref->getBlameURI() && $this->getBlameEnabled()) {
$content = phutil_split_lines($content);
$blame = range(1, count($content));
$blame = array_fuse($blame);

View File

@@ -69,6 +69,9 @@ abstract class PhabricatorDocumentRenderingEngine
$engine->setHighlightingConfiguration($highlight_setting);
}
$blame_setting = ($request->getStr('blame') !== 'off');
$engine->setBlameConfiguration($blame_setting);
$views = array();
foreach ($engines as $candidate_key => $candidate_engine) {
$label = $candidate_engine->getViewAsLabel($ref);
@@ -104,6 +107,8 @@ abstract class PhabricatorDocumentRenderingEngine
'controlID' => $control_id,
);
$this->willStageRef($ref);
if ($engine->shouldRenderAsync($ref)) {
$content = $engine->newLoadingContent($ref);
$config['next'] = 'render';
@@ -142,7 +147,11 @@ abstract class PhabricatorDocumentRenderingEngine
'value' => $highlight_setting,
),
'blame' => array(
'icon' => 'fa-backward',
'hide' => pht('Hide Blame'),
'show' => pht('Show Blame'),
'uri' => $ref->getBlameURI(),
'enabled' => $blame_setting,
'value' => null,
),
'coverage' => array(
@@ -180,6 +189,7 @@ abstract class PhabricatorDocumentRenderingEngine
}
final public function newRenderResponse(PhabricatorDocumentRef $ref) {
$this->willStageRef($ref);
$this->willRenderRef($ref);
$request = $this->getRequest();
@@ -207,6 +217,9 @@ abstract class PhabricatorDocumentRenderingEngine
$engine->setHighlightingConfiguration($highlight_setting);
}
$blame_setting = ($request->getStr('blame') !== 'off');
$engine->setBlameConfiguration($blame_setting);
try {
$content = $engine->newDocument($ref);
} catch (Exception $ex) {
@@ -314,6 +327,10 @@ abstract class PhabricatorDocumentRenderingEngine
return;
}
protected function willStageRef(PhabricatorDocumentRef $ref) {
return;
}
protected function willRenderRef(PhabricatorDocumentRef $ref) {
return;
}

View File

@@ -247,7 +247,14 @@ final class PhabricatorFaviconRef extends Phobject {
$src_w = $template['width'];
$src_h = $template['height'];
$template_data = $template['file']->loadFileData();
try {
$template_data = $template['file']->loadFileData();
} catch (Exception $ex) {
// In rare cases, we can end up with a corrupted or inaccessible file.
// If we do, just give up: otherwise, it's impossible to get pages to
// generate and not obvious how to fix it.
return null;
}
if (!function_exists('imagecreatefromstring')) {
return $template_data;

View File

@@ -85,6 +85,32 @@ final class PhabricatorFilesManagementMigrateWorkflow
foreach ($iterator as $file) {
$monogram = $file->getMonogram();
// See T7148. When we export data for an instance, we copy all the data
// for Files from S3 into the database dump so that the database dump is
// a complete, standalone archive of all the data. In the general case,
// installs may have a similar process using "--copy" to create a more
// complete backup.
// When doing this, we may run into temporary files which have been
// deleted between the time we took the original dump and the current
// timestamp. These files can't be copied since the data no longer
// exists: the daemons on the live install already deleted it.
// Simply avoid this whole mess by declining to migrate expired temporary
// files. They're as good as dead anyway.
$ttl = $file->getTTL();
if ($ttl) {
if ($ttl < PhabricatorTime::getNow()) {
echo tsprintf(
"%s\n",
pht(
'%s: Skipping expired temporary file.',
$monogram));
continue;
}
}
$engine_key = $file->getStorageEngine();
$engine = idx($engines, $engine_key);

View File

@@ -260,6 +260,18 @@ final class PhabricatorEmbedFileRemarkupRule
$autoplay = null;
}
if ($is_video) {
// See T13135. Chrome refuses to play videos with type "video/quicktime",
// even though it may actually be able to play them. The least awful fix
// based on available information is to simply omit the "type" attribute
// from `<source />` tags. This causes Chrome to try to play the video
// and realize it can, and does not appear to produce any bad behavior in
// any other browser.
$mime_type = null;
} else {
$mime_type = $file->getMimeType();
}
return $this->newTag(
$tag,
array(
@@ -274,7 +286,7 @@ final class PhabricatorEmbedFileRemarkupRule
'source',
array(
'src' => $file->getBestURI(),
'type' => $file->getMimeType(),
'type' => $mime_type,
)));
}

View File

@@ -492,12 +492,13 @@ final class PhabricatorFile extends PhabricatorFileDAO
$this->setStorageFormat($format->getStorageFormatKey());
$this->setStorageProperties($properties);
list($identifier, $new_handle) = $this->writeToEngine(
list($identifier, $new_handle, $integrity_hash) = $this->writeToEngine(
$engine,
$data,
$params);
$this->setStorageHandle($new_handle);
$this->setIntegrityHash($integrity_hash);
$this->save();
$this->deleteFileDataIfUnused(

View File

@@ -3,6 +3,10 @@
final class HarbormasterBuildLogDownloadController
extends HarbormasterController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$request = $this->getRequest();
$viewer = $request->getUser();

View File

@@ -3,6 +3,10 @@
final class HarbormasterBuildLogRenderController
extends HarbormasterController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();

View File

@@ -3,6 +3,10 @@
final class HarbormasterBuildLogViewController
extends HarbormasterController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();

View File

@@ -3,6 +3,10 @@
final class HarbormasterBuildViewController
extends HarbormasterController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$request = $this->getRequest();
$viewer = $request->getUser();

View File

@@ -3,6 +3,10 @@
final class HarbormasterBuildableViewController
extends HarbormasterController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
@@ -350,6 +354,4 @@ final class HarbormasterBuildableViewController
return array($lint, $unit);
}
}

View File

@@ -3,6 +3,10 @@
final class HarbormasterLintMessagesController
extends HarbormasterController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();

View File

@@ -2,6 +2,10 @@
final class HarbormasterPlanViewController extends HarbormasterPlanController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
$id = $request->getURIData('id');

View File

@@ -3,6 +3,10 @@
final class HarbormasterStepViewController
extends HarbormasterPlanController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
$id = $request->getURIData('id');

View File

@@ -3,6 +3,10 @@
final class HarbormasterUnitMessageListController
extends HarbormasterController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();

View File

@@ -3,6 +3,10 @@
final class HarbormasterUnitMessageViewController
extends HarbormasterController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();

View File

@@ -106,6 +106,14 @@ EOTEXT
),
'meta_data' => array(
'buildTargetPHID' => $build_target->getPHID(),
// See PHI611. These are undocumented secret magic.
'phabricator:build:id' => (int)$build->getID(),
'phabricator:build:url' =>
PhabricatorEnv::getProductionURI($build->getURI()),
'phabricator:buildable:id' => (int)$buildable->getID(),
'phabricator:buildable:url' =>
PhabricatorEnv::getProductionURI($buildable->getURI()),
),
);

View File

@@ -643,7 +643,13 @@ final class HarbormasterBuildLog
$pos += $slice_length;
$map_bytes += $slice_length;
$line_count += count(preg_split("/\r\n|\r|\n/", $slice)) - 1;
// Count newlines in the slice. This goofy approach is meaningfully
// faster than "preg_match_all()" or "preg_split()". See PHI766.
$n_rn = substr_count($slice, "\r\n");
$n_r = substr_count($slice, "\r");
$n_n = substr_count($slice, "\n");
$line_count += ($n_rn) + ($n_r - $n_rn) + ($n_n - $n_rn);
if ($map_bytes >= ($marker_distance - $max_utf8_width)) {
$map[] = array(

View File

@@ -46,7 +46,13 @@ final class HarbormasterTargetWorker extends HarbormasterWorker {
$build = $target->getBuild();
$viewer = $this->getViewer();
$target->setDateStarted(time());
// If this is the first time we're starting work on this target, mark the
// current time as the start time. If the target yields or waits, we may
// end up here again later, so we don't want to overwrite the start time if
// we already have a value.
if (!$target->getDateStarted()) {
$target->setDateStarted(PhabricatorTime::getNow());
}
try {
if ($target->getBuildGeneration() !== $build->getBuildGeneration()) {

View File

@@ -0,0 +1,74 @@
<?php
final class HeraldRuleAdapter extends HeraldAdapter {
private $rule;
protected function newObject() {
return new HeraldRule();
}
public function getAdapterApplicationClass() {
return 'PhabricatorHeraldApplication';
}
public function getAdapterContentDescription() {
return pht('React to Herald rules being created or updated.');
}
public function isTestAdapterForObject($object) {
return ($object instanceof HeraldRule);
}
public function getAdapterTestDescription() {
return pht(
'Test rules which run when another Herald rule is created or '.
'updated.');
}
protected function initializeNewAdapter() {
$this->rule = $this->newObject();
}
public function supportsApplicationEmail() {
return true;
}
public function supportsRuleType($rule_type) {
switch ($rule_type) {
case HeraldRuleTypeConfig::RULE_TYPE_GLOBAL:
case HeraldRuleTypeConfig::RULE_TYPE_PERSONAL:
return true;
case HeraldRuleTypeConfig::RULE_TYPE_OBJECT:
default:
return false;
}
}
public function setRule(HeraldRule $rule) {
$this->rule = $rule;
return $this;
}
public function getRule() {
return $this->rule;
}
public function setObject($object) {
$this->rule = $object;
return $this;
}
public function getObject() {
return $this->rule;
}
public function getAdapterContentName() {
return pht('Herald Rules');
}
public function getHeraldName() {
return $this->getRule()->getMonogram();
}
}

View File

@@ -38,8 +38,10 @@ final class HeraldTestConsoleController extends HeraldController {
$object = $this->getTestObject();
$adapter = $this->getTestAdapter();
$source = $this->newContentSource($object);
$adapter
->setContentSource($source)
->setIsNewObject(false)
->setActingAsPHID($viewer->getPHID())
->setViewer($viewer);
@@ -218,4 +220,29 @@ final class HeraldTestConsoleController extends HeraldController {
->appendChild($view);
}
private function newContentSource($object) {
$viewer = $this->getViewer();
// Try using the content source associated with the most recent transaction
// on the object.
$query = PhabricatorApplicationTransactionQuery::newQueryForObject($object);
$xaction = $query
->setViewer($viewer)
->withObjectPHIDs(array($object->getPHID()))
->setLimit(1)
->setOrder('newest')
->executeOne();
if ($xaction) {
return $xaction->getContentSource();
}
// If we couldn't find a transaction (which should be rare), fall back to
// building a new content source from the test console request itself.
$request = $this->getRequest();
return PhabricatorContentSource::newFromRequest($request);
}
}

View File

@@ -87,4 +87,68 @@ final class HeraldRuleEditor
return;
}
protected function shouldApplyHeraldRules(
PhabricatorLiskDAO $object,
array $xactions) {
return true;
}
protected function buildHeraldAdapter(
PhabricatorLiskDAO $object,
array $xactions) {
return id(new HeraldRuleAdapter())
->setRule($object);
}
protected function shouldSendMail(
PhabricatorLiskDAO $object,
array $xactions) {
return true;
}
protected function getMailTo(PhabricatorLiskDAO $object) {
$phids = array();
$phids[] = $this->getActingAsPHID();
if ($object->isPersonalRule()) {
$phids[] = $object->getAuthorPHID();
}
return $phids;
}
protected function buildReplyHandler(PhabricatorLiskDAO $object) {
return id(new HeraldRuleReplyHandler())
->setMailReceiver($object);
}
protected function buildMailTemplate(PhabricatorLiskDAO $object) {
$monogram = $object->getMonogram();
$name = $object->getName();
$subject = pht('%s: %s', $monogram, $name);
return id(new PhabricatorMetaMTAMail())
->setSubject($subject);
}
protected function getMailSubjectPrefix() {
return pht('[Herald]');
}
protected function buildMailBody(
PhabricatorLiskDAO $object,
array $xactions) {
$body = parent::buildMailBody($object, $xactions);
$body->addLinkSection(
pht('RULE DETAIL'),
PhabricatorEnv::getProductionURI($object->getURI()));
return $body;
}
}

Some files were not shown because too many files have changed in this diff Show More