[ Index ]

PHP Cross Reference of Phabricator

title

Body

[close]

/src/applications/diffusion/conduit/ -> DiffusionHistoryQueryConduitAPIMethod.php (source)

   1  <?php
   2  
   3  final class DiffusionHistoryQueryConduitAPIMethod
   4    extends DiffusionQueryConduitAPIMethod {
   5  
   6    private $parents = array();
   7  
   8    public function getAPIMethodName() {
   9      return 'diffusion.historyquery';
  10    }
  11  
  12    public function getMethodDescription() {
  13      return 'Returns history information for a repository at a specific '.
  14        'commit and path.';
  15    }
  16  
  17    public function defineReturnType() {
  18      return 'array';
  19    }
  20  
  21    protected function defineCustomParamTypes() {
  22      return array(
  23        'commit' => 'required string',
  24        'path' => 'required string',
  25        'offset' => 'required int',
  26        'limit' => 'required int',
  27        'needDirectChanges' => 'optional bool',
  28        'needChildChanges' => 'optional bool',
  29      );
  30    }
  31  
  32    protected function getResult(ConduitAPIRequest $request) {
  33      $path_changes = parent::getResult($request);
  34  
  35      return array(
  36        'pathChanges' => mpull($path_changes, 'toDictionary'),
  37        'parents' => $this->parents,
  38      );
  39    }
  40  
  41    protected function getGitResult(ConduitAPIRequest $request) {
  42      $drequest = $this->getDiffusionRequest();
  43      $repository = $drequest->getRepository();
  44      $commit_hash = $request->getValue('commit');
  45      $path = $request->getValue('path');
  46      $offset = $request->getValue('offset');
  47      $limit = $request->getValue('limit');
  48  
  49      list($stdout) = $repository->execxLocalCommand(
  50        'log '.
  51          '--skip=%d '.
  52          '-n %d '.
  53          '--pretty=format:%s '.
  54          '%s -- %C',
  55        $offset,
  56        $limit,
  57        '%H:%P',
  58        $commit_hash,
  59        // Git omits merge commits if the path is provided, even if it is empty.
  60        (strlen($path) ? csprintf('%s', $path) : ''));
  61  
  62      $lines = explode("\n", trim($stdout));
  63      $lines = array_filter($lines);
  64      if (!$lines) {
  65        return array();
  66      }
  67  
  68      $hash_list = array();
  69      $parent_map = array();
  70      foreach ($lines as $line) {
  71        list($hash, $parents) = explode(':', $line);
  72        $hash_list[] = $hash;
  73        $parent_map[$hash] = preg_split('/\s+/', $parents);
  74      }
  75  
  76      $this->parents = $parent_map;
  77  
  78      return DiffusionQuery::loadHistoryForCommitIdentifiers(
  79        $hash_list,
  80        $drequest);
  81    }
  82  
  83    protected function getMercurialResult(ConduitAPIRequest $request) {
  84      $drequest = $this->getDiffusionRequest();
  85      $repository = $drequest->getRepository();
  86      $commit_hash = $request->getValue('commit');
  87      $path = $request->getValue('path');
  88      $offset = $request->getValue('offset');
  89      $limit = $request->getValue('limit');
  90  
  91      $path = DiffusionPathIDQuery::normalizePath($path);
  92      $path = ltrim($path, '/');
  93  
  94      // NOTE: Older versions of Mercurial give different results for these
  95      // commands (see T1268):
  96      //
  97      //   $ hg log -- ''
  98      //   $ hg log
  99      //
 100      // All versions of Mercurial give different results for these commands
 101      // (merge commits are excluded with the "." version):
 102      //
 103      //   $ hg log -- .
 104      //   $ hg log
 105      //
 106      // If we don't have a path component in the query, omit it from the command
 107      // entirely to avoid these inconsistencies.
 108  
 109      // NOTE: When viewing the history of a file, we don't use "-b", because
 110      // Mercurial stops history at the branchpoint but we're interested in all
 111      // ancestors. When viewing history of a branch, we do use "-b", and thus
 112      // stop history (this is more consistent with the Mercurial worldview of
 113      // branches).
 114  
 115      if (strlen($path)) {
 116        $path_arg = csprintf('-- %s', $path);
 117        $branch_arg = '';
 118      } else {
 119        $path_arg = '';
 120        // NOTE: --branch used to be called --only-branch; use -b for
 121        // compatibility.
 122        $branch_arg = csprintf('-b %s', $drequest->getBranch());
 123      }
 124  
 125      list($stdout) = $repository->execxLocalCommand(
 126        'log --debug --template %s --limit %d %C --rev %s %C',
 127        '{node};{parents}\\n',
 128        ($offset + $limit), // No '--skip' in Mercurial.
 129        $branch_arg,
 130        hgsprintf('reverse(ancestors(%s))', $commit_hash),
 131        $path_arg);
 132  
 133      $stdout = PhabricatorRepository::filterMercurialDebugOutput($stdout);
 134      $lines = explode("\n", trim($stdout));
 135      $lines = array_slice($lines, $offset);
 136  
 137      $hash_list = array();
 138      $parent_map = array();
 139  
 140      $last = null;
 141      foreach (array_reverse($lines) as $line) {
 142        list($hash, $parents) = explode(';', $line);
 143        $parents = trim($parents);
 144        if (!$parents) {
 145          if ($last === null) {
 146            $parent_map[$hash] = array('...');
 147          } else {
 148            $parent_map[$hash] = array($last);
 149          }
 150        } else {
 151          $parents = preg_split('/\s+/', $parents);
 152          foreach ($parents as $parent) {
 153            list($plocal, $phash) = explode(':', $parent);
 154            if (!preg_match('/^0+$/', $phash)) {
 155              $parent_map[$hash][] = $phash;
 156            }
 157          }
 158          // This may happen for the zeroth commit in repository, both hashes
 159          // are "000000000...".
 160          if (empty($parent_map[$hash])) {
 161            $parent_map[$hash] = array('...');
 162          }
 163        }
 164  
 165        // The rendering code expects the first commit to be "mainline", like
 166        // Git. Flip the order so it does the right thing.
 167        $parent_map[$hash] = array_reverse($parent_map[$hash]);
 168  
 169        $hash_list[] = $hash;
 170        $last = $hash;
 171      }
 172  
 173      $hash_list = array_reverse($hash_list);
 174      $this->parents = $parent_map;
 175  
 176      return DiffusionQuery::loadHistoryForCommitIdentifiers(
 177        $hash_list,
 178        $drequest);
 179    }
 180  
 181    protected function getSVNResult(ConduitAPIRequest $request) {
 182      $drequest = $this->getDiffusionRequest();
 183      $repository = $drequest->getRepository();
 184      $commit = $request->getValue('commit');
 185      $path = $request->getValue('path');
 186      $offset = $request->getValue('offset');
 187      $limit = $request->getValue('limit');
 188      $need_direct_changes = $request->getValue('needDirectChanges');
 189      $need_child_changes = $request->getValue('needChildChanges');
 190  
 191      $conn_r = $repository->establishConnection('r');
 192  
 193      $paths = queryfx_all(
 194        $conn_r,
 195        'SELECT id, path FROM %T WHERE pathHash IN (%Ls)',
 196        PhabricatorRepository::TABLE_PATH,
 197        array(md5('/'.trim($path, '/'))));
 198      $paths = ipull($paths, 'id', 'path');
 199      $path_id = idx($paths, '/'.trim($path, '/'));
 200  
 201      if (!$path_id) {
 202        return array();
 203      }
 204  
 205      $filter_query = '';
 206      if ($need_direct_changes) {
 207        if ($need_child_changes) {
 208          $type = DifferentialChangeType::TYPE_CHILD;
 209          $filter_query = 'AND (isDirect = 1 OR changeType = '.$type.')';
 210        } else {
 211          $filter_query = 'AND (isDirect = 1)';
 212        }
 213      }
 214  
 215      $history_data = queryfx_all(
 216        $conn_r,
 217        'SELECT * FROM %T WHERE repositoryID = %d AND pathID = %d
 218          AND commitSequence <= %d
 219          %Q
 220          ORDER BY commitSequence DESC
 221          LIMIT %d, %d',
 222        PhabricatorRepository::TABLE_PATHCHANGE,
 223        $repository->getID(),
 224        $path_id,
 225        $commit ? $commit : 0x7FFFFFFF,
 226        $filter_query,
 227        $offset,
 228        $limit);
 229  
 230      $commits = array();
 231      $commit_data = array();
 232  
 233      $commit_ids = ipull($history_data, 'commitID');
 234      if ($commit_ids) {
 235        $commits = id(new PhabricatorRepositoryCommit())->loadAllWhere(
 236          'id IN (%Ld)',
 237          $commit_ids);
 238        if ($commits) {
 239          $commit_data = id(new PhabricatorRepositoryCommitData())->loadAllWhere(
 240            'commitID in (%Ld)',
 241            $commit_ids);
 242          $commit_data = mpull($commit_data, null, 'getCommitID');
 243        }
 244      }
 245  
 246      $history = array();
 247      foreach ($history_data as $row) {
 248        $item = new DiffusionPathChange();
 249  
 250        $commit = idx($commits, $row['commitID']);
 251        if ($commit) {
 252          $item->setCommit($commit);
 253          $item->setCommitIdentifier($commit->getCommitIdentifier());
 254          $data = idx($commit_data, $commit->getID());
 255          if ($data) {
 256            $item->setCommitData($data);
 257          }
 258        }
 259  
 260        $item->setChangeType($row['changeType']);
 261        $item->setFileType($row['fileType']);
 262  
 263        $history[] = $item;
 264      }
 265  
 266      return $history;
 267    }
 268  
 269  }


Generated: Sun Nov 30 09:20:46 2014 Cross-referenced by PHPXref 0.7.1