зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1722832
- Streamline UX for `./mach ide vscode` with existing settings or in remote shells, r=andi
This patch has a few minor improvements to `./mach ide vscode` to make it nicer to use in various situations. Specifically: * Tries to locate the `code` using `shutil.which` in addition to the existing methods so that the binary is found when being run from within a vscode remote shell. * If locating the code binary fails, only prompts to ask whether or not to continue, rather than requiring entering the complete path. The only use of the vscode command is to start an instance connected to the correct path, so if no binary was found, a message is logged instead. (bug 1699943) * When changes need to be made to the settings.json file, a full diff is shown between the old and new files, rather than just showing the computed state before and after. * If parsing the existing settings.json file fails (e.g. because there were c-style comments in it - see bug 1670997), the diff is shown and an additional warning is emitted to ask if the change should be made. Differential Revision: https://phabricator.services.mozilla.com/D121157
This commit is contained in:
Родитель
2a64c08522
Коммит
15880d1df1
|
@ -49,13 +49,14 @@ class MachCommands(MachCommandBase):
|
|||
return 1
|
||||
|
||||
if ide == "vscode":
|
||||
# Verify if platform has VSCode installed
|
||||
vscode_cmd = self.found_vscode_path(command_context)
|
||||
# Check if platform has VSCode installed
|
||||
vscode_cmd = self.find_vscode_cmd(command_context)
|
||||
if vscode_cmd is None:
|
||||
command_context.log(
|
||||
logging.ERROR, "ide", {}, "VSCode cannot be found, aborting!"
|
||||
choice = prompt_bool(
|
||||
"VSCode cannot be found, and may not be installed. Proceed?"
|
||||
)
|
||||
return 1
|
||||
if not choice:
|
||||
return 1
|
||||
|
||||
# Create the Build environment to configure the tree
|
||||
builder = Build(command_context._mach_context, None)
|
||||
|
@ -124,8 +125,18 @@ class MachCommands(MachCommandBase):
|
|||
def get_visualstudio_workspace_path(self, command_context):
|
||||
return os.path.join(command_context.topobjdir, "msvc", "mozilla.sln")
|
||||
|
||||
def found_vscode_path(self, command_context):
|
||||
def find_vscode_cmd(self, command_context):
|
||||
import shutil
|
||||
|
||||
# Try to look up the `code` binary on $PATH, and use it if present. This
|
||||
# should catch cases like being run from within a vscode-remote shell,
|
||||
# even if vscode itself is also installed on the remote host.
|
||||
path = shutil.which("code")
|
||||
if path is not None:
|
||||
return [path]
|
||||
|
||||
# If the binary wasn't on $PATH, try to find it in a variety of other
|
||||
# well-known install locations based on the current platform.
|
||||
if "linux" in command_context.platform[0]:
|
||||
cmd_and_path = [
|
||||
{"path": "/usr/local/bin/code", "cmd": ["/usr/local/bin/code"]},
|
||||
|
@ -178,13 +189,6 @@ class MachCommands(MachCommandBase):
|
|||
if os.path.exists(element["path"]):
|
||||
return element["cmd"]
|
||||
|
||||
for _ in range(5):
|
||||
vscode_path = input(
|
||||
"Could not find the VSCode binary. Please provide the full path to it:\n"
|
||||
)
|
||||
if os.path.exists(vscode_path):
|
||||
return [vscode_path]
|
||||
|
||||
# Path cannot be found
|
||||
return None
|
||||
|
||||
|
@ -220,19 +224,18 @@ class MachCommands(MachCommandBase):
|
|||
|
||||
import multiprocessing
|
||||
import json
|
||||
import difflib
|
||||
from mozbuild.code_analysis.utils import ClangTidyConfig
|
||||
|
||||
clang_tidy_cfg = ClangTidyConfig(command_context.topsrcdir)
|
||||
|
||||
clangd_json = json.loads(
|
||||
"""
|
||||
{
|
||||
"clangd.path": "%s",
|
||||
clangd_json = {
|
||||
"clangd.path": clangd_path,
|
||||
"clangd.arguments": [
|
||||
"--compile-commands-dir",
|
||||
"%s",
|
||||
clangd_cc_path,
|
||||
"-j",
|
||||
"%s",
|
||||
str(multiprocessing.cpu_count() // 2),
|
||||
"--limit-results",
|
||||
"0",
|
||||
"--completion-style",
|
||||
|
@ -245,61 +248,77 @@ class MachCommands(MachCommandBase):
|
|||
"memory",
|
||||
"--clang-tidy",
|
||||
"--clang-tidy-checks",
|
||||
"%s"
|
||||
]
|
||||
}
|
||||
"""
|
||||
% (
|
||||
clangd_path,
|
||||
clangd_cc_path,
|
||||
int(multiprocessing.cpu_count() / 2),
|
||||
",".join(clang_tidy_cfg.checks),
|
||||
)
|
||||
)
|
||||
],
|
||||
}
|
||||
|
||||
# Create an empty settings dictionary
|
||||
settings = {}
|
||||
|
||||
# Modify the .vscode/settings.json configuration file
|
||||
if os.path.exists(vscode_settings):
|
||||
# If exists prompt for a configuration change
|
||||
choice = prompt_bool(
|
||||
"Configuration for {settings} must change. "
|
||||
"Do you want to proceed?".format(settings=vscode_settings)
|
||||
)
|
||||
if not choice:
|
||||
return 1
|
||||
|
||||
# Read the original vscode settings
|
||||
# Load the existing .vscode/settings.json file, to check if if needs to
|
||||
# be created or updated.
|
||||
try:
|
||||
with open(vscode_settings) as fh:
|
||||
try:
|
||||
settings = json.load(fh)
|
||||
print(
|
||||
"The following modifications will occur:\nOriginal:\n{orig}\n"
|
||||
"New:\n{new}".format(
|
||||
orig=json.dumps(
|
||||
{
|
||||
key: settings[key] if key in settings else ""
|
||||
for key in ["clangd.path", "clangd.arguments"]
|
||||
},
|
||||
indent=4,
|
||||
),
|
||||
new=json.dumps(clangd_json, indent=4),
|
||||
)
|
||||
old_settings_str = fh.read()
|
||||
except FileNotFoundError:
|
||||
print("Configuration for {} will be created.".format(vscode_settings))
|
||||
old_settings_str = None
|
||||
|
||||
if old_settings_str is None:
|
||||
# No old settings exist
|
||||
with open(vscode_settings, "w") as fh:
|
||||
json.dump(clangd_json, fh, indent=4)
|
||||
else:
|
||||
# Merge our new settings with the existing settings, and check if we
|
||||
# need to make changes. Only prompt & write out the updated config
|
||||
# file if settings actually changed.
|
||||
try:
|
||||
old_settings = json.loads(old_settings_str)
|
||||
prompt_prefix = ""
|
||||
except ValueError:
|
||||
old_settings = {}
|
||||
prompt_prefix = (
|
||||
"\n**WARNING**: Parsing of existing settings file failed. "
|
||||
"Existing settings will be lost!"
|
||||
)
|
||||
|
||||
settings = {**old_settings, **clangd_json}
|
||||
|
||||
if old_settings != settings:
|
||||
# Prompt the user with a diff of the changes we're going to make
|
||||
new_settings_str = json.dumps(settings, indent=4)
|
||||
print(
|
||||
"\nThe following modifications to {settings} will occur:\n{diff}".format(
|
||||
settings=vscode_settings,
|
||||
diff="".join(
|
||||
difflib.unified_diff(
|
||||
old_settings_str.splitlines(keepends=True),
|
||||
new_settings_str.splitlines(keepends=True),
|
||||
"a/.vscode/settings.json",
|
||||
"b/.vscode/settings.json",
|
||||
n=30,
|
||||
)
|
||||
),
|
||||
)
|
||||
)
|
||||
choice = prompt_bool(
|
||||
"{}\nProceed with modifications to {}?".format(
|
||||
prompt_prefix, vscode_settings
|
||||
)
|
||||
)
|
||||
if not choice:
|
||||
return 1
|
||||
|
||||
except ValueError:
|
||||
# Decoding has failed, work with an empty dict
|
||||
settings = {}
|
||||
with open(vscode_settings, "w") as fh:
|
||||
fh.write(new_settings_str)
|
||||
|
||||
# Write our own Configuration
|
||||
settings["clangd.path"] = clangd_json["clangd.path"]
|
||||
settings["clangd.arguments"] = clangd_json["clangd.arguments"]
|
||||
# Open vscode with new configuration, or ask the user to do so if the
|
||||
# binary was not found.
|
||||
if vscode_cmd is None:
|
||||
print(
|
||||
"Please open VS Code manually and load directory: {}".format(
|
||||
command_context.topsrcdir
|
||||
)
|
||||
)
|
||||
return 0
|
||||
|
||||
with open(vscode_settings, "w") as fh:
|
||||
fh.write(json.dumps(settings, indent=4))
|
||||
|
||||
# Open vscode with new configuration
|
||||
rc = subprocess.call(vscode_cmd + [command_context.topsrcdir])
|
||||
|
||||
if rc != 0:
|
||||
|
|
Загрузка…
Ссылка в новой задаче