@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
3abstract class DiffusionQueryConduitAPIMethod
4 extends DiffusionConduitAPIMethod {
5
6 public function shouldAllowPublic() {
7 return true;
8 }
9
10 private $diffusionRequest;
11 private $repository;
12
13 protected function setDiffusionRequest(DiffusionRequest $request) {
14 $this->diffusionRequest = $request;
15 return $this;
16 }
17
18 protected function getDiffusionRequest() {
19 return $this->diffusionRequest;
20 }
21
22 protected function getRepository(ConduitAPIRequest $request) {
23 return $this->getDiffusionRequest()->getRepository();
24 }
25
26 final protected function defineErrorTypes() {
27 return $this->defineCustomErrorTypes() +
28 array(
29 'ERR-UNKNOWN-REPOSITORY' =>
30 pht('There is no matching repository.'),
31 'ERR-UNKNOWN-VCS-TYPE' =>
32 pht('Unknown repository VCS type.'),
33 'ERR-UNSUPPORTED-VCS' =>
34 pht('VCS is not supported for this method.'),
35 );
36 }
37
38 /**
39 * Subclasses should override this to specify custom error types.
40 */
41 protected function defineCustomErrorTypes() {
42 return array();
43 }
44
45 final protected function defineParamTypes() {
46 return $this->defineCustomParamTypes() +
47 array(
48 'callsign' => 'optional string (deprecated)',
49 'repository' => 'optional string',
50 'branch' => 'optional string',
51 );
52 }
53
54 /**
55 * Subclasses should override this to specify custom param types.
56 */
57 protected function defineCustomParamTypes() {
58 return array();
59 }
60
61 /**
62 * Subclasses should override these methods with the proper result for the
63 * pertinent version control system, e.g. getGitResult for Git.
64 *
65 * If the result is not supported for that VCS, do not implement it. e.g.
66 * Subversion (SVN) does not support branches.
67 */
68 protected function getGitResult(ConduitAPIRequest $request) {
69 throw new ConduitException('ERR-UNSUPPORTED-VCS');
70 }
71 protected function getSVNResult(ConduitAPIRequest $request) {
72 throw new ConduitException('ERR-UNSUPPORTED-VCS');
73 }
74 protected function getMercurialResult(ConduitAPIRequest $request) {
75 throw new ConduitException('ERR-UNSUPPORTED-VCS');
76 }
77
78 /**
79 * This method is final because most queries will need to construct a
80 * @{class:DiffusionRequest} and use it. Consolidating this codepath and
81 * enforcing @{method:getDiffusionRequest} works when we need it is good.
82 *
83 * @{method:getResult} should be overridden by subclasses as necessary, e.g.
84 * there is a common operation across all version control systems that
85 * should occur after @{method:getResult}, like formatting a timestamp.
86 */
87 final protected function execute(ConduitAPIRequest $request) {
88 $drequest = $this->getDiffusionRequest();
89
90 // We pass this flag on to prevent proxying of any other Conduit calls
91 // which we need to make in order to respond to this one. Although we
92 // could safely proxy them, we take a big performance hit in the common
93 // case, and doing more proxying wouldn't exercise any additional code so
94 // we wouldn't gain a testability/predictability benefit.
95 $is_cluster_request = $request->getIsClusterRequest();
96 $drequest->setIsClusterRequest($is_cluster_request);
97
98 $viewer = $request->getViewer();
99 $repository = $drequest->getRepository();
100
101 // TODO: Allow web UI queries opt out of this if they don't care about
102 // fetching the most up-to-date data? Synchronization can be slow, and a
103 // lot of web reads are probably fine if they're a few seconds out of
104 // date.
105 id(new DiffusionRepositoryClusterEngine())
106 ->setViewer($viewer)
107 ->setRepository($repository)
108 ->synchronizeWorkingCopyBeforeRead();
109
110 return $this->getResult($request);
111 }
112
113
114 protected function newConduitCallProxyClient(ConduitAPIRequest $request) {
115 $viewer = $request->getViewer();
116
117 $identifier = $request->getValue('repository');
118 if ($identifier === null) {
119 $identifier = $request->getValue('callsign');
120 }
121
122 $drequest = DiffusionRequest::newFromDictionary(
123 array(
124 'user' => $viewer,
125 'repository' => $identifier,
126 'branch' => $request->getValue('branch'),
127 'path' => $request->getValue('path'),
128 'commit' => $request->getValue('commit'),
129 ));
130
131 if (!$drequest) {
132 throw new Exception(
133 pht(
134 'Repository "%s" is not a valid repository.',
135 $identifier));
136 }
137
138 $repository = $drequest->getRepository();
139
140 $client = $repository->newConduitClientForRequest($request);
141 if ($client) {
142 return $client;
143 }
144
145 $this->setDiffusionRequest($drequest);
146
147 return null;
148 }
149
150 protected function getResult(ConduitAPIRequest $request) {
151 $repository = $this->getRepository($request);
152 $result = null;
153 switch ($repository->getVersionControlSystem()) {
154 case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
155 $result = $this->getGitResult($request);
156 break;
157 case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
158 $result = $this->getMercurialResult($request);
159 break;
160 case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
161 $result = $this->getSVNResult($request);
162 break;
163 default:
164 throw new ConduitException('ERR-UNKNOWN-VCS-TYPE');
165 }
166 return $result;
167 }
168
169}