Skip to content

Commit

Permalink
Move revisions instead of creating new revisions
Browse files Browse the repository at this point in the history
  • Loading branch information
it-spiderman committed Sep 4, 2024
1 parent a320cc8 commit 45c0990
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 30 deletions.
2 changes: 1 addition & 1 deletion includes/Inbox/InboxImporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,6 @@ public function mergePages( Title $local, Title $remoteTitle, User $user, ?strin
*/
public function mergePagesForceRemote( Title $local, Title $remoteTitle, User $user ) {
// Merge remote into local, but force the latest text of remote as new content
$this->mergePages( $local, $remoteTitle, $user, null );
$this->revisionManipulator->moveChain( $local, $remoteTitle );
}
}
89 changes: 61 additions & 28 deletions includes/RevisionManipulator.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use MediaWiki\User\UserIdentity;
use Message;
use MWException;
use Throwable;
use Title;
use User;
use Wikimedia\Rdbms\IDatabase;
Expand Down Expand Up @@ -255,6 +256,54 @@ public function forkPage( Title $target, RevisionRecord $revision, UserIdentity
);
}

private function getEntities( Title $local, Title $remote ) {
define( 'DA_MERGE', 1 );
wfDebug( "Starting page merge: {$remote->getPrefixedText()} => {$local->getPrefixedText()}", 'da' );
$localEntities = $this->getVerificationEntitiesForMerge( $local );
$remoteEntities = $this->getVerificationEntitiesForMerge( $remote );
$commonParent = $this->getCommonParent( $localEntities, $remoteEntities );
if ( !$commonParent ) {
throw new Exception( 'No common parent found' );
}
$this->assertSameGenesis( $localEntities, $remoteEntities );
return [ $localEntities, $remoteEntities, $commonParent ];
}

private function moveRevisions( array $remoteEntities, $commonParent, Title $local ): ?VerificationEntity {
$db = $this->lb->getConnection( DB_PRIMARY );
$lastInserted = null;
foreach ( $remoteEntities as $hash => $remoteEntity ) {
if ( isset( $localEntities[$hash] ) ) {

Check failure on line 276 in includes/RevisionManipulator.php

View workflow job for this annotation

GitHub Actions / Static Analysis

Variable $localEntities in isset() is never defined.
// Exists locally
continue;
}
$parent = $lastInserted ?? $commonParent;
$isFork = $remoteEntity->getHash( VerificationEntity::PREVIOUS_VERIFICATION_HASH ) ===
$commonParent->getHash();
$this->moveRevision( $db, $remoteEntity, $parent, $commonParent, $local, $isFork, __METHOD__ );
wfDebug( "Moving revision " . $remoteEntity->getRevision()->getId() . ',isFork: ' . $isFork, 'da' );
$lastInserted = $remoteEntity;
}
$db->update(
'page',
[ 'page_latest' => $lastInserted->getRevision()->getId() ],
[ 'page_id' => $local->getArticleID() ],
__METHOD__
);
return $lastInserted;
}

public function moveChain( Title $local, Title $remote ) {
[ $localEntities, $remoteEntities, $commonParent ] = $this->getEntities( $local, $remote );
$this->moveRevisions( $remoteEntities, $commonParent, $local );
$db = $this->lb->getConnection( DB_PRIMARY )->delete(
'page',
[ 'page_id' => $remote->getArticleID() ],
__METHOD__
);
$this->verificationEngine->getLookup()->clearEntriesForPage( $remote );
}

/**
* @param Title $local
* @param Title $remote
Expand All @@ -266,15 +315,8 @@ public function forkPage( Title $target, RevisionRecord $revision, UserIdentity
public function mergePages(
Title $local, Title $remote, UserIdentity $user, ?string $mergedText
) {
define( 'DA_MERGE', 1 );
wfDebug( "Starting page merge: {$remote->getPrefixedText()} => {$local->getPrefixedText()}", 'da' );
$localEntities = $this->getVerificationEntitiesForMerge( $local );
$remoteEntities = $this->getVerificationEntitiesForMerge( $remote );
$commonParent = $this->getCommonParent( $localEntities, $remoteEntities );
if ( !$commonParent ) {
throw new Exception( 'No common parent found' );
}
$this->assertSameGenesis( $localEntities, $remoteEntities );
$db = $this->lb->getConnection( DB_PRIMARY );
[ $localEntities, $remoteEntities, $commonParent ] = $this->getEntities( $local, $remote );
// Last entry in the local entities is the last revision
// that was not forked, and is the parent of the first forked revision
$lastLocal = end( $localEntities );
Expand All @@ -287,28 +329,21 @@ public function mergePages(
// Main role is already set by setting text
continue;
}
$slotsToCopy[$role->getName()] = $lastRemote->getRevision()->getContent( $role );
$slotsToCopy[$role] = $lastRemote->getRevision()->getContent( $role );
}
$this->assertMergedContentDifferent( $lastLocal, $text );
$this->assertMergedContentDifferent( $lastLocal, $text, $slotsToCopy );

wfDebug( "Last local revision is: " . $lastLocal->getRevision()->getId(), 'da' );
$wp = $this->wikipageFactory->newFromTitle( $local );
$lastInserted = null;
$db = $this->lb->getConnection( DB_PRIMARY );

$db->startAtomic( __METHOD__ );
foreach ( $remoteEntities as $hash => $remoteEntity ) {
if ( isset( $localEntities[$hash] ) ) {
// Exists locally
continue;
}
$parent = $lastInserted ?? $commonParent;
$isFork = $remoteEntity->getHash( VerificationEntity::PREVIOUS_VERIFICATION_HASH ) ===
$commonParent->getHash();
$this->moveRevision( $db, $remoteEntity, $parent, $commonParent, $local, $isFork, __METHOD__ );
wfDebug( "Moving revision " . $remoteEntity->getRevision()->getId() . ',isFork: ' . $isFork, 'da' );
$lastInserted = $remoteEntity;
try {
$lastInserted = $this->moveRevisions( $remoteEntities, $commonParent, $local );
} catch ( Throwable $ex ) {
$db->cancelAtomic( __METHOD__ );
throw $ex;
}

// Insert merged revision
$updater = $wp->newPageUpdater( $user );
wfDebug( "Creating new revision with text: " . $text, 'da' );
Expand Down Expand Up @@ -405,7 +440,6 @@ private function moveRevision(
}
$res = $db->update( 'revision', $revData, [ 'rev_id' => $entity->getRevision()->getId() ] );
if ( !$res ) {
$db->cancelAtomic( $mtd );
throw new Exception( 'Failed to move revision' );
}
// Move verification entity
Expand All @@ -422,7 +456,6 @@ private function moveRevision(
}
wfDebug( "Setting verification data on moved revision: " . json_encode( $data ), 'da' );
if ( !$db->update( 'revision_verification', $data, [ 'rev_id' => $entity->getRevision()->getId() ] ) ) {
$db->cancelAtomic( $mtd );
throw new Exception( 'Failed to move verification entity' );
}
}
Expand Down Expand Up @@ -530,8 +563,8 @@ private function shortenHash( string $hash ): string {
* @return void
* @throws Exception
*/
private function assertMergedContentDifferent( VerificationEntity $lastLocal, string $text ) {
if ( $text === $lastLocal->getRevision()->getContent( SlotRecord::MAIN )->getText() ) {
private function assertMergedContentDifferent( VerificationEntity $lastLocal, string $text, array $slots ) {
if ( $text === $lastLocal->getRevision()->getContent( SlotRecord::MAIN )->getText() && empty( $slots ) ) {
throw new Exception( 'Merged content is the same as the last local revision. Nothing to merge' );
}
}
Expand Down
2 changes: 1 addition & 1 deletion includes/SpecialWitness.php
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ private function fetchVerificationPages( $filter = [] ): IResultWrapper {
$conds = [
'page_namespace NOT IN (' . $db->makeList( [ NS_DATAACCOUNTING, NS_MEDIAWIKI ] ) . ')',
];
foreach( $filter as $key => $value ) {
foreach ( $filter as $key => $value ) {
if ( empty( $value ) ) {
continue;
}
Expand Down

0 comments on commit 45c0990

Please sign in to comment.