This will be pre-writing for an expanded and improved version of this part 
<http://leoeditor.com/scripting-miscellany.html#running-code-in-separate-processes>
 
of Leo's scripting miscellany 
<http://leoeditor.com/scripting-miscellany.html>.

There are at least three ways to execute shell commands from Leo.  Which 
you choose is a matter of taste. You can use whatever way is simplest or 
clearest.  All of the following run 'npm run dev' from 
leo/proto/Vitalije/leo-el-vue.

Assume the following in each example:

import os
base_dir = g.os_path_finalize_join(g.app.loadDir, '..', 'proto', 'Vitalije', 
'leo-el-vue')

*Note*: I have not found a way of doing 'cd directory' using 
subprocess.popen on Windows 10.  Yes, this is strange.

*Call subprocess.popen directly*

This may be simplest/clearest if there are few commands to execute and the 
exact commands are known beforehand.  The following doesn't wait for 'npm 
run dev' to return, which is usually what is wanted (Leo doesn't hang).

os.chdir(base_dir)
subprocess.Popen('npm run dev', shell=True)

The following *does *wait:

os.chdir(base_dir)
proc = subprocess.Popen(command, shell=True)
proc.communicate()

*Call g.execute_shell_commands*

This function calls subprocess.popen once for every command in a list.  
This function waits for commands that start with '&'.  It doesn't do all 
that much:

def execute_shell_commands(commands, trace=False):
    if g.isString(commands): commands = [commands]
    for command in commands:
        wait = not command.startswith('&')
        if command.startswith('&'): command = command[1:].strip()
        if trace: print('\n>%s%s\n' % ('' if wait else '&', command))
        proc = subprocess.Popen(command, shell=True)
        if wait: proc.communicate()

So the following works:

os.chdir(base_dir)
g.execute_shell_commands(['&npm run dev',])

g.execute_shell_commands might be slightly preferable to popen if there 
were several commands to run at once.

*Call g.execute_shell_commands_with_options*

This is experimental code.  All the examples above work with rev 516c9c6.

This function has arguments that allow scripts to get both the starting 
directory and the list of commands *from settings*. Its signature is:

def execute_shell_commands_with_options(
    base_dir = None,
    c = None,
    command_setting = None,
    commands = None,
    path_setting = None,
    warning = None,
):
    '''
    A helper for prototype commands or any other code that
    runs programs in a separate process.
    
    base_dir:           Base directory to use if no config path given.
    commands:           A list of commands, for g.execute_shell_commands.
    commands_setting:   Name of @data setting for commands.
    path_setting:       Name of @string setting for the base directory.
    warning:            A warning to be printed before executing the 
commands.
    '''

The following works:

g.execute_shell_commands_with_options(
        c = c,
        base_dir=base_dir,
        commands = ['&npm run dev',],
        command_setting = 'leo-el-vue-commands',
            # @data leo-el-vue-commands
        path_setting= 'leo-el-vue-base',
            # @string leo-el-vue-base
    )

This lets devs change a) the location of the test directory and b) the 
commands that will be executed.  For example, vitalije recommends using 
yarn instead of npm.  To do this, I only needed to put this in 
myLeoSettings.leo:

@data leo-el-vue-commands
yarn dev

The 'leo-el-vue' command itself did *not* need to change.

*Summary*

It is dead easy for scripts, including @button scripts, plugins, etc., to 
drive any external processes, including compilers and interpreters, from 
within Leo. Scripts can use subprocess.popen directly or 
g.execute_shell_commands.

The new g.execute_shell_commands_*with_options* function allows scripts to 
use settings to specify a) the directory in which to run commands, and b) 
the commands themselves. All of Leo's proto-* commands will use this 
function.

All comments, bug reports and suggestions are welcome.

Edward

-- 
You received this message because you are subscribed to the Google Groups 
"leo-editor" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/leo-editor.
For more options, visit https://groups.google.com/d/optout.

Reply via email to