class PoolInstaller(Installer): def __init__(self, chroot_path, pool_path, arch, environ={}): super(PoolInstaller, self).__init__(chroot_path, environ) from pyproject.pool.pool import Pool self.pool = Pool(pool_path) self.arch = arch @staticmethod def _get_package_index(packagedir): def filesize(path): return str(os.stat(path).st_size) def md5sum(path): return str(hashlib.md5(open(path, 'rb').read()).hexdigest()) def sha256sum(path): return str(hashlib.sha256(open(path, 'rb').read()).hexdigest()) index = [] for package in os.listdir(packagedir): path = os.path.join(packagedir, package) # dl_path would best be calculated; but we don't have access to chroot_path here... dl_path = os.path.join('var/cache/apt/archives', package) if path.endswith('.deb'): control = debinfo.get_control_fields(path) for field in control.keys(): index.append(field + ": " + control[field]) index.append("Filename: " + dl_path) index.append("Size: " + filesize(path)) index.append("MD5sum: " + md5sum(path)) index.append("SHA256: " + sha256sum(path)) index.append("") return index def install(self, packages, ignore_errors=[]): """install packages into chroot via pool""" print "getting packages..." packagedir = join(self.chroot.path, "var/cache/apt/archives") self.pool.get(packagedir, packages, strict=True) print "generating package index..." sources_list = RevertibleFile( join(self.chroot.path, "etc/apt/sources.list")) print >> sources_list, "deb file:/// local debs" sources_list.close() index_file = "_dists_local_debs_binary-%s_Packages" % self.arch index_path = join(self.chroot.path, "var/lib/apt/lists", index_file) index = self._get_package_index(packagedir) file(index_path, "w").write("\n".join(index)) self.chroot.system("apt-cache gencaches") print "installing packages..." self._install(packages, ignore_errors, ['--allow-unauthenticated'])
class PoolInstaller(Installer): def __init__(self, chroot_path, pool_path, arch, environ={}): super(PoolInstaller, self).__init__(chroot_path, environ) from pyproject.pool.pool import Pool self.pool = Pool(pool_path) self.arch = arch @staticmethod def _get_package_index(packagedir): def filesize(path): return str(os.stat(path).st_size) def md5sum(path): return str(hashlib.md5(open(path, 'rb').read()).hexdigest()) index = [] for package in os.listdir(packagedir): path = os.path.join(packagedir, package) if path.endswith('.deb'): control = debinfo.get_control_fields(path) for field in control.keys(): index.append(field + ": " + control[field]) index.append("Filename: " + path) index.append("Size: " + filesize(path)) index.append("MD5sum: " + md5sum(path)) index.append("") return index def install(self, packages, ignore_errors=[]): """install packages into chroot via pool""" print "getting packages..." packagedir = join(self.chroot.path, "var/cache/apt/archives") self.pool.get(packagedir, packages, strict=True) print "generating package index..." sources_list = RevertibleFile(join(self.chroot.path, "etc/apt/sources.list")) print >> sources_list, "deb file:/// local debs" sources_list.close() index_file = "_dists_local_debs_binary-%s_Packages" % self.arch index_path = join(self.chroot.path, "var/lib/apt/lists", index_file) index = self._get_package_index(packagedir) file(index_path, "w").write("\n".join(index)) self.chroot.system("apt-cache gencaches") print "installing packages..." self._install(packages, ignore_errors, ['--allow-unauthenticated'])
def get_packages_info(packages, pool_path): info = {} from pyproject.pool.pool import Pool pool = Pool(pool_path) tmpdir = TempDir() pool.get(tmpdir.path, packages, strict=True) for package in os.listdir(tmpdir.path): path = os.path.join(tmpdir.path, package) if path.endswith('.deb'): control = debinfo.get_control_fields(path) info[control['Package']] = control['Description'] return info
def __init__(self, iterable=(), pool_path=None): set.__init__(self, iterable) if pool_path: from pyproject.pool.pool import Pool self.pool = Pool(pool_path) else: self.pool = None self.packageorigins = PackageOrigins()
def __init__(self, chroot_path, pool_path, arch, environ={}): super(PoolInstaller, self).__init__(chroot_path, environ) from pyproject.pool.pool import Pool self.pool = Pool(pool_path) self.arch = arch
class Plan(set): @staticmethod def _parse_plan_file(path, cpp_opts=[]): """process plan through cpp, then parse it and add packages to plan """ processed_plan = cpp.cpp(path, cpp_opts) packages = set() for expr in processed_plan.splitlines(): expr = re.sub(r'#.*', '', expr) expr = expr.strip() if not expr: continue if expr.startswith("!"): package = expr[1:] if package in packages: packages.remove(package) else: package = expr packages.add(package) return packages @classmethod def init_from_file(cls, plan_file_path, cpp_opts=[], pool_path=None): return cls(cls._parse_plan_file(plan_file_path, cpp_opts), pool_path) def __new__(cls, iterable=(), pool_path=None): return set.__new__(cls, iterable) def __init__(self, iterable=(), pool_path=None): set.__init__(self, iterable) if pool_path: from pyproject.pool.pool import Pool self.pool = Pool(pool_path) else: self.pool = None self.packageorigins = PackageOrigins() def _get_new_deps(self, pkg_control, old_deps, depend_fields): def parse_depends(val): if val is None or val.strip() == "": return [] return re.split("\s*,\s*", val.strip()) new_deps = set() raw_depends = [] for field_name in depend_fields: raw_depends += parse_depends(pkg_control.get(field_name)) for raw_depend in raw_depends: if "|" not in raw_depend: new_deps.add(Dependency(raw_depend)) continue alternatives = [ Dependency(alt) for alt in raw_depend.split("|") ] # continue if any of the alternatives are already in resolved or unresolved sets if set(alternatives) & old_deps: continue # add the first alternative that exists in the pool to set of new dependencies for alternative in alternatives: if self.pool.exists(alternative.name): new_deps.add(alternative) break for dep in new_deps: self.packageorigins.add(dep.name, pkg_control.get('Package')) return new_deps @staticmethod def _get_provided(pkg_control): raw_provided = pkg_control.get('Provides') if raw_provided is None or raw_provided.strip() == "": return set() return set(re.split("\s*,\s*", raw_provided.strip())) def dctrls(self): """return plan dependencies control file info""" toquery = set([ Dependency(pkg) for pkg in self ]) packages = PackageGetter(toquery, self.pool) dctrls = {} for dep in toquery: package_path = packages[dep] if package_path is None: raise Error('could not find package', dep.name) dctrls[dep] = debinfo.get_control_fields(package_path) dctrls[dep]['Filename'] = basename(package_path) return dctrls def resolve(self): """resolve plan dependencies recursively -> return spec""" spec = Spec() if not self.pool: return list(self) resolved = set() missing = set() provided = set() def reformat2dep(pkg): if '=' not in pkg: return pkg name, version = pkg.split("=", 1) return "%s (= %s)" % (name, version) unresolved = set([ Dependency(reformat2dep(pkg)) for pkg in self ]) while unresolved: # get newest package versions of unresolved dependencies from the pool # and pray they don't conflict with our dependency restrictions packages = PackageGetter(unresolved, self.pool) new_deps = set() for dep in unresolved: package_path = packages[dep] if not package_path: continue pkg_control = debinfo.get_control_fields(package_path) version = pkg_control['Version'] if not dep.is_version_ok(version): raise Error("dependency '%s' incompatible with newest pool version (%s)" % (dep, version)) spec.add(dep.name, version) resolved.add(dep) new_deps |= self._get_new_deps(pkg_control, resolved | unresolved | new_deps, dep.fields) provided |= self._get_provided(pkg_control) unresolved = new_deps - resolved missing = (missing | packages.missing) - provided if missing: def get_origins(dep): # trace the package origins origins = [] while dep: try: dep = self.packageorigins[dep][0] origins.append(dep) except KeyError: dep = None return origins brokendeps = [] for dep in missing: brokendeps.append("%s (%s)" % (dep, " -> ".join(get_origins(dep)))) raise Error("broken dependencies: " + "\n".join(brokendeps)) return spec