Skip to content

Commit

Permalink
Refactoring to allow for user libraries to have the libspec generated…
Browse files Browse the repository at this point in the history
… / show progress of the generation. WIP #163
  • Loading branch information
fabioz committed Nov 24, 2021
1 parent 7dda87f commit 0457e14
Show file tree
Hide file tree
Showing 22 changed files with 562 additions and 85 deletions.
5 changes: 5 additions & 0 deletions robocorp-python-ls-core/src/robocorp_ls_core/basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -441,3 +441,8 @@ def build_subprocess_kwargs(cwd, env, **kwargs) -> dict:
kwargs["env"] = env
kwargs["startupinfo"] = startupinfo
return kwargs


def make_unique(lst):
seen = set()
return [x for x in lst if x not in seen and not seen.add(x)]
72 changes: 64 additions & 8 deletions robocorp-python-ls-core/src/robocorp_ls_core/progress_report.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
from functools import partial
import itertools
import threading

from robocorp_ls_core.protocols import IEndPoint, IDirCache
from robocorp_ls_core.protocols import IEndPoint, IDirCache, IProgressReporter
from contextlib import contextmanager
from typing import Optional
from typing import Optional, Iterator
from robocorp_ls_core.robotframework_log import get_logger
from robocorp_ls_core.basic import implements


log = get_logger(__name__)
next_id = partial(next, itertools.count(1))


def _next_id():
# Note: changed to uuid from incremental because multiple processes
# may start the progress and it shouldn't conflict from one to the
# other.
import uuid

return str(uuid.uuid4())


class _ProgressReporter(object):
Expand All @@ -33,7 +40,7 @@ def __init__(
self._finished = False

self._lock = threading.Lock()
self._id = next_id()
self._id = _next_id()

self._expected_time = None
self._initial_time = time.time()
Expand Down Expand Up @@ -107,6 +114,7 @@ def _on_recurrent_timeout(self) -> None:
self.endpoint.notify("$/customProgress", args)
self.timeout_tracker.call_on_timeout(0.5, self._on_recurrent_timeout)

@implements(IProgressReporter.set_additional_info)
def set_additional_info(self, additional_info: str) -> None:
self._additional_info = additional_info

Expand All @@ -125,6 +133,11 @@ def finish(self) -> None:
if dir_cache:
dir_cache.store(self._last_elapsed_time_key, total_elapsed_time)

def __typecheckself__(self) -> None:
from robocorp_ls_core.protocols import check_implements

_: IProgressReporter = check_implements(self)


_progress_context = threading.local()

Expand All @@ -145,13 +158,56 @@ def get_current_progress_reporter() -> Optional[_ProgressReporter]:
return None


class ProgressWrapperForTotalWork:
"""
Wraps an IProgressReporter to have a quick way to show stes/total steps.
i.e.:
with progress_context(...) as progress_reporter:
progress_wrapper = ProgressWrapperForTotalWork(progress_reporter)
# Schedule many steps and at each point call.
progress_reporter.increment_total_steps()
# When a step is done, increment steps done.
progress_reporter.increment_step_done()
"""

def __init__(
self,
progress_reporter: IProgressReporter,
message: str = "%s of %s",
) -> None:
self.progress_reporter = progress_reporter
self.message = message
self._lock = threading.Lock()
self._total_steps = 0
self._current_step = 0

def increment_total_steps(self):
with self._lock:
self._total_steps += 1
self._update_message()

def increment_step_done(self):
with self._lock:
self._current_step += 1
self._update_message()

def _update_message(self):
self.progress_reporter.set_additional_info(
self.message % (self._current_step, self._total_steps)
)


@contextmanager
def progress_context(
endpoint: IEndPoint,
title: str,
dir_cache: Optional[IDirCache],
elapsed_time_key=None,
):
) -> Iterator[IProgressReporter]:
"""
Creates a progress context which submits $/customProgress notifications to the
client.
Expand All @@ -177,7 +233,7 @@ def progress_context(

stack.append(progress_reporter)
try:
yield
yield progress_reporter
finally:
del stack[-1]
progress_reporter.finish()
9 changes: 9 additions & 0 deletions robocorp-python-ls-core/src/robocorp_ls_core/protocols.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,15 @@ def consume(self, message: Dict):
"""


class IProgressReporter(Protocol):
def set_additional_info(self, additional_info: str) -> None:
"""
The progress reporter shows the title and elapsed time automatically.
With this API it's possible to add additional info for the user to see.
"""


class CommunicationDropped(object):
def __str__(self):
return "CommunicationDropped"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class RobotState {
public String robotVariables = "";
public String robotPythonpath = "";
public String robotLibrariesLibdocNeedsArgs = "";
public String robotLibrariesLibdocPreGenerate = "";
public String robotCodeFormatter = "";
public String robotLintRobocopEnabled = "";
public String robotCompletionsSectionHeadersForm = "";
Expand All @@ -45,6 +46,7 @@ public class RobotPreferences implements PersistentStateComponent<RobotState> {
public static final String ROBOT_VARIABLES = "robot.variables";
public static final String ROBOT_PYTHONPATH = "robot.pythonpath";
public static final String ROBOT_LIBRARIES_LIBDOC_NEEDS_ARGS = "robot.libraries.libdoc.needsArgs";
public static final String ROBOT_LIBRARIES_LIBDOC_PRE_GENERATE = "robot.libraries.libdoc.preGenerate";
public static final String ROBOT_CODE_FORMATTER = "robot.codeFormatter";
public static final String ROBOT_LINT_ROBOCOP_ENABLED = "robot.lint.robocop.enabled";
public static final String ROBOT_COMPLETIONS_SECTION_HEADERS_FORM = "robot.completions.section_headers.form";
Expand All @@ -67,6 +69,7 @@ public RobotState getState() {
robotState.robotVariables = getRobotVariables();
robotState.robotPythonpath = getRobotPythonpath();
robotState.robotLibrariesLibdocNeedsArgs = getRobotLibrariesLibdocNeedsArgs();
robotState.robotLibrariesLibdocPreGenerate = getRobotLibrariesLibdocPreGenerate();
robotState.robotCodeFormatter = getRobotCodeFormatter();
robotState.robotLintRobocopEnabled = getRobotLintRobocopEnabled();
robotState.robotCompletionsSectionHeadersForm = getRobotCompletionsSectionHeadersForm();
Expand All @@ -87,6 +90,7 @@ public void loadState(@NotNull RobotState robotState) {
setRobotVariables(robotState.robotVariables);
setRobotPythonpath(robotState.robotPythonpath);
setRobotLibrariesLibdocNeedsArgs(robotState.robotLibrariesLibdocNeedsArgs);
setRobotLibrariesLibdocPreGenerate(robotState.robotLibrariesLibdocPreGenerate);
setRobotCodeFormatter(robotState.robotCodeFormatter);
setRobotLintRobocopEnabled(robotState.robotLintRobocopEnabled);
setRobotCompletionsSectionHeadersForm(robotState.robotCompletionsSectionHeadersForm);
Expand Down Expand Up @@ -163,6 +167,14 @@ public JsonObject asJsonObject() {
}
}

if(!robotLibrariesLibdocPreGenerate.isEmpty()){
try {
jsonObject.add(ROBOT_LIBRARIES_LIBDOC_PRE_GENERATE, g.fromJson(robotLibrariesLibdocPreGenerate, JsonArray.class));
} catch(Exception e) {
LOG.error(e);
}
}

if(!robotCodeFormatter.isEmpty()){
try {
jsonObject.add(ROBOT_CODE_FORMATTER, new JsonPrimitive(robotCodeFormatter));
Expand Down Expand Up @@ -551,6 +563,49 @@ public void setRobotLibrariesLibdocNeedsArgs(String s) {
}
}

private String robotLibrariesLibdocPreGenerate = "";

public @NotNull String getRobotLibrariesLibdocPreGenerate() {
return robotLibrariesLibdocPreGenerate;
}

public @Nullable JsonArray getRobotLibrariesLibdocPreGenerateAsJson() {
if(robotLibrariesLibdocPreGenerate.isEmpty()){
return null;
}
Gson g = new Gson();
return g.fromJson(robotLibrariesLibdocPreGenerate, JsonArray.class);
}

public @NotNull String validateRobotLibrariesLibdocPreGenerate(String robotLibrariesLibdocPreGenerate) {
if(robotLibrariesLibdocPreGenerate.isEmpty()) {
return "";
}
try {
Gson g = new Gson();
g.fromJson(robotLibrariesLibdocPreGenerate, JsonArray.class);

return "";

} catch(Exception e) {
return e.toString();
}
}

public void setRobotLibrariesLibdocPreGenerate(String s) {
if (s == null) {
s = "";
}
if (s.equals(robotLibrariesLibdocPreGenerate)) {
return;
}
String old = robotLibrariesLibdocPreGenerate;
robotLibrariesLibdocPreGenerate = s;
for (LanguageServerDefinition.IPreferencesListener listener : listeners) {
listener.onChanged(ROBOT_LIBRARIES_LIBDOC_PRE_GENERATE, old, s);
}
}

private String robotCodeFormatter = "";

public @NotNull String getRobotCodeFormatter() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class RobotPreferencesComponent {
private final JBTextField robotVariables = new JBTextField();
private final JBTextField robotPythonpath = new JBTextField();
private final JBTextField robotLibrariesLibdocNeedsArgs = new JBTextField();
private final JBTextField robotLibrariesLibdocPreGenerate = new JBTextField();
private final JBTextField robotCodeFormatter = new JBTextField();
private final JBTextField robotLintRobocopEnabled = new JBTextField();
private final JBTextField robotCompletionsSectionHeadersForm = new JBTextField();
Expand All @@ -52,6 +53,8 @@ public RobotPreferencesComponent() {
.addComponent(createJTextArea("Entries to be added to the PYTHONPATH\n(used when resolving resources and imports and automatically passed to the launch config as\n--pythonpath entries).\n(i.e.: [\"c:/my/pro/src\"])\nNote: expected format: JSON Array\n"))
.addLabeledComponent(new JBLabel("Libraries Libdoc Needs Args"), robotLibrariesLibdocNeedsArgs, 1, false)
.addComponent(createJTextArea("Libraries which will generate a different set of keywords based on the arguments provided.\n(i.e.: [\"remote\", \"fakerlib\"])\nNote: expected format: JSON Array\n"))
.addLabeledComponent(new JBLabel("Libraries Libdoc Pre Generate"), robotLibrariesLibdocPreGenerate, 1, false)
.addComponent(createJTextArea("List of libraries which should have the libspec pre-generated.\nNote: expected format: JSON Array\n"))
.addLabeledComponent(new JBLabel("Code Formatter"), robotCodeFormatter, 1, false)
.addComponent(createJTextArea("Allows the configuration of the code-formatter engine to be used. One of: robotidy, builtinTidy.\n"))
.addLabeledComponent(new JBLabel("Lint Robocop Enabled"), robotLintRobocopEnabled, 1, false)
Expand Down Expand Up @@ -158,6 +161,15 @@ public void setRobotLibrariesLibdocNeedsArgs (@NotNull String newText) {
robotLibrariesLibdocNeedsArgs.setText(newText);
}

@NotNull
public String getRobotLibrariesLibdocPreGenerate() {
return robotLibrariesLibdocPreGenerate.getText();
}

public void setRobotLibrariesLibdocPreGenerate (@NotNull String newText) {
robotLibrariesLibdocPreGenerate.setText(newText);
}

@NotNull
public String getRobotCodeFormatter() {
return robotCodeFormatter.getText();
Expand Down Expand Up @@ -263,6 +275,10 @@ public boolean isModified() {
return true;
}

if(!settings.getRobotLibrariesLibdocPreGenerate().equals(component.getRobotLibrariesLibdocPreGenerate())){
return true;
}

if(!settings.getRobotCodeFormatter().equals(component.getRobotCodeFormatter())){
return true;
}
Expand Down Expand Up @@ -298,6 +314,7 @@ public void reset() {
component.setRobotVariables(settings.getRobotVariables());
component.setRobotPythonpath(settings.getRobotPythonpath());
component.setRobotLibrariesLibdocNeedsArgs(settings.getRobotLibrariesLibdocNeedsArgs());
component.setRobotLibrariesLibdocPreGenerate(settings.getRobotLibrariesLibdocPreGenerate());
component.setRobotCodeFormatter(settings.getRobotCodeFormatter());
component.setRobotLintRobocopEnabled(settings.getRobotLintRobocopEnabled());
component.setRobotCompletionsSectionHeadersForm(settings.getRobotCompletionsSectionHeadersForm());
Expand Down Expand Up @@ -342,6 +359,10 @@ public void apply() throws ConfigurationException {
if(!s.isEmpty()) {
throw new ConfigurationException("Error in Libraries Libdoc Needs Args:\n" + s);
}
s = settings.validateRobotLibrariesLibdocPreGenerate(component.getRobotLibrariesLibdocPreGenerate());
if(!s.isEmpty()) {
throw new ConfigurationException("Error in Libraries Libdoc Pre Generate:\n" + s);
}
s = settings.validateRobotCodeFormatter(component.getRobotCodeFormatter());
if(!s.isEmpty()) {
throw new ConfigurationException("Error in Code Formatter:\n" + s);
Expand Down Expand Up @@ -371,6 +392,7 @@ public void apply() throws ConfigurationException {
settings.setRobotVariables(component.getRobotVariables());
settings.setRobotPythonpath(component.getRobotPythonpath());
settings.setRobotLibrariesLibdocNeedsArgs(component.getRobotLibrariesLibdocNeedsArgs());
settings.setRobotLibrariesLibdocPreGenerate(component.getRobotLibrariesLibdocPreGenerate());
settings.setRobotCodeFormatter(component.getRobotCodeFormatter());
settings.setRobotLintRobocopEnabled(component.getRobotLintRobocopEnabled());
settings.setRobotCompletionsSectionHeadersForm(component.getRobotCompletionsSectionHeadersForm());
Expand Down
Loading

0 comments on commit 0457e14

Please sign in to comment.