mirror of
https://github.com/servo/servo.git
synced 2025-07-17 20:33:40 +01:00
Requires servo/servo#37045 for deps and config. Testing: No need for tests to test tests. Fixes: servo/servo#37041 --------- Signed-off-by: zefr0x <zer0-x.7ty50@aleeas.com>
259 lines
9.5 KiB
Python
259 lines
9.5 KiB
Python
# Copyright 2013 The Servo Project Developers. See the COPYRIGHT
|
|
# file at the top-level directory of this distribution.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
# option. This file may not be copied, modified, or distributed
|
|
# except according to those terms.
|
|
|
|
import json
|
|
import os
|
|
import os.path as path
|
|
import subprocess
|
|
from shutil import copy2
|
|
from typing import List
|
|
|
|
import mozdebug
|
|
|
|
from mach.decorators import (
|
|
CommandArgument,
|
|
CommandProvider,
|
|
Command,
|
|
)
|
|
|
|
import servo.util
|
|
import servo.platform
|
|
|
|
from servo.command_base import (
|
|
CommandBase,
|
|
check_call,
|
|
is_linux,
|
|
)
|
|
|
|
|
|
ANDROID_APP_NAME = "org.servo.servoshell"
|
|
|
|
|
|
def read_file(filename, if_exists=False):
|
|
if if_exists and not path.exists(filename):
|
|
return None
|
|
with open(filename) as f:
|
|
return f.read()
|
|
|
|
|
|
# Copied from Python 3.3+'s shlex.quote()
|
|
def shell_quote(arg):
|
|
# use single quotes, and put single quotes into double quotes
|
|
# the string $'b is then quoted as '$'"'"'b'
|
|
return "'" + arg.replace("'", "'\"'\"'") + "'"
|
|
|
|
|
|
@CommandProvider
|
|
class PostBuildCommands(CommandBase):
|
|
@Command("run", description="Run Servo", category="post-build")
|
|
@CommandArgument(
|
|
"--android", action="store_true", default=None, help="Run on an Android device through `adb shell`"
|
|
)
|
|
@CommandArgument("--emulator", action="store_true", help="For Android, run in the only emulated device")
|
|
@CommandArgument("--usb", action="store_true", help="For Android, run in the only USB device")
|
|
@CommandArgument(
|
|
"--debugger",
|
|
action="store_true",
|
|
help="Enable the debugger. Not specifying a "
|
|
"--debugger-cmd option will result in the default "
|
|
"debugger being used. The following arguments "
|
|
"have no effect without this.",
|
|
)
|
|
@CommandArgument("--debugger-cmd", default=None, type=str, help="Name of debugger to use.")
|
|
@CommandArgument("--headless", "-z", action="store_true", help="Launch in headless mode")
|
|
@CommandArgument("--software", "-s", action="store_true", help="Launch with software rendering")
|
|
@CommandArgument("params", nargs="...", help="Command-line arguments to be passed through to Servo")
|
|
@CommandBase.common_command_arguments(binary_selection=True)
|
|
@CommandBase.allow_target_configuration
|
|
def run(
|
|
self,
|
|
servo_binary: str,
|
|
params,
|
|
debugger=False,
|
|
debugger_cmd=None,
|
|
headless=False,
|
|
software=False,
|
|
emulator=False,
|
|
usb=False,
|
|
):
|
|
return self._run(servo_binary, params, debugger, debugger_cmd, headless, software, emulator, usb)
|
|
|
|
def _run(
|
|
self,
|
|
servo_binary: str,
|
|
params,
|
|
debugger=False,
|
|
debugger_cmd=None,
|
|
headless=False,
|
|
software=False,
|
|
emulator=False,
|
|
usb=False,
|
|
):
|
|
env = self.build_env()
|
|
env["RUST_BACKTRACE"] = "1"
|
|
if software:
|
|
if not is_linux():
|
|
print("Software rendering is only supported on Linux at the moment.")
|
|
return
|
|
|
|
env["LIBGL_ALWAYS_SOFTWARE"] = "1"
|
|
os.environ.update(env)
|
|
|
|
# Make --debugger-cmd imply --debugger
|
|
if debugger_cmd:
|
|
debugger = True
|
|
|
|
if self.is_android():
|
|
if debugger:
|
|
print("Android on-device debugging is not supported by mach yet. See")
|
|
print("https://github.com/servo/servo/wiki/Building-for-Android#debugging-on-device")
|
|
return
|
|
script = [
|
|
f"am force-stop {ANDROID_APP_NAME}",
|
|
]
|
|
json_params = shell_quote(json.dumps(params))
|
|
extra = "-e servoargs " + json_params
|
|
rust_log = env.get("RUST_LOG", None)
|
|
if rust_log:
|
|
extra += " -e servolog " + rust_log
|
|
gst_debug = env.get("GST_DEBUG", None)
|
|
if gst_debug:
|
|
extra += " -e gstdebug " + gst_debug
|
|
script += [
|
|
f"am start {extra} {ANDROID_APP_NAME}/{ANDROID_APP_NAME}.MainActivity",
|
|
"sleep 0.5",
|
|
f"echo Servo PID: $(pidof {ANDROID_APP_NAME})",
|
|
f"logcat --pid=$(pidof {ANDROID_APP_NAME})",
|
|
"exit",
|
|
]
|
|
args = [self.android_adb_path(env)]
|
|
if emulator and usb:
|
|
print("Cannot run in both emulator and USB at the same time.")
|
|
return 1
|
|
if emulator:
|
|
args += ["-e"]
|
|
if usb:
|
|
args += ["-d"]
|
|
shell = subprocess.Popen(args + ["shell"], stdin=subprocess.PIPE)
|
|
shell.communicate(bytes("\n".join(script) + "\n", "utf8"))
|
|
return shell.wait()
|
|
|
|
args = [servo_binary]
|
|
|
|
if headless:
|
|
args.append("-z")
|
|
|
|
# Borrowed and modified from:
|
|
# http://hg.mozilla.org/mozilla-central/file/c9cfa9b91dea/python/mozbuild/mozbuild/mach_commands.py#l883
|
|
if debugger:
|
|
if not debugger_cmd:
|
|
# No debugger name was provided. Look for the default ones on
|
|
# current OS.
|
|
debugger_cmd = mozdebug.get_default_debugger_name(mozdebug.DebuggerSearch.KeepLooking)
|
|
|
|
debugger_info = mozdebug.get_debugger_info(debugger_cmd)
|
|
if not debugger_info:
|
|
print("Could not find a suitable debugger in your PATH.")
|
|
return 1
|
|
|
|
command = debugger_info.path
|
|
if debugger_cmd == "gdb" or debugger_cmd == "lldb":
|
|
rust_command = "rust-" + debugger_cmd
|
|
try:
|
|
subprocess.check_call([rust_command, "--version"], env=env, stdout=open(os.devnull, "w"))
|
|
except (OSError, subprocess.CalledProcessError):
|
|
pass
|
|
else:
|
|
command = rust_command
|
|
|
|
# Prepend the debugger args.
|
|
args = [command] + debugger_info.args + args + params
|
|
else:
|
|
args = args + params
|
|
|
|
try:
|
|
check_call(args, env=env)
|
|
except subprocess.CalledProcessError as exception:
|
|
if exception.returncode < 0:
|
|
print(f"Servo was terminated by signal {-exception.returncode}")
|
|
else:
|
|
print(f"Servo exited with non-zero status {exception.returncode}")
|
|
return exception.returncode
|
|
except OSError as exception:
|
|
if exception.errno == 2:
|
|
print("Servo Binary can't be found! Run './mach build' and try again!")
|
|
else:
|
|
raise exception
|
|
|
|
@Command("android-emulator", description="Run the Android emulator", category="post-build")
|
|
@CommandArgument("args", nargs="...", help="Command-line arguments to be passed through to the emulator")
|
|
def android_emulator(self, args=None):
|
|
if not args:
|
|
print("AVDs created by `./mach bootstrap-android` are servo-arm and servo-x86.")
|
|
emulator = self.android_emulator_path(self.build_env())
|
|
return subprocess.call([emulator] + args)
|
|
|
|
@Command("rr-record", description="Run Servo whilst recording execution with rr", category="post-build")
|
|
@CommandArgument("params", nargs="...", help="Command-line arguments to be passed through to Servo")
|
|
@CommandBase.common_command_arguments(binary_selection=True)
|
|
def rr_record(self, servo_binary: str, params=[]):
|
|
env = self.build_env()
|
|
env["RUST_BACKTRACE"] = "1"
|
|
|
|
servo_cmd = [servo_binary] + params
|
|
rr_cmd = ["rr", "--fatal-errors", "record"]
|
|
try:
|
|
check_call(rr_cmd + servo_cmd)
|
|
except OSError as e:
|
|
if e.errno == 2:
|
|
print("rr binary can't be found!")
|
|
else:
|
|
raise e
|
|
|
|
@Command(
|
|
"rr-replay",
|
|
description="Replay the most recent execution of Servo that was recorded with rr",
|
|
category="post-build",
|
|
)
|
|
def rr_replay(self):
|
|
try:
|
|
check_call(["rr", "--fatal-errors", "replay"])
|
|
except OSError as e:
|
|
if e.errno == 2:
|
|
print("rr binary can't be found!")
|
|
else:
|
|
raise e
|
|
|
|
@Command("doc", description="Generate documentation", category="post-build")
|
|
@CommandArgument("params", nargs="...", help="Command-line arguments to be passed through to cargo doc")
|
|
@CommandBase.common_command_arguments(build_configuration=True, build_type=False)
|
|
def doc(self, params: List[str], **kwargs):
|
|
self.ensure_bootstrapped()
|
|
|
|
docs = path.join(servo.util.get_target_dir(), "doc")
|
|
if not path.exists(docs):
|
|
os.makedirs(docs)
|
|
|
|
# Document library crates to avoid package name conflict between severoshell
|
|
# and libservo. Besides, main.rs in servoshell is just a stub.
|
|
params.insert(0, "--lib")
|
|
# Documentation build errors shouldn't cause the entire build to fail. This
|
|
# prevents issues with dependencies from breaking our documentation build,
|
|
# with the downside that it hides documentation issues.
|
|
params.insert(0, "--keep-going")
|
|
|
|
env = self.build_env()
|
|
env["RUSTC"] = "rustc"
|
|
returncode = self.run_cargo_build_like_command("doc", params, env=env, **kwargs)
|
|
if returncode:
|
|
return returncode
|
|
|
|
static = path.join(self.context.topdir, "etc", "doc.servo.org")
|
|
for name in os.listdir(static):
|
|
copy2(path.join(static, name), path.join(docs, name))
|