public function processRequest()
 {
     $request = $this->getRequest();
     $repository_phid = $request->getStr('repositoryPHID');
     $repository = id(new PhabricatorRepository())->loadOneWhere('phid = %s', $repository_phid);
     if (!$repository) {
         return new Aphront400Response();
     }
     $query_path = $request->getStr('q');
     if (preg_match('@/$@', $query_path)) {
         $query_dir = $query_path;
     } else {
         $query_dir = dirname($query_path) . '/';
     }
     $query_dir = ltrim($query_dir, '/');
     $drequest = DiffusionRequest::newFromDictionary(array('repository' => $repository, 'path' => $query_dir));
     $browse_query = DiffusionBrowseQuery::newFromDiffusionRequest($drequest);
     $paths = $browse_query->loadPaths();
     $output = array();
     foreach ($paths as $path) {
         $full_path = $query_dir . $path->getPath();
         if ($path->getFileType() == DifferentialChangeType::FILE_DIRECTORY) {
             $full_path .= '/';
         }
         $output[] = array('/' . $full_path, null, substr(md5($full_path), 0, 7));
     }
     return id(new AphrontAjaxResponse())->setContent($output);
 }
 public function willProcessRequest(array $data)
 {
     // This controller doesn't use blob/path stuff, just pass the dictionary
     // in directly instead of using the AphrontRequest parsing mechanism.
     $drequest = DiffusionRequest::newFromDictionary($data);
     $this->diffusionRequest = $drequest;
 }
 protected function processDiffusionRequest(AphrontRequest $request)
 {
     $repository_phid = $request->getStr('repositoryPHID');
     $repository = id(new PhabricatorRepositoryQuery())->setViewer($request->getUser())->withPHIDs(array($repository_phid))->executeOne();
     if (!$repository) {
         return new Aphront400Response();
     }
     $query_path = $request->getStr('q');
     if (preg_match('@/$@', $query_path)) {
         $query_dir = $query_path;
     } else {
         $query_dir = dirname($query_path) . '/';
     }
     $query_dir = ltrim($query_dir, '/');
     $drequest = DiffusionRequest::newFromDictionary(array('user' => $request->getUser(), 'repository' => $repository, 'path' => $query_dir));
     $this->setDiffusionRequest($drequest);
     $browse_results = DiffusionBrowseResultSet::newFromConduit($this->callConduitWithDiffusionRequest('diffusion.browsequery', array('path' => $drequest->getPath(), 'commit' => $drequest->getCommit())));
     $paths = $browse_results->getPaths();
     $output = array();
     foreach ($paths as $path) {
         $full_path = $query_dir . $path->getPath();
         if ($path->getFileType() == DifferentialChangeType::FILE_DIRECTORY) {
             $full_path .= '/';
         }
         $output[] = array('/' . $full_path, null, substr(md5($full_path), 0, 7));
     }
     return id(new AphrontAjaxResponse())->setContent($output);
 }
 private static function loadDiffusionChangesForCommit($commit)
 {
     $repository = id(new PhabricatorRepository())->load($commit->getRepositoryID());
     $data = array('user' => PhabricatorUser::getOmnipotentUser(), 'initFromConduit' => false, 'repository' => $repository, 'commit' => $commit->getCommitIdentifier());
     $drequest = DiffusionRequest::newFromDictionary($data);
     $change_query = DiffusionPathChangeQuery::newFromDiffusionRequest($drequest);
     return $change_query->loadChanges();
 }
 public function getURI()
 {
     if ($this->isExternal) {
         return $this->externalURI;
     }
     $request = DiffusionRequest::newFromDictionary(array('user' => PhabricatorUser::getOmnipotentUser(), 'repository' => $this->getRepository()));
     return $request->generateURI(array('action' => 'browse', 'path' => $this->getPath(), 'line' => $this->getLineNumber()));
 }
 protected final function parseCommit(PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit)
 {
     $viewer = PhabricatorUser::getOmnipotentUser();
     $refs_raw = DiffusionQuery::callConduitWithDiffusionRequest($viewer, DiffusionRequest::newFromDictionary(array('repository' => $repository, 'user' => $viewer)), 'diffusion.querycommits', array('repositoryPHID' => $repository->getPHID(), 'phids' => array($commit->getPHID()), 'bypassCache' => true, 'needMessages' => true));
     if (empty($refs_raw['data'])) {
         throw new Exception(pht('Unable to retrieve details for commit "%s"!', $commit->getPHID()));
     }
     $ref = DiffusionCommitRef::newFromConduitResult(head($refs_raw['data']));
     $this->parseCommitWithRef($repository, $commit, $ref);
 }
 public function fromPartial($partial_string)
 {
     $this->objectPHID = null;
     // Look for diffs
     $matches = array();
     if (preg_match('/^D([1-9]\\d*)$/', $partial_string, $matches)) {
         $diff_id = $matches[1];
         // TOOD: (T603) This is all slated for annihilation.
         $diff_rev = id(new DifferentialRevision())->load($diff_id);
         if (!$diff_rev) {
             throw new ReleephCommitFinderException("{$partial_string} does not refer to an existing diff.");
         }
         $commit_phids = $diff_rev->loadCommitPHIDs();
         if (!$commit_phids) {
             throw new ReleephCommitFinderException("{$partial_string} has no commits associated with it yet.");
         }
         $this->objectPHID = $diff_rev->getPHID();
         $commits = id(new PhabricatorRepositoryCommit())->loadAllWhere('phid IN (%Ls) ORDER BY epoch ASC', $commit_phids);
         return head($commits);
     }
     // Look for a raw commit number, or r<callsign><commit-number>.
     $repository = $this->releephProject->getRepository();
     $dr_data = null;
     $matches = array();
     if (preg_match('/^r(?P<callsign>[A-Z]+)(?P<commit>\\w+)$/', $partial_string, $matches)) {
         $callsign = $matches['callsign'];
         if ($callsign != $repository->getCallsign()) {
             throw new ReleephCommitFinderException(sprintf('%s is in a different repository to this Releeph project (%s).', $partial_string, $repository->getCallsign()));
         } else {
             $dr_data = $matches;
         }
     } else {
         $dr_data = array('callsign' => $repository->getCallsign(), 'commit' => $partial_string);
     }
     try {
         $dr_data['user'] = $this->getUser();
         $dr = DiffusionRequest::newFromDictionary($dr_data);
     } catch (Exception $ex) {
         $message = "No commit matches {$partial_string}: " . $ex->getMessage();
         throw new ReleephCommitFinderException($message);
     }
     $phabricator_repository_commit = $dr->loadCommit();
     if (!$phabricator_repository_commit) {
         throw new ReleephCommitFinderException("The commit {$partial_string} doesn't exist in this repository.");
     }
     // When requesting a single commit, if it has an associated review we
     // imply the review was requested instead. This is always correct for now
     // and consistent with the older behavior, although it might not be the
     // right rule in the future.
     $phids = PhabricatorEdgeQuery::loadDestinationPHIDs($phabricator_repository_commit->getPHID(), PhabricatorEdgeConfig::TYPE_COMMIT_HAS_DREV);
     if ($phids) {
         $this->objectPHID = head($phids);
     }
     return $phabricator_repository_commit;
 }
 public function fromPartial($partial_string)
 {
     $this->objectPHID = null;
     // Look for diffs
     $matches = array();
     if (preg_match('/^D([1-9]\\d*)$/', $partial_string, $matches)) {
         $diff_id = $matches[1];
         $diff_rev = id(new DifferentialRevisionQuery())->setViewer($this->getUser())->withIDs(array($diff_id))->needCommitPHIDs(true)->executeOne();
         if (!$diff_rev) {
             throw new ReleephCommitFinderException(pht('%s does not refer to an existing diff.', $partial_string));
         }
         $commit_phids = $diff_rev->getCommitPHIDs();
         if (!$commit_phids) {
             throw new ReleephCommitFinderException(pht('%s has no commits associated with it yet.', $partial_string));
         }
         $this->objectPHID = $diff_rev->getPHID();
         $commits = id(new DiffusionCommitQuery())->setViewer($this->getUser())->withPHIDs($commit_phids)->execute();
         $commits = msort($commits, 'getEpoch');
         return head($commits);
     }
     // Look for a raw commit number, or r<callsign><commit-number>.
     $repository = $this->releephProject->getRepository();
     $dr_data = null;
     $matches = array();
     if (preg_match('/^r(?P<callsign>[A-Z]+)(?P<commit>\\w+)$/', $partial_string, $matches)) {
         $callsign = $matches['callsign'];
         if ($callsign != $repository->getCallsign()) {
             throw new ReleephCommitFinderException(pht('%s is in a different repository to this Releeph project (%s).', $partial_string, $repository->getCallsign()));
         } else {
             $dr_data = $matches;
         }
     } else {
         $dr_data = array('callsign' => $repository->getCallsign(), 'commit' => $partial_string);
     }
     try {
         $dr_data['user'] = $this->getUser();
         $dr = DiffusionRequest::newFromDictionary($dr_data);
     } catch (Exception $ex) {
         $message = pht('No commit matches %s: %s', $partial_string, $ex->getMessage());
         throw new ReleephCommitFinderException($message);
     }
     $phabricator_repository_commit = $dr->loadCommit();
     if (!$phabricator_repository_commit) {
         throw new ReleephCommitFinderException(pht("The commit %s doesn't exist in this repository.", $partial_string));
     }
     // When requesting a single commit, if it has an associated review we
     // imply the review was requested instead. This is always correct for now
     // and consistent with the older behavior, although it might not be the
     // right rule in the future.
     $phids = PhabricatorEdgeQuery::loadDestinationPHIDs($phabricator_repository_commit->getPHID(), DiffusionCommitHasRevisionEdgeType::EDGECONST);
     if ($phids) {
         $this->objectPHID = head($phids);
     }
     return $phabricator_repository_commit;
 }
 protected function execute(ConduitAPIRequest $request)
 {
     $drequest = DiffusionRequest::newFromDictionary(array('callsign' => $request->getValue('callsign'), 'path' => $request->getValue('path')));
     $history = DiffusionHistoryQuery::newFromDiffusionRequest($drequest)->setLimit(self::RESULT_LIMIT)->needDirectChanges(true)->needChildChanges(true)->loadHistory();
     $raw_commit_identifiers = mpull($history, 'getCommitIdentifier');
     $result = array();
     foreach ($raw_commit_identifiers as $id) {
         $result[] = 'r' . $request->getValue('callsign') . $id;
     }
     return $result;
 }
 public function getURI()
 {
     if (!$this->repository) {
         // This symbol is in the index, but we don't know which Repository it's
         // part of. Usually this means the Arcanist Project hasn't been linked
         // to a Repository. We can't generate a URI, so just fail.
         return null;
     }
     $request = DiffusionRequest::newFromDictionary(array('user' => PhabricatorUser::getOmnipotentUser(), 'repository' => $this->getRepository()));
     return $request->generateURI(array('action' => 'browse', 'path' => $this->getPath(), 'line' => $this->getLineNumber()));
 }
 private function loadContext(array $options)
 {
     $request = $this->getRequest();
     $viewer = $this->getViewer();
     $identifier = $this->getRepositoryIdentifierFromRequest($request);
     $params = $options + array('repository' => $identifier, 'user' => $viewer, 'blob' => $this->getDiffusionBlobFromRequest($request), 'commit' => $request->getURIData('commit'), 'path' => $request->getURIData('path'), 'line' => $request->getURIData('line'), 'branch' => $request->getURIData('branch'), 'lint' => $request->getStr('lint'));
     $drequest = DiffusionRequest::newFromDictionary($params);
     if (!$drequest) {
         return new Aphront404Response();
     }
     $this->diffusionRequest = $drequest;
     return null;
 }
 protected function execute(ConduitAPIRequest $request)
 {
     $drequest = DiffusionRequest::newFromDictionary(array('user' => $request->getUser(), 'callsign' => $request->getValue('callsign'), 'path' => $request->getValue('path'), 'branch' => $request->getValue('branch')));
     $limit = nonempty($request->getValue('limit'), self::DEFAULT_LIMIT);
     $history_result = DiffusionQuery::callConduitWithDiffusionRequest($request->getUser(), $drequest, 'diffusion.historyquery', array('commit' => $drequest->getCommit(), 'path' => $drequest->getPath(), 'offset' => 0, 'limit' => $limit, 'needDirectChanges' => true, 'needChildChanges' => true));
     $history = DiffusionPathChange::newFromConduit($history_result['pathChanges']);
     $raw_commit_identifiers = mpull($history, 'getCommitIdentifier');
     $result = array();
     foreach ($raw_commit_identifiers as $id) {
         $result[] = 'r' . $request->getValue('callsign') . $id;
     }
     return $result;
 }
 protected final function parseCommit(PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit)
 {
     if (!$this->shouldSkipImportStep()) {
         $viewer = PhabricatorUser::getOmnipotentUser();
         $refs_raw = DiffusionQuery::callConduitWithDiffusionRequest($viewer, DiffusionRequest::newFromDictionary(array('repository' => $repository, 'user' => $viewer)), 'diffusion.querycommits', array('repositoryPHID' => $repository->getPHID(), 'phids' => array($commit->getPHID()), 'bypassCache' => true, 'needMessages' => true));
         if (empty($refs_raw['data'])) {
             throw new Exception(pht('Unable to retrieve details for commit "%s"!', $commit->getPHID()));
         }
         $ref = DiffusionCommitRef::newFromConduitResult(head($refs_raw['data']));
         $this->updateCommitData($ref);
     }
     if ($this->shouldQueueFollowupTasks()) {
         $this->queueTask($this->getFollowupTaskClass(), array('commitID' => $commit->getID()), array('priority' => PhabricatorWorker::PRIORITY_DEFAULT));
     }
 }
 public static function loadAffectedPaths(PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit, PhabricatorUser $user)
 {
     $drequest = DiffusionRequest::newFromDictionary(array('user' => $user, 'repository' => $repository, 'commit' => $commit->getCommitIdentifier()));
     $path_query = DiffusionPathChangeQuery::newFromDiffusionRequest($drequest);
     $paths = $path_query->loadChanges();
     $result = array();
     foreach ($paths as $path) {
         $basic_path = '/' . $path->getPath();
         if ($path->getFileType() == DifferentialChangeType::FILE_DIRECTORY) {
             $basic_path = rtrim($basic_path, '/') . '/';
         }
         $result[] = $basic_path;
     }
     return $result;
 }
 public function renderResultsList(array $branches, PhabricatorSavedQuery $saved)
 {
     assert_instances_of($branches, 'ReleephBranch');
     $viewer = $this->getRequest()->getUser();
     $products = mpull($branches, 'getProduct');
     $repo_phids = mpull($products, 'getRepositoryPHID');
     $repos = id(new PhabricatorRepositoryQuery())->setViewer($viewer)->withPHIDs($repo_phids)->execute();
     $repos = mpull($repos, null, 'getPHID');
     $phids = mpull($branches, 'getCreatedByUserPHID');
     $this->loadHandles($phids);
     $requests = array();
     if ($branches) {
         $requests = id(new ReleephRequestQuery())->setViewer($viewer)->withBranchIDs(mpull($branches, 'getID'))->withStatus(ReleephRequestQuery::STATUS_OPEN)->execute();
         $requests = mgroup($requests, 'getBranchID');
     }
     $list = id(new PHUIObjectItemListView())->setUser($viewer);
     foreach ($branches as $branch) {
         $diffusion_href = null;
         $repo = idx($repos, $branch->getProduct()->getRepositoryPHID());
         if ($repo) {
             $drequest = DiffusionRequest::newFromDictionary(array('user' => $viewer, 'repository' => $repo));
             $diffusion_href = $drequest->generateURI(array('action' => 'branch', 'branch' => $branch->getName()));
         }
         $branch_link = $branch->getName();
         if ($diffusion_href) {
             $branch_link = phutil_tag('a', array('href' => $diffusion_href), $branch_link);
         }
         $item = id(new PHUIObjectItemView())->setHeader($branch->getDisplayName())->setHref($this->getApplicationURI('branch/' . $branch->getID() . '/'))->addAttribute($branch_link);
         if (!$branch->getIsActive()) {
             $item->setDisabled(true);
         }
         $commit = $branch->getCutPointCommit();
         if ($commit) {
             $item->addIcon('none', phabricator_datetime($commit->getEpoch(), $viewer));
         }
         $open_count = count(idx($requests, $branch->getID(), array()));
         if ($open_count) {
             $item->setBarColor('orange');
             $item->addIcon('fa-code-fork', pht('%d Open Pull Request(s)', new PhutilNumber($open_count)));
         }
         $list->addItem($item);
     }
     return $list;
 }
 private function loadRawPatchText(PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit)
 {
     $drequest = DiffusionRequest::newFromDictionary(array('user' => PhabricatorUser::getOmnipotentUser(), 'repository' => $repository, 'commit' => $commit->getCommitIdentifier()));
     $raw_query = DiffusionRawDiffQuery::newFromDiffusionRequest($drequest);
     $raw_query->setLinesOfContext(3);
     $time_key = 'metamta.diffusion.time-limit';
     $byte_key = 'metamta.diffusion.byte-limit';
     $time_limit = PhabricatorEnv::getEnvConfig($time_key);
     $byte_limit = PhabricatorEnv::getEnvConfig($byte_key);
     if ($time_limit) {
         $raw_query->setTimeout($time_limit);
     }
     $raw_diff = $raw_query->loadRawDiff();
     $size = strlen($raw_diff);
     if ($byte_limit && $size > $byte_limit) {
         $pretty_size = phutil_format_bytes($size);
         $pretty_limit = phutil_format_bytes($byte_limit);
         throw new Exception(pht('Patch size of %s exceeds configured byte size limit (%s) of %s.', $pretty_size, $byte_key, $pretty_limit));
     }
     return $raw_diff;
 }
 public function execute(PhutilArgumentParser $args)
 {
     $commits = $this->loadCommits($args, 'commits');
     if (!$commits) {
         throw new PhutilArgumentUsageException(pht('Specify one or more commits to resolve users for.'));
     }
     $console = PhutilConsole::getConsole();
     foreach ($commits as $commit) {
         $repo = $commit->getRepository();
         $name = $repo->formatCommitName($commit->getCommitIdentifier());
         $console->writeOut("%s\n", pht('Examining commit %s...', $name));
         $refs_raw = DiffusionQuery::callConduitWithDiffusionRequest($this->getViewer(), DiffusionRequest::newFromDictionary(array('repository' => $repo, 'user' => $this->getViewer())), 'diffusion.querycommits', array('repositoryPHID' => $repo->getPHID(), 'phids' => array($commit->getPHID()), 'bypassCache' => true));
         if (empty($refs_raw['data'])) {
             throw new Exception(pht('Unable to retrieve details for commit "%s"!', $commit->getPHID()));
         }
         $ref = DiffusionCommitRef::newFromConduitResult(head($refs_raw['data']));
         $author = $ref->getAuthor();
         $console->writeOut("%s\n", pht('Raw author string: %s', coalesce($author, 'null')));
         if ($author !== null) {
             $handle = $this->resolveUser($commit, $author);
             if ($handle) {
                 $console->writeOut("%s\n", pht('Phabricator user: %s', $handle->getFullName()));
             } else {
                 $console->writeOut("%s\n", pht('Unable to resolve a corresponding Phabricator user.'));
             }
         }
         $committer = $ref->getCommitter();
         $console->writeOut("%s\n", pht('Raw committer string: %s', coalesce($committer, 'null')));
         if ($committer !== null) {
             $handle = $this->resolveUser($commit, $committer);
             if ($handle) {
                 $console->writeOut("%s\n", pht('Phabricator user: %s', $handle->getFullName()));
             } else {
                 $console->writeOut("%s\n", pht('Unable to resolve a corresponding Phabricator user.'));
             }
         }
     }
     return 0;
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $repository_phid = $request->getStr('repositoryPHID');
     $repository = id(new PhabricatorRepository())->loadOneWhere('phid = %s', $repository_phid);
     if (!$repository) {
         return new Aphront400Response();
     }
     $path = $request->getStr('path');
     $path = ltrim($path, '/');
     $drequest = DiffusionRequest::newFromDictionary(array('repository' => $repository, 'path' => $path));
     $browse_query = DiffusionBrowseQuery::newFromDiffusionRequest($drequest);
     $browse_query->needValidityOnly(true);
     $valid = $browse_query->loadPaths();
     if (!$valid) {
         switch ($browse_query->getReasonForEmptyResultSet()) {
             case DiffusionBrowseQuery::REASON_IS_FILE:
                 $valid = true;
                 break;
             case DiffusionBrowseQuery::REASON_IS_EMPTY:
                 $valid = true;
                 break;
         }
     }
     $output = array('valid' => (bool) $valid);
     if (!$valid) {
         $branch = $drequest->getBranch();
         if ($branch) {
             $message = 'Not found in ' . $branch;
         } else {
             $message = 'Not found at HEAD';
         }
     } else {
         $message = 'OK';
     }
     $output['message'] = $message;
     return id(new AphrontAjaxResponse())->setContent($output);
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $repository_phid = $request->getStr('repositoryPHID');
     $repository = id(new PhabricatorRepositoryQuery())->setViewer($request->getUser())->withPHIDs(array($repository_phid))->executeOne();
     if (!$repository) {
         return new Aphront400Response();
     }
     $path = $request->getStr('path');
     $path = ltrim($path, '/');
     $drequest = DiffusionRequest::newFromDictionary(array('user' => $request->getUser(), 'repository' => $repository, 'path' => $path));
     $this->setDiffusionRequest($drequest);
     $browse_results = DiffusionBrowseResultSet::newFromConduit($this->callConduitWithDiffusionRequest('diffusion.browsequery', array('path' => $drequest->getPath(), 'commit' => $drequest->getCommit(), 'needValidityOnly' => true)));
     $valid = $browse_results->isValidResults();
     if (!$valid) {
         switch ($browse_results->getReasonForEmptyResultSet()) {
             case DiffusionBrowseResultSet::REASON_IS_FILE:
                 $valid = true;
                 break;
             case DiffusionBrowseResultSet::REASON_IS_EMPTY:
                 $valid = true;
                 break;
         }
     }
     $output = array('valid' => (bool) $valid);
     if (!$valid) {
         $branch = $drequest->getBranch();
         if ($branch) {
             $message = pht('Not found in %s', $branch);
         } else {
             $message = pht('Not found at HEAD');
         }
     } else {
         $message = pht('OK');
     }
     $output['message'] = $message;
     return id(new AphrontAjaxResponse())->setContent($output);
 }
 /**
  * This method is final because most queries will need to construct a
  * @{class:DiffusionRequest} and use it. Consolidating this codepath and
  * enforcing @{method:getDiffusionRequest} works when we need it is good.
  *
  * @{method:getResult} should be overridden by subclasses as necessary, e.g.
  * there is a common operation across all version control systems that
  * should occur after @{method:getResult}, like formatting a timestamp.
  */
 protected final function execute(ConduitAPIRequest $request)
 {
     $drequest = DiffusionRequest::newFromDictionary(array('user' => $request->getUser(), 'callsign' => $request->getValue('callsign'), 'branch' => $request->getValue('branch'), 'path' => $request->getValue('path'), 'commit' => $request->getValue('commit')));
     // Figure out whether we're going to handle this request on this device,
     // or proxy it to another node in the cluster.
     // If this is a cluster request and we need to proxy, we'll explode here
     // to prevent infinite recursion.
     $is_cluster_request = $request->getIsClusterRequest();
     $repository = $drequest->getRepository();
     $client = $repository->newConduitClient($request->getUser(), $is_cluster_request);
     if ($client) {
         // We're proxying, so just make an intracluster call.
         return $client->callMethodSynchronous($this->getAPIMethodName(), $request->getAllParameters());
     } else {
         // We pass this flag on to prevent proxying of any other Conduit calls
         // which we need to make in order to respond to this one. Although we
         // could safely proxy them, we take a big performance hit in the common
         // case, and doing more proxying wouldn't exercise any additional code so
         // we wouldn't gain a testability/predictability benefit.
         $drequest->setIsClusterRequest($is_cluster_request);
         $this->setDiffusionRequest($drequest);
         return $this->getResult($request);
     }
 }
 private function loadContext(array $options)
 {
     $request = $this->getRequest();
     $viewer = $this->getViewer();
     $identifier = $this->getRepositoryIdentifierFromRequest($request);
     $params = $options + array('repository' => $identifier, 'user' => $viewer, 'blob' => $this->getDiffusionBlobFromRequest($request), 'commit' => $request->getURIData('commit'), 'path' => $request->getURIData('path'), 'line' => $request->getURIData('line'), 'branch' => $request->getURIData('branch'), 'lint' => $request->getStr('lint'));
     $drequest = DiffusionRequest::newFromDictionary($params);
     if (!$drequest) {
         return new Aphront404Response();
     }
     // If the client is making a request like "/diffusion/1/...", but the
     // repository has a different canonical path like "/diffusion/XYZ/...",
     // redirect them to the canonical path.
     $request_path = $request->getPath();
     $repository = $drequest->getRepository();
     $canonical_path = $repository->getCanonicalPath($request_path);
     if ($canonical_path !== null) {
         if ($canonical_path != $request_path) {
             return id(new AphrontRedirectResponse())->setURI($canonical_path);
         }
     }
     $this->diffusionRequest = $drequest;
     return null;
 }
 public function loadChangesetsForCommit($identifier)
 {
     $byte_limit = HeraldCommitAdapter::getEnormousByteLimit();
     $time_limit = HeraldCommitAdapter::getEnormousTimeLimit();
     $vcs = $this->getRepository()->getVersionControlSystem();
     switch ($vcs) {
         case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
         case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
             // For git and hg, we can use normal commands.
             $drequest = DiffusionRequest::newFromDictionary(array('repository' => $this->getRepository(), 'user' => $this->getViewer(), 'commit' => $identifier));
             $raw_diff = DiffusionRawDiffQuery::newFromDiffusionRequest($drequest)->setTimeout($time_limit)->setByteLimit($byte_limit)->setLinesOfContext(0)->loadRawDiff();
             break;
         case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
             // TODO: This diff has 3 lines of context, which produces slightly
             // incorrect "added file content" and "removed file content" results.
             // This may also choke on binaries, but "svnlook diff" does not support
             // the "--diff-cmd" flag.
             // For subversion, we need to use `svnlook`.
             $future = new ExecFuture('svnlook diff -t %s %s', $this->subversionTransaction, $this->subversionRepository);
             $future->setTimeout($time_limit);
             $future->setStdoutSizeLimit($byte_limit);
             $future->setStderrSizeLimit($byte_limit);
             list($raw_diff) = $future->resolvex();
             break;
         default:
             throw new Exception(pht("Unknown VCS '%s!'", $vcs));
     }
     if (strlen($raw_diff) >= $byte_limit) {
         throw new Exception(pht('The raw text of this change is enormous (larger than %d ' . 'bytes). Herald can not process it.', $byte_limit));
     }
     if (!strlen($raw_diff)) {
         // If the commit is actually empty, just return no changesets.
         return array();
     }
     $parser = new ArcanistDiffParser();
     $changes = $parser->parseDiff($raw_diff);
     $diff = DifferentialDiff::newEphemeralFromRawChanges($changes);
     return $diff->getChangesets();
 }
 protected function processDiffusionRequest(AphrontRequest $request)
 {
     $user = $request->getUser();
     // This controller doesn't use blob/path stuff, just pass the dictionary
     // in directly instead of using the AphrontRequest parsing mechanism.
     $data = $request->getURIMap();
     $data['user'] = $user;
     $drequest = DiffusionRequest::newFromDictionary($data);
     $this->diffusionRequest = $drequest;
     if ($request->getStr('diff')) {
         return $this->buildRawDiffResponse($drequest);
     }
     $repository = $drequest->getRepository();
     $callsign = $repository->getCallsign();
     $content = array();
     $commit = id(new DiffusionCommitQuery())->setViewer($request->getUser())->withRepository($repository)->withIdentifiers(array($drequest->getCommit()))->needCommitData(true)->needAuditRequests(true)->executeOne();
     $crumbs = $this->buildCrumbs(array('commit' => true));
     if (!$commit) {
         $exists = $this->callConduitWithDiffusionRequest('diffusion.existsquery', array('commit' => $drequest->getCommit()));
         if (!$exists) {
             return new Aphront404Response();
         }
         $error = id(new PHUIInfoView())->setTitle(pht('Commit Still Parsing'))->appendChild(pht('Failed to load the commit because the commit has not been ' . 'parsed yet.'));
         return $this->buildApplicationPage(array($crumbs, $error), array('title' => pht('Commit Still Parsing')));
     }
     $audit_requests = $commit->getAudits();
     $this->auditAuthorityPHIDs = PhabricatorAuditCommentEditor::loadAuditPHIDsForUser($user);
     $commit_data = $commit->getCommitData();
     $is_foreign = $commit_data->getCommitDetail('foreign-svn-stub');
     if ($is_foreign) {
         $subpath = $commit_data->getCommitDetail('svn-subpath');
         $error_panel = new PHUIInfoView();
         $error_panel->setTitle(pht('Commit Not Tracked'));
         $error_panel->setSeverity(PHUIInfoView::SEVERITY_WARNING);
         $error_panel->appendChild(pht("This Diffusion repository is configured to track only one " . "subdirectory of the entire Subversion repository, and this commit " . "didn't affect the tracked subdirectory ('%s'), so no " . "information is available.", $subpath));
         $content[] = $error_panel;
     } else {
         $engine = PhabricatorMarkupEngine::newDifferentialMarkupEngine();
         $engine->setConfig('viewer', $user);
         require_celerity_resource('phabricator-remarkup-css');
         $parents = $this->callConduitWithDiffusionRequest('diffusion.commitparentsquery', array('commit' => $drequest->getCommit()));
         if ($parents) {
             $parents = id(new DiffusionCommitQuery())->setViewer($user)->withRepository($repository)->withIdentifiers($parents)->execute();
         }
         $headsup_view = id(new PHUIHeaderView())->setHeader(nonempty($commit->getSummary(), pht('Commit Detail')));
         $headsup_actions = $this->renderHeadsupActionList($commit, $repository);
         $commit_properties = $this->loadCommitProperties($commit, $commit_data, $parents, $audit_requests);
         $property_list = id(new PHUIPropertyListView())->setHasKeyboardShortcuts(true)->setUser($user)->setObject($commit);
         foreach ($commit_properties as $key => $value) {
             $property_list->addProperty($key, $value);
         }
         $message = $commit_data->getCommitMessage();
         $revision = $commit->getCommitIdentifier();
         $message = $this->linkBugtraq($message);
         $message = $engine->markupText($message);
         $property_list->invokeWillRenderEvent();
         $property_list->setActionList($headsup_actions);
         $detail_list = new PHUIPropertyListView();
         $detail_list->addSectionHeader(pht('Description'), PHUIPropertyListView::ICON_SUMMARY);
         $detail_list->addTextContent(phutil_tag('div', array('class' => 'diffusion-commit-message phabricator-remarkup'), $message));
         $headsup_view->setTall(true);
         $object_box = id(new PHUIObjectBoxView())->setHeader($headsup_view)->addPropertyList($property_list)->addPropertyList($detail_list);
         $content[] = $object_box;
     }
     $content[] = $this->buildComments($commit);
     $hard_limit = 1000;
     if ($commit->isImported()) {
         $change_query = DiffusionPathChangeQuery::newFromDiffusionRequest($drequest);
         $change_query->setLimit($hard_limit + 1);
         $changes = $change_query->loadChanges();
     } else {
         $changes = array();
     }
     $was_limited = count($changes) > $hard_limit;
     if ($was_limited) {
         $changes = array_slice($changes, 0, $hard_limit);
     }
     $content[] = $this->buildMergesTable($commit);
     $highlighted_audits = $commit->getAuthorityAudits($user, $this->auditAuthorityPHIDs);
     $count = count($changes);
     $bad_commit = null;
     if ($count == 0) {
         $bad_commit = queryfx_one(id(new PhabricatorRepository())->establishConnection('r'), 'SELECT * FROM %T WHERE fullCommitName = %s', PhabricatorRepository::TABLE_BADCOMMIT, 'r' . $callsign . $commit->getCommitIdentifier());
     }
     $show_changesets = false;
     if ($bad_commit) {
         $content[] = $this->renderStatusMessage(pht('Bad Commit'), $bad_commit['description']);
     } else {
         if ($is_foreign) {
             // Don't render anything else.
         } else {
             if (!$commit->isImported()) {
                 $content[] = $this->renderStatusMessage(pht('Still Importing...'), pht('This commit is still importing. Changes will be visible once ' . 'the import finishes.'));
             } else {
                 if (!count($changes)) {
                     $content[] = $this->renderStatusMessage(pht('Empty Commit'), pht('This commit is empty and does not affect any paths.'));
                 } else {
                     if ($was_limited) {
                         $content[] = $this->renderStatusMessage(pht('Enormous Commit'), pht('This commit is enormous, and affects more than %d files. ' . 'Changes are not shown.', $hard_limit));
                     } else {
                         $show_changesets = true;
                         // The user has clicked "Show All Changes", and we should show all the
                         // changes inline even if there are more than the soft limit.
                         $show_all_details = $request->getBool('show_all');
                         $change_panel = new PHUIObjectBoxView();
                         $header = new PHUIHeaderView();
                         $header->setHeader(pht('Changes (%s)', new PhutilNumber($count)));
                         $change_panel->setID('toc');
                         if ($count > self::CHANGES_LIMIT && !$show_all_details) {
                             $icon = id(new PHUIIconView())->setIconFont('fa-files-o');
                             $button = id(new PHUIButtonView())->setText(pht('Show All Changes'))->setHref('?show_all=true')->setTag('a')->setIcon($icon);
                             $warning_view = id(new PHUIInfoView())->setSeverity(PHUIInfoView::SEVERITY_WARNING)->setTitle(pht('Very Large Commit'))->appendChild(pht('This commit is very large. Load each file individually.'));
                             $change_panel->setInfoView($warning_view);
                             $header->addActionLink($button);
                         }
                         $changesets = DiffusionPathChange::convertToDifferentialChangesets($user, $changes);
                         // TODO: This table and panel shouldn't really be separate, but we need
                         // to clean up the "Load All Files" interaction first.
                         $change_table = $this->buildTableOfContents($changesets);
                         $change_panel->setTable($change_table);
                         $change_panel->setHeader($header);
                         $content[] = $change_panel;
                         $vcs = $repository->getVersionControlSystem();
                         switch ($vcs) {
                             case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
                                 $vcs_supports_directory_changes = true;
                                 break;
                             case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
                             case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
                                 $vcs_supports_directory_changes = false;
                                 break;
                             default:
                                 throw new Exception(pht('Unknown VCS.'));
                         }
                         $references = array();
                         foreach ($changesets as $key => $changeset) {
                             $file_type = $changeset->getFileType();
                             if ($file_type == DifferentialChangeType::FILE_DIRECTORY) {
                                 if (!$vcs_supports_directory_changes) {
                                     unset($changesets[$key]);
                                     continue;
                                 }
                             }
                             $references[$key] = $drequest->generateURI(array('action' => 'rendering-ref', 'path' => $changeset->getFilename()));
                         }
                         // TODO: Some parts of the views still rely on properties of the
                         // DifferentialChangeset. Make the objects ephemeral to make sure we don't
                         // accidentally save them, and then set their ID to the appropriate ID for
                         // this application (the path IDs).
                         $path_ids = array_flip(mpull($changes, 'getPath'));
                         foreach ($changesets as $changeset) {
                             $changeset->makeEphemeral();
                             $changeset->setID($path_ids[$changeset->getFilename()]);
                         }
                         if ($count <= self::CHANGES_LIMIT || $show_all_details) {
                             $visible_changesets = $changesets;
                         } else {
                             $visible_changesets = array();
                             $inlines = PhabricatorAuditInlineComment::loadDraftAndPublishedComments($user, $commit->getPHID());
                             $path_ids = mpull($inlines, null, 'getPathID');
                             foreach ($changesets as $key => $changeset) {
                                 if (array_key_exists($changeset->getID(), $path_ids)) {
                                     $visible_changesets[$key] = $changeset;
                                 }
                             }
                         }
                         $change_list_title = DiffusionView::nameCommit($repository, $commit->getCommitIdentifier());
                         $change_list = new DifferentialChangesetListView();
                         $change_list->setTitle($change_list_title);
                         $change_list->setChangesets($changesets);
                         $change_list->setVisibleChangesets($visible_changesets);
                         $change_list->setRenderingReferences($references);
                         $change_list->setRenderURI('/diffusion/' . $callsign . '/diff/');
                         $change_list->setRepository($repository);
                         $change_list->setUser($user);
                         // TODO: Try to setBranch() to something reasonable here?
                         $change_list->setStandaloneURI('/diffusion/' . $callsign . '/diff/');
                         $change_list->setRawFileURIs(null, '/diffusion/' . $callsign . '/diff/?view=r');
                         $change_list->setInlineCommentControllerURI('/diffusion/inline/edit/' . phutil_escape_uri($commit->getPHID()) . '/');
                         $content[] = $change_list->render();
                     }
                 }
             }
         }
     }
     $content[] = $this->renderAddCommentPanel($commit, $audit_requests);
     $commit_id = 'r' . $callsign . $commit->getCommitIdentifier();
     $short_name = DiffusionView::nameCommit($repository, $commit->getCommitIdentifier());
     $prefs = $user->loadPreferences();
     $pref_filetree = PhabricatorUserPreferences::PREFERENCE_DIFF_FILETREE;
     $pref_collapse = PhabricatorUserPreferences::PREFERENCE_NAV_COLLAPSED;
     $show_filetree = $prefs->getPreference($pref_filetree);
     $collapsed = $prefs->getPreference($pref_collapse);
     if ($show_changesets && $show_filetree) {
         $nav = id(new DifferentialChangesetFileTreeSideNavBuilder())->setTitle($short_name)->setBaseURI(new PhutilURI('/' . $commit_id))->build($changesets)->setCrumbs($crumbs)->setCollapsed((bool) $collapsed)->appendChild($content);
         $content = $nav;
     } else {
         $content = array($crumbs, $content);
     }
     return $this->buildApplicationPage($content, array('title' => $commit_id, 'pageObjects' => array($commit->getPHID())));
 }
 public function willProcessRequest(array $data)
 {
     $this->diffusionRequest = DiffusionRequest::newFromDictionary($data);
 }
 private function isCommitOnBranch(PhabricatorRepository $repo, PhabricatorRepositoryCommit $commit, ReleephBranch $releeph_branch)
 {
     switch ($repo->getVersionControlSystem()) {
         case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
             list($output) = $repo->execxLocalCommand('branch --all --no-color --contains %s', $commit->getCommitIdentifier());
             $remote_prefix = 'remotes/origin/';
             $branches = array();
             foreach (array_filter(explode("\n", $output)) as $line) {
                 $tokens = explode(' ', $line);
                 $ref = last($tokens);
                 if (strncmp($ref, $remote_prefix, strlen($remote_prefix)) === 0) {
                     $branch = substr($ref, strlen($remote_prefix));
                     $branches[$branch] = $branch;
                 }
             }
             return idx($branches, $releeph_branch->getName());
             break;
         case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
             $change_query = DiffusionPathChangeQuery::newFromDiffusionRequest(DiffusionRequest::newFromDictionary(array('user' => $this->getUser(), 'repository' => $repo, 'commit' => $commit->getCommitIdentifier())));
             $path_changes = $change_query->loadChanges();
             $commit_paths = mpull($path_changes, 'getPath');
             $branch_path = $releeph_branch->getName();
             $in_branch = array();
             $ex_branch = array();
             foreach ($commit_paths as $path) {
                 if (strncmp($path, $branch_path, strlen($branch_path)) === 0) {
                     $in_branch[] = $path;
                 } else {
                     $ex_branch[] = $path;
                 }
             }
             if ($in_branch && $ex_branch) {
                 $error = pht('CONFUSION: commit %s in %s contains %d path change(s) that were ' . 'part of a Releeph branch, but also has %d path change(s) not ' . 'part of a Releeph branch!', $commit->getCommitIdentifier(), $repo->getCallsign(), count($in_branch), count($ex_branch));
                 phlog($error);
             }
             return !empty($in_branch);
             break;
     }
 }
 private function loadChangedByCommit(DifferentialDiff $diff)
 {
     $repository = $this->repository;
     $vs_changesets = array();
     $vs_diff = id(new DifferentialDiff())->loadOneWhere('revisionID = %d AND creationMethod != %s ORDER BY id DESC LIMIT 1', $diff->getRevisionID(), 'commit');
     foreach ($vs_diff->loadChangesets() as $changeset) {
         $path = $changeset->getAbsoluteRepositoryPath($repository, $vs_diff);
         $path = ltrim($path, '/');
         $vs_changesets[$path] = $changeset;
     }
     $changesets = array();
     foreach ($diff->getChangesets() as $changeset) {
         $path = $changeset->getAbsoluteRepositoryPath($repository, $diff);
         $path = ltrim($path, '/');
         $changesets[$path] = $changeset;
     }
     if (array_fill_keys(array_keys($changesets), true) != array_fill_keys(array_keys($vs_changesets), true)) {
         return $vs_diff;
     }
     $hunks = id(new DifferentialHunk())->loadAllWhere('changesetID IN (%Ld)', mpull($vs_changesets, 'getID'));
     $hunks = mgroup($hunks, 'getChangesetID');
     foreach ($vs_changesets as $changeset) {
         $changeset->attachHunks(idx($hunks, $changeset->getID(), array()));
     }
     $file_phids = array();
     foreach ($vs_changesets as $changeset) {
         $metadata = $changeset->getMetadata();
         $file_phid = idx($metadata, 'new:binary-phid');
         if ($file_phid) {
             $file_phids[$file_phid] = $file_phid;
         }
     }
     $files = array();
     if ($file_phids) {
         $files = id(new PhabricatorFile())->loadAllWhere('phid IN (%Ls)', $file_phids);
         $files = mpull($files, null, 'getPHID');
     }
     foreach ($changesets as $path => $changeset) {
         $vs_changeset = $vs_changesets[$path];
         $file_phid = idx($vs_changeset->getMetadata(), 'new:binary-phid');
         if ($file_phid) {
             if (!isset($files[$file_phid])) {
                 return $vs_diff;
             }
             $drequest = DiffusionRequest::newFromDictionary(array('repository' => $this->repository, 'commit' => $this->commit->getCommitIdentifier(), 'path' => $path));
             $corpus = DiffusionFileContentQuery::newFromDiffusionRequest($drequest)->loadFileContent()->getCorpus();
             if ($files[$file_phid]->loadFileData() != $corpus) {
                 return $vs_diff;
             }
         } else {
             $context = implode("\n", $changeset->makeChangesWithContext());
             $vs_context = implode("\n", $vs_changeset->makeChangesWithContext());
             // We couldn't just compare $context and $vs_context because following
             // diffs will be considered different:
             //
             //   -(empty line)
             //   -echo 'test';
             //    (empty line)
             //
             //    (empty line)
             //   -echo "test";
             //   -(empty line)
             $hunk = id(new DifferentialHunk())->setChanges($context);
             $vs_hunk = id(new DifferentialHunk())->setChanges($vs_context);
             if ($hunk->makeOldFile() != $vs_hunk->makeOldFile() || $hunk->makeNewFile() != $vs_hunk->makeNewFile()) {
                 return $vs_diff;
             }
         }
     }
     return null;
 }
 protected function getResult(ConduitAPIRequest $request)
 {
     $drequest = $this->getDiffusionRequest();
     $path_dicts = $request->getValue('paths', array());
     $paths = array();
     foreach ($path_dicts as $dict) {
         $paths[] = DiffusionRepositoryPath::newFromDictionary($dict);
     }
     $best = -1;
     $readme = '';
     $best_render_type = 'plain';
     foreach ($paths as $result_path) {
         $file_type = $result_path->getFileType();
         if ($file_type != ArcanistDiffChangeType::FILE_NORMAL && $file_type != ArcanistDiffChangeType::FILE_TEXT) {
             // Skip directories, etc.
             continue;
         }
         $path = strtolower($result_path->getPath());
         if ($path === 'readme') {
             $path .= '.remarkup';
         }
         if (strncmp($path, 'readme.', 7) !== 0) {
             continue;
         }
         $priority = 0;
         switch (substr($path, 7)) {
             case 'remarkup':
                 $priority = 100;
                 $render_type = 'remarkup';
                 break;
             case 'rainbow':
                 $priority = 90;
                 $render_type = 'rainbow';
                 break;
             case 'md':
                 $priority = 50;
                 $render_type = 'remarkup';
                 break;
             case 'txt':
                 $priority = 10;
                 $render_type = 'plain';
                 break;
             default:
                 $priority = 0;
                 $render_type = 'plain';
                 break;
         }
         if ($priority > $best) {
             $best = $priority;
             $readme = $result_path;
             $best_render_type = $render_type;
         }
     }
     if (!$readme) {
         return '';
     }
     $readme_request = DiffusionRequest::newFromDictionary(array('user' => $request->getUser(), 'repository' => $drequest->getRepository(), 'commit' => $drequest->getStableCommit(), 'path' => $readme->getFullPath()));
     $file_content = DiffusionFileContent::newFromConduit(DiffusionQuery::callConduitWithDiffusionRequest($request->getUser(), $readme_request, 'diffusion.filecontentquery', array('commit' => $drequest->getStableCommit(), 'path' => $readme->getFullPath(), 'needsBlame' => false)));
     $readme_content = $file_content->getCorpus();
     switch ($best_render_type) {
         case 'plain':
             $readme_content = phutil_escape_html_newlines($readme_content);
             $class = null;
             break;
         case 'rainbow':
             $highlighter = new PhutilRainbowSyntaxHighlighter();
             $readme_content = $highlighter->getHighlightFuture($readme_content)->resolve();
             $readme_content = phutil_escape_html_newlines($readme_content);
             require_celerity_resource('syntax-highlighting-css');
             $class = 'remarkup-code';
             break;
         case 'remarkup':
             // TODO: This is sketchy, but make sure we hit the markup cache.
             $markup_object = id(new PhabricatorMarkupOneOff())->setEngineRuleset('diffusion-readme')->setContent($readme_content);
             $markup_field = 'default';
             $readme_content = id(new PhabricatorMarkupEngine())->setViewer($request->getUser())->addObject($markup_object, $markup_field)->process()->getOutput($markup_object, $markup_field);
             $engine = $markup_object->newMarkupEngine($markup_field);
             $toc = PhutilRemarkupHeaderBlockRule::renderTableOfContents($engine);
             if ($toc) {
                 $toc = phutil_tag_div('phabricator-remarkup-toc', array(phutil_tag_div('phabricator-remarkup-toc-header', pht('Table of Contents')), $toc));
                 $readme_content = array($toc, $readme_content);
             }
             $class = 'phabricator-remarkup';
             break;
     }
     $readme_content = phutil_tag('div', array('class' => $class), $readme_content);
     return $readme_content;
 }
 public function getDiffusionBrowseURIForPath(PhabricatorUser $user, $path, $line = null, $branch = null)
 {
     $drequest = DiffusionRequest::newFromDictionary(array('user' => $user, 'repository' => $this, 'path' => $path, 'branch' => $branch));
     return $drequest->generateURI(array('action' => 'browse', 'line' => $line));
 }
 private function blameAuthors()
 {
     $repository = id(new PhabricatorRepositoryQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withIDs(array($this->branch->getRepositoryID()))->executeOne();
     $queries = array();
     $futures = array();
     foreach ($this->blame as $path => $lines) {
         $drequest = DiffusionRequest::newFromDictionary(array('user' => PhabricatorUser::getOmnipotentUser(), 'repository' => $repository, 'branch' => $this->branch->getName(), 'path' => $path, 'commit' => $this->lintCommit));
         // TODO: Restore blame information / generally fix this workflow.
         $query = DiffusionFileContentQuery::newFromDiffusionRequest($drequest);
         $queries[$path] = $query;
         $futures[$path] = $query->getFileContentFuture();
     }
     $authors = array();
     $futures = id(new FutureIterator($futures))->limit(8);
     foreach ($futures as $path => $future) {
         $queries[$path]->loadFileContentFromFuture($future);
         list(, $rev_list, $blame_dict) = $queries[$path]->getBlameData();
         foreach (array_keys($this->blame[$path]) as $line) {
             $commit_identifier = $rev_list[$line - 1];
             $author = idx($blame_dict[$commit_identifier], 'authorPHID');
             if ($author) {
                 $authors[$author][$path][] = $line;
             }
         }
     }
     if ($authors) {
         $this->conn->openTransaction();
         foreach ($authors as $author => $paths) {
             $where = array();
             foreach ($paths as $path => $lines) {
                 $where[] = qsprintf($this->conn, '(path = %s AND line IN (%Ld))', $this->svnRoot . '/' . $path, $lines);
             }
             queryfx($this->conn, 'UPDATE %T SET authorPHID = %s WHERE %Q', PhabricatorRepository::TABLE_LINTMESSAGE, $author, implode(' OR ', $where));
         }
         $this->conn->saveTransaction();
     }
 }
 public function getDiffusionBrowseURIForPath($path)
 {
     $drequest = DiffusionRequest::newFromDictionary(array('repository' => $this, 'path' => $path));
     return $drequest->generateURI(array('action' => 'browse'));
 }