def import_reasoner_from_directory(cls, directory): """ Import a reasoner from the given directory: * Lookup for the reasoner .spec configuration file. * Search for the module where the reasoner is implemented. * Search for the class implementing the reasoner. * Import the reasoner module. :type directory: str :rtype: tuple """ if isdir(directory): reasoner_spec_path = os.path.join(directory, 'reasoner.spec') if fexists(reasoner_spec_path): try: #LOGGER.debug('Found reasoner .spec: %s', reasoner_spec_path) reasoner_spec = ReasonerManager.spec(fread(reasoner_spec_path)) reasoner_name = reasoner_spec.get('reasoner', 'id') for extension in ('.pyc', '.pyo', '.py'): reasoner_path = os.path.join(directory, '%s%s' % (reasoner_name, extension)) if fexists(reasoner_path): #LOGGER.debug('Found reasoner module: %s', reasoner_path) reasoner_module = SourceFileLoader(reasoner_name, reasoner_path).load_module() reasoner_class = ReasonerManager.find_class(reasoner_module, reasoner_name) return reasoner_spec, reasoner_class else: raise ReasonerError('missing reasoner module: %s.py(c|o)' % os.path.join(directory, reasoner_name)) except Exception as e: LOGGER.exception('Failed to import reasoner: %s', e)
def import_plugin_from_directory(cls, directory): """ Import a plugin from the given directory: * Lookup for the plugin .spec configuration file. * Search for the module where the plugin is implemented. * Search for the class implementing the plugin. * Import the plugin module. :type directory: str :rtype: tuple """ if isdir(directory): plugin_spec_path = os.path.join(directory, 'plugin.spec') if fexists(plugin_spec_path): try: #LOGGER.debug('Found plugin .spec: %s', plugin_spec_path) plugin_spec = PluginManager.spec(fread(plugin_spec_path)) plugin_name = plugin_spec.get('plugin', 'id') for extension in ('.pyc', '.pyo', '.py'): plugin_path = os.path.join(directory, '%s%s' % (plugin_name, extension)) if fexists(plugin_path): #LOGGER.debug('Found plugin module: %s', plugin_path) plugin_module = SourceFileLoader(plugin_name, plugin_path).load_module() plugin_class = PluginManager.find_class(plugin_module, plugin_name) return plugin_spec, plugin_class else: raise PluginError('missing plugin module: %s.py(c|o)' % os.path.join(directory, plugin_name)) except Exception as e: LOGGER.exception('Failed to import plugin: %s', e)
def import_plugin_from_directory(self, directory): """ Import a plugin from the given directory: * Lookup for the plugin .spec configuration file. * Search for the module where the plugin is implemented. * Search for the class implementing the plugin. * Import the plugin module. :type directory: str :rtype: tuple """ if isdir(directory): plugin_spec_path = os.path.join(directory, 'plugin.spec') if fexists(plugin_spec_path): try: LOGGER.debug('Found plugin .spec: %s', plugin_spec_path) plugin_spec = self.spec(fread(plugin_spec_path)) plugin_name = plugin_spec.get('plugin', 'id') for extension in ('.pyc', '.pyo', '.py'): plugin_path = os.path.join(directory, '%s%s' % (plugin_name, extension)) if fexists(plugin_path): LOGGER.debug('Found plugin module: %s', plugin_path) plugin_module = SourceFileLoader(plugin_name, plugin_path).load_module() plugin_class = self.find_class(plugin_module, plugin_name) return plugin_spec, plugin_class else: raise PluginError('missing plugin module: %s.py(c|o)' % os.path.join(directory, plugin_name)) except Exception as e: LOGGER.exception('Failed to import plugin: %s', e)
def buildDmg(self): """Build the DMG image.""" try: import dmgbuild except ImportError: raise OSError( 'Unable to import dmgbuild: please install the dmgbuild package.' ) if fexists(self.dmgName): os.unlink(self.dmgName) defines = { 'appname': APPNAME, 'files': [self.bundleDir], 'license_file': expandPath('@root/LICENSE'), 'icon_locations': { '{}.app'.format(APPNAME): (60, 50) }, } if self.applications_shortcut: defines['symlinks'] = {'Applications': '/Applications'} defines['icon_locations']['Applications'] = (60, 130) if self.volume_background: if not fexists(self.volume_background): raise OSError( 'DMG volume background image not found at {0}'.format( self.volume_background)) print('Using DMG volume background: {0}'.format( self.volume_background)) from PIL import Image w, h = Image.open(self.volume_background).size defines['background'] = self.volume_background defines['window_rect'] = ((100, 500), (str(w), (str(h)))) if self.volume_icon: if not fexists(self.volume_icon): raise OSError('DMG volume icon not found at {0}'.format( self.volume_icon)) print('Using DMG volume icon: {0}'.format(self.volume_icon)) defines['icon'] = self.volume_icon # Create the disk image using dmgbuild package. dmgbuild.build_dmg( self.dmgName, self.volume_label, settings_file=expandPath('@support/dmgbuild/settings.py'), defines=defines, )
def buildDMG(self): """ Build the DMG image. """ if not isdir('@support/createdmg') or not fexists('@support/createdmg/create-dmg'): raise OSError('unable to find create-dmg utility: please clone Eddy with all its submodules' ) if fexists(self.dmgName): os.unlink(self.dmgName) stagingDir = os.path.join(self.buildDir, 'tmp') if isdir(stagingDir): rmdir(stagingDir) self.mkpath(stagingDir) # Move the app bundle into a separate folder that will be used as source folder for the DMG image if subprocess.call(['cp', '-R', self.bundleDir, stagingDir]) != 0: raise OSError('could not move app bundle in staging directory') # We create the DMG disk image using the create-dmg submodule. params = [expandPath('@support/createdmg/create-dmg')] params.extend(['--volname', self.volume_label]) params.extend(['--text-size', '12']) params.extend(['--icon-size', '48']) params.extend(['--icon', '{0}.app'.format(self.bundleName), '60', '50']) params.extend(['--hide-extension', '{0}.app'.format(self.bundleName)]) if self.applications_shortcut: params.extend(['--app-drop-link', '60', '130']) if self.volume_background: if not fexists(self.volume_background): raise OSError('DMG volume background image not found at {0}'.format(self.volume_background)) print('Using DMG volume background: {0}'.format(self.volume_background)) from PIL import Image w, h = Image.open(self.volume_background).size params.extend(['--background', self.volume_background, '--window-size', str(w), str(h)]) if self.volume_icon: if not fexists(self.volume_icon): raise OSError('DMG volume icon not found at {0}'.format(self.volume_icon)) print('Using DMG volume icon: {0}'.format(self.volume_icon)) params.extend(['--volicon', self.volume_icon]) params.extend([self.dmgName, stagingDir]) subprocess.call(params) rmdir(stagingDir)
def doUpdateRecentProjects(self): """ Update the list of recent projects. """ # UPDATE THE RECENT PROJECT LIST recentList = [] settings = QtCore.QSettings() for path in map(expandPath, settings.value('project/recent', None, str) or []): if fexists(path): recentList.append(path) settings.setValue('project/recent', recentList) settings.sync() # CLEAR CURRENT LAYOUT for i in reversed(range(self.innerLayoutL.count())): item = self.innerLayoutL.itemAt(i) self.innerLayoutL.removeItem(item) # DISPOSE NEW PROJECT BLOCK if recentList: self.placeholder.setVisible(False) for path in recentList: project = ProjectBlock(path, self.innerWidgetL) connect(project.sgnDeleteProject, self.doDeleteProject) connect(project.sgnOpenProject, self.doOpenProject) connect(project.sgnRemoveProject, self.doRemoveProject) self.innerLayoutL.addWidget(project, 0, QtCore.Qt.AlignTop) else: self.placeholder.setVisible(True)
def do_import(self): """ Import an ontology into the currently active Project. """ self.debug('Open dialog') dialog = QtWidgets.QFileDialog(self.session) dialog.setAcceptMode(QtWidgets.QFileDialog.AcceptOpen) dialog.setDirectory(expandPath('~')) dialog.setFileMode(QtWidgets.QFileDialog.ExistingFiles) dialog.setViewMode(QtWidgets.QFileDialog.Detail) if dialog.exec_(): selected = [x for x in dialog.selectedFiles() if fexists(x)] if selected: try: with BusyProgressDialog(parent=self.session) as progress: for path in selected: progress.setWindowTitle('Importing {0}...'.format( os.path.basename(path))) worker = DescriptionsLoader( path, self.session.project, self.session) worker.run() except Exception as e: msgbox = QtWidgets.QMessageBox(self.session) msgbox.setDetailedText(format_exception(e)) msgbox.setIconPixmap( QtGui.QIcon( ':/icons/48/ic_error_outline_black').pixmap(48)) msgbox.setStandardButtons(QtWidgets.QMessageBox.Close) msgbox.setText( 'Eddy could not import all the selected files!') msgbox.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) msgbox.setWindowTitle('Import failed!') msgbox.exec_()
def find_spec(cls, file_or_directory): """ Searches the given file or directory for a 'plugin.spec' file and tries to load it, or returns 'None' if no such file exists. :type file_or_directory: str :rtype: PluginSpec """ file_or_directory = expandPath(file_or_directory) try: if os.path.exists(file_or_directory) and os.access( file_or_directory, os.R_OK): # READ SPEC FILE FROM DIRECTORY if isdir(file_or_directory): plugin_spec_path = os.path.join(file_or_directory, 'plugin.spec') if fexists(plugin_spec_path): return cls.spec(fread(plugin_spec_path)) # READ SPEC FILE FROM ZIP ARCHIVE elif is_zipfile(file_or_directory): zf = ZipFile(file_or_directory) zf_name_list = zf.namelist() if 'plugin.spec' in zf_name_list: plugin_spec_content = zf.read('plugin.spec').decode( 'utf8') return cls.spec(plugin_spec_content) except Exception as e: LOGGER.exception('Failed to load plugin spec: %s', e)
def import_plugin_from_zip(self, archive): """ Import a plugin from the given zip archive: * Lookup for the plugin .spec configuration file. * Search for the module where the plugin is implemented. * Search for the class implementing the plugin. * Import the plugin module. :type archive: str """ if fexists(archive) and File.forPath(archive) is File.Zip: zf = ZipFile(archive) zf_name_list = zf.namelist() for file_or_directory in zf_name_list: if file_or_directory.endswith('plugin.spec'): try: LOGGER.debug('Found plugin .spec: %s', os.path.join(archive, file_or_directory)) plugin_spec_content = zf.read(file_or_directory).decode('utf8') plugin_spec = self.spec(plugin_spec_content) plugin_name = plugin_spec.get('plugin', 'id') plugin_zip_base_path = rstrip(file_or_directory, 'plugin.spec') plugin_abs_base_path = os.path.join(archive, plugin_zip_base_path) plugin_zip_module_base_path = os.path.join(plugin_zip_base_path, plugin_name) plugin_abs_module_base_path = os.path.join(archive, plugin_zip_module_base_path) for extension in ('.pyc', '.pyo', '.py'): plugin_zip_module_path = '%s%s' % (plugin_zip_module_base_path, extension) if plugin_zip_module_path in zf_name_list: LOGGER.debug('Found plugin module: %s', os.path.join(archive, plugin_zip_module_path)) plugin_module = zipimporter(plugin_abs_base_path).load_module(plugin_name) plugin_class = self.find_class(plugin_module, plugin_name) return plugin_spec, plugin_class else: raise PluginError('missing plugin module: %s.py(c|o)' % plugin_abs_module_base_path) except Exception as e: LOGGER.exception('Failed to import plugin: %s', e)
def import_plugin_from_zip(cls, archive): """ Import a plugin from the given zip archive: * Lookup for the plugin .spec configuration file. * Search for the module where the plugin is implemented. * Search for the class implementing the plugin. * Import the plugin module. :type archive: str :rtype: tuple """ if fexists(archive) and File.forPath(archive) is File.Zip: zf = ZipFile(archive) zf_name_list = zf.namelist() for file_or_directory in zf_name_list: if file_or_directory.endswith('plugin.spec'): try: #LOGGER.debug('Found plugin .spec: %s', os.path.join(archive, file_or_directory)) plugin_spec_content = zf.read(file_or_directory).decode('utf8') plugin_spec = PluginManager.spec(plugin_spec_content) plugin_name = plugin_spec.get('plugin', 'id') plugin_zip_base_path = rstrip(file_or_directory, 'plugin.spec') plugin_abs_base_path = os.path.join(archive, plugin_zip_base_path) plugin_zip_module_base_path = os.path.join(plugin_zip_base_path, plugin_name) plugin_abs_module_base_path = os.path.join(archive, plugin_zip_module_base_path) for extension in ('.pyc', '.pyo', '.py'): plugin_zip_module_path = '%s%s' % (plugin_zip_module_base_path, extension) if plugin_zip_module_path in zf_name_list: #LOGGER.debug('Found plugin module: %s', os.path.join(archive, plugin_zip_module_path)) plugin_module = zipimporter(plugin_abs_base_path).load_module(plugin_name) plugin_class = PluginManager.find_class(plugin_module, plugin_name) return plugin_spec, plugin_class else: raise PluginError('missing plugin module: %s.py(c|o)' % plugin_abs_module_base_path) except Exception as e: LOGGER.exception('Failed to import plugin: %s', e)
def import_reasoner_from_zip(cls, archive): """ Import a reasoner from the given zip archive: * Lookup for the reasoner .spec configuration file. * Search for the module where the reasoner is implemented. * Search for the class implementing the reasoner. * Import the reasoner module. :type archive: str :rtype: tuple """ if fexists(archive) and File.forPath(archive) is File.Zip: zf = ZipFile(archive) zf_name_list = zf.namelist() for file_or_directory in zf_name_list: if file_or_directory.endswith('reasoner.spec'): try: #LOGGER.debug('Found reasoner .spec: %s', os.path.join(archive, file_or_directory)) reasoner_spec_content = zf.read(file_or_directory).decode('utf8') reasoner_spec = ReasonerManager.spec(reasoner_spec_content) reasoner_name = reasoner_spec.get('reasoner', 'id') reasoner_zip_base_path = rstrip(file_or_directory, 'reasoner.spec') reasoner_abs_base_path = os.path.join(archive, reasoner_zip_base_path) reasoner_zip_module_base_path = os.path.join(reasoner_zip_base_path, reasoner_name) reasoner_abs_module_base_path = os.path.join(archive, reasoner_zip_module_base_path) for extension in ('.pyc', '.pyo', '.py'): reasoner_zip_module_path = '%s%s' % (reasoner_zip_module_base_path, extension) if reasoner_zip_module_path in zf_name_list: #LOGGER.debug('Found reasoner module: %s', os.path.join(archive, reasoner_zip_module_path)) reasoner_module = zipimporter(reasoner_abs_base_path).load_module(reasoner_name) reasoner_class = ReasonerManager.find_class(reasoner_module, reasoner_name) return reasoner_spec, reasoner_class else: raise ReasonerError('missing reasoner module: %s.py(c|o)' % reasoner_abs_module_base_path) except Exception as e: LOGGER.exception('Failed to import reasoner: %s', e)
def make_installer(self): """ Create a Windows installer using InnoSetup """ if WIN32: import yaml with open(os.path.join('support', 'innosetup', 'build.yaml'), 'r') as f: config = yaml.load(f) if 'scripts' not in config: print("ERROR: invalid config file: could not find 'scripts' section") sys.exit(1) if not len(config['scripts']): print("ERROR: invalid config file: no entry found in 'scripts' section") sys.exit(1) if 'iscc' not in config: print("ERROR: invalid config file: could not find 'iscc' entry") sys.exit(1) if not fexists(os.path.join('support', 'innosetup', config['iscc'])): print("ERROR: invalid config file: '{0}' is not a file".format(config['iscc'])) sys.exit(1) # Location of the InnoSetup Compiler program taken from environment. config['iscc'] = os.environ.get('ISCC_EXE', config['iscc']) if not config['iscc'].lower().endswith('iscc.exe'): print("ERROR: invalid location for the ISCC.exe program: {0}".format(config['iscc'])) sys.exit(1) # Build each given innosetup script for filename in config['scripts']: script_file = os.path.join('support', 'innosetup', filename) distutils.log.info("building: {0}".format(script_file)) try: cmd = [ config['iscc'], script_file, '/Q', '/O{0}'.format(DIST_DIR), '/dEDDY_APPID={0}'.format(APPID), '/dEDDY_APPNAME={0}'.format(APPNAME), '/dEDDY_ARCHITECTURE={0}'.format(platform.machine().lower()), '/dEDDY_BUGTRACKER={0}'.format(BUG_TRACKER), '/dEDDY_BUILD_PATH={0}'.format(self.build_exe), '/dEDDY_COPYRIGHT={0}'.format(COPYRIGHT), '/dEDDY_DOWNLOAD_URL={0}'.format(GRAPHOL_HOME), '/dEDDY_EXECUTABLE={0}'.format(EXEC_NAME), '/dEDDY_GRAPHOL_URL={0}'.format(GRAPHOL_HOME), '/dEDDY_LICENSE={0}'.format(LICENSE.lower()), '/dEDDY_ORGANIZATION={0}'.format(ORGANIZATION), '/dEDDY_ORGANIZATION_URL={0}'.format(DIAG_HOME), '/dEDDY_PROJECT_HOME={0}'.format(PROJECT_HOME), '/dEDDY_VERSION={0}'.format(VERSION), ] subprocess.call(cmd) except Exception as e: distutils.log.error('Failed to build {0}: {1}'.format(script_file, e))
def setRelativeReferencePaths(self): """ For all files in Contents/MacOS, check if they are binaries with references to other files in that dir. If so, make those references relative. The appropriate commands are applied to all files; they will just fail for files on which they do not apply. """ files = [] for root, dirs, dir_files in os.walk(self.binDir): files.extend([ os.path.join(root, f).replace(self.binDir + '/', '') for f in dir_files ]) for filename in files: if filename.endswith('.zip'): continue filepath = os.path.join(self.binDir, filename) mode = os.stat(filepath).st_mode if not mode & stat.S_IWUSR: os.chmod(filepath, mode | stat.S_IWUSR) subprocess.call( ('install_name_tool', '-id', '@executable_path/{0}'.format(filename), filepath)) otool = subprocess.Popen(('otool', '-L', filepath), stdout=subprocess.PIPE) references = otool.stdout.readlines()[1:] for reference in references: referenced_file = reference.decode().strip().split()[0] if referenced_file.startswith('@executable_path/'): continue path, name = os.path.split(referenced_file) # Some referenced files have not previously been copied to the executable directory - the # assumption is that you don't need to copy anything from /usr or /System, just from folders # like /opt this fix should probably be elsewhere though. if name not in files and not path.startswith( '/usr') and not path.startswith('/System'): if fexists(referenced_file): self.copy_file(referenced_file, os.path.join(self.binDir, name)) files.append(name) new_reference = None if name in files: new_reference = '@executable_path/{0}'.format(name) elif path.startswith('@rpath'): for i in files: if i.endswith(name): new_reference = '@executable_path/{0}'.format( i) if new_reference: subprocess.call( ('install_name_tool', '-change', referenced_file, new_reference, filepath))
def install(self, archive): """ Install the given plugin archive. During the installation process we'll check for a correct plugin structure, i.e. for the .spec file and the plugin module to be available. We won't check if the plugin actually runs since this will be handle by the application start sequence. :type archive: str :rtype: PluginSpec """ try: # CHECK FOR CORRECT PLUGIN ARCHIVE if not fexists(archive): raise PluginError('file not found: %s' % archive) if not File.forPath(archive) is File.Zip: raise PluginError('%s is not a valid plugin' % archive) # LOOKUP THE SPEC FILE zf = ZipFile(archive) zf_name_list = zf.namelist() if 'plugin.spec' in zf_name_list: LOGGER.debug('Found plugin .spec: %s', os.path.join(archive, 'plugin.spec')) plugin_spec_content = zf.read('plugin.spec').decode('utf8') plugin_spec = self.spec(plugin_spec_content) else: raise PluginError('missing plugin.spec in %s' % archive) # LOOKUP THE PLUGIN MODULE plugin_name = plugin_spec.get('plugin', 'id') for extension in importlib.machinery.all_suffixes() + ['/']: plugin_zip_module_path = '%s%s' % (plugin_name, extension) if plugin_zip_module_path in zf_name_list: LOGGER.debug('Found plugin module: %s', os.path.join(archive, plugin_zip_module_path)) break else: raise PluginError('missing plugin module in %s' % archive) # CHECK FOR THE PLUGIN TO BE ALREADY RUNNING plugin_id = plugin_spec.get('plugin', 'id') plugin_name = plugin_spec.get('plugin', 'name') if self.session.plugin(plugin_spec.get('plugin', 'id')): raise PluginError('plugin %s (id: %s) is already installed' % (plugin_name, plugin_id)) # CHECK FOR THE PLUGIN NAMESPACE TO BE UNIQUE if plugin_id in self.info: raise PluginError('plugin %s (id: %s) is already installed' % (plugin_name, plugin_id)) # COPY THE PLUGIN mkdir('@home/plugins/') fcopy(archive, '@home/plugins/') except Exception as e: LOGGER.error('Failed to install plugin: %s', e, exc_info=not isinstance(e, PluginError)) raise e else: return plugin_spec
def run(self): """Command execution.""" self.appImageName = '{}-{}-{}.AppImage'.format( APPNAME, VERSION, EXEC_ARCH) self.mkpath(self.dist_dir) self.execute(self.build_appimage, (), msg='Creating AppImage...') if fexists(self.appImageName): self.move_file( self.appImageName, os.path.join(self.dist_dir, DIST_NAME + '.AppImage'))
def uninstall(self, plugin): """ Uninstall the given plugin. :type plugin: AbstractPlugin """ if self.dispose(plugin): self.session.removePlugin(plugin) path = plugin.path() if isdir(path): rmdir(path) elif fexists(path): fremove(path)
def uninstall(self, reasoner): """ Uninstall the given reasoner. :type reasoner: AbstractReasoner """ if self.dispose(reasoner): self.session.removeReasoner(reasoner) path = reasoner.path() if isdir(path): rmdir(path) elif fexists(path): fremove(path)
def createDomDocument(self): """ Create the QDomDocument from where to parse information. """ QtWidgets.QApplication.processEvents() LOGGER.info('Loading diagram: %s', self.path) if not fexists(self.path): raise DiagramNotFoundError('diagram not found: {0}'.format(self.path)) self.document = QtXml.QDomDocument() if not self.document.setContent(fread(self.path)): raise DiagramNotValidError('could not parse diagram from {0}'.format(self.path))
def event(self, event): """ Executed when an event is received. :type event: T <= QEvent | QFileOpenEvent :rtype: bool """ # HANDLE FILEOPEN EVENT (TRIGGERED BY MACOS WHEN DOUBLE CLICKING A FILE) if event.type() == QtCore.QEvent.FileOpen: path = expandPath(event.file()) if fexists(path): if self.started: self.sgnCreateSession.emit(os.path.dirname(path)) else: # CACHE PATH UNTIL APPLICATION STARTUP HAS COMPLETED self.openFilePath = path return super().event(event)
def setRelativeReferencePaths(self): """ For all files in Contents/MacOS, check if they are binaries with references to other files in that dir. If so, make those references relative. The appropriate commands are applied to all files; they will just fail for files on which they do not apply. """ files = [] for root, dirs, dir_files in os.walk(self.binDir): files.extend([os.path.join(root, f).replace(self.binDir + '/', '') for f in dir_files]) for filename in files: if filename.endswith('.zip'): continue filepath = os.path.join(self.binDir, filename) mode = os.stat(filepath).st_mode if not mode & stat.S_IWUSR: os.chmod(filepath, mode | stat.S_IWUSR) subprocess.call(('install_name_tool', '-id', '@executable_path/{0}'.format(filename), filepath)) otool = subprocess.Popen(('otool', '-L', filepath), stdout=subprocess.PIPE) references = otool.stdout.readlines()[1:] for reference in references: referenced_file = reference.decode().strip().split()[0] if referenced_file.startswith('@executable_path/'): continue path, name = os.path.split(referenced_file) # Some referenced files have not previously been copied to the executable directory - the # assumption is that you don't need to copy anything from /usr or /System, just from folders # like /opt this fix should probably be elsewhere though. if name not in files and not path.startswith('/usr') and not path.startswith('/System'): if fexists(referenced_file): self.copy_file(referenced_file, os.path.join(self.binDir, name)) files.append(name) new_reference = None if name in files: new_reference = '@executable_path/{0}'.format(name) elif path.startswith('@rpath'): for i in files: if i.endswith(name): new_reference = '@executable_path/{0}'.format(i) if new_reference: subprocess.call(('install_name_tool', '-change', referenced_file, new_reference, filepath))
def start(self): """ Run the application by showing the welcome dialog. """ # CONFIGURE THE WORKSPACE #settings = QtCore.QSettings() #workspace = expandPath(settings.value('workspace/home', WORKSPACE, str)) ''' if not isdir(workspace): window = WorkspaceDialog() if window.exec_() == WorkspaceDialog.Rejected: raise SystemExit ''' # PROCESS COMMAND LINE ARGUMENTS args = self.options.positionalArguments() if self.openFilePath: args.append(self.openFilePath) self.openFilePath = None # SHOW WELCOME DIALOG self.welcome = Welcome(self) self.welcome.show() # PROCESS ADDITIONAL COMMAND LINE OPTIONS if self.options.isSet(CommandLineParser.OPEN): value = self.options.value(CommandLineParser.OPEN) if value: project = os.path.join(workspace, value) if project and isdir(os.path.join(workspace, project)): self.sgnCreateSession.emit(project) else: LOGGER.warning('Unable to open project: %s', project) # POSITIONAL ARGUMENTS elif args: fname = expandPath(args[0]) if fexists(fname): #project = os.path.dirname(fname) project = fname self.sgnCreateSession.emit(project) else: LOGGER.warning('Unable to open file: %s', fname) # COMPLETE STARTUP self.started = True
def createProjectFile(self): """ Serialize a previously created QDomDocument to disk. """ try: currPath = self.exportPath if self.exportPath else self.project.path if not fexists(currPath): folderPath = os.path.dirname(currPath) if not isdir(folderPath): mkdir(folderPath) fd = os.open(currPath, os.O_CREAT) os.close(fd) #TODO filename = postfix(self.project.name, File.Graphol.extension) #TODO filepath = os.path.join(self.project.path, filename) #TODO fwrite(self.document.toString(2), filepath) fwrite(self.document.toString(2), currPath) except Exception as e: raise e else: LOGGER.info('Saved project %s to %s', self.project.name, currPath)
def event(self, event): """ Executed when an event is received. :type event: T <= QEvent | QFileOpenEvent :rtype: bool """ # HANDLE FILEOPEN EVENT (TRIGGERED BY MACOS WHEN DOUBLE CLICKING A FILE) #if event.type() == QtCore.QEvent.FileOpen and not __debug__: if event.type() == QtCore.QEvent.FileOpen: path = expandPath(event.file()) #fileName,fileExtension = os.path.splitext(path) type = File.forPath(path) if type and type is File.Graphol: if fexists(path): if self.started: self.sgnCreateSession.emit(path) else: # CACHE PATH UNTIL APPLICATION STARTUP HAS COMPLETED self.openFilePath = path return super().event(event)
def assertFileExists(self, filepath, msg=None): """Assert for the given path to represent a file""" if not fexists(filepath): standardMsg = '%s is not a file' % safe_repr(expandPath(filepath)) self.fail(self._formatMessage(msg, standardMsg))
def install(self, archive): """ Install the given plugin archive. During the installation process we'll check for a correct plugin structure, i.e. for the .spec file and the plugin module to be available. We won't check if the plugin actually runs since this will be handle by the application statt sequence. :type archive: str :rtype: PluginSpec """ try: ## CHECK FOR CORRECT PLUGIN ARCHIVE if not fexists(archive): raise PluginError('file not found: %s' % archive) if not File.forPath(archive) is File.Zip: raise PluginError('%s is not a valid plugin' % archive) ## LOOKUP THE SPEC FILE zf = ZipFile(archive) zf_name_list = zf.namelist() for file_or_directory in zf_name_list: if file_or_directory.endswith('plugin.spec'): LOGGER.debug('Found plugin .spec: %s', os.path.join(archive, file_or_directory)) plugin_spec_content = zf.read(file_or_directory).decode('utf8') plugin_spec = self.spec(plugin_spec_content) break else: raise PluginError('missing plugin.spec in %s' % archive) ## LOOKUP THE PLUGIN MODULE plugin_name = plugin_spec.get('plugin', 'id') plugin_zip_base_path = rstrip(file_or_directory, 'plugin.spec') plugin_zip_module_base_path = os.path.join(plugin_zip_base_path, plugin_name) for extension in ('.pyc', '.pyo', '.py'): plugin_zip_module_path = '%s%s' % (plugin_zip_module_base_path, extension) if plugin_zip_module_path in zf_name_list: LOGGER.debug('Found plugin module: %s', os.path.join(archive, plugin_zip_module_path)) break else: raise PluginError('missing plugin module: %s.py(c|o) in %s' % (plugin_zip_module_base_path, archive)) # CHECK FOR THE PLUGIN TO BE ALREADY RUNNING plugin_id = plugin_spec.get('plugin', 'id') plugin_name = plugin_spec.get('plugin', 'name') if self.session.plugin(plugin_spec.get('plugin', 'id')): raise PluginError('plugin %s (id: %s) is already installed' % (plugin_name, plugin_id)) # CHECK FOR THE PLUGIN NAMESPACE TO BE UNIQUE plugin_module_base_path = rstrip(first(filter(None, plugin_zip_module_path.split(os.path.sep))), File.Zip.extension) for path in (expandPath('@plugins/'), expandPath('@home/plugins/')): for entry in os.listdir(path): if plugin_module_base_path == rstrip(entry, File.Zip.extension): raise PluginError('plugin %s (id: %s) is already installed' % (plugin_name, plugin_id)) # COPY THE PLUGIN mkdir('@home/plugins/') fcopy(archive, '@home/plugins/') except Exception as e: LOGGER.error('Failed to install plugin: %s', e, exc_info=not isinstance(e, PluginError)) raise e else: return plugin_spec
def configure(self, options): """ Perform initial configuration tasks for Eddy to work properly. :type options: Namespace """ ############################################# # DRAW THE SPLASH SCREEN ################################# splash = None if not options.nosplash: splash = Splash(mtime=4) splash.show() ############################################# # CONFIGURE RECENT PROJECTS ################################# settings = QtCore.QSettings(ORGANIZATION, APPNAME) examples = [ expandPath('@examples/Animals'), expandPath('@examples/Diet'), expandPath('@examples/Family'), expandPath('@examples/LUBM'), expandPath('@examples/Pizza'), ] if not settings.contains('project/recent'): # From PyQt5 documentation: if the value of the setting is a container (corresponding # to either QVariantList, QVariantMap or QVariantHash) then the type is applied to the # contents of the container. So we can't use an empty list as default value because # PyQt5 needs to know the type of the contents added to the collection: we avoid # this problem by placing the list of example projects as recent project list. settings.setValue('project/recent', examples) else: # If we have some projects in our recent list, check whether they exists on the # filesystem. If they do not exists we remove them from our recent list. projects = [] for path in map(expandPath, settings.value('project/recent')): if isdir(path) and path not in projects: projects.append(path) settings.setValue('project/recent', projects or examples) settings.sync() ############################################# # CONFIGURE FONTS ################################# fontDB = QtGui.QFontDatabase() fontDB.addApplicationFont(':/fonts/Roboto-Black') fontDB.addApplicationFont(':/fonts/Roboto-BlackItalic') fontDB.addApplicationFont(':/fonts/Roboto-Bold') fontDB.addApplicationFont(':/fonts/Roboto-BoldItalic') fontDB.addApplicationFont(':/fonts/Roboto-Italic') fontDB.addApplicationFont(':/fonts/Roboto-Light') fontDB.addApplicationFont(':/fonts/Roboto-LightItalic') fontDB.addApplicationFont(':/fonts/Roboto-Medium') fontDB.addApplicationFont(':/fonts/Roboto-MediumItalic') fontDB.addApplicationFont(':/fonts/Roboto-Regular') fontDB.addApplicationFont(':/fonts/Roboto-Thin') fontDB.addApplicationFont(':/fonts/Roboto-ThinItalic') fontDB.addApplicationFont(':/fonts/RobotoCondensed-Bold') fontDB.addApplicationFont(':/fonts/RobotoCondensed-BoldItalic') fontDB.addApplicationFont(':/fonts/RobotoCondensed-Italic') fontDB.addApplicationFont(':/fonts/RobotoCondensed-Light') fontDB.addApplicationFont(':/fonts/RobotoCondensed-LightItalic') fontDB.addApplicationFont(':/fonts/RobotoCondensed-Regular') fontDB.addApplicationFont(':/fonts/RobotoMono-Bold') fontDB.addApplicationFont(':/fonts/RobotoMono-BoldItalic') fontDB.addApplicationFont(':/fonts/RobotoMono-Italic') fontDB.addApplicationFont(':/fonts/RobotoMono-Light') fontDB.addApplicationFont(':/fonts/RobotoMono-LightItalic') fontDB.addApplicationFont(':/fonts/RobotoMono-Medium') fontDB.addApplicationFont(':/fonts/RobotoMono-MediumItalic') fontDB.addApplicationFont(':/fonts/RobotoMono-Regular') fontDB.addApplicationFont(':/fonts/RobotoMono-Thin') fontDB.addApplicationFont(':/fonts/RobotoMono-ThinItalic') self.setFont(Font('Roboto', 12)) ############################################# # CONFIGURE LAYOUT ################################# buffer = '' resources = expandPath('@resources/styles/') for name in os.listdir(resources): path = os.path.join(resources, name) if fexists(path) and File.forPath(path) is File.Qss: buffer += fread(path) self.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps) self.setStyle(EddyProxyStyle('Fusion')) self.setStyleSheet(buffer) ############################################# # LOOKUP PLUGINS ################################# PluginManager.scan('@plugins/', '@home/plugins/') ############################################# # CLOSE THE SPLASH SCREEN ################################# if splash and not options.nosplash: splash.sleep() splash.close() ############################################# # CONFIGURE THE WORKSPACE ################################# workspace = expandPath(settings.value('workspace/home', WORKSPACE, str)) if not isdir(workspace): window = WorkspaceDialog() if window.exec_() == WorkspaceDialog.Rejected: raise SystemExit
def configure(self, options): """ Perform initial configuration tasks for Eddy to work properly. :type options: Namespace """ ############################################# # DRAW THE SPLASH SCREEN ################################# splash = None if not options.nosplash: splash = Splash(mtime=4) splash.show() ############################################# # CONFIGURE RECENT PROJECTS ################################# settings = QtCore.QSettings(ORGANIZATION, APPNAME) examples = [ expandPath('@examples/Animals'), expandPath('@examples/Diet'), expandPath('@examples/Family'), expandPath('@examples/LUBM'), expandPath('@examples/Pizza'), ] if not settings.contains('project/recent'): # From PyQt5 documentation: if the value of the setting is a container (corresponding # to either QVariantList, QVariantMap or QVariantHash) then the type is applied to the # contents of the container. So we can't use an empty list as default value because # PyQt5 needs to know the type of the contents added to the collection: we avoid # this problem by placing the list of example projects as recent project list. settings.setValue('project/recent', examples) else: # If we have some projects in our recent list, check whether they exists on the # filesystem. If they do not exists we remove them from our recent list. projects = [] for path in map(expandPath, settings.value('project/recent')): if isdir(path) and path not in projects: projects.append(path) settings.setValue('project/recent', projects or examples) settings.sync() ############################################# # CONFIGURE FONTS ################################# fontDB = QtGui.QFontDatabase() fontDB.addApplicationFont(':/fonts/Roboto-Black') fontDB.addApplicationFont(':/fonts/Roboto-BlackItalic') fontDB.addApplicationFont(':/fonts/Roboto-Bold') fontDB.addApplicationFont(':/fonts/Roboto-BoldItalic') fontDB.addApplicationFont(':/fonts/Roboto-Italic') fontDB.addApplicationFont(':/fonts/Roboto-Light') fontDB.addApplicationFont(':/fonts/Roboto-LightItalic') fontDB.addApplicationFont(':/fonts/Roboto-Medium') fontDB.addApplicationFont(':/fonts/Roboto-MediumItalic') fontDB.addApplicationFont(':/fonts/Roboto-Regular') fontDB.addApplicationFont(':/fonts/Roboto-Thin') fontDB.addApplicationFont(':/fonts/Roboto-ThinItalic') fontDB.addApplicationFont(':/fonts/RobotoCondensed-Bold') fontDB.addApplicationFont(':/fonts/RobotoCondensed-BoldItalic') fontDB.addApplicationFont(':/fonts/RobotoCondensed-Italic') fontDB.addApplicationFont(':/fonts/RobotoCondensed-Light') fontDB.addApplicationFont(':/fonts/RobotoCondensed-LightItalic') fontDB.addApplicationFont(':/fonts/RobotoCondensed-Regular') fontDB.addApplicationFont(':/fonts/RobotoMono-Bold') fontDB.addApplicationFont(':/fonts/RobotoMono-BoldItalic') fontDB.addApplicationFont(':/fonts/RobotoMono-Italic') fontDB.addApplicationFont(':/fonts/RobotoMono-Light') fontDB.addApplicationFont(':/fonts/RobotoMono-LightItalic') fontDB.addApplicationFont(':/fonts/RobotoMono-Medium') fontDB.addApplicationFont(':/fonts/RobotoMono-MediumItalic') fontDB.addApplicationFont(':/fonts/RobotoMono-Regular') fontDB.addApplicationFont(':/fonts/RobotoMono-Thin') fontDB.addApplicationFont(':/fonts/RobotoMono-ThinItalic') self.setFont(Font('Roboto', 12)) ############################################# # CONFIGURE LAYOUT ################################# buffer = '' resources = expandPath('@resources/styles/') for name in os.listdir(resources): path = os.path.join(resources, name) if fexists(path) and File.forPath(path) is File.Qss: buffer += fread(path) self.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps) self.setStyle(EddyProxyStyle('Fusion')) self.setStyleSheet(buffer) ############################################# # CLOSE THE SPLASH SCREEN ################################# if splash and not options.nosplash: splash.sleep() splash.close() ############################################# # CONFIGURE THE WORKSPACE ################################# workspace = expandPath(settings.value('workspace/home', WORKSPACE, str)) if not isdir(workspace): window = WorkspaceDialog() if window.exec_() == WorkspaceDialog.Rejected: raise SystemExit
def configure(self): """ Perform initial configuration tasks for Eddy to work properly. """ ############################################# # CONFIGURE FONTS ################################# fontDB = QtGui.QFontDatabase() fonts = QtCore.QDirIterator(':/fonts/') while fonts.hasNext(): fontDB.addApplicationFont(fonts.next()) # FONT SUBSTITUTIONS QtGui.QFont.insertSubstitution('Sans Serif', 'Roboto') QtGui.QFont.insertSubstitution('Monospace', 'Roboto Mono') # APPLICATION DEFAULT FONT self.setFont(Font('Roboto', pixelSize=12)) ############################################# # CONFIGURE LAYOUT ################################# style = EddyProxyStyle('Fusion') self.setStyle(style) self.setStyleSheet(style.stylesheet) ############################################# # DRAW THE SPLASH SCREEN ################################# splash = None if not self.options.isSet(CommandLineParser.NO_SPLASH): splash = Splash(mtime=2) splash.show() ############################################# # CONFIGURE RECENT PROJECTS ################################# settings = QtCore.QSettings() if not settings.contains('project/recent'): # From PyQt5 documentation: if the value of the setting is a container (corresponding # to either QVariantList, QVariantMap or QVariantHash) then the type is applied to the # contents of the container. So we can't use an empty list as default value because # PyQt5 needs to know the type of the contents added to the collection: we avoid # this problem by placing the list of example projects as recent project list. examples = list(filter(lambda path: fexists(path) and faccess(path), [ expandPath('@examples/Animals{}'.format(File.Graphol.extension)), expandPath('@examples/Diet{}'.format(File.Graphol.extension)), expandPath('@examples/Family{}'.format(File.Graphol.extension)), expandPath('@examples/LUBM{}'.format(File.Graphol.extension)), expandPath('@examples/Pizza{}'.format(File.Graphol.extension)), ])) settings.setValue('project/recent', examples) else: # If we have some projects in our recent list, check whether they exists on the # filesystem. If they do not exists we remove them from our recent list. projects = [] for path in map(expandPath, settings.value('project/recent', None, str) or []): if fexists(path) and path not in projects: projects.append(path) settings.setValue('project/recent', projects) settings.sync() ############################################# # LOOKUP PLUGINS ################################# PluginManager.scan('@plugins/', '@home/plugins/') ############################################# # CLOSE THE SPLASH SCREEN ################################# if splash and not self.options.isSet(CommandLineParser.NO_SPLASH): splash.sleep() splash.close()
def make_installer(self): """Create a Windows installer using InnoSetup.""" import yaml with open(os.path.join('support', 'innosetup', 'build.yaml'), 'r') as f: config = yaml.safe_load(f) if 'scripts' not in config: print( "ERROR: invalid config file: could not find 'scripts' section" ) sys.exit(1) if not len(config['scripts']): print( "ERROR: invalid config file: no entry found in 'scripts' section" ) sys.exit(1) # Location of the InnoSetup Compiler program taken from environment. config['iscc'] = os.environ.get('ISCC_EXE', config['iscc']) if 'iscc' not in config: print( "ERROR: invalid config file: could not find 'iscc' entry") sys.exit(1) if not config['iscc'].lower().endswith('iscc.exe'): print("ERROR: invalid location for the ISCC.exe program: %s" % config['iscc']) sys.exit(1) if not fexists(os.path.join('support', 'innosetup', config['iscc'])): print("ERROR: invalid config file: '%s' is not a file" % config['iscc']) sys.exit(1) # Disable installation of 64 bit executables on 32 bit Windows architecturesAllowed = 'x64' if platform.architecture( )[0] == '64bit' else '' # Build each given innosetup script for filename in config['scripts']: script_file = os.path.join('support', 'innosetup', filename) distutils.log.info("building: %s" % script_file) try: cmd = [ config['iscc'], script_file, '/Q', '/O{0}'.format(self.dist_dir), '/dEDDY_APPID={0}'.format(APPID), '/dEDDY_APPNAME={0}'.format(APPNAME), '/dEDDY_ARCHITECTURE={0}'.format(EXEC_ARCH), '/dEDDY_ARCHITECTURES_ALLOWED={0}'.format( architecturesAllowed), '/dEDDY_BUGTRACKER={0}'.format(BUG_TRACKER), '/dEDDY_BUILD_PATH={0}'.format( os.path.join(self.distpath, DIST_NAME)), '/dEDDY_COPYRIGHT={0}'.format(COPYRIGHT), '/dEDDY_DOWNLOAD_URL={0}'.format(GRAPHOL_HOME), '/dEDDY_EXECUTABLE={0}'.format(EXEC_NAME), '/dEDDY_GRAPHOL_URL={0}'.format(GRAPHOL_HOME), '/dEDDY_LICENSE={0}'.format(LICENSE.lower()), '/dEDDY_ORGANIZATION={0}'.format(ORGANIZATION), '/dEDDY_ORGANIZATION_URL={0}'.format(ORGANIZATION_URL), '/dEDDY_PROJECT_HOME={0}'.format(PROJECT_HOME), '/dEDDY_VERSION={0}'.format(VERSION), ] subprocess.call(cmd) except Exception as e: distutils.log.error('Failed to build {0}: {1}'.format( script_file, e))
def install(self, archive): """ Install the given reasoner archive. During the installation process we'll check for a correct reasoner structure, i.e. for the .spec file and the reasoner module to be available. We won't check if the reasoner actually runs since this will be handle by the application statt sequence. :type archive: str :rtype: ReasonerSpec """ try: ## CHECK FOR CORRECT REASONER ARCHIVE if not fexists(archive): raise ReasonerError('file not found: %s' % archive) if not File.forPath(archive) is File.Zip: raise ReasonerError('%s is not a valid reasoner' % archive) ## LOOKUP THE SPEC FILE zf = ZipFile(archive) zf_name_list = zf.namelist() for file_or_directory in zf_name_list: if file_or_directory.endswith('reasoner.spec'): LOGGER.debug('Found reasoner .spec: %s', os.path.join(archive, file_or_directory)) reasoner_spec_content = zf.read(file_or_directory).decode('utf8') reasoner_spec = self.spec(reasoner_spec_content) break else: raise ReasonerError('missing reasoner.spec in %s' % archive) ## LOOKUP THE REASONER MODULE reasoner_name = reasoner_spec.get('reasoner', 'id') reasoner_zip_base_path = rstrip(file_or_directory, 'reasoner.spec') reasoner_zip_module_base_path = os.path.join(reasoner_zip_base_path, reasoner_name) for extension in ('.pyc', '.pyo', '.py'): reasoner_zip_module_path = '%s%s' % (reasoner_zip_module_base_path, extension) if reasoner_zip_module_path in zf_name_list: LOGGER.debug('Found reasoner module: %s', os.path.join(archive, reasoner_zip_module_path)) break else: raise ReasonerError('missing reasoner module: %s.py(c|o) in %s' % (reasoner_zip_module_base_path, archive)) # CHECK FOR THE REASONER TO BE ALREADY RUNNING reasoner_id = reasoner_spec.get('reasoner', 'id') reasoner_name = reasoner_spec.get('reasoner', 'name') if self.session.reasoner(reasoner_spec.get('reasoner', 'id')): raise ReasonerError('reasoner %s (id: %s) is already installed' % (reasoner_name, reasoner_id)) # CHECK FOR THE REASONER NAMESPACE TO BE UNIQUE reasoner_module_base_path = rstrip(first(filter(None, reasoner_zip_module_path.split(os.path.sep))), File.Zip.extension) for path in (expandPath('@reasoners/'), expandPath('@home/reasoners/')): for entry in os.listdir(path): if reasoner_module_base_path == rstrip(entry, File.Zip.extension): raise ReasonerError('reasoner %s (id: %s) is already installed' % (reasoner_name, reasoner_id)) # COPY THE REASONER mkdir('@home/reasoners/') fcopy(archive, '@home/reasoners/') except Exception as e: LOGGER.error('Failed to install reasoner: %s', e, exc_info=not isinstance(e, ReasonerError)) raise e else: return reasoner_spec