array( 'metadata' => self::SERIALIZATION_JSON, 'oldProperties' => self::SERIALIZATION_JSON, 'newProperties' => self::SERIALIZATION_JSON, 'awayPaths' => self::SERIALIZATION_JSON, )) + parent::getConfiguration(); } public function getAffectedLineCount() { return $this->getAddLines() + $this->getDelLines(); } public function attachHunks(array $hunks) { assert_instances_of($hunks, 'DifferentialHunk'); $this->hunks = $hunks; return $this; } public function getHunks() { return $this->assertAttached($this->hunks); } public function getDisplayFilename() { $name = $this->getFilename(); if ($this->getFileType() == DifferentialChangeType::FILE_DIRECTORY) { $name .= '/'; } return $name; } public function addUnsavedHunk(DifferentialHunk $hunk) { if ($this->hunks === self::ATTACHABLE) { $this->hunks = array(); } $this->hunks[] = $hunk; $this->unsavedHunks[] = $hunk; return $this; } public function loadHunks() { if (!$this->getID()) { return array(); } return id(new DifferentialHunk())->loadAllWhere( 'changesetID = %d', $this->getID()); } public function save() { $this->openTransaction(); $ret = parent::save(); foreach ($this->unsavedHunks as $hunk) { $hunk->setChangesetID($this->getID()); $hunk->save(); } $this->saveTransaction(); return $ret; } public function delete() { $this->openTransaction(); foreach ($this->loadHunks() as $hunk) { $hunk->delete(); } $this->unsavedHunks = array(); queryfx( $this->establishConnection('w'), 'DELETE FROM %T WHERE id = %d', self::TABLE_CACHE, $this->getID()); $ret = parent::delete(); $this->saveTransaction(); return $ret; } public function getSortKey() { $sort_key = $this->getFilename(); // Sort files with ".h" in them first, so headers (.h, .hpp) come before // implementations (.c, .cpp, .cs). $sort_key = str_replace('.h', '.!h', $sort_key); return $sort_key; } public function makeNewFile() { $file = mpull($this->getHunks(), 'makeNewFile'); return implode('', $file); } public function makeOldFile() { $file = mpull($this->getHunks(), 'makeOldFile'); return implode('', $file); } public function makeChangesWithContext($num_lines = 3) { $with_context = array(); foreach ($this->getHunks() as $hunk) { $context = array(); $changes = explode("\n", $hunk->getChanges()); foreach ($changes as $l => $line) { $type = substr($line, 0, 1); if ($type == '+' || $type == '-') { $context += array_fill($l - $num_lines, 2 * $num_lines + 1, true); } } $with_context[] = array_intersect_key($changes, $context); } return array_mergev($with_context); } public function getAnchorName() { return substr(md5($this->getFilename()), 0, 8); } public function getAbsoluteRepositoryPath( PhabricatorRepository $repository = null, DifferentialDiff $diff = null) { $base = '/'; if ($diff && $diff->getSourceControlPath()) { $base = id(new PhutilURI($diff->getSourceControlPath()))->getPath(); } $path = $this->getFilename(); $path = rtrim($base, '/').'/'.ltrim($path, '/'); $svn = PhabricatorRepositoryType::REPOSITORY_TYPE_SVN; if ($repository && $repository->getVersionControlSystem() == $svn) { $prefix = $repository->getDetail('remote-uri'); $prefix = id(new PhutilURI($prefix))->getPath(); if (!strncmp($path, $prefix, strlen($prefix))) { $path = substr($path, strlen($prefix)); } $path = '/'.ltrim($path, '/'); } return $path; } public function getWhitespaceMatters() { $config = PhabricatorEnv::getEnvConfig('differential.whitespace-matters'); foreach ($config as $regexp) { if (preg_match($regexp, $this->getFilename())) { return true; } } return false; } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, ); } public function getPolicy($capability) { // TODO: For now, these are never queried directly through the policy // framework. Fix that up. return PhabricatorPolicies::getMostOpenPolicy(); } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return false; } public function describeAutomaticCapability($capability) { return null; } }