2013-05-01 23:44:28 +02:00
|
|
|
<?php
|
|
|
|
|
Rename Conduit classes
Summary: Ref T5655. Rename Conduit classes and provide a `getAPIMethodName` method to declare the API method.
Test Plan:
```
> echo '{}' | arc --conduit-uri='http://phabricator.joshuaspence.com' call-conduit user.whoami
Waiting for JSON parameters on stdin...
{"error":null,"errorMessage":null,"response":{"phid":"PHID-USER-lioqffnwn6y475mu5ndb","userName":"josh","realName":"Joshua Spence","image":"http:\/\/phabricator.joshuaspence.com\/res\/1404425321T\/phabricator\/3eb28cd9\/rsrc\/image\/avatar.png","uri":"http:\/\/phabricator.joshuaspence.com\/p\/josh\/","roles":["admin","verified","approved","activated"]}}
```
Reviewers: epriestley, #blessed_reviewers
Reviewed By: epriestley, #blessed_reviewers
Subscribers: epriestley, Korvin, hach-que
Maniphest Tasks: T5655
Differential Revision: https://secure.phabricator.com/D9991
2014-07-25 02:54:15 +02:00
|
|
|
abstract class DiffusionQueryConduitAPIMethod
|
|
|
|
extends DiffusionConduitAPIMethod {
|
2013-05-01 23:44:28 +02:00
|
|
|
|
2013-10-22 22:47:52 +02:00
|
|
|
public function shouldAllowPublic() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-05-07 23:57:08 +02:00
|
|
|
public function getMethodStatus() {
|
|
|
|
return self::METHOD_STATUS_UNSTABLE;
|
|
|
|
}
|
2013-10-22 22:47:52 +02:00
|
|
|
|
2013-05-07 23:57:08 +02:00
|
|
|
public function getMethodStatusDescription() {
|
|
|
|
return pht(
|
2015-05-22 09:27:56 +02:00
|
|
|
'See T2784 - migrating Diffusion working copy calls to conduit methods. '.
|
2013-05-07 23:57:08 +02:00
|
|
|
'Until that task is completed (and possibly after) these methods are '.
|
|
|
|
'unstable.');
|
|
|
|
}
|
|
|
|
|
2013-05-01 23:44:28 +02:00
|
|
|
private $diffusionRequest;
|
2013-05-15 00:32:19 +02:00
|
|
|
private $repository;
|
|
|
|
|
2013-05-01 23:44:28 +02:00
|
|
|
protected function setDiffusionRequest(DiffusionRequest $request) {
|
|
|
|
$this->diffusionRequest = $request;
|
|
|
|
return $this;
|
|
|
|
}
|
2014-05-13 22:51:33 +02:00
|
|
|
|
2013-05-01 23:44:28 +02:00
|
|
|
protected function getDiffusionRequest() {
|
|
|
|
return $this->diffusionRequest;
|
|
|
|
}
|
|
|
|
|
2013-05-15 00:32:19 +02:00
|
|
|
protected function getRepository(ConduitAPIRequest $request) {
|
2014-05-13 22:51:33 +02:00
|
|
|
return $this->getDiffusionRequest()->getRepository();
|
2013-05-15 00:32:19 +02:00
|
|
|
}
|
|
|
|
|
2015-04-13 00:59:07 +02:00
|
|
|
final protected function defineErrorTypes() {
|
2013-05-01 23:44:28 +02:00
|
|
|
return $this->defineCustomErrorTypes() +
|
|
|
|
array(
|
2013-05-15 00:32:19 +02:00
|
|
|
'ERR-UNKNOWN-REPOSITORY' =>
|
2016-01-02 20:03:05 +01:00
|
|
|
pht('There is no matching repository.'),
|
2013-05-15 00:32:19 +02:00
|
|
|
'ERR-UNKNOWN-VCS-TYPE' =>
|
2013-05-01 23:44:28 +02:00
|
|
|
pht('Unknown repository VCS type.'),
|
|
|
|
'ERR-UNSUPPORTED-VCS' =>
|
2014-10-07 15:01:04 +02:00
|
|
|
pht('VCS is not supported for this method.'),
|
|
|
|
);
|
2013-05-01 23:44:28 +02:00
|
|
|
}
|
2014-07-10 00:12:48 +02:00
|
|
|
|
2013-05-01 23:44:28 +02:00
|
|
|
/**
|
|
|
|
* Subclasses should override this to specify custom error types.
|
|
|
|
*/
|
|
|
|
protected function defineCustomErrorTypes() {
|
|
|
|
return array();
|
|
|
|
}
|
|
|
|
|
2015-04-13 00:59:07 +02:00
|
|
|
final protected function defineParamTypes() {
|
2013-05-01 23:44:28 +02:00
|
|
|
return $this->defineCustomParamTypes() +
|
|
|
|
array(
|
2016-01-02 20:03:05 +01:00
|
|
|
'callsign' => 'optional string (deprecated)',
|
|
|
|
'repository' => 'optional string',
|
2013-08-13 19:11:15 +02:00
|
|
|
'branch' => 'optional string',
|
|
|
|
);
|
2013-05-01 23:44:28 +02:00
|
|
|
}
|
2014-07-10 00:12:48 +02:00
|
|
|
|
2013-05-01 23:44:28 +02:00
|
|
|
/**
|
|
|
|
* Subclasses should override this to specify custom param types.
|
|
|
|
*/
|
|
|
|
protected function defineCustomParamTypes() {
|
|
|
|
return array();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Subclasses should override these methods with the proper result for the
|
|
|
|
* pertinent version control system, e.g. getGitResult for Git.
|
|
|
|
*
|
|
|
|
* If the result is not supported for that VCS, do not implement it. e.g.
|
|
|
|
* Subversion (SVN) does not support branches.
|
|
|
|
*/
|
|
|
|
protected function getGitResult(ConduitAPIRequest $request) {
|
|
|
|
throw new ConduitException('ERR-UNSUPPORTED-VCS');
|
|
|
|
}
|
|
|
|
protected function getSVNResult(ConduitAPIRequest $request) {
|
|
|
|
throw new ConduitException('ERR-UNSUPPORTED-VCS');
|
|
|
|
}
|
|
|
|
protected function getMercurialResult(ConduitAPIRequest $request) {
|
|
|
|
throw new ConduitException('ERR-UNSUPPORTED-VCS');
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-05-15 00:32:19 +02:00
|
|
|
* This method is final because most queries will need to construct a
|
2013-05-01 23:44:28 +02:00
|
|
|
* @{class:DiffusionRequest} and use it. Consolidating this codepath and
|
|
|
|
* enforcing @{method:getDiffusionRequest} works when we need it is good.
|
|
|
|
*
|
|
|
|
* @{method:getResult} should be overridden by subclasses as necessary, e.g.
|
|
|
|
* there is a common operation across all version control systems that
|
|
|
|
* should occur after @{method:getResult}, like formatting a timestamp.
|
|
|
|
*/
|
|
|
|
final protected function execute(ConduitAPIRequest $request) {
|
2016-01-02 20:03:05 +01:00
|
|
|
$identifier = $request->getValue('repository');
|
|
|
|
if ($identifier === null) {
|
|
|
|
$identifier = $request->getValue('callsign');
|
|
|
|
}
|
|
|
|
|
2014-05-13 22:51:33 +02:00
|
|
|
$drequest = DiffusionRequest::newFromDictionary(
|
|
|
|
array(
|
|
|
|
'user' => $request->getUser(),
|
2016-01-02 20:03:05 +01:00
|
|
|
'repository' => $identifier,
|
2014-05-13 22:51:33 +02:00
|
|
|
'branch' => $request->getValue('branch'),
|
|
|
|
'path' => $request->getValue('path'),
|
|
|
|
'commit' => $request->getValue('commit'),
|
|
|
|
));
|
|
|
|
|
2016-01-06 13:56:27 +01:00
|
|
|
if (!$drequest) {
|
|
|
|
throw new Exception(
|
|
|
|
pht(
|
|
|
|
'Repository "%s" is not a valid repository.',
|
|
|
|
$identifier));
|
|
|
|
}
|
|
|
|
|
2015-01-23 22:30:52 +01:00
|
|
|
// Figure out whether we're going to handle this request on this device,
|
|
|
|
// or proxy it to another node in the cluster.
|
|
|
|
|
|
|
|
// If this is a cluster request and we need to proxy, we'll explode here
|
|
|
|
// to prevent infinite recursion.
|
|
|
|
|
|
|
|
$is_cluster_request = $request->getIsClusterRequest();
|
|
|
|
|
|
|
|
$repository = $drequest->getRepository();
|
|
|
|
$client = $repository->newConduitClient(
|
|
|
|
$request->getUser(),
|
|
|
|
$is_cluster_request);
|
|
|
|
if ($client) {
|
|
|
|
// We're proxying, so just make an intracluster call.
|
|
|
|
return $client->callMethodSynchronous(
|
|
|
|
$this->getAPIMethodName(),
|
|
|
|
$request->getAllParameters());
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// We pass this flag on to prevent proxying of any other Conduit calls
|
|
|
|
// which we need to make in order to respond to this one. Although we
|
|
|
|
// could safely proxy them, we take a big performance hit in the common
|
|
|
|
// case, and doing more proxying wouldn't exercise any additional code so
|
|
|
|
// we wouldn't gain a testability/predictability benefit.
|
|
|
|
$drequest->setIsClusterRequest($is_cluster_request);
|
|
|
|
|
|
|
|
$this->setDiffusionRequest($drequest);
|
|
|
|
|
Synchronize (hosted, clustered, Git) repositories over Conduit + HTTP
Summary:
Ref T4292. We currently synchronize hosted, clustered, Git repositories when we receive an SSH pull or push.
Additionally:
- Synchronize before HTTP reads and writes.
- Synchronize reads before Conduit requests.
We could relax Conduit eventually and allow Diffusion to say "it's OK to give me stale data".
We could also redirect some set of these actions to just go to the up-to-date host instead of connecting to a random host and synchronizing it. However, this potentially won't work as well at scale: if you have a larger number of servers, it sends all of the traffic to the leader immediately following a write. That can cause "thundering herd" issues, and isn't efficient if replicas are in different geographical regions and the write just went to the east coast but most clients are on the west coast. In large-scale cases, it's better to go to the local replica, wait for an update, then serve traffic from it -- particularly given that writes are relatively rare. But we can finesse this later once things are solid.
Test Plan:
- Pushed and pulled a Git repository over HTTP.
- Browsed a Git repository from the web UI.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T4292
Differential Revision: https://secure.phabricator.com/D15758
2016-04-19 17:03:12 +02:00
|
|
|
// TODO: Allow web UI queries opt out of this if they don't care about
|
|
|
|
// fetching the most up-to-date data? Synchronization can be slow, and a
|
|
|
|
// lot of web reads are probably fine if they're a few seconds out of
|
|
|
|
// date.
|
|
|
|
$repository->synchronizeWorkingCopyBeforeRead();
|
|
|
|
|
2015-01-23 22:30:52 +01:00
|
|
|
return $this->getResult($request);
|
|
|
|
}
|
2013-05-01 23:44:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
protected function getResult(ConduitAPIRequest $request) {
|
2013-05-15 00:32:19 +02:00
|
|
|
$repository = $this->getRepository($request);
|
2013-05-01 23:44:28 +02:00
|
|
|
$result = null;
|
|
|
|
switch ($repository->getVersionControlSystem()) {
|
|
|
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
|
|
|
$result = $this->getGitResult($request);
|
|
|
|
break;
|
|
|
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
|
|
|
|
$result = $this->getMercurialResult($request);
|
|
|
|
break;
|
|
|
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
|
|
|
|
$result = $this->getSVNResult($request);
|
|
|
|
break;
|
|
|
|
default:
|
2013-05-15 00:32:19 +02:00
|
|
|
throw new ConduitException('ERR-UNKNOWN-VCS-TYPE');
|
2013-05-01 23:44:28 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return $result;
|
|
|
|
}
|
2014-07-10 00:12:48 +02:00
|
|
|
|
2013-05-01 23:44:28 +02:00
|
|
|
}
|