mercurial/commandserver.py
author Pierre-Yves DAVID <pierre-yves.david@octobus.net>
Wed, 01 Jun 2022 01:34:33 +0200
changeset 49265 30d2beab8163
parent 48946 642e31cb55f0
child 49280 311fcc5a65f6
permissions -rw-r--r--
debugindex: add a `sd-chunk-size` column
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
     1
# commandserver.py - communicate with Mercurial's API over a pipe
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
     2
#
46819
d4ba4d51f85f contributor: change mentions of mpm to olivia
Raphaël Gomès <rgomes@octobus.net>
parents: 46101
diff changeset
     3
#  Copyright Olivia Mackall <olivia@selenic.com>
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
     4
#
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
     5
# This software may be used and distributed according to the terms of the
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
     6
# GNU General Public License version 2 or any later version.
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
     7
27351
28e50c4b15ed commandserver: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 26587
diff changeset
     8
28e50c4b15ed commandserver: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 26587
diff changeset
     9
import errno
29513
e5b4d79a9140 commandserver: backport handling of forking server from chgserver
Yuya Nishihara <yuya@tcha.org>
parents: 29512
diff changeset
    10
import gc
27351
28e50c4b15ed commandserver: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 26587
diff changeset
    11
import os
29513
e5b4d79a9140 commandserver: backport handling of forking server from chgserver
Yuya Nishihara <yuya@tcha.org>
parents: 29512
diff changeset
    12
import random
29544
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
    13
import signal
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
    14
import socket
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
    15
import struct
27351
28e50c4b15ed commandserver: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 26587
diff changeset
    16
import traceback
28e50c4b15ed commandserver: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 26587
diff changeset
    17
36940
b0ffcb540357 commandserver: prefer first-party selectors module from Python 3 to backport
Augie Fackler <augie@google.com>
parents: 36835
diff changeset
    18
try:
b0ffcb540357 commandserver: prefer first-party selectors module from Python 3 to backport
Augie Fackler <augie@google.com>
parents: 36835
diff changeset
    19
    import selectors
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
    20
36940
b0ffcb540357 commandserver: prefer first-party selectors module from Python 3 to backport
Augie Fackler <augie@google.com>
parents: 36835
diff changeset
    21
    selectors.BaseSelector
b0ffcb540357 commandserver: prefer first-party selectors module from Python 3 to backport
Augie Fackler <augie@google.com>
parents: 36835
diff changeset
    22
except ImportError:
b0ffcb540357 commandserver: prefer first-party selectors module from Python 3 to backport
Augie Fackler <augie@google.com>
parents: 36835
diff changeset
    23
    from .thirdparty import selectors2 as selectors
b0ffcb540357 commandserver: prefer first-party selectors module from Python 3 to backport
Augie Fackler <augie@google.com>
parents: 36835
diff changeset
    24
27351
28e50c4b15ed commandserver: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 26587
diff changeset
    25
from .i18n import _
43089
c59eb1560c44 py3: manually import getattr where it is needed
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43077
diff changeset
    26
from .pycompat import getattr
27351
28e50c4b15ed commandserver: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 26587
diff changeset
    27
from . import (
28e50c4b15ed commandserver: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 26587
diff changeset
    28
    encoding,
28e50c4b15ed commandserver: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 26587
diff changeset
    29
    error,
40824
82210d88d814 commandserver: install logger to record server events through canonical API
Yuya Nishihara <yuya@tcha.org>
parents: 40823
diff changeset
    30
    loggingutil,
40589
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
    31
    pycompat,
40999
dcac24ec935b commandserver: preload repository in master server and reuse its file cache
Yuya Nishihara <yuya@tcha.org>
parents: 40998
diff changeset
    32
    repocache,
27351
28e50c4b15ed commandserver: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 26587
diff changeset
    33
    util,
40824
82210d88d814 commandserver: install logger to record server events through canonical API
Yuya Nishihara <yuya@tcha.org>
parents: 40823
diff changeset
    34
    vfs as vfsmod,
27351
28e50c4b15ed commandserver: use absolute_import
Yuya Nishihara <yuya@tcha.org>
parents: 26587
diff changeset
    35
)
37119
d4a2e0d5d042 procutil: bulk-replace util.std* to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36940
diff changeset
    36
from .utils import (
40589
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
    37
    cborutil,
37119
d4a2e0d5d042 procutil: bulk-replace util.std* to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36940
diff changeset
    38
    procutil,
d4a2e0d5d042 procutil: bulk-replace util.std* to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36940
diff changeset
    39
)
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
    40
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
    41
48946
642e31cb55f0 py3: use class X: instead of class X(object):
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
    42
class channeledoutput:
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
    43
    """
22561
1120b1e2f975 cmdserver: correct doc of channeledoutput
Yuya Nishihara <yuya@tcha.org>
parents: 21195
diff changeset
    44
    Write data to out in the following format:
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
    45
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
    46
    data length (unsigned int),
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
    47
    data
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
    48
    """
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
    49
22563
8cc5e673cac0 cmdserver: drop useless in_ attribute from channeledoutput
Yuya Nishihara <yuya@tcha.org>
parents: 22562
diff changeset
    50
    def __init__(self, out, channel):
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
    51
        self.out = out
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
    52
        self.channel = channel
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
    53
27415
f4ca33e33781 commandserver: implement name() to clarify channel is not a plain file
Yuya Nishihara <yuya@tcha.org>
parents: 27352
diff changeset
    54
    @property
f4ca33e33781 commandserver: implement name() to clarify channel is not a plain file
Yuya Nishihara <yuya@tcha.org>
parents: 27352
diff changeset
    55
    def name(self):
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
    56
        return b'<%c-channel>' % self.channel
27415
f4ca33e33781 commandserver: implement name() to clarify channel is not a plain file
Yuya Nishihara <yuya@tcha.org>
parents: 27352
diff changeset
    57
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
    58
    def write(self, data):
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
    59
        if not data:
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
    60
            return
30263
7f2313450e86 cmdserver: write channel header and payload by a single write() call
Yuya Nishihara <yuya@tcha.org>
parents: 29609
diff changeset
    61
        # single write() to guarantee the same atomicity as the underlying file
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
    62
        self.out.write(struct.pack(b'>cI', self.channel, len(data)) + data)
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
    63
        self.out.flush()
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
    64
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
    65
    def __getattr__(self, attr):
43506
9f70512ae2cf cleanup: remove pointless r-prefixes on single-quoted strings
Augie Fackler <augie@google.com>
parents: 43089
diff changeset
    66
        if attr in ('isatty', 'fileno', 'tell', 'seek'):
18174
56ef99fbd6f2 commandserver: clean up use of two-argument raise
Augie Fackler <raf@durin42.com>
parents: 17425
diff changeset
    67
            raise AttributeError(attr)
22563
8cc5e673cac0 cmdserver: drop useless in_ attribute from channeledoutput
Yuya Nishihara <yuya@tcha.org>
parents: 22562
diff changeset
    68
        return getattr(self.out, attr)
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
    69
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
    70
48946
642e31cb55f0 py3: use class X: instead of class X(object):
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
    71
class channeledmessage:
40589
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
    72
    """
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
    73
    Write encoded message and metadata to out in the following format:
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
    74
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
    75
    data length (unsigned int),
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
    76
    encoded message and metadata, as a flat key-value dict.
40590
83dd8c63a0c6 ui: extract helpers to write message with type or label
Yuya Nishihara <yuya@tcha.org>
parents: 40589
diff changeset
    77
83dd8c63a0c6 ui: extract helpers to write message with type or label
Yuya Nishihara <yuya@tcha.org>
parents: 40589
diff changeset
    78
    Each message should have 'type' attribute. Messages of unknown type
83dd8c63a0c6 ui: extract helpers to write message with type or label
Yuya Nishihara <yuya@tcha.org>
parents: 40589
diff changeset
    79
    should be ignored.
40589
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
    80
    """
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
    81
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
    82
    # teach ui that write() can take **opts
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
    83
    structured = True
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
    84
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
    85
    def __init__(self, out, channel, encodename, encodefn):
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
    86
        self._cout = channeledoutput(out, channel)
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
    87
        self.encoding = encodename
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
    88
        self._encodefn = encodefn
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
    89
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
    90
    def write(self, data, **opts):
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
    91
        opts = pycompat.byteskwargs(opts)
40594
234c2d8c9e48 commandserver: send raw progress information to message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40590
diff changeset
    92
        if data is not None:
234c2d8c9e48 commandserver: send raw progress information to message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40590
diff changeset
    93
            opts[b'data'] = data
40589
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
    94
        self._cout.write(self._encodefn(opts))
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
    95
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
    96
    def __getattr__(self, attr):
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
    97
        return getattr(self._cout, attr)
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
    98
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
    99
48946
642e31cb55f0 py3: use class X: instead of class X(object):
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
   100
class channeledinput:
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   101
    """
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   102
    Read data from in_.
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   103
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   104
    Requests for input are written to out in the following format:
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   105
    channel identifier - 'I' for plain input, 'L' line based (1 byte)
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   106
    how many bytes to send at most (unsigned int),
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   107
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   108
    The client replies with:
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   109
    data length (unsigned int), 0 meaning EOF
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   110
    data
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   111
    """
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   112
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   113
    maxchunksize = 4 * 1024
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   114
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   115
    def __init__(self, in_, out, channel):
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   116
        self.in_ = in_
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   117
        self.out = out
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   118
        self.channel = channel
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   119
27415
f4ca33e33781 commandserver: implement name() to clarify channel is not a plain file
Yuya Nishihara <yuya@tcha.org>
parents: 27352
diff changeset
   120
    @property
f4ca33e33781 commandserver: implement name() to clarify channel is not a plain file
Yuya Nishihara <yuya@tcha.org>
parents: 27352
diff changeset
   121
    def name(self):
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   122
        return b'<%c-channel>' % self.channel
27415
f4ca33e33781 commandserver: implement name() to clarify channel is not a plain file
Yuya Nishihara <yuya@tcha.org>
parents: 27352
diff changeset
   123
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   124
    def read(self, size=-1):
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   125
        if size < 0:
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   126
            # if we need to consume all the clients input, ask for 4k chunks
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   127
            # so the pipe doesn't fill up risking a deadlock
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   128
            size = self.maxchunksize
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   129
            s = self._read(size, self.channel)
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   130
            buf = s
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   131
            while s:
14728
350dcd481410 cmdserver: fix read-loop string concatenation
Idan Kamara <idankk86@gmail.com>
parents: 14719
diff changeset
   132
                s = self._read(size, self.channel)
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   133
                buf += s
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   134
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   135
            return buf
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   136
        else:
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   137
            return self._read(size, self.channel)
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   138
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   139
    def _read(self, size, channel):
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   140
        if not size:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   141
            return b''
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   142
        assert size > 0
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   143
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   144
        # tell the client we need at most size bytes
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   145
        self.out.write(struct.pack(b'>cI', channel, size))
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   146
        self.out.flush()
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   147
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   148
        length = self.in_.read(4)
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   149
        length = struct.unpack(b'>I', length)[0]
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   150
        if not length:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   151
            return b''
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   152
        else:
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   153
            return self.in_.read(length)
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   154
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   155
    def readline(self, size=-1):
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   156
        if size < 0:
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   157
            size = self.maxchunksize
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   158
            s = self._read(size, b'L')
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   159
            buf = s
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   160
            # keep asking for more until there's either no more or
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   161
            # we got a full line
44373
98c14f0108b8 py3: fix EOL detection in commandserver.channeledinput
Yuya Nishihara <yuya@tcha.org>
parents: 43506
diff changeset
   162
            while s and not s.endswith(b'\n'):
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   163
                s = self._read(size, b'L')
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   164
                buf += s
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   165
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   166
            return buf
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   167
        else:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   168
            return self._read(size, b'L')
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   169
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   170
    def __iter__(self):
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   171
        return self
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   172
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   173
    def next(self):
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   174
        l = self.readline()
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   175
        if not l:
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   176
            raise StopIteration
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   177
        return l
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   178
40358
afbfcc4e3473 py3: alias next to __next__ in commandserver.py
Yuya Nishihara <yuya@tcha.org>
parents: 40357
diff changeset
   179
    __next__ = next
afbfcc4e3473 py3: alias next to __next__ in commandserver.py
Yuya Nishihara <yuya@tcha.org>
parents: 40357
diff changeset
   180
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   181
    def __getattr__(self, attr):
43506
9f70512ae2cf cleanup: remove pointless r-prefixes on single-quoted strings
Augie Fackler <augie@google.com>
parents: 43089
diff changeset
   182
        if attr in ('isatty', 'fileno', 'tell', 'seek'):
18174
56ef99fbd6f2 commandserver: clean up use of two-argument raise
Augie Fackler <raf@durin42.com>
parents: 17425
diff changeset
   183
            raise AttributeError(attr)
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   184
        return getattr(self.in_, attr)
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   185
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   186
40589
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
   187
_messageencoders = {
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
   188
    b'cbor': lambda v: b''.join(cborutil.streamencode(v)),
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
   189
}
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
   190
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   191
40589
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
   192
def _selectmessageencoder(ui):
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
   193
    encnames = ui.configlist(b'cmdserver', b'message-encodings')
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
   194
    for n in encnames:
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
   195
        f = _messageencoders.get(n)
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
   196
        if f:
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
   197
            return n, f
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   198
    raise error.Abort(
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   199
        b'no supported message encodings: %s' % b' '.join(encnames)
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   200
    )
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   201
40589
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
   202
48946
642e31cb55f0 py3: use class X: instead of class X(object):
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
   203
class server:
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   204
    """
22990
a0e81aa94125 cmdserver: make server streams switchable
Yuya Nishihara <yuya@tcha.org>
parents: 22989
diff changeset
   205
    Listens for commands on fin, runs them and writes the output on a channel
a0e81aa94125 cmdserver: make server streams switchable
Yuya Nishihara <yuya@tcha.org>
parents: 22989
diff changeset
   206
    based stream to fout.
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   207
    """
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   208
40875
e7110f44ee2d commandserver: pass around option to hook repo instance creation
Yuya Nishihara <yuya@tcha.org>
parents: 40828
diff changeset
   209
    def __init__(self, ui, repo, fin, fout, prereposetups=None):
39818
24e493ec2229 py3: rename pycompat.getcwd() to encoding.getcwd() (API)
Matt Harbison <matt_harbison@yahoo.com>
parents: 38768
diff changeset
   210
        self.cwd = encoding.getcwd()
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   211
20650
e811b93f2cb1 cmdserver: allow to start server without repository
Yuya Nishihara <yuya@tcha.org>
parents: 20631
diff changeset
   212
        if repo:
e811b93f2cb1 cmdserver: allow to start server without repository
Yuya Nishihara <yuya@tcha.org>
parents: 20631
diff changeset
   213
            # the ui here is really the repo ui so take its baseui so we don't
e811b93f2cb1 cmdserver: allow to start server without repository
Yuya Nishihara <yuya@tcha.org>
parents: 20631
diff changeset
   214
            # end up with its local configuration
e811b93f2cb1 cmdserver: allow to start server without repository
Yuya Nishihara <yuya@tcha.org>
parents: 20631
diff changeset
   215
            self.ui = repo.baseui
e811b93f2cb1 cmdserver: allow to start server without repository
Yuya Nishihara <yuya@tcha.org>
parents: 20631
diff changeset
   216
            self.repo = repo
e811b93f2cb1 cmdserver: allow to start server without repository
Yuya Nishihara <yuya@tcha.org>
parents: 20631
diff changeset
   217
            self.repoui = repo.ui
e811b93f2cb1 cmdserver: allow to start server without repository
Yuya Nishihara <yuya@tcha.org>
parents: 20631
diff changeset
   218
        else:
e811b93f2cb1 cmdserver: allow to start server without repository
Yuya Nishihara <yuya@tcha.org>
parents: 20631
diff changeset
   219
            self.ui = ui
e811b93f2cb1 cmdserver: allow to start server without repository
Yuya Nishihara <yuya@tcha.org>
parents: 20631
diff changeset
   220
            self.repo = self.repoui = None
40875
e7110f44ee2d commandserver: pass around option to hook repo instance creation
Yuya Nishihara <yuya@tcha.org>
parents: 40828
diff changeset
   221
        self._prereposetups = prereposetups
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   222
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   223
        self.cdebug = channeledoutput(fout, b'd')
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   224
        self.cerr = channeledoutput(fout, b'e')
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   225
        self.cout = channeledoutput(fout, b'o')
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   226
        self.cin = channeledinput(fin, fout, b'I')
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   227
        self.cresult = channeledoutput(fout, b'r')
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   228
40824
82210d88d814 commandserver: install logger to record server events through canonical API
Yuya Nishihara <yuya@tcha.org>
parents: 40823
diff changeset
   229
        if self.ui.config(b'cmdserver', b'log') == b'-':
82210d88d814 commandserver: install logger to record server events through canonical API
Yuya Nishihara <yuya@tcha.org>
parents: 40823
diff changeset
   230
            # switch log stream of server's ui to the 'd' (debug) channel
82210d88d814 commandserver: install logger to record server events through canonical API
Yuya Nishihara <yuya@tcha.org>
parents: 40823
diff changeset
   231
            # (don't touch repo.ui as its lifetime is longer than the server)
82210d88d814 commandserver: install logger to record server events through canonical API
Yuya Nishihara <yuya@tcha.org>
parents: 40823
diff changeset
   232
            self.ui = self.ui.copy()
82210d88d814 commandserver: install logger to record server events through canonical API
Yuya Nishihara <yuya@tcha.org>
parents: 40823
diff changeset
   233
            setuplogging(self.ui, repo=None, fp=self.cdebug)
82210d88d814 commandserver: install logger to record server events through canonical API
Yuya Nishihara <yuya@tcha.org>
parents: 40823
diff changeset
   234
40589
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
   235
        self.cmsg = None
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
   236
        if ui.config(b'ui', b'message-output') == b'channel':
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
   237
            encname, encfn = _selectmessageencoder(ui)
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
   238
            self.cmsg = channeledmessage(fout, b'm', encname, encfn)
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
   239
22990
a0e81aa94125 cmdserver: make server streams switchable
Yuya Nishihara <yuya@tcha.org>
parents: 22989
diff changeset
   240
        self.client = fin
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   241
45057
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   242
        # If shutdown-on-interrupt is off, the default SIGINT handler is
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   243
        # removed so that client-server communication wouldn't be interrupted.
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   244
        # For example, 'runcommand' handler will issue three short read()s.
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   245
        # If one of the first two read()s were interrupted, the communication
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   246
        # channel would be left at dirty state and the subsequent request
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   247
        # wouldn't be parsed. So catching KeyboardInterrupt isn't enough.
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   248
        self._shutdown_on_interrupt = ui.configbool(
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   249
            b'cmdserver', b'shutdown-on-interrupt'
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   250
        )
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   251
        self._old_inthandler = None
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   252
        if not self._shutdown_on_interrupt:
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   253
            self._old_inthandler = signal.signal(signal.SIGINT, signal.SIG_IGN)
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   254
29512
538d0003c9e0 commandserver: promote .cleanup() hook from chgserver
Yuya Nishihara <yuya@tcha.org>
parents: 29511
diff changeset
   255
    def cleanup(self):
538d0003c9e0 commandserver: promote .cleanup() hook from chgserver
Yuya Nishihara <yuya@tcha.org>
parents: 29511
diff changeset
   256
        """release and restore resources taken during server session"""
45057
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   257
        if not self._shutdown_on_interrupt:
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   258
            signal.signal(signal.SIGINT, self._old_inthandler)
29512
538d0003c9e0 commandserver: promote .cleanup() hook from chgserver
Yuya Nishihara <yuya@tcha.org>
parents: 29511
diff changeset
   259
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   260
    def _read(self, size):
14706
5fd5dd9a610a cmdserver: don't raise EOFError when trying to read 0 bytes from the client
Idan Kamara <idankk86@gmail.com>
parents: 14647
diff changeset
   261
        if not size:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   262
            return b''
14706
5fd5dd9a610a cmdserver: don't raise EOFError when trying to read 0 bytes from the client
Idan Kamara <idankk86@gmail.com>
parents: 14647
diff changeset
   263
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   264
        data = self.client.read(size)
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   265
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   266
        # is the other end closed?
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   267
        if not data:
16687
e34106fa0dc3 cleanup: "raise SomeException()" -> "raise SomeException"
Brodie Rao <brodie@sf.io>
parents: 16683
diff changeset
   268
            raise EOFError
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   269
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   270
        return data
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   271
28156
75f586a1bf55 commandserver: add _readstr and _readlist
Jun Wu <quark@fb.com>
parents: 28027
diff changeset
   272
    def _readstr(self):
75f586a1bf55 commandserver: add _readstr and _readlist
Jun Wu <quark@fb.com>
parents: 28027
diff changeset
   273
        """read a string from the channel
75f586a1bf55 commandserver: add _readstr and _readlist
Jun Wu <quark@fb.com>
parents: 28027
diff changeset
   274
75f586a1bf55 commandserver: add _readstr and _readlist
Jun Wu <quark@fb.com>
parents: 28027
diff changeset
   275
        format:
75f586a1bf55 commandserver: add _readstr and _readlist
Jun Wu <quark@fb.com>
parents: 28027
diff changeset
   276
        data length (uint32), data
75f586a1bf55 commandserver: add _readstr and _readlist
Jun Wu <quark@fb.com>
parents: 28027
diff changeset
   277
        """
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   278
        length = struct.unpack(b'>I', self._read(4))[0]
28156
75f586a1bf55 commandserver: add _readstr and _readlist
Jun Wu <quark@fb.com>
parents: 28027
diff changeset
   279
        if not length:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   280
            return b''
28156
75f586a1bf55 commandserver: add _readstr and _readlist
Jun Wu <quark@fb.com>
parents: 28027
diff changeset
   281
        return self._read(length)
75f586a1bf55 commandserver: add _readstr and _readlist
Jun Wu <quark@fb.com>
parents: 28027
diff changeset
   282
75f586a1bf55 commandserver: add _readstr and _readlist
Jun Wu <quark@fb.com>
parents: 28027
diff changeset
   283
    def _readlist(self):
75f586a1bf55 commandserver: add _readstr and _readlist
Jun Wu <quark@fb.com>
parents: 28027
diff changeset
   284
        """read a list of NULL separated strings from the channel"""
75f586a1bf55 commandserver: add _readstr and _readlist
Jun Wu <quark@fb.com>
parents: 28027
diff changeset
   285
        s = self._readstr()
75f586a1bf55 commandserver: add _readstr and _readlist
Jun Wu <quark@fb.com>
parents: 28027
diff changeset
   286
        if s:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   287
            return s.split(b'\0')
28156
75f586a1bf55 commandserver: add _readstr and _readlist
Jun Wu <quark@fb.com>
parents: 28027
diff changeset
   288
        else:
75f586a1bf55 commandserver: add _readstr and _readlist
Jun Wu <quark@fb.com>
parents: 28027
diff changeset
   289
            return []
75f586a1bf55 commandserver: add _readstr and _readlist
Jun Wu <quark@fb.com>
parents: 28027
diff changeset
   290
45057
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   291
    def _dispatchcommand(self, req):
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   292
        from . import dispatch  # avoid cycle
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   293
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   294
        if self._shutdown_on_interrupt:
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   295
            # no need to restore SIGINT handler as it is unmodified.
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   296
            return dispatch.dispatch(req)
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   297
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   298
        try:
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   299
            signal.signal(signal.SIGINT, self._old_inthandler)
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   300
            return dispatch.dispatch(req)
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   301
        except error.SignalInterrupt:
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   302
            # propagate SIGBREAK, SIGHUP, or SIGTERM.
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   303
            raise
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   304
        except KeyboardInterrupt:
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   305
            # SIGINT may be received out of the try-except block of dispatch(),
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   306
            # so catch it as last ditch. Another KeyboardInterrupt may be
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   307
            # raised while handling exceptions here, but there's no way to
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   308
            # avoid that except for doing everything in C.
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   309
            pass
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   310
        finally:
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   311
            signal.signal(signal.SIGINT, signal.SIG_IGN)
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   312
        # On KeyboardInterrupt, print error message and exit *after* SIGINT
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   313
        # handler removed.
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   314
        req.ui.error(_(b'interrupted!\n'))
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   315
        return -1
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   316
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   317
    def runcommand(self):
45942
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 45682
diff changeset
   318
        """reads a list of \0 terminated arguments, executes
89a2afe31e82 formating: upgrade to black 20.8b1
Augie Fackler <raf@durin42.com>
parents: 45682
diff changeset
   319
        and writes the return code to the result channel"""
27352
9fd8f1552369 commandserver: cut import cycle by itself
Yuya Nishihara <yuya@tcha.org>
parents: 27351
diff changeset
   320
        from . import dispatch  # avoid cycle
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   321
28157
e7c9b59dbbcf commandserver: use _readlist
Jun Wu <quark@fb.com>
parents: 28156
diff changeset
   322
        args = self._readlist()
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   323
14750
f5f97a0f983f cmdserver: copy repo.ui before running commands
Idan Kamara <idankk86@gmail.com>
parents: 14728
diff changeset
   324
        # copy the uis so changes (e.g. --config or --verbose) don't
f5f97a0f983f cmdserver: copy repo.ui before running commands
Idan Kamara <idankk86@gmail.com>
parents: 14728
diff changeset
   325
        # persist between requests
14751
712954a67be3 cmdserver: assign repo.baseui before running commands
Idan Kamara <idankk86@gmail.com>
parents: 14750
diff changeset
   326
        copiedui = self.ui.copy()
21195
9336bc7dca8e cmdserver: forcibly use L channel to read password input (issue3161)
Yuya Nishihara <yuya@tcha.org>
parents: 20650
diff changeset
   327
        uis = [copiedui]
20650
e811b93f2cb1 cmdserver: allow to start server without repository
Yuya Nishihara <yuya@tcha.org>
parents: 20631
diff changeset
   328
        if self.repo:
e811b93f2cb1 cmdserver: allow to start server without repository
Yuya Nishihara <yuya@tcha.org>
parents: 20631
diff changeset
   329
            self.repo.baseui = copiedui
e811b93f2cb1 cmdserver: allow to start server without repository
Yuya Nishihara <yuya@tcha.org>
parents: 20631
diff changeset
   330
            # clone ui without using ui.copy because this is protected
e811b93f2cb1 cmdserver: allow to start server without repository
Yuya Nishihara <yuya@tcha.org>
parents: 20631
diff changeset
   331
            repoui = self.repoui.__class__(self.repoui)
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   332
            repoui.copy = copiedui.copy  # redo copy protection
21195
9336bc7dca8e cmdserver: forcibly use L channel to read password input (issue3161)
Yuya Nishihara <yuya@tcha.org>
parents: 20650
diff changeset
   333
            uis.append(repoui)
20650
e811b93f2cb1 cmdserver: allow to start server without repository
Yuya Nishihara <yuya@tcha.org>
parents: 20631
diff changeset
   334
            self.repo.ui = self.repo.dirstate._ui = repoui
e811b93f2cb1 cmdserver: allow to start server without repository
Yuya Nishihara <yuya@tcha.org>
parents: 20631
diff changeset
   335
            self.repo.invalidateall()
14751
712954a67be3 cmdserver: assign repo.baseui before running commands
Idan Kamara <idankk86@gmail.com>
parents: 14750
diff changeset
   336
21195
9336bc7dca8e cmdserver: forcibly use L channel to read password input (issue3161)
Yuya Nishihara <yuya@tcha.org>
parents: 20650
diff changeset
   337
        for ui in uis:
29366
d269e7db2f55 ui: provide official way to reset internal state per command
Yuya Nishihara <yuya@tcha.org>
parents: 28511
diff changeset
   338
            ui.resetstate()
27565
e7937438e3f7 commandserver: do not set nontty flag if channel is replaced by a real file
Yuya Nishihara <yuya@tcha.org>
parents: 27415
diff changeset
   339
            # any kind of interaction must use server channels, but chg may
e7937438e3f7 commandserver: do not set nontty flag if channel is replaced by a real file
Yuya Nishihara <yuya@tcha.org>
parents: 27415
diff changeset
   340
            # replace channels by fully functional tty files. so nontty is
e7937438e3f7 commandserver: do not set nontty flag if channel is replaced by a real file
Yuya Nishihara <yuya@tcha.org>
parents: 27415
diff changeset
   341
            # enforced only if cin is a channel.
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   342
            if not util.safehasattr(self.cin, b'fileno'):
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   343
                ui.setconfig(b'ui', b'nontty', b'true', b'commandserver')
21195
9336bc7dca8e cmdserver: forcibly use L channel to read password input (issue3161)
Yuya Nishihara <yuya@tcha.org>
parents: 20650
diff changeset
   344
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   345
        req = dispatch.request(
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   346
            args[:],
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   347
            copiedui,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   348
            self.repo,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   349
            self.cin,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   350
            self.cout,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   351
            self.cerr,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   352
            self.cmsg,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   353
            prereposetups=self._prereposetups,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   354
        )
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   355
35652
40da2d7b4871 commandserver: restore cwd in case of exception
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35461
diff changeset
   356
        try:
46101
49b6910217f9 dispatch: move IOError handling and flushing of streams to `dispatch()`
Pulkit Goyal <7895pulkit@gmail.com>
parents: 46086
diff changeset
   357
            ret = self._dispatchcommand(req) & 255
45057
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   358
            # If shutdown-on-interrupt is off, it's important to write the
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   359
            # result code *after* SIGINT handler removed. If the result code
d6e99a446eea cmdserver: add option to not exit from message loop on SIGINT
Yuya Nishihara <yuya@tcha.org>
parents: 44374
diff changeset
   360
            # were lost, the client wouldn't be able to continue processing.
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   361
            self.cresult.write(struct.pack(b'>i', int(ret)))
35652
40da2d7b4871 commandserver: restore cwd in case of exception
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35461
diff changeset
   362
        finally:
40da2d7b4871 commandserver: restore cwd in case of exception
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35461
diff changeset
   363
            # restore old cwd
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   364
            if b'--cwd' in args:
35652
40da2d7b4871 commandserver: restore cwd in case of exception
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35461
diff changeset
   365
                os.chdir(self.cwd)
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   366
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   367
    def getencoding(self):
47062
f38bf44e077f black: make codebase compatible with black v21.4b2 and v20.8b1
Kyle Lippincott <spectral@google.com>
parents: 46819
diff changeset
   368
        """writes the current encoding to the result channel"""
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   369
        self.cresult.write(encoding.encoding)
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   370
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   371
    def serveone(self):
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   372
        cmd = self.client.readline()[:-1]
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   373
        if cmd:
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   374
            handler = self.capabilities.get(cmd)
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   375
            if handler:
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   376
                handler(self)
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   377
            else:
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   378
                # clients are expected to check what commands are supported by
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   379
                # looking at the servers capabilities
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   380
                raise error.Abort(_(b'unknown command %s') % cmd)
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   381
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   382
        return cmd != b''
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   383
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   384
    capabilities = {b'runcommand': runcommand, b'getencoding': getencoding}
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   385
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   386
    def serve(self):
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   387
        hellomsg = b'capabilities: ' + b' '.join(sorted(self.capabilities))
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   388
        hellomsg += b'\n'
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   389
        hellomsg += b'encoding: ' + encoding.encoding
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   390
        hellomsg += b'\n'
40589
054d0fcba2c4 commandserver: add experimental option to use separate message channel
Yuya Nishihara <yuya@tcha.org>
parents: 40588
diff changeset
   391
        if self.cmsg:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   392
            hellomsg += b'message-encoding: %s\n' % self.cmsg.encoding
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   393
        hellomsg += b'pid: %d' % procutil.getpid()
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   394
        if util.safehasattr(os, b'getpgid'):
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   395
            hellomsg += b'\n'
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   396
            hellomsg += b'pgid: %d' % os.getpgid(0)
14719
c19de7f32961 cmdserver: write the hello message as one chunk on the 'o' channel
Idan Kamara <idankk86@gmail.com>
parents: 14707
diff changeset
   397
c19de7f32961 cmdserver: write the hello message as one chunk on the 'o' channel
Idan Kamara <idankk86@gmail.com>
parents: 14707
diff changeset
   398
        # write the hello msg in -one- chunk
c19de7f32961 cmdserver: write the hello message as one chunk on the 'o' channel
Idan Kamara <idankk86@gmail.com>
parents: 14707
diff changeset
   399
        self.cout.write(hellomsg)
14647
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   400
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   401
        try:
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   402
            while self.serveone():
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   403
                pass
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   404
        except EOFError:
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   405
            # we'll get here if the client disconnected while we were reading
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   406
            # its request
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   407
            return 1
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   408
2e9f379de0ac serve: add --cmdserver option to communicate with hg over a pipe
Idan Kamara <idankk86@gmail.com>
parents:
diff changeset
   409
        return 0
22988
32b77aba2772 cmdserver: wrap 'pipe' mode server by service object
Yuya Nishihara <yuya@tcha.org>
parents: 22563
diff changeset
   410
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   411
40824
82210d88d814 commandserver: install logger to record server events through canonical API
Yuya Nishihara <yuya@tcha.org>
parents: 40823
diff changeset
   412
def setuplogging(ui, repo=None, fp=None):
40823
368ecbf734af commandserver: enable logging when server process started
Yuya Nishihara <yuya@tcha.org>
parents: 40819
diff changeset
   413
    """Set up server logging facility
368ecbf734af commandserver: enable logging when server process started
Yuya Nishihara <yuya@tcha.org>
parents: 40819
diff changeset
   414
40824
82210d88d814 commandserver: install logger to record server events through canonical API
Yuya Nishihara <yuya@tcha.org>
parents: 40823
diff changeset
   415
    If cmdserver.log is '-', log messages will be sent to the given fp.
82210d88d814 commandserver: install logger to record server events through canonical API
Yuya Nishihara <yuya@tcha.org>
parents: 40823
diff changeset
   416
    It should be the 'd' channel while a client is connected, and otherwise
82210d88d814 commandserver: install logger to record server events through canonical API
Yuya Nishihara <yuya@tcha.org>
parents: 40823
diff changeset
   417
    is the stderr of the server process.
40823
368ecbf734af commandserver: enable logging when server process started
Yuya Nishihara <yuya@tcha.org>
parents: 40819
diff changeset
   418
    """
368ecbf734af commandserver: enable logging when server process started
Yuya Nishihara <yuya@tcha.org>
parents: 40819
diff changeset
   419
    # developer config: cmdserver.log
368ecbf734af commandserver: enable logging when server process started
Yuya Nishihara <yuya@tcha.org>
parents: 40819
diff changeset
   420
    logpath = ui.config(b'cmdserver', b'log')
368ecbf734af commandserver: enable logging when server process started
Yuya Nishihara <yuya@tcha.org>
parents: 40819
diff changeset
   421
    if not logpath:
368ecbf734af commandserver: enable logging when server process started
Yuya Nishihara <yuya@tcha.org>
parents: 40819
diff changeset
   422
        return
40827
d23fd01cc115 commandserver: add config knob for various logging options
Yuya Nishihara <yuya@tcha.org>
parents: 40826
diff changeset
   423
    # developer config: cmdserver.track-log
d23fd01cc115 commandserver: add config knob for various logging options
Yuya Nishihara <yuya@tcha.org>
parents: 40826
diff changeset
   424
    tracked = set(ui.configlist(b'cmdserver', b'track-log'))
40823
368ecbf734af commandserver: enable logging when server process started
Yuya Nishihara <yuya@tcha.org>
parents: 40819
diff changeset
   425
40824
82210d88d814 commandserver: install logger to record server events through canonical API
Yuya Nishihara <yuya@tcha.org>
parents: 40823
diff changeset
   426
    if logpath == b'-' and fp:
82210d88d814 commandserver: install logger to record server events through canonical API
Yuya Nishihara <yuya@tcha.org>
parents: 40823
diff changeset
   427
        logger = loggingutil.fileobjectlogger(fp, tracked)
82210d88d814 commandserver: install logger to record server events through canonical API
Yuya Nishihara <yuya@tcha.org>
parents: 40823
diff changeset
   428
    elif logpath == b'-':
82210d88d814 commandserver: install logger to record server events through canonical API
Yuya Nishihara <yuya@tcha.org>
parents: 40823
diff changeset
   429
        logger = loggingutil.fileobjectlogger(ui.ferr, tracked)
82210d88d814 commandserver: install logger to record server events through canonical API
Yuya Nishihara <yuya@tcha.org>
parents: 40823
diff changeset
   430
    else:
47624
27e75b8bf784 windows: use abspath in commandserver
Pierre-Yves David <pierre-yves.david@octobus.net>
parents: 47062
diff changeset
   431
        logpath = util.abspath(util.expandpath(logpath))
40827
d23fd01cc115 commandserver: add config knob for various logging options
Yuya Nishihara <yuya@tcha.org>
parents: 40826
diff changeset
   432
        # developer config: cmdserver.max-log-files
d23fd01cc115 commandserver: add config knob for various logging options
Yuya Nishihara <yuya@tcha.org>
parents: 40826
diff changeset
   433
        maxfiles = ui.configint(b'cmdserver', b'max-log-files')
d23fd01cc115 commandserver: add config knob for various logging options
Yuya Nishihara <yuya@tcha.org>
parents: 40826
diff changeset
   434
        # developer config: cmdserver.max-log-size
d23fd01cc115 commandserver: add config knob for various logging options
Yuya Nishihara <yuya@tcha.org>
parents: 40826
diff changeset
   435
        maxsize = ui.configbytes(b'cmdserver', b'max-log-size')
40824
82210d88d814 commandserver: install logger to record server events through canonical API
Yuya Nishihara <yuya@tcha.org>
parents: 40823
diff changeset
   436
        vfs = vfsmod.vfs(os.path.dirname(logpath))
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   437
        logger = loggingutil.filelogger(
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   438
            vfs,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   439
            os.path.basename(logpath),
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   440
            tracked,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   441
            maxfiles=maxfiles,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   442
            maxsize=maxsize,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   443
        )
40824
82210d88d814 commandserver: install logger to record server events through canonical API
Yuya Nishihara <yuya@tcha.org>
parents: 40823
diff changeset
   444
82210d88d814 commandserver: install logger to record server events through canonical API
Yuya Nishihara <yuya@tcha.org>
parents: 40823
diff changeset
   445
    targetuis = {ui}
82210d88d814 commandserver: install logger to record server events through canonical API
Yuya Nishihara <yuya@tcha.org>
parents: 40823
diff changeset
   446
    if repo:
82210d88d814 commandserver: install logger to record server events through canonical API
Yuya Nishihara <yuya@tcha.org>
parents: 40823
diff changeset
   447
        targetuis.add(repo.baseui)
82210d88d814 commandserver: install logger to record server events through canonical API
Yuya Nishihara <yuya@tcha.org>
parents: 40823
diff changeset
   448
        targetuis.add(repo.ui)
82210d88d814 commandserver: install logger to record server events through canonical API
Yuya Nishihara <yuya@tcha.org>
parents: 40823
diff changeset
   449
    for u in targetuis:
82210d88d814 commandserver: install logger to record server events through canonical API
Yuya Nishihara <yuya@tcha.org>
parents: 40823
diff changeset
   450
        u.setlogger(b'cmdserver', logger)
82210d88d814 commandserver: install logger to record server events through canonical API
Yuya Nishihara <yuya@tcha.org>
parents: 40823
diff changeset
   451
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   452
48946
642e31cb55f0 py3: use class X: instead of class X(object):
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
   453
class pipeservice:
22988
32b77aba2772 cmdserver: wrap 'pipe' mode server by service object
Yuya Nishihara <yuya@tcha.org>
parents: 22563
diff changeset
   454
    def __init__(self, ui, repo, opts):
23323
bc374458688b cmdserver: postpone creation of pipe server until run()
Yuya Nishihara <yuya@tcha.org>
parents: 23322
diff changeset
   455
        self.ui = ui
bc374458688b cmdserver: postpone creation of pipe server until run()
Yuya Nishihara <yuya@tcha.org>
parents: 23322
diff changeset
   456
        self.repo = repo
22988
32b77aba2772 cmdserver: wrap 'pipe' mode server by service object
Yuya Nishihara <yuya@tcha.org>
parents: 22563
diff changeset
   457
32b77aba2772 cmdserver: wrap 'pipe' mode server by service object
Yuya Nishihara <yuya@tcha.org>
parents: 22563
diff changeset
   458
    def init(self):
32b77aba2772 cmdserver: wrap 'pipe' mode server by service object
Yuya Nishihara <yuya@tcha.org>
parents: 22563
diff changeset
   459
        pass
32b77aba2772 cmdserver: wrap 'pipe' mode server by service object
Yuya Nishihara <yuya@tcha.org>
parents: 22563
diff changeset
   460
32b77aba2772 cmdserver: wrap 'pipe' mode server by service object
Yuya Nishihara <yuya@tcha.org>
parents: 22563
diff changeset
   461
    def run(self):
23323
bc374458688b cmdserver: postpone creation of pipe server until run()
Yuya Nishihara <yuya@tcha.org>
parents: 23322
diff changeset
   462
        ui = self.ui
23324
69f86b937035 cmdserver: protect pipe server streams against corruption caused by direct io
Yuya Nishihara <yuya@tcha.org>
parents: 23323
diff changeset
   463
        # redirect stdio to null device so that broken extensions or in-process
69f86b937035 cmdserver: protect pipe server streams against corruption caused by direct io
Yuya Nishihara <yuya@tcha.org>
parents: 23323
diff changeset
   464
        # hooks will never cause corruption of channel protocol.
41284
b0e3f2d7c143 ui: move protectedstdio() context manager from procutil
Yuya Nishihara <yuya@tcha.org>
parents: 40999
diff changeset
   465
        with ui.protectedfinout() as (fin, fout):
40588
9683dfb6f13a commandserver: fix reference before assignment error in pipeservice cleanup
Yuya Nishihara <yuya@tcha.org>
parents: 40361
diff changeset
   466
            sv = server(ui, self.repo, fin, fout)
37124
6715e8035b4f procutil: introduce context-manager interface for protect/restorestdio
Yuya Nishihara <yuya@tcha.org>
parents: 37123
diff changeset
   467
            try:
6715e8035b4f procutil: introduce context-manager interface for protect/restorestdio
Yuya Nishihara <yuya@tcha.org>
parents: 37123
diff changeset
   468
                return sv.serve()
6715e8035b4f procutil: introduce context-manager interface for protect/restorestdio
Yuya Nishihara <yuya@tcha.org>
parents: 37123
diff changeset
   469
            finally:
6715e8035b4f procutil: introduce context-manager interface for protect/restorestdio
Yuya Nishihara <yuya@tcha.org>
parents: 37123
diff changeset
   470
                sv.cleanup()
22989
dc8803ce3dfe cmdserver: switch service objects by mode
Yuya Nishihara <yuya@tcha.org>
parents: 22988
diff changeset
   471
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   472
29586
42cdba9cfee4 commandserver: separate initialization and cleanup of forked process
Yuya Nishihara <yuya@tcha.org>
parents: 29585
diff changeset
   473
def _initworkerprocess():
29609
591c3badff2e commandserver: update comment about setpgid
Jun Wu <quark@fb.com>
parents: 29588
diff changeset
   474
    # use a different process group from the master process, in order to:
591c3badff2e commandserver: update comment about setpgid
Jun Wu <quark@fb.com>
parents: 29588
diff changeset
   475
    # 1. make the current process group no longer "orphaned" (because the
591c3badff2e commandserver: update comment about setpgid
Jun Wu <quark@fb.com>
parents: 29588
diff changeset
   476
    #    parent of this process is in a different process group while
591c3badff2e commandserver: update comment about setpgid
Jun Wu <quark@fb.com>
parents: 29588
diff changeset
   477
    #    remains in a same session)
591c3badff2e commandserver: update comment about setpgid
Jun Wu <quark@fb.com>
parents: 29588
diff changeset
   478
    #    according to POSIX 2.2.2.52, orphaned process group will ignore
591c3badff2e commandserver: update comment about setpgid
Jun Wu <quark@fb.com>
parents: 29588
diff changeset
   479
    #    terminal-generated stop signals like SIGTSTP (Ctrl+Z), which will
591c3badff2e commandserver: update comment about setpgid
Jun Wu <quark@fb.com>
parents: 29588
diff changeset
   480
    #    cause trouble for things like ncurses.
591c3badff2e commandserver: update comment about setpgid
Jun Wu <quark@fb.com>
parents: 29588
diff changeset
   481
    # 2. the client can use kill(-pgid, sig) to simulate terminal-generated
591c3badff2e commandserver: update comment about setpgid
Jun Wu <quark@fb.com>
parents: 29588
diff changeset
   482
    #    SIGINT (Ctrl+C) and process-exit-generated SIGHUP. our child
591c3badff2e commandserver: update comment about setpgid
Jun Wu <quark@fb.com>
parents: 29588
diff changeset
   483
    #    processes like ssh will be killed properly, without affecting
591c3badff2e commandserver: update comment about setpgid
Jun Wu <quark@fb.com>
parents: 29588
diff changeset
   484
    #    unrelated processes.
29585
6ed452d0f1f1 commandserver: unindent superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 29580
diff changeset
   485
    os.setpgid(0, 0)
6ed452d0f1f1 commandserver: unindent superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 29580
diff changeset
   486
    # change random state otherwise forked request handlers would have a
6ed452d0f1f1 commandserver: unindent superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 29580
diff changeset
   487
    # same state inherited from parent.
6ed452d0f1f1 commandserver: unindent superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 29580
diff changeset
   488
    random.seed()
29542
6011ad3b0a42 commandserver: manually create file objects from socket
Yuya Nishihara <yuya@tcha.org>
parents: 29532
diff changeset
   489
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   490
40875
e7110f44ee2d commandserver: pass around option to hook repo instance creation
Yuya Nishihara <yuya@tcha.org>
parents: 40828
diff changeset
   491
def _serverequest(ui, repo, conn, createcmdserver, prereposetups):
43506
9f70512ae2cf cleanup: remove pointless r-prefixes on single-quoted strings
Augie Fackler <augie@google.com>
parents: 43089
diff changeset
   492
    fin = conn.makefile('rb')
9f70512ae2cf cleanup: remove pointless r-prefixes on single-quoted strings
Augie Fackler <augie@google.com>
parents: 43089
diff changeset
   493
    fout = conn.makefile('wb')
29585
6ed452d0f1f1 commandserver: unindent superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 29580
diff changeset
   494
    sv = None
6ed452d0f1f1 commandserver: unindent superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 29580
diff changeset
   495
    try:
40875
e7110f44ee2d commandserver: pass around option to hook repo instance creation
Yuya Nishihara <yuya@tcha.org>
parents: 40828
diff changeset
   496
        sv = createcmdserver(repo, conn, fin, fout, prereposetups)
22994
840be5ca03e1 cmdserver: add service that listens on unix domain socket and forks process
Yuya Nishihara <yuya@tcha.org>
parents: 22990
diff changeset
   497
        try:
29585
6ed452d0f1f1 commandserver: unindent superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 29580
diff changeset
   498
            sv.serve()
6ed452d0f1f1 commandserver: unindent superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 29580
diff changeset
   499
        # handle exceptions that may be raised by command server. most of
6ed452d0f1f1 commandserver: unindent superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 29580
diff changeset
   500
        # known exceptions are caught by dispatch.
6ed452d0f1f1 commandserver: unindent superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 29580
diff changeset
   501
        except error.Abort as inst:
45682
d2e1dcd4490d errors: name arguments to Abort constructor
Martin von Zweigbergk <martinvonz@google.com>
parents: 45058
diff changeset
   502
            ui.error(_(b'abort: %s\n') % inst.message)
29585
6ed452d0f1f1 commandserver: unindent superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 29580
diff changeset
   503
        except IOError as inst:
6ed452d0f1f1 commandserver: unindent superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 29580
diff changeset
   504
            if inst.errno != errno.EPIPE:
6ed452d0f1f1 commandserver: unindent superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 29580
diff changeset
   505
                raise
6ed452d0f1f1 commandserver: unindent superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 29580
diff changeset
   506
        except KeyboardInterrupt:
6ed452d0f1f1 commandserver: unindent superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 29580
diff changeset
   507
            pass
29513
e5b4d79a9140 commandserver: backport handling of forking server from chgserver
Yuya Nishihara <yuya@tcha.org>
parents: 29512
diff changeset
   508
        finally:
29585
6ed452d0f1f1 commandserver: unindent superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 29580
diff changeset
   509
            sv.cleanup()
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   510
    except:  # re-raises
29585
6ed452d0f1f1 commandserver: unindent superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 29580
diff changeset
   511
        # also write traceback to error channel. otherwise client cannot
6ed452d0f1f1 commandserver: unindent superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 29580
diff changeset
   512
        # see it because it is written to server's stderr by default.
6ed452d0f1f1 commandserver: unindent superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 29580
diff changeset
   513
        if sv:
6ed452d0f1f1 commandserver: unindent superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 29580
diff changeset
   514
            cerr = sv.cerr
6ed452d0f1f1 commandserver: unindent superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 29580
diff changeset
   515
        else:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   516
            cerr = channeledoutput(fout, b'e')
40361
b7de186efd82 py3: don't use traceback.print_exc() in commandserver.py
Yuya Nishihara <yuya@tcha.org>
parents: 40359
diff changeset
   517
        cerr.write(encoding.strtolocal(traceback.format_exc()))
29585
6ed452d0f1f1 commandserver: unindent superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 29580
diff changeset
   518
        raise
6ed452d0f1f1 commandserver: unindent superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 29580
diff changeset
   519
    finally:
6ed452d0f1f1 commandserver: unindent superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 29580
diff changeset
   520
        fin.close()
6ed452d0f1f1 commandserver: unindent superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 29580
diff changeset
   521
        try:
6ed452d0f1f1 commandserver: unindent superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 29580
diff changeset
   522
            fout.close()  # implicit flush() may cause another EPIPE
6ed452d0f1f1 commandserver: unindent superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 29580
diff changeset
   523
        except IOError as inst:
6ed452d0f1f1 commandserver: unindent superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 29580
diff changeset
   524
            if inst.errno != errno.EPIPE:
6ed452d0f1f1 commandserver: unindent superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 29580
diff changeset
   525
                raise
22994
840be5ca03e1 cmdserver: add service that listens on unix domain socket and forks process
Yuya Nishihara <yuya@tcha.org>
parents: 22990
diff changeset
   526
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   527
48946
642e31cb55f0 py3: use class X: instead of class X(object):
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
   528
class unixservicehandler:
29544
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   529
    """Set of pluggable operations for unix-mode services
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   530
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   531
    Almost all methods except for createcmdserver() are called in the main
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   532
    process. You can't pass mutable resource back from createcmdserver().
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   533
    """
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   534
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   535
    pollinterval = None
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   536
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   537
    def __init__(self, ui):
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   538
        self.ui = ui
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   539
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   540
    def bindsocket(self, sock, address):
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   541
        util.bindunixsocket(sock, address)
32236
c8b9943c07eb commandserver: move "listen" responsibility from service to handler
Jun Wu <quark@fb.com>
parents: 30924
diff changeset
   542
        sock.listen(socket.SOMAXCONN)
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   543
        self.ui.status(_(b'listening at %s\n') % address)
32237
1ada3d18e7fb commandserver: move printbanner logic to bindsocket
Jun Wu <quark@fb.com>
parents: 32236
diff changeset
   544
        self.ui.flush()  # avoid buffering of status message
29544
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   545
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   546
    def unlinksocket(self, address):
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   547
        os.unlink(address)
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   548
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   549
    def shouldexit(self):
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   550
        """True if server should shut down; checked per pollinterval"""
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   551
        return False
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   552
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   553
    def newconnection(self):
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   554
        """Called when main process notices new connection"""
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   555
40875
e7110f44ee2d commandserver: pass around option to hook repo instance creation
Yuya Nishihara <yuya@tcha.org>
parents: 40828
diff changeset
   556
    def createcmdserver(self, repo, conn, fin, fout, prereposetups):
29544
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   557
        """Create new command server instance; called in the process that
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   558
        serves for the current connection"""
40875
e7110f44ee2d commandserver: pass around option to hook repo instance creation
Yuya Nishihara <yuya@tcha.org>
parents: 40828
diff changeset
   559
        return server(self.ui, repo, fin, fout, prereposetups)
29544
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   560
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   561
48946
642e31cb55f0 py3: use class X: instead of class X(object):
Gregory Szorc <gregory.szorc@gmail.com>
parents: 48875
diff changeset
   562
class unixforkingservice:
22994
840be5ca03e1 cmdserver: add service that listens on unix domain socket and forks process
Yuya Nishihara <yuya@tcha.org>
parents: 22990
diff changeset
   563
    """
840be5ca03e1 cmdserver: add service that listens on unix domain socket and forks process
Yuya Nishihara <yuya@tcha.org>
parents: 22990
diff changeset
   564
    Listens on unix domain socket and forks server per connection
840be5ca03e1 cmdserver: add service that listens on unix domain socket and forks process
Yuya Nishihara <yuya@tcha.org>
parents: 22990
diff changeset
   565
    """
29548
9da1adc18639 commandserver: drop old unixservice implementation
Yuya Nishihara <yuya@tcha.org>
parents: 29544
diff changeset
   566
9da1adc18639 commandserver: drop old unixservice implementation
Yuya Nishihara <yuya@tcha.org>
parents: 29544
diff changeset
   567
    def __init__(self, ui, repo, opts, handler=None):
22994
840be5ca03e1 cmdserver: add service that listens on unix domain socket and forks process
Yuya Nishihara <yuya@tcha.org>
parents: 22990
diff changeset
   568
        self.ui = ui
840be5ca03e1 cmdserver: add service that listens on unix domain socket and forks process
Yuya Nishihara <yuya@tcha.org>
parents: 22990
diff changeset
   569
        self.repo = repo
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   570
        self.address = opts[b'address']
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   571
        if not util.safehasattr(socket, b'AF_UNIX'):
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   572
            raise error.Abort(_(b'unsupported platform'))
22994
840be5ca03e1 cmdserver: add service that listens on unix domain socket and forks process
Yuya Nishihara <yuya@tcha.org>
parents: 22990
diff changeset
   573
        if not self.address:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   574
            raise error.Abort(_(b'no socket path specified with --address'))
29544
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   575
        self._servicehandler = handler or unixservicehandler(ui)
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   576
        self._sock = None
40998
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   577
        self._mainipc = None
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   578
        self._workeripc = None
29544
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   579
        self._oldsigchldhandler = None
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   580
        self._workerpids = set()  # updated by signal handler; do not iterate
30887
a95fc01aaffe commandserver: prevent unlink socket twice
Jun Wu <quark@fb.com>
parents: 30519
diff changeset
   581
        self._socketunlinked = None
40999
dcac24ec935b commandserver: preload repository in master server and reuse its file cache
Yuya Nishihara <yuya@tcha.org>
parents: 40998
diff changeset
   582
        # experimental config: cmdserver.max-repo-cache
dcac24ec935b commandserver: preload repository in master server and reuse its file cache
Yuya Nishihara <yuya@tcha.org>
parents: 40998
diff changeset
   583
        maxlen = ui.configint(b'cmdserver', b'max-repo-cache')
dcac24ec935b commandserver: preload repository in master server and reuse its file cache
Yuya Nishihara <yuya@tcha.org>
parents: 40998
diff changeset
   584
        if maxlen < 0:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   585
            raise error.Abort(_(b'negative max-repo-cache size not allowed'))
40999
dcac24ec935b commandserver: preload repository in master server and reuse its file cache
Yuya Nishihara <yuya@tcha.org>
parents: 40998
diff changeset
   586
        self._repoloader = repocache.repoloader(ui, maxlen)
44368
6392bd7c26a8 darwin: add another preemptive gui() call when using chg
Kyle Lippincott <spectral@google.com>
parents: 43506
diff changeset
   587
        # attempt to avoid crash in CoreFoundation when using chg after fix in
6392bd7c26a8 darwin: add another preemptive gui() call when using chg
Kyle Lippincott <spectral@google.com>
parents: 43506
diff changeset
   588
        # a89381e04c58
6392bd7c26a8 darwin: add another preemptive gui() call when using chg
Kyle Lippincott <spectral@google.com>
parents: 43506
diff changeset
   589
        if pycompat.isdarwin:
6392bd7c26a8 darwin: add another preemptive gui() call when using chg
Kyle Lippincott <spectral@google.com>
parents: 43506
diff changeset
   590
            procutil.gui()
29544
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   591
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   592
    def init(self):
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   593
        self._sock = socket.socket(socket.AF_UNIX)
40998
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   594
        # IPC channel from many workers to one main process; this is actually
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   595
        # a uni-directional pipe, but is backed by a DGRAM socket so each
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   596
        # message can be easily separated.
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   597
        o = socket.socketpair(socket.AF_UNIX, socket.SOCK_DGRAM)
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   598
        self._mainipc, self._workeripc = o
29544
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   599
        self._servicehandler.bindsocket(self._sock, self.address)
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   600
        if util.safehasattr(procutil, b'unblocksignal'):
37120
a8a902d7176e procutil: bulk-replace function calls to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 37119
diff changeset
   601
            procutil.unblocksignal(signal.SIGCHLD)
29544
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   602
        o = signal.signal(signal.SIGCHLD, self._sigchldhandler)
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   603
        self._oldsigchldhandler = o
30887
a95fc01aaffe commandserver: prevent unlink socket twice
Jun Wu <quark@fb.com>
parents: 30519
diff changeset
   604
        self._socketunlinked = False
40999
dcac24ec935b commandserver: preload repository in master server and reuse its file cache
Yuya Nishihara <yuya@tcha.org>
parents: 40998
diff changeset
   605
        self._repoloader.start()
30887
a95fc01aaffe commandserver: prevent unlink socket twice
Jun Wu <quark@fb.com>
parents: 30519
diff changeset
   606
a95fc01aaffe commandserver: prevent unlink socket twice
Jun Wu <quark@fb.com>
parents: 30519
diff changeset
   607
    def _unlinksocket(self):
a95fc01aaffe commandserver: prevent unlink socket twice
Jun Wu <quark@fb.com>
parents: 30519
diff changeset
   608
        if not self._socketunlinked:
a95fc01aaffe commandserver: prevent unlink socket twice
Jun Wu <quark@fb.com>
parents: 30519
diff changeset
   609
            self._servicehandler.unlinksocket(self.address)
a95fc01aaffe commandserver: prevent unlink socket twice
Jun Wu <quark@fb.com>
parents: 30519
diff changeset
   610
            self._socketunlinked = True
29544
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   611
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   612
    def _cleanup(self):
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   613
        signal.signal(signal.SIGCHLD, self._oldsigchldhandler)
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   614
        self._sock.close()
40998
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   615
        self._mainipc.close()
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   616
        self._workeripc.close()
30887
a95fc01aaffe commandserver: prevent unlink socket twice
Jun Wu <quark@fb.com>
parents: 30519
diff changeset
   617
        self._unlinksocket()
40999
dcac24ec935b commandserver: preload repository in master server and reuse its file cache
Yuya Nishihara <yuya@tcha.org>
parents: 40998
diff changeset
   618
        self._repoloader.stop()
29544
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   619
        # don't kill child processes as they have active clients, just wait
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   620
        self._reapworkers(0)
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   621
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   622
    def run(self):
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   623
        try:
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   624
            self._mainloop()
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   625
        finally:
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   626
            self._cleanup()
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   627
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   628
    def _mainloop(self):
30891
b1b36c6499c2 commandserver: handle backlog before exiting
Jun Wu <quark@fb.com>
parents: 30887
diff changeset
   629
        exiting = False
29544
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   630
        h = self._servicehandler
36940
b0ffcb540357 commandserver: prefer first-party selectors module from Python 3 to backport
Augie Fackler <augie@google.com>
parents: 36835
diff changeset
   631
        selector = selectors.DefaultSelector()
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   632
        selector.register(
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   633
            self._sock, selectors.EVENT_READ, self._acceptnewconnection
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   634
        )
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   635
        selector.register(
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   636
            self._mainipc, selectors.EVENT_READ, self._handlemainipc
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   637
        )
30891
b1b36c6499c2 commandserver: handle backlog before exiting
Jun Wu <quark@fb.com>
parents: 30887
diff changeset
   638
        while True:
b1b36c6499c2 commandserver: handle backlog before exiting
Jun Wu <quark@fb.com>
parents: 30887
diff changeset
   639
            if not exiting and h.shouldexit():
b1b36c6499c2 commandserver: handle backlog before exiting
Jun Wu <quark@fb.com>
parents: 30887
diff changeset
   640
                # clients can no longer connect() to the domain socket, so
b1b36c6499c2 commandserver: handle backlog before exiting
Jun Wu <quark@fb.com>
parents: 30887
diff changeset
   641
                # we stop queuing new requests.
b1b36c6499c2 commandserver: handle backlog before exiting
Jun Wu <quark@fb.com>
parents: 30887
diff changeset
   642
                # for requests that are queued (connect()-ed, but haven't been
b1b36c6499c2 commandserver: handle backlog before exiting
Jun Wu <quark@fb.com>
parents: 30887
diff changeset
   643
                # accept()-ed), handle them before exit. otherwise, clients
b1b36c6499c2 commandserver: handle backlog before exiting
Jun Wu <quark@fb.com>
parents: 30887
diff changeset
   644
                # waiting for recv() will receive ECONNRESET.
b1b36c6499c2 commandserver: handle backlog before exiting
Jun Wu <quark@fb.com>
parents: 30887
diff changeset
   645
                self._unlinksocket()
b1b36c6499c2 commandserver: handle backlog before exiting
Jun Wu <quark@fb.com>
parents: 30887
diff changeset
   646
                exiting = True
40788
41f0529b5112 commandserver: get around ETIMEDOUT raised by selectors2
Yuya Nishihara <yuya@tcha.org>
parents: 40361
diff changeset
   647
            try:
40878
2525faf4ecdb commandserver: loop over selector events
Yuya Nishihara <yuya@tcha.org>
parents: 40877
diff changeset
   648
                events = selector.select(timeout=h.pollinterval)
40788
41f0529b5112 commandserver: get around ETIMEDOUT raised by selectors2
Yuya Nishihara <yuya@tcha.org>
parents: 40361
diff changeset
   649
            except OSError as inst:
41f0529b5112 commandserver: get around ETIMEDOUT raised by selectors2
Yuya Nishihara <yuya@tcha.org>
parents: 40361
diff changeset
   650
                # selectors2 raises ETIMEDOUT if timeout exceeded while
41f0529b5112 commandserver: get around ETIMEDOUT raised by selectors2
Yuya Nishihara <yuya@tcha.org>
parents: 40361
diff changeset
   651
                # handling signal interrupt. That's probably wrong, but
41f0529b5112 commandserver: get around ETIMEDOUT raised by selectors2
Yuya Nishihara <yuya@tcha.org>
parents: 40361
diff changeset
   652
                # we can easily get around it.
41f0529b5112 commandserver: get around ETIMEDOUT raised by selectors2
Yuya Nishihara <yuya@tcha.org>
parents: 40361
diff changeset
   653
                if inst.errno != errno.ETIMEDOUT:
41f0529b5112 commandserver: get around ETIMEDOUT raised by selectors2
Yuya Nishihara <yuya@tcha.org>
parents: 40361
diff changeset
   654
                    raise
40878
2525faf4ecdb commandserver: loop over selector events
Yuya Nishihara <yuya@tcha.org>
parents: 40877
diff changeset
   655
                events = []
2525faf4ecdb commandserver: loop over selector events
Yuya Nishihara <yuya@tcha.org>
parents: 40877
diff changeset
   656
            if not events:
33543
3ef3bf704e47 commandserver: do not handle EINTR for selector.select
Jun Wu <quark@fb.com>
parents: 33506
diff changeset
   657
                # only exit if we completed all queued requests
3ef3bf704e47 commandserver: do not handle EINTR for selector.select
Jun Wu <quark@fb.com>
parents: 33506
diff changeset
   658
                if exiting:
3ef3bf704e47 commandserver: do not handle EINTR for selector.select
Jun Wu <quark@fb.com>
parents: 33506
diff changeset
   659
                    break
3ef3bf704e47 commandserver: do not handle EINTR for selector.select
Jun Wu <quark@fb.com>
parents: 33506
diff changeset
   660
                continue
40878
2525faf4ecdb commandserver: loop over selector events
Yuya Nishihara <yuya@tcha.org>
parents: 40877
diff changeset
   661
            for key, _mask in events:
2525faf4ecdb commandserver: loop over selector events
Yuya Nishihara <yuya@tcha.org>
parents: 40877
diff changeset
   662
                key.data(key.fileobj, selector)
40876
dc9901558e3c commandserver: extract handler of new socket connection
Yuya Nishihara <yuya@tcha.org>
parents: 40875
diff changeset
   663
        selector.close()
dc9901558e3c commandserver: extract handler of new socket connection
Yuya Nishihara <yuya@tcha.org>
parents: 40875
diff changeset
   664
dc9901558e3c commandserver: extract handler of new socket connection
Yuya Nishihara <yuya@tcha.org>
parents: 40875
diff changeset
   665
    def _acceptnewconnection(self, sock, selector):
dc9901558e3c commandserver: extract handler of new socket connection
Yuya Nishihara <yuya@tcha.org>
parents: 40875
diff changeset
   666
        h = self._servicehandler
40877
9f00de4dc7cb commandserver: remove redundant "if True" block
Yuya Nishihara <yuya@tcha.org>
parents: 40876
diff changeset
   667
        try:
9f00de4dc7cb commandserver: remove redundant "if True" block
Yuya Nishihara <yuya@tcha.org>
parents: 40876
diff changeset
   668
            conn, _addr = sock.accept()
9f00de4dc7cb commandserver: remove redundant "if True" block
Yuya Nishihara <yuya@tcha.org>
parents: 40876
diff changeset
   669
        except socket.error as inst:
9f00de4dc7cb commandserver: remove redundant "if True" block
Yuya Nishihara <yuya@tcha.org>
parents: 40876
diff changeset
   670
            if inst.args[0] == errno.EINTR:
9f00de4dc7cb commandserver: remove redundant "if True" block
Yuya Nishihara <yuya@tcha.org>
parents: 40876
diff changeset
   671
                return
9f00de4dc7cb commandserver: remove redundant "if True" block
Yuya Nishihara <yuya@tcha.org>
parents: 40876
diff changeset
   672
            raise
9f00de4dc7cb commandserver: remove redundant "if True" block
Yuya Nishihara <yuya@tcha.org>
parents: 40876
diff changeset
   673
40999
dcac24ec935b commandserver: preload repository in master server and reuse its file cache
Yuya Nishihara <yuya@tcha.org>
parents: 40998
diff changeset
   674
        # Future improvement: On Python 3.7, maybe gc.freeze() can be used
dcac24ec935b commandserver: preload repository in master server and reuse its file cache
Yuya Nishihara <yuya@tcha.org>
parents: 40998
diff changeset
   675
        # to prevent COW memory from being touched by GC.
dcac24ec935b commandserver: preload repository in master server and reuse its file cache
Yuya Nishihara <yuya@tcha.org>
parents: 40998
diff changeset
   676
        # https://instagram-engineering.com/
dcac24ec935b commandserver: preload repository in master server and reuse its file cache
Yuya Nishihara <yuya@tcha.org>
parents: 40998
diff changeset
   677
        #   copy-on-write-friendly-python-garbage-collection-ad6ed5233ddf
40877
9f00de4dc7cb commandserver: remove redundant "if True" block
Yuya Nishihara <yuya@tcha.org>
parents: 40876
diff changeset
   678
        pid = os.fork()
9f00de4dc7cb commandserver: remove redundant "if True" block
Yuya Nishihara <yuya@tcha.org>
parents: 40876
diff changeset
   679
        if pid:
29544
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   680
            try:
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   681
                self.ui.log(
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   682
                    b'cmdserver', b'forked worker process (pid=%d)\n', pid
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   683
                )
40877
9f00de4dc7cb commandserver: remove redundant "if True" block
Yuya Nishihara <yuya@tcha.org>
parents: 40876
diff changeset
   684
                self._workerpids.add(pid)
9f00de4dc7cb commandserver: remove redundant "if True" block
Yuya Nishihara <yuya@tcha.org>
parents: 40876
diff changeset
   685
                h.newconnection()
9f00de4dc7cb commandserver: remove redundant "if True" block
Yuya Nishihara <yuya@tcha.org>
parents: 40876
diff changeset
   686
            finally:
9f00de4dc7cb commandserver: remove redundant "if True" block
Yuya Nishihara <yuya@tcha.org>
parents: 40876
diff changeset
   687
                conn.close()  # release handle in parent process
9f00de4dc7cb commandserver: remove redundant "if True" block
Yuya Nishihara <yuya@tcha.org>
parents: 40876
diff changeset
   688
        else:
9f00de4dc7cb commandserver: remove redundant "if True" block
Yuya Nishihara <yuya@tcha.org>
parents: 40876
diff changeset
   689
            try:
9f00de4dc7cb commandserver: remove redundant "if True" block
Yuya Nishihara <yuya@tcha.org>
parents: 40876
diff changeset
   690
                selector.close()
9f00de4dc7cb commandserver: remove redundant "if True" block
Yuya Nishihara <yuya@tcha.org>
parents: 40876
diff changeset
   691
                sock.close()
40998
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   692
                self._mainipc.close()
40877
9f00de4dc7cb commandserver: remove redundant "if True" block
Yuya Nishihara <yuya@tcha.org>
parents: 40876
diff changeset
   693
                self._runworker(conn)
9f00de4dc7cb commandserver: remove redundant "if True" block
Yuya Nishihara <yuya@tcha.org>
parents: 40876
diff changeset
   694
                conn.close()
40998
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   695
                self._workeripc.close()
40877
9f00de4dc7cb commandserver: remove redundant "if True" block
Yuya Nishihara <yuya@tcha.org>
parents: 40876
diff changeset
   696
                os._exit(0)
9f00de4dc7cb commandserver: remove redundant "if True" block
Yuya Nishihara <yuya@tcha.org>
parents: 40876
diff changeset
   697
            except:  # never return, hence no re-raises
29544
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   698
                try:
40877
9f00de4dc7cb commandserver: remove redundant "if True" block
Yuya Nishihara <yuya@tcha.org>
parents: 40876
diff changeset
   699
                    self.ui.traceback(force=True)
29544
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   700
                finally:
40877
9f00de4dc7cb commandserver: remove redundant "if True" block
Yuya Nishihara <yuya@tcha.org>
parents: 40876
diff changeset
   701
                    os._exit(255)
29544
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   702
40998
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   703
    def _handlemainipc(self, sock, selector):
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   704
        """Process messages sent from a worker"""
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   705
        try:
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   706
            path = sock.recv(32768)  # large enough to receive path
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   707
        except socket.error as inst:
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   708
            if inst.args[0] == errno.EINTR:
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   709
                return
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   710
            raise
40999
dcac24ec935b commandserver: preload repository in master server and reuse its file cache
Yuya Nishihara <yuya@tcha.org>
parents: 40998
diff changeset
   711
        self._repoloader.load(path)
40998
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   712
29544
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   713
    def _sigchldhandler(self, signal, frame):
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   714
        self._reapworkers(os.WNOHANG)
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   715
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   716
    def _reapworkers(self, options):
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   717
        while self._workerpids:
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   718
            try:
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   719
                pid, _status = os.waitpid(-1, options)
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   720
            except OSError as inst:
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   721
                if inst.errno == errno.EINTR:
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   722
                    continue
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   723
                if inst.errno != errno.ECHILD:
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   724
                    raise
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   725
                # no child processes at all (reaped by other waitpid()?)
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   726
                self._workerpids.clear()
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   727
                return
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   728
            if pid == 0:
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   729
                # no waitable child processes
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   730
                return
40828
25e9089c7686 commandserver: turn server debug messages into logs
Yuya Nishihara <yuya@tcha.org>
parents: 40827
diff changeset
   731
            self.ui.log(b'cmdserver', b'worker process exited (pid=%d)\n', pid)
29544
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   732
            self._workerpids.discard(pid)
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   733
29587
536eec443b4a commandserver: rename _serveworker() to _runworker()
Yuya Nishihara <yuya@tcha.org>
parents: 29586
diff changeset
   734
    def _runworker(self, conn):
29544
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   735
        signal.signal(signal.SIGCHLD, self._oldsigchldhandler)
29586
42cdba9cfee4 commandserver: separate initialization and cleanup of forked process
Yuya Nishihara <yuya@tcha.org>
parents: 29585
diff changeset
   736
        _initworkerprocess()
29544
024e8f82f3de commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org>
parents: 29543
diff changeset
   737
        h = self._servicehandler
29586
42cdba9cfee4 commandserver: separate initialization and cleanup of forked process
Yuya Nishihara <yuya@tcha.org>
parents: 29585
diff changeset
   738
        try:
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   739
            _serverequest(
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   740
                self.ui,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   741
                self.repo,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   742
                conn,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   743
                h.createcmdserver,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   744
                prereposetups=[self._reposetup],
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   745
            )
29586
42cdba9cfee4 commandserver: separate initialization and cleanup of forked process
Yuya Nishihara <yuya@tcha.org>
parents: 29585
diff changeset
   746
        finally:
42cdba9cfee4 commandserver: separate initialization and cleanup of forked process
Yuya Nishihara <yuya@tcha.org>
parents: 29585
diff changeset
   747
            gc.collect()  # trigger __del__ since worker process uses os._exit
40998
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   748
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   749
    def _reposetup(self, ui, repo):
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   750
        if not repo.local():
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   751
            return
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   752
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   753
        class unixcmdserverrepo(repo.__class__):
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   754
            def close(self):
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   755
                super(unixcmdserverrepo, self).close()
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   756
                try:
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   757
                    self._cmdserveripc.send(self.root)
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   758
                except socket.error:
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   759
                    self.ui.log(
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   760
                        b'cmdserver', b'failed to send repo root to master\n'
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 41284
diff changeset
   761
                    )
40998
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   762
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   763
        repo.__class__ = unixcmdserverrepo
042ed354b9eb commandserver: add IPC channel to teach repository path on command finished
Yuya Nishihara <yuya@tcha.org>
parents: 40878
diff changeset
   764
        repo._cmdserveripc = self._workeripc
40999
dcac24ec935b commandserver: preload repository in master server and reuse its file cache
Yuya Nishihara <yuya@tcha.org>
parents: 40998
diff changeset
   765
dcac24ec935b commandserver: preload repository in master server and reuse its file cache
Yuya Nishihara <yuya@tcha.org>
parents: 40998
diff changeset
   766
        cachedrepo = self._repoloader.get(repo.root)
dcac24ec935b commandserver: preload repository in master server and reuse its file cache
Yuya Nishihara <yuya@tcha.org>
parents: 40998
diff changeset
   767
        if cachedrepo is None:
dcac24ec935b commandserver: preload repository in master server and reuse its file cache
Yuya Nishihara <yuya@tcha.org>
parents: 40998
diff changeset
   768
            return
dcac24ec935b commandserver: preload repository in master server and reuse its file cache
Yuya Nishihara <yuya@tcha.org>
parents: 40998
diff changeset
   769
        repo.ui.log(b'repocache', b'repo from cache: %s\n', repo.root)
dcac24ec935b commandserver: preload repository in master server and reuse its file cache
Yuya Nishihara <yuya@tcha.org>
parents: 40998
diff changeset
   770
        repocache.copycache(cachedrepo, repo)