Skip to content

Commit 9a2e45e

Browse files
author
epriestley
committed
Serve Git reads over SSH
Summary: Like D7423, but for SSH. Test Plan: Ran `git clone ssh://...`, got a clone. Reviewers: btrahan Reviewed By: btrahan CC: hach-que, aran Maniphest Tasks: T2230 Differential Revision: https://secure.phabricator.com/D7424
1 parent 7d9dfb5 commit 9a2e45e

File tree

3 files changed

+65
-5
lines changed

3 files changed

+65
-5
lines changed

src/applications/diffusion/ssh/DiffusionSSHGitUploadPackWorkflow.php

+8
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,12 @@ public function getRequestPath() {
2323
return head($args->getArg('dir'));
2424
}
2525

26+
protected function executeRepositoryOperations(
27+
PhabricatorRepository $repository) {
28+
29+
$future = new ExecFuture('git-upload-pack %s', $repository->getLocalPath());
30+
31+
return $this->passthruIO($future);
32+
}
33+
2634
}

src/applications/diffusion/ssh/DiffusionSSHWorkflow.php

+4-5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ public function getArgs() {
1010

1111
abstract protected function isReadOnly();
1212
abstract protected function getRequestPath();
13+
abstract protected function executeRepositoryOperations(
14+
PhabricatorRepository $repository);
15+
1316
protected function writeError($message) {
1417
$this->getErrorChannel()->write($message);
1518
return $this;
@@ -20,15 +23,11 @@ final public function execute(PhutilArgumentParser $args) {
2023

2124
try {
2225
$repository = $this->loadRepository();
23-
24-
throw new Exception("TODO: Implement serve over SSH.");
25-
26+
return $this->executeRepositoryOperations($repository);
2627
} catch (Exception $ex) {
2728
$this->writeError(get_class($ex).': '.$ex->getMessage());
2829
return 1;
2930
}
30-
31-
return 0;
3231
}
3332

3433
private function loadRepository() {

src/infrastructure/ssh/PhabricatorSSHWorkflow.php

+53
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,50 @@ public function getIOChannel() {
3737
return $this->iochannel;
3838
}
3939

40+
public function passthruIO(ExecFuture $future) {
41+
$exec_channel = new PhutilExecChannel($future);
42+
$exec_channel->setStderrHandler(array($this, 'writeErrorIOCallback'));
43+
44+
$io_channel = $this->getIOChannel();
45+
$error_channel = $this->getErrorChannel();
46+
47+
$channels = array($exec_channel, $io_channel, $error_channel);
48+
49+
while (true) {
50+
PhutilChannel::waitForAny($channels);
51+
52+
$io_channel->update();
53+
$exec_channel->update();
54+
$error_channel->update();
55+
56+
$done = !$exec_channel->isOpen();
57+
58+
$data = $io_channel->read();
59+
if (strlen($data)) {
60+
$exec_channel->write($data);
61+
}
62+
63+
$data = $exec_channel->read();
64+
if (strlen($data)) {
65+
$io_channel->write($data);
66+
}
67+
68+
// If we have nothing left on stdin, close stdin on the subprocess.
69+
if (!$io_channel->isOpenForReading()) {
70+
// TODO: This should probably be part of PhutilExecChannel?
71+
$future->write('');
72+
}
73+
74+
if ($done) {
75+
break;
76+
}
77+
}
78+
79+
list($err) = $future->resolve();
80+
81+
return $err;
82+
}
83+
4084
public function readAllInput() {
4185
$channel = $this->getIOChannel();
4286
while ($channel->update()) {
@@ -53,4 +97,13 @@ public function writeIO($data) {
5397
return $this;
5498
}
5599

100+
public function writeErrorIO($data) {
101+
$this->getErrorChannel()->write($data);
102+
return $this;
103+
}
104+
105+
public function writeErrorIOCallback(PhutilChannel $channel, $data) {
106+
$this->writeErrorIO($data);
107+
}
108+
56109
}

0 commit comments

Comments
 (0)