2013-06-21 12:54:56 -07:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Temporary wrapper for transitioning Differential to ApplicationTransactions.
|
|
|
|
*/
|
|
|
|
final class DifferentialInlineCommentQuery
|
|
|
|
extends PhabricatorOffsetPagedQuery {
|
|
|
|
|
2015-04-20 14:33:58 -07:00
|
|
|
// TODO: Remove this when this query eventually moves to PolicyAware.
|
|
|
|
private $viewer;
|
|
|
|
|
2013-06-21 12:54:56 -07:00
|
|
|
private $ids;
|
2015-03-08 13:04:38 -07:00
|
|
|
private $phids;
|
2015-04-20 14:33:58 -07:00
|
|
|
private $drafts;
|
|
|
|
private $authorPHIDs;
|
|
|
|
private $revisionPHIDs;
|
|
|
|
private $deletedDrafts;
|
Allow inline comments to be individually hidden
Summary:
Ref T7447. Implements per-viewer comment hiding. Once a comment is obsolete or uninteresting, you can hide it completely.
This is sticky per-user.
My hope is that this will strike a better balance between concerns than some of the other approaches (conservative porting, summarization, hide-all).
Specifically, this adds a new action here:
{F435621}
Clicking it completely collapses the comment into a small icon on the previous line, and saves the comment state as hidden for you:
{F435626}
You can click the icon to reveal all hidden comments below the line.
Test Plan:
- Hid comments.
- Showed comments.
- Created, edited, deleted and submitted comments.
- Used Diffusion comments (hiding is not implemented there yet, but I'd plan to bring it there eventually if it works out in Differential).
Reviewers: btrahan, chad
Reviewed By: btrahan
Subscribers: jparise, yelirekim, epriestley
Maniphest Tasks: T7447
Differential Revision: https://secure.phabricator.com/D13009
2015-05-27 10:28:38 -07:00
|
|
|
private $needHidden;
|
2015-04-20 14:33:58 -07:00
|
|
|
|
|
|
|
public function setViewer(PhabricatorUser $viewer) {
|
|
|
|
$this->viewer = $viewer;
|
2013-06-21 12:54:56 -07:00
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2015-04-20 14:33:58 -07:00
|
|
|
public function getViewer() {
|
|
|
|
return $this->viewer;
|
2013-06-21 12:54:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
public function withIDs(array $ids) {
|
|
|
|
$this->ids = $ids;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2015-03-08 13:04:38 -07:00
|
|
|
public function withPHIDs(array $phids) {
|
|
|
|
$this->phids = $phids;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2015-04-20 14:33:58 -07:00
|
|
|
public function withDrafts($drafts) {
|
|
|
|
$this->drafts = $drafts;
|
2013-06-21 12:54:56 -07:00
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2015-04-20 14:33:58 -07:00
|
|
|
public function withAuthorPHIDs(array $author_phids) {
|
|
|
|
$this->authorPHIDs = $author_phids;
|
2013-06-21 12:54:56 -07:00
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2015-04-20 14:33:58 -07:00
|
|
|
public function withRevisionPHIDs(array $revision_phids) {
|
|
|
|
$this->revisionPHIDs = $revision_phids;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function withDeletedDrafts($deleted_drafts) {
|
|
|
|
$this->deletedDrafts = $deleted_drafts;
|
2013-06-21 12:54:56 -07:00
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
Allow inline comments to be individually hidden
Summary:
Ref T7447. Implements per-viewer comment hiding. Once a comment is obsolete or uninteresting, you can hide it completely.
This is sticky per-user.
My hope is that this will strike a better balance between concerns than some of the other approaches (conservative porting, summarization, hide-all).
Specifically, this adds a new action here:
{F435621}
Clicking it completely collapses the comment into a small icon on the previous line, and saves the comment state as hidden for you:
{F435626}
You can click the icon to reveal all hidden comments below the line.
Test Plan:
- Hid comments.
- Showed comments.
- Created, edited, deleted and submitted comments.
- Used Diffusion comments (hiding is not implemented there yet, but I'd plan to bring it there eventually if it works out in Differential).
Reviewers: btrahan, chad
Reviewed By: btrahan
Subscribers: jparise, yelirekim, epriestley
Maniphest Tasks: T7447
Differential Revision: https://secure.phabricator.com/D13009
2015-05-27 10:28:38 -07:00
|
|
|
public function needHidden($need) {
|
|
|
|
$this->needHidden = $need;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2013-06-21 12:54:56 -07:00
|
|
|
public function execute() {
|
Migrate all Differential inline comments to ApplicationTransactions
Summary:
Ref T2222. This implements step (1) described there, which is moving over all the inline comments.
The old and new tables are simliar. The only real trick here is that `transactionPHID` and `legacyCommentID` mean roughly the same thing (`null` if the inline is a draft, non-null if it has been submitted) but we don't have real `transactionPHID`s yet. We just make some up -- we'll backfill them later.
Two risks here:
- I need to take a second look at the keys on this table. I think we need to tweak them a bit, and it will be less disruptive to do that before this migration than after.
- This will take a while for Facebook, and other large installs with tens of thousands of revisions. I'll communicate this.
I'm otherwise pretty satisfied with this, seems to work well and is pretty low risk / non-disruptive.
Test Plan:
- Before migrating, then after migrating:
- Made a bunch of inlines (drafts, submitted).
- Edited and deleted inlines.
- Verified inlines showed up in preview.
- Verified that inlines aren't indexed when they're drafts (`bin/search index D935`).
- Verified that inlines ARE indexed when they're not drafts.
- Verified that drafts inlines make revisions appear as "with draft" in the revision list.
- Made left, right, and draft inlines.
- Migrated (`bin/storage upgrade`).
- Verified that my inlines from before the migration still showed up.
- (Repeated all the stuff above.)
- Manually inspected the inline comment table.
Reviewers: btrahan
Reviewed By: btrahan
CC: FacebookPOC, aran
Maniphest Tasks: T2222
Differential Revision: https://secure.phabricator.com/D7139
2013-10-19 05:03:25 -07:00
|
|
|
$table = new DifferentialTransactionComment();
|
2013-06-21 12:54:56 -07:00
|
|
|
$conn_r = $table->establishConnection('r');
|
|
|
|
|
|
|
|
$data = queryfx_all(
|
|
|
|
$conn_r,
|
|
|
|
'SELECT * FROM %T %Q %Q',
|
|
|
|
$table->getTableName(),
|
|
|
|
$this->buildWhereClause($conn_r),
|
|
|
|
$this->buildLimitClause($conn_r));
|
|
|
|
|
Migrate all Differential inline comments to ApplicationTransactions
Summary:
Ref T2222. This implements step (1) described there, which is moving over all the inline comments.
The old and new tables are simliar. The only real trick here is that `transactionPHID` and `legacyCommentID` mean roughly the same thing (`null` if the inline is a draft, non-null if it has been submitted) but we don't have real `transactionPHID`s yet. We just make some up -- we'll backfill them later.
Two risks here:
- I need to take a second look at the keys on this table. I think we need to tweak them a bit, and it will be less disruptive to do that before this migration than after.
- This will take a while for Facebook, and other large installs with tens of thousands of revisions. I'll communicate this.
I'm otherwise pretty satisfied with this, seems to work well and is pretty low risk / non-disruptive.
Test Plan:
- Before migrating, then after migrating:
- Made a bunch of inlines (drafts, submitted).
- Edited and deleted inlines.
- Verified inlines showed up in preview.
- Verified that inlines aren't indexed when they're drafts (`bin/search index D935`).
- Verified that inlines ARE indexed when they're not drafts.
- Verified that drafts inlines make revisions appear as "with draft" in the revision list.
- Made left, right, and draft inlines.
- Migrated (`bin/storage upgrade`).
- Verified that my inlines from before the migration still showed up.
- (Repeated all the stuff above.)
- Manually inspected the inline comment table.
Reviewers: btrahan
Reviewed By: btrahan
CC: FacebookPOC, aran
Maniphest Tasks: T2222
Differential Revision: https://secure.phabricator.com/D7139
2013-10-19 05:03:25 -07:00
|
|
|
$comments = $table->loadAllFromArray($data);
|
|
|
|
|
Allow inline comments to be individually hidden
Summary:
Ref T7447. Implements per-viewer comment hiding. Once a comment is obsolete or uninteresting, you can hide it completely.
This is sticky per-user.
My hope is that this will strike a better balance between concerns than some of the other approaches (conservative porting, summarization, hide-all).
Specifically, this adds a new action here:
{F435621}
Clicking it completely collapses the comment into a small icon on the previous line, and saves the comment state as hidden for you:
{F435626}
You can click the icon to reveal all hidden comments below the line.
Test Plan:
- Hid comments.
- Showed comments.
- Created, edited, deleted and submitted comments.
- Used Diffusion comments (hiding is not implemented there yet, but I'd plan to bring it there eventually if it works out in Differential).
Reviewers: btrahan, chad
Reviewed By: btrahan
Subscribers: jparise, yelirekim, epriestley
Maniphest Tasks: T7447
Differential Revision: https://secure.phabricator.com/D13009
2015-05-27 10:28:38 -07:00
|
|
|
if ($this->needHidden) {
|
|
|
|
$viewer_phid = $this->getViewer()->getPHID();
|
|
|
|
if ($viewer_phid && $comments) {
|
|
|
|
$hidden = queryfx_all(
|
|
|
|
$conn_r,
|
|
|
|
'SELECT commentID FROM %T WHERE userPHID = %s
|
|
|
|
AND commentID IN (%Ls)',
|
|
|
|
id(new DifferentialHiddenComment())->getTableName(),
|
|
|
|
$viewer_phid,
|
|
|
|
mpull($comments, 'getID'));
|
|
|
|
$hidden = array_fuse(ipull($hidden, 'commentID'));
|
|
|
|
} else {
|
|
|
|
$hidden = array();
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ($comments as $inline) {
|
|
|
|
$inline->attachIsHidden(isset($hidden[$inline->getID()]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Migrate all Differential inline comments to ApplicationTransactions
Summary:
Ref T2222. This implements step (1) described there, which is moving over all the inline comments.
The old and new tables are simliar. The only real trick here is that `transactionPHID` and `legacyCommentID` mean roughly the same thing (`null` if the inline is a draft, non-null if it has been submitted) but we don't have real `transactionPHID`s yet. We just make some up -- we'll backfill them later.
Two risks here:
- I need to take a second look at the keys on this table. I think we need to tweak them a bit, and it will be less disruptive to do that before this migration than after.
- This will take a while for Facebook, and other large installs with tens of thousands of revisions. I'll communicate this.
I'm otherwise pretty satisfied with this, seems to work well and is pretty low risk / non-disruptive.
Test Plan:
- Before migrating, then after migrating:
- Made a bunch of inlines (drafts, submitted).
- Edited and deleted inlines.
- Verified inlines showed up in preview.
- Verified that inlines aren't indexed when they're drafts (`bin/search index D935`).
- Verified that inlines ARE indexed when they're not drafts.
- Verified that drafts inlines make revisions appear as "with draft" in the revision list.
- Made left, right, and draft inlines.
- Migrated (`bin/storage upgrade`).
- Verified that my inlines from before the migration still showed up.
- (Repeated all the stuff above.)
- Manually inspected the inline comment table.
Reviewers: btrahan
Reviewed By: btrahan
CC: FacebookPOC, aran
Maniphest Tasks: T2222
Differential Revision: https://secure.phabricator.com/D7139
2013-10-19 05:03:25 -07:00
|
|
|
foreach ($comments as $key => $value) {
|
|
|
|
$comments[$key] = DifferentialInlineComment::newFromModernComment(
|
|
|
|
$value);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $comments;
|
2013-06-21 12:54:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
public function executeOne() {
|
2015-04-20 14:33:58 -07:00
|
|
|
// TODO: Remove when this query moves to PolicyAware.
|
2013-06-21 12:54:56 -07:00
|
|
|
return head($this->execute());
|
|
|
|
}
|
|
|
|
|
Make buildWhereClause() a method of AphrontCursorPagedPolicyAwareQuery
Summary:
Ref T4100. Ref T5595.
To support a unified "Projects:" query across all applications, a future diff is going to add a set of "Edge Logic" capabilities to `PolicyAwareQuery` which write the required SELECT, JOIN, WHERE, HAVING and GROUP clauses for you.
With the addition of "Edge Logic", we'll have three systems which may need to build components of query claues: ordering/paging, customfields/applicationsearch, and edge logic.
For most clauses, queries don't currently call into the parent explicitly to get default components. I want to move more query construction logic up the class tree so it can be shared.
For most methods, this isn't a problem, but many subclasses define a `buildWhereClause()`. Make all such definitions protected and consistent.
This causes no behavioral changes.
Test Plan: Ran `arc unit --everything`, which does a pretty through job of verifying this statically.
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: yelirekim, hach-que, epriestley
Maniphest Tasks: T4100, T5595
Differential Revision: https://secure.phabricator.com/D12453
2015-04-18 07:08:30 -07:00
|
|
|
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
|
2013-06-21 12:54:56 -07:00
|
|
|
$where = array();
|
|
|
|
|
Migrate all Differential inline comments to ApplicationTransactions
Summary:
Ref T2222. This implements step (1) described there, which is moving over all the inline comments.
The old and new tables are simliar. The only real trick here is that `transactionPHID` and `legacyCommentID` mean roughly the same thing (`null` if the inline is a draft, non-null if it has been submitted) but we don't have real `transactionPHID`s yet. We just make some up -- we'll backfill them later.
Two risks here:
- I need to take a second look at the keys on this table. I think we need to tweak them a bit, and it will be less disruptive to do that before this migration than after.
- This will take a while for Facebook, and other large installs with tens of thousands of revisions. I'll communicate this.
I'm otherwise pretty satisfied with this, seems to work well and is pretty low risk / non-disruptive.
Test Plan:
- Before migrating, then after migrating:
- Made a bunch of inlines (drafts, submitted).
- Edited and deleted inlines.
- Verified inlines showed up in preview.
- Verified that inlines aren't indexed when they're drafts (`bin/search index D935`).
- Verified that inlines ARE indexed when they're not drafts.
- Verified that drafts inlines make revisions appear as "with draft" in the revision list.
- Made left, right, and draft inlines.
- Migrated (`bin/storage upgrade`).
- Verified that my inlines from before the migration still showed up.
- (Repeated all the stuff above.)
- Manually inspected the inline comment table.
Reviewers: btrahan
Reviewed By: btrahan
CC: FacebookPOC, aran
Maniphest Tasks: T2222
Differential Revision: https://secure.phabricator.com/D7139
2013-10-19 05:03:25 -07:00
|
|
|
// Only find inline comments.
|
|
|
|
$where[] = qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
'changesetID IS NOT NULL');
|
|
|
|
|
2015-04-20 14:33:58 -07:00
|
|
|
if ($this->ids !== null) {
|
2013-06-21 12:54:56 -07:00
|
|
|
$where[] = qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
'id IN (%Ld)',
|
|
|
|
$this->ids);
|
|
|
|
}
|
|
|
|
|
2015-03-08 13:04:38 -07:00
|
|
|
if ($this->phids !== null) {
|
|
|
|
$where[] = qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
'phid IN (%Ls)',
|
|
|
|
$this->phids);
|
|
|
|
}
|
|
|
|
|
2015-04-20 14:33:58 -07:00
|
|
|
if ($this->revisionPHIDs !== null) {
|
2013-06-21 12:54:56 -07:00
|
|
|
$where[] = qsprintf(
|
|
|
|
$conn_r,
|
2015-04-20 14:33:58 -07:00
|
|
|
'revisionPHID IN (%Ls)',
|
|
|
|
$this->revisionPHIDs);
|
2013-06-21 12:54:56 -07:00
|
|
|
}
|
|
|
|
|
2015-04-20 14:33:58 -07:00
|
|
|
if ($this->drafts === null) {
|
|
|
|
if ($this->deletedDrafts) {
|
|
|
|
$where[] = qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
'(authorPHID = %s) OR (transactionPHID IS NOT NULL)',
|
|
|
|
$this->getViewer()->getPHID());
|
|
|
|
} else {
|
|
|
|
$where[] = qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
'(authorPHID = %s AND isDeleted = 0)
|
|
|
|
OR (transactionPHID IS NOT NULL)',
|
|
|
|
$this->getViewer()->getPHID());
|
Migrate all Differential inline comments to ApplicationTransactions
Summary:
Ref T2222. This implements step (1) described there, which is moving over all the inline comments.
The old and new tables are simliar. The only real trick here is that `transactionPHID` and `legacyCommentID` mean roughly the same thing (`null` if the inline is a draft, non-null if it has been submitted) but we don't have real `transactionPHID`s yet. We just make some up -- we'll backfill them later.
Two risks here:
- I need to take a second look at the keys on this table. I think we need to tweak them a bit, and it will be less disruptive to do that before this migration than after.
- This will take a while for Facebook, and other large installs with tens of thousands of revisions. I'll communicate this.
I'm otherwise pretty satisfied with this, seems to work well and is pretty low risk / non-disruptive.
Test Plan:
- Before migrating, then after migrating:
- Made a bunch of inlines (drafts, submitted).
- Edited and deleted inlines.
- Verified inlines showed up in preview.
- Verified that inlines aren't indexed when they're drafts (`bin/search index D935`).
- Verified that inlines ARE indexed when they're not drafts.
- Verified that drafts inlines make revisions appear as "with draft" in the revision list.
- Made left, right, and draft inlines.
- Migrated (`bin/storage upgrade`).
- Verified that my inlines from before the migration still showed up.
- (Repeated all the stuff above.)
- Manually inspected the inline comment table.
Reviewers: btrahan
Reviewed By: btrahan
CC: FacebookPOC, aran
Maniphest Tasks: T2222
Differential Revision: https://secure.phabricator.com/D7139
2013-10-19 05:03:25 -07:00
|
|
|
}
|
2015-04-20 14:33:58 -07:00
|
|
|
} else if ($this->drafts) {
|
2013-06-21 12:54:56 -07:00
|
|
|
$where[] = qsprintf(
|
|
|
|
$conn_r,
|
2015-04-20 14:33:58 -07:00
|
|
|
'(authorPHID = %s AND isDeleted = 0) AND (transactionPHID IS NULL)',
|
|
|
|
$this->getViewer()->getPHID());
|
|
|
|
} else {
|
2013-06-21 12:54:56 -07:00
|
|
|
$where[] = qsprintf(
|
|
|
|
$conn_r,
|
2015-04-20 14:33:58 -07:00
|
|
|
'transactionPHID IS NOT NULL');
|
2013-06-21 12:54:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return $this->formatWhereClause($where);
|
|
|
|
}
|
|
|
|
|
2015-04-21 15:31:18 -07:00
|
|
|
public function adjustInlinesForChangesets(
|
|
|
|
array $inlines,
|
|
|
|
array $old,
|
2015-05-04 11:52:21 -07:00
|
|
|
array $new,
|
|
|
|
DifferentialRevision $revision) {
|
2015-04-21 15:31:18 -07:00
|
|
|
|
|
|
|
assert_instances_of($inlines, 'DifferentialInlineComment');
|
|
|
|
assert_instances_of($old, 'DifferentialChangeset');
|
|
|
|
assert_instances_of($new, 'DifferentialChangeset');
|
|
|
|
|
|
|
|
$viewer = $this->getViewer();
|
2015-05-04 12:02:42 -07:00
|
|
|
|
Convert some loadPreferences() to getUserSetting()
Summary:
Ref T4103. This doesn't get everything, but takes care of most of the easy stuff.
The tricky-ish bit here is that I need to move timezones, pronouns and translations to proper settings. I expect to pursue that next.
Test Plan:
- Grepped for `loadPreferences` to identify callsites.
- Changed start-of-week setting, loaded Calendar, saw correct start.
- Visited welcome page, read "Adjust Settings" point.
- Loaded Conpherence -- I changed behavior here slightly (switching threads drops the title glyph) but it wasn't consistent to start with and this seems like a good thing to push to the next version of Conpherence.
- Enabled Filetree, toggled in Differential.
- Disabled Filetree, no longer visible in Differential.
- Changed "Unified Diffs" preference to "Small Screens" vs "Always".
- Toggled filetree in Diffusion.
- Edited a task, saw sensible projects in policy dropdown.
- Viewed user profile, uncollapsed/collapsed side nav, reloaded page, sticky'd.
- Toggled "monospaced textareas", used a comment box, got appropriate fonts.
- Toggled durable column.
- Disabled title glyphs.
- Changed monospaced font to 18px/36px impact.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T4103
Differential Revision: https://secure.phabricator.com/D16004
2016-06-01 13:59:08 -07:00
|
|
|
$no_ghosts = $viewer->compareUserSetting(
|
|
|
|
PhabricatorOlderInlinesSetting::SETTINGKEY,
|
|
|
|
PhabricatorOlderInlinesSetting::VALUE_GHOST_INLINES_DISABLED);
|
|
|
|
if ($no_ghosts) {
|
2015-05-04 12:02:42 -07:00
|
|
|
return $inlines;
|
|
|
|
}
|
|
|
|
|
2015-04-21 15:31:18 -07:00
|
|
|
$all = array_merge($old, $new);
|
|
|
|
|
|
|
|
$changeset_ids = mpull($inlines, 'getChangesetID');
|
|
|
|
$changeset_ids = array_unique($changeset_ids);
|
2015-04-21 15:32:23 -07:00
|
|
|
|
|
|
|
$all_map = mpull($all, null, 'getID');
|
|
|
|
|
|
|
|
// We already have at least some changesets, and we might not need to do
|
|
|
|
// any more data fetching. Remove everything we already have so we can
|
|
|
|
// tell if we need new stuff.
|
|
|
|
foreach ($changeset_ids as $key => $id) {
|
|
|
|
if (isset($all_map[$id])) {
|
|
|
|
unset($changeset_ids[$key]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-21 15:31:18 -07:00
|
|
|
if ($changeset_ids) {
|
|
|
|
$changesets = id(new DifferentialChangesetQuery())
|
|
|
|
->setViewer($viewer)
|
|
|
|
->withIDs($changeset_ids)
|
|
|
|
->execute();
|
|
|
|
$changesets = mpull($changesets, null, 'getID');
|
|
|
|
} else {
|
|
|
|
$changesets = array();
|
|
|
|
}
|
2015-04-21 15:32:23 -07:00
|
|
|
$changesets += $all_map;
|
2015-04-21 15:31:18 -07:00
|
|
|
|
|
|
|
$id_map = array();
|
|
|
|
foreach ($all as $changeset) {
|
|
|
|
$id_map[$changeset->getID()] = $changeset->getID();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generate filename maps for older and newer comments. If we're bringing
|
|
|
|
// an older comment forward in a diff-of-diffs, we want to put it on the
|
|
|
|
// left side of the screen, not the right side. Both sides are "new" files
|
|
|
|
// with the same name, so they're both appropriate targets, but the left
|
|
|
|
// is a better target conceptually for users because it's more consistent
|
|
|
|
// with the rest of the UI, which shows old information on the left and
|
|
|
|
// new information on the right.
|
|
|
|
$move_here = DifferentialChangeType::TYPE_MOVE_HERE;
|
|
|
|
|
|
|
|
$name_map_old = array();
|
|
|
|
$name_map_new = array();
|
|
|
|
$move_map = array();
|
|
|
|
foreach ($all as $changeset) {
|
|
|
|
$changeset_id = $changeset->getID();
|
|
|
|
|
|
|
|
$filenames = array();
|
|
|
|
$filenames[] = $changeset->getFilename();
|
|
|
|
|
|
|
|
// If this is the target of a move, also map comments on the old filename
|
|
|
|
// to this changeset.
|
|
|
|
if ($changeset->getChangeType() == $move_here) {
|
|
|
|
$old_file = $changeset->getOldFile();
|
|
|
|
$filenames[] = $old_file;
|
|
|
|
$move_map[$changeset_id][$old_file] = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ($filenames as $filename) {
|
|
|
|
// We update the old map only if we don't already have an entry (oldest
|
|
|
|
// changeset persists).
|
|
|
|
if (empty($name_map_old[$filename])) {
|
|
|
|
$name_map_old[$filename] = $changeset_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We always update the new map (newest changeset overwrites).
|
|
|
|
$name_map_new[$changeset->getFilename()] = $changeset_id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find the smallest "new" changeset ID. We'll consider everything
|
|
|
|
// larger than this to be "newer", and everything smaller to be "older".
|
|
|
|
$first_new_id = min(mpull($new, 'getID'));
|
|
|
|
|
|
|
|
$results = array();
|
|
|
|
foreach ($inlines as $inline) {
|
|
|
|
$changeset_id = $inline->getChangesetID();
|
|
|
|
if (isset($id_map[$changeset_id])) {
|
|
|
|
// This inline is legitimately on one of the current changesets, so
|
|
|
|
// we can include it in the result set unmodified.
|
|
|
|
$results[] = $inline;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
$changeset = idx($changesets, $changeset_id);
|
|
|
|
if (!$changeset) {
|
|
|
|
// Just discard this inline, as it has bogus data.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
$target_id = null;
|
|
|
|
|
|
|
|
if ($changeset_id >= $first_new_id) {
|
|
|
|
$name_map = $name_map_new;
|
|
|
|
$is_new = true;
|
|
|
|
} else {
|
|
|
|
$name_map = $name_map_old;
|
|
|
|
$is_new = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$filename = $changeset->getFilename();
|
|
|
|
if (isset($name_map[$filename])) {
|
|
|
|
// This changeset is on a file with the same name as the current
|
|
|
|
// changeset, so we're going to port it forward or backward.
|
|
|
|
$target_id = $name_map[$filename];
|
|
|
|
|
|
|
|
$is_move = isset($move_map[$target_id][$filename]);
|
|
|
|
if ($is_new) {
|
|
|
|
if ($is_move) {
|
|
|
|
$reason = pht(
|
|
|
|
'This comment was made on a file with the same name as the '.
|
|
|
|
'file this file was moved from, but in a newer diff.');
|
|
|
|
} else {
|
|
|
|
$reason = pht(
|
|
|
|
'This comment was made on a file with the same name, but '.
|
|
|
|
'in a newer diff.');
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ($is_move) {
|
|
|
|
$reason = pht(
|
|
|
|
'This comment was made on a file with the same name as the '.
|
|
|
|
'file this file was moved from, but in an older diff.');
|
|
|
|
} else {
|
|
|
|
$reason = pht(
|
|
|
|
'This comment was made on a file with the same name, but '.
|
|
|
|
'in an older diff.');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// If we didn't find a target and this change is the target of a move,
|
|
|
|
// look for a match against the old filename.
|
|
|
|
if (!$target_id) {
|
|
|
|
if ($changeset->getChangeType() == $move_here) {
|
|
|
|
$filename = $changeset->getOldFile();
|
|
|
|
if (isset($name_map[$filename])) {
|
|
|
|
$target_id = $name_map[$filename];
|
|
|
|
if ($is_new) {
|
|
|
|
$reason = pht(
|
|
|
|
'This comment was made on a file which this file was moved '.
|
|
|
|
'to, but in a newer diff.');
|
|
|
|
} else {
|
|
|
|
$reason = pht(
|
|
|
|
'This comment was made on a file which this file was moved '.
|
|
|
|
'to, but in an older diff.');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// If we found a changeset to port this comment to, bring it forward
|
|
|
|
// or backward and mark it.
|
|
|
|
if ($target_id) {
|
2015-05-04 11:52:21 -07:00
|
|
|
$diff_id = $changeset->getDiffID();
|
|
|
|
$inline_id = $inline->getID();
|
|
|
|
$revision_id = $revision->getID();
|
|
|
|
$href = "/D{$revision_id}?id={$diff_id}#inline-{$inline_id}";
|
|
|
|
|
2015-04-21 15:31:18 -07:00
|
|
|
$inline
|
|
|
|
->makeEphemeral(true)
|
|
|
|
->setChangesetID($target_id)
|
|
|
|
->setIsGhost(
|
|
|
|
array(
|
|
|
|
'new' => $is_new,
|
|
|
|
'reason' => $reason,
|
2015-05-04 11:52:21 -07:00
|
|
|
'href' => $href,
|
2015-05-07 14:09:41 -07:00
|
|
|
'originalID' => $changeset->getID(),
|
2015-04-21 15:31:18 -07:00
|
|
|
));
|
|
|
|
|
|
|
|
$results[] = $inline;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Filter out the inlines we ported forward which won't be visible because
|
|
|
|
// they appear on the wrong side of a file.
|
|
|
|
$keep_map = array();
|
|
|
|
foreach ($old as $changeset) {
|
|
|
|
$keep_map[$changeset->getID()][0] = true;
|
|
|
|
}
|
|
|
|
foreach ($new as $changeset) {
|
|
|
|
$keep_map[$changeset->getID()][1] = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ($results as $key => $inline) {
|
|
|
|
$is_new = (int)$inline->getIsNewFile();
|
|
|
|
$changeset_id = $inline->getChangesetID();
|
|
|
|
if (!isset($keep_map[$changeset_id][$is_new])) {
|
|
|
|
unset($results[$key]);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-07 14:09:41 -07:00
|
|
|
// Adjust inline line numbers to account for content changes across
|
|
|
|
// updates and rebases.
|
|
|
|
$plan = array();
|
|
|
|
$need = array();
|
|
|
|
foreach ($results as $inline) {
|
|
|
|
$ghost = $inline->getIsGhost();
|
|
|
|
if (!$ghost) {
|
|
|
|
// If this isn't a "ghost" inline, ignore it.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
$src_id = $ghost['originalID'];
|
|
|
|
$dst_id = $inline->getChangesetID();
|
|
|
|
|
|
|
|
$xforms = array();
|
|
|
|
|
|
|
|
// If the comment is on the right, transform it through the inverse map
|
|
|
|
// back to the left.
|
|
|
|
if ($inline->getIsNewFile()) {
|
|
|
|
$xforms[] = array($src_id, $src_id, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Transform it across rebases.
|
|
|
|
$xforms[] = array($src_id, $dst_id, false);
|
|
|
|
|
|
|
|
// If the comment is on the right, transform it back onto the right.
|
|
|
|
if ($inline->getIsNewFile()) {
|
|
|
|
$xforms[] = array($dst_id, $dst_id, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
$key = array();
|
|
|
|
foreach ($xforms as $xform) {
|
|
|
|
list($u, $v, $inverse) = $xform;
|
|
|
|
|
|
|
|
$short = $u.'/'.$v;
|
|
|
|
$need[$short] = array($u, $v);
|
|
|
|
|
|
|
|
$part = $u.($inverse ? '<' : '>').$v;
|
|
|
|
$key[] = $part;
|
|
|
|
}
|
|
|
|
$key = implode(',', $key);
|
|
|
|
|
|
|
|
if (empty($plan[$key])) {
|
|
|
|
$plan[$key] = array(
|
|
|
|
'xforms' => $xforms,
|
|
|
|
'inlines' => array(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
$plan[$key]['inlines'][] = $inline;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($need) {
|
|
|
|
$maps = DifferentialLineAdjustmentMap::loadMaps($need);
|
|
|
|
} else {
|
|
|
|
$maps = array();
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ($plan as $step) {
|
|
|
|
$xforms = $step['xforms'];
|
|
|
|
|
|
|
|
$chain = null;
|
|
|
|
foreach ($xforms as $xform) {
|
|
|
|
list($u, $v, $inverse) = $xform;
|
|
|
|
$map = idx(idx($maps, $u, array()), $v);
|
|
|
|
if (!$map) {
|
|
|
|
continue 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($inverse) {
|
|
|
|
$map = DifferentialLineAdjustmentMap::newInverseMap($map);
|
|
|
|
} else {
|
|
|
|
$map = clone $map;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($chain) {
|
|
|
|
$chain->addMapToChain($map);
|
|
|
|
} else {
|
|
|
|
$chain = $map;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ($step['inlines'] as $inline) {
|
|
|
|
$head_line = $inline->getLineNumber();
|
|
|
|
$tail_line = ($head_line + $inline->getLineLength());
|
|
|
|
|
|
|
|
$head_info = $chain->mapLine($head_line, false);
|
|
|
|
$tail_info = $chain->mapLine($tail_line, true);
|
|
|
|
|
|
|
|
list($head_deleted, $head_offset, $head_line) = $head_info;
|
|
|
|
list($tail_deleted, $tail_offset, $tail_line) = $tail_info;
|
|
|
|
|
|
|
|
if ($head_offset !== false) {
|
|
|
|
$inline->setLineNumber($head_line + 1 + $head_offset);
|
|
|
|
} else {
|
|
|
|
$inline->setLineNumber($head_line);
|
|
|
|
$inline->setLineLength($tail_line - $head_line);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-21 15:31:18 -07:00
|
|
|
return $results;
|
|
|
|
}
|
|
|
|
|
2013-06-21 12:54:56 -07:00
|
|
|
}
|