Esempio n. 1
0
def main(ctx, interactive, suppress_output, no_temp_profile, generate_docs,
         only_document_plugins, omit_header, debug, version, debugger_url,
         log_level, script_log_level, plugins, script, remainder):
    if version is True:
        print('webfriend {}'.format(webfriend.info.version))
        sys.exit(0)

    log.setLevel(logging.getLevelName(log_level.upper()))

    if plugins:
        plugins = plugins.split(',')

    if generate_docs:
        click.echo('\n'.join(
            document_commands(plugins=plugins,
                              only_plugins=only_document_plugins,
                              omit_header=omit_header)))
    else:
        if debug:
            os.environ['WEBFRIEND_DEBUG'] = 'true'

        if not interactive and script is None and sys.stdin.isatty():
            raise IOError("Must provide the path to script to execute.")

        # using the with-syntax launches an instance of chrome in the background before proceeding
        with Chrome(debug_url=debugger_url,
                    use_temp_profile=(not no_temp_profile)) as chrome:
            environment = Environment(browser=chrome,
                                      log_level=script_log_level)

            if isinstance(plugins, list):
                for plugin in plugins:
                    environment.register_by_module_name(plugin)

            # interactive REPL
            if interactive:
                repl = REPL(chrome, environment=environment)
                repl.run()
            else:
                # by now we've validated that there is not a TTY waiting at stdin, so there
                # must be some data to read.  In that case, read the script from stdin.
                #
                # This let's users call `webfriend` by piping commands to it or by passing in heredocs
                #
                scriptpath = os.getcwd()

                if script is None:
                    script = sys.stdin
                else:
                    scriptpath = os.path.abspath(os.path.dirname(script.name))

                # execute script as file (or via shebang invocation)
                scope = execute_script(chrome,
                                       script.read(),
                                       environment=environment,
                                       scriptpath=scriptpath).as_dict()

            if not suppress_output:
                click.echo(json.dumps(scope, indent=4))
Esempio n. 2
0
    def execute_script(self, script, scope=None):
        """
        Execute an automation script against this browser session.

        Args:
            script (str):
                The full text of the script to execute.

            scope (`webfriend.scripting.Scope`, optional):
                An optional initial scope to execute the script from.  This can be used to provide the
                script with initial values for variables used in the script.
        """
        return execute_script(self, script, scope)
Esempio n. 3
0
 def _eval(self, script):
     return execute_script(None, script).as_dict()
Esempio n. 4
0
    def run(
        self,
        script_name,
        data=None,
        isolated=True,
        preserve_state=True,
        merge_scopes=False,
        result_key=Environment.default_result_key
    ):
        """
        Evaluates another Friendscript loaded from another file.

        #### Arguments

        - **script_name** (`str`):

            The filename or basename of the file to search for in the `WEBFRIEND_PATH` environment
            variable to load and evaluate.  The `WEBFRIEND_PATH` variable behaves like the the
            traditional *nix `PATH` variable, wherein multiple paths can be specified as a
            colon-separated (`:`) list.  The current working directory will always be checked
            first.

        - **data** (`dict`, optional):

            If specified, these values will be made available to the evaluated script before it
            begins execution.

        - **isolated** (`bool`):

            Whether the script should have access to the calling script's variables or not.

        - **preserve_state** (`bool`):

            Whether event handlers created in the evaluated script should remain defined after the
            script has completed.

        - **merge_scopes** (`bool`):

            Whether the scope state at the end of the script's evaluation should be merged into the
            current execution scope.  Setting this to true allows variables defined inside of the
            evaluated script to stay defined after the script has completed.  Otherwise, only the
            value of the **result_key** variable is returned as the result of this command.

        - **result_key** (`str`):

            Defines the name of the variable that will be read from the evaluated script's scope
            and returned from this command.  Defaults to "result", which is the same behavior as
            all other commands.

        #### Returns
        The value of the variable named by **result_key** at the end of the evaluated script's
        execution.

        #### Raises
        Any exception that can be raised from Friendscript.
        """
        script = None
        final_script_name = None
        path_prefixes = ['.']

        # makes the ".fs" optional when passing scripts as arguments
        script_name = re.sub(r'\.fs$', '', script_name) + '.fs'

        # setup scopes
        if isolated:
            scope = Scope()
        else:
            scope = Scope(parent=self.scope)

        # if data is specified, set these values in the evaluated script's scope
        if isinstance(isolated, dict):
            scope.update(isolated)

        # process WEBFRIEND_PATH envvar
        for prefix in os.environ.get('WEBFRIEND_PATH', '').split(':'):
            path_prefixes.append(prefix)

        # search for file in all prefixes
        for prefix in path_prefixes:
            s = os.path.join(prefix, script_name)

            if os.path.isfile(s):
                final_script_name = s
                script = open(final_script_name, 'r').read()
                break

        # validate the script was read
        if script is None:
            raise exceptions.NotFound('Unable to locate script "{}" in any path'.format(
                script_name
            ))

        elif isinstance(script, str):
            script = script.decode('UTF-8')

        # evaluate the script
        logging.debug('Evaluating script {}'.format(final_script_name))
        scope = execute_script(
            self.browser,
            script,
            scope=scope,
            preserve_state=preserve_state
        )

        # if not using an isolated scope, then the top-level keys that were modified in this script
        # are set in our current scope (as if the included code ran inline)
        if merge_scopes:
            logging.debug(
                'Updating {} variables in calling scope with result scope (iso={})'.format(
                    len(scope),
                    isolated
                )
            )

            self.scope.update(scope)

        return scope.get('result')