本文整理汇总了PHP中PhabricatorRepository::getDetail方法的典型用法代码示例。如果您正苦于以下问题:PHP PhabricatorRepository::getDetail方法的具体用法?PHP PhabricatorRepository::getDetail怎么用?PHP PhabricatorRepository::getDetail使用的例子?那么恭喜您, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类PhabricatorRepository
的用法示例。
在下文中一共展示了PhabricatorRepository::getDetail方法的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的PHP代码示例。
示例1: checkIfRepositoryIsFullyImported
private function checkIfRepositoryIsFullyImported(PhabricatorRepository $repository)
{
// Check if the repository has the "Importing" flag set. We want to clear
// the flag if we can.
$importing = $repository->getDetail('importing');
if (!$importing) {
// This repository isn't marked as "Importing", so we're done.
return;
}
// Look for any commit which hasn't imported.
$unparsed_commit = queryfx_one($repository->establishConnection('r'), 'SELECT * FROM %T WHERE repositoryID = %d AND (importStatus & %d) != %d
LIMIT 1', id(new PhabricatorRepositoryCommit())->getTableName(), $repository->getID(), PhabricatorRepositoryCommit::IMPORTED_ALL, PhabricatorRepositoryCommit::IMPORTED_ALL);
if ($unparsed_commit) {
// We found a commit which still needs to import, so we can't clear the
// flag.
return;
}
// Clear the "importing" flag.
$repository->openTransaction();
$repository->beginReadLocking();
$repository = $repository->reload();
$repository->setDetail('importing', false);
$repository->save();
$repository->endReadLocking();
$repository->saveTransaction();
}
示例2: handleProtocols
public function handleProtocols(PhabricatorRepository $repository)
{
$request = $this->getRequest();
$user = $request->getUser();
$type = $repository->getVersionControlSystem();
$is_svn = $type == PhabricatorRepositoryType::REPOSITORY_TYPE_SVN;
$v_http_mode = $repository->getDetail('serve-over-http', PhabricatorRepository::SERVE_OFF);
$v_ssh_mode = $repository->getDetail('serve-over-ssh', PhabricatorRepository::SERVE_OFF);
$edit_uri = $this->getRepositoryControllerURI($repository, 'edit/');
$prev_uri = $this->getRepositoryControllerURI($repository, 'edit/hosting/');
if ($request->isFormPost()) {
$v_http_mode = $request->getStr('http');
$v_ssh_mode = $request->getStr('ssh');
$xactions = array();
$template = id(new PhabricatorRepositoryTransaction());
$type_http = PhabricatorRepositoryTransaction::TYPE_PROTOCOL_HTTP;
$type_ssh = PhabricatorRepositoryTransaction::TYPE_PROTOCOL_SSH;
if (!$is_svn) {
$xactions[] = id(clone $template)->setTransactionType($type_http)->setNewValue($v_http_mode);
}
$xactions[] = id(clone $template)->setTransactionType($type_ssh)->setNewValue($v_ssh_mode);
id(new PhabricatorRepositoryEditor())->setContinueOnNoEffect(true)->setContentSourceFromRequest($request)->setActor($user)->applyTransactions($repository, $xactions);
return id(new AphrontRedirectResponse())->setURI($edit_uri);
}
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb(pht('Edit Protocols'));
$title = pht('Edit Protocols (%s)', $repository->getName());
$rw_message = pht('Phabricator will serve a read-write copy of this repository.');
if (!$repository->isHosted()) {
$rw_message = array($rw_message, phutil_tag('br'), phutil_tag('br'), pht('%s: This repository is hosted elsewhere, so Phabricator can not ' . 'perform writes. This mode will act like "Read Only" for ' . 'repositories hosted elsewhere.', phutil_tag('strong', array(), 'WARNING')));
}
$ssh_control = id(new AphrontFormRadioButtonControl())->setName('ssh')->setLabel(pht('SSH'))->setValue($v_ssh_mode)->addButton(PhabricatorRepository::SERVE_OFF, PhabricatorRepository::getProtocolAvailabilityName(PhabricatorRepository::SERVE_OFF), pht('Phabricator will not serve this repository over SSH.'))->addButton(PhabricatorRepository::SERVE_READONLY, PhabricatorRepository::getProtocolAvailabilityName(PhabricatorRepository::SERVE_READONLY), pht('Phabricator will serve a read-only copy of this repository ' . 'over SSH.'))->addButton(PhabricatorRepository::SERVE_READWRITE, PhabricatorRepository::getProtocolAvailabilityName(PhabricatorRepository::SERVE_READWRITE), $rw_message);
$http_control = id(new AphrontFormRadioButtonControl())->setName('http')->setLabel(pht('HTTP'))->setValue($v_http_mode)->addButton(PhabricatorRepository::SERVE_OFF, PhabricatorRepository::getProtocolAvailabilityName(PhabricatorRepository::SERVE_OFF), pht('Phabricator will not serve this repository over HTTP.'))->addButton(PhabricatorRepository::SERVE_READONLY, PhabricatorRepository::getProtocolAvailabilityName(PhabricatorRepository::SERVE_READONLY), pht('Phabricator will serve a read-only copy of this repository ' . 'over HTTP.'))->addButton(PhabricatorRepository::SERVE_READWRITE, PhabricatorRepository::getProtocolAvailabilityName(PhabricatorRepository::SERVE_READWRITE), $rw_message);
if ($is_svn) {
$http_control = id(new AphrontFormMarkupControl())->setLabel(pht('HTTP'))->setValue(phutil_tag('em', array(), pht('Phabricator does not currently support HTTP access to ' . 'Subversion repositories.')));
}
$form = id(new AphrontFormView())->setUser($user)->appendRemarkupInstructions(pht('Phabricator can serve repositories over various protocols. You can ' . 'configure server protocols here.'))->appendChild($ssh_control);
if (!PhabricatorEnv::getEnvConfig('diffusion.allow-http-auth')) {
$form->appendRemarkupInstructions(pht('NOTE: The configuration setting [[ %s | %s ]] is currently ' . 'disabled. You must enable it to activate authenticated access ' . 'to repositories over HTTP.', '/config/edit/diffusion.allow-http-auth/', 'diffusion.allow-http-auth'));
}
$form->appendChild($http_control)->appendChild(id(new AphrontFormSubmitControl())->setValue(pht('Save Changes'))->addCancelButton($prev_uri, pht('Back')));
$object_box = id(new PHUIObjectBoxView())->setHeaderText($title)->setForm($form);
return $this->buildApplicationPage(array($crumbs, $object_box), array('title' => $title));
}
示例3: parseCommit
public function parseCommit(PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit)
{
$uri = $repository->getDetail('remote-uri');
$log = $this->getSVNLogXMLObject($uri, $commit->getCommitIdentifier(), $verbose = false);
$entry = $log->logentry[0];
$author = (string) $entry->author;
$message = (string) $entry->msg;
$this->updateCommitData($author, $message);
if ($this->shouldQueueFollowupTasks()) {
$task = new PhabricatorWorkerTask();
$task->setTaskClass('PhabricatorRepositorySvnCommitChangeParserWorker');
$task->setData(array('commitID' => $commit->getID()));
$task->save();
}
}
示例4: parseCommit
public function parseCommit(PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit)
{
$local_path = $repository->getDetail('local-path');
// NOTE: %B was introduced somewhat recently in git's history, so pull
// commit message information with %s and %b instead.
list($info) = execx('(cd %s && git log -n 1 --pretty=format:%%an%%x00%%s%%n%%n%%b %s)', $local_path, $commit->getCommitIdentifier());
list($author, $message) = explode("", $info);
// Make sure these are valid UTF-8.
$author = phutil_utf8ize($author);
$message = phutil_utf8ize($message);
$message = trim($message);
$this->updateCommitData($author, $message);
if ($this->shouldQueueFollowupTasks()) {
$task = new PhabricatorWorkerTask();
$task->setTaskClass('PhabricatorRepositoryGitCommitChangeParserWorker');
$task->setData(array('commitID' => $commit->getID()));
$task->save();
}
}
开发者ID:nguyennamtien,项目名称:phabricator,代码行数:19,代码来源:PhabricatorRepositoryGitCommitMessageParserWorker.php
示例5: triggerOwnerAudits
private function triggerOwnerAudits(PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit)
{
if ($repository->getDetail('herald-disabled')) {
return;
}
$affected_paths = PhabricatorOwnerPathQuery::loadAffectedPaths($repository, $commit, PhabricatorUser::getOmnipotentUser());
$affected_packages = PhabricatorOwnersPackage::loadAffectedPackages($repository, $affected_paths);
if ($affected_packages) {
$requests = id(new PhabricatorRepositoryAuditRequest())->loadAllWhere('commitPHID = %s', $commit->getPHID());
$requests = mpull($requests, null, 'getAuditorPHID');
foreach ($affected_packages as $package) {
$request = idx($requests, $package->getPHID());
if ($request) {
// Don't update request if it exists already.
continue;
}
if ($package->getAuditingEnabled()) {
$reasons = $this->checkAuditReasons($commit, $package);
if ($reasons) {
$audit_status = PhabricatorAuditStatusConstants::AUDIT_REQUIRED;
} else {
$audit_status = PhabricatorAuditStatusConstants::AUDIT_NOT_REQUIRED;
}
} else {
$reasons = array();
$audit_status = PhabricatorAuditStatusConstants::NONE;
}
$relationship = new PhabricatorRepositoryAuditRequest();
$relationship->setAuditorPHID($package->getPHID());
$relationship->setCommitPHID($commit->getPHID());
$relationship->setAuditReasons($reasons);
$relationship->setAuditStatus($audit_status);
$relationship->save();
$requests[$package->getPHID()] = $relationship;
}
$commit->updateAuditStatus($requests);
$commit->save();
}
}
示例6: parseCommit
public function parseCommit(PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit)
{
if ($repository->getDetail('herald-disabled')) {
return;
}
$data = id(new PhabricatorRepositoryCommitData())->loadOneWhere('commitID = %d', $commit->getID());
$rules = HeraldRule::loadAllByContentTypeWithFullData(HeraldContentTypeConfig::CONTENT_TYPE_COMMIT);
$adapter = new HeraldCommitAdapter($repository, $commit, $data);
$engine = new HeraldEngine();
$effects = $engine->applyRules($rules, $adapter);
$engine->applyEffects($effects, $adapter);
$email_phids = $adapter->getEmailPHIDs();
if (!$email_phids) {
return;
}
$xscript = $engine->getTranscript();
$commit_name = $adapter->getHeraldName();
$revision = $adapter->loadDifferentialRevision();
$name = null;
if ($revision) {
$name = ' ' . $revision->getTitle();
}
$author_phid = $data->getCommitDetail('authorPHID');
$reviewer_phid = $data->getCommitDetail('reviewerPHID');
$phids = array_filter(array($author_phid, $reviewer_phid));
$handles = array();
if ($phids) {
$handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
}
if ($author_phid) {
$author_name = $handles[$author_phid]->getName();
} else {
$author_name = $data->getAuthorName();
}
if ($reviewer_phid) {
$reviewer_name = $handles[$reviewer_phid]->getName();
} else {
$reviewer_name = null;
}
$who = implode(', ', array_filter(array($author_name, $reviewer_name)));
$description = $data->getCommitMessage();
$details = PhabricatorEnv::getProductionURI('/' . $commit_name);
$differential = $revision ? PhabricatorEnv::getProductionURI('/D' . $revision->getID()) : 'No revision.';
$files = $adapter->loadAffectedPaths();
sort($files);
$files = implode("\n ", $files);
$xscript_id = $xscript->getID();
$manage_uri = PhabricatorEnv::getProductionURI('/herald/view/commits/');
$why_uri = PhabricatorEnv::getProductionURI('/herald/transcript/' . $xscript_id . '/');
$body = <<<EOBODY
DESCRIPTION
{$description}
DETAILS
{$details}
DIFFERENTIAL REVISION
{$differential}
AFFECTED FILES
{$files}
MANAGE HERALD COMMIT RULES
{$manage_uri}
WHY DID I GET THIS EMAIL?
{$why_uri}
EOBODY;
$subject = "[Herald/Commit] {$commit_name} ({$who}){$name}";
$mailer = new PhabricatorMetaMTAMail();
$mailer->setRelatedPHID($commit->getPHID());
$mailer->addTos($email_phids);
$mailer->setSubject($subject);
$mailer->setBody($body);
$mailer->addHeader('X-Herald-Rules', $xscript->getXHeraldRulesHeader());
if ($author_phid) {
$mailer->setFrom($author_phid);
}
$mailer->saveAndSend();
}
示例7: lookupSvnCommits
private function lookupSvnCommits(PhabricatorRepository $repository, array $commits)
{
if (!$commits) {
return array();
}
$commit_table = new PhabricatorRepositoryCommit();
$commit_data = queryfx_all($commit_table->establishConnection('w'), 'SELECT id, commitIdentifier FROM %T
WHERE repositoryID = %d AND commitIdentifier in (%Ls)', $commit_table->getTableName(), $repository->getID(), $commits);
$commit_map = ipull($commit_data, 'id', 'commitIdentifier');
$need = array();
foreach ($commits as $commit) {
if (empty($commit_map[$commit])) {
$need[] = $commit;
}
}
// If we are parsing a Subversion repository and have been configured to
// import only some subdirectory of it, we may find commits which reference
// other foreign commits outside of the directory (for instance, because of
// a move or copy). Rather than trying to execute full parses on them, just
// create stub commits and identify the stubs as foreign commits.
if ($need) {
$subpath = $repository->getDetail('svn-subpath');
if (!$subpath) {
$commits = implode(', ', $need);
throw new Exception("Missing commits ({$need}) in a SVN repository which is not " . "configured for subdirectory-only parsing!");
}
foreach ($need as $foreign_commit) {
$commit = new PhabricatorRepositoryCommit();
$commit->setRepositoryID($repository->getID());
$commit->setCommitIdentifier($foreign_commit);
$commit->setEpoch(0);
// Mark this commit as imported so it doesn't prevent the repository
// from transitioning into the "Imported" state.
$commit->setImportStatus(PhabricatorRepositoryCommit::IMPORTED_ALL);
$commit->save();
$data = new PhabricatorRepositoryCommitData();
$data->setCommitID($commit->getID());
$data->setAuthorName('');
$data->setCommitMessage('');
$data->setCommitDetails(array('foreign-svn-stub' => true, 'svn-subpath' => $subpath));
$data->save();
$commit_map[$foreign_commit] = $commit->getID();
}
}
return $commit_map;
}
示例8: buildPropertiesTable
private function buildPropertiesTable(PhabricatorRepository $repository)
{
$properties = array();
$properties['Name'] = $repository->getName();
$properties['Callsign'] = $repository->getCallsign();
$properties['Description'] = $repository->getDetail('description');
switch ($repository->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$properties['Clone URI'] = $repository->getPublicRemoteURI();
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$properties['Repository Root'] = $repository->getPublicRemoteURI();
break;
}
$rows = array();
foreach ($properties as $key => $value) {
$rows[] = array(phutil_escape_html($key), phutil_escape_html($value));
}
$table = new AphrontTableView($rows);
$table->setColumnClasses(array('header', 'wide'));
$panel = new AphrontPanelView();
$panel->setHeader('Repository Properties');
$panel->appendChild($table);
return $panel;
}
示例9: buildDescriptionView
private function buildDescriptionView(PhabricatorRepository $repository)
{
$viewer = $this->getViewer();
$view = id(new PHUIPropertyListView())->setUser($viewer);
$description = $repository->getDetail('description');
if (strlen($description)) {
$description = new PHUIRemarkupView($viewer, $description);
$view->addTextContent($description);
return id(new PHUIObjectBoxView())->setHeaderText(pht('Description'))->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)->appendChild($view);
}
return null;
}
示例10: lookupRecursiveFileList
private function lookupRecursiveFileList(PhabricatorRepository $repository, array $info)
{
$path = $info['rawPath'];
$rev = $info['rawCommit'];
$path = $this->encodeSVNPath($path);
$hashkey = md5($repository->getDetail('remote-uri') . $path . '@' . $rev);
// This method is quite horrible. The underlying challenge is that some
// commits in the Facebook repository are enormous, taking multiple hours
// to 'ls -R' out of the repository and producing XML files >1GB in size.
// If we try to SimpleXML them, the object exhausts available memory on a
// 64G machine. Instead, cache the XML output and then parse it line by line
// to limit space requirements.
$cache_loc = sys_get_temp_dir() . '/diffusion.' . $hashkey . '.svnls';
if (!Filesystem::pathExists($cache_loc)) {
$tmp = new TempFile();
execx('svn --non-interactive --xml ls -R %s%s@%d > %s', $repository->getDetail('remote-uri'), $path, $rev, $tmp);
execx('mv %s %s', $tmp, $cache_loc);
}
$map = $this->parseRecursiveListFileData($cache_loc);
Filesystem::remove($cache_loc);
return $map;
}
示例11: parseCommit
protected function parseCommit(PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit)
{
$full_name = 'r' . $repository->getCallsign() . $commit->getCommitIdentifier();
echo "Parsing {$full_name}...\n";
if ($this->isBadCommit($full_name)) {
echo "This commit is marked bad!\n";
return;
}
$local_path = $repository->getDetail('local-path');
list($raw) = execx('(cd %s && git log -n1 -M -C -B --find-copies-harder --raw -t ' . '--abbrev=40 --pretty=format: %s)', $local_path, $commit->getCommitIdentifier());
$changes = array();
$move_away = array();
$copy_away = array();
$lines = explode("\n", $raw);
foreach ($lines as $line) {
if (!strlen(trim($line))) {
continue;
}
list($old_mode, $new_mode, $old_hash, $new_hash, $more_stuff) = preg_split('/ +/', $line);
// We may only have two pieces here.
list($action, $src_path, $dst_path) = array_merge(explode("\t", $more_stuff), array(null));
// Normalize the paths for consistency with the SVN workflow.
$src_path = '/' . $src_path;
if ($dst_path) {
$dst_path = '/' . $dst_path;
}
$old_mode = intval($old_mode, 8);
$new_mode = intval($new_mode, 8);
$file_type = DifferentialChangeType::FILE_NORMAL;
if ($new_mode & 040000) {
$file_type = DifferentialChangeType::FILE_DIRECTORY;
} else {
if ($new_mode & 0120000) {
$file_type = DifferentialChangeType::FILE_SYMLINK;
}
}
// TODO: We can detect binary changes as git does, through a combination
// of running 'git check-attr' for stuff like 'binary', 'merge' or 'diff',
// and by falling back to inspecting the first 8,000 characters of the
// buffer for null bytes (this is seriously git's algorithm, see
// buffer_is_binary() in xdiff-interface.c).
$change_type = null;
$change_path = $src_path;
$change_target = null;
$is_direct = true;
switch ($action[0]) {
case 'A':
$change_type = DifferentialChangeType::TYPE_ADD;
break;
case 'D':
$change_type = DifferentialChangeType::TYPE_DELETE;
break;
case 'C':
$change_type = DifferentialChangeType::TYPE_COPY_HERE;
$change_path = $dst_path;
$change_target = $src_path;
$copy_away[$change_target][] = $change_path;
break;
case 'R':
$change_type = DifferentialChangeType::TYPE_MOVE_HERE;
$change_path = $dst_path;
$change_target = $src_path;
$move_away[$change_target][] = $change_path;
break;
case 'T':
// Type of the file changed, fall through and treat it as a
// modification. Not 100% sure this is the right thing to do but it
// seems reasonable.
// Type of the file changed, fall through and treat it as a
// modification. Not 100% sure this is the right thing to do but it
// seems reasonable.
case 'M':
if ($file_type == DifferentialChangeType::FILE_DIRECTORY) {
$change_type = DifferentialChangeType::TYPE_CHILD;
$is_direct = false;
} else {
$change_type = DifferentialChangeType::TYPE_CHANGE;
}
break;
// NOTE: "U" (unmerged) and "X" (unknown) statuses are also possible
// in theory but shouldn't appear here.
// NOTE: "U" (unmerged) and "X" (unknown) statuses are also possible
// in theory but shouldn't appear here.
default:
throw new Exception("Failed to parse line '{$line}'.");
}
$changes[$change_path] = array('repositoryID' => $repository->getID(), 'commitID' => $commit->getID(), 'path' => $change_path, 'changeType' => $change_type, 'fileType' => $file_type, 'isDirect' => $is_direct, 'commitSequence' => $commit->getEpoch(), 'targetPath' => $change_target, 'targetCommitID' => $change_target ? $commit->getID() : null);
}
// Add a change to '/' since git doesn't mention it.
$changes['/'] = array('repositoryID' => $repository->getID(), 'commitID' => $commit->getID(), 'path' => '/', 'changeType' => DifferentialChangeType::TYPE_CHILD, 'fileType' => DifferentialChangeType::FILE_DIRECTORY, 'isDirect' => false, 'commitSequence' => $commit->getEpoch(), 'targetPath' => null, 'targetCommitID' => null);
foreach ($copy_away as $change_path => $destinations) {
if (isset($move_away[$change_path])) {
$change_type = DifferentialChangeType::TYPE_MULTICOPY;
$is_direct = true;
unset($move_away[$change_path]);
} else {
$change_type = DifferentialChangeType::TYPE_COPY_AWAY;
$is_direct = false;
}
$reference = $changes[reset($destinations)];
//.........这里部分代码省略.........
开发者ID:nguyennamtien,项目名称:phabricator,代码行数:101,代码来源:PhabricatorRepositoryGitCommitChangeParserWorker.php
示例12: buildDictForRepository
protected function buildDictForRepository(PhabricatorRepository $repository)
{
return array('name' => $repository->getName(), 'phid' => $repository->getPHID(), 'callsign' => $repository->getCallsign(), 'vcs' => $repository->getVersionControlSystem(), 'uri' => PhabricatorEnv::getProductionURI($repository->getURI()), 'remoteURI' => (string) $repository->getPublicRemoteURI(), 'tracking' => $repository->getDetail('tracking-enabled'), 'description' => $repository->getDetail('description'));
}
示例13: executeSvnGetBaseSVNLogURI
private function executeSvnGetBaseSVNLogURI(PhabricatorRepository $repository)
{
$uri = $repository->getDetail('remote-uri');
$subpath = $repository->getDetail('svn-subpath');
return $uri . $subpath;
}
示例14: resolveUpdateFuture
/**
* @task pull
*/
private function resolveUpdateFuture(PhabricatorRepository $repository, ExecFuture $future, $min_sleep)
{
$monogram = $repository->getMonogram();
$this->log(pht('Resolving update for "%s".', $monogram));
try {
list($stdout, $stderr) = $future->resolvex();
} catch (Exception $ex) {
$proxy = new PhutilProxyException(pht('Error while updating the "%s" repository.', $repository->getMonogram()), $ex);
phlog($proxy);
return time() + $min_sleep;
}
if (strlen($stderr)) {
$stderr_msg = pht('Unexpected output while updating repository "%s": %s', $monogram, $stderr);
phlog($stderr_msg);
}
// For now, continue respecting this deprecated setting for raising the
// minimum pull frequency.
// TODO: Remove this some day once this code has been completely stable
// for a while.
$sleep_for = (int) $repository->getDetail('pull-frequency');
$min_sleep = max($sleep_for, $min_sleep);
$smart_wait = $repository->loadUpdateInterval($min_sleep);
$this->log(pht('Based on activity in repository "%s", considering a wait of %s ' . 'seconds before update.', $repository->getMonogram(), new PhutilNumber($smart_wait)));
return time() + $smart_wait;
}
示例15: getAbsoluteRepositoryPath
public function getAbsoluteRepositoryPath(PhabricatorRepository $repository, DifferentialDiff $diff = null)
{
$base = '/';
if ($diff && $diff->getSourceControlPath()) {
$base = id(new PhutilURI($diff->getSourceControlPath()))->getPath();
}
$path = $this->getFilename();
$path = rtrim($base, '/') . '/' . ltrim($path, '/');
$vcs = $repository->getVersionControlSystem();
if ($vcs == PhabricatorRepositoryType::REPOSITORY_TYPE_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;
}