@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 DiffusionMercurialServeSSHWorkflow
4 extends DiffusionMercurialSSHWorkflow {
5
6 protected $didSeeWrite;
7
8 protected function didConstruct() {
9 $this->setName('hg');
10 $this->setArguments(
11 array(
12 array(
13 'name' => 'repository',
14 'short' => 'R',
15 'param' => 'repo',
16 ),
17 array(
18 'name' => 'stdio',
19 ),
20 array(
21 'name' => 'command',
22 'wildcard' => true,
23 ),
24 ));
25 }
26
27 protected function identifyRepository() {
28 $args = $this->getArgs();
29 $path = $args->getArg('repository');
30 return $this->loadRepositoryWithPath(
31 $path,
32 PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL);
33 }
34
35 protected function executeRepositoryOperations() {
36 $repository = $this->getRepository();
37 $args = $this->getArgs();
38
39 if (!$args->getArg('stdio')) {
40 throw new Exception(pht('Expected `%s`!', 'hg ... --stdio'));
41 }
42
43 if ($args->getArg('command') !== array('serve')) {
44 throw new Exception(pht('Expected `%s`!', 'hg ... serve'));
45 }
46
47 if ($this->shouldProxy()) {
48 // NOTE: For now, we're always requesting a writable node. The request
49 // may not actually need one, but we can't currently determine whether
50 // it is read-only or not at this phase of evaluation.
51 $command = $this->getProxyCommand(true);
52 } else {
53 $command = csprintf(
54 'hg -R %s serve --stdio',
55 $repository->getLocalPath());
56 }
57 $command = PhabricatorDaemon::sudoCommandAsDaemonUser($command);
58
59 $future = id(new ExecFuture('%C', $command))
60 ->setEnv($this->getEnvironment());
61
62 $io_channel = $this->getIOChannel();
63 $protocol_channel = new DiffusionMercurialWireClientSSHProtocolChannel(
64 $io_channel);
65
66 $err = id($this->newPassthruCommand())
67 ->setIOChannel($protocol_channel)
68 ->setCommandChannelFromExecFuture($future)
69 ->setWillWriteCallback(array($this, 'willWriteMessageCallback'))
70 ->execute();
71
72 if (!$err && $this->didSeeWrite) {
73 $repository->writeStatusMessage(
74 PhabricatorRepositoryStatusMessage::TYPE_NEEDS_UPDATE,
75 PhabricatorRepositoryStatusMessage::CODE_OKAY);
76 }
77
78 return $err;
79 }
80
81 public function willWriteMessageCallback(
82 PhabricatorSSHPassthruCommand $command,
83 $message) {
84
85 $command = $message['command'];
86
87 // Check if this is a readonly command.
88
89 $is_readonly = false;
90 if ($command == 'batch') {
91 $cmds = idx($message['arguments'], 'cmds');
92 if (DiffusionMercurialWireProtocol::isReadOnlyBatchCommand($cmds)) {
93 $is_readonly = true;
94 }
95 } else if (DiffusionMercurialWireProtocol::isReadOnlyCommand($command)) {
96 $is_readonly = true;
97 }
98
99 if (!$is_readonly) {
100 $this->requireWriteAccess();
101 $this->didSeeWrite = true;
102 }
103
104 return $message['raw'];
105 }
106
107 protected function raiseWrongVCSException(
108 PhabricatorRepository $repository) {
109 throw new Exception(
110 pht(
111 'This repository ("%s") is not a Mercurial repository. Use "%s" to '.
112 'interact with this repository.',
113 $repository->getDisplayName(),
114 $repository->getVersionControlSystem()));
115 }
116
117}