diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/backend/libsisyphus.py | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/src/backend/libsisyphus.py b/src/backend/libsisyphus.py new file mode 100755 index 0000000..36a2dce --- /dev/null +++ b/src/backend/libsisyphus.py @@ -0,0 +1,259 @@ +#!/usr/bin/python3 + +import animation +import csv +import os +import shutil +import sqlite3 +import subprocess +import sys +import urllib3 +import io +from datetime import datetime + +redcore_portage_config_path = '/opt/redcore-build' + +rmtPkgCsv = '/var/lib/sisyphus/csv/remotePackagesPre.csv' +rmtDscCsv = '/var/lib/sisyphus/csv/remoteDescriptionsPre.csv' +lclPkgCsv = '/var/lib/sisyphus/csv/localPackagesPre.csv' +sisyphusDB = '/var/lib/sisyphus/db/sisyphus.db' +mirrorCfg = '/etc/sisyphus/mirrors.conf' + +def checkRoot(): + if not os.getuid() == 0: + sys.exit("\nYou need root permissions to do this, exiting!\n") + +def checkSystemMode(): + portage_binmode_make_conf = '/opt/redcore-build/conf/intel/portage/make.conf.amd64-binmode' + portage_mixedmode_make_conf = '/opt/redcore-build/conf/intel/portage/make.conf.amd64-mixedmode' + portage_make_conf_symlink = '/etc/portage/make.conf' + + if not os.path.islink(portage_make_conf_symlink): + print("\nmake.conf is not a symlink, refusing to run!\n") + sys.exit(1) + else: + if os.path.realpath(portage_make_conf_symlink) == portage_binmode_make_conf: + pass + elif os.path.realpath(portage_make_conf_symlink) == portage_mixedmode_make_conf: + pass + else: + print("\nThe system is not set to binmode or mixedmode, refusing to run!\n") + sys.exit(1) + +def fetchRemoteDatabaseCSV(): + portageExec = subprocess.Popen(['emerge', '--info', '--verbose'], stdout=subprocess.PIPE) + for portageOutput in io.TextIOWrapper(portageExec.stdout, encoding="utf-8"): + if "PORTAGE_BINHOST" in portageOutput.rstrip(): + rmtCsvUrl = str(portageOutput.rstrip().split("=")[1].strip('\"').replace('packages', 'csv') + 'remotePackagesPre.csv') + rmtDscUrl = str(portageOutput.rstrip().split("=")[1].strip('\"').replace('packages', 'csv') + 'remoteDescriptionsPre.csv') + + http = urllib3.PoolManager() + + with http.request('GET', rmtCsvUrl, preload_content=False) as tmp_buffer, open(rmtPkgCsv, 'wb') as output_file: + shutil.copyfileobj(tmp_buffer, output_file) + + with http.request('GET', rmtDscUrl, preload_content=False) as tmp_buffer, open(rmtDscCsv, 'wb') as output_file: + shutil.copyfileobj(tmp_buffer, output_file) + +def syncGitRepos(): + subprocess.check_call(['emerge', '--sync', '--quiet']) + +def syncPortageCfg(): + os.chdir(redcore_portage_config_path) + subprocess.call(['git', 'pull', '--quiet']) + +def syncRemoteDatabaseCSV(): + sisyphusdb = sqlite3.connect(sisyphusDB) + sisyphusdb.cursor().execute('''drop table if exists remote_packages''') + sisyphusdb.cursor().execute('''create table remote_packages (category TEXT,name TEXT,version TEXT,slot TEXT)''') + with open(rmtPkgCsv) as rmtCsv: + for row in csv.reader(rmtCsv): + sisyphusdb.cursor().execute("insert into remote_packages (category, name, version, slot) values (?, ?, ?, ?);", row) + sisyphusdb.commit() + sisyphusdb.close() + + sisyphusdb = sqlite3.connect(sisyphusDB) + sisyphusdb.cursor().execute('''drop table if exists remote_descriptions''') + sisyphusdb.cursor().execute('''create table remote_descriptions (category TEXT,name TEXT,description TEXT)''') + with open(rmtDscCsv) as rmtCsv: + for row in csv.reader(rmtCsv): + sisyphusdb.cursor().execute("insert into remote_descriptions (category, name, description) values (?, ?, ?);", row) + sisyphusdb.commit() + sisyphusdb.close() + +def syncRemoteDatabaseTable(): + fetchRemoteDatabaseCSV() + syncRemoteDatabaseCSV() + +@animation.wait('syncing remote database tables') +def syncAll(): + checkRoot() + + portageExec = subprocess.Popen(['emerge', '--info', '--verbose'], stdout=subprocess.PIPE) + for portageOutput in io.TextIOWrapper(portageExec.stdout, encoding="utf-8"): + if "PORTAGE_BINHOST" in portageOutput.rstrip(): + rmtCsvUrl = str(portageOutput.rstrip().split("=")[1].strip('\"').replace('packages', 'csv') + 'remotePackagesPre.csv') + rmtDscUrl = str(portageOutput.rstrip().split("=")[1].strip('\"').replace('packages', 'csv') + 'remoteDescriptionsPre.csv') + + http = urllib3.PoolManager() + + reqRmtPkgTs = http.request('HEAD',rmtCsvUrl) + rmtPkgTs = int(datetime.strptime(reqRmtPkgTs.headers['last-modified'], '%a, %d %b %Y %H:%M:%S %Z').strftime("%s")) + lclPkgTs = int(datetime.utcnow().strftime("%s")) + + reqRmtDscTs = http.request('HEAD',rmtDscUrl) + rmtDscTs = int(datetime.strptime(reqRmtDscTs.headers['last-modified'], '%a, %d %b %Y %H:%M:%S %Z').strftime("%s")) + lclDscTs = int(datetime.utcnow().strftime("%s")) + + if rmtPkgTs > lclPkgTs or rmtDscTs > lclDscTs: + fetchRemoteDatabaseCSV() + syncGitRepos() + syncPortageCfg() + syncRemoteDatabaseTable() + +def makeLocalDatabaseCSV(): + subprocess.check_call(['/usr/share/sisyphus/helpers/make_local_csv']) # this is really hard to do in python, so we cheat with a bash helper script + +def syncLocalDatabaseTable(): + sisyphusdb = sqlite3.connect(sisyphusDB) + sisyphusdb.cursor().execute('''drop table if exists local_packages''') + sisyphusdb.cursor().execute('''create table local_packages (category TEXT,name TEXT,version TEXT,slot TEXT)''') + with open(lclPkgCsv) as lclCsv: + for row in csv.reader(lclCsv): + sisyphusdb.cursor().execute("insert into local_packages (category, name, version, slot) values (?, ?, ?, ?);", row) + sisyphusdb.commit() + sisyphusdb.close() + +@animation.wait('syncing local database tables') +def startSyncSPM(): + makeLocalDatabaseCSV() + syncLocalDatabaseTable() + +def startInstall(pkgList): + syncAll() + portageExec = subprocess.Popen(['emerge', '-aq'] + pkgList) + portageExec.communicate() + makeLocalDatabaseCSV() + syncLocalDatabaseTable() + +def startUninstall(pkgList): + portageExec = subprocess.Popen(['emerge', '--depclean', '-aq'] + pkgList) + portageExec.communicate() + makeLocalDatabaseCSV() + syncLocalDatabaseTable() + +def startUninstallForce(pkgList): + portageExec = subprocess.Popen(['emerge', '--unmerge', '-aq'] + pkgList) + portageExec.communicate() + makeLocalDatabaseCSV() + syncLocalDatabaseTable() + +def removeOrphans(): + portageExec = subprocess.Popen(['emerge', '--depclean', '-aq']) + portageExec.communicate() + makeLocalDatabaseCSV() + syncLocalDatabaseTable() + +def startUpgrade(): + syncAll() + portageExec = subprocess.Popen(['emerge', '-uDaNq', '--backtrack=100', '--with-bdeps=y', '@world']) + portageExec.communicate() + makeLocalDatabaseCSV() + syncLocalDatabaseTable() + +def startSearch(pkgList): + subprocess.check_call(['emerge', '--search'] + pkgList) + +def startUpdate(): + syncAll() + +def sysInfo(): + subprocess.check_call(['emerge', '--info']) + +@animation.wait('resurrecting database tables') +def rescueDB(): + if os.path.exists(rmtPkgCsv): + os.remove(rmtPkgCsv) + if os.path.exists(rmtDscCsv): + os.remove(rmtDscCsv) + if os.path.exists(lclPkgCsv): + os.remove(lclPkgCsv) + if os.path.exists(sisyphusDB): + os.remove(sisyphusDB) + + fetchRemoteDatabaseCSV() + syncRemoteDatabaseCSV() + + makeLocalDatabaseCSV() + syncLocalDatabaseTable() + +def portageKill(portageCmd): + portageCmd.terminate() + +def getMirrors(): + mirrorList = [] + with open(mirrorCfg) as mirrorFile: + for line in mirrorFile.readlines(): + if 'PORTAGE_BINHOST=' in line: + url = line.split("=")[1].replace('"', '').rstrip() + mirror = {'isActive':True,'Url':url} + if line.startswith('#'): + mirror['isActive'] = False + mirrorList.append(mirror) + mirrorFile.close() + return mirrorList + +def setActiveMirror(mirrorList): + with open(mirrorCfg, 'w+') as mirrorFile: + mirrorFile.write("#######################################################\n") + mirrorFile.write("# Support for multiple mirrors is somewhat incomplete #\n") + mirrorFile.write("# Uncomment only one mirror from the list bellow #\n") + mirrorFile.write("#######################################################\n") + mirrorFile.write("\n") + for line in mirrorList : + mirror = 'PORTAGE_BINHOST=' + '"' + line['Url'] + '"' + if not line['isActive']: + mirror = '# ' + mirror + mirrorFile.write(mirror + "\n") + mirrorFile.write("\n") + +def listRepo(): + mirrorList = getMirrors() + for i, line in enumerate(mirrorList): + if line['isActive']: + print(i+1,'*',line['Url']) + else: + print(i+1,' ',line['Url']) + +def setRepo(mirror): + mirror = int(mirror[0]) + mirrorList = getMirrors() + if mirror not in range(1,len(mirrorList)+1): + print('mirror index is wrong, please check with "sisyphus mirror list"') + else: + for i in range(0,len(mirrorList)): + indx = i+1 + if indx == mirror : + mirrorList[i]['isActive'] = True + else: + mirrorList[i]['isActive'] = False + setActiveMirror(mirrorList) + +def showHelp(): + print("\nUsage : sisyphus command [package(s)] || [file(s)]\n") + print("Sisyphus is a simple python wrapper around portage, gentoolkit, and portage-utils that provides") + print("an apt-get/yum-alike interface to these commands, to assist newcomer people transitioning from") + print("Debian/RedHat-based systems to Gentoo.\n") + print("Commands :\n") + print("install - Install new packages") + print("uninstall - Uninstall packages *safely* (INFO : If reverse deps are found, package(s) will NOT be uninstalled)") + print("force-uninstall - Uninstall packages *unsafely* (WARNING : This option will ignore reverse deps, which may break your system)") + print("remove-orphans - Uninstall packages that are no longer needed") + print("update - Update the Portage tree, Overlay(s), Portage config files && Sisyphus database remote_packages table") + print("upgrade - Upgrade the system") + print("search - Search for packages") + print("spmsync - Sync Sisyphus database with Portage database (if you install something with Portage, not Sisyphus)") + print("rescue - Rescue Sisyphus database if lost or corrupted") + print("mirror list - List available mirrors (the active one is marked with *)") + print("mirror set INDEX - Switch the repository to the selected mirror") + print("sysinfo - Display information about installed core packages and portage configuration") |