robotcode-plugin 2.8.0.dev677__tar.gz → 2.9.0.dev51__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {robotcode_plugin-2.8.0.dev677 → robotcode_plugin-2.9.0.dev51}/PKG-INFO +1 -1
- {robotcode_plugin-2.8.0.dev677 → robotcode_plugin-2.9.0.dev51}/src/robotcode/plugin/__init__.py +26 -0
- robotcode_plugin-2.9.0.dev51/src/robotcode/plugin/__version__.py +1 -0
- robotcode_plugin-2.9.0.dev51/src/robotcode/plugin/click_helper/wrappable.py +110 -0
- robotcode_plugin-2.8.0.dev677/src/robotcode/plugin/__version__.py +0 -1
- robotcode_plugin-2.8.0.dev677/src/robotcode/plugin/click_helper/wrappable.py +0 -26
- {robotcode_plugin-2.8.0.dev677 → robotcode_plugin-2.9.0.dev51}/.gitignore +0 -0
- {robotcode_plugin-2.8.0.dev677 → robotcode_plugin-2.9.0.dev51}/README.md +0 -0
- {robotcode_plugin-2.8.0.dev677 → robotcode_plugin-2.9.0.dev51}/pyproject.toml +0 -0
- {robotcode_plugin-2.8.0.dev677 → robotcode_plugin-2.9.0.dev51}/src/robotcode/plugin/_agent_detection.py +0 -0
- {robotcode_plugin-2.8.0.dev677 → robotcode_plugin-2.9.0.dev51}/src/robotcode/plugin/click_helper/aliases.py +0 -0
- {robotcode_plugin-2.8.0.dev677 → robotcode_plugin-2.9.0.dev51}/src/robotcode/plugin/click_helper/exit_codes.py +0 -0
- {robotcode_plugin-2.8.0.dev677 → robotcode_plugin-2.9.0.dev51}/src/robotcode/plugin/click_helper/options.py +0 -0
- {robotcode_plugin-2.8.0.dev677 → robotcode_plugin-2.9.0.dev51}/src/robotcode/plugin/click_helper/types.py +0 -0
- {robotcode_plugin-2.8.0.dev677 → robotcode_plugin-2.9.0.dev51}/src/robotcode/plugin/manager.py +0 -0
- {robotcode_plugin-2.8.0.dev677 → robotcode_plugin-2.9.0.dev51}/src/robotcode/plugin/py.typed +0 -0
- {robotcode_plugin-2.8.0.dev677 → robotcode_plugin-2.9.0.dev51}/src/robotcode/plugin/specs.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: robotcode-plugin
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.9.0-dev.51
|
|
4
4
|
Summary: Some classes for RobotCode plugin management
|
|
5
5
|
Project-URL: Donate, https://opencollective.com/robotcode
|
|
6
6
|
Project-URL: Documentation, https://github.com/robotcodedev/robotcode#readme
|
{robotcode_plugin-2.8.0.dev677 → robotcode_plugin-2.9.0.dev51}/src/robotcode/plugin/__init__.py
RENAMED
|
@@ -41,6 +41,7 @@ __all__ = [
|
|
|
41
41
|
"UnknownError",
|
|
42
42
|
"hookimpl",
|
|
43
43
|
"pass_application",
|
|
44
|
+
"show_error",
|
|
44
45
|
]
|
|
45
46
|
|
|
46
47
|
F = TypeVar("F", bound=Callable[..., Any])
|
|
@@ -83,6 +84,8 @@ class CommonConfig:
|
|
|
83
84
|
colored_output: ColoredOutput = ColoredOutput.AUTO
|
|
84
85
|
default_paths: Optional[Sequence[str]] = None
|
|
85
86
|
launcher_script: Optional[str] = None
|
|
87
|
+
wrapper: Optional[str] = None
|
|
88
|
+
no_wrapper: bool = False
|
|
86
89
|
output_format: Optional[OutputFormat] = None
|
|
87
90
|
pager: Optional[bool] = None
|
|
88
91
|
log_enabled: bool = False
|
|
@@ -528,4 +531,27 @@ class Application:
|
|
|
528
531
|
sys.path = self._syspath
|
|
529
532
|
|
|
530
533
|
|
|
534
|
+
def show_error(app: Application, error: click.ClickException, file: Optional[IO[Any]] = None) -> None:
|
|
535
|
+
"""Write a Click error as robotcode writes the errors it reports, `[ ERROR ] <message>`
|
|
536
|
+
(`Application.error`), instead of Click's `Error: <message>`.
|
|
537
|
+
|
|
538
|
+
A usage error with a context gets Click's usage line and hint to `--help` first. An
|
|
539
|
+
error that writes itself in a form of its own, such as Click's help for a command
|
|
540
|
+
called without arguments, is written by its `show`.
|
|
541
|
+
"""
|
|
542
|
+
if type(error).show not in (click.ClickException.show, click.UsageError.show):
|
|
543
|
+
error.show(file)
|
|
544
|
+
return
|
|
545
|
+
|
|
546
|
+
if isinstance(error, click.UsageError) and error.ctx is not None:
|
|
547
|
+
ctx = error.ctx
|
|
548
|
+
hint = ""
|
|
549
|
+
if ctx.command.get_help_option(ctx) is not None:
|
|
550
|
+
help_option = max(ctx.command.get_help_option_names(ctx), key=len)
|
|
551
|
+
hint = f"Try '{ctx.command_path} {help_option}' for help.\n"
|
|
552
|
+
click.echo(f"{ctx.get_usage()}\n{hint}", file=file, err=True, color=ctx.color)
|
|
553
|
+
|
|
554
|
+
app.error(error.format_message(), file=file)
|
|
555
|
+
|
|
556
|
+
|
|
531
557
|
pass_application = click.make_pass_decorator(Application, ensure=True)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2.9.0-dev.51"
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import shlex
|
|
3
|
+
import subprocess
|
|
4
|
+
import sys
|
|
5
|
+
from typing import TYPE_CHECKING, Any, Optional, Sequence
|
|
6
|
+
|
|
7
|
+
import click
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from robotcode.plugin import Application
|
|
11
|
+
|
|
12
|
+
# Set in the environment once a wrapper has been applied to the process tree.
|
|
13
|
+
# Prevents infinite re-exec recursion and lets an outer layer (e.g. the VS Code
|
|
14
|
+
# debug launcher applying its own wrapper) suppress the CLI/profile re-exec.
|
|
15
|
+
WRAPPER_APPLIED_ENV = "ROBOTCODE_WRAPPER_APPLIED"
|
|
16
|
+
|
|
17
|
+
_WRAPPABLE_ATTR = "__robotcode_wrappable__"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def wrappable(cmd: click.Command) -> click.Command:
|
|
21
|
+
"""Mark a CLI command as *wrappable*.
|
|
22
|
+
|
|
23
|
+
When a `wrapper` (session) command is configured, a wrappable command is
|
|
24
|
+
re-executed through it, because it executes Robot Framework (and may, for
|
|
25
|
+
example, need to run inside a specific X11/Wayland session). Commands that
|
|
26
|
+
do not execute Robot Framework - language server, discovery, libdoc, … -
|
|
27
|
+
must NOT be marked.
|
|
28
|
+
|
|
29
|
+
The re-execution happens when the command loads its configuration with
|
|
30
|
+
`load_robot_profile` or `handle_robot_options` of `robotcode.runner.cli.robot`,
|
|
31
|
+
so a marked command must do that first, before it starts a server, an
|
|
32
|
+
interpreter or a debugger. A marked command that loads its configuration in
|
|
33
|
+
another way runs without the wrapper.
|
|
34
|
+
"""
|
|
35
|
+
setattr(cmd, _WRAPPABLE_ATTR, True)
|
|
36
|
+
return cmd
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def is_wrappable(cmd: click.Command) -> bool:
|
|
40
|
+
"""Return whether `cmd` was marked with :func:`wrappable`."""
|
|
41
|
+
return bool(getattr(cmd, _WRAPPABLE_ATTR, False))
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def invoked_command_is_wrappable(ctx: click.Context) -> bool:
|
|
45
|
+
"""Return whether the command that the root group invokes is marked with :func:`wrappable`.
|
|
46
|
+
|
|
47
|
+
A command that such a command runs itself, such as `robot` in `debug`, belongs to it.
|
|
48
|
+
"""
|
|
49
|
+
root = ctx.find_root()
|
|
50
|
+
sub_name = root.invoked_subcommand
|
|
51
|
+
if not sub_name or not isinstance(root.command, click.Group):
|
|
52
|
+
return False
|
|
53
|
+
# Aliases resolve to the same command object, so this is alias-safe and needs
|
|
54
|
+
# no central name list.
|
|
55
|
+
sub_cmd = root.command.get_command(root, sub_name)
|
|
56
|
+
return sub_cmd is not None and is_wrappable(sub_cmd)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def run_under_wrapper(app: "Application", profile_wrapper: Optional[Sequence[Any]]) -> None:
|
|
60
|
+
"""Re-execute this process through the configured ``wrapper`` command.
|
|
61
|
+
|
|
62
|
+
A wrappable command calls this once it has loaded its configuration, before it
|
|
63
|
+
starts anything. ``--wrapper`` overrides the ``wrapper`` of the profile
|
|
64
|
+
(``profile_wrapper``); ``--no-wrapper`` disables wrapping for this run. The
|
|
65
|
+
guard env var prevents infinite recursion and lets an outer layer suppress the
|
|
66
|
+
re-exec by setting it itself. Returns when no wrapper applies or for a dry run.
|
|
67
|
+
"""
|
|
68
|
+
if app.config.no_wrapper or os.environ.get(WRAPPER_APPLIED_ENV):
|
|
69
|
+
return
|
|
70
|
+
|
|
71
|
+
# `--wrapper` overrides the profile's `wrapper`. The evaluated profile turns
|
|
72
|
+
# StringExpression entries into plain strings.
|
|
73
|
+
if app.config.wrapper:
|
|
74
|
+
wrapper = shlex.split(app.config.wrapper)
|
|
75
|
+
elif profile_wrapper:
|
|
76
|
+
wrapper = [str(w) for w in profile_wrapper]
|
|
77
|
+
else:
|
|
78
|
+
return
|
|
79
|
+
|
|
80
|
+
# A dry run must not start the wrapper: it would set up and tear down the
|
|
81
|
+
# real environment. Show it instead; the command itself then prints its own
|
|
82
|
+
# dry-run output.
|
|
83
|
+
if app.config.dry:
|
|
84
|
+
app.echo(f"Dry run, not executing the wrapper. Would run robotcode under: {' '.join(wrapper)}")
|
|
85
|
+
return
|
|
86
|
+
|
|
87
|
+
# Rebuild the invocation the way this process was actually started, so the
|
|
88
|
+
# re-exec finds robotcode even when it runs from a bundled path (VS Code) and
|
|
89
|
+
# is not installed in the interpreter. `launcher_script` is set only when we
|
|
90
|
+
# were started through a bundled entry (its `__main__` sets it) or an explicit
|
|
91
|
+
# `--launcher-script`; otherwise robotcode is importable directly and
|
|
92
|
+
# `-m robotcode.cli` is correct. We deliberately do NOT consult the
|
|
93
|
+
# ROBOTCODE_BUNDLED_ROBOTCODE_MAIN env var: VS Code sets it in every terminal,
|
|
94
|
+
# so a directly started robotcode would be diverted to the bundled copy.
|
|
95
|
+
# Mirrors the debug launcher's `debugger_script` handling.
|
|
96
|
+
entry = [str(app.config.launcher_script)] if app.config.launcher_script else ["-m", "robotcode.cli"]
|
|
97
|
+
command = [*wrapper, sys.executable, *entry, *sys.argv[1:]]
|
|
98
|
+
app.verbose(lambda: "Running under wrapper: " + " ".join(command))
|
|
99
|
+
|
|
100
|
+
# Run robotcode again under the wrapper; the guard env stops the spawned
|
|
101
|
+
# robotcode from wrapping a second time. On POSIX we replace this process with
|
|
102
|
+
# execvp (no extra process); Windows has no such exec, so there we spawn the
|
|
103
|
+
# command, wait, and forward its exit code.
|
|
104
|
+
os.environ[WRAPPER_APPLIED_ENV] = "1"
|
|
105
|
+
try:
|
|
106
|
+
if sys.platform == "win32":
|
|
107
|
+
sys.exit(subprocess.run(command).returncode)
|
|
108
|
+
os.execvp(command[0], command)
|
|
109
|
+
except OSError as e:
|
|
110
|
+
raise click.ClickException(f"Failed to execute wrapper command {wrapper!r}: {e}") from e
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "2.8.0-dev.677"
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import click
|
|
2
|
-
|
|
3
|
-
# Set in the environment once a wrapper has been applied to the process tree.
|
|
4
|
-
# Prevents infinite re-exec recursion and lets an outer layer (e.g. the VS Code
|
|
5
|
-
# debug launcher applying its own wrapper) suppress the CLI/profile re-exec.
|
|
6
|
-
WRAPPER_APPLIED_ENV = "ROBOTCODE_WRAPPER_APPLIED"
|
|
7
|
-
|
|
8
|
-
_WRAPPABLE_ATTR = "__robotcode_wrappable__"
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def wrappable(cmd: click.Command) -> click.Command:
|
|
12
|
-
"""Mark a CLI command as *wrappable*.
|
|
13
|
-
|
|
14
|
-
When a `wrapper` (session) command is configured, a wrappable command is
|
|
15
|
-
re-executed through it, because it executes Robot Framework (and may, for
|
|
16
|
-
example, need to run inside a specific X11/Wayland session). Commands that
|
|
17
|
-
do not execute Robot Framework - language server, discovery, libdoc, … -
|
|
18
|
-
must NOT be marked.
|
|
19
|
-
"""
|
|
20
|
-
setattr(cmd, _WRAPPABLE_ATTR, True)
|
|
21
|
-
return cmd
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def is_wrappable(cmd: click.Command) -> bool:
|
|
25
|
-
"""Return whether `cmd` was marked with :func:`wrappable`."""
|
|
26
|
-
return bool(getattr(cmd, _WRAPPABLE_ATTR, False))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{robotcode_plugin-2.8.0.dev677 → robotcode_plugin-2.9.0.dev51}/src/robotcode/plugin/manager.py
RENAMED
|
File without changes
|
{robotcode_plugin-2.8.0.dev677 → robotcode_plugin-2.9.0.dev51}/src/robotcode/plugin/py.typed
RENAMED
|
File without changes
|
{robotcode_plugin-2.8.0.dev677 → robotcode_plugin-2.9.0.dev51}/src/robotcode/plugin/specs.py
RENAMED
|
File without changes
|