Merge branch 'master' into blender-tweaks
This commit is contained in:
@@ -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',
|
||||
|
||||
@@ -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};
|
||||
14
resources/sql/autopatches/20180430.repo_identity.sql
Normal file
14
resources/sql/autopatches/20180430.repo_identity.sql
Normal 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};
|
||||
26
resources/sql/autopatches/20180504.owners.01.mailkey.php
Normal file
26
resources/sql/autopatches/20180504.owners.01.mailkey.php
Normal 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());
|
||||
}
|
||||
2
resources/sql/autopatches/20180504.owners.02.rmkey.sql
Normal file
2
resources/sql/autopatches/20180504.owners.02.rmkey.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE {$NAMESPACE}_owners.owners_package
|
||||
DROP mailKey;
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE {$NAMESPACE}_owners.owners_package
|
||||
ADD properties LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT};
|
||||
2
resources/sql/autopatches/20180504.owners.04.default.sql
Normal file
2
resources/sql/autopatches/20180504.owners.04.default.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
UPDATE {$NAMESPACE}_owners.owners_package
|
||||
SET properties = '{}' WHERE properties = '';
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE {$NAMESPACE}_repository.repository_identity
|
||||
ADD COLUMN authorPHID VARBINARY(64) NOT NULL;
|
||||
19
resources/sql/autopatches/20180504.repo_identity.xaction.sql
Normal file
19
resources/sql/autopatches/20180504.repo_identity.xaction.sql
Normal 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};
|
||||
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE {$NAMESPACE}_repository.repository_commit
|
||||
ADD COLUMN authorIdentityPHID VARBINARY(64) DEFAULT NULL,
|
||||
ADD COLUMN committerIdentityPHID VARBINARY(64) DEFAULT NULL;
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE {$NAMESPACE}_phriction.phriction_document
|
||||
ADD spacePHID VARBINARY(64) DEFAULT NULL;
|
||||
2
resources/sql/autopatches/20180730.project.01.spaces.sql
Normal file
2
resources/sql/autopatches/20180730.project.01.spaces.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE {$NAMESPACE}_project.project
|
||||
ADD COLUMN spacePHID VARBINARY(64) DEFAULT NULL;
|
||||
@@ -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',
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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".')),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ final class PhabricatorConfigApplication extends PhabricatorApplication {
|
||||
}
|
||||
|
||||
public function getTitleGlyph() {
|
||||
return "\xE2\x98\xBA";
|
||||
return "\xE2\x9C\xA8";
|
||||
}
|
||||
|
||||
public function getApplicationGroup() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 )----------------------------------------- */
|
||||
|
||||
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -307,7 +307,7 @@ final class DifferentialRevisionUpdateHistoryView extends AphrontView {
|
||||
$content = phabricator_form(
|
||||
$this->getUser(),
|
||||
array(
|
||||
'action' => '#toc',
|
||||
'action' => '/D'.$revision_id.'#toc',
|
||||
),
|
||||
array(
|
||||
$table,
|
||||
|
||||
@@ -86,4 +86,12 @@ final class DifferentialRevisionAbandonTransaction
|
||||
$this->renderObject());
|
||||
}
|
||||
|
||||
public function getTransactionTypeForConduit($xaction) {
|
||||
return 'abandon';
|
||||
}
|
||||
|
||||
public function getFieldValuesForConduit($object, $data) {
|
||||
return array();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -154,5 +154,4 @@ final class DifferentialRevisionCloseTransaction
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -87,4 +87,12 @@ final class DifferentialRevisionCommandeerTransaction
|
||||
$this->renderObject());
|
||||
}
|
||||
|
||||
public function getTransactionTypeForConduit($xaction) {
|
||||
return 'commandeer';
|
||||
}
|
||||
|
||||
public function getFieldValuesForConduit($object, $data) {
|
||||
return array();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -85,4 +85,12 @@ final class DifferentialRevisionReclaimTransaction
|
||||
$this->renderObject());
|
||||
}
|
||||
|
||||
public function getTransactionTypeForConduit($xaction) {
|
||||
return 'reclaim';
|
||||
}
|
||||
|
||||
public function getFieldValuesForConduit($object, $data) {
|
||||
return array();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -72,4 +72,12 @@ final class DifferentialRevisionReopenTransaction
|
||||
$this->renderObject());
|
||||
}
|
||||
|
||||
public function getTransactionTypeForConduit($xaction) {
|
||||
return 'reopen';
|
||||
}
|
||||
|
||||
public function getFieldValuesForConduit($object, $data) {
|
||||
return array();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -84,4 +84,12 @@ final class DifferentialRevisionRequestReviewTransaction
|
||||
$this->renderObject());
|
||||
}
|
||||
|
||||
public function getTransactionTypeForConduit($xaction) {
|
||||
return 'request-review';
|
||||
}
|
||||
|
||||
public function getFieldValuesForConduit($object, $data) {
|
||||
return array();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -93,4 +93,12 @@ final class DifferentialRevisionResignTransaction
|
||||
$this->renderObject());
|
||||
}
|
||||
|
||||
public function getTransactionTypeForConduit($xaction) {
|
||||
return 'resign';
|
||||
}
|
||||
|
||||
public function getFieldValuesForConduit($object, $data) {
|
||||
return array();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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>[^/]+)/'
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,6 +22,7 @@ final class DiffusionBranchTableController extends DiffusionController {
|
||||
$params = array(
|
||||
'offset' => $pager->getOffset(),
|
||||
'limit' => $pager->getPageSize() + 1,
|
||||
'branch' => null,
|
||||
);
|
||||
|
||||
$contains = $drequest->getSymbolicCommit();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
final class DiffusionIdentityEditController
|
||||
extends DiffusionController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
return id(new PhabricatorRepositoryIdentityEditEngine())
|
||||
->setController($this)
|
||||
->buildResponse();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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.'>');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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(),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.'));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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(
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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,
|
||||
)));
|
||||
}
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
final class HarbormasterBuildLogRenderController
|
||||
extends HarbormasterController {
|
||||
|
||||
public function shouldAllowPublic() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
final class HarbormasterBuildLogViewController
|
||||
extends HarbormasterController {
|
||||
|
||||
public function shouldAllowPublic() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
final class HarbormasterLintMessagesController
|
||||
extends HarbormasterController {
|
||||
|
||||
public function shouldAllowPublic() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
final class HarbormasterUnitMessageListController
|
||||
extends HarbormasterController {
|
||||
|
||||
public function shouldAllowPublic() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
final class HarbormasterUnitMessageViewController
|
||||
extends HarbormasterController {
|
||||
|
||||
public function shouldAllowPublic() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
|
||||
@@ -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()),
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
74
src/applications/herald/adapter/HeraldRuleAdapter.php
Normal file
74
src/applications/herald/adapter/HeraldRuleAdapter.php
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user