172 lines
4.0 KiB
Python
172 lines
4.0 KiB
Python
from typing import List, Optional
|
|
|
|
from biopro.util.sys import system_call, CalledProcessError
|
|
|
|
|
|
class Package:
|
|
def __init__(self):
|
|
self.name = ''
|
|
self.version = ''
|
|
|
|
@classmethod
|
|
def manager(cls) -> str:
|
|
try:
|
|
system_call('which', 'dpkg')
|
|
return 'dpkg'
|
|
except CalledProcessError:
|
|
pass
|
|
|
|
try:
|
|
system_call('which', 'pacman')
|
|
return 'pacman'
|
|
except CalledProcessError:
|
|
pass
|
|
|
|
raise RuntimeError()
|
|
|
|
@classmethod
|
|
def list(cls) -> List['Package']:
|
|
manager = cls.manager()
|
|
if manager == 'dpkg':
|
|
return AptGetPackage.list()
|
|
|
|
elif manager == 'pacman':
|
|
return PacmanPackage.list()
|
|
|
|
return []
|
|
|
|
|
|
_DESIRED = ( # TODO use typing.Literal in Python 3.8
|
|
'u', # Unknown
|
|
'i', # Install
|
|
'r', # Remove
|
|
'p', # Purge
|
|
'h', # Hold
|
|
)
|
|
_STATUS = ( # TODO use typing.Literal in Python 3.8
|
|
'n', # Not (The package is not installed)
|
|
'i', # Inst (The package is successfully installed)
|
|
'c', # Conf-files (Configuration files are present)
|
|
'u', # Unpacked (The package is stilled unpacked)
|
|
'f', # Failed-conf (Failed to remove configuration files)
|
|
'h', # Half-inst (The package is only partially installed)
|
|
'W', # trig-aWait ()
|
|
't', # Trig-pend ()
|
|
)
|
|
|
|
|
|
class AptGetPackage(Package):
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
self.desired = '' # Unknown/Install/Remove/Purge/Hold
|
|
self.status = '' # Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|
|
self.err: Optional[str] = None # (none)/Reinst-required (Status,Err: uppercase=bad)
|
|
self.architecture = ''
|
|
self.description = ''
|
|
|
|
def __repr__(self):
|
|
return '%s%s%s %s %s %s %s' % (
|
|
self.desired,
|
|
self.status,
|
|
'' if self.err is None else self.err,
|
|
self.name,
|
|
self.version,
|
|
self.architecture,
|
|
self.description
|
|
)
|
|
|
|
@classmethod
|
|
def list(cls) -> List['AptGetPackage']:
|
|
output = system_call('dpkg', '-l')
|
|
|
|
ret = []
|
|
|
|
for line in output.split('\n')[6:]:
|
|
if len(line) == 0:
|
|
continue
|
|
|
|
part: List[str] = list(filter(len, line.split(' ')))
|
|
|
|
package = AptGetPackage()
|
|
ret.append(package)
|
|
|
|
c = part[0]
|
|
package.desired = c[0]
|
|
package.status = c[1]
|
|
|
|
try:
|
|
package.err = c[2]
|
|
except IndexError:
|
|
pass
|
|
|
|
package.name = part[1]
|
|
package.version = part[2]
|
|
package.architecture = part[3]
|
|
package.description = ' '.join(part[4:])
|
|
|
|
return ret
|
|
|
|
|
|
class PacmanPackage(Package):
|
|
|
|
def __repr__(self):
|
|
return '%s %s' % (
|
|
self.name,
|
|
self.version,
|
|
)
|
|
|
|
@classmethod
|
|
def list(cls) -> List['PacmanPackage']:
|
|
output = system_call('pacman', '-Q')
|
|
|
|
ret = []
|
|
|
|
for line in output.split('\n'):
|
|
if len(line) == 0:
|
|
continue
|
|
|
|
part: List[str] = list(filter(len, line.split(' ')))
|
|
|
|
package = PacmanPackage()
|
|
ret.append(package)
|
|
|
|
package.name = part[0]
|
|
package.version = part[1]
|
|
|
|
return ret
|
|
|
|
|
|
class PipPackage(Package):
|
|
def __repr__(self):
|
|
return '%s %s' % (
|
|
self.name,
|
|
self.version,
|
|
)
|
|
|
|
@classmethod
|
|
def list(cls) -> List['PipPackage']:
|
|
output = system_call('pip3', 'list')
|
|
|
|
ret = []
|
|
|
|
for line in output.split('\n')[2:]:
|
|
if len(line) == 0:
|
|
continue
|
|
|
|
part: List[str] = list(filter(len, line.split(' ')))
|
|
|
|
package = PipPackage()
|
|
ret.append(package)
|
|
|
|
package.name = part[0]
|
|
package.version = part[1]
|
|
|
|
return ret
|
|
|
|
|
|
if __name__ == '__main__':
|
|
print(Package.manager())
|
|
for p in Package.list():
|
|
print(p)
|