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.
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 systemsxterm
is also accessible on Darwin and FreeBSD and serves as fallbacksubprocess.Popen()
is also non-blocking, safer and has more options (e.g.communicate
orkill
)
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.