hgext/chgserver.py
author Jun Wu <quark@fb.com>
Sat, 12 Mar 2016 04:24:11 +0000
changeset 28536 a979f5b03320
parent 28535 aa082a8125da
child 28537 881d027d3935
permissions -rw-r--r--
chgserver: invalidate the server if extensions fail to load Previously, if extensions fail to load, chg server will just keep working without those extensions. It will print a warning message but only if a new server starts. This patch invalidates the server if any extension failed to load, but still serve the client (hopefully just) once. It will help chg pass some test cases of test-bad-extension.t.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
27792
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
     1
# chgserver.py - command server extension for cHg
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
     2
#
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
     3
# Copyright 2011 Yuya Nishihara <yuya@tcha.org>
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
     4
#
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
     5
# This software may be used and distributed according to the terms of the
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
     6
# GNU General Public License version 2 or any later version.
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
     7
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
     8
"""command server extension for cHg (EXPERIMENTAL)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
     9
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    10
'S' channel (read/write)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    11
    propagate ui.system() request to client
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    12
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    13
'attachio' command
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    14
    attach client's stdio passed by sendmsg()
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    15
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    16
'chdir' command
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    17
    change current directory
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    18
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    19
'getpager' command
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    20
    checks if pager is enabled and which pager should be executed
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    21
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    22
'setenv' command
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    23
    replace os.environ completely
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    24
28325
9fec3cb8d128 chgserver: update docs
Jun Wu <quark@fb.com>
parents: 28277
diff changeset
    25
'setumask' command
9fec3cb8d128 chgserver: update docs
Jun Wu <quark@fb.com>
parents: 28277
diff changeset
    26
    set umask
9fec3cb8d128 chgserver: update docs
Jun Wu <quark@fb.com>
parents: 28277
diff changeset
    27
28350
8f9661d1637b chgserver: implement validate command
Jun Wu <quark@fb.com>
parents: 28342
diff changeset
    28
'validate' command
8f9661d1637b chgserver: implement validate command
Jun Wu <quark@fb.com>
parents: 28342
diff changeset
    29
    reload the config and check if the server is up to date
8f9661d1637b chgserver: implement validate command
Jun Wu <quark@fb.com>
parents: 28342
diff changeset
    30
28325
9fec3cb8d128 chgserver: update docs
Jun Wu <quark@fb.com>
parents: 28277
diff changeset
    31
Config
9fec3cb8d128 chgserver: update docs
Jun Wu <quark@fb.com>
parents: 28277
diff changeset
    32
------
9fec3cb8d128 chgserver: update docs
Jun Wu <quark@fb.com>
parents: 28277
diff changeset
    33
9fec3cb8d128 chgserver: update docs
Jun Wu <quark@fb.com>
parents: 28277
diff changeset
    34
::
9fec3cb8d128 chgserver: update docs
Jun Wu <quark@fb.com>
parents: 28277
diff changeset
    35
9fec3cb8d128 chgserver: update docs
Jun Wu <quark@fb.com>
parents: 28277
diff changeset
    36
  [chgserver]
9fec3cb8d128 chgserver: update docs
Jun Wu <quark@fb.com>
parents: 28277
diff changeset
    37
  idletimeout = 3600 # seconds, after which an idle server will exit
28326
ea400a4f32e6 chgserver: mangle server address to include confighash
Jun Wu <quark@fb.com>
parents: 28325
diff changeset
    38
  skiphash = False   # whether to skip config or env change checks
27792
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    39
"""
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    40
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    41
from __future__ import absolute_import
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    42
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    43
import SocketServer
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    44
import errno
28276
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
    45
import inspect
27792
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    46
import os
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    47
import re
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    48
import struct
28276
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
    49
import sys
28223
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
    50
import threading
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
    51
import time
27792
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    52
import traceback
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    53
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    54
from mercurial.i18n import _
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    55
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    56
from mercurial import (
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    57
    cmdutil,
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    58
    commands,
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    59
    commandserver,
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    60
    dispatch,
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    61
    error,
28276
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
    62
    extensions,
27792
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    63
    osutil,
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    64
    util,
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    65
)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    66
27793
8c9bbf5cd349 chgserver: mark as a built-in extension
Yuya Nishihara <yuya@tcha.org>
parents: 27792
diff changeset
    67
# Note for extension authors: ONLY specify testedwith = 'internal' for
8c9bbf5cd349 chgserver: mark as a built-in extension
Yuya Nishihara <yuya@tcha.org>
parents: 27792
diff changeset
    68
# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
8c9bbf5cd349 chgserver: mark as a built-in extension
Yuya Nishihara <yuya@tcha.org>
parents: 27792
diff changeset
    69
# be specifying the version(s) of Mercurial they are tested with, or
8c9bbf5cd349 chgserver: mark as a built-in extension
Yuya Nishihara <yuya@tcha.org>
parents: 27792
diff changeset
    70
# leave the attribute unspecified.
8c9bbf5cd349 chgserver: mark as a built-in extension
Yuya Nishihara <yuya@tcha.org>
parents: 27792
diff changeset
    71
testedwith = 'internal'
8c9bbf5cd349 chgserver: mark as a built-in extension
Yuya Nishihara <yuya@tcha.org>
parents: 27792
diff changeset
    72
27792
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    73
_log = commandserver.log
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
    74
28262
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
    75
def _hashlist(items):
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
    76
    """return sha1 hexdigest for a list"""
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
    77
    return util.sha1(str(items)).hexdigest()
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
    78
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
    79
# sensitive config sections affecting confighash
28478
e6e183687545 chgserver: include [extdiff] in confighash
Jun Wu <quark@fb.com>
parents: 28454
diff changeset
    80
_configsections = [
e6e183687545 chgserver: include [extdiff] in confighash
Jun Wu <quark@fb.com>
parents: 28454
diff changeset
    81
    'extdiff',  # uisetup will register new commands
e6e183687545 chgserver: include [extdiff] in confighash
Jun Wu <quark@fb.com>
parents: 28454
diff changeset
    82
    'extensions',
e6e183687545 chgserver: include [extdiff] in confighash
Jun Wu <quark@fb.com>
parents: 28454
diff changeset
    83
]
28262
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
    84
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
    85
# sensitive environment variables affecting confighash
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
    86
_envre = re.compile(r'''\A(?:
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
    87
                    CHGHG
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
    88
                    |HG.*
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
    89
                    |LANG(?:UAGE)?
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
    90
                    |LC_.*
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
    91
                    |LD_.*
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
    92
                    |PATH
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
    93
                    |PYTHON.*
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
    94
                    |TERM(?:INFO)?
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
    95
                    |TZ
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
    96
                    )\Z''', re.X)
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
    97
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
    98
def _confighash(ui):
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
    99
    """return a quick hash for detecting config/env changes
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
   100
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
   101
    confighash is the hash of sensitive config items and environment variables.
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
   102
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
   103
    for chgserver, it is designed that once confighash changes, the server is
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
   104
    not qualified to serve its client and should redirect the client to a new
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
   105
    server. different from mtimehash, confighash change will not mark the
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
   106
    server outdated and exit since the user can have different configs at the
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
   107
    same time.
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
   108
    """
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
   109
    sectionitems = []
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
   110
    for section in _configsections:
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
   111
        sectionitems.append(ui.configitems(section))
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
   112
    sectionhash = _hashlist(sectionitems)
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
   113
    envitems = [(k, v) for k, v in os.environ.iteritems() if _envre.match(k)]
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
   114
    envhash = _hashlist(sorted(envitems))
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
   115
    return sectionhash[:6] + envhash[:6]
53dc4aada2d9 chgserver: add utilities to calculate confighash
Jun Wu <quark@fb.com>
parents: 28261
diff changeset
   116
28276
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   117
def _getmtimepaths(ui):
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   118
    """get a list of paths that should be checked to detect change
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   119
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   120
    The list will include:
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   121
    - extensions (will not cover all files for complex extensions)
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   122
    - mercurial/__version__.py
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   123
    - python binary
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   124
    """
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   125
    modules = [m for n, m in extensions.extensions(ui)]
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   126
    try:
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   127
        from mercurial import __version__
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   128
        modules.append(__version__)
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   129
    except ImportError:
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   130
        pass
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   131
    files = [sys.executable]
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   132
    for m in modules:
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   133
        try:
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   134
            files.append(inspect.getabsfile(m))
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   135
        except TypeError:
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   136
            pass
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   137
    return sorted(set(files))
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   138
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   139
def _mtimehash(paths):
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   140
    """return a quick hash for detecting file changes
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   141
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   142
    mtimehash calls stat on given paths and calculate a hash based on size and
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   143
    mtime of each file. mtimehash does not read file content because reading is
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   144
    expensive. therefore it's not 100% reliable for detecting content changes.
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   145
    it's possible to return different hashes for same file contents.
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   146
    it's also possible to return a same hash for different file contents for
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   147
    some carefully crafted situation.
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   148
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   149
    for chgserver, it is designed that once mtimehash changes, the server is
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   150
    considered outdated immediately and should no longer provide service.
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   151
    """
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   152
    def trystat(path):
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   153
        try:
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   154
            st = os.stat(path)
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   155
            return (st.st_mtime, st.st_size)
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   156
        except OSError:
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   157
            # could be ENOENT, EPERM etc. not fatal in any case
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   158
            pass
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   159
    return _hashlist(map(trystat, paths))[:12]
b4ceadb2c439 chgserver: add utilities to calculate mtimehash
Jun Wu <quark@fb.com>
parents: 28264
diff changeset
   160
28277
cdc6319f6a7d chgserver: add a structure for confighash and mtimehash
Jun Wu <quark@fb.com>
parents: 28276
diff changeset
   161
class hashstate(object):
cdc6319f6a7d chgserver: add a structure for confighash and mtimehash
Jun Wu <quark@fb.com>
parents: 28276
diff changeset
   162
    """a structure storing confighash, mtimehash, paths used for mtimehash"""
cdc6319f6a7d chgserver: add a structure for confighash and mtimehash
Jun Wu <quark@fb.com>
parents: 28276
diff changeset
   163
    def __init__(self, confighash, mtimehash, mtimepaths):
cdc6319f6a7d chgserver: add a structure for confighash and mtimehash
Jun Wu <quark@fb.com>
parents: 28276
diff changeset
   164
        self.confighash = confighash
cdc6319f6a7d chgserver: add a structure for confighash and mtimehash
Jun Wu <quark@fb.com>
parents: 28276
diff changeset
   165
        self.mtimehash = mtimehash
cdc6319f6a7d chgserver: add a structure for confighash and mtimehash
Jun Wu <quark@fb.com>
parents: 28276
diff changeset
   166
        self.mtimepaths = mtimepaths
cdc6319f6a7d chgserver: add a structure for confighash and mtimehash
Jun Wu <quark@fb.com>
parents: 28276
diff changeset
   167
cdc6319f6a7d chgserver: add a structure for confighash and mtimehash
Jun Wu <quark@fb.com>
parents: 28276
diff changeset
   168
    @staticmethod
cdc6319f6a7d chgserver: add a structure for confighash and mtimehash
Jun Wu <quark@fb.com>
parents: 28276
diff changeset
   169
    def fromui(ui, mtimepaths=None):
cdc6319f6a7d chgserver: add a structure for confighash and mtimehash
Jun Wu <quark@fb.com>
parents: 28276
diff changeset
   170
        if mtimepaths is None:
cdc6319f6a7d chgserver: add a structure for confighash and mtimehash
Jun Wu <quark@fb.com>
parents: 28276
diff changeset
   171
            mtimepaths = _getmtimepaths(ui)
cdc6319f6a7d chgserver: add a structure for confighash and mtimehash
Jun Wu <quark@fb.com>
parents: 28276
diff changeset
   172
        confighash = _confighash(ui)
cdc6319f6a7d chgserver: add a structure for confighash and mtimehash
Jun Wu <quark@fb.com>
parents: 28276
diff changeset
   173
        mtimehash = _mtimehash(mtimepaths)
cdc6319f6a7d chgserver: add a structure for confighash and mtimehash
Jun Wu <quark@fb.com>
parents: 28276
diff changeset
   174
        _log('confighash = %s mtimehash = %s\n' % (confighash, mtimehash))
cdc6319f6a7d chgserver: add a structure for confighash and mtimehash
Jun Wu <quark@fb.com>
parents: 28276
diff changeset
   175
        return hashstate(confighash, mtimehash, mtimepaths)
cdc6319f6a7d chgserver: add a structure for confighash and mtimehash
Jun Wu <quark@fb.com>
parents: 28276
diff changeset
   176
27792
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   177
# copied from hgext/pager.py:uisetup()
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   178
def _setuppagercmd(ui, options, cmd):
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   179
    if not ui.formatted():
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   180
        return
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   181
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   182
    p = ui.config("pager", "pager", os.environ.get("PAGER"))
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   183
    usepager = False
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   184
    always = util.parsebool(options['pager'])
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   185
    auto = options['pager'] == 'auto'
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   186
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   187
    if not p:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   188
        pass
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   189
    elif always:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   190
        usepager = True
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   191
    elif not auto:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   192
        usepager = False
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   193
    else:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   194
        attended = ['annotate', 'cat', 'diff', 'export', 'glog', 'log', 'qdiff']
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   195
        attend = ui.configlist('pager', 'attend', attended)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   196
        ignore = ui.configlist('pager', 'ignore')
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   197
        cmds, _ = cmdutil.findcmd(cmd, commands.table)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   198
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   199
        for cmd in cmds:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   200
            var = 'attend-%s' % cmd
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   201
            if ui.config('pager', var):
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   202
                usepager = ui.configbool('pager', var)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   203
                break
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   204
            if (cmd in attend or
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   205
                (cmd not in ignore and not attend)):
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   206
                usepager = True
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   207
                break
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   208
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   209
    if usepager:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   210
        ui.setconfig('ui', 'formatted', ui.formatted(), 'pager')
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   211
        ui.setconfig('ui', 'interactive', False, 'pager')
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   212
        return p
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   213
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   214
_envvarre = re.compile(r'\$[a-zA-Z_]+')
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   215
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   216
def _clearenvaliases(cmdtable):
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   217
    """Remove stale command aliases referencing env vars; variable expansion
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   218
    is done at dispatch.addaliases()"""
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   219
    for name, tab in cmdtable.items():
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   220
        cmddef = tab[0]
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   221
        if (isinstance(cmddef, dispatch.cmdalias) and
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   222
            not cmddef.definition.startswith('!') and  # shell alias
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   223
            _envvarre.search(cmddef.definition)):
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   224
            del cmdtable[name]
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   225
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   226
def _newchgui(srcui, csystem):
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   227
    class chgui(srcui.__class__):
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   228
        def __init__(self, src=None):
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   229
            super(chgui, self).__init__(src)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   230
            if src:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   231
                self._csystem = getattr(src, '_csystem', csystem)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   232
            else:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   233
                self._csystem = csystem
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   234
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   235
        def system(self, cmd, environ=None, cwd=None, onerr=None,
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   236
                   errprefix=None):
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   237
            # copied from mercurial/util.py:system()
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   238
            self.flush()
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   239
            def py2shell(val):
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   240
                if val is None or val is False:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   241
                    return '0'
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   242
                if val is True:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   243
                    return '1'
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   244
                return str(val)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   245
            env = os.environ.copy()
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   246
            if environ:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   247
                env.update((k, py2shell(v)) for k, v in environ.iteritems())
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   248
            env['HG'] = util.hgexecutable()
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   249
            rc = self._csystem(cmd, env, cwd)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   250
            if rc and onerr:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   251
                errmsg = '%s %s' % (os.path.basename(cmd.split(None, 1)[0]),
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   252
                                    util.explainexit(rc)[0])
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   253
                if errprefix:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   254
                    errmsg = '%s: %s' % (errprefix, errmsg)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   255
                raise onerr(errmsg)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   256
            return rc
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   257
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   258
    return chgui(srcui)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   259
28264
3682e201cce6 chgserver: make _renewui load repo and command line configs
Jun Wu <quark@fb.com>
parents: 28262
diff changeset
   260
def _renewui(srcui, args=None):
3682e201cce6 chgserver: make _renewui load repo and command line configs
Jun Wu <quark@fb.com>
parents: 28262
diff changeset
   261
    if not args:
3682e201cce6 chgserver: make _renewui load repo and command line configs
Jun Wu <quark@fb.com>
parents: 28262
diff changeset
   262
        args = []
3682e201cce6 chgserver: make _renewui load repo and command line configs
Jun Wu <quark@fb.com>
parents: 28262
diff changeset
   263
27792
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   264
    newui = srcui.__class__()
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   265
    for a in ['fin', 'fout', 'ferr', 'environ']:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   266
        setattr(newui, a, getattr(srcui, a))
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   267
    if util.safehasattr(srcui, '_csystem'):
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   268
        newui._csystem = srcui._csystem
28264
3682e201cce6 chgserver: make _renewui load repo and command line configs
Jun Wu <quark@fb.com>
parents: 28262
diff changeset
   269
3682e201cce6 chgserver: make _renewui load repo and command line configs
Jun Wu <quark@fb.com>
parents: 28262
diff changeset
   270
    # load wd and repo config, copied from dispatch.py
3682e201cce6 chgserver: make _renewui load repo and command line configs
Jun Wu <quark@fb.com>
parents: 28262
diff changeset
   271
    cwds = dispatch._earlygetopt(['--cwd'], args)
3682e201cce6 chgserver: make _renewui load repo and command line configs
Jun Wu <quark@fb.com>
parents: 28262
diff changeset
   272
    cwd = cwds and os.path.realpath(cwds[-1]) or None
3682e201cce6 chgserver: make _renewui load repo and command line configs
Jun Wu <quark@fb.com>
parents: 28262
diff changeset
   273
    rpath = dispatch._earlygetopt(["-R", "--repository", "--repo"], args)
3682e201cce6 chgserver: make _renewui load repo and command line configs
Jun Wu <quark@fb.com>
parents: 28262
diff changeset
   274
    path, newui = dispatch._getlocal(newui, rpath, wd=cwd)
3682e201cce6 chgserver: make _renewui load repo and command line configs
Jun Wu <quark@fb.com>
parents: 28262
diff changeset
   275
3682e201cce6 chgserver: make _renewui load repo and command line configs
Jun Wu <quark@fb.com>
parents: 28262
diff changeset
   276
    # internal config: extensions.chgserver
3682e201cce6 chgserver: make _renewui load repo and command line configs
Jun Wu <quark@fb.com>
parents: 28262
diff changeset
   277
    # copy it. it can only be overrided from command line.
3682e201cce6 chgserver: make _renewui load repo and command line configs
Jun Wu <quark@fb.com>
parents: 28262
diff changeset
   278
    newui.setconfig('extensions', 'chgserver',
3682e201cce6 chgserver: make _renewui load repo and command line configs
Jun Wu <quark@fb.com>
parents: 28262
diff changeset
   279
                    srcui.config('extensions', 'chgserver'), '--config')
3682e201cce6 chgserver: make _renewui load repo and command line configs
Jun Wu <quark@fb.com>
parents: 28262
diff changeset
   280
3682e201cce6 chgserver: make _renewui load repo and command line configs
Jun Wu <quark@fb.com>
parents: 28262
diff changeset
   281
    # command line args
3682e201cce6 chgserver: make _renewui load repo and command line configs
Jun Wu <quark@fb.com>
parents: 28262
diff changeset
   282
    dispatch._parseconfig(newui, dispatch._earlygetopt(['--config'], args))
3682e201cce6 chgserver: make _renewui load repo and command line configs
Jun Wu <quark@fb.com>
parents: 28262
diff changeset
   283
27792
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   284
    # stolen from tortoisehg.util.copydynamicconfig()
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   285
    for section, name, value in srcui.walkconfig():
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   286
        source = srcui.configsource(section, name)
28264
3682e201cce6 chgserver: make _renewui load repo and command line configs
Jun Wu <quark@fb.com>
parents: 28262
diff changeset
   287
        if ':' in source or source == '--config':
3682e201cce6 chgserver: make _renewui load repo and command line configs
Jun Wu <quark@fb.com>
parents: 28262
diff changeset
   288
            # path:line or command line
27792
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   289
            continue
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   290
        if source == 'none':
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   291
            # ui.configsource returns 'none' by default
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   292
            source = ''
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   293
        newui.setconfig(section, name, value, source)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   294
    return newui
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   295
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   296
class channeledsystem(object):
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   297
    """Propagate ui.system() request in the following format:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   298
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   299
    payload length (unsigned int),
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   300
    cmd, '\0',
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   301
    cwd, '\0',
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   302
    envkey, '=', val, '\0',
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   303
    ...
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   304
    envkey, '=', val
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   305
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   306
    and waits:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   307
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   308
    exitcode length (unsigned int),
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   309
    exitcode (int)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   310
    """
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   311
    def __init__(self, in_, out, channel):
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   312
        self.in_ = in_
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   313
        self.out = out
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   314
        self.channel = channel
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   315
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   316
    def __call__(self, cmd, environ, cwd):
28514
0747ef2c4ab2 chgserver: resolve relative path before sending via system channel
Jun Wu <quark@fb.com>
parents: 28511
diff changeset
   317
        args = [util.quotecommand(cmd), os.path.abspath(cwd or '.')]
27792
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   318
        args.extend('%s=%s' % (k, v) for k, v in environ.iteritems())
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   319
        data = '\0'.join(args)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   320
        self.out.write(struct.pack('>cI', self.channel, len(data)))
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   321
        self.out.write(data)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   322
        self.out.flush()
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   323
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   324
        length = self.in_.read(4)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   325
        length, = struct.unpack('>I', length)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   326
        if length != 4:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   327
            raise error.Abort(_('invalid response'))
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   328
        rc, = struct.unpack('>i', self.in_.read(4))
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   329
        return rc
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   330
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   331
_iochannels = [
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   332
    # server.ch, ui.fp, mode
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   333
    ('cin', 'fin', 'rb'),
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   334
    ('cout', 'fout', 'wb'),
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   335
    ('cerr', 'ferr', 'wb'),
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   336
]
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   337
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   338
class chgcmdserver(commandserver.server):
28328
e00e57d83653 chgserver: pass hashstate and base server address to chgcmdserver
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   339
    def __init__(self, ui, repo, fin, fout, sock, hashstate, baseaddress):
27792
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   340
        super(chgcmdserver, self).__init__(
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   341
            _newchgui(ui, channeledsystem(fin, fout, 'S')), repo, fin, fout)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   342
        self.clientsock = sock
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   343
        self._oldios = []  # original (self.ch, ui.fp, fd) before "attachio"
28328
e00e57d83653 chgserver: pass hashstate and base server address to chgcmdserver
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   344
        self.hashstate = hashstate
e00e57d83653 chgserver: pass hashstate and base server address to chgcmdserver
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   345
        self.baseaddress = baseaddress
28350
8f9661d1637b chgserver: implement validate command
Jun Wu <quark@fb.com>
parents: 28342
diff changeset
   346
        if hashstate is not None:
8f9661d1637b chgserver: implement validate command
Jun Wu <quark@fb.com>
parents: 28342
diff changeset
   347
            self.capabilities = self.capabilities.copy()
8f9661d1637b chgserver: implement validate command
Jun Wu <quark@fb.com>
parents: 28342
diff changeset
   348
            self.capabilities['validate'] = chgcmdserver.validate
27792
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   349
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   350
    def cleanup(self):
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   351
        # dispatch._runcatch() does not flush outputs if exception is not
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   352
        # handled by dispatch._dispatch()
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   353
        self.ui.flush()
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   354
        self._restoreio()
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   355
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   356
    def attachio(self):
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   357
        """Attach to client's stdio passed via unix domain socket; all
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   358
        channels except cresult will no longer be used
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   359
        """
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   360
        # tell client to sendmsg() with 1-byte payload, which makes it
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   361
        # distinctive from "attachio\n" command consumed by client.read()
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   362
        self.clientsock.sendall(struct.pack('>cI', 'I', 1))
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   363
        clientfds = osutil.recvfds(self.clientsock.fileno())
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   364
        _log('received fds: %r\n' % clientfds)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   365
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   366
        ui = self.ui
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   367
        ui.flush()
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   368
        first = self._saveio()
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   369
        for fd, (cn, fn, mode) in zip(clientfds, _iochannels):
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   370
            assert fd > 0
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   371
            fp = getattr(ui, fn)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   372
            os.dup2(fd, fp.fileno())
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   373
            os.close(fd)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   374
            if not first:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   375
                continue
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   376
            # reset buffering mode when client is first attached. as we want
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   377
            # to see output immediately on pager, the mode stays unchanged
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   378
            # when client re-attached. ferr is unchanged because it should
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   379
            # be unbuffered no matter if it is a tty or not.
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   380
            if fn == 'ferr':
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   381
                newfp = fp
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   382
            else:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   383
                # make it line buffered explicitly because the default is
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   384
                # decided on first write(), where fout could be a pager.
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   385
                if fp.isatty():
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   386
                    bufsize = 1  # line buffered
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   387
                else:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   388
                    bufsize = -1  # system default
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   389
                newfp = os.fdopen(fp.fileno(), mode, bufsize)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   390
                setattr(ui, fn, newfp)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   391
            setattr(self, cn, newfp)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   392
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   393
        self.cresult.write(struct.pack('>i', len(clientfds)))
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   394
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   395
    def _saveio(self):
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   396
        if self._oldios:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   397
            return False
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   398
        ui = self.ui
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   399
        for cn, fn, _mode in _iochannels:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   400
            ch = getattr(self, cn)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   401
            fp = getattr(ui, fn)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   402
            fd = os.dup(fp.fileno())
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   403
            self._oldios.append((ch, fp, fd))
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   404
        return True
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   405
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   406
    def _restoreio(self):
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   407
        ui = self.ui
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   408
        for (ch, fp, fd), (cn, fn, _mode) in zip(self._oldios, _iochannels):
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   409
            newfp = getattr(ui, fn)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   410
            # close newfp while it's associated with client; otherwise it
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   411
            # would be closed when newfp is deleted
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   412
            if newfp is not fp:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   413
                newfp.close()
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   414
            # restore original fd: fp is open again
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   415
            os.dup2(fd, fp.fileno())
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   416
            os.close(fd)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   417
            setattr(self, cn, ch)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   418
            setattr(ui, fn, fp)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   419
        del self._oldios[:]
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   420
28350
8f9661d1637b chgserver: implement validate command
Jun Wu <quark@fb.com>
parents: 28342
diff changeset
   421
    def validate(self):
8f9661d1637b chgserver: implement validate command
Jun Wu <quark@fb.com>
parents: 28342
diff changeset
   422
        """Reload the config and check if the server is up to date
8f9661d1637b chgserver: implement validate command
Jun Wu <quark@fb.com>
parents: 28342
diff changeset
   423
8f9661d1637b chgserver: implement validate command
Jun Wu <quark@fb.com>
parents: 28342
diff changeset
   424
        Read a list of '\0' separated arguments.
8f9661d1637b chgserver: implement validate command
Jun Wu <quark@fb.com>
parents: 28342
diff changeset
   425
        Write a non-empty list of '\0' separated instruction strings or '\0'
8f9661d1637b chgserver: implement validate command
Jun Wu <quark@fb.com>
parents: 28342
diff changeset
   426
        if the list is empty.
8f9661d1637b chgserver: implement validate command
Jun Wu <quark@fb.com>
parents: 28342
diff changeset
   427
        An instruction string could be either:
8f9661d1637b chgserver: implement validate command
Jun Wu <quark@fb.com>
parents: 28342
diff changeset
   428
            - "unlink $path", the client should unlink the path to stop the
8f9661d1637b chgserver: implement validate command
Jun Wu <quark@fb.com>
parents: 28342
diff changeset
   429
              outdated server.
28535
aa082a8125da chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents: 28516
diff changeset
   430
            - "redirect $path", the client should attempt to connect to $path
aa082a8125da chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents: 28516
diff changeset
   431
              first. If it does not work, start a new server. It implies
aa082a8125da chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents: 28516
diff changeset
   432
              "reconnect".
28516
3bf2892f685f chgserver: handle ParseError during validate
Jun Wu <quark@fb.com>
parents: 28514
diff changeset
   433
            - "exit $n", the client should exit directly with code n.
3bf2892f685f chgserver: handle ParseError during validate
Jun Wu <quark@fb.com>
parents: 28514
diff changeset
   434
              This may happen if we cannot parse the config.
28535
aa082a8125da chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents: 28516
diff changeset
   435
            - "reconnect", the client should close the connection and
aa082a8125da chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents: 28516
diff changeset
   436
              reconnect.
aa082a8125da chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents: 28516
diff changeset
   437
        If neither "reconnect" nor "redirect" is included in the instruction
aa082a8125da chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents: 28516
diff changeset
   438
        list, the client can continue with this server after completing all
aa082a8125da chgserver: add an explicit "reconnect" instruction to validate
Jun Wu <quark@fb.com>
parents: 28516
diff changeset
   439
        the instructions.
28350
8f9661d1637b chgserver: implement validate command
Jun Wu <quark@fb.com>
parents: 28342
diff changeset
   440
        """
8f9661d1637b chgserver: implement validate command
Jun Wu <quark@fb.com>
parents: 28342
diff changeset
   441
        args = self._readlist()
28516
3bf2892f685f chgserver: handle ParseError during validate
Jun Wu <quark@fb.com>
parents: 28514
diff changeset
   442
        try:
3bf2892f685f chgserver: handle ParseError during validate
Jun Wu <quark@fb.com>
parents: 28514
diff changeset
   443
            self.ui = _renewui(self.ui, args)
3bf2892f685f chgserver: handle ParseError during validate
Jun Wu <quark@fb.com>
parents: 28514
diff changeset
   444
        except error.ParseError as inst:
3bf2892f685f chgserver: handle ParseError during validate
Jun Wu <quark@fb.com>
parents: 28514
diff changeset
   445
            dispatch._formatparse(self.ui.warn, inst)
3bf2892f685f chgserver: handle ParseError during validate
Jun Wu <quark@fb.com>
parents: 28514
diff changeset
   446
            self.ui.flush()
3bf2892f685f chgserver: handle ParseError during validate
Jun Wu <quark@fb.com>
parents: 28514
diff changeset
   447
            self.cresult.write('exit 255')
3bf2892f685f chgserver: handle ParseError during validate
Jun Wu <quark@fb.com>
parents: 28514
diff changeset
   448
            return
28350
8f9661d1637b chgserver: implement validate command
Jun Wu <quark@fb.com>
parents: 28342
diff changeset
   449
        newhash = hashstate.fromui(self.ui, self.hashstate.mtimepaths)
8f9661d1637b chgserver: implement validate command
Jun Wu <quark@fb.com>
parents: 28342
diff changeset
   450
        insts = []
8f9661d1637b chgserver: implement validate command
Jun Wu <quark@fb.com>
parents: 28342
diff changeset
   451
        if newhash.mtimehash != self.hashstate.mtimehash:
8f9661d1637b chgserver: implement validate command
Jun Wu <quark@fb.com>
parents: 28342
diff changeset
   452
            addr = _hashaddress(self.baseaddress, self.hashstate.confighash)
8f9661d1637b chgserver: implement validate command
Jun Wu <quark@fb.com>
parents: 28342
diff changeset
   453
            insts.append('unlink %s' % addr)
28536
a979f5b03320 chgserver: invalidate the server if extensions fail to load
Jun Wu <quark@fb.com>
parents: 28535
diff changeset
   454
            # mtimehash is empty if one or more extensions fail to load.
a979f5b03320 chgserver: invalidate the server if extensions fail to load
Jun Wu <quark@fb.com>
parents: 28535
diff changeset
   455
            # to be compatible with hg, still serve the client this time.
a979f5b03320 chgserver: invalidate the server if extensions fail to load
Jun Wu <quark@fb.com>
parents: 28535
diff changeset
   456
            if self.hashstate.mtimehash:
a979f5b03320 chgserver: invalidate the server if extensions fail to load
Jun Wu <quark@fb.com>
parents: 28535
diff changeset
   457
                insts.append('reconnect')
28350
8f9661d1637b chgserver: implement validate command
Jun Wu <quark@fb.com>
parents: 28342
diff changeset
   458
        if newhash.confighash != self.hashstate.confighash:
8f9661d1637b chgserver: implement validate command
Jun Wu <quark@fb.com>
parents: 28342
diff changeset
   459
            addr = _hashaddress(self.baseaddress, newhash.confighash)
8f9661d1637b chgserver: implement validate command
Jun Wu <quark@fb.com>
parents: 28342
diff changeset
   460
            insts.append('redirect %s' % addr)
8f9661d1637b chgserver: implement validate command
Jun Wu <quark@fb.com>
parents: 28342
diff changeset
   461
        _log('validate: %s\n' % insts)
8f9661d1637b chgserver: implement validate command
Jun Wu <quark@fb.com>
parents: 28342
diff changeset
   462
        self.cresult.write('\0'.join(insts) or '\0')
8f9661d1637b chgserver: implement validate command
Jun Wu <quark@fb.com>
parents: 28342
diff changeset
   463
27792
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   464
    def chdir(self):
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   465
        """Change current directory
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   466
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   467
        Note that the behavior of --cwd option is bit different from this.
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   468
        It does not affect --config parameter.
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   469
        """
28158
7cc57a531f0c chgserver: use _readlist and _readstr
Jun Wu <quark@fb.com>
parents: 28014
diff changeset
   470
        path = self._readstr()
7cc57a531f0c chgserver: use _readlist and _readstr
Jun Wu <quark@fb.com>
parents: 28014
diff changeset
   471
        if not path:
27792
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   472
            return
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   473
        _log('chdir to %r\n' % path)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   474
        os.chdir(path)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   475
28159
d2d04d1d2f92 chgserver: add setumask method
Jun Wu <quark@fb.com>
parents: 28158
diff changeset
   476
    def setumask(self):
d2d04d1d2f92 chgserver: add setumask method
Jun Wu <quark@fb.com>
parents: 28158
diff changeset
   477
        """Change umask"""
d2d04d1d2f92 chgserver: add setumask method
Jun Wu <quark@fb.com>
parents: 28158
diff changeset
   478
        mask = struct.unpack('>I', self._read(4))[0]
d2d04d1d2f92 chgserver: add setumask method
Jun Wu <quark@fb.com>
parents: 28158
diff changeset
   479
        _log('setumask %r\n' % mask)
d2d04d1d2f92 chgserver: add setumask method
Jun Wu <quark@fb.com>
parents: 28158
diff changeset
   480
        os.umask(mask)
d2d04d1d2f92 chgserver: add setumask method
Jun Wu <quark@fb.com>
parents: 28158
diff changeset
   481
27792
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   482
    def getpager(self):
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   483
        """Read cmdargs and write pager command to r-channel if enabled
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   484
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   485
        If pager isn't enabled, this writes '\0' because channeledoutput
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   486
        does not allow to write empty data.
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   487
        """
28158
7cc57a531f0c chgserver: use _readlist and _readstr
Jun Wu <quark@fb.com>
parents: 28014
diff changeset
   488
        args = self._readlist()
27792
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   489
        try:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   490
            cmd, _func, args, options, _cmdoptions = dispatch._parse(self.ui,
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   491
                                                                     args)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   492
        except (error.Abort, error.AmbiguousCommand, error.CommandError,
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   493
                error.UnknownCommand):
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   494
            cmd = None
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   495
            options = {}
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   496
        if not cmd or 'pager' not in options:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   497
            self.cresult.write('\0')
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   498
            return
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   499
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   500
        pagercmd = _setuppagercmd(self.ui, options, cmd)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   501
        if pagercmd:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   502
            self.cresult.write(pagercmd)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   503
        else:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   504
            self.cresult.write('\0')
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   505
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   506
    def setenv(self):
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   507
        """Clear and update os.environ
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   508
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   509
        Note that not all variables can make an effect on the running process.
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   510
        """
28158
7cc57a531f0c chgserver: use _readlist and _readstr
Jun Wu <quark@fb.com>
parents: 28014
diff changeset
   511
        l = self._readlist()
27792
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   512
        try:
28158
7cc57a531f0c chgserver: use _readlist and _readstr
Jun Wu <quark@fb.com>
parents: 28014
diff changeset
   513
            newenv = dict(s.split('=', 1) for s in l)
27792
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   514
        except ValueError:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   515
            raise ValueError('unexpected value in setenv request')
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   516
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   517
        diffkeys = set(k for k in set(os.environ.keys() + newenv.keys())
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   518
                       if os.environ.get(k) != newenv.get(k))
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   519
        _log('change env: %r\n' % sorted(diffkeys))
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   520
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   521
        os.environ.clear()
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   522
        os.environ.update(newenv)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   523
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   524
        if set(['HGPLAIN', 'HGPLAINEXCEPT']) & diffkeys:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   525
            # reload config so that ui.plain() takes effect
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   526
            self.ui = _renewui(self.ui)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   527
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   528
        _clearenvaliases(commands.table)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   529
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   530
    capabilities = commandserver.server.capabilities.copy()
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   531
    capabilities.update({'attachio': attachio,
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   532
                         'chdir': chdir,
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   533
                         'getpager': getpager,
28159
d2d04d1d2f92 chgserver: add setumask method
Jun Wu <quark@fb.com>
parents: 28158
diff changeset
   534
                         'setenv': setenv,
d2d04d1d2f92 chgserver: add setumask method
Jun Wu <quark@fb.com>
parents: 28158
diff changeset
   535
                         'setumask': setumask})
27792
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   536
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   537
# copied from mercurial/commandserver.py
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   538
class _requesthandler(SocketServer.StreamRequestHandler):
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   539
    def handle(self):
28014
83fc0c055664 chgserver: create new process group after fork (issue5051)
Jun Wu <quark@fb.com>
parents: 27793
diff changeset
   540
        # use a different process group from the master process, making this
83fc0c055664 chgserver: create new process group after fork (issue5051)
Jun Wu <quark@fb.com>
parents: 27793
diff changeset
   541
        # process pass kernel "is_current_pgrp_orphaned" check so signals like
83fc0c055664 chgserver: create new process group after fork (issue5051)
Jun Wu <quark@fb.com>
parents: 27793
diff changeset
   542
        # SIGTSTP, SIGTTIN, SIGTTOU are not ignored.
83fc0c055664 chgserver: create new process group after fork (issue5051)
Jun Wu <quark@fb.com>
parents: 27793
diff changeset
   543
        os.setpgid(0, 0)
27792
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   544
        ui = self.server.ui
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   545
        repo = self.server.repo
28511
ff5f923fca3c cmdserver: write early exception to 'e' channel in 'unix' mode
Yuya Nishihara <yuya@tcha.org>
parents: 28482
diff changeset
   546
        sv = None
27792
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   547
        try:
28511
ff5f923fca3c cmdserver: write early exception to 'e' channel in 'unix' mode
Yuya Nishihara <yuya@tcha.org>
parents: 28482
diff changeset
   548
            sv = chgcmdserver(ui, repo, self.rfile, self.wfile, self.connection,
ff5f923fca3c cmdserver: write early exception to 'e' channel in 'unix' mode
Yuya Nishihara <yuya@tcha.org>
parents: 28482
diff changeset
   549
                              self.server.hashstate, self.server.baseaddress)
27792
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   550
            try:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   551
                sv.serve()
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   552
            # handle exceptions that may be raised by command server. most of
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   553
            # known exceptions are caught by dispatch.
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   554
            except error.Abort as inst:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   555
                ui.warn(_('abort: %s\n') % inst)
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   556
            except IOError as inst:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   557
                if inst.errno != errno.EPIPE:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   558
                    raise
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   559
            except KeyboardInterrupt:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   560
                pass
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   561
            finally:
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   562
                sv.cleanup()
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   563
        except: # re-raises
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   564
            # also write traceback to error channel. otherwise client cannot
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   565
            # see it because it is written to server's stderr by default.
28511
ff5f923fca3c cmdserver: write early exception to 'e' channel in 'unix' mode
Yuya Nishihara <yuya@tcha.org>
parents: 28482
diff changeset
   566
            if sv:
ff5f923fca3c cmdserver: write early exception to 'e' channel in 'unix' mode
Yuya Nishihara <yuya@tcha.org>
parents: 28482
diff changeset
   567
                cerr = sv.cerr
ff5f923fca3c cmdserver: write early exception to 'e' channel in 'unix' mode
Yuya Nishihara <yuya@tcha.org>
parents: 28482
diff changeset
   568
            else:
ff5f923fca3c cmdserver: write early exception to 'e' channel in 'unix' mode
Yuya Nishihara <yuya@tcha.org>
parents: 28482
diff changeset
   569
                cerr = commandserver.channeledoutput(self.wfile, 'e')
ff5f923fca3c cmdserver: write early exception to 'e' channel in 'unix' mode
Yuya Nishihara <yuya@tcha.org>
parents: 28482
diff changeset
   570
            traceback.print_exc(file=cerr)
27792
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   571
            raise
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   572
28223
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   573
def _tempaddress(address):
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   574
    return '%s.%d.tmp' % (address, os.getpid())
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   575
28326
ea400a4f32e6 chgserver: mangle server address to include confighash
Jun Wu <quark@fb.com>
parents: 28325
diff changeset
   576
def _hashaddress(address, hashstr):
ea400a4f32e6 chgserver: mangle server address to include confighash
Jun Wu <quark@fb.com>
parents: 28325
diff changeset
   577
    return '%s-%s' % (address, hashstr)
ea400a4f32e6 chgserver: mangle server address to include confighash
Jun Wu <quark@fb.com>
parents: 28325
diff changeset
   578
28223
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   579
class AutoExitMixIn:  # use old-style to comply with SocketServer design
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   580
    lastactive = time.time()
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   581
    idletimeout = 3600  # default 1 hour
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   582
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   583
    def startautoexitthread(self):
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   584
        # note: the auto-exit check here is cheap enough to not use a thread,
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   585
        # be done in serve_forever. however SocketServer is hook-unfriendly,
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   586
        # you simply cannot hook serve_forever without copying a lot of code.
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   587
        # besides, serve_forever's docstring suggests using thread.
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   588
        thread = threading.Thread(target=self._autoexitloop)
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   589
        thread.daemon = True
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   590
        thread.start()
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   591
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   592
    def _autoexitloop(self, interval=1):
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   593
        while True:
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   594
            time.sleep(interval)
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   595
            if not self.issocketowner():
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   596
                _log('%s is not owned, exiting.\n' % self.server_address)
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   597
                break
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   598
            if time.time() - self.lastactive > self.idletimeout:
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   599
                _log('being idle too long. exiting.\n')
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   600
                break
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   601
        self.shutdown()
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   602
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   603
    def process_request(self, request, address):
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   604
        self.lastactive = time.time()
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   605
        return SocketServer.ForkingMixIn.process_request(
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   606
            self, request, address)
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   607
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   608
    def server_bind(self):
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   609
        # use a unique temp address so we can stat the file and do ownership
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   610
        # check later
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   611
        tempaddress = _tempaddress(self.server_address)
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   612
        self.socket.bind(tempaddress)
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   613
        self._socketstat = os.stat(tempaddress)
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   614
        # rename will replace the old socket file if exists atomically. the
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   615
        # old server will detect ownership change and exit.
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   616
        util.rename(tempaddress, self.server_address)
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   617
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   618
    def issocketowner(self):
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   619
        try:
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   620
            stat = os.stat(self.server_address)
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   621
            return (stat.st_ino == self._socketstat.st_ino and
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   622
                    stat.st_mtime == self._socketstat.st_mtime)
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   623
        except OSError:
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   624
            return False
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   625
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   626
    def unlinksocketfile(self):
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   627
        if not self.issocketowner():
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   628
            return
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   629
        # it is possible to have a race condition here that we may
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   630
        # remove another server's socket file. but that's okay
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   631
        # since that server will detect and exit automatically and
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   632
        # the client will start a new server on demand.
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   633
        try:
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   634
            os.unlink(self.server_address)
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   635
        except OSError as exc:
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   636
            if exc.errno != errno.ENOENT:
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   637
                raise
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   638
27792
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   639
class chgunixservice(commandserver.unixservice):
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   640
    def init(self):
28326
ea400a4f32e6 chgserver: mangle server address to include confighash
Jun Wu <quark@fb.com>
parents: 28325
diff changeset
   641
        self._inithashstate()
28536
a979f5b03320 chgserver: invalidate the server if extensions fail to load
Jun Wu <quark@fb.com>
parents: 28535
diff changeset
   642
        self._checkextensions()
28223
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   643
        class cls(AutoExitMixIn, SocketServer.ForkingMixIn,
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   644
                  SocketServer.UnixStreamServer):
27792
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   645
            ui = self.ui
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   646
            repo = self.repo
28328
e00e57d83653 chgserver: pass hashstate and base server address to chgcmdserver
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   647
            hashstate = self.hashstate
e00e57d83653 chgserver: pass hashstate and base server address to chgcmdserver
Jun Wu <quark@fb.com>
parents: 28327
diff changeset
   648
            baseaddress = self.baseaddress
27792
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   649
        self.server = cls(self.address, _requesthandler)
28223
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   650
        self.server.idletimeout = self.ui.configint(
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   651
            'chgserver', 'idletimeout', self.server.idletimeout)
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   652
        self.server.startautoexitthread()
28326
ea400a4f32e6 chgserver: mangle server address to include confighash
Jun Wu <quark@fb.com>
parents: 28325
diff changeset
   653
        self._createsymlink()
27792
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   654
28326
ea400a4f32e6 chgserver: mangle server address to include confighash
Jun Wu <quark@fb.com>
parents: 28325
diff changeset
   655
    def _inithashstate(self):
ea400a4f32e6 chgserver: mangle server address to include confighash
Jun Wu <quark@fb.com>
parents: 28325
diff changeset
   656
        self.baseaddress = self.address
ea400a4f32e6 chgserver: mangle server address to include confighash
Jun Wu <quark@fb.com>
parents: 28325
diff changeset
   657
        if self.ui.configbool('chgserver', 'skiphash', False):
ea400a4f32e6 chgserver: mangle server address to include confighash
Jun Wu <quark@fb.com>
parents: 28325
diff changeset
   658
            self.hashstate = None
ea400a4f32e6 chgserver: mangle server address to include confighash
Jun Wu <quark@fb.com>
parents: 28325
diff changeset
   659
            return
ea400a4f32e6 chgserver: mangle server address to include confighash
Jun Wu <quark@fb.com>
parents: 28325
diff changeset
   660
        self.hashstate = hashstate.fromui(self.ui)
ea400a4f32e6 chgserver: mangle server address to include confighash
Jun Wu <quark@fb.com>
parents: 28325
diff changeset
   661
        self.address = _hashaddress(self.address, self.hashstate.confighash)
ea400a4f32e6 chgserver: mangle server address to include confighash
Jun Wu <quark@fb.com>
parents: 28325
diff changeset
   662
28536
a979f5b03320 chgserver: invalidate the server if extensions fail to load
Jun Wu <quark@fb.com>
parents: 28535
diff changeset
   663
    def _checkextensions(self):
a979f5b03320 chgserver: invalidate the server if extensions fail to load
Jun Wu <quark@fb.com>
parents: 28535
diff changeset
   664
        if not self.hashstate:
a979f5b03320 chgserver: invalidate the server if extensions fail to load
Jun Wu <quark@fb.com>
parents: 28535
diff changeset
   665
            return
a979f5b03320 chgserver: invalidate the server if extensions fail to load
Jun Wu <quark@fb.com>
parents: 28535
diff changeset
   666
        if extensions.notloaded():
a979f5b03320 chgserver: invalidate the server if extensions fail to load
Jun Wu <quark@fb.com>
parents: 28535
diff changeset
   667
            # one or more extensions failed to load. mtimehash becomes
a979f5b03320 chgserver: invalidate the server if extensions fail to load
Jun Wu <quark@fb.com>
parents: 28535
diff changeset
   668
            # meaningless because we do not know the paths of those extensions.
a979f5b03320 chgserver: invalidate the server if extensions fail to load
Jun Wu <quark@fb.com>
parents: 28535
diff changeset
   669
            # set mtimehash to an illegal hash value to invalidate the server.
a979f5b03320 chgserver: invalidate the server if extensions fail to load
Jun Wu <quark@fb.com>
parents: 28535
diff changeset
   670
            self.hashstate.mtimehash = ''
a979f5b03320 chgserver: invalidate the server if extensions fail to load
Jun Wu <quark@fb.com>
parents: 28535
diff changeset
   671
28326
ea400a4f32e6 chgserver: mangle server address to include confighash
Jun Wu <quark@fb.com>
parents: 28325
diff changeset
   672
    def _createsymlink(self):
ea400a4f32e6 chgserver: mangle server address to include confighash
Jun Wu <quark@fb.com>
parents: 28325
diff changeset
   673
        if self.baseaddress == self.address:
ea400a4f32e6 chgserver: mangle server address to include confighash
Jun Wu <quark@fb.com>
parents: 28325
diff changeset
   674
            return
ea400a4f32e6 chgserver: mangle server address to include confighash
Jun Wu <quark@fb.com>
parents: 28325
diff changeset
   675
        tempaddress = _tempaddress(self.baseaddress)
28342
bd05d38a1002 chgserver: use basename for socket symlink
Jun Wu <quark@fb.com>
parents: 28328
diff changeset
   676
        os.symlink(os.path.basename(self.address), tempaddress)
28326
ea400a4f32e6 chgserver: mangle server address to include confighash
Jun Wu <quark@fb.com>
parents: 28325
diff changeset
   677
        util.rename(tempaddress, self.baseaddress)
ea400a4f32e6 chgserver: mangle server address to include confighash
Jun Wu <quark@fb.com>
parents: 28325
diff changeset
   678
28223
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   679
    def run(self):
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   680
        try:
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   681
            self.server.serve_forever()
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   682
        finally:
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   683
            self.server.unlinksocketfile()
0a853dc9b306 chgserver: auto exit after being idle for too long or lose the socket file
Jun Wu <quark@fb.com>
parents: 28159
diff changeset
   684
27792
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   685
def uisetup(ui):
980957333cfa chgserver: import background server extension from cHg
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
   686
    commandserver._servicemap['chgunix'] = chgunixservice
28261
2ab59ac06b76 chg: detect chg started by chg
Jun Wu <quark@fb.com>
parents: 28223
diff changeset
   687
2ab59ac06b76 chg: detect chg started by chg
Jun Wu <quark@fb.com>
parents: 28223
diff changeset
   688
    # CHGINTERNALMARK is temporarily set by chg client to detect if chg will
2ab59ac06b76 chg: detect chg started by chg
Jun Wu <quark@fb.com>
parents: 28223
diff changeset
   689
    # start another chg. drop it to avoid possible side effects.
2ab59ac06b76 chg: detect chg started by chg
Jun Wu <quark@fb.com>
parents: 28223
diff changeset
   690
    if 'CHGINTERNALMARK' in os.environ:
2ab59ac06b76 chg: detect chg started by chg
Jun Wu <quark@fb.com>
parents: 28223
diff changeset
   691
        del os.environ['CHGINTERNALMARK']