@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.)
hq.recaptime.dev/wiki/Phorge
phorge
phabricator
1<?php
2
3final class DiffusionSearchQueryConduitAPIMethod
4 extends DiffusionQueryConduitAPIMethod {
5
6 public function getAPIMethodName() {
7 return 'diffusion.searchquery';
8 }
9
10 public function getMethodDescription() {
11 return pht('Search (grep) a repository at a specific path and commit.');
12 }
13
14 protected function defineReturnType() {
15 return 'array';
16 }
17
18 protected function defineCustomParamTypes() {
19 return array(
20 'path' => 'required string',
21 'commit' => 'optional string',
22 'grep' => 'required string',
23 'limit' => 'optional int',
24 'offset' => 'optional int',
25 );
26 }
27
28 protected function getResult(ConduitAPIRequest $request) {
29 try {
30 $results = parent::getResult($request);
31 } catch (CommandException $ex) {
32 $err = $ex->getError();
33
34 if ($err === 1) {
35 // `git grep` and `hg grep` exit with 1 if there are no matches;
36 // assume we just didn't get any hits.
37 return array();
38 }
39
40 throw $ex;
41 }
42
43 $offset = $request->getValue('offset', 0);
44 $results = array_slice($results, $offset);
45
46 return $results;
47 }
48
49 protected function getGitResult(ConduitAPIRequest $request) {
50 $drequest = $this->getDiffusionRequest();
51 $path = $drequest->getPath();
52 $grep = $request->getValue('grep');
53 $repository = $drequest->getRepository();
54 $limit = $request->getValue('limit');
55 $offset = $request->getValue('offset');
56
57 // Starting with Git 2.16.0, Git assumes passing an empty argument is
58 // an error and recommends you pass "." instead.
59 if (!strlen($path)) {
60 $path = '.';
61 }
62
63 $results = array();
64 $future = $repository->getLocalCommandFuture(
65 // NOTE: --perl-regexp is available only with libpcre compiled in.
66 'grep --extended-regexp --null -n --no-color -f - %s -- %s',
67 gitsprintf('%s', $drequest->getStableCommit()),
68 $path);
69
70 // NOTE: We're writing the pattern on stdin to avoid issues with UTF8
71 // being mangled by the shell. See T12807.
72 $future->write($grep);
73
74 $binary_pattern = '/Binary file [^:]*:(.+) matches/';
75 $lines = new LinesOfALargeExecFuture($future);
76
77 foreach ($lines as $line) {
78 $result = null;
79 if (preg_match('/[^:]*:(.+)\0(.+)\0(.*)/', $line, $result)) {
80 $results[] = array_slice($result, 1);
81 } else if (preg_match($binary_pattern, $line, $result)) {
82 list(, $path) = $result;
83 $results[] = array($path, null, pht('Binary file'));
84 } else {
85 $results[] = array(null, null, $line);
86 }
87 if (count($results) >= $offset + $limit) {
88 break;
89 }
90 }
91 unset($lines);
92
93 return $results;
94 }
95
96 protected function getMercurialResult(ConduitAPIRequest $request) {
97 $drequest = $this->getDiffusionRequest();
98 $path = $drequest->getPath();
99 $grep = $request->getValue('grep');
100 $repository = $drequest->getRepository();
101 $limit = $request->getValue('limit');
102 $offset = $request->getValue('offset');
103
104 $results = array();
105 $future = $repository->getLocalCommandFuture(
106 'grep --rev %s --print0 --line-number -- %s %s',
107 hgsprintf('ancestors(%s)', $drequest->getStableCommit()),
108 $grep,
109 $path);
110
111 $lines = id(new LinesOfALargeExecFuture($future))->setDelimiter("\0");
112 $parts = array();
113 foreach ($lines as $line) {
114 $parts[] = $line;
115 if (count($parts) == 4) {
116 list($path, $char_offset, $line, $string) = $parts;
117 $results[] = array($path, $line, $string);
118 if (count($results) >= $offset + $limit) {
119 break;
120 }
121 $parts = array();
122 }
123 }
124 unset($lines);
125
126 return $results;
127 }
128
129}