Page MenuHomePhabricator

D7421.diff

diff --git a/scripts/ssh/ssh-exec.php b/scripts/ssh/ssh-exec.php
--- a/scripts/ssh/ssh-exec.php
+++ b/scripts/ssh/ssh-exec.php
@@ -61,6 +61,8 @@
$workflows = array(
new ConduitSSHWorkflow(),
+
+ new DiffusionSSHGitUploadPackWorkflow(),
);
$workflow_names = mpull($workflows, 'getName', 'getName');
@@ -81,16 +83,24 @@
throw new Exception("Unable to open stdout.");
}
+ $sock_stderr = fopen('php://stderr', 'w');
+ if (!$sock_stderr) {
+ throw new Exception("Unable to open stderr.");
+ }
+
$socket_channel = new PhutilSocketChannel(
$sock_stdin,
$sock_stdout);
+ $error_channel = new PhutilSocketChannel(null, $sock_stderr);
$metrics_channel = new PhutilMetricsChannel($socket_channel);
$workflow->setIOChannel($metrics_channel);
+ $workflow->setErrorChannel($error_channel);
$err = $workflow->execute($original_args);
$metrics_channel->flush();
+ $error_channel->flush();
} catch (Exception $ex) {
- echo "phabricator-ssh-exec: ".$ex->getMessage()."\n";
+ fwrite(STDERR, "phabricator-ssh-exec: ".$ex->getMessage()."\n");
exit(1);
}
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -526,6 +526,9 @@
'DiffusionRepositoryPath' => 'applications/diffusion/data/DiffusionRepositoryPath.php',
'DiffusionRepositoryTag' => 'applications/diffusion/data/DiffusionRepositoryTag.php',
'DiffusionRequest' => 'applications/diffusion/request/DiffusionRequest.php',
+ 'DiffusionSSHGitUploadPackWorkflow' => 'applications/diffusion/ssh/DiffusionSSHGitUploadPackWorkflow.php',
+ 'DiffusionSSHGitWorkflow' => 'applications/diffusion/ssh/DiffusionSSHGitWorkflow.php',
+ 'DiffusionSSHWorkflow' => 'applications/diffusion/ssh/DiffusionSSHWorkflow.php',
'DiffusionSetupException' => 'applications/diffusion/exception/DiffusionSetupException.php',
'DiffusionStableCommitNameQuery' => 'applications/diffusion/query/stablecommitname/DiffusionStableCommitNameQuery.php',
'DiffusionSvnCommitParentsQuery' => 'applications/diffusion/query/parents/DiffusionSvnCommitParentsQuery.php',
@@ -2711,6 +2714,9 @@
0 => 'DiffusionController',
1 => 'PhabricatorApplicationSearchResultsControllerInterface',
),
+ 'DiffusionSSHGitUploadPackWorkflow' => 'DiffusionSSHGitWorkflow',
+ 'DiffusionSSHGitWorkflow' => 'DiffusionSSHWorkflow',
+ 'DiffusionSSHWorkflow' => 'PhabricatorSSHWorkflow',
'DiffusionSetupException' => 'AphrontUsageException',
'DiffusionStableCommitNameQuery' => 'DiffusionQuery',
'DiffusionSvnCommitParentsQuery' => 'DiffusionCommitParentsQuery',
diff --git a/src/applications/diffusion/controller/DiffusionRepositoryEditHostingController.php b/src/applications/diffusion/controller/DiffusionRepositoryEditHostingController.php
--- a/src/applications/diffusion/controller/DiffusionRepositoryEditHostingController.php
+++ b/src/applications/diffusion/controller/DiffusionRepositoryEditHostingController.php
@@ -134,7 +134,7 @@
if ($request->isFormPost()) {
$v_http_mode = $request->getStr('http');
- $v_ssh_mode = PhabricatorRepository::SERVE_OFF;
+ $v_ssh_mode = $request->getStr('ssh');
$xactions = array();
$template = id(new PhabricatorRepositoryTransaction());
@@ -176,6 +176,29 @@
'writes.');
}
+ $ssh_control =
+ id(new AphrontFormRadioButtonControl())
+ ->setName('ssh')
+ ->setLabel(pht('SSH'))
+ ->setValue($v_ssh_mode)
+ ->addButton(
+ PhabricatorRepository::SERVE_OFF,
+ PhabricatorRepository::getProtocolAvailabilityName(
+ PhabricatorRepository::SERVE_OFF),
+ pht('Phabricator will not serve this repository.'))
+ ->addButton(
+ PhabricatorRepository::SERVE_READONLY,
+ PhabricatorRepository::getProtocolAvailabilityName(
+ PhabricatorRepository::SERVE_READONLY),
+ pht('Phabricator will serve a read-only copy of this repository.'))
+ ->addButton(
+ PhabricatorRepository::SERVE_READWRITE,
+ PhabricatorRepository::getProtocolAvailabilityName(
+ PhabricatorRepository::SERVE_READWRITE),
+ $rw_message,
+ $repository->isHosted() ? null : 'disabled',
+ $repository->isHosted() ? null : true);
+
$http_control =
id(new AphrontFormRadioButtonControl())
->setName('http')
@@ -205,6 +228,7 @@
pht(
'Phabricator can serve repositories over various protocols. You can '.
'configure server protocols here.'))
+ ->appendChild($ssh_control)
->appendChild($http_control)
->appendChild(
id(new AphrontFormSubmitControl())
diff --git a/src/applications/diffusion/ssh/DiffusionSSHGitUploadPackWorkflow.php b/src/applications/diffusion/ssh/DiffusionSSHGitUploadPackWorkflow.php
new file mode 100644
--- /dev/null
+++ b/src/applications/diffusion/ssh/DiffusionSSHGitUploadPackWorkflow.php
@@ -0,0 +1,26 @@
+<?php
+
+final class DiffusionSSHGitUploadPackWorkflow
+ extends DiffusionSSHGitWorkflow {
+
+ public function didConstruct() {
+ $this->setName('git-upload-pack');
+ $this->setArguments(
+ array(
+ array(
+ 'name' => 'dir',
+ 'wildcard' => true,
+ ),
+ ));
+ }
+
+ public function isReadOnly() {
+ return true;
+ }
+
+ public function getRequestPath() {
+ $args = $this->getArgs();
+ return head($args->getArg('dir'));
+ }
+
+}
diff --git a/src/applications/diffusion/ssh/DiffusionSSHGitWorkflow.php b/src/applications/diffusion/ssh/DiffusionSSHGitWorkflow.php
new file mode 100644
--- /dev/null
+++ b/src/applications/diffusion/ssh/DiffusionSSHGitWorkflow.php
@@ -0,0 +1,10 @@
+<?php
+
+abstract class DiffusionSSHGitWorkflow extends DiffusionSSHWorkflow {
+
+ protected function writeError($message) {
+ // Git assumes we'll add our own newlines.
+ return parent::writeError($message."\n");
+ }
+
+}
diff --git a/src/applications/diffusion/ssh/DiffusionSSHWorkflow.php b/src/applications/diffusion/ssh/DiffusionSSHWorkflow.php
new file mode 100644
--- /dev/null
+++ b/src/applications/diffusion/ssh/DiffusionSSHWorkflow.php
@@ -0,0 +1,90 @@
+<?php
+
+abstract class DiffusionSSHWorkflow extends PhabricatorSSHWorkflow {
+
+ private $args;
+
+ public function getArgs() {
+ return $this->args;
+ }
+
+ abstract protected function isReadOnly();
+ abstract protected function getRequestPath();
+ protected function writeError($message) {
+ $this->getErrorChannel()->write($message);
+ return $this;
+ }
+
+ final public function execute(PhutilArgumentParser $args) {
+ $this->args = $args;
+
+ try {
+ $repository = $this->loadRepository();
+
+ throw new Exception("TODO: Implement serve over SSH.");
+
+ } catch (Exception $ex) {
+ $this->writeError(get_class($ex).': '.$ex->getMessage());
+ return 1;
+ }
+
+ return 0;
+ }
+
+ private function loadRepository() {
+ $viewer = $this->getUser();
+ $path = $this->getRequestPath();
+
+ $regex = '@^/?diffusion/(?P<callsign>[A-Z]+)(?:/|$)@';
+ $matches = null;
+ if (!preg_match($regex, $path, $matches)) {
+ throw new Exception(
+ pht(
+ 'Unrecognized repository path "%s". Expected a path like '.
+ '"%s".',
+ $path,
+ "/diffusion/X/"));
+ }
+
+ $callsign = $matches[1];
+ $repository = id(new PhabricatorRepositoryQuery())
+ ->setViewer($viewer)
+ ->withCallsigns(array($callsign))
+ ->executeOne();
+
+ if (!$repository) {
+ throw new Exception(
+ pht('No repository "%s" exists!', $callsign));
+ }
+
+ $is_push = !$this->isReadOnly();
+
+ switch ($repository->getServeOverSSH()) {
+ case PhabricatorRepository::SERVE_READONLY:
+ if ($is_push) {
+ throw new Exception(
+ pht('This repository is read-only over SSH.'));
+ }
+ break;
+ case PhabricatorRepository::SERVE_READWRITE:
+ if ($is_push) {
+ $can_push = PhabricatorPolicyFilter::hasCapability(
+ $viewer,
+ $repository,
+ DiffusionCapabilityPush::CAPABILITY);
+ if (!$can_push) {
+ throw new Exception(
+ pht('You do not have permission to push to this repository.'));
+ }
+ }
+ break;
+ case PhabricatorRepository::SERVE_OFF:
+ default:
+ throw new Exception(
+ pht('This repository is not available over SSH.'));
+ }
+
+ return $repository;
+ }
+
+}
diff --git a/src/infrastructure/ssh/PhabricatorSSHWorkflow.php b/src/infrastructure/ssh/PhabricatorSSHWorkflow.php
--- a/src/infrastructure/ssh/PhabricatorSSHWorkflow.php
+++ b/src/infrastructure/ssh/PhabricatorSSHWorkflow.php
@@ -4,6 +4,16 @@
private $user;
private $iochannel;
+ private $errorChannel;
+
+ public function setErrorChannel(PhutilChannel $error_channel) {
+ $this->errorChannel = $error_channel;
+ return $this;
+ }
+
+ public function getErrorChannel() {
+ return $this->errorChannel;
+ }
public function setUser(PhabricatorUser $user) {
$this->user = $user;
@@ -38,4 +48,9 @@
return $channel->read();
}
+ public function writeIO($data) {
+ $this->getIOChannel()->write($data);
+ return $this;
+ }
+
}

File Metadata

Mime Type
text/x-diff
Storage Engine
amazon-s3
Storage Format
Raw Data
Storage Handle
phabricator/du/jj/3wekjxk6sty6427r
Default Alt Text
D7421.diff (9 KB)

Event Timeline