chiark / gitweb /
pauseAtZ plugin: Support re-homing X and Y before restarting
[cura.git] / Cura / util / pluginInfo.py
1 """
2 The plugin module contains information about the plugins found for Cura.
3 It keeps track of a list of installed plugins and the information contained within.
4 """
5 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
6
7 import os
8 import sys
9 import traceback
10 import platform
11 import re
12 import tempfile
13 import cPickle as pickle
14
15 from Cura.util import profile
16 from Cura.util import resources
17
18 _pluginList = None
19
20 class pluginInfo(object):
21         """
22         Plugin information object. Used to keep track of information about the available plugins in this installation of Cura.
23         Each plugin as meta-data associated with it which can be retrieved from this class.
24         """
25         def __init__(self, dirname, filename):
26                 self._dirname = dirname
27                 self._filename = filename
28                 self._name = os.path.splitext(os.path.basename(filename))[0]
29                 self._type = 'unknown'
30                 self._info = ''
31                 self._params = []
32                 with open(os.path.join(dirname, filename), "r") as f:
33                         for line in f:
34                                 line = line.strip()
35                                 if not line.startswith('#'):
36                                         break
37                                 line = line[1:].split(':', 1)
38                                 if len(line) != 2:
39                                         continue
40                                 if line[0].upper() == 'NAME':
41                                         self._name = line[1].strip()
42                                 elif line[0].upper() == 'INFO':
43                                         self._info = line[1].strip()
44                                 elif line[0].upper() == 'TYPE':
45                                         self._type = line[1].strip()
46                                 elif line[0].upper() == 'DEPEND':
47                                         pass
48                                 elif line[0].upper() == 'PARAM':
49                                         m = re.match('([a-zA-Z][a-zA-Z0-9_]*)\(([a-zA-Z_]*)(?::([^\)]*))?\) +(.*)', line[1].strip())
50                                         if m is not None:
51                                                 self._params.append({'name': m.group(1), 'type': m.group(2), 'default': m.group(3), 'description': m.group(4)})
52                                 # else:
53                                 #       print "Unknown item in plugin meta data: %s %s" % (line[0], line[1])
54
55         def getFilename(self):
56                 return self._filename
57
58         def getFullFilename(self):
59                 return os.path.join(self._dirname, self._filename)
60
61         def getType(self):
62                 return self._type
63
64         def getName(self):
65                 return self._name
66
67         def getInfo(self):
68                 return self._info
69
70         def getParams(self):
71                 return self._params
72
73 def getPostProcessPluginConfig():
74         try:
75                 return pickle.loads(str(profile.getProfileSetting('plugin_config')))
76         except:
77                 return []
78
79 def setPostProcessPluginConfig(config):
80         profile.putProfileSetting('plugin_config', pickle.dumps(config))
81
82 def overridePostProcessPluginConfig(config):
83         profile.setTempOverride('plugin_config', pickle.dumps(config))
84
85 def getPluginBasePaths():
86         ret = []
87         if platform.system() != "Windows":
88                 ret.append(os.path.expanduser('~/.cura/plugins/'))
89         if platform.system() == "Darwin" and hasattr(sys, 'frozen'):
90                 ret.append(os.path.normpath(os.path.join(resources.resourceBasePath, "plugins")))
91         else:
92                 ret.append(os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', 'plugins')))
93         return ret
94
95 def getPluginList(pluginType):
96         global _pluginList
97         if _pluginList is None:
98                 _pluginList = []
99                 for basePath in getPluginBasePaths():
100                         if os.path.isdir(basePath):
101                                 for filename in os.listdir(basePath):
102                                         if filename.startswith('.'):
103                                                 continue
104                                         if filename.startswith('_'):
105                                                 continue
106                                         if os.path.isdir(os.path.join(basePath, filename)):
107                                                 if os.path.exists(os.path.join(basePath, filename, 'script.py')):
108                                                         _pluginList.append(pluginInfo(basePath, os.path.join(filename, 'script.py')))
109                                         elif filename.endswith('.py'):
110                                                 _pluginList.append(pluginInfo(basePath, filename))
111         ret = []
112         for plugin in _pluginList:
113                 if plugin.getType() == pluginType:
114                         ret.append(plugin)
115         return ret
116
117 def runPostProcessingPlugins(engineResult, pluginConfigList):
118         pluginList = getPluginList('postprocess')
119
120         tempfilename = None
121         for pluginConfig in pluginConfigList:
122                 plugin = None
123                 for pluginTest in pluginList:
124                         if pluginTest.getFilename() == pluginConfig['filename']:
125                                 plugin = pluginTest
126                 if plugin is None:
127                         continue
128
129                 pythonFile = plugin.getFullFilename()
130
131                 if tempfilename is None:
132                         f = tempfile.NamedTemporaryFile(prefix='CuraPluginTemp', delete=False)
133                         tempfilename = f.name
134                         gcode = engineResult.getGCode()
135                         while True:
136                                 data = gcode.read(16 * 1024)
137                                 if len(data) == 0:
138                                         break
139                                 f.write(data)
140                         f.close()
141                         del gcode
142
143                 locals = {'filename': tempfilename}
144                 for param in plugin.getParams():
145                         value = param['default']
146                         if param['name'] in pluginConfig['params']:
147                                 value = pluginConfig['params'][param['name']]
148
149                         if param['type'] == 'float':
150                                 try:
151                                         value = float(value)
152                                 except:
153                                         value = float(param['default'])
154
155                         locals[param['name']] = value
156                 try:
157                         execfile(pythonFile, locals)
158                 except:
159                         traceback.print_exc()
160                         locationInfo = traceback.extract_tb(sys.exc_info()[2])[-1]
161                         return "%s: '%s' @ %s:%s:%d" % (str(sys.exc_info()[0].__name__), str(sys.exc_info()[1]), os.path.basename(locationInfo[0]), locationInfo[2], locationInfo[1])
162         if tempfilename is not None:
163                 f = open(tempfilename, "r")
164                 engineResult.setGCode("")
165                 import gc
166                 gc.collect()
167                 data = f.read(4096)
168                 while len(data) > 0:
169                         engineResult._gcodeData.write(data)
170                         data = f.read(4096)
171                 f.close()
172                 os.unlink(tempfilename)
173         return None