protected function executeQuery()
 {
     $drequest = $this->getRequest();
     $repository = $drequest->getRepository();
     $path = $drequest->getPath();
     $commit_hash = $drequest->getCommit();
     $path = DiffusionPathIDQuery::normalizePath($path);
     list($stdout) = $repository->execxLocalCommand('log --template %s --limit %d --branch %s --rev %s:0 -- %s', '{node}\\n', $this->getOffset() + $this->getLimit(), $drequest->getBranch(), $commit_hash, nonempty(ltrim($path, '/'), '.'));
     $hashes = explode("\n", $stdout);
     $hashes = array_filter($hashes);
     $hashes = array_slice($hashes, $this->getOffset());
     return $this->loadHistoryForCommitIdentifiers($hashes);
 }
 protected function executeQuery()
 {
     $drequest = $this->getRequest();
     $repository = $drequest->getRepository();
     $path = $drequest->getPath();
     $commit_hash = $drequest->getStableCommitName();
     $path = DiffusionPathIDQuery::normalizePath($path);
     // NOTE: Using '' as a default path produces the correct behavior if HEAD
     // is a merge commit; using '.' does not (the merge commit is not included
     // in the log).
     $default_path = '';
     list($stdout) = $repository->execxLocalCommand('log --debug --template %s --limit %d --branch %s --rev %s:0 -- %s', '{node};{parents}\\n', $this->getOffset() + $this->getLimit(), $drequest->getBranch(), $commit_hash, nonempty(ltrim($path, '/'), $default_path));
     $lines = explode("\n", trim($stdout));
     $lines = array_slice($lines, $this->getOffset());
     $hash_list = array();
     $parent_map = array();
     $last = null;
     foreach (array_reverse($lines) as $line) {
         list($hash, $parents) = explode(';', $line);
         $parents = trim($parents);
         if (!$parents) {
             if ($last === null) {
                 $parent_map[$hash] = array('...');
             } else {
                 $parent_map[$hash] = array($last);
             }
         } else {
             $parents = preg_split('/\\s+/', $parents);
             foreach ($parents as $parent) {
                 list($plocal, $phash) = explode(':', $parent);
                 if (!preg_match('/^0+$/', $phash)) {
                     $parent_map[$hash][] = $phash;
                 }
             }
             // This may happen for the zeroth commit in repository, both hashes
             // are "000000000...".
             if (empty($parent_map[$hash])) {
                 $parent_map[$hash] = array('...');
             }
         }
         // The rendering code expects the first commit to be "mainline", like
         // Git. Flip the order so it does the right thing.
         $parent_map[$hash] = array_reverse($parent_map[$hash]);
         $hash_list[] = $hash;
         $last = $hash;
     }
     $hash_list = array_reverse($hash_list);
     $this->parents = $parent_map;
     return $this->loadHistoryForCommitIdentifiers($hash_list);
 }
Exemplo n.º 3
0
 protected final function loadHistoryForCommitIdentifiers(array $identifiers)
 {
     if (!$identifiers) {
         return array();
     }
     $drequest = $this->getRequest();
     $repository = $drequest->getRepository();
     $commits = self::loadCommitsByIdentifiers($identifiers);
     $path = $drequest->getPath();
     $conn_r = $repository->establishConnection('r');
     $path_normal = DiffusionPathIDQuery::normalizePath($path);
     $paths = queryfx_all($conn_r, 'SELECT id, path FROM %T WHERE pathHash IN (%Ls)', PhabricatorRepository::TABLE_PATH, array(md5($path_normal)));
     $paths = ipull($paths, 'id', 'path');
     $path_id = idx($paths, $path_normal);
     $path_changes = queryfx_all($conn_r, 'SELECT * FROM %T WHERE commitID IN (%Ld) AND pathID = %d', PhabricatorRepository::TABLE_PATHCHANGE, mpull($commits, 'getID'), $path_id);
     $path_changes = ipull($path_changes, null, 'commitID');
     $history = array();
     foreach ($identifiers as $identifier) {
         $item = new DiffusionPathChange();
         $item->setCommitIdentifier($identifier);
         $commit = idx($commits, $identifier);
         if ($commit) {
             $item->setCommit($commit);
             try {
                 $item->setCommitData($commit->getCommitData());
             } catch (Exception $ex) {
                 // Ignore, commit just doesn't have data.
             }
             $change = idx($path_changes, $commit->getID());
             if ($change) {
                 $item->setChangeType($change['changeType']);
                 $item->setFileType($change['fileType']);
             }
         }
         $history[] = $item;
     }
     return $history;
 }
 protected function executeQuery()
 {
     $drequest = $this->getRequest();
     $repository = $drequest->getRepository();
     $path = $drequest->getPath();
     $commit = $drequest->getCommit();
     $subpath = $repository->getDetail('svn-subpath');
     if ($subpath && strncmp($subpath, $path, strlen($subpath))) {
         // If we have a subpath and the path isn't a child of it, it (almost
         // certainly) won't exist since we don't track commits which affect
         // it. (Even if it exists, return a consistent result.)
         $this->reason = self::REASON_IS_UNTRACKED_PARENT;
         return array();
     }
     $conn_r = $repository->establishConnection('r');
     $parent_path = DiffusionPathIDQuery::getParentPath($path);
     $path_query = new DiffusionPathIDQuery(array($path, $parent_path));
     $path_map = $path_query->loadPathIDs();
     $path_id = $path_map[$path];
     $parent_path_id = $path_map[$parent_path];
     if (empty($path_id)) {
         $this->reason = self::REASON_IS_NONEXISTENT;
         return array();
     }
     if ($commit) {
         $slice_clause = 'AND svnCommit <= ' . (int) $commit;
     } else {
         $slice_clause = '';
     }
     $index = queryfx_all($conn_r, 'SELECT pathID, max(svnCommit) maxCommit FROM %T WHERE
     repositoryID = %d AND parentID = %d
     %Q GROUP BY pathID', PhabricatorRepository::TABLE_FILESYSTEM, $repository->getID(), $path_id, $slice_clause);
     if (!$index) {
         if ($path == '/') {
             $this->reason = self::REASON_IS_EMPTY;
         } else {
             // NOTE: The parent path ID is included so this query can take
             // advantage of the table's primary key; it is uniquely determined by
             // the pathID but if we don't do the lookup ourselves MySQL doesn't have
             // the information it needs to avoid a table scan.
             $reasons = queryfx_all($conn_r, 'SELECT * FROM %T WHERE repositoryID = %d
           AND parentID = %d
           AND pathID = %d
         %Q ORDER BY svnCommit DESC LIMIT 2', PhabricatorRepository::TABLE_FILESYSTEM, $repository->getID(), $parent_path_id, $path_id, $slice_clause);
             $reason = reset($reasons);
             if (!$reason) {
                 $this->reason = self::REASON_IS_NONEXISTENT;
             } else {
                 $file_type = $reason['fileType'];
                 if (empty($reason['existed'])) {
                     $this->reason = self::REASON_IS_DELETED;
                     $this->deletedAtCommit = $reason['svnCommit'];
                     if (!empty($reasons[1])) {
                         $this->existedAtCommit = $reasons[1]['svnCommit'];
                     }
                 } else {
                     if ($file_type == DifferentialChangeType::FILE_DIRECTORY) {
                         $this->reason = self::REASON_IS_EMPTY;
                     } else {
                         $this->reason = self::REASON_IS_FILE;
                     }
                 }
             }
         }
         return array();
     }
     if ($this->shouldOnlyTestValidity()) {
         return true;
     }
     $sql = array();
     foreach ($index as $row) {
         $sql[] = '(' . (int) $row['pathID'] . ', ' . (int) $row['maxCommit'] . ')';
     }
     $browse = queryfx_all($conn_r, 'SELECT *, p.path pathName
     FROM %T f JOIN %T p ON f.pathID = p.id
     WHERE repositoryID = %d
       AND parentID = %d
       AND existed = 1
     AND (pathID, svnCommit) in (%Q)
     ORDER BY pathName', PhabricatorRepository::TABLE_FILESYSTEM, PhabricatorRepository::TABLE_PATH, $repository->getID(), $path_id, implode(', ', $sql));
     $loadable_commits = array();
     foreach ($browse as $key => $file) {
         // We need to strip out directories because we don't store last-modified
         // in the filesystem table.
         if ($file['fileType'] != DifferentialChangeType::FILE_DIRECTORY) {
             $loadable_commits[] = $file['svnCommit'];
             $browse[$key]['hasCommit'] = true;
         }
     }
     $commits = array();
     $commit_data = array();
     if ($loadable_commits) {
         // NOTE: Even though these are integers, use '%Ls' because MySQL doesn't
         // use the second part of the key otherwise!
         $commits = id(new PhabricatorRepositoryCommit())->loadAllWhere('repositoryID = %d AND commitIdentifier IN (%Ls)', $repository->getID(), $loadable_commits);
         $commits = mpull($commits, null, 'getCommitIdentifier');
         if ($commits) {
             $commit_data = id(new PhabricatorRepositoryCommitData())->loadAllWhere('commitID in (%Ld)', mpull($commits, 'getID'));
             $commit_data = mpull($commit_data, null, 'getCommitID');
         } else {
             $commit_data = array();
         }
     }
     $path_normal = DiffusionPathIDQuery::normalizePath($path);
     $results = array();
     foreach ($browse as $file) {
         $full_path = $file['pathName'];
         $file_path = ltrim(substr($full_path, strlen($path_normal)), '/');
         $full_path = ltrim($full_path, '/');
         $result = new DiffusionRepositoryPath();
         $result->setPath($file_path);
         $result->setFullPath($full_path);
         //      $result->setHash($hash);
         $result->setFileType($file['fileType']);
         //      $result->setFileSize($size);
         if (!empty($file['hasCommit'])) {
             $commit = idx($commits, $file['svnCommit']);
             if ($commit) {
                 $data = idx($commit_data, $commit->getID());
                 $result->setLastModifiedCommit($commit);
                 $result->setLastCommitData($data);
             }
         }
         $results[] = $result;
     }
     if (empty($results)) {
         $this->reason = self::REASON_IS_EMPTY;
     }
     return $results;
 }
 protected function getMercurialResult(ConduitAPIRequest $request)
 {
     $drequest = $this->getDiffusionRequest();
     $repository = $drequest->getRepository();
     $commit_hash = $request->getValue('commit');
     $path = $request->getValue('path');
     $offset = $request->getValue('offset');
     $limit = $request->getValue('limit');
     $path = DiffusionPathIDQuery::normalizePath($path);
     $path = ltrim($path, '/');
     // NOTE: Older versions of Mercurial give different results for these
     // commands (see T1268):
     //
     //   $ hg log -- ''
     //   $ hg log
     //
     // All versions of Mercurial give different results for these commands
     // (merge commits are excluded with the "." version):
     //
     //   $ hg log -- .
     //   $ hg log
     //
     // If we don't have a path component in the query, omit it from the command
     // entirely to avoid these inconsistencies.
     // NOTE: When viewing the history of a file, we don't use "-b", because
     // Mercurial stops history at the branchpoint but we're interested in all
     // ancestors. When viewing history of a branch, we do use "-b", and thus
     // stop history (this is more consistent with the Mercurial worldview of
     // branches).
     if (strlen($path)) {
         $path_arg = csprintf('-- %s', $path);
         $branch_arg = '';
     } else {
         $path_arg = '';
         // NOTE: --branch used to be called --only-branch; use -b for
         // compatibility.
         $branch_arg = csprintf('-b %s', $drequest->getBranch());
     }
     list($stdout) = $repository->execxLocalCommand('log --debug --template %s --limit %d %C --rev %s %C', '{node};{parents}\\n', $offset + $limit, $branch_arg, hgsprintf('reverse(ancestors(%s))', $commit_hash), $path_arg);
     $stdout = PhabricatorRepository::filterMercurialDebugOutput($stdout);
     $lines = explode("\n", trim($stdout));
     $lines = array_slice($lines, $offset);
     $hash_list = array();
     $parent_map = array();
     $last = null;
     foreach (array_reverse($lines) as $line) {
         list($hash, $parents) = explode(';', $line);
         $parents = trim($parents);
         if (!$parents) {
             if ($last === null) {
                 $parent_map[$hash] = array('...');
             } else {
                 $parent_map[$hash] = array($last);
             }
         } else {
             $parents = preg_split('/\\s+/', $parents);
             foreach ($parents as $parent) {
                 list($plocal, $phash) = explode(':', $parent);
                 if (!preg_match('/^0+$/', $phash)) {
                     $parent_map[$hash][] = $phash;
                 }
             }
             // This may happen for the zeroth commit in repository, both hashes
             // are "000000000...".
             if (empty($parent_map[$hash])) {
                 $parent_map[$hash] = array('...');
             }
         }
         // The rendering code expects the first commit to be "mainline", like
         // Git. Flip the order so it does the right thing.
         $parent_map[$hash] = array_reverse($parent_map[$hash]);
         $hash_list[] = $hash;
         $last = $hash;
     }
     $hash_list = array_reverse($hash_list);
     $this->parents = $parent_map;
     return DiffusionQuery::loadHistoryForCommitIdentifiers($hash_list, $drequest);
 }
 protected function executeQuery()
 {
     $drequest = $this->getRequest();
     $repository = $drequest->getRepository();
     $path = $drequest->getPath();
     $commit_hash = $drequest->getStableCommitName();
     $path = DiffusionPathIDQuery::normalizePath($path);
     $path = ltrim($path, '/');
     // NOTE: Older versions of Mercurial give different results for these
     // commands (see T1268):
     //
     //   $ hg log -- ''
     //   $ hg log
     //
     // All versions of Mercurial give different results for these commands
     // (merge commits are excluded with the "." version):
     //
     //   $ hg log -- .
     //   $ hg log
     //
     // If we don't have a path component in the query, omit it from the command
     // entirely to avoid these inconsistencies.
     $path_arg = '';
     if (strlen($path)) {
         $path_arg = csprintf('-- %s', $path);
     }
     // NOTE: --branch used to be called --only-branch; use -b for compatibility.
     list($stdout) = $repository->execxLocalCommand('log --debug --template %s --limit %d -b %s --rev %s:0 %C', '{node};{parents}\\n', $this->getOffset() + $this->getLimit(), $drequest->getBranch(), $commit_hash, $path_arg);
     $lines = explode("\n", trim($stdout));
     $lines = array_slice($lines, $this->getOffset());
     $hash_list = array();
     $parent_map = array();
     $last = null;
     foreach (array_reverse($lines) as $line) {
         list($hash, $parents) = explode(';', $line);
         $parents = trim($parents);
         if (!$parents) {
             if ($last === null) {
                 $parent_map[$hash] = array('...');
             } else {
                 $parent_map[$hash] = array($last);
             }
         } else {
             $parents = preg_split('/\\s+/', $parents);
             foreach ($parents as $parent) {
                 list($plocal, $phash) = explode(':', $parent);
                 if (!preg_match('/^0+$/', $phash)) {
                     $parent_map[$hash][] = $phash;
                 }
             }
             // This may happen for the zeroth commit in repository, both hashes
             // are "000000000...".
             if (empty($parent_map[$hash])) {
                 $parent_map[$hash] = array('...');
             }
         }
         // The rendering code expects the first commit to be "mainline", like
         // Git. Flip the order so it does the right thing.
         $parent_map[$hash] = array_reverse($parent_map[$hash]);
         $hash_list[] = $hash;
         $last = $hash;
     }
     $hash_list = array_reverse($hash_list);
     $this->parents = $parent_map;
     return $this->loadHistoryForCommitIdentifiers($hash_list);
 }
 protected final function loadHistoryForCommitIdentifiers(array $identifiers)
 {
     if (!$identifiers) {
         return array();
     }
     $commits = array();
     $commit_data = array();
     $path_changes = array();
     $drequest = $this->getRequest();
     $repository = $drequest->getRepository();
     $path = $drequest->getPath();
     $commits = id(new PhabricatorRepositoryCommit())->loadAllWhere('repositoryID = %d AND commitIdentifier IN (%Ls)', $repository->getID(), $identifiers);
     $commits = mpull($commits, null, 'getCommitIdentifier');
     if (!$commits) {
         return array();
     }
     $commit_data = id(new PhabricatorRepositoryCommitData())->loadAllWhere('commitID in (%Ld)', mpull($commits, 'getID'));
     $commit_data = mpull($commit_data, null, 'getCommitID');
     $conn_r = $repository->establishConnection('r');
     $path_normal = DiffusionPathIDQuery::normalizePath($path);
     $paths = queryfx_all($conn_r, 'SELECT id, path FROM %T WHERE path IN (%Ls)', PhabricatorRepository::TABLE_PATH, array($path_normal));
     $paths = ipull($paths, 'id', 'path');
     $path_id = idx($paths, $path_normal);
     $path_changes = queryfx_all($conn_r, 'SELECT * FROM %T WHERE commitID IN (%Ld) AND pathID = %d', PhabricatorRepository::TABLE_PATHCHANGE, mpull($commits, 'getID'), $path_id);
     $path_changes = ipull($path_changes, null, 'commitID');
     $history = array();
     foreach ($identifiers as $identifier) {
         $item = new DiffusionPathChange();
         $item->setCommitIdentifier($identifier);
         $commit = idx($commits, $identifier);
         if ($commit) {
             $item->setCommit($commit);
             $data = idx($commit_data, $commit->getID());
             if ($data) {
                 $item->setCommitData($data);
             }
             $change = idx($path_changes, $commit->getID());
             if ($change) {
                 $item->setChangeType($change['changeType']);
                 $item->setFileType($change['fileType']);
             }
         }
         $history[] = $item;
     }
     return $history;
 }