tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

server_utils.py (4193B)


      1 # Copyright 2021 The Chromium Authors
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 import contextlib
      6 import json
      7 import os
      8 import pathlib
      9 import socket
     10 import platform
     11 import sys
     12 import struct
     13 
     14 sys.path.insert(1, os.path.join(os.path.dirname(__file__), '..'))
     15 from util import build_utils
     16 
     17 # Use a unix abstract domain socket:
     18 # https://man7.org/linux/man-pages/man7/unix.7.html#:~:text=abstract:
     19 SOCKET_ADDRESS = '\0chromium_build_server_socket'
     20 BUILD_SERVER_ENV_VARIABLE = 'INVOKED_BY_BUILD_SERVER'
     21 
     22 ADD_TASK = 'add_task'
     23 QUERY_BUILD = 'query_build'
     24 POLL_HEARTBEAT = 'poll_heartbeat'
     25 REGISTER_BUILDER = 'register_builder'
     26 CANCEL_BUILD = 'cancel_build'
     27 
     28 SERVER_SCRIPT = pathlib.Path(
     29    build_utils.DIR_SOURCE_ROOT
     30 ) / 'build' / 'android' / 'fast_local_dev_server.py'
     31 
     32 
     33 def AssertEnvironmentVariables():
     34  assert os.environ.get('AUTONINJA_BUILD_ID')
     35  assert os.environ.get('AUTONINJA_STDOUT_NAME')
     36 
     37 
     38 def MaybeRunCommand(name, argv, stamp_file, use_build_server=False):
     39  """Returns True if the command was successfully sent to the build server."""
     40  if not use_build_server or platform.system() == 'Darwin':
     41    # Build server does not support Mac.
     42    return False
     43 
     44  # When the build server runs a command, it sets this environment variable.
     45  # This prevents infinite recursion where the script sends a request to the
     46  # build server, then the build server runs the script, and then the script
     47  # sends another request to the build server.
     48  if BUILD_SERVER_ENV_VARIABLE in os.environ:
     49    return False
     50 
     51  build_id = os.environ.get('AUTONINJA_BUILD_ID')
     52  if not build_id:
     53    raise Exception(
     54        'AUTONINJA_BUILD_ID is not set. Should have been set by autoninja.')
     55  stdout_name = os.environ.get('AUTONINJA_STDOUT_NAME')
     56  # If we get a bad tty (happens when autoninja is not run from the terminal
     57  # directly but as part of another script), ignore the build server and build
     58  # normally since the build server will not know where to output to otherwise.
     59  if not stdout_name or not os.path.exists(stdout_name):
     60    return False
     61 
     62  with contextlib.closing(socket.socket(socket.AF_UNIX)) as sock:
     63    try:
     64      sock.connect(SOCKET_ADDRESS)
     65    except socket.error as e:
     66      # [Errno 111] Connection refused. Either the server has not been started
     67      #             or the server is not currently accepting new connections.
     68      if e.errno == 111:
     69        raise RuntimeError(
     70            '\n\nBuild server is not running and '
     71            'android_static_analysis="build_server" is set.\n\n') from None
     72      raise e
     73 
     74    SendMessage(
     75        sock, {
     76            'name': name,
     77            'message_type': ADD_TASK,
     78            'cmd': [sys.executable] + argv,
     79            'cwd': os.getcwd(),
     80            'build_id': build_id,
     81            'stamp_file': stamp_file,
     82        })
     83 
     84  # Siso needs the stamp file to be created in order for the build step to
     85  # complete. If the task fails when the build server runs it, the build server
     86  # will delete the stamp file so that it will be run again next build.
     87  build_utils.Touch(stamp_file)
     88  return True
     89 
     90 
     91 def MaybeTouch(stamp_file):
     92  """Touch |stamp_file| if we are not running under the build_server."""
     93  # If we are running under the build server, the stamp file has already been
     94  # touched when the task was created. If we touch it again, siso will consider
     95  # the target dirty.
     96  if BUILD_SERVER_ENV_VARIABLE in os.environ:
     97    return
     98  build_utils.Touch(stamp_file)
     99 
    100 
    101 def SendMessage(sock: socket.socket, message: dict):
    102  data = json.dumps(message).encode('utf-8')
    103  size_prefix = struct.pack('!i', len(data))
    104  sock.sendall(size_prefix + data)
    105 
    106 
    107 def ReceiveMessage(sock: socket.socket) -> dict:
    108  size_prefix = b''
    109  remaining = 4  # sizeof(int)
    110  while remaining > 0:
    111    data = sock.recv(remaining)
    112    if not data:
    113      return None
    114    remaining -= len(data)
    115    size_prefix += data
    116  remaining, = struct.unpack('!i', size_prefix)
    117  received = []
    118  while remaining > 0:
    119    data = sock.recv(remaining)
    120    if not data:
    121      break
    122    received.append(data)
    123    remaining -= len(data)
    124  if received:
    125    return json.loads(b''.join(received))
    126  return None