Merge pull request #5075 from chennes/openSCADSandboxingFix
[OpenSCAD] Add ability to communicate over stdin/stdout (to support Snaps, etc.)
This commit is contained in:
@@ -305,6 +305,13 @@ polyhedron(
|
||||
# FreeCAD.closeDocument(doc.Name)
|
||||
|
||||
def test_import_import_stl(self):
|
||||
preferences = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD")
|
||||
transfer_mechanism = preferences.GetInt('transfermechanism',0)
|
||||
if transfer_mechanism == 2:
|
||||
print ("Cannot test STL import, communication with OpenSCAD is via pipes")
|
||||
print ("If either OpenSCAD or FreeCAD are installed as sandboxed packages,")
|
||||
print ("use of import is not possible.")
|
||||
return
|
||||
testfile = join(self.test_dir, "Cube.stl").replace('\\','/')
|
||||
doc = self.utility_create_scad("import(\"{}\");".format(testfile), "import_stl");
|
||||
object = doc.ActiveObject
|
||||
|
||||
@@ -168,12 +168,22 @@ def callopenscad(inputfilename,outputfilename=None,outputext='csg',keepname=Fals
|
||||
FreeCAD.Console.PrintMessage(stdoutd+u'\n')
|
||||
return stdoutd
|
||||
|
||||
osfilename = FreeCAD.ParamGet(\
|
||||
"User parameter:BaseApp/Preferences/Mod/OpenSCAD").\
|
||||
GetString('openscadexecutable')
|
||||
preferences = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD")
|
||||
osfilename = preferences.GetString('openscadexecutable')
|
||||
transferMechanism = preferences.GetInt('transfermechanism',0)
|
||||
if transferMechanism == 0: # Use the Python temp-directory creation function
|
||||
transferDirectory = tempfile.gettempdir()
|
||||
elif transferMechanism == 1: # Use a user-specified directory for the transfer
|
||||
transferDirectory = preferences.GetString('transferdirectory')
|
||||
elif transferMechanism == 2: # Use pipes instead of tempfiles
|
||||
return call_openscad_with_pipes(inputfilename, outputfilename, outputext, keepname)
|
||||
else:
|
||||
raise OpenSCADError("Invalid transfer mechanism specified");
|
||||
|
||||
if osfilename and os.path.isfile(osfilename):
|
||||
if not outputfilename:
|
||||
dir1=tempfile.gettempdir()
|
||||
|
||||
dir1 = transferDirectory
|
||||
if keepname:
|
||||
outputfilename=os.path.join(dir1,'%s.%s' % (os.path.split(\
|
||||
inputfilename)[1].rsplit('.',1)[0],outputext))
|
||||
@@ -185,6 +195,47 @@ def callopenscad(inputfilename,outputfilename=None,outputext='csg',keepname=Fals
|
||||
else:
|
||||
raise OpenSCADError('OpenSCAD executable unavailable')
|
||||
|
||||
def call_openscad_with_pipes(input_filename, output_filename, output_extension, keep_name):
|
||||
''' Call OpenSCAD by sending input data to stdin, and read the output from stdout.
|
||||
Returns the tempfile the output is stored in on success, or None on failure.
|
||||
NOTE: This feature was added to OpenSCAD in 2021.01'''
|
||||
|
||||
# For testing purposes continue using temp files, but now OpenSCAD does not need
|
||||
# read or write access to the files, only the FreeCAD process does. In the future
|
||||
# this could be changed to keep everything in memory, if desired.
|
||||
import subprocess,tempfile,os
|
||||
transfer_directory = tempfile.gettempdir()
|
||||
|
||||
# Load the data back in from our tempfile:
|
||||
with open(input_filename) as datafile:
|
||||
openscad_data = datafile.read()
|
||||
# On the command line this looks like:
|
||||
# $ cat myfile.scad | openscad --export-format csg -o - -
|
||||
preferences = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/OpenSCAD")
|
||||
openscad_executable = preferences.GetString('openscadexecutable')
|
||||
p = subprocess.Popen([openscad_executable,"--export-format","csg", "-o", "-", "-"],
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
stdoutd,stderrd = p.communicate (input = openscad_data.encode('utf8'), timeout=15)
|
||||
stdoutd = stdoutd.decode("utf8")
|
||||
stderrd = stderrd.decode("utf8")
|
||||
if p.returncode != 0:
|
||||
raise OpenSCADError('%s %s\n' % (stdoutd.strip(),stderrd.strip()))
|
||||
|
||||
if not output_filename:
|
||||
dir1 = transfer_directory
|
||||
if keep_name:
|
||||
output_filename=os.path.join(dir1,'%s.%s' % (os.path.split(\
|
||||
input_filename)[1].rsplit('.',1)[0],output_extension))
|
||||
else:
|
||||
output_filename=os.path.join(dir1,'%s.%s' % \
|
||||
(next(tempfilenamegen),output_extension))
|
||||
with open(output_filename,"w") as outfile:
|
||||
outfile.write(stdoutd);
|
||||
return output_filename
|
||||
return None
|
||||
|
||||
def callopenscadstring(scadstr,outputext='csg'):
|
||||
'''create a tempfile and call the open scad binary
|
||||
returns the filename of the result (or None),
|
||||
|
||||
@@ -17,7 +17,16 @@
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
@@ -36,7 +45,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Gui::PrefFileChooser" name="gui::preffilechooser">
|
||||
<widget class="Gui::PrefFileChooser" name="gui::preffilechooser" native="true">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>300</width>
|
||||
@@ -166,7 +175,79 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3"/>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Send to OpenSCAD via:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Gui::PrefComboBox" name="guiprefcomboSendVia">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>The transfer mechanism for getting data to and from OpenSCAD</string>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>transfermechanism</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/OpenSCAD</cstring>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Standard temp directory</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>User-specified directory</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>stdout pipe (requires OpenSCAD >= 2021.1)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="transferDirectoryLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Transfer directory</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Gui::PrefFileChooser" name="gui::preffilechooser" native="true">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>300</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>The path to the directory for transfering files to and from OpenSCAD</string>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>transferdirectory</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/OpenSCAD</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
@@ -442,6 +523,11 @@
|
||||
<extends>QDoubleSpinBox</extends>
|
||||
<header>Gui/PrefWidgets.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>Gui::PrefComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>Gui/PrefWidgets.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
||||
Reference in New Issue
Block a user