First pass almost working. Need to not have the STL show up.

This commit is contained in:
Ross Hendrickson 2013-07-18 00:03:07 -06:00
parent 3cadbbeb85
commit 711d18d9ad
11 changed files with 256 additions and 73 deletions

View file

@ -0,0 +1,57 @@
__author__ = "Ross Hendrickson savorywatt"
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
import logging
from octoprint.settings import settings
class CuraFactory(object):
@staticmethod
def create_slicer(path=None):
if path:
return CuraEngine(path)
current_settings = settings(init=True)
path = current_settings.get(["curaEngine", "path"])
return CuraEngine(path)
class CuraEngine(object):
def __init__(self, cura_path):
if not cura_path:
raise Exception("Unable to create CuraEngine - no path specified")
self.cura_path = cura_path
logging.info('CuraEngine Created')
def process_file(self, config, gcode, file_path, call_back, call_back_args):
"""Wraps around the main.cpp processFile method.
:param config: :class: `string` :path to a cura config file:
:param gcode: :class: `string :path to write out the gcode generated:
:param file_path: :class: `string :path to the STL to be sliced:
:note: This will spawn a thread to handle the subprocess call and allow
us to be able to have a call back
"""
import threading
def start_thread(call_back, call_back_args, call_args):
import subprocess
logging.info("Starting SubProcess in Thread")
logging.info("Subprocess args: %s" % str(call_args))
process = subprocess.call(call_args)
call_back(*call_back_args)
logging.info("Slicing call back complete")
args = [self.cura_path, '-s', config, '-o', gcode, file_path]
logging.info('CuraEngine args:%s' % str(args))
thread = threading.Thread(target=start_thread, args=(call_back,
call_back_args, args))
thread.start()
logging.info('CuraEngine Slicing File:%s' % file_path)

View file

@ -1,48 +0,0 @@
__author__ = "Ross Hendrickson savorywatt"
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
import logging
import subprocess
APPNAME="OctoPrint"
class CuraFactory(object):
CURA_PATH = '/home/rosshendrickson/workspaces/opensource/CuraEngine/CuraEngine'
@staticmethod
def create_slicer(path=None):
if path:
return CuraEngine(path)
else:
return CuraEngine(CuraFactory.CURA_PATH)
class CuraEngine(object):
def __init__(self, cura_path):
self.cura_path = cura_path
logging.info('CuraEngine Created')
def process_file(self, config, gcode, file_path):
"""Wraps around the main.cpp processFile method.
:param config: :class: `string` :path to a cura config file:
:param gcode: :class: `string :path to write out the gcode generated:
:param file_path: :class: `string :path to the STL to be sliced:
:note This just uses subprocess at the moment.
"""
args = [self.cura_path, '-s', config, '-o', gcode, file_path]
logging.info('CuraEngine args:%s' % str(args))
process = subprocess.call(args)
logging.info('CuraEngine Exit:%s' % str(process))

View file

@ -1,9 +1,10 @@
import unittest
from mock import patch
from cura import CuraFactory
from cura import CuraEngine
from octoprint.cura import CuraFactory
from octoprint.cura import CuraEngine
class CuraFactoryTestCase(unittest.TestCase):
@ -15,14 +16,19 @@ class CuraFactoryTestCase(unittest.TestCase):
self.assertEqual(fake_path, result.cura_path)
def test_cura_engine_process_file(self):
cura_engine = CuraFactory.create_slicer()
@patch('threading.Thread')
def test_cura_engine_process_file(self, thread):
path = 'rosshendrickson/workspaces/opensource/CuraEngine/'
cura_engine = CuraFactory.create_slicer(path)
file_path = './cura/tests/test.stl'
config_path = './cura/tests/config'
gcode_filename= './cura/tests/output.gcode'
file_path = './cura/tests/test.stl'
config_path = './cura/tests/config'
gcode_filename= './cura/tests/output.gcode'
cura_engine.process_file(config_path, gcode_filename, file_path)
args = [path, '-s', config_path, '-o', file_path]
cura_engine.process_file(config_path, gcode_filename, file_path)
self.assertTrue(thread.called)

View file

View file

@ -0,0 +1,6 @@
class FileTypes(object):
STL = "stl"
GCODE = "gcode"

View file

@ -114,18 +114,55 @@ class GcodeManager:
#~~ file handling
def addFile(self, file):
if file:
absolutePath = self.getAbsolutePath(file.filename, mustExist=False)
if absolutePath is not None:
if file.filename in self._metadata.keys():
# delete existing metadata entry, since the file is going to get overwritten
del self._metadata[file.filename]
self._metadataDirty = True
self._saveMetadata()
file.save(absolutePath)
self._metadataAnalyzer.addFileToQueue(os.path.basename(absolutePath))
return self._getBasicFilename(absolutePath)
return None
from octoprint.filemanager.types import FileTypes
if not file:
return None
absolutePath = self.getAbsolutePath(file.filename, mustExist=False)
logging.info("Abs Path %s" % absolutePath)
if absolutePath is None:
return None
file.save(absolutePath)
fileType = file.filename.rsplit(".", 1)[1]
if not fileType:
return None
if fileType == FileTypes.GCODE:
return self.processGcode(file.filename, absolutePath)
if fileType == FileTypes.STL:
return self.processSTL(file.filename, absolutePath)
def processSTL(self, filename, absolutePath):
from octoprint.cura import CuraFactory
callBack = self.processGcode
gcodeFileName = util.genGcodeFileName(filename)
gcodePath = util.genGcodeFileName(absolutePath)
callBackArgs = [gcodeFileName, gcodePath]
curaEngine = CuraFactory.create_slicer()
current_settings = settings()
config = current_settings.get(["curaEngine", "config"])
curaEngine.process_file(
config, gcodePath, absolutePath, callBack, callBackArgs)
return self._getBasicFilename(absolutePath)
def processGcode(self, filename, absolutePath):
if filename in self._metadata.keys():
# delete existing metadata entry, since the file is going to get overwritten
del self._metadata[filename]
self._metadataDirty = True
self._saveMetadata()
self._metadataAnalyzer.addFileToQueue(os.path.basename(absolutePath))
return self._getBasicFilename(absolutePath)
def removeFile(self, filename):
filename = self._getBasicFilename(filename)
@ -139,11 +176,11 @@ class GcodeManager:
def getAbsolutePath(self, filename, mustExist=True):
"""
Returns the absolute path of the given filename in the gcode upload folder.
Returns the absolute path of the given filename in the correct upload folder.
Ensures that the file
<ul>
<li>has the extension ".gcode"</li>
<li>has the extension ".gcode" or ".stl"</li>
<li>exists and is a file (not a directory) if "mustExist" is set to True</li>
</ul>
@ -153,9 +190,10 @@ class GcodeManager:
"""
filename = self._getBasicFilename(filename)
if not util.isAllowedFile(filename, set(["gcode"])):
if not util.isAllowedFile(filename, set(["gcode", "stl"])):
return None
# TODO: detect which type of file and add in the extra folder portion
secure = os.path.join(self._uploadFolder, secure_filename(self._getBasicFilename(filename)))
if mustExist and (not os.path.exists(secure) or not os.path.isfile(secure)):
return None

View file

@ -308,6 +308,7 @@ def readGcodeFile(filename):
@login_required
def uploadGcodeFile():
filename = None
logging.info(str(request.files.keys()))
if "gcode_file" in request.files.keys():
file = request.files["gcode_file"]
filename = gcodeManager.addFile(file)

View file

View file

@ -0,0 +1,97 @@
import unittest
from mock import Mock
from mock import patch
import logging
class FileManipulationTestCase(unittest.TestCase):
def setUp(self):
from octoprint.settings import settings
from octoprint.gcodefiles import GcodeManager
self.settings = settings(True)
self.manager = GcodeManager()
self.filenames = []
def tearDown(self):
for filename in self.filenames:
self.manager.removeFile(filename)
logging.info("REMOVED %s filenames" % str(len(self.filenames)))
@patch('octoprint.cura.CuraEngine.process_file')
def test_add_stl_file(self, process):
fake = Mock()
fake.filename = "test_stl.stl"
self.filenames.append(fake.filename)
fake.__getitem__ = "SOMETHING"
result = self.manager.addFile(fake)
logging.info("RESULT:%s" % str(result))
self.assertTrue(fake.filename == result)
self.assertTrue(process.called)
def test_add_gcode_file(self):
fake = Mock()
fake.filename = "test_stl.gcode"
self.filenames.append(fake.filename)
fake.__getitem__ = "SOMETHING"
result = self.manager.addFile(fake)
logging.info("RESULT:%s" % str(result))
self.assertTrue(fake.filename == result)
class FileUtilTestCase(unittest.TestCase):
def test_isGcode(self):
from octoprint.util import isGcodeFileName
filename = "/asdj/wefasdf/junk.stl"
result = isGcodeFileName(filename)
self.assertFalse(result)
filename = "/asdj/wefasdf/junk.gcode"
result = isGcodeFileName(filename)
self.assertTrue(result)
def test_isSTLFileName(self):
from octoprint.util import isSTLFileName
filename = "/asdj/wefasdf/junk.stl"
result = isSTLFileName(filename)
self.assertTrue(result)
filename = "/asdj/wefasdf/junk.gcode"
result = isSTLFileName(filename)
self.assertFalse(result)
def test_genGcodeFileName(self):
from octoprint.util import genGcodeFileName
filename = "test.stl"
expected = "test.gcode"
result = genGcodeFileName(filename)
self.assertEqual(result, expected)

View file

@ -0,0 +1,9 @@
import unittest
class FileManipulationTestCase(unittest.TestCase):
def test_simple(self):
self.assertTrue(True)

View file

@ -43,4 +43,21 @@ def getClass(name):
return m
def matchesGcode(line, gcode):
return re.search("^\s*%s\D" % gcode, line, re.I)
return re.search("^\s*%s\D" % gcode, line, re.I)
def isGcodeFileName(filename):
return "." in filename and filename.rsplit(".", 1)[1] in ["gcode", "GCODE"]
def isSTLFileName(filename):
return "." in filename and filename.rsplit(".", 1)[1] in ["stl", "STL"]
def genGcodeFileName(filename):
if not filename:
return None
if "." not in filename:
return filename + ".gcode"
return filename.replace('.stl', '.gcode')