Changeset View
Changeset View
Standalone View
Standalone View
src/parser/ArcanistDiffParser.php
<?php | <?php | ||||
/** | /** | ||||
* Parses diffs from a working copy. | * Parses diffs from a working copy. | ||||
* | * | ||||
* @group diff | * @group diff | ||||
*/ | */ | ||||
final class ArcanistDiffParser { | final class ArcanistDiffParser { | ||||
protected $repositoryAPI; | protected $repositoryAPI; | ||||
protected $text; | protected $text; | ||||
protected $line; | protected $line; | ||||
protected $lineSaved; | protected $lineSaved; | ||||
protected $isGit; | protected $isGit; | ||||
protected $isMercurial; | protected $isMercurial; | ||||
protected $isRCS; | |||||
protected $detectBinaryFiles = false; | protected $detectBinaryFiles = false; | ||||
protected $tryEncoding; | protected $tryEncoding; | ||||
protected $rawDiff; | protected $rawDiff; | ||||
protected $writeDiffOnFailure; | protected $writeDiffOnFailure; | ||||
protected $changes = array(); | protected $changes = array(); | ||||
private $forcePath; | private $forcePath; | ||||
▲ Show 20 Lines • Show All 176 Lines • ▼ Show 20 Lines | do { | ||||
'(?P<type>Index): (?P<cur>.+)', | '(?P<type>Index): (?P<cur>.+)', | ||||
// This is an SVN property change, probably from "svn diff". | // This is an SVN property change, probably from "svn diff". | ||||
'(?P<type>Property changes on): (?P<cur>.+)', | '(?P<type>Property changes on): (?P<cur>.+)', | ||||
// This is a git commit message, probably from "git show". | // This is a git commit message, probably from "git show". | ||||
'(?P<type>commit) (?P<hash>[a-f0-9]+)(?: \(.*\))?', | '(?P<type>commit) (?P<hash>[a-f0-9]+)(?: \(.*\))?', | ||||
// This is a git diff, probably from "git show" or "git diff". | // This is a git diff, probably from "git show" or "git diff". | ||||
// Note that the filenames may appear quoted. | // Note that the filenames may appear quoted. | ||||
'(?P<type>diff --git) (?P<oldnew>.*)', | '(?P<type>diff --git) (?P<oldnew>.*)', | ||||
// RCS Diff | |||||
'(?P<type>rcsdiff -u) (?P<oldnew>.*)', | |||||
// This is a unified diff, probably from "diff -u" or synthetic diffing. | // This is a unified diff, probably from "diff -u" or synthetic diffing. | ||||
'(?P<type>---) (?P<old>.+)\s+\d{4}-\d{2}-\d{2}.*', | '(?P<type>---) (?P<old>.+)\s+\d{4}-\d{2}-\d{2}.*', | ||||
'(?P<binary>Binary) files '. | '(?P<binary>Binary) files '. | ||||
'(?P<old>.+)\s+\d{4}-\d{2}-\d{2} and '. | '(?P<old>.+)\s+\d{4}-\d{2}-\d{2} and '. | ||||
'(?P<new>.+)\s+\d{4}-\d{2}-\d{2} differ.*', | '(?P<new>.+)\s+\d{4}-\d{2}-\d{2} differ.*', | ||||
// This is a normal Mercurial text change, probably from "hg diff". It | // This is a normal Mercurial text change, probably from "hg diff". It | ||||
// may have two "-r" blocks if it came from "hg diff -r x:y". | // may have two "-r" blocks if it came from "hg diff -r x:y". | ||||
'(?P<type>diff -r) (?P<hgrev>[a-f0-9]+) (?:-r [a-f0-9]+ )?(?P<cur>.+)', | '(?P<type>diff -r) (?P<hgrev>[a-f0-9]+) (?:-r [a-f0-9]+ )?(?P<cur>.+)', | ||||
▲ Show 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | do { | ||||
} | } | ||||
$change->setCurrentPath($match[1]); | $change->setCurrentPath($match[1]); | ||||
$line = $this->nextLine(); | $line = $this->nextLine(); | ||||
$this->parseChangeset($change); | $this->parseChangeset($change); | ||||
break; | break; | ||||
case 'diff -r': | case 'diff -r': | ||||
$this->setIsMercurial(true); | $this->setIsMercurial(true); | ||||
$this->parseIndexHunk($change); | $this->parseIndexHunk($change); | ||||
break; | break; | ||||
case 'rcsdiff -u': | |||||
$this->isRCS = true; | |||||
$this->parseIndexHunk($change); | |||||
break; | |||||
epriestley: I //think// you should be able to add something like this:
case 'rcsdiff -u':
$this… | |||||
default: | default: | ||||
$this->didFailParse("Unknown diff type."); | $this->didFailParse("Unknown diff type."); | ||||
break; | break; | ||||
} | } | ||||
} while ($this->getLine() !== null); | } while ($this->getLine() !== null); | ||||
$this->didFinishParse(); | $this->didFinishParse(); | ||||
▲ Show 20 Lines • Show All 415 Lines • ▼ Show 20 Lines | protected function parseIndexHunk(ArcanistDiffChange $change) { | ||||
if ($is_git) { | if ($is_git) { | ||||
// "git diff -b" ignores whitespace, but has an empty hunk target | // "git diff -b" ignores whitespace, but has an empty hunk target | ||||
if (preg_match('@^diff --git .*$@', $line)) { | if (preg_match('@^diff --git .*$@', $line)) { | ||||
$this->nextLine(); | $this->nextLine(); | ||||
return null; | return null; | ||||
} | } | ||||
} | } | ||||
if ($this->isRCS) { | |||||
// Skip the RCS headers. | |||||
$this->nextLine(); | |||||
$this->nextLine(); | |||||
$this->nextLine(); | |||||
} | |||||
$old_file = $this->parseHunkTarget(); | $old_file = $this->parseHunkTarget(); | ||||
$new_file = $this->parseHunkTarget(); | $new_file = $this->parseHunkTarget(); | ||||
if ($this->isRCS) { | |||||
$change->setCurrentPath($new_file); | |||||
} | |||||
$change->setOldPath($old_file); | $change->setOldPath($old_file); | ||||
$this->parseChangeset($change); | $this->parseChangeset($change); | ||||
} | } | ||||
private function parseGitBinaryPatch() { | private function parseGitBinaryPatch() { | ||||
// TODO: We could decode the patches, but it's a giant mess so don't bother | // TODO: We could decode the patches, but it's a giant mess so don't bother | ||||
Show All 22 Lines | protected function parseHunkTarget() { | ||||
$line = $this->getLine(); | $line = $this->getLine(); | ||||
$matches = null; | $matches = null; | ||||
$remainder = '(?:\s*\(.*\))?'; | $remainder = '(?:\s*\(.*\))?'; | ||||
if ($this->getIsMercurial()) { | if ($this->getIsMercurial()) { | ||||
// Something like "Fri Aug 26 01:20:50 2005 -0700", don't bother trying | // Something like "Fri Aug 26 01:20:50 2005 -0700", don't bother trying | ||||
// to parse it. | // to parse it. | ||||
$remainder = '\t.*'; | $remainder = '\t.*'; | ||||
} else if ($this->isRCS) { | |||||
$remainder = '\s.*'; | |||||
} | } | ||||
$ok = preg_match( | $ok = preg_match( | ||||
'@^[-+]{3} (?:[ab]/)?(?P<path>.*?)'.$remainder.'$@', | '@^[-+]{3} (?:[ab]/)?(?P<path>.*?)'.$remainder.'$@', | ||||
$line, | $line, | ||||
$matches); | $matches); | ||||
if (!$ok) { | if (!$ok) { | ||||
$this->didFailParse( | $this->didFailParse( | ||||
"Expected hunk target '+++ path/to/file.ext (revision N)'."); | "Expected hunk target '+++ path/to/file.ext (revision N)'."); | ||||
} | } | ||||
$this->nextLine(); | $this->nextLine(); | ||||
return $matches['path']; | return $matches['path']; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 513 Lines • Show Last 20 Lines |
I think you should be able to add something like this: