Merge pull request #5075 from chennes/openSCADSandboxingFix

[OpenSCAD] Add ability to communicate over stdin/stdout (to support Snaps, etc.)
This commit is contained in:
Chris Hennes
2021-09-29 14:29:57 -05:00
committed by GitHub
3 changed files with 151 additions and 7 deletions

View File

@@ -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

View File

@@ -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),

View File

@@ -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 &gt;= 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/>