#-*- coding: utf-8 -*- # Copyright 2014 Calculate Ltd. http://www.calculate-linux.org # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from collections import Mapping from functools import total_ordering import os from os import path import bz2 import re try: from calculate.lib.utils.files import readFile, listDirectory, pathJoin from calculate.lib.datavars import SimpleDataVars except ImportError: from cl_utils import readFile, listDirectory, pathJoin from cl_datavars import DataVars class SimpleRepositoryMapper(Mapping): """ Определение пути до репозитория """ map_repository = {'gentoo': '/usr/portage', 'calculate': '/var/lib/layman/calculate'} layman_path = '/var/lib/layman' def __init__(self, prefix='/'): self.prefix = prefix def __getitem__(self, item): if item in self.map_repository: return pathJoin(self.prefix, self.map_repository[item]) return pathJoin(self.prefix, self.layman_path, item) def __iter__(self): return iter(self.map_repository) def __len__(self): return len(self.map_repository) class EbuildInfoError(Exception): pass class EbuildInfo(object): """ Информация о ebuild (DEPEND) из metadata """ map_repository = SimpleRepositoryMapper() meta_suffix_path = 'metadata/md5-cache' support_keys = ('DEPEND', 'RDEPEND', 'PDEPEND') def __init__(self, atom, repository): meta_path = path.join(self.map_repository[repository], self.meta_suffix_path) self._meta_info_path = path.join(meta_path, atom) if not path.exists(self._meta_info_path): raise EbuildInfoError("Package is not found") self._info = self._get_info() def _get_info(self): with open(self._meta_info_path, 'r') as f: return {k.strip(): v.strip() for k, v in (line.partition('=')[::2] for line in f.readlines()) if k in self.support_keys} def __getitem__(self, item): if item in self.support_keys: return self._info.get(item,'') raise KeyError(item) @classmethod def set_repository_mapper(cls, mapper): cls.map_repository = mapper def __eq__(self, other): return all(other[k] == self[k] for k in self.support_keys) def __ne__(self, other): return any(other[k] != self[k] for k in self.support_keys) class InstalledPackageInfoError(Exception): pass class InstalledPackageInfo(object): """ Информация об установленном пакете (DEPEND) из /var/db/pkg """ pkg_dir = '/var/db/pkg' depend_pattern = 'declare (?:-x )?({0})="([^"]+)"' re_depend = re.compile(depend_pattern.format("RDEPEND|PDEPEND|DEPEND"), re.DOTALL) re_multispace = re.compile("\s+", re.DOTALL) def __init__(self, atom): self.atom = atom self._pkg_path = path.join(self.pkg_dir, atom) if not path.exists(self._pkg_path): raise InstalledPackageInfoError("Package is not found") self._info = self._get_info() def _get_info(self): info = {k: "" for k in ("RDEPEND", "DEPEND", "PDEPEND")} env_path = path.join(self._pkg_path, 'environment.bz2') if path.exists(env_path): with bz2.BZ2File(env_path, 'r') as f: for r in self.re_depend.finditer(f.read()): key, value = r.groups() value = self.re_multispace.sub(" ", value) info[key] = value.strip() rep_path = path.join(self._pkg_path, 'repository') info['repository'] = readFile(rep_path).strip() return info def __getitem__(self, item): return self._info[item] @classmethod def get_install_packages(cls): for category in listDirectory(cls.pkg_dir): for pkg in listDirectory(path.join(cls.pkg_dir, category)): yield InstalledPackageInfo("%s/%s" % (category, pkg)) def __str__(self): return self.atom def __repr__(self): return "InstalledPackageInfo(%s)" % self.atom class SimpleVariable(object): def __init__(self, varname, fallback_value="", section="main", type="string"): self.varname = varname self.fallback_value = fallback_value self.section = section self.type = type def get(self): return self.fallback_value def getVariableName(self): return self.varname class ArchVariable(SimpleVariable): def __init__(self, varname, fallback_value="", section="main", type="string", prefix="/"): self.varname = varname self.fallback_value = fallback_value self.section = section self.type = type self.prefix = prefix def get(self): if path.lexists(path.join(self.prefix,'lib64')): return 'x86_64' elif path.lexists(path.join(self.prefix,'lib')): return 'i686' else: d['os_arch_machine'] = '' class ProfileVariable(SimpleVariable): def __init__(self, varname, fallback_value="", section="main", type="string", prefix="/"): self.varname = varname self.fallback_value = fallback_value self.section = section self.type = type self.prefix = prefix def get(self): for profile in ('etc/portage/make.profile', 'etc/make.profile'): profile = path.join(self.prefix, profile) if path.exists(profile): return os.readlink(profile) return ""