RayMairlot/Batch-Render-Tools

Currently doesn't support OSs other than Windows

Opened this issue · 2 comments

I am trying to open a new terminal window, run Blender and be able to pass it some arguments so that I can commence background rendering and be able to see the progress of this render in the newly created terminal.

I'm currently using os.system to open a Command Prompt, which is the Windows specific part. The advantage of opening a command prompt over using something like subprocess.call is that it is a) Non-blocking, b) Shows feedback from Blender on the progress of the render, c) Allows the render to be cancelled by simply closing the Command Prompt window and d) Doesn't require Blender to be open during rendering (aside from starting the render).

I have this working on Windows and I know how to get it to work on Linux (though I haven't yet updated the add-on) with:

command = 'xterm -e ' + bpy.app.binary_path + ' -b ' + PathToBlend + ' -a'
os.system(command)

But, what I can't seem to do is work out how to get it to work on Mac OSX. This works:

command = 'open -a /Applications/Utilities/Terminal.app ' + bpy.app.binary_path'
os.system(command)

It opens a Terminal and runs Blender, but I don't know how to pass additional arguments to Blender. If anyone knows how to do that, please let me know.

Update

An untested 'Linux and OSX Support' branch now exists thanks to the contributions from antoniochiurla. I still intend to make my own attempt at OSX and Linux support in the main branch at some point.

p2or commented

Hi Ray,

open does not support any additional arguments. It feels a bit 'hacky' but the way to go is running a bash file in a new terminal instance via open -n -a Terminal --args bashfile.sh. In order to close the terminal window when the process is done, you can change the terminal preferences manually to close the window if the shell exited cleanly (Terminal > Preferences > Settings > Shell). I also struggled with this two years ago and I came up with this (cross platform):

import bpy
import sys
import subprocess
import os

def verify_app(cmd):
    try:
        subprocess.call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
    except OSError as e:
        if e.errno == os.errno.ENOENT:
            return False
    return True

# https://docs.python.org/3/library/sys.html#sys.platform
def render_terminal(args_user, bashfile=""):

    if sys.platform.startswith('win32'):
        ''' Windows-specific code here '''
        #args = ["start", "cmd.exe", "/k", bpy.app.binary_path, "-b"] + args_user # not necessary
        args = [bpy.app.binary_path, "-b"] + args_user

    elif sys.platform.startswith('darwin'):
        ''' OSX-specific code here... '''
        #args = ["open", "-a", "Terminal", "-n", bpy.app.binary_path, "--args", "-b"] # not supported
        bin = os.path.abspath(bpy.app.binary_path)

        # verify blender and check if a path for the bash file is given
        if verify_app([bin, "--help"]) and bashfile:
            bashcmd = [bin, '-b'] + args_user
            fp = open(bashfile, 'w')
            fp.write('#! /bin/sh\n')
            fp.write(" ".join(bashcmd))
            #fp.write('\nread -p "Press return to close..."') # user input to close the terminal window
            #fp.write('\nbash') # leave the window open
            fp.close()
            os.chmod(bashfile, 0o777) # http://stackoverflow.com/a/1837896
            args = ["open", "-n", "-a", "Terminal", "--args", bashfile]       
        else:
            # Fallback, otherwise call xterm
            args = ["xterm", "-e", bpy.app.binary_path, '-b']
            args += args_user

    elif sys.platform.startswith('linux'):
        ''' Linux-specific code here '''
        #if verify_app(["gnome-terminal", "--help"]): # verify gnome terminal on a debian ("-x" required)
        if verify_app(["x-terminal-emulator", "--help"]): # should work for all linux systems
            args = ["x-terminal-emulator", "-e", bpy.app.binary_path, '-b']
        else:
            # Fallback
            args = ["xterm", "-e", bpy.app.binary_path, '-b']
        args += args_user 

    elif sys.platform.startswith('freebsd'):
        ''' FreeBSD-specific code here '''
        args = ["xterm", "-e", bpy.app.binary_path, '-b']  
        args += args_user        

    else:
        ''' unspecific OS code here... '''
        args = ["xterm", "-e", bpy.app.binary_path, '-b']
        args += args_user 

    try:
        # shell=True requires a string, not a list!
        if sys.platform.startswith('win32'):
            p = subprocess.Popen(args, creationflags=subprocess.CREATE_NEW_CONSOLE)
        else: 
            #subprocess.call(args) # same as Popen().wait()
            p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            #print ("PID", p.pid)
        return p

    except:
        print ("Running the process is not possible")


# path to the blend
blend_file = <path-to-blend>

# custom command line arguments
cli_args = [blend_file, '-a']

# get the script path to create bash file next to the addon
addon_path = os.path.dirname(os.path.realpath(__file__))
bash_path = os.path.join(addon_path, ".render.sh")

# render via command line
process = render_terminal(cli_args)

# bash_path as optional parameter
#process = render_terminal(cli_args, bash_path) 

# kill the process
#process.kill()

Notes

  • x-terminal-emulator is some kind of wrapper and should work for all Linux systems
  • xterm is also accessible on Darwin and FreeBSD and serves as fallback
  • subprocess.Popen() is also non-blocking, safer and has more options (e.g. communicate or kill)

I hope this helps. Just let me know if you are ok with a pull request, then I'll try to implement that.

Best regards,
Christian

Thanks, Christian, that's really useful information. I had tried the bashfile method myself, but I'm not really familiar enough with Bash to know what I'm doing, so it's good to see how you are doing that.

What I'd prefer to do at the moment - instead of a pull request - is have a go at implementing this myself when I get some time. I have to do a lot of reworking of the code anyway for Linux to work, as it's quite Windows-specific at the minute.

Thanks,
Ray.