# HG changeset patch # User greg # Date 1256305308 -7200 # Node ID 7ac746c07ff2bb045f45fcb34f8cbb3fea72a9fa # Parent 3f285782ac9bd13612448224b24c9a8f78226753 Check ProjectPath write permission Manage buildpath diff -r 3f285782ac9b -r 7ac746c07ff2 Beremiz.py --- a/Beremiz.py Thu Oct 22 17:20:24 2009 +0200 +++ b/Beremiz.py Fri Oct 23 15:41:48 2009 +0200 @@ -293,6 +293,8 @@ kind=wx.ITEM_NORMAL, text=_(u'Open\tCTRL+O')) AppendMenu(parent, help='', id=wx.ID_SAVE, kind=wx.ITEM_NORMAL, text=_(u'Save\tCTRL+S')) + AppendMenu(parent, help='', id=wx.ID_SAVEAS, + kind=wx.ITEM_NORMAL, text=_(u'Save as\tCTRL+S')) AppendMenu(parent, help='', id=wx.ID_CLOSE, kind=wx.ITEM_NORMAL, text=_(u'Close Tab\tCTRL+W')) AppendMenu(parent, help='', id=wx.ID_CLOSE_ALL, @@ -314,6 +316,7 @@ self.Bind(wx.EVT_MENU, self.OnNewProjectMenu, id=wx.ID_NEW) self.Bind(wx.EVT_MENU, self.OnOpenProjectMenu, id=wx.ID_OPEN) self.Bind(wx.EVT_MENU, self.OnSaveProjectMenu, id=wx.ID_SAVE) + self.Bind(wx.EVT_MENU, self.OnSaveProjectAsMenu, id=wx.ID_SAVEAS) self.Bind(wx.EVT_MENU, self.OnCloseTabMenu, id=wx.ID_CLOSE) self.Bind(wx.EVT_MENU, self.OnCloseProjectMenu, id=wx.ID_CLOSE_ALL) self.Bind(wx.EVT_MENU, self.OnPageSetupMenu, id=wx.ID_PAGE_SETUP) @@ -543,6 +546,7 @@ self.FileMenu.Enable(wx.ID_PRINT, False) self.FileMenu.Enable(wx.ID_PAGE_SETUP, True) self.FileMenu.Enable(wx.ID_SAVE, True) + self.FileMenu.Enable(wx.ID_SAVEAS, True) self.FileMenu.Enable(wx.ID_PROPERTIES, True) self.FileMenu.Enable(wx.ID_CLOSE_ALL, True) else: @@ -551,6 +555,7 @@ self.FileMenu.Enable(wx.ID_PREVIEW, False) self.FileMenu.Enable(wx.ID_PRINT, False) self.FileMenu.Enable(wx.ID_SAVE, False) + self.FileMenu.Enable(wx.ID_SAVEAS, False) self.FileMenu.Enable(wx.ID_PROPERTIES, False) self.FileMenu.Enable(wx.ID_CLOSE_ALL, False) @@ -1370,6 +1375,13 @@ self.RefreshAll() self.RefreshTitle() + def OnSaveProjectAsMenu(self, event): + if self.PluginRoot is not None: + self.PluginRoot.SaveProjectAs() + self.RefreshAll() + self.RefreshTitle() + event.Skip() + def OnPropertiesMenu(self, event): self.ShowProperties() @@ -1402,24 +1414,26 @@ return DeleteButtonFunction def AddPlugin(self, PluginType, plugin): - dialog = wx.TextEntryDialog(self, _("Please enter a name for plugin:"), _("Add Plugin"), "", wx.OK|wx.CANCEL) - if dialog.ShowModal() == wx.ID_OK: - PluginName = dialog.GetValue() - plugin.PlugAddChild(PluginName, PluginType) - self.RefreshPluginTree() - self.PluginRoot.RefreshPluginsBlockLists() - dialog.Destroy() + if self.PluginRoot.CheckProjectPathPerm(): + dialog = wx.TextEntryDialog(self, _("Please enter a name for plugin:"), _("Add Plugin"), "", wx.OK|wx.CANCEL) + if dialog.ShowModal() == wx.ID_OK: + PluginName = dialog.GetValue() + plugin.PlugAddChild(PluginName, PluginType) + self.RefreshPluginTree() + self.PluginRoot.RefreshPluginsBlockLists() + dialog.Destroy() def DeletePlugin(self, plugin): - dialog = wx.MessageDialog(self, _("Really delete plugin ?"), _("Remove plugin"), wx.YES_NO|wx.NO_DEFAULT) - if dialog.ShowModal() == wx.ID_YES: - self.PluginInfos.pop(plugin) - plugin.PlugRemove() - del plugin - self.PluginRoot.RefreshPluginsBlockLists() - self.RefreshPluginTree() - dialog.Destroy() - + if self.PluginRoot.CheckProjectPathPerm(): + dialog = wx.MessageDialog(self, _("Really delete plugin ?"), _("Remove plugin"), wx.YES_NO|wx.NO_DEFAULT) + if dialog.ShowModal() == wx.ID_YES: + self.PluginInfos.pop(plugin) + plugin.PlugRemove() + del plugin + self.PluginRoot.RefreshPluginsBlockLists() + self.RefreshPluginTree() + dialog.Destroy() + #------------------------------------------------------------------------------- # Exception Handler #------------------------------------------------------------------------------- diff -r 3f285782ac9b -r 7ac746c07ff2 plugger.py --- a/plugger.py Thu Oct 22 17:20:24 2009 +0200 +++ b/plugger.py Fri Oct 23 15:41:48 2009 +0200 @@ -74,7 +74,17 @@ # helper func to get path to images def opjimg(imgname): return os.path.join("images",imgname) - + +# helper func to check path write permission +def CheckPathPerm(path): + if path is None or not os.path.isdir(path): + return False + for root, dirs, files in os.walk(path): + for name in files: + if os.access(root, os.W_OK) is not True or os.access(os.path.join(root, name), os.W_OK) is not True: + return False + return True + class PlugTemplate: """ This class is the one that define plugins. @@ -181,38 +191,39 @@ os.mkdir(self.PlugPath()) def PlugRequestSave(self): - # If plugin do not have corresponding directory - plugpath = self.PlugPath() - if not os.path.isdir(plugpath): - # Create it - os.mkdir(plugpath) - - # generate XML for base XML parameters controller of the plugin - if self.MandatoryParams: - BaseXMLFile = open(self.PluginBaseXmlFilePath(),'w') - BaseXMLFile.write("\n") - BaseXMLFile.write(self.MandatoryParams[1].generateXMLText(self.MandatoryParams[0], 0)) - BaseXMLFile.close() - - # generate XML for XML parameters controller of the plugin - if self.PlugParams: - XMLFile = open(self.PluginXmlFilePath(),'w') - XMLFile.write("\n") - XMLFile.write(self.PlugParams[1].generateXMLText(self.PlugParams[0], 0)) - XMLFile.close() - - # Call the plugin specific OnPlugSave method - result = self.OnPlugSave() - if not result: - return _("Error while saving \"%s\"\n")%self.PlugPath() - - # mark plugin as saved - self.ChangesToSave = False - # go through all childs and do the same - for PlugChild in self.IterChilds(): - result = PlugChild.PlugRequestSave() - if result: - return result + if self.GetPlugRoot().CheckProjectPathPerm(False): + # If plugin do not have corresponding directory + plugpath = self.PlugPath() + if not os.path.isdir(plugpath): + # Create it + os.mkdir(plugpath) + + # generate XML for base XML parameters controller of the plugin + if self.MandatoryParams: + BaseXMLFile = open(self.PluginBaseXmlFilePath(),'w') + BaseXMLFile.write("\n") + BaseXMLFile.write(self.MandatoryParams[1].generateXMLText(self.MandatoryParams[0], 0)) + BaseXMLFile.close() + + # generate XML for XML parameters controller of the plugin + if self.PlugParams: + XMLFile = open(self.PluginXmlFilePath(),'w') + XMLFile.write("\n") + XMLFile.write(self.PlugParams[1].generateXMLText(self.PlugParams[0], 0)) + XMLFile.close() + + # Call the plugin specific OnPlugSave method + result = self.OnPlugSave() + if not result: + return _("Error while saving \"%s\"\n")%self.PlugPath() + + # mark plugin as saved + self.ChangesToSave = False + # go through all childs and do the same + for PlugChild in self.IterChilds(): + result = PlugChild.PlugRequestSave() + if result: + return result return None def PlugImport(self, src_PlugPath): @@ -690,7 +701,7 @@ "LREAL" : 8, } -import re +import re, tempfile import targets import connectors from discovery import DiscoveryDialog @@ -764,7 +775,7 @@ self.PlugType = "Beremiz" # After __init__ root plugin is not valid self.ProjectPath = None - self.BuildPath = None + self._setBuildPath(None) self.DebugThread = None self.debug_break = False self.previous_plcstate = None @@ -852,6 +863,23 @@ if path.startswith("BeremizRoot.TargetType.") and self.BeremizRoot.getTargetType().getcontent() is None: self.BeremizRoot.setTargetType(self.GetDefaultTarget()) return PlugTemplate.SetParamsAttribute(self, path, value) + + # helper func to check project path write permission + def CheckProjectPathPerm(self, dosave=True): + if CheckPathPerm(self.ProjectPath): + return True + dialog = wx.MessageDialog(self.AppFrame, + _('You must have write permission to work on the project\nWork on a project copy ?'), + _('Error'), + wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) + answer = dialog.ShowModal() + dialog.Destroy() + if answer == wx.ID_YES: + if self.SaveProjectAs(): + self.AppFrame.RefreshAll() + self.AppFrame.RefreshTitle() + return True + return False def NewProject(self, ProjectPath, BuildPath=None): """ @@ -879,7 +907,7 @@ self.PluggedChilds = {} # Keep track of the root plugin (i.e. project path) self.ProjectPath = ProjectPath - self.BuildPath = BuildPath + self._setBuildPath(BuildPath) # get plugins bloclist (is that usefull at project creation?) self.RefreshPluginsBlockLists() # this will create files base XML files @@ -906,7 +934,7 @@ self.PluggedChilds = {} # Keep track of the root plugin (i.e. project path) self.ProjectPath = ProjectPath - self.BuildPath = BuildPath + self._setBuildPath(BuildPath) # If dir have already be made, and file exist if os.path.isdir(self.PlugPath()) and os.path.isfile(self.PluginXmlFilePath()): #Load the plugin.xml file into parameters members @@ -930,11 +958,26 @@ self.ResetAppFrame(None) def SaveProject(self): - if not self.SaveXMLFile(): + if self.CheckProjectPathPerm(False): self.SaveXMLFile(os.path.join(self.ProjectPath, 'plc.xml')) - result = self.PlugRequestSave() - if result: - self.logger.write_error(result) + result = self.PlugRequestSave() + if result: + self.logger.write_error(result) + + def SaveProjectAs(self, dosave=True): + # Ask user to choose a path with write permissions + dirdialog = wx.DirDialog(self.AppFrame , _("Choose a directory to save project"), os.getenv("HOME"), wx.DD_NEW_DIR_BUTTON) + answer = dirdialog.ShowModal() + dirdialog.Destroy() + if answer == wx.ID_OK: + newprojectpath = dirdialog.GetPath() + if os.path.isdir(newprojectpath): + self.ProjectPath = newprojectpath + if dosave: + self.SaveProject() + self._setBuildPath(self.BuildPath) + return True + return False # Update PLCOpenEditor Plugin Block types from loaded plugins def RefreshPluginsBlockLists(self): @@ -971,10 +1014,33 @@ def ParentsBlockTypesFactory(self): return self.BlockTypesFactory() + def _setBuildPath(self, buildpath): + if CheckPathPerm(buildpath): + self.BuildPath = buildpath + else: + self.BuildPath = None + self.BuildPath = buildpath + self.DefaultBuildPath = None + if self._builder is not None: + self._builder.SetBuildPath(self._getBuildPath()) + def _getBuildPath(self): - if self.BuildPath is None: - return os.path.join(self.ProjectPath, "build") - return self.BuildPath + # BuildPath is defined by user + if self.BuildPath is not None: + return self.BuildPath + # BuildPath isn't defined by user but already created by default + if self.DefaultBuildPath is not None: + return self.DefaultBuildPath + # Create a build path in project folder if user has permissions + if CheckPathPerm(self.ProjectPath): + self.DefaultBuildPath = os.path.join(self.ProjectPath, "build") + # Create a build path in temp folder + else: + self.DefaultBuildPath = os.path.join(tempfile.mkdtemp(), os.path.basename(self.ProjectPath), "build") + + if not os.path.exists(self.DefaultBuildPath): + os.makedirs(self.DefaultBuildPath) + return self.DefaultBuildPath def _getExtraFilesPath(self): return os.path.join(self._getBuildPath(), "extra_files") diff -r 3f285782ac9b -r 7ac746c07ff2 plugins/c_ext/CFileEditor.py --- a/plugins/c_ext/CFileEditor.py Thu Oct 22 17:20:24 2009 +0200 +++ b/plugins/c_ext/CFileEditor.py Fri Oct 23 15:41:48 2009 +0200 @@ -908,14 +908,12 @@ selected = self.PartsOpened.GetSelection() if selected >= 0: self.PartsOpened.DeletePage(selected) - event.Skip() def OnSaveMenu(self, event): if getattr(self, "_onsave", None) != None: self._onsave() self.RefreshTitle() self.RefreshEditMenu() - event.Skip() #------------------------------------------------------------------------------- # Notebook Unified Functions @@ -957,7 +955,6 @@ if selected != -1: window = self.PartsOpened.GetPage(selected) window.RefreshView() - event.Skip() def OnUndoMenu(self, event): self.Controler.LoadPrevious() @@ -967,7 +964,6 @@ window.RefreshView() self.RefreshTitle() self.RefreshEditMenu() - event.Skip() def OnRedoMenu(self, event): self.Controler.LoadNext() @@ -977,7 +973,6 @@ window.RefreshView() self.RefreshTitle() self.RefreshEditMenu() - event.Skip() #------------------------------------------------------------------------------- # CFile Editor Panels Management Functions diff -r 3f285782ac9b -r 7ac746c07ff2 plugins/c_ext/c_ext.py --- a/plugins/c_ext/c_ext.py Thu Oct 22 17:20:24 2009 +0200 +++ b/plugins/c_ext/c_ext.py Fri Oct 23 15:41:48 2009 +0200 @@ -222,14 +222,28 @@ _View = None def _OpenView(self): if not self._View: - def _onclose(): - self._View = None - def _onsave(): - self.GetPlugRoot().SaveProject() - self._View = CFileEditor(self.GetPlugRoot().AppFrame, self) - self._View._onclose = _onclose - self._View._onsave = _onsave - self._View.Show() + open_cfileeditor = True + has_permissions = self.GetPlugRoot().CheckProjectPathPerm() + if not has_permissions: + dialog = wx.MessageDialog(self.GetPlugRoot().AppFrame, + _("You don't have write permissions.\nOpen CFileEditor anyway ?"), + _("Open CFileEditor"), + wx.YES_NO|wx.ICON_QUESTION) + open_cfileeditor = dialog.ShowModal() == wx.ID_YES + dialog.Destroy() + if open_cfileeditor: + def _onclose(): + self._View = None + if has_permissions: + def _onsave(): + self.GetPlugRoot().SaveProject() + else: + def _onsave(): + pass + self._View = CFileEditor(self.GetPlugRoot().AppFrame, self) + self._View._onclose = _onclose + self._View._onsave = _onsave + self._View.Show() PluginMethods = [ {"bitmap" : os.path.join("images", "EditCfile"), diff -r 3f285782ac9b -r 7ac746c07ff2 plugins/canfestival/canfestival.py --- a/plugins/canfestival/canfestival.py Thu Oct 22 17:20:24 2009 +0200 +++ b/plugins/canfestival/canfestival.py Fri Oct 23 15:41:48 2009 +0200 @@ -100,16 +100,31 @@ _View = None def _OpenView(self): if not self._View: - def _onclose(): - self._View = None - def _onsave(): - self.GetPlugRoot().SaveProject() - self._View = objdictedit(self.GetPlugRoot().AppFrame, self) - # TODO redefine BusId when IEC channel change - self._View.SetBusId(self.GetCurrentLocation()) - self._View._onclose = _onclose - self._View._onsave = _onsave - self._View.Show() + open_objdictedit = True + has_permissions = self.GetPlugRoot().CheckProjectPathPerm() + if not has_permissions: + dialog = wx.MessageDialog(self.GetPlugRoot().AppFrame, + _("You don't have write permissions.\nOpen ObjDictEdit anyway ?"), + _("Open ObjDictEdit"), + wx.YES_NO|wx.ICON_QUESTION) + open_objdictedit = dialog.ShowModal() == wx.ID_YES + dialog.Destroy() + if open_objdictedit: + def _onclose(): + self._View = None + if has_permissions: + def _onsave(): + self.GetPlugRoot().SaveProject() + else: + def _onsave(): + pass + + self._View = objdictedit(self.GetPlugRoot().AppFrame, self) + # TODO redefine BusId when IEC channel change + self._View.SetBusId(self.GetCurrentLocation()) + self._View._onclose = _onclose + self._View._onsave = _onsave + self._View.Show() PluginMethods = [ {"bitmap" : os.path.join("images", "NetworkEdit"), @@ -185,16 +200,30 @@ _View = None def _OpenView(self): if not self._View: - def _onclose(): - self._View = None - def _onsave(): - self.GetPlugRoot().SaveProject() - self._View = networkedit(self.GetPlugRoot().AppFrame, self) - # TODO redefine BusId when IEC channel change - self._View.SetBusId(self.GetCurrentLocation()) - self._View._onclose = _onclose - self._View._onsave = _onsave - self._View.Show() + open_networkedit = True + has_permissions = self.GetPlugRoot().CheckProjectPathPerm() + if not has_permissions: + dialog = wx.MessageDialog(self.GetPlugRoot().AppFrame, + _("You don't have write permissions.\nOpen NetworkEdit anyway ?"), + _("Open NetworkEdit"), + wx.YES_NO|wx.ICON_QUESTION) + open_networkedit = dialog.ShowModal() == wx.ID_YES + dialog.Destroy() + if open_networkedit: + def _onclose(): + self._View = None + if has_permissions: + def _onsave(): + self.GetPlugRoot().SaveProject() + else: + def _onsave(): + pass + self._View = networkedit(self.GetPlugRoot().AppFrame, self) + # TODO redefine BusId when IEC channel change + self._View.SetBusId(self.GetCurrentLocation()) + self._View._onclose = _onclose + self._View._onsave = _onsave + self._View.Show() def _ShowMasterGenerated(self): buildpath = self._getBuildPath() diff -r 3f285782ac9b -r 7ac746c07ff2 plugins/python/PythonEditor.py --- a/plugins/python/PythonEditor.py Thu Oct 22 17:20:24 2009 +0200 +++ b/plugins/python/PythonEditor.py Fri Oct 23 15:41:48 2009 +0200 @@ -560,7 +560,6 @@ self._onsave() self.RefreshTitle() self.RefreshEditMenu() - event.Skip() def RefreshTitle(self): title = _("PythonEditor") @@ -577,19 +576,17 @@ def OnRefreshMenu(self, event): self.PythonEdited.RefreshView() - event.Skip() def OnUndoMenu(self, event): self.Controler.LoadPrevious() self.PythonEdited.RefreshView() self.RefreshTitle() self.RefreshEditMenu() - event.Skip() def OnRedoMenu(self, event): self.Controler.LoadNext() self.PythonEdited.RefreshView() self.RefreshTitle() self.RefreshEditMenu() - event.Skip() - + + diff -r 3f285782ac9b -r 7ac746c07ff2 plugins/python/modules/svgui/svgui.py --- a/plugins/python/modules/svgui/svgui.py Thu Oct 22 17:20:24 2009 +0200 +++ b/plugins/python/modules/svgui/svgui.py Fri Oct 23 15:41:48 2009 +0200 @@ -98,6 +98,15 @@ def _StartInkscape(self): svgfile = self._getSVGpath() - if not os.path.isfile(svgfile): - svgfile = None - open_svg(svgfile) + open_inkscape = True + if not self.GetPlugRoot().CheckProjectPathPerm(): + dialog = wx.MessageDialog(self.GetPlugRoot().AppFrame, + _("You don't have write permissions.\nOpen Inkscape anyway ?"), + _("Open Inkscape"), + wx.YES_NO|wx.ICON_QUESTION) + open_inkscape = dialog.ShowModal() == wx.ID_YES + dialog.Destroy() + if open_inkscape: + if not os.path.isfile(svgfile): + svgfile = None + open_svg(svgfile) diff -r 3f285782ac9b -r 7ac746c07ff2 plugins/python/modules/wxglade_hmi/wxglade_hmi.py --- a/plugins/python/modules/wxglade_hmi/wxglade_hmi.py Thu Oct 22 17:20:24 2009 +0200 +++ b/plugins/python/modules/wxglade_hmi/wxglade_hmi.py Fri Oct 23 15:41:48 2009 +0200 @@ -100,16 +100,25 @@ def _editWXGLADE(self): wxg_filename = self._getWXGLADEpath() - if not os.path.exists(wxg_filename): - hmi_name = self.BaseParams.getName() - open(wxg_filename,"w").write(""" - - - - frame_1 - - -""" % {"name": hmi_name, "class": "Class_%s" % hmi_name}) - if wx.Platform == '__WXMSW__': - wxg_filename = "\"%s\""%wxg_filename - self.launch_wxglade([wxg_filename]) + open_wxglade = True + if not self.GetPlugRoot().CheckProjectPathPerm(): + dialog = wx.MessageDialog(self.GetPlugRoot().AppFrame, + _("You don't have write permissions.\nOpen wxGlade anyway ?"), + _("Open wxGlade"), + wx.YES_NO|wx.ICON_QUESTION) + open_wxglade = dialog.ShowModal() == wx.ID_YES + dialog.Destroy() + if open_wxglade: + if not os.path.exists(wxg_filename): + hmi_name = self.BaseParams.getName() + open(wxg_filename,"w").write(""" + + + + frame_1 + + + """ % {"name": hmi_name, "class": "Class_%s" % hmi_name}) + if wx.Platform == '__WXMSW__': + wxg_filename = "\"%s\""%wxg_filename + self.launch_wxglade([wxg_filename]) diff -r 3f285782ac9b -r 7ac746c07ff2 plugins/python/python.py --- a/plugins/python/python.py Thu Oct 22 17:20:24 2009 +0200 +++ b/plugins/python/python.py Fri Oct 23 15:41:48 2009 +0200 @@ -141,14 +141,28 @@ _View = None def _OpenView(self): if not self._View: - def _onclose(): - self._View = None - def _onsave(): - self.GetPlugRoot().SaveProject() - self._View = PythonEditorFrame(self.GetPlugRoot().AppFrame, self) - self._View._onclose = _onclose - self._View._onsave = _onsave - self._View.Show() + open_pyeditor = True + has_permissions = self.GetPlugRoot().CheckProjectPathPerm() + if not has_permissions: + dialog = wx.MessageDialog(self.GetPlugRoot().AppFrame, + _("You don't have write permissions.\nOpen PythonEditor anyway ?"), + _("Open PythonEditor"), + wx.YES_NO|wx.ICON_QUESTION) + open_pyeditor = dialog.ShowModal() == wx.ID_YES + dialog.Destroy() + if open_pyeditor: + def _onclose(): + self._View = None + if has_permissions: + def _onsave(): + self.GetPlugRoot().SaveProject() + else: + def _onsave(): + pass + self._View = PythonEditorFrame(self.GetPlugRoot().AppFrame, self) + self._View._onclose = _onclose + self._View._onsave = _onsave + self._View.Show() def OnPlugSave(self): filepath = self.PythonFileName() diff -r 3f285782ac9b -r 7ac746c07ff2 targets/toolchain_gcc.py --- a/targets/toolchain_gcc.py Thu Oct 22 17:20:24 2009 +0200 +++ b/targets/toolchain_gcc.py Fri Oct 23 15:41:48 2009 +0200 @@ -12,11 +12,8 @@ """ def __init__(self, PluginsRootInstance): self.PluginsRootInstance = PluginsRootInstance - self.exe = PluginsRootInstance.GetProjectName() + self.extension - self.buildpath = PluginsRootInstance._getBuildPath() - self.exe_path = os.path.join(self.buildpath, self.exe) - self.md5key = None - self.srcmd5 = {} + self.buildpath = None + self.SetBuildPath(self.PluginsRootInstance._getBuildPath()) def getTarget(self): target = self.PluginsRootInstance.BeremizRoot.getTargetType() @@ -54,7 +51,15 @@ return open(self._GetMD5FileName(), "r").read() except Exception, e: return None - + + def SetBuildPath(self, buildpath): + if self.buildpath != buildpath: + self.buildpath = buildpath + self.exe = self.PluginsRootInstance.GetProjectName() + self.extension + self.exe_path = os.path.join(self.buildpath, self.exe) + self.md5key = None + self.srcmd5 = {} + def check_and_update_hash_and_deps(self, bn): # Get latest computed hash and deps oldhash, deps = self.srcmd5.get(bn,(None,[]))