private static function mergeUnmergedPath($repository, $path) { $shellrepo = escapeshellarg($repository); $common_ancestor = uniqid(sys_get_temp_dir() . "/") . "ancestor"; $argument = escapeshellarg(":1:{$path}"); $command = "cd {$shellrepo}; git show {$argument} > {$common_ancestor}"; exec($command, $output, $exit_code); $head_version = uniqid(sys_get_temp_dir() . "/") . "head"; $argument = escapeshellarg(":2:{$path}"); $command = "cd {$shellrepo}; git show {$argument} > {$head_version}"; exec($command, $output, $exit_code); $merge_head_version = uniqid(sys_get_temp_dir() . "/") . "merge_head"; $argument = escapeshellarg(":3:{$path}"); $command = "cd {$shellrepo}; git show {$argument} > {$merge_head_version}"; exec($command, $output, $exit_code); $mergeBase = file_get_contents($common_ancestor); $userData = file_get_contents($head_version); $serverData = file_get_contents($merge_head_version); $mergedData = Filter_Merge::run($mergeBase, $userData, $serverData); $mergedData = str_replace("new__line", "\n", $mergedData); $mergedData = trim($mergedData); file_put_contents("{$repository}/{$path}", $mergedData); unlink($common_ancestor); unlink($head_version); unlink($merge_head_version); }
public static function run($base, $user, $server) { // The three files for merging. $mergeBaseFile = uniqid(sys_get_temp_dir() . "/") . "mergebase.txt"; $userModificationFile = uniqid(sys_get_temp_dir() . "/") . "usermodification.txt"; $serverModificationFile = uniqid(sys_get_temp_dir() . "/") . "servermodification.txt"; $success = false; // Try a standard line-based merge. Should be sufficient for most cases. file_put_contents($mergeBaseFile, $base); file_put_contents($userModificationFile, $user); file_put_contents($serverModificationFile, $server); $exit_code = Filter_Merge::merge($mergeBaseFile, $userModificationFile, $serverModificationFile); $result = file_get_contents($userModificationFile); if ($exit_code == 0) { $success = true; } if (!$success) { // Convert the data to one word per line, and try to merge again. $baseWords = Filter_Merge::lines2words($base); $userWords = Filter_Merge::lines2words($user); $serverWords = Filter_Merge::lines2words($server); file_put_contents($mergeBaseFile, $baseWords); file_put_contents($userModificationFile, $userWords); file_put_contents($serverModificationFile, $serverWords); $exit_code = Filter_Merge::merge($mergeBaseFile, $userModificationFile, $serverModificationFile); $result = file_get_contents($userModificationFile); $result = Filter_Merge::words2lines($result); if ($exit_code == 0) { $success = true; } } if (!$success) { // Convert the data so it has one grapheme per line, and try again. $baseGraphemes = Filter_Merge::lines2graphemes($base); $userGraphemes = Filter_Merge::lines2graphemes($user); $serverGraphemes = Filter_Merge::lines2graphemes($server); file_put_contents($mergeBaseFile, $baseGraphemes); file_put_contents($userModificationFile, $userGraphemes); file_put_contents($serverModificationFile, $serverGraphemes); $exit_code = Filter_Merge::merge($mergeBaseFile, $userModificationFile, $serverModificationFile); $result = file_get_contents($userModificationFile); $result = Filter_Merge::graphemes2lines($result); if ($exit_code == 0) { $success = true; } } if (!$success) { // Everthing failed. Return the server data. $result = $server; } // Clear up. @unlink($mergeBaseFile); @unlink($userModificationFile); @unlink($serverModificationFile); // Merge result. return $result; }
public static function run($base, $user, $server) { $success = false; // Try a standard line-based merge. Should be sufficient for most cases. $result = Filter_Merge::merge($base, $user, $server); if ($result) { $success = true; } if (!$success) { // Convert the data to one word per line, and try to merge again. $baseWords = Filter_Merge::lines2words($base); $userWords = Filter_Merge::lines2words($user); $serverWords = Filter_Merge::lines2words($server); $result = Filter_Merge::merge($baseWords, $userWords, $serverWords); $result = Filter_Merge::words2lines($result); if ($result) { $success = true; } } if (!$success) { // Convert the data so it has one grapheme per line, and try again. $baseGraphemes = Filter_Merge::lines2graphemes($base); $userGraphemes = Filter_Merge::lines2graphemes($user); $serverGraphemes = Filter_Merge::lines2graphemes($server); $result = Filter_Merge::merge($baseGraphemes, $userGraphemes, $serverGraphemes); $result = Filter_Merge::graphemes2lines($result); if ($result) { $success = true; } } if (!$success) { // Everything failed. Return the server data. $result = $server; } // Merge result. return $result; }
$database_logs->log($message, Filter_Roles::MANAGER_LEVEL); echo $message; die; } $serverusfm = $database_bibles->getChapter($bible, $book, $chapter); // Gather data for recording the changes made by the user, for the change notifications. $old_id = $database_bibles->getChapterId($bible, $book, $chapter); $old_text = $serverusfm; $new_text = $newusfm; if ($serverusfm == "") { // If the chapter on the server is still empty, then just store the client's version on the server, and that's it. Bible_Logic::storeChapter($bible, $book, $chapter, $newusfm); } else { if ($newusfm != $serverusfm) { // Do a merge in case the client sends USFM that differs from what's on the server. $mergedusfm = Filter_Merge::run($oldusfm, $newusfm, $serverusfm); if ($mergedusfm == $serverusfm) { // When the merged USFM is the same as what's already on the server, then it means there was a merge conflict. // Email the user with the details, so the user can resolve the conflicts. $subject = "Problem sending chapter to server"; $body = "<p>While sending {$bible} {$bookname} {$chapter} to the server, the server didn't manage to merge it.</p>"; $body .= "<p>Please re-enter your changes as you see fit.</p>"; $body .= "<p>Here is the chapter you sent to the server:</p>"; $body .= "<pre>{$newusfm}</pre>"; $database_mail->send($username, $subject, $body); } else { // Update the server with the new chapter data. Bible_Logic::storeChapter($bible, $book, $chapter, $mergedusfm); } } }
$database_logs->log(Locale_Translate::_("Failure getting chapter:") . " {$bible} {$book_name} {$chapter}", Filter_Roles::TRANSLATOR_LEVEL); continue; } // Verify the checksum of the chapter on the server, to be sure there's no corruption during transmission. $server_usfm = explode("\n", $server_usfm); $checksum = array_shift($server_usfm); $server_usfm = implode("\n", $server_usfm); if (!Checksum_Logic::get($server_usfm) == $checksum) { $database_logs->log(Locale_Translate::_("Checksum error while receiving chapter from server:") . " {$bible} {$book_name} {$chapter}", Filter_Roles::TRANSLATOR_LEVEL); continue; } // Check whether the user on the client has made changes in this chapter since the edits were sent to the server. // If there are none, then the client stores the chapter as it gets it from the server, and is done. $old_usfm = $database_bibleactions->getUsfm($bible, $book, $chapter); if ($old_usfm == "") { $database_bibles->storeChapter($bible, $book, $chapter, $server_usfm); continue; } // At this stage we're in a situation that there are changes on the client, and changes on the server. // Merge them. // It uses a 3-way merge, taking the chapter from the bible actions as the basis, and the other two (client and server) to merge together. // Store the merged data on the client. // It stores through the Bible Logic so the changes are staged to be sent. // The changes will be sent to the server during the next synchronize action. $database_logs->log(Locale_Translate::_("Merging changes on server and client:") . " {$bible} {$book_name} {$chapter}", Filter_Roles::TRANSLATOR_LEVEL); $client_usfm = $database_bibles->getChapter($bible, $book, $chapter); $merged_usfm = Filter_Merge::run($old_usfm, $client_usfm, $server_usfm); Bible_Logic::storeChapter($bible, $book, $chapter, $merged_usfm); } } }
public function testPracticalMergeExampleOne() { $this->mergeBaseData = <<<'EOD' \c 1 \p \v 1 This is really the text of the first (1st) verse. \v 2 And this is what the second (2nd) verse contains. \v 3 The third (3rd) verse. \v 4 The fourth (4th) verse. \v 5 EOD; $this->userModificationData = <<<'EOD' \c 1 \p \v 1 This is really the text of the first (1st) verse. \v 2 And this is what the second verse contains. \v 3 The third verse. \v 4 The fourth (4th) verse. \v 5 EOD; $this->serverModificationData = <<<'EOD' \c 1 \p \v 1 This is really the text of the first verse. \v 2 And this is what the second (2nd) verse contains. \v 3 The third (3rd) verse. \v 4 The fourth verse. \v 5 EOD; $output = Filter_Merge::run($this->mergeBaseData, $this->userModificationData, $this->serverModificationData); $standard = <<<'EOD' \c 1 \p \v 1 This is really the text of the first verse. \v 2 And this is what the second verse contains. \v 3 The third verse. \v 4 The fourth verse. \v 5 EOD; $this->assertEquals($standard, $output); }
along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* Note: This object should not call other objects within the Bibledit-Web source, because this object is also called from Bibledit-Gtk, and does not have access to those other objects. Calling other objects would result in faral errors that break Bibledit-Gtk. */ // This calls Bibledit-Web's three-way merge filter from the command line. // Security: The script runs from the cli SAPI only. if (php_sapi_name() != "cli") { echo "Fatal: This only runs through the cli Server API\n"; die; } if ($argc != 5) { echo "Three-way file merge with grapheme granularity.\n"; echo "It needs the following four arguments:\n"; echo "- Name of the file with the merge base\n"; echo "- Name of the file with the user modifications\n"; echo "- Name of the file with the server modifications\n"; echo "- Name of the file to store the merged output\n"; die; } $mergeBase = file_get_contents($argv[1]); $userModification = file_get_contents($argv[2]); $serverModification = file_get_contents($argv[3]); include "merge.php"; include "rmdir.php"; $output = Filter_Merge::run($mergeBase, $userModification, $serverModification); file_put_contents($argv[4], $output);