| 1 |
"""
|
| 2 |
# Copyright 1999-2005 Gentoo Foundation
|
| 3 |
# This source code is distributed under the terms of version 2 of the GNU
|
| 4 |
# General Public License as published by the Free Software Foundation, a copy
|
| 5 |
# of which can be found in the main directory of this project.
|
| 6 |
Gentoo Linux Installer
|
| 7 |
|
| 8 |
$Id: GLIPortage.py,v 1.1 2005/12/23 21:14:08 agaffney Exp $
|
| 9 |
"""
|
| 10 |
|
| 11 |
import os
|
| 12 |
import GLIUtility
|
| 13 |
|
| 14 |
class MissingPackagesError(Exception):
|
| 15 |
pass
|
| 16 |
|
| 17 |
class depgraph:
|
| 18 |
|
| 19 |
def __init__(self):
|
| 20 |
self.graph = {}
|
| 21 |
|
| 22 |
def add(self, node, parent=None):
|
| 23 |
if node not in self.graph:
|
| 24 |
self.graph[node] = [[], []]
|
| 25 |
if parent and parent not in self.graph[node][0]:
|
| 26 |
if parent not in self.graph:
|
| 27 |
self.graph[parent] = [[], []]
|
| 28 |
self.graph[node][0].append(parent)
|
| 29 |
self.graph[parent][1].append(node)
|
| 30 |
|
| 31 |
def remove(self, node):
|
| 32 |
for parent in self.graph[node][0]:
|
| 33 |
self.graph[parent][1].remove(node)
|
| 34 |
for child in self.graph[node][1]:
|
| 35 |
self.graph[child][0].remove(node)
|
| 36 |
return self.graph.pop(node)
|
| 37 |
|
| 38 |
def has_node(self, node):
|
| 39 |
return node in self.graph
|
| 40 |
|
| 41 |
def leaf_nodes(self):
|
| 42 |
return [node for node in self.graph if not self.graph[node][1]]
|
| 43 |
|
| 44 |
def node_count(self):
|
| 45 |
return len(self.graph)
|
| 46 |
|
| 47 |
def important_node(self):
|
| 48 |
important_node = None
|
| 49 |
importance = 0
|
| 50 |
for node in self.graph:
|
| 51 |
if len(self.graph[node][0]) > importance:
|
| 52 |
importance = len(self.graph[node][0])
|
| 53 |
important_node = node
|
| 54 |
return important_node
|
| 55 |
|
| 56 |
class GLIPortage(object):
|
| 57 |
|
| 58 |
def __init__(self, chroot_dir):
|
| 59 |
os.environ['ROOT'] = chroot_dir
|
| 60 |
import portage, portage_dep
|
| 61 |
self.vdb = portage.db["/"]["vartree"].dbapi
|
| 62 |
self.chroot_dir = chroot_dir
|
| 63 |
|
| 64 |
def resolve_deps(self, dep_list):
|
| 65 |
if dep_list and dep_list[0] == "||":
|
| 66 |
for dep in dep_list[1:]:
|
| 67 |
if isinstance(dep, list):
|
| 68 |
try:
|
| 69 |
atoms = resolve_deps(dep)
|
| 70 |
except MissingPackagesError:
|
| 71 |
continue
|
| 72 |
else:
|
| 73 |
atoms = [dep]
|
| 74 |
all_found = True
|
| 75 |
for atom in atoms:
|
| 76 |
if not atom.startswith("!") and not self.vdb.match(atom):
|
| 77 |
all_found = False
|
| 78 |
break
|
| 79 |
if all_found:
|
| 80 |
return atoms
|
| 81 |
raise MissingPackagesError(dep_list)
|
| 82 |
atoms = []
|
| 83 |
for dep in dep_list:
|
| 84 |
if isinstance(dep, list):
|
| 85 |
atoms.extend(resolve_deps(dep))
|
| 86 |
elif not dep.startswith("!"):
|
| 87 |
if not self.vdb.match(dep):
|
| 88 |
raise MissingPackagesError([dep])
|
| 89 |
atoms.append(dep)
|
| 90 |
return atoms
|
| 91 |
|
| 92 |
def calc_required_pkgs(self, atom, graph, parent=None):
|
| 93 |
pkg = portage.best(self.vdb.match(atom))
|
| 94 |
if not pkg:
|
| 95 |
raise MissingPackagesError([atom])
|
| 96 |
if pkg == parent:
|
| 97 |
return
|
| 98 |
already_processed = graph.has_node(pkg)
|
| 99 |
graph.add(pkg, parent)
|
| 100 |
if already_processed:
|
| 101 |
return
|
| 102 |
useflags = self.vdb.aux_get(pkg, ["USE"])[0].split()
|
| 103 |
rdep_raw = " ".join(self.vdb.aux_get(pkg, ["RDEPEND", "PDEPEND"]))
|
| 104 |
rdep_struct = portage_dep.use_reduce(portage_dep.paren_reduce(rdep_raw), uselist=useflags)
|
| 105 |
rdep_struct = portage.dep_virtual(portage_dep.dep_opconvert(rdep_struct), portage.settings)
|
| 106 |
rdep_atoms = portage.unique_array(resolve_deps(rdep_struct))
|
| 107 |
for atom in rdep_atoms:
|
| 108 |
calc_required_pkgs(atom, graph, pkg)
|
| 109 |
|
| 110 |
def prune_existing(self, graph):
|
| 111 |
db = portage.db[portage.root]["vartree"].dbapi
|
| 112 |
for atom in db.cp_all():
|
| 113 |
for pkg in db.match(atom):
|
| 114 |
if graph.has_node(pkg):
|
| 115 |
graph.remove(pkg)
|
| 116 |
|
| 117 |
def get_deps(self, pkgs, grp_install):
|
| 118 |
if not grp_install:
|
| 119 |
del(os.environ['ROOT'])
|
| 120 |
return GLIUtility.spawn("emerge -p " + pkgs + r" | grep -e '^\[[a-z]' | cut -d ']' -f2 | sed -e 's:^ ::' -e 's: .\+$::'", chroot=self.chroot_dir, return_output=True)[1].split("\n")
|
| 121 |
os.environ['ROOT'] = self.chroot_dir
|
| 122 |
else:
|
| 123 |
pkglist = []
|
| 124 |
graph = depgraph()
|
| 125 |
for pkg in pkgs.split():
|
| 126 |
if not self.vdb.match(pkg):
|
| 127 |
continue
|
| 128 |
self.calc_required_pkgs(pkg, graph)
|
| 129 |
while graph.node_count():
|
| 130 |
leaf_nodes = graph.leaf_nodes()
|
| 131 |
if not leaf_nodes:
|
| 132 |
node = graph.important_node()
|
| 133 |
pkglist.append(node)
|
| 134 |
graph.remove(node)
|
| 135 |
continue
|
| 136 |
pkglist.extend(leaf_nodes)
|
| 137 |
for node in leaf_nodes:
|
| 138 |
graph.remove(node)
|
| 139 |
return pkglist
|