protected function executeQuery() { $drequest = $this->getRequest(); $repository = $drequest->getRepository(); $path = $drequest->getPath(); $commit = $drequest->getCommit(); $local_path = $repository->getDetail('local-path'); if ($path == '') { // Fast path to improve the performance of the repository view; we know // the root is always a tree at any commit and always exists. $stdout = 'tree'; } else { try { list($stdout) = execx("(cd %s && git cat-file -t %s:%s)", $local_path, $commit, $path); } catch (CommandException $e) { $stderr = $e->getStdErr(); if (preg_match('/^fatal: Not a valid object name/', $stderr)) { // Grab two logs, since the first one is when the object was deleted. list($stdout) = execx('(cd %s && git log -n2 --format="%%H" %s -- %s)', $local_path, $commit, $path); $stdout = trim($stdout); if ($stdout) { $commits = explode("\n", $stdout); $this->reason = self::REASON_IS_DELETED; $this->deletedAtCommit = idx($commits, 0); $this->existedAtCommit = idx($commits, 1); return array(); } $this->reason = self::REASON_IS_NONEXISTENT; return array(); } else { throw $e; } } } if (trim($stdout) == 'blob') { $this->reason = self::REASON_IS_FILE; return array(); } if ($this->shouldOnlyTestValidity()) { return true; } list($stdout) = execx("(cd %s && git ls-tree -l %s:%s)", $local_path, $commit, $path); $results = array(); foreach (explode("\n", rtrim($stdout)) as $line) { list($mode, $type, $hash, $size, $name) = preg_split('/\\s+/', $line); if ($type == 'tree') { $file_type = DifferentialChangeType::FILE_DIRECTORY; } else { $file_type = DifferentialChangeType::FILE_NORMAL; } $result = new DiffusionRepositoryPath(); $result->setPath($name); $result->setHash($hash); $result->setFileType($file_type); $result->setFileSize($size); $results[] = $result; } return $results; }
protected function getGitResult(ConduitAPIRequest $request) { $drequest = $this->getDiffusionRequest(); $repository = $drequest->getRepository(); $path = $request->getValue('path'); $commit = $request->getValue('commit'); $offset = (int) $request->getValue('offset'); $limit = (int) $request->getValue('limit'); $result = $this->getEmptyResultSet(); if ($path == '') { // Fast path to improve the performance of the repository view; we know // the root is always a tree at any commit and always exists. $stdout = 'tree'; } else { try { list($stdout) = $repository->execxLocalCommand('cat-file -t %s:%s', $commit, $path); } catch (CommandException $e) { $stderr = $e->getStdErr(); if (preg_match('/^fatal: Not a valid object name/', $stderr)) { // Grab two logs, since the first one is when the object was deleted. list($stdout) = $repository->execxLocalCommand('log -n2 --format="%%H" %s -- %s', $commit, $path); $stdout = trim($stdout); if ($stdout) { $commits = explode("\n", $stdout); $result->setReasonForEmptyResultSet(DiffusionBrowseResultSet::REASON_IS_DELETED)->setDeletedAtCommit(idx($commits, 0))->setExistedAtCommit(idx($commits, 1)); return $result; } $result->setReasonForEmptyResultSet(DiffusionBrowseResultSet::REASON_IS_NONEXISTENT); return $result; } else { throw $e; } } } if (trim($stdout) == 'blob') { $result->setReasonForEmptyResultSet(DiffusionBrowseResultSet::REASON_IS_FILE); return $result; } $result->setIsValidResults(true); if ($this->shouldOnlyTestValidity($request)) { return $result; } list($stdout) = $repository->execxLocalCommand('ls-tree -z -l %s:%s', $commit, $path); $submodules = array(); if (strlen($path)) { $prefix = rtrim($path, '/') . '/'; } else { $prefix = ''; } $count = 0; $results = array(); $lines = empty($stdout) ? array() : explode("", rtrim($stdout)); foreach ($lines as $line) { // NOTE: Limit to 5 components so we parse filenames with spaces in them // correctly. // NOTE: The output uses a mixture of tabs and one-or-more spaces to // delimit fields. $parts = preg_split('/\\s+/', $line, 5); if (count($parts) < 5) { throw new Exception(pht('Expected "<mode> <type> <hash> <size>\\t<name>", for ls-tree of ' . '"%s:%s", got: %s', $commit, $path, $line)); } list($mode, $type, $hash, $size, $name) = $parts; $path_result = new DiffusionRepositoryPath(); if ($type == 'tree') { $file_type = DifferentialChangeType::FILE_DIRECTORY; } else { if ($type == 'commit') { $file_type = DifferentialChangeType::FILE_SUBMODULE; $submodules[] = $path_result; } else { $mode = intval($mode, 8); if (($mode & 0120000) == 0120000) { $file_type = DifferentialChangeType::FILE_SYMLINK; } else { $file_type = DifferentialChangeType::FILE_NORMAL; } } } $path_result->setFullPath($prefix . $name); $path_result->setPath($name); $path_result->setHash($hash); $path_result->setFileType($file_type); $path_result->setFileSize($size); if ($count >= $offset) { $results[] = $path_result; } $count++; if ($limit && $count >= $offset + $limit) { break; } } // If we identified submodules, lookup the module info at this commit to // find their source URIs. if ($submodules) { // NOTE: We need to read the file out of git and write it to a temporary // location because "git config -f" doesn't accept a "commit:path"-style // argument. // NOTE: This file may not exist, e.g. because the commit author removed // it when they added the submodule. See T1448. If it's not present, just // show the submodule without enriching it. If ".gitmodules" was removed // it seems to partially break submodules, but the repository as a whole // continues to work fine and we've seen at least two cases of this in // the wild. list($err, $contents) = $repository->execLocalCommand('cat-file blob %s:.gitmodules', $commit); if (!$err) { $tmp = new TempFile(); Filesystem::writeFile($tmp, $contents); list($module_info) = $repository->execxLocalCommand('config -l -f %s', $tmp); $dict = array(); $lines = explode("\n", trim($module_info)); foreach ($lines as $line) { list($key, $value) = explode('=', $line, 2); $parts = explode('.', $key); $dict[$key] = $value; } foreach ($submodules as $path) { $full_path = $path->getFullPath(); $key = 'submodule.' . $full_path . '.url'; if (isset($dict[$key])) { $path->setExternalURI($dict[$key]); } } } } return $result->setPaths($results); }
protected function executeQuery() { $drequest = $this->getRequest(); $repository = $drequest->getRepository(); $path = $drequest->getPath(); $commit = $drequest->getCommit(); if ($path == '') { // Fast path to improve the performance of the repository view; we know // the root is always a tree at any commit and always exists. $stdout = 'tree'; } else { try { list($stdout) = $repository->execxLocalCommand('cat-file -t %s:%s', $commit, $path); } catch (CommandException $e) { $stderr = $e->getStdErr(); if (preg_match('/^fatal: Not a valid object name/', $stderr)) { // Grab two logs, since the first one is when the object was deleted. list($stdout) = $repository->execxLocalCommand('log -n2 --format="%%H" %s -- %s', $commit, $path); $stdout = trim($stdout); if ($stdout) { $commits = explode("\n", $stdout); $this->reason = self::REASON_IS_DELETED; $this->deletedAtCommit = idx($commits, 0); $this->existedAtCommit = idx($commits, 1); return array(); } $this->reason = self::REASON_IS_NONEXISTENT; return array(); } else { throw $e; } } } if (trim($stdout) == 'blob') { $this->reason = self::REASON_IS_FILE; return array(); } if ($this->shouldOnlyTestValidity()) { return true; } list($stdout) = $repository->execxLocalCommand('ls-tree -z -l %s:%s', $commit, $path); $submodules = array(); $results = array(); foreach (explode("", rtrim($stdout)) as $line) { // NOTE: Limit to 5 components so we parse filenames with spaces in them // correctly. list($mode, $type, $hash, $size, $name) = preg_split('/\\s+/', $line, 5); $result = new DiffusionRepositoryPath(); if ($type == 'tree') { $file_type = DifferentialChangeType::FILE_DIRECTORY; } else { if ($type == 'commit') { $file_type = DifferentialChangeType::FILE_SUBMODULE; $submodules[] = $result; } else { $mode = intval($mode, 8); if (($mode & 0120000) == 0120000) { $file_type = DifferentialChangeType::FILE_SYMLINK; } else { $file_type = DifferentialChangeType::FILE_NORMAL; } } } $result->setFullPath($path . $name); $result->setPath($name); $result->setHash($hash); $result->setFileType($file_type); $result->setFileSize($size); $results[] = $result; } // If we identified submodules, lookup the module info at this commit to // find their source URIs. if ($submodules) { list($module_info) = $repository->execxLocalCommand('show %s:.gitmodules', $commit); $module_info = parse_ini_string($module_info, $process_sections = true, $scanner_mode = INI_SCANNER_RAW); foreach ($submodules as $path) { foreach ($module_info as $section) { if (empty($section['path']) || empty($section['url'])) { continue; } if ($section['path'] == $path->getFullPath()) { $path->setExternalURI($section['url']); } } } } return $results; }