def yaml_contents(self) -> dict:
        yaml_contents = self._yaml_contents
        if yaml_contents is None:
            from robocorp_ls_core import yaml_wrapper
            from io import StringIO

            s = StringIO(self.contents)
            yaml_contents = self._yaml_contents = yaml_wrapper.load(s)
        return yaml_contents
                def get_robot_metadata(robot_yaml: Path):
                    name = robot_yaml.parent.name
                    with robot_yaml.open("r", encoding="utf-8") as stream:
                        yaml_contents = yaml_wrapper.load(stream)
                        name = yaml_contents.get("name", name)

                    robot_metadata: LocalRobotMetadataInfoDict = {
                        "directory": str(sub),
                        "filePath": str(robot_yaml),
                        "name": name,
                        "yamlContents": yaml_contents,
                    }
                    return robot_metadata
    def get_yaml_contents(self) -> Optional[Any]:
        try:
            source = self.source
        except:
            log.exception("Error getting source for: %s" % (self.uri, ))
            return None

        try:
            from robocorp_ls_core import yaml_wrapper
            from io import StringIO

            s = StringIO()
            s.write(source)
            s.seek(0)
            return yaml_wrapper.load(s)
        except:
            log.critical(f"Error parsing yaml file: {self.uri}")
            return None
Exemple #4
0
    def _get_robot_metadata(self,
                            sub: Path) -> Optional[LocalRobotMetadataInfoDict]:
        robot_yaml = sub / "robot.yaml"

        if robot_yaml.exists():
            # Let's try to get the name from the yaml, if it's
            # not there, use the folder name.
            name = sub.name
            from robocorp_ls_core import yaml_wrapper

            try:
                with robot_yaml.open("r", encoding="utf-8") as stream:
                    yaml_contents = yaml_wrapper.load(stream)
                    name = yaml_contents.get("name", name)
            except:
                log.exception("Unable to get Robot name for: %s", robot_yaml)

            folder_info: LocalRobotMetadataInfoDict = {
                "directory": str(sub),
                "name": name,
            }
            return folder_info
        return None
Exemple #5
0
def compute_robot_launch_from_robocorp_code_launch(
    name: Optional[str],
    request: Optional[str],
    task: Optional[str],
    robot: Optional[str],
    additional_pythonpath_entries: Optional[List[str]],
    env: Optional[Dict[str, str]],
    python_exe: Optional[str],
) -> ActionResultDictRobotLaunch:

    if not name:
        return {
            "success": False,
            "message": "'name' must be specified to make launch.",
            "result": None,
        }
    if not request:
        return {
            "success": False,
            "message": "'request' must be specified to make launch.",
            "result": None,
        }
    if not robot:
        return {
            "success": False,
            "message": "'robot' must be specified to make launch.",
            "result": None,
        }

    if not os.path.isfile(robot):
        return {
            "success": False,
            "message": f"The specified robot.yaml does not exist or is not a file ({robot}).",
            "result": None,
        }

    try:

        from robocorp_ls_core import yaml_wrapper

        with open(robot, "r") as stream:
            yaml_contents = yaml_wrapper.load(stream)

        if not yaml_contents:
            raise RuntimeError("Empty yaml contents.")
        if not isinstance(yaml_contents, dict):
            raise RuntimeError("Expected yaml contents root to be a dict.")
    except:
        log.exception("Error loading contents from: %s", robot)
        return {
            "success": False,
            "message": f"Unable to load robot.yaml contents from: ({robot}).",
            "result": None,
        }

    tasks = yaml_contents.get("tasks")
    if not tasks:
        return {
            "success": False,
            "message": "Expected the robot.yaml to have the 'tasks' defined.",
            "result": None,
        }

    if not isinstance(tasks, dict):
        return {
            "success": False,
            "message": f"Expected the robot.yaml 'tasks' to be a dict of tasks. Found: {type(tasks)}.",
            "result": None,
        }

    if not task:
        if len(tasks) == 1:
            task = next(iter(tasks))
        else:
            return {
                "success": False,
                "message": f"'task' must be specified in launch when Robot contains more than 1 task. Available tasks: {', '.join(list(tasks))}.",
                "result": None,
            }

    task_info = tasks.get(task)
    if not task_info:
        return {
            "success": False,
            "message": f"Unable to find task: {task} in the Robot: {robot}.",
            "result": None,
        }
    if not isinstance(task_info, dict):
        return {
            "success": False,
            "message": f"Expected the task: {task} to be a dict. Found: {type(task_info)}.",
            "result": None,
        }

    command = task_info.get("command")
    if not command:
        shell = task_info.get("shell")
        if shell:
            import shlex

            command = shlex.split(shell, posix=True)
        else:
            robot_task_name = task_info.get("robotTaskName")
            if robot_task_name:
                command = [
                    "python",
                    "-m",
                    "robot",
                    "--report",
                    "NONE",
                    "--outputdir",
                    "output",
                    "--logtitle",
                    "Task log",
                    "--task",
                    robot_task_name,
                    os.path.dirname(robot),
                ]
            else:
                return {
                    "success": False,
                    "message": f"Expected the task: {task} to have the command/shell/robotTaskName defined.",
                    "result": None,
                }

    if not isinstance(command, list):
        return {
            "success": False,
            "message": f"Expected the task: {task} to have a list(str) as the command. Found: {type(command)}.",
            "result": None,
        }

    command = [str(c) for c in command]
    cwd = os.path.dirname(robot)

    if command[:3] == ["python", "-m", "robot"]:
        args: List[str] = command[3:]

        if not args:
            return {
                "success": False,
                "message": (
                    f"Expected the robot file/directory to be executed to be provided"
                ),
                "result": None,
            }

        target_last = args[-1]
        if not os.path.isabs(target_last):
            target_last = os.path.abspath(
                os.path.join(os.path.dirname(robot), target_last)
            )

        if os.path.exists(target_last):
            target = target_last
            args = args[:-1]  # i.e.: Remove python -m robot ... target
        else:
            # Not the last...also check if the first argument is the target.
            target_first = args[0]

            if not os.path.isabs(target_first):
                target_first = os.path.abspath(
                    os.path.join(os.path.dirname(robot), target_first)
                )

            if os.path.exists(target_first):
                target = target_first
                args = args[1:]  # i.e.: Remove python -m robot ... target ...

            else:
                return {
                    "success": False,
                    "message": (
                        f"Expected the first/last argument to be the robot file/directory to be executed. Found: first:{target_first}, last:{target_last}"
                    ),
                    "result": None,
                }

        if additional_pythonpath_entries:
            for s in additional_pythonpath_entries:
                args.append("--pythonpath")
                args.append(s)

        result = {
            "type": "robotframework-lsp",
            "name": name,
            "request": request,
            "target": target,
            "cwd": cwd,
            "args": args,
            "terminal": "none",
        }
        if env:
            result["env"] = env
        return {"success": True, "message": None, "result": result}

    elif command[:1] == ["python"]:
        # It must be something as:
        # python [option] ... [-c cmd | -m mod | file | -] [arg]
        module = None
        program = None
        vmargs = []
        for i, c in enumerate(command):
            if i == 0:
                continue  # skip 'python'
            if c == "-m":
                module = command[i + 1]
                vmargs = command[1:i]
                args = command[i + 2 :]
                break

            elif c == "-c":
                return {
                    "success": False,
                    "message": f"Unable to deal with running with python '-c' flag.",
                    "result": None,
                }

            else:
                if not os.path.isabs(c):
                    c = os.path.abspath(os.path.join(os.path.dirname(robot), c))

                if os.path.exists(c):
                    program = c
                    vmargs = command[1:i]
                    args = command[i + 1 :]
                    break

        else:
            return {
                "success": False,
                "message": f"Unable to detect module or program to be launched.",
                "result": None,
            }

        result = {
            "type": "python",
            "name": name,
            "request": request,
            "cwd": cwd,
            "args": args,
            "pythonArgs": vmargs,
            "console": "internalConsole",
        }

        if python_exe:
            result["pythonPath"] = python_exe

        if module is not None:
            result["module"] = module
        elif program is not None:
            result["program"] = program
        else:
            return {
                "success": False,
                "message": f"Unable to detect module or program to be launched (unexpected error).",
                "result": None,
            }

        if env:
            result["env"] = env

        return {"success": True, "message": None, "result": result}

    else:
        return {
            "success": False,
            "message": (
                f"Currently it's only possible to debug Robot Framework or python tasks "
                f"(i.e.: the task must start with 'python -m robot' or 'python'). Task command: {command}"
            ),
            "result": None,
        }