Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/differential/storage/DifferentialDiff.php b/src/applications/differential/storage/DifferentialDiff.php
index 3f66656da6..2459dac2f8 100644
--- a/src/applications/differential/storage/DifferentialDiff.php
+++ b/src/applications/differential/storage/DifferentialDiff.php
@@ -1,314 +1,324 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
final class DifferentialDiff extends DifferentialDAO {
protected $revisionID;
protected $authorPHID;
protected $sourceMachine;
protected $sourcePath;
protected $sourceControlSystem;
protected $sourceControlBaseRevision;
protected $sourceControlPath;
protected $lintStatus;
protected $unitStatus;
protected $lineCount;
protected $branch;
protected $bookmark;
protected $parentRevisionID;
protected $arcanistProjectPHID;
protected $creationMethod;
protected $repositoryUUID;
protected $description;
private $unsavedChangesets = array();
private $changesets;
public function addUnsavedChangeset(DifferentialChangeset $changeset) {
if ($this->changesets === null) {
$this->changesets = array();
}
$this->unsavedChangesets[] = $changeset;
$this->changesets[] = $changeset;
return $this;
}
public function attachChangesets(array $changesets) {
assert_instances_of($changesets, 'DifferentialChangeset');
$this->changesets = $changesets;
return $this;
}
public function getChangesets() {
if ($this->changesets === null) {
throw new Exception("Must load and attach changesets first!");
}
return $this->changesets;
}
public function loadChangesets() {
if (!$this->getID()) {
return array();
}
return id(new DifferentialChangeset())->loadAllWhere(
'diffID = %d',
$this->getID());
}
public function loadArcanistProject() {
if (!$this->getArcanistProjectPHID()) {
return null;
}
return id(new PhabricatorRepositoryArcanistProject())->loadOneWhere(
'phid = %s',
$this->getArcanistProjectPHID());
}
public function getBackingVersionControlSystem() {
$arcanist_project = $this->loadArcanistProject();
if (!$arcanist_project) {
return null;
}
$repository = $arcanist_project->loadRepository();
if (!$repository) {
return null;
}
return $repository->getVersionControlSystem();
}
public function save() {
$this->openTransaction();
$ret = parent::save();
foreach ($this->unsavedChangesets as $changeset) {
$changeset->setDiffID($this->getID());
$changeset->save();
}
$this->saveTransaction();
return $ret;
}
public function delete() {
$this->openTransaction();
foreach ($this->loadChangesets() as $changeset) {
$changeset->delete();
}
$properties = id(new DifferentialDiffProperty())->loadAllWhere(
'diffID = %d',
$this->getID());
foreach ($properties as $prop) {
$prop->delete();
}
$ret = parent::delete();
$this->saveTransaction();
return $ret;
}
public static function newFromRawChanges(array $changes) {
assert_instances_of($changes, 'ArcanistDiffChange');
$diff = new DifferentialDiff();
$lines = 0;
foreach ($changes as $change) {
$changeset = new DifferentialChangeset();
$add_lines = 0;
$del_lines = 0;
+ $first_line = PHP_INT_MAX;
$hunks = $change->getHunks();
if ($hunks) {
foreach ($hunks as $hunk) {
$dhunk = new DifferentialHunk();
$dhunk->setOldOffset($hunk->getOldOffset());
$dhunk->setOldLen($hunk->getOldLength());
$dhunk->setNewOffset($hunk->getNewOffset());
$dhunk->setNewLen($hunk->getNewLength());
$dhunk->setChanges($hunk->getCorpus());
$changeset->addUnsavedHunk($dhunk);
$add_lines += $hunk->getAddLines();
$del_lines += $hunk->getDelLines();
+ $added_lines = $hunk->getChangedLines('new');
+ if ($added_lines) {
+ $first_line = min($first_line, head_key($added_lines));
+ }
}
$lines += $add_lines + $del_lines;
} else {
// This happens when you add empty files.
$changeset->attachHunks(array());
}
+ $metadata = $change->getAllMetadata();
+ if ($first_line != PHP_INT_MAX) {
+ $metadata['line:first'] = $first_line;
+ }
+
$changeset->setOldFile($change->getOldPath());
$changeset->setFilename($change->getCurrentPath());
$changeset->setChangeType($change->getType());
$changeset->setFileType($change->getFileType());
- $changeset->setMetadata($change->getAllMetadata());
+ $changeset->setMetadata($metadata);
$changeset->setOldProperties($change->getOldProperties());
$changeset->setNewProperties($change->getNewProperties());
$changeset->setAwayPaths($change->getAwayPaths());
$changeset->setAddLines($add_lines);
$changeset->setDelLines($del_lines);
$diff->addUnsavedChangeset($changeset);
}
$diff->setLineCount($lines);
$diff->detectCopiedCode();
return $diff;
}
public function detectCopiedCode($min_width = 30, $min_lines = 3) {
$map = array();
$files = array();
$types = array();
foreach ($this->changesets as $changeset) {
$file = $changeset->getFilename();
foreach ($changeset->getHunks() as $hunk) {
$line = $hunk->getOldOffset();
foreach (explode("\n", $hunk->getChanges()) as $code) {
$type = (isset($code[0]) ? $code[0] : '');
if ($type == '-' || $type == ' ') {
$code = trim(substr($code, 1));
$files[$file][$line] = $code;
$types[$file][$line] = $type;
if (strlen($code) >= $min_width) {
$map[$code][] = array($file, $line);
}
$line++;
}
}
}
}
foreach ($this->changesets as $changeset) {
$copies = array();
foreach ($changeset->getHunks() as $hunk) {
$added = array_map('trim', $hunk->getAddedLines());
for (reset($added); list($line, $code) = each($added); next($added)) {
if (isset($map[$code])) { // We found a long matching line.
$best_length = 0;
foreach ($map[$code] as $val) { // Explore all candidates.
list($file, $orig_line) = $val;
$length = 1;
// Search also backwards for short lines.
foreach (array(-1, 1) as $direction) {
$offset = $direction;
while (!isset($copies[$line + $offset]) &&
isset($added[$line + $offset]) &&
idx($files[$file], $orig_line + $offset) ===
$added[$line + $offset]) {
$length++;
$offset += $direction;
}
}
if ($length > $best_length ||
($length == $best_length && // Prefer moves.
idx($types[$file], $orig_line) == '-')) {
$best_length = $length;
// ($offset - 1) contains number of forward matching lines.
$best_offset = $offset - 1;
$best_file = $file;
$best_line = $orig_line;
}
}
$file = ($best_file == $changeset->getFilename() ? '' : $best_file);
for ($i = $best_length; $i--; ) {
$type = idx($types[$best_file], $best_line + $best_offset - $i);
$copies[$line + $best_offset - $i] = ($best_length < $min_lines
? array() // Ignore short blocks.
: array($file, $best_line + $best_offset - $i, $type));
}
for ($i = 0; $i < $best_offset; $i++) {
next($added);
}
}
}
}
$copies = array_filter($copies);
if ($copies) {
$metadata = $changeset->getMetadata();
$metadata['copy:lines'] = $copies;
$changeset->setMetadata($metadata);
}
}
}
public function getDiffDict() {
$dict = array(
'id' => $this->getID(),
'parent' => $this->getParentRevisionID(),
'revisionID' => $this->getRevisionID(),
'sourceControlBaseRevision' => $this->getSourceControlBaseRevision(),
'sourceControlPath' => $this->getSourceControlPath(),
'sourceControlSystem' => $this->getSourceControlSystem(),
'branch' => $this->getBranch(),
'bookmark' => $this->getBookmark(),
'creationMethod' => $this->getCreationMethod(),
'description' => $this->getDescription(),
'unitStatus' => $this->getUnitStatus(),
'lintStatus' => $this->getLintStatus(),
'changes' => array(),
'properties' => array(),
);
foreach ($this->getChangesets() as $changeset) {
$hunks = array();
foreach ($changeset->getHunks() as $hunk) {
$hunks[] = array(
'oldOffset' => $hunk->getOldOffset(),
'newOffset' => $hunk->getNewOffset(),
'oldLength' => $hunk->getOldLen(),
'newLength' => $hunk->getNewLen(),
'addLines' => null,
'delLines' => null,
'isMissingOldNewline' => null,
'isMissingNewNewline' => null,
'corpus' => $hunk->getChanges(),
);
}
$change = array(
'metadata' => $changeset->getMetadata(),
'oldPath' => $changeset->getOldFile(),
'currentPath' => $changeset->getFilename(),
'awayPaths' => $changeset->getAwayPaths(),
'oldProperties' => $changeset->getOldProperties(),
'newProperties' => $changeset->getNewProperties(),
'type' => $changeset->getChangeType(),
'fileType' => $changeset->getFileType(),
'commitHash' => null,
'addLines' => $changeset->getAddLines(),
'delLines' => $changeset->getDelLines(),
'hunks' => $hunks,
);
$dict['changes'][] = $change;
}
$properties = id(new DifferentialDiffProperty())->loadAllWhere(
'diffID = %d',
$this->getID());
foreach ($properties as $property) {
$dict['properties'][$property->getName()] = $property->getData();
}
return $dict;
}
}
diff --git a/src/applications/differential/view/DifferentialChangesetListView.php b/src/applications/differential/view/DifferentialChangesetListView.php
index c85990b448..3f9cfe8e13 100644
--- a/src/applications/differential/view/DifferentialChangesetListView.php
+++ b/src/applications/differential/view/DifferentialChangesetListView.php
@@ -1,314 +1,315 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
final class DifferentialChangesetListView extends AphrontView {
private $changesets = array();
private $visibleChangesets = array();
private $references = array();
private $inlineURI;
private $renderURI = '/differential/changeset/';
private $whitespace;
private $standaloneURI;
private $leftRawFileURI;
private $rightRawFileURI;
private $user;
private $symbolIndexes = array();
private $repository;
private $diff;
private $vsMap = array();
public function setChangesets($changesets) {
$this->changesets = $changesets;
return $this;
}
public function setVisibleChangesets($visible_changesets) {
$this->visibleChangesets = $visible_changesets;
return $this;
}
public function setInlineCommentControllerURI($uri) {
$this->inlineURI = $uri;
return $this;
}
public function setUser(PhabricatorUser $user) {
$this->user = $user;
return $this;
}
public function setRepository(PhabricatorRepository $repository) {
$this->repository = $repository;
return $this;
}
public function setDiff(DifferentialDiff $diff) {
$this->diff = $diff;
return $this;
}
public function setRenderingReferences(array $references) {
$this->references = $references;
return $this;
}
public function setSymbolIndexes(array $indexes) {
$this->symbolIndexes = $indexes;
return $this;
}
public function setRenderURI($render_uri) {
$this->renderURI = $render_uri;
return $this;
}
public function setWhitespace($whitespace) {
$this->whitespace = $whitespace;
return $this;
}
public function setVsMap(array $vs_map) {
$this->vsMap = $vs_map;
return $this;
}
public function getVsMap() {
return $this->vsMap;
}
public function setStandaloneURI($uri) {
$this->standaloneURI = $uri;
return $this;
}
public function setRawFileURIs($l, $r) {
$this->leftRawFileURI = $l;
$this->rightRawFileURI = $r;
return $this;
}
public function render() {
require_celerity_resource('differential-changeset-view-css');
$changesets = $this->changesets;
Javelin::initBehavior('differential-toggle-files', array());
$output = array();
$mapping = array();
foreach ($changesets as $key => $changeset) {
$file = $changeset->getFilename();
$class = 'differential-changeset';
if (!$this->inlineURI) {
$class .= ' differential-changeset-noneditable';
}
$ref = $this->references[$key];
$detail = new DifferentialChangesetDetailView();
$view_options = $this->renderViewOptionsDropdown(
$detail,
$ref,
$changeset);
$prefs = $this->user->loadPreferences();
$pref_symbols = $prefs->getPreference(
PhabricatorUserPreferences::PREFERENCE_DIFFUSION_SYMBOLS);
$detail->setChangeset($changeset);
$detail->addButton($view_options);
if ($pref_symbols != 'disabled') {
$detail->setSymbolIndex(idx($this->symbolIndexes, $key));
}
$detail->setVsChangesetID(idx($this->vsMap, $changeset->getID()));
$detail->setEditable(true);
$uniq_id = 'diff-'.$changeset->getAnchorName();
if (isset($this->visibleChangesets[$key])) {
$load = 'Loading...';
$mapping[$uniq_id] = $ref;
} else {
$load = javelin_render_tag(
'a',
array(
'href' => '#'.$uniq_id,
'meta' => array(
'id' => $uniq_id,
'ref' => $ref,
'kill' => true,
),
'sigil' => 'differential-load',
'mustcapture' => true,
),
'Load');
}
$detail->appendChild(
phutil_render_tag(
'div',
array(
'id' => $uniq_id,
),
'<div class="differential-loading">'.$load.'</div>'));
$output[] = $detail->render();
}
require_celerity_resource('aphront-tooltip-css');
Javelin::initBehavior('differential-populate', array(
'registry' => $mapping,
'whitespace' => $this->whitespace,
'uri' => $this->renderURI,
));
Javelin::initBehavior('differential-show-more', array(
'uri' => $this->renderURI,
'whitespace' => $this->whitespace,
));
Javelin::initBehavior('differential-comment-jump', array());
if ($this->inlineURI) {
$undo_templates = $this->renderUndoTemplates();
Javelin::initBehavior('differential-edit-inline-comments', array(
'uri' => $this->inlineURI,
'undo_templates' => $undo_templates,
'stage' => 'differential-review-stage',
));
}
return phutil_render_tag(
'div',
array(
'class' => 'differential-review-stage',
'id' => 'differential-review-stage',
),
implode("\n", $output));
}
/**
* Render the "Undo" markup for the inline comment undo feature.
*/
private function renderUndoTemplates() {
$link = javelin_render_tag(
'a',
array(
'href' => '#',
'sigil' => 'differential-inline-comment-undo',
),
'Undo');
$div = phutil_render_tag(
'div',
array(
'class' => 'differential-inline-undo',
),
'Changes discarded. '.$link);
$template =
'<table><tr>'.
'<th></th><td>%s</td>'.
'<th></th><td colspan="2">%s</td>'.
'</tr></table>';
return array(
'l' => sprintf($template, $div, ''),
'r' => sprintf($template, '', $div),
);
}
private function renderViewOptionsDropdown(
DifferentialChangesetDetailView $detail,
$ref,
DifferentialChangeset $changeset) {
$meta = array();
$qparams = array(
'ref' => $ref,
'whitespace' => $this->whitespace,
);
if ($this->standaloneURI) {
$uri = new PhutilURI($this->standaloneURI);
$uri->setQueryParams($uri->getQueryParams() + $qparams);
$meta['standaloneURI'] = (string)$uri;
}
$repository = $this->repository;
if ($repository) {
$meta['diffusionURI'] = (string)$repository->getDiffusionBrowseURIForPath(
- $changeset->getAbsoluteRepositoryPath($repository, $this->diff));
+ $changeset->getAbsoluteRepositoryPath($repository, $this->diff),
+ idx($changeset->getMetadata(), 'line:first'));
}
$change = $changeset->getChangeType();
if ($this->leftRawFileURI) {
if ($change != DifferentialChangeType::TYPE_ADD) {
$uri = new PhutilURI($this->leftRawFileURI);
$uri->setQueryParams($uri->getQueryParams() + $qparams);
$meta['leftURI'] = (string)$uri;
}
}
if ($this->rightRawFileURI) {
if ($change != DifferentialChangeType::TYPE_DELETE &&
$change != DifferentialChangeType::TYPE_MULTICOPY) {
$uri = new PhutilURI($this->rightRawFileURI);
$uri->setQueryParams($uri->getQueryParams() + $qparams);
$meta['rightURI'] = (string)$uri;
}
}
$user = $this->user;
if ($user && $repository) {
$path = ltrim(
$changeset->getAbsoluteRepositoryPath($repository, $this->diff),
'/');
- $line = 1; // TODO: get first changed line
+ $line = idx($changeset->getMetadata(), 'line:first', 1);
$callsign = $repository->getCallsign();
$editor_link = $user->loadEditorLink($path, $line, $callsign);
if ($editor_link) {
$meta['editor'] = $editor_link;
} else {
$meta['editorConfigure'] = '/settings/panel/display/';
}
}
$meta['containerID'] = $detail->getID();
Javelin::initBehavior(
'differential-dropdown-menus',
array());
return javelin_render_tag(
'a',
array(
'class' => 'button small grey',
'meta' => $meta,
'href' => idx($meta, 'detailURI', '#'),
'target' => '_blank',
'sigil' => 'differential-view-options',
),
"View Options \xE2\x96\xBC");
}
}
diff --git a/src/applications/repository/storage/PhabricatorRepository.php b/src/applications/repository/storage/PhabricatorRepository.php
index b5be702783..f3387c5b36 100644
--- a/src/applications/repository/storage/PhabricatorRepository.php
+++ b/src/applications/repository/storage/PhabricatorRepository.php
@@ -1,550 +1,551 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @task uri Repository URI Management
*/
final class PhabricatorRepository extends PhabricatorRepositoryDAO {
const TABLE_PATH = 'repository_path';
const TABLE_PATHCHANGE = 'repository_pathchange';
const TABLE_FILESYSTEM = 'repository_filesystem';
const TABLE_SUMMARY = 'repository_summary';
const TABLE_BADCOMMIT = 'repository_badcommit';
protected $phid;
protected $name;
protected $callsign;
protected $uuid;
protected $versionControlSystem;
protected $details = array();
private $sshKeyfile;
public function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
self::CONFIG_SERIALIZATION => array(
'details' => self::SERIALIZATION_JSON,
),
) + parent::getConfiguration();
}
public function generatePHID() {
return PhabricatorPHID::generateNewPHID(
PhabricatorPHIDConstants::PHID_TYPE_REPO);
}
public function getDetail($key, $default = null) {
return idx($this->details, $key, $default);
}
public function setDetail($key, $value) {
$this->details[$key] = $value;
return $this;
}
- public function getDiffusionBrowseURIForPath($path) {
+ public function getDiffusionBrowseURIForPath($path, $line = null) {
$drequest = DiffusionRequest::newFromDictionary(
array(
'repository' => $this,
'path' => $path,
));
return $drequest->generateURI(
array(
'action' => 'browse',
+ 'line' => $line,
));
}
public function getLocalPath() {
return $this->getDetail('local-path');
}
public function execRemoteCommand($pattern /* , $arg, ... */) {
$args = func_get_args();
$args = $this->formatRemoteCommand($args);
return call_user_func_array('exec_manual', $args);
}
public function execxRemoteCommand($pattern /* , $arg, ... */) {
$args = func_get_args();
$args = $this->formatRemoteCommand($args);
return call_user_func_array('execx', $args);
}
public function getRemoteCommandFuture($pattern /* , $arg, ... */) {
$args = func_get_args();
$args = $this->formatRemoteCommand($args);
return newv('ExecFuture', $args);
}
public function passthruRemoteCommand($pattern /* , $arg, ... */) {
$args = func_get_args();
$args = $this->formatRemoteCommand($args);
return call_user_func_array('phutil_passthru', $args);
}
public function execLocalCommand($pattern /* , $arg, ... */) {
$args = func_get_args();
$args = $this->formatLocalCommand($args);
return call_user_func_array('exec_manual', $args);
}
public function execxLocalCommand($pattern /* , $arg, ... */) {
$args = func_get_args();
$args = $this->formatLocalCommand($args);
return call_user_func_array('execx', $args);
}
public function getLocalCommandFuture($pattern /* , $arg, ... */) {
$args = func_get_args();
$args = $this->formatLocalCommand($args);
return newv('ExecFuture', $args);
}
public function passthruLocalCommand($pattern /* , $arg, ... */) {
$args = func_get_args();
$args = $this->formatLocalCommand($args);
return call_user_func_array('phutil_passthru', $args);
}
private function formatRemoteCommand(array $args) {
$pattern = $args[0];
$args = array_slice($args, 1);
if ($this->shouldUseSSH()) {
switch ($this->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$pattern = "SVN_SSH=%s svn --non-interactive {$pattern}";
array_unshift(
$args,
csprintf(
'ssh -l %s -i %s',
$this->getSSHLogin(),
$this->getSSHKeyfile()));
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$command = call_user_func_array(
'csprintf',
array_merge(
array(
"(ssh-add %s && git {$pattern})",
$this->getSSHKeyfile(),
),
$args));
$pattern = "ssh-agent sh -c %s";
$args = array($command);
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$pattern = "hg --config ui.ssh=%s {$pattern}";
array_unshift(
$args,
csprintf(
'ssh -l %s -i %s',
$this->getSSHLogin(),
$this->getSSHKeyfile()));
break;
default:
throw new Exception("Unrecognized version control system.");
}
} else if ($this->shouldUseHTTP()) {
switch ($this->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$pattern =
"svn ".
"--non-interactive ".
"--no-auth-cache ".
"--trust-server-cert ".
"--username %s ".
"--password %s ".
$pattern;
array_unshift(
$args,
$this->getDetail('http-login'),
$this->getDetail('http-pass'));
break;
default:
throw new Exception(
"No support for HTTP Basic Auth in this version control system.");
}
} else if ($this->shouldUseSVNProtocol()) {
switch ($this->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$pattern =
"svn ".
"--non-interactive ".
"--no-auth-cache ".
"--username %s ".
"--password %s ".
$pattern;
array_unshift(
$args,
$this->getDetail('http-login'),
$this->getDetail('http-pass'));
break;
default:
throw new Exception(
"SVN protocol is SVN only.");
}
} else {
switch ($this->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$pattern = "svn --non-interactive {$pattern}";
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$pattern = "git {$pattern}";
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$pattern = "hg {$pattern}";
break;
default:
throw new Exception("Unrecognized version control system.");
}
}
array_unshift($args, $pattern);
return $args;
}
private function formatLocalCommand(array $args) {
$pattern = $args[0];
$args = array_slice($args, 1);
switch ($this->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$pattern = "(cd %s && svn --non-interactive {$pattern})";
array_unshift($args, $this->getLocalPath());
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$pattern = "(cd %s && git {$pattern})";
array_unshift($args, $this->getLocalPath());
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$pattern = "(cd %s && HGPLAIN=1 hg {$pattern})";
array_unshift($args, $this->getLocalPath());
break;
default:
throw new Exception("Unrecognized version control system.");
}
array_unshift($args, $pattern);
return $args;
}
private function getSSHLogin() {
return $this->getDetail('ssh-login');
}
private function getSSHKeyfile() {
if ($this->sshKeyfile === null) {
$key = $this->getDetail('ssh-key');
$keyfile = $this->getDetail('ssh-keyfile');
if ($keyfile) {
// Make sure we can read the file, that it exists, etc.
Filesystem::readFile($keyfile);
$this->sshKeyfile = $keyfile;
} else if ($key) {
$keyfile = new TempFile('phabricator-repository-ssh-key');
chmod($keyfile, 0600);
Filesystem::writeFile($keyfile, $key);
$this->sshKeyfile = $keyfile;
} else {
$this->sshKeyfile = '';
}
}
return (string)$this->sshKeyfile;
}
public function getURI() {
return '/diffusion/'.$this->getCallsign().'/';
}
public function isTracked() {
return $this->getDetail('tracking-enabled', false);
}
public function getDefaultBranch() {
$default = $this->getDetail('default-branch');
if (strlen($default)) {
return $default;
}
$default_branches = array(
PhabricatorRepositoryType::REPOSITORY_TYPE_GIT => 'master',
PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL => 'default',
);
return idx($default_branches, $this->getVersionControlSystem());
}
private function isBranchInFilter($branch, $filter_key) {
$vcs = $this->getVersionControlSystem();
$is_git = ($vcs == PhabricatorRepositoryType::REPOSITORY_TYPE_GIT);
$use_filter = ($is_git);
if ($use_filter) {
$filter = $this->getDetail($filter_key, array());
if ($filter && empty($filter[$branch])) {
return false;
}
}
// By default, all branches pass.
return true;
}
public function shouldTrackBranch($branch) {
return $this->isBranchInFilter($branch, 'branch-filter');
}
public function shouldAutocloseBranch($branch) {
if ($this->getDetail('disable-autoclose', false)) {
return false;
}
return $this->isBranchInFilter($branch, 'close-commits-filter');
}
public function shouldAutocloseCommit(
PhabricatorRepositoryCommit $commit,
PhabricatorRepositoryCommitData $data) {
if ($this->getDetail('disable-autoclose', false)) {
return false;
}
switch ($this->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
return true;
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
return true;
default:
throw new Exception("Unrecognized version control system.");
}
$branches = $data->getCommitDetail('seenOnBranches', array());
foreach ($branches as $branch) {
if ($this->shouldAutocloseBranch($branch)) {
return true;
}
}
return false;
}
public function formatCommitName($commit_identifier) {
$vcs = $this->getVersionControlSystem();
$type_git = PhabricatorRepositoryType::REPOSITORY_TYPE_GIT;
$type_hg = PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL;
$is_git = ($vcs == $type_git);
$is_hg = ($vcs == $type_hg);
if ($is_git || $is_hg) {
$short_identifier = substr($commit_identifier, 0, 12);
} else {
$short_identifier = $commit_identifier;
}
return 'r'.$this->getCallsign().$short_identifier;
}
public static function loadAllByPHIDOrCallsign(array $names) {
$repositories = array();
foreach ($names as $name) {
$repo = id(new PhabricatorRepository())->loadOneWhere(
'phid = %s OR callsign = %s',
$name,
$name);
if (!$repo) {
throw new Exception(
"No repository with PHID or callsign '{$name}' exists!");
}
$repositories[$repo->getID()] = $repo;
}
return $repositories;
}
/* -( Repository URI Management )------------------------------------------ */
/**
* Get the remote URI for this repository.
*
* @return string
* @task uri
*/
public function getRemoteURI() {
return (string)$this->getRemoteURIObject();
}
/**
* Get the remote URI for this repository, without authentication information.
*
* @return string Repository URI.
* @task uri
*/
public function getPublicRemoteURI() {
$uri = $this->getRemoteURIObject();
// Make sure we don't leak anything if this repo is using HTTP Basic Auth
// with the credentials in the URI or something zany like that.
if ($uri instanceof PhutilGitURI) {
$uri->setUser(null);
} else {
$uri->setUser(null);
$uri->setPass(null);
}
return (string)$uri;
}
/**
* Get the protocol for the repository's remote.
*
* @return string Protocol, like "ssh" or "git".
* @task uri
*/
public function getRemoteProtocol() {
$uri = $this->getRemoteURIObject();
if ($uri instanceof PhutilGitURI) {
return 'ssh';
} else {
return $uri->getProtocol();
}
}
/**
* Get a parsed object representation of the repository's remote URI. This
* may be a normal URI (returned as a @{class@libphutil:PhutilURI}) or a git
* URI (returned as a @{class@libphutil:PhutilGitURI}).
*
* @return wild A @{class@libphutil:PhutilURI} or
* @{class@libphutil:PhutilGitURI}.
* @task uri
*/
private function getRemoteURIObject() {
$raw_uri = $this->getDetail('remote-uri');
if (!$raw_uri) {
return new PhutilURI('');
}
if (!strncmp($raw_uri, '/', 1)) {
return new PhutilURI('file://'.$raw_uri);
}
$uri = new PhutilURI($raw_uri);
if ($uri->getProtocol()) {
if ($this->isSSHProtocol($uri->getProtocol())) {
if ($this->getSSHLogin()) {
$uri->setUser($this->getSSHLogin());
}
}
return $uri;
}
$uri = new PhutilGitURI($raw_uri);
if ($uri->getDomain()) {
if ($this->getSSHLogin()) {
$uri->setUser($this->getSSHLogin());
}
return $uri;
}
throw new Exception("Remote URI '{$raw_uri}' could not be parsed!");
}
/**
* Determine if we should connect to the remote using SSH flags and
* credentials.
*
* @return bool True to use the SSH protocol.
* @task uri
*/
private function shouldUseSSH() {
$protocol = $this->getRemoteProtocol();
if ($this->isSSHProtocol($protocol)) {
return (bool)$this->getSSHKeyfile();
} else {
return false;
}
}
/**
* Determine if we should connect to the remote using HTTP flags and
* credentials.
*
* @return bool True to use the HTTP protocol.
* @task uri
*/
private function shouldUseHTTP() {
$protocol = $this->getRemoteProtocol();
if ($protocol == 'http' || $protocol == 'https') {
return (bool)$this->getDetail('http-login');
} else {
return false;
}
}
/**
* Determine if we should connect to the remote using SVN flags and
* credentials.
*
* @return bool True to use the SVN protocol.
* @task uri
*/
private function shouldUseSVNProtocol() {
$protocol = $this->getRemoteProtocol();
if ($protocol == 'svn') {
return (bool)$this->getDetail('http-login');
} else {
return false;
}
}
/**
* Determine if a protocol is SSH or SSH-like.
*
* @param string A protocol string, like "http" or "ssh".
* @return bool True if the protocol is SSH-like.
* @task uri
*/
private function isSSHProtocol($protocol) {
return ($protocol == 'ssh' || $protocol == 'svn+ssh');
}
}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Dec 2, 4:04 PM (16 h, 8 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
432198
Default Alt Text
(35 KB)

Event Timeline