#!/usr/bin/env python #pyqt front end to some eix search functions from PyQt5 import QtCore, QtWidgets from PyQt5.QtWidgets import QMainWindow from PyQt5.QtGui import QStandardItemModel,QStandardItem import sys, subprocess, re class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(938, 483) MainWindow.setMinimumSize(QtCore.QSize(460, 300)) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) self.gridLayout.setObjectName("gridLayout") self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") self.le_search = QtWidgets.QLineEdit(self.centralwidget) self.le_search.setObjectName("le_search") self.horizontalLayout_2.addWidget(self.le_search) self.pb_search = QtWidgets.QPushButton(self.centralwidget) self.pb_search.setObjectName("pb_search") self.horizontalLayout_2.addWidget(self.pb_search) self.gridLayout.addLayout(self.horizontalLayout_2, 0, 0, 1, 1) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") self.cb_stable = QtWidgets.QCheckBox(self.centralwidget) self.cb_stable.setObjectName("cb_stable") self.horizontalLayout.addWidget(self.cb_stable) self.cb_testing = QtWidgets.QCheckBox(self.centralwidget) self.cb_testing.setObjectName("cb_testing") self.horizontalLayout.addWidget(self.cb_testing) self.cb_installed = QtWidgets.QCheckBox(self.centralwidget) self.cb_installed.setObjectName("cb_installed") self.horizontalLayout.addWidget(self.cb_installed) self.cb_overlay = QtWidgets.QCheckBox(self.centralwidget) self.cb_overlay.setTristate(False) self.cb_overlay.setObjectName("cb_overlay") self.horizontalLayout.addWidget(self.cb_overlay) self.gridLayout.addLayout(self.horizontalLayout, 1, 0, 1, 1) self.horizontalLayout_6 = QtWidgets.QHBoxLayout() self.horizontalLayout_6.setObjectName("horizontalLayout_6") self.rb_any = QtWidgets.QRadioButton(self.centralwidget) self.rb_any.setObjectName("rb_any") self.horizontalLayout_6.addWidget(self.rb_any) self.rb_decription = QtWidgets.QRadioButton(self.centralwidget) self.rb_decription.setObjectName("rb_decription") self.horizontalLayout_6.addWidget(self.rb_decription) self.rb_category = QtWidgets.QRadioButton(self.centralwidget) self.rb_category.setObjectName("rb_category") self.horizontalLayout_6.addWidget(self.rb_category) self.rb_name = QtWidgets.QRadioButton(self.centralwidget) self.rb_name.setObjectName("rb_name") self.horizontalLayout_6.addWidget(self.rb_name) self.gridLayout.addLayout(self.horizontalLayout_6, 2, 0, 1, 1) self.horizontalLayout_5 = QtWidgets.QHBoxLayout() self.horizontalLayout_5.setObjectName("horizontalLayout_5") self.rb_iuse = QtWidgets.QRadioButton(self.centralwidget) self.rb_iuse.setObjectName("rb_iuse") self.horizontalLayout_5.addWidget(self.rb_iuse) self.rb_use_enabled = QtWidgets.QRadioButton(self.centralwidget) self.rb_use_enabled.setObjectName("rb_use_enabled") self.horizontalLayout_5.addWidget(self.rb_use_enabled) self.rb_use_disabled = QtWidgets.QRadioButton(self.centralwidget) self.rb_use_disabled.setObjectName("rb_use_disabled") self.horizontalLayout_5.addWidget(self.rb_use_disabled) self.horizontalLayout_4 = QtWidgets.QHBoxLayout() self.horizontalLayout_4.setObjectName("horizontalLayout_4") self.l_res_count = QtWidgets.QLabel(self.centralwidget) self.l_res_count.setObjectName("l_res_count") self.horizontalLayout_4.addWidget(self.l_res_count) self.horizontalLayout_5.addLayout(self.horizontalLayout_4) self.gridLayout.addLayout(self.horizontalLayout_5, 3, 0, 1, 1) self.tv_results = QtWidgets.QTreeView(self.centralwidget) self.tv_results.setObjectName("tv_results") self.gridLayout.addWidget(self.tv_results, 4, 0, 1, 1) self.line = QtWidgets.QFrame(self.centralwidget) self.line.setFrameShape(QtWidgets.QFrame.HLine) self.line.setFrameShadow(QtWidgets.QFrame.Sunken) self.line.setObjectName("line") self.gridLayout.addWidget(self.line, 5, 0, 1, 1) self.horizontalLayout_3 = QtWidgets.QHBoxLayout() self.horizontalLayout_3.setObjectName("horizontalLayout_3") self.pb_expand_all = QtWidgets.QPushButton(self.centralwidget) self.pb_expand_all.setObjectName("pb_expand_all") self.horizontalLayout_3.addWidget(self.pb_expand_all) self.pb_expand_pkg = QtWidgets.QPushButton(self.centralwidget) self.pb_expand_pkg.setObjectName("pb_expand_pkg") self.horizontalLayout_3.addWidget(self.pb_expand_pkg) self.pb_collapse = QtWidgets.QPushButton(self.centralwidget) self.pb_collapse.setObjectName("pb_collapse") self.horizontalLayout_3.addWidget(self.pb_collapse) self.pb_updatedb = QtWidgets.QPushButton(self.centralwidget) self.pb_updatedb.setObjectName("pb_updatedb") self.horizontalLayout_3.addWidget(self.pb_updatedb) self.le_command = QtWidgets.QLineEdit(self.centralwidget) self.le_command.setEnabled(False) self.le_command.setObjectName("le_command") self.horizontalLayout_3.addWidget(self.le_command) self.gridLayout.addLayout(self.horizontalLayout_3, 6, 0, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 938, 26)) self.menubar.setObjectName("menubar") MainWindow.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) MainWindow.setTabOrder(self.le_search, self.pb_search) MainWindow.setTabOrder(self.pb_search, self.cb_stable) MainWindow.setTabOrder(self.cb_stable, self.cb_testing) MainWindow.setTabOrder(self.cb_testing, self.cb_installed) MainWindow.setTabOrder(self.cb_installed, self.cb_overlay) MainWindow.setTabOrder(self.cb_overlay, self.rb_any) MainWindow.setTabOrder(self.rb_any, self.rb_decription) MainWindow.setTabOrder(self.rb_decription, self.rb_category) MainWindow.setTabOrder(self.rb_category, self.rb_name) MainWindow.setTabOrder(self.rb_name, self.rb_iuse) MainWindow.setTabOrder(self.rb_iuse, self.rb_use_enabled) MainWindow.setTabOrder(self.rb_use_enabled, self.rb_use_disabled) MainWindow.setTabOrder(self.rb_use_disabled, self.tv_results) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "PyEix")) self.pb_search.setText(_translate("MainWindow", "Search")) self.cb_stable.setToolTip(_translate("MainWindow", "Only match packages with a stable version")) self.cb_stable.setText(_translate("MainWindow", "Stable")) self.cb_testing.setToolTip(_translate("MainWindow", "Only match packages with a testing version")) self.cb_testing.setText(_translate("MainWindow", "Testing")) self.cb_installed.setToolTip(_translate("MainWindow", "Only match installed packages")) self.cb_installed.setText(_translate("MainWindow", "Installed")) self.cb_overlay.setToolTip(_translate("MainWindow", "Only match packages with at least one version in an overlay")) self.cb_overlay.setText(_translate("MainWindow", "Overlay")) self.rb_any.setToolTip(_translate("MainWindow", "Search any field")) self.rb_any.setText(_translate("MainWindow", "Any")) self.rb_decription.setToolTip(_translate("MainWindow", "Search the description field")) self.rb_decription.setText(_translate("MainWindow", "Description")) self.rb_category.setToolTip(_translate("MainWindow", "Search the category field")) self.rb_category.setText(_translate("MainWindow", "Category")) self.rb_name.setToolTip(_translate("MainWindow", "Search the name field")) self.rb_name.setText(_translate("MainWindow", "Name")) self.rb_iuse.setToolTip(_translate("MainWindow", "Search for packages that can have that use flag enabled")) self.rb_iuse.setText(_translate("MainWindow", "Use flags (IUSE)")) self.rb_use_enabled.setToolTip(_translate("MainWindow", "Search for packages installed with that use flag enabled")) self.rb_use_enabled.setText(_translate("MainWindow", "Use enabled")) self.rb_use_disabled.setToolTip(_translate("MainWindow", "Search for packages instealled with that use flag diabled")) self.rb_use_disabled.setText(_translate("MainWindow", "Use Disabled")) self.l_res_count.setText(_translate("MainWindow", " Results: ")) self.pb_expand_all.setText(_translate("MainWindow", "Expand All")) self.pb_expand_pkg.setText(_translate("MainWindow", "Expand Pkgs")) self.pb_collapse.setText(_translate("MainWindow", "Collapse")) self.pb_updatedb.setToolTip(_translate("MainWindow", "

Update eix\'s database (uses sudo)

")) self.pb_updatedb.setText(_translate("MainWindow", "Update DB")) self.le_command.setText(_translate("MainWindow", "eix")) class Category: def __init__(self): self.UID=1 self.PUID=0 self.Name='' self.Packages=[] class Package: def __init__(self): self.UID=0 self.PUID=0 self.Name='' self.Description='' self.Homepage='' self.Installed=[] self.Available=[] class Installed: def __init__(self): self.UID=0 self.PUID=0 self.Version='' self.Use='' self.Homepage='Installed ->' class Available: def __init__(self): self.UID=0 self.PUID=0 self.Version='' self.Use='' self.Homepage='Available ->' class Result: def __init__(self): self.UID=0 self.PUID=0 self.Category='' self.Name='' self.Description='' self.Homepage='' self.Version='' self.Use='' class MainWindow(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setupUi(self) self.cb_option={ 'cb_stable':[self.cb_stable,'--stable'], 'cb_testing':[self.cb_testing,'--testing'], 'cb_installed':[self.cb_installed,'--installed'], 'cb_overlay':[self.cb_overlay,'--overlay'], } self.rb_option={ 'rb_decription':[self.rb_decription,'--description'], 'rb_use_disabled':[self.rb_use_disabled,'--installed-without-use'], 'rb_any':[self.rb_any,'--any'], 'rb_name':[self.rb_name,'--name'], 'rb_category':[self.rb_category,'--category'], 'rb_iuse':[self.rb_iuse,'--use'], 'rb_use_enabled':[self.rb_use_enabled,'--installed-with-use'], } self.find={ 'Category':[re.compile('^\[[0-9I]\] [A-z0-9]|^\* [A-z0-9]'), self.getCat, 0], 'Name':[re.compile('^\[[0-9I]\] [A-z0-9]|^\* [A-z0-9]'), self.getName, 1], 'Description':[re.compile('Description:'), self.getDesc, 2], 'Homepage':[re.compile('Homepage:'), self.getHome, 3], 'Installed':[re.compile('Installed versions:'), self.getInstVers, 4], 'Installed_use':[re.compile('Installed versions:'), self.getIuse, 5], 'Available':[re.compile('Available versions:'), self.getAvailVers, 6], 'Available_use':[re.compile('\{.*\}'), self.getAuse, 7], 'avail_ver_single':re.compile('(\)|[0-9]|c|\]) [0-9~\*\[]'), 'avail_ver_multi':re.compile('([0-9]|c) [0-9~\*\[]'), } self.cats=0 def on_le_search_returnPressed(self): self.on_pb_search_released() def on_pb_expand_pkg_released(self): model=self.tv_results.model() for a in range(0,self.cats+1): self.tv_results.expand(model.createIndex(a,1)) def on_pb_expand_all_released(self): self.tv_results.expandAll() def on_pb_collapse_released(self): self.tv_results.collapseAll() def on_pb_search_released(self): options=['eix','-n'] for rb in self.rb_option: if self.rb_option[rb][0].isChecked(): options.append(self.rb_option[rb][1]) break for cb in self.cb_option: if self.cb_option[cb][0].isChecked(): options.append(self.cb_option[cb][1]) terms=re.sub(' ','|',self.le_search.text()) options.append(terms) self.le_command.setText(' '.join(options)) self.doSearch(options) def doSearch(self, options): process=subprocess.Popen(options,encoding='utf-8',stdout=subprocess.PIPE, env={'EIX_LIMIT':'0', 'HOME':'$HOME'}) results=[] result=[] in_result=False starter=re.compile('^\[[0-9I]\] [A-z0-9]|^\* [A-z0-9]') overlay=re.compile('^\[[0-9]\] "') while True: output = process.stdout.readline() if output == '' and process.poll() is not None: break if starter.match(output): in_result=True elif output=='\n': in_result=False elif overlay.match(output) and not in_result: list=output.split(' ') result=['* Overlays/%s: %s'%(list[1][1:-1],list[0]),'Description: %s'%list[2]] in_result=False if output and in_result: result.append(output.strip()) elif result and not in_result: results.append(result) result=[] model = self.createResultsModel(self) uid=1 cats=[] self.l_res_count.setText('Results: %s'%len(results)) for result in results: cats,uid=self.formatResult(cats,uid,result) ex_cats=self.sortResults(cats) self.addResults(model,ex_cats) self.cats=len(cats) self.tv_results.setModel(model) def formatResult(self,cats,uid,result): cat=None in_avail=False for field in result: if self.find['Category'][0].search(field): cat_name=self.find['Category'][1](field) for pcat in cats: if pcat.Name==cat_name: cat=pcat break if not cat: cat=Category() cat.Name=cat_name cat.UID=uid cats.append(cat) uid+=1 pkg=Package() pkg.Name=self.find['Name'][1](field) pkg.UID=uid uid+=1 pkg.PUID=cat.UID cat.Packages.append(pkg) continue if self.find['Description'][0].search(field): in_avail=False pkg.Description=self.find['Description'][1](field) continue if self.find['Homepage'][0].search(field): in_avail=False pkg.Homepage=self.find['Homepage'][1](field) continue if self.find['Installed'][0].search(field): in_avail=False for installed,use in self.find['Installed'][1](field): inst=Installed() inst.Version=installed inst.Use='Use flags: %s'%use inst.PUID=pkg.UID inst.UID=uid uid+=1 pkg.Installed.append(inst) continue if self.find['Available'][0].search(field): in_avail=True versions=self.find['Available'][1](field,self.find['avail_ver_single']) for version in versions: if version=='':continue avail=Available() avail.Version=version avail.PUID=pkg.UID avail.UID=uid avail.Use='Use flags: %s'%self.getAuse(field) uid+=1 pkg.Available.append(avail) if self.find['Available_use'][0].search(field): in_avail=False use=self.find['Available_use'][1](field) if use: for avail in pkg.Available: avail.Use='Use flags: %s'%use continue if self.find['Available_use'][0].search(field): in_avail=False use=self.find['Available_use'][1](field,) if use: for avail in pkg.Available: avail.Use='Use flags: %s'%use continue if in_avail: versions=self.find['Available'][1](field,self.find['avail_ver_multi']) for version in versions: avail=Available() avail.Version=version avail.PUID=pkg.UID avail.UID=uid uid+=1 pkg.Available.append(avail) return cats,uid def sortResults(self, results): sorted=[] for cat in results: result=Result() result.UID=cat.UID result.Category=cat.Name sorted.append(result) for pkg in cat.Packages: result=Result() result.Name=pkg.Name result.UID=pkg.UID result.PUID=pkg.PUID result.Description=pkg.Description result.Homepage=pkg.Homepage sorted.append(result) for inst in pkg.Installed: result=Result() result.UID=inst.UID result.PUID=inst.PUID result.Name=inst.Homepage result.Description=inst.Version result.Homepage=inst.Use sorted.append(result) for avail in pkg.Available: if avail.Version[0]=='(' and avail.Version[len(avail.Version)-1]==')': continue result=Result() result.UID=avail.UID result.PUID=avail.PUID result.Name=avail.Homepage result.Description=avail.Version result.Homepage=avail.Use sorted.append(result) return sorted def getName(self, str): return str.split('/')[1] def getCat(self, str): return str.split(' ')[1].split('/')[0] def getAvailVers(self,str,RE): result=[] use=self.getAuse(str) if use: str=str[:str.find('{')] str=self.clean(str) match=RE.search(str) while match: ver=str[:match.start()+1] result.append(ver) str=str[match.end()-1:] match=RE.search(str) result.append(str) return result def getInstVers(self, str): result=[] str=re.sub('Installed versions: *','',str) match=re.search('\) [0-9]',str) while match: ver=str[:match.start()+1] use=self.getIuse(ver) if use: ver=ver[:ver.rfind('(')] ver=self.clean(ver) result.append([ver,use]) str=str[match.end()-1:] match=re.search('\) [0-9]',str) use=self.getIuse(str) if use: str=str[:str.rfind('(')] str=self.clean(str) result.append([str,use]) return result def getHome(self, str): t=self.find['Homepage'][0].match(str) home=str[t.end()+1:].strip() return home def getDesc(self, str): t=self.find['Description'][0].match(str) desc=str[t.end()+1:].strip() return desc def getIuse(self, str): iuse='' match=re.search('\)\([A-z0-9\-]',str) if match: iuse=str[match.end()-1:str.rfind(')')] return iuse def getAuse(self, str): t=self.find['Available_use'][0].search(str) if t: return str[t.start()+1:t.end()-1] else: return '' def clean(self,str): strip={ '\^[a-z]{1,3}':'','\*l':'','\(~\)':'~','Available versions: *':'', '\(([0-9]{2}:){2}[0-9]{2} ([0-9]{2}/){2}[0-9]{2}\)':''} for RE in strip: str=re.sub(RE,strip[RE],str) return str def createResultsModel(self,parent): headers=['Category','Name','Description','Homepage' ] model = QStandardItemModel() model.setHorizontalHeaderLabels(headers) return model def addResults(self,model,results): items={} for result in results: if result.PUID==0: parent=model.invisibleRootItem() else: parent=items[result.PUID] try: parent.appendRow([ QStandardItem(result.Category), QStandardItem(result.Name), QStandardItem(result.Description), QStandardItem(result.Homepage), ]) except: print(result.Category,result.Name,result.Description,result.Homepage) sys.exit() items[result.UID] = parent.child(parent.rowCount()-1) return model def on_pb_updatedb_released(self): child=subprocess.Popen(['sudo','eix-update']) child.wait() sys.argv[0] if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) ui = MainWindow() ui.show() sys.exit(app.exec_())