Patchwork D2464: debugcommands: add debugserve command

login
register
mail settings
Submitter phabricator
Date Feb. 26, 2018, 9:17 p.m.
Message ID <differential-rev-PHID-DREV-xuczbh5rhr5f4f4vi5kj-req@phab.mercurial-scm.org>
Download mbox | patch
Permalink /patch/28426/
State Superseded
Headers show

Comments

phabricator - Feb. 26, 2018, 9:17 p.m.
indygreg created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  `hg serve --stdio` requires the exact command argument form
  `hg -R <path> serve --stdio` for security reasons. An upcoming
  commit will need to start an SSH protocol server process with
  custom settings.
  
  This commit creates a `hg debugserve` command for starting servers
  with custom options. There are no security restrictions and we can
  add options here that aren't appropriate for built-in commands.
  
  We currently only support starting an SSH protocol server using
  the process's stdio file descriptors. The server supports logging
  its I/O activity to a file descriptor number passed as a command
  argument.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D2464

AFFECTED FILES
  mercurial/debugcommands.py
  tests/test-completion.t
  tests/test-help.t
  tests/test-ssh-proto.t

CHANGE DETAILS




To: indygreg, #hg-reviewers
Cc: mercurial-devel

Patch

diff --git a/tests/test-ssh-proto.t b/tests/test-ssh-proto.t
--- a/tests/test-ssh-proto.t
+++ b/tests/test-ssh-proto.t
@@ -39,6 +39,43 @@ 
   384
   capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
 
+`hg debugserve --sshstdio` works
+
+  $ cd server
+  $ hg debugserve --sshstdio << EOF
+  > hello
+  > EOF
+  384
+  capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
+
+I/O logging works
+
+  $ hg debugserve --sshstdio --logiofd 1 << EOF
+  > hello
+  > EOF
+  o> write(4) -> None:
+  o>     384\n
+  o> write(384) -> None:
+  o>     capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n
+  384
+  capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
+  o> flush() -> None
+
+  $ hg debugserve --sshstdio --logiofile $TESTTMP/io << EOF
+  > hello
+  > EOF
+  384
+  capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
+
+  $ cat $TESTTMP/io
+  o> write(4) -> None:
+  o>     384\n
+  o> write(384) -> None:
+  o>     capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n
+  o> flush() -> None
+
+  $ cd ..
+
 >=0.9.1 clients send a "hello" + "between" for the null range as part of handshake.
 Server should reply with capabilities and should send "1\n\n" as a successful
 reply with empty response to the "between".
diff --git a/tests/test-help.t b/tests/test-help.t
--- a/tests/test-help.t
+++ b/tests/test-help.t
@@ -967,6 +967,7 @@ 
    debugrename   dump rename information
    debugrevlog   show data and statistics about a revlog
    debugrevspec  parse and apply a revision specification
+   debugserve    run a server with advanced settings
    debugsetparents
                  manually set the parents of the current working directory
    debugssl      test a secure connection to a server
diff --git a/tests/test-completion.t b/tests/test-completion.t
--- a/tests/test-completion.t
+++ b/tests/test-completion.t
@@ -111,6 +111,7 @@ 
   debugrename
   debugrevlog
   debugrevspec
+  debugserve
   debugsetparents
   debugssl
   debugsub
@@ -291,6 +292,7 @@ 
   debugrename: rev
   debugrevlog: changelog, manifest, dir, dump
   debugrevspec: optimize, show-revs, show-set, show-stage, no-optimized, verify-optimized
+  debugserve: sshstdio, logiofd
   debugsetparents: 
   debugssl: 
   debugsub: rev
diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py
--- a/mercurial/debugcommands.py
+++ b/mercurial/debugcommands.py
@@ -73,6 +73,7 @@ 
     url as urlmod,
     util,
     vfs as vfsmod,
+    wireprotoserver,
 )
 
 release = lockmod.release
@@ -2229,6 +2230,37 @@ 
     for c in revs:
         ui.write("%d\n" % c)
 
+@command('debugserve', [
+    ('', 'sshstdio', False, _('run an SSH server bound to process handles')),
+    ('', 'logiofd', '', _('file descriptor to log server I/O to')),
+    ('', 'logiofile', '', _('file to log server I/O to')),
+], '')
+def debugserve(ui, repo, **opts):
+    """run a server with advanced settings
+
+    This command is similar to :hg:`serve`. It exists partially as a
+    workaround to the fact that ``hg serve --stdio`` must have specific
+    arguments for security reasons.
+    """
+    opts = pycompat.byteskwargs(opts)
+
+    if not opts['sshstdio']:
+        raise error.Abort(_('only --sshstdio is currently supported'))
+
+    logfh = None
+
+    if opts['logiofd'] and opts['logiofile']:
+        raise error.Abort(_('cannot use both --logiofd and --logiofile'))
+
+    if opts['logiofd']:
+        # Line buffered because output is line based.
+        logfh = os.fdopen(int(opts['logiofd']), 'ab', 1)
+    elif opts['logiofile']:
+        logfh = open(opts['logiofile'], 'ab', 1)
+
+    s = wireprotoserver.sshserver(ui, repo, logfh=logfh)
+    s.serve_forever()
+
 @command('debugsetparents', [], _('REV1 [REV2]'))
 def debugsetparents(ui, repo, rev1, rev2=None):
     """manually set the parents of the current working directory