| 1 |
agaffney |
1181 |
""" |
| 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 |