[ Index ]

PHP Cross Reference of Phabricator

title

Body

[close]

/src/applications/diffusion/ssh/ -> DiffusionSSHMercurialServeWorkflow.php (source)

   1  <?php
   2  
   3  final class DiffusionSSHMercurialServeWorkflow
   4    extends DiffusionSSHMercurialWorkflow {
   5  
   6    protected $didSeeWrite;
   7  
   8    public 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 executeRepositoryOperations() {
  28      $args = $this->getArgs();
  29      $path = $args->getArg('repository');
  30      $repository = $this->loadRepository($path);
  31  
  32      $args = $this->getArgs();
  33  
  34      if (!$args->getArg('stdio')) {
  35        throw new Exception('Expected `hg ... --stdio`!');
  36      }
  37  
  38      if ($args->getArg('command') !== array('serve')) {
  39        throw new Exception('Expected `hg ... serve`!');
  40      }
  41  
  42      $command = csprintf('hg -R %s serve --stdio', $repository->getLocalPath());
  43      $command = PhabricatorDaemon::sudoCommandAsDaemonUser($command);
  44  
  45      $future = id(new ExecFuture('%C', $command))
  46        ->setEnv($this->getEnvironment());
  47  
  48      $io_channel = $this->getIOChannel();
  49      $protocol_channel = new DiffusionSSHMercurialWireClientProtocolChannel(
  50        $io_channel);
  51  
  52      $err = id($this->newPassthruCommand())
  53        ->setIOChannel($protocol_channel)
  54        ->setCommandChannelFromExecFuture($future)
  55        ->setWillWriteCallback(array($this, 'willWriteMessageCallback'))
  56        ->execute();
  57  
  58      // TODO: It's apparently technically possible to communicate errors to
  59      // Mercurial over SSH by writing a special "\n<error>\n-\n" string. However,
  60      // my attempt to implement that resulted in Mercurial closing the socket and
  61      // then hanging, without showing the error. This might be an issue on our
  62      // side (we need to close our half of the socket?), or maybe the code
  63      // for this in Mercurial doesn't actually work, or maybe something else
  64      // is afoot. At some point, we should look into doing this more cleanly.
  65      // For now, when we, e.g., reject writes for policy reasons, the user will
  66      // see "abort: unexpected response: empty string" after the diagnostically
  67      // useful, e.g., "remote: This repository is read-only over SSH." message.
  68  
  69      if (!$err && $this->didSeeWrite) {
  70        $repository->writeStatusMessage(
  71          PhabricatorRepositoryStatusMessage::TYPE_NEEDS_UPDATE,
  72          PhabricatorRepositoryStatusMessage::CODE_OKAY);
  73      }
  74  
  75      return $err;
  76    }
  77  
  78    public function willWriteMessageCallback(
  79      PhabricatorSSHPassthruCommand $command,
  80      $message) {
  81  
  82      $command = $message['command'];
  83  
  84      // Check if this is a readonly command.
  85  
  86      $is_readonly = false;
  87      if ($command == 'batch') {
  88        $cmds = idx($message['arguments'], 'cmds');
  89        if (DiffusionMercurialWireProtocol::isReadOnlyBatchCommand($cmds)) {
  90          $is_readonly = true;
  91        }
  92      } else if (DiffusionMercurialWireProtocol::isReadOnlyCommand($command)) {
  93        $is_readonly = true;
  94      }
  95  
  96      if (!$is_readonly) {
  97        $this->requireWriteAccess();
  98        $this->didSeeWrite = true;
  99      }
 100  
 101      // If we're good, return the raw message data.
 102      return $message['raw'];
 103    }
 104  
 105  }


Generated: Sun Nov 30 09:20:46 2014 Cross-referenced by PHPXref 0.7.1