pkgcrap/pkgcrap/parse.py

164 lines
5.1 KiB
Python

from os import listdir
from os.path import abspath, isfile, dirname
from portage.versions import cpv_sort_key
from configparser import ConfigParser
import xml.etree.ElementTree as ET
class ebuild:
def __init__(self, package, full_name):
self.package = package
self.path = package.path+'/'+full_name+'.ebuild'
self.name = '-'.join(full_name.split('-')[0:-1])
self.version = full_name.split('-')[-1]
self.live = self.version[:4] == '9999'
self.inherits = []
self.vars = {}
self.loaded = False
def load(self):
# TODO: Read ebuilds properly
with open(self.path, 'r') as fp:
for line in fp.readlines():
line = line[:-1].split('#', maxsplit=1)[0]
if len(line) > 0 and '=' in line:
s = [p.strip() for p in line.split('=', maxsplit=1)]
if len(s[1]) > 1 and s[1][0] == s[1][-1] == '"':
self.vars[s[0]] = s[1][1:-1]
if line.startswith('inherit'):
self.inherits.extend(line.split(' ')[1:])
if len(line) > 0 and line[-1] == '{':
break
self.loaded = True
class manifest:
def __init__(self, path):
self.path = path
self.loaded = False
def load(self):
with open(self.path, 'r') as fp:
self.entries = [n[:-1].split(' ') for n in fp.readlines()]
self.loaded = True
class metadata:
def __init__(self, path):
self.path = path
self.maintainers = []
self.remotes = []
self.loaded = False
def load(self):
self.tree = ET.parse(self.path)
self.root = self.tree.getroot()
for maintainer in self.root.findall('./maintainer'):
self.maintainers.append(maintainer.find('email').text)
for upstream in self.root.findall('./upstream'):
remote = upstream.find('remote-id')
if remote is not None:
self.remotes.append([remote.get('type'), remote.text])
self.loaded = True
class package:
def __init__(self, category, name):
self.category = category
self.name = name
self.path = category.path+'/'+name
self.ebuilds = []
self.loaded = False
@classmethod
def from_path(self, path):
path = abspath(path)
if path[-1] == '/':
path = path[:-1]
cat = category.from_path(dirname(path))
return package(cat, path.split('/')[-1])
def load(self):
self.full_name = self.category.name+'/'+self.name+'::'+self.category.repo.name
ls = listdir(self.path)
if 'Manifest' in ls:
mf = manifest(self.path+'/Manifest')
mf.load()
self.manifest = mf
if 'metadata.xml' in ls:
md = metadata(self.path+'/metadata.xml')
md.load()
self.metadata = md
ebuild_names = [n[:-7] for n in filter(lambda name: name[-7:] == '.ebuild', ls)]
ebuild_names = sorted(ebuild_names, key=cpv_sort_key())[::-1]
for name in ebuild_names:
eb = ebuild(self, name)
eb.load()
self.ebuilds.append(eb)
self.loaded = True
def version_latest(self):
for eb in self.ebuilds:
if not eb.live:
return eb.version
return None
class category:
def __init__(self, repo, name):
self.repo = repo
self.name = name
self.path = repo.path+'/'+name
self.packages = {}
self.loaded = False
@classmethod
def from_path(self, path):
path = abspath(path)
if path[-1] == '/':
path = path[:-1]
repo = repository(dirname(path))
return category(repo, path.split('/')[-1])
def load(self):
for name in listdir(self.path):
if isfile(self.path+'/'+name):
continue
self.packages[name] = package(self, name)
self.loaded = True
class repository:
def __init__(self, path):
self.path = abspath(path)
self.categories = {}
with open(self.path+'/profiles/repo_name', 'r') as fp:
self.name = fp.read().replace("\n", '')
self.loaded = False
def load(self):
for name in listdir(self.path):
if '-' not in name or isfile(self.path+'/'+name):
continue
self.categories[name] = category(self, name)
self.loaded = True
class repos:
def __init__(self):
self.from_path('/etc/portage/repos.conf')
self.loaded = False
@classmethod
def from_path(self, path):
self.path = abspath(path)
self.repos = {}
def load(self):
conf_paths = []
if isfile(self.path):
conf_paths.append(self.path)
else:
for name in listdir(self.path):
if name[-5:] == '.conf':
conf_paths.append(self.path+'/'+name)
conf = ConfigParser()
conf.read(conf_paths)
for section in conf.sections():
self.repos[section] = repository(conf[section]['location'])
self.loaded = True