Exemple #1
0
    public function testCreate()
    {
        $before = <<<'EOD'
unchanged
replaced
unchanged
removed
EOD;
        $after = <<<'EOD'
added
unchanged
replacement
unchanged
EOD;
        $diff = [['added', 1], ['unchanged', 0], ['replaced', 2], ['replacement', 1], ['unchanged', 0], ['removed', 2]];
        $lines = [new Line(Line::ADDED, 'added', -1), new Line(Line::UNCHANGED, 'unchanged', 0), new Line(Line::REMOVED, 'replaced', 1), new Line(Line::ADDED, 'replacement', 1), new Line(Line::UNCHANGED, 'unchanged', 2), new Line(Line::REMOVED, 'removed', 3)];
        $differ = new Differ();
        $array_diff = $differ->diffToArray($before, $after);
        $this->assertEquals($diff, $array_diff);
        $result = Line::createArray($diff);
        $this->assertEquals($lines, $result);
        try {
            $diff[] = ['invalid', 3];
            Line::createArray($diff);
            $this->assertTrue(false, 'An exception was not thrown');
        } catch (\RuntimeException $e) {
            $this->assertEquals('Unsupported diff line type.', $e->getMessage());
        }
    }
Exemple #2
0
 /**
  * @inheritDoc
  */
 public function merge($base, $remote, $local)
 {
     // Skip merging if there is nothing to do.
     if ($merged = PhpMergeBase::simpleMerge($base, $remote, $local)) {
         return $merged;
     }
     $remoteDiff = Line::createArray($this->differ->diffToArray($base, $remote));
     $localDiff = Line::createArray($this->differ->diffToArray($base, $local));
     $baseLines = Line::createArray(array_map(function ($l) {
         return [$l, 0];
     }, explode("\n", $base)));
     $remoteHunks = Hunk::createArray($remoteDiff);
     $localHunks = Hunk::createArray($localDiff);
     $conflicts = [];
     $merged = PhpMerge::mergeHunks($baseLines, $remoteHunks, $localHunks, $conflicts);
     if ($conflicts) {
         throw new MergeException('A merge conflict has occured.', $conflicts, $merged);
     }
     return $merged;
 }
Exemple #3
0
 /**
  * Get the conflicts from a file which is left with merge conflicts.
  *
  * @param string $file
  *   The file name.
  * @param string $baseText
  *   The original text used for merging.
  * @param string $remoteText
  *   The first chaned text.
  * @param string $localText
  *   The second changed text.
  * @param MergeConflict[] $conflicts
  *   The merge conflicts will be apended to this array.
  * @param string[] $merged
  *   The merged text resolving conflicts by using the first set of changes.
  */
 protected static function getConflicts($file, $baseText, $remoteText, $localText, &$conflicts, &$merged)
 {
     $raw = new \ArrayObject(explode("\n", file_get_contents($file)));
     $lineIterator = $raw->getIterator();
     $state = 'unchanged';
     $conflictIndicator = ['<<<<<<< HEAD' => 'local', '||||||| merged common ancestors' => 'base', '=======' => 'remote', '>>>>>>> original' => 'end conflict'];
     // Create hunks from the text diff.
     $differ = new Differ();
     $remoteDiff = Line::createArray($differ->diffToArray($baseText, $remoteText));
     $localDiff = Line::createArray($differ->diffToArray($baseText, $localText));
     $remote_hunks = new \ArrayObject(Hunk::createArray($remoteDiff));
     $local_hunks = new \ArrayObject(Hunk::createArray($localDiff));
     $remoteIterator = $remote_hunks->getIterator();
     $localIterator = $local_hunks->getIterator();
     $base = [];
     $remote = [];
     $local = [];
     $lineNumber = -1;
     $newLine = 0;
     $skipedLines = 0;
     $addingConflict = false;
     // Loop over all the lines in the file.
     while ($lineIterator->valid()) {
         $line = $lineIterator->current();
         if (array_key_exists(trim($line), $conflictIndicator)) {
             // Check for a line matching a conflict indicator.
             $state = $conflictIndicator[trim($line)];
             $skipedLines++;
             if ($state == 'end conflict') {
                 // We just treated a merge conflict.
                 $conflicts[] = new MergeConflict($base, $remote, $local, $lineNumber, $newLine);
                 if ($lineNumber == -1) {
                     $lineNumber = 0;
                 }
                 $lineNumber += count($base);
                 $newLine += count($remote);
                 $base = [];
                 $remote = [];
                 $local = [];
                 $remoteIterator->next();
                 $localIterator->next();
                 if ($addingConflict) {
                     // Advance the counter for conflicts with adding.
                     $lineNumber++;
                     $newLine++;
                     $addingConflict = false;
                 }
                 $state = 'unchanged';
             }
         } else {
             switch ($state) {
                 case 'local':
                     $local[] = $line;
                     $skipedLines++;
                     break;
                 case 'base':
                     $base[] = $line;
                     $skipedLines++;
                     if ($lineNumber == -1) {
                         $lineNumber = 0;
                     }
                     break;
                 case 'remote':
                     $remote[] = $line;
                     $merged[] = $line;
                     break;
                 case 'unchanged':
                     if ($lineNumber == -1) {
                         $lineNumber = 0;
                     }
                     $merged[] = $line;
                     /** @var Hunk $r */
                     $r = $remoteIterator->current();
                     /** @var Hunk $l */
                     $l = $localIterator->current();
                     if ($r == $l) {
                         // If they are the same, treat only one.
                         $localIterator->next();
                         $l = $localIterator->current();
                     }
                     // A hunk has been successfully merged, so we can just
                     // tally the lines added and removed and skip forward.
                     if ($r && $r->getStart() == $lineNumber) {
                         if (!$r->hasIntersection($l)) {
                             $lineNumber += count($r->getRemovedLines());
                             $newLine += count($r->getAddedLines());
                             $lineIterator->seek($newLine + $skipedLines - 1);
                             $remoteIterator->next();
                         } else {
                             // If the conflict occurs on added lines, the
                             // next line in the merge will deal with it.
                             if ($r->getType() == Hunk::ADDED && $l->getType() == Hunk::ADDED) {
                                 $addingConflict = true;
                             } else {
                                 $lineNumber++;
                                 $newLine++;
                             }
                         }
                     } elseif ($l && $l->getStart() == $lineNumber) {
                         if (!$l->hasIntersection($r)) {
                             $lineNumber += count($l->getRemovedLines());
                             $newLine += count($l->getAddedLines());
                             $lineIterator->seek($newLine + $skipedLines - 1);
                             $localIterator->next();
                         } else {
                             $lineNumber++;
                             $newLine++;
                         }
                     } else {
                         $lineNumber++;
                         $newLine++;
                     }
                     break;
             }
         }
         $lineIterator->next();
     }
 }