autounmask: Add ability to adjust USE
[portage.git] / pym / portage / tests / resolver / ResolverPlayground.py
1 # Copyright 2010 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
3
4 from itertools import chain
5 import shutil
6 import tempfile
7 import portage
8 from portage import os
9 from portage.dbapi.vartree import vartree
10 from portage.dbapi.porttree import portagetree
11 from portage.dbapi.bintree import binarytree
12 from portage.dep import Atom
13 from portage.package.ebuild.config import config
14 from portage.sets import load_default_config
15 from portage.versions import catsplit
16
17 from _emerge.Blocker import Blocker
18 from _emerge.create_depgraph_params import create_depgraph_params
19 from _emerge.depgraph import backtrack_depgraph
20 from _emerge.RootConfig import RootConfig
21
22 class ResolverPlayground(object):
23         """
24         This class help to create the necessary files on disk and
25         the needed settings instances, etc. for the resolver to do
26         it's work.
27         """
28         
29         def __init__(self, ebuilds={}, installed={}, profile={}):
30                 """
31                 ebuilds: cpv -> metadata mapping simulating avaiable ebuilds. 
32                 installed: cpv -> metadata mapping simulating installed packages.
33                         If a metadata key is missing, it gets a default value.
34                 profile: settings defined by the profile.
35                 """
36                 self.root = tempfile.mkdtemp() + os.path.sep
37                 self.portdir = os.path.join(self.root, "usr/portage")
38                 self.vdbdir = os.path.join(self.root, "var/db/pkg")
39                 os.makedirs(self.portdir)
40                 os.makedirs(self.vdbdir)
41                 
42                 self._create_ebuilds(ebuilds)
43                 self._create_installed(installed)
44                 self._create_profile(ebuilds, installed, profile)
45                 
46                 self.settings, self.trees = self._load_config()
47                 
48                 self._create_ebuild_manifests(ebuilds)
49
50         def _create_ebuilds(self, ebuilds):
51                 for cpv in ebuilds:
52                         a = Atom("=" + cpv)
53                         ebuild_dir = os.path.join(self.portdir, a.cp)
54                         ebuild_path = os.path.join(ebuild_dir, a.cpv.split("/")[1] + ".ebuild")
55                         try:
56                                 os.makedirs(ebuild_dir)
57                         except os.error:
58                                 pass
59                         
60                         metadata = ebuilds[cpv]
61                         eapi = metadata.get("EAPI", 0)
62                         slot = metadata.get("SLOT", 0)
63                         keywords = metadata.get("KEYWORDS", "x86")
64                         iuse = metadata.get("IUSE", "")
65                         depend = metadata.get("DEPEND", "")
66                         rdepend = metadata.get("RDEPEND", None)
67                         pdepend = metadata.get("PDEPEND", None)
68
69                         f = open(ebuild_path, "w")
70                         f.write('EAPI="' + str(eapi) + '"\n')
71                         f.write('SLOT="' + str(slot) + '"\n')
72                         f.write('KEYWORDS="' + str(keywords) + '"\n')
73                         f.write('IUSE="' + str(iuse) + '"\n')
74                         f.write('DEPEND="' + str(depend) + '"\n')
75                         if rdepend is not None:
76                                 f.write('RDEPEND="' + str(rdepend) + '"\n')
77                         if rdepend is not None:
78                                 f.write('PDEPEND="' + str(pdepend) + '"\n')
79                         f.close()
80
81         def _create_ebuild_manifests(self, ebuilds):
82                 for cpv in ebuilds:
83                         a = Atom("=" + cpv)
84                         ebuild_dir = os.path.join(self.portdir, a.cp)
85                         ebuild_path = os.path.join(ebuild_dir, a.cpv.split("/")[1] + ".ebuild")
86                         
87                         portage.util.noiselimit = -1
88                         tmpsettings = config(clone=self.settings)
89                         portdb = self.trees[self.root]["porttree"].dbapi
90                         portage.doebuild(ebuild_path, "digest", self.root, tmpsettings,
91                                 tree="porttree", mydbapi=portdb)
92                         portage.util.noiselimit = 0
93                 
94         def _create_installed(self, installed):
95                 for cpv in installed:
96                         a = Atom("=" + cpv)
97                         vdb_pkg_dir = os.path.join(self.vdbdir, a.cpv)
98                         try:
99                                 os.makedirs(vdb_pkg_dir)
100                         except os.error:
101                                 pass
102
103                         metadata = installed[cpv]
104                         eapi = metadata.get("EAPI", 0)
105                         slot = metadata.get("SLOT", 0)
106                         keywords = metadata.get("KEYWORDS", "~x86")
107                         iuse = metadata.get("IUSE", "")
108                         use = metadata.get("USE", "")
109                         depend = metadata.get("DEPEND", "")
110                         rdepend = metadata.get("RDEPEND", None)
111                         pdepend = metadata.get("PDEPEND", None)
112                         
113                         def write_key(key, value):
114                                 f = open(os.path.join(vdb_pkg_dir, key), "w")
115                                 f.write(str(value) + "\n")
116                                 f.close()
117                         
118                         write_key("EAPI", eapi)
119                         write_key("SLOT", slot)
120                         write_key("KEYWORDS", keywords)
121                         write_key("IUSE", iuse)
122                         write_key("USE", use)
123                         write_key("DEPEND", depend)
124                         if rdepend is not None:
125                                 write_key("RDEPEND", rdepend)
126                         if rdepend is not None:
127                                 write_key("PDEPEND", pdepend)
128
129         def _create_profile(self, ebuilds, installed, profile):
130                 #Create $PORTDIR/profiles/categories
131                 categories = set()
132                 for cpv in chain(ebuilds.keys(), installed.keys()):
133                         categories.add(catsplit(cpv)[0])
134                 
135                 profile_dir = os.path.join(self.portdir, "profiles")
136                 try:
137                         os.makedirs(profile_dir)
138                 except os.error:
139                         pass
140                 
141                 categories_file = os.path.join(profile_dir, "categories")
142                 
143                 f = open(categories_file, "w")
144                 for cat in categories:
145                         f.write(cat + "\n")
146                 f.close()
147                 
148                 #Create $PORTDIR/eclass (we fail to digest the ebuilds if it's not there)
149                 os.makedirs(os.path.join(self.portdir, "eclass"))
150                 
151                 if profile:
152                         #This is meant to allow the consumer to set up his own profile,
153                         #with package.mask and what not.
154                         raise NotImplentedError()
155
156         def _load_config(self):
157                 env = { "PORTDIR": self.portdir, "ROOT": self.root, "ACCEPT_KEYWORDS": "x86"}
158                 settings = config(config_root=self.root, target_root=self.root, local_config=False, env=env)
159                 settings.lock()
160
161                 trees = {
162                         self.root: {
163                                         "virtuals": settings.getvirtuals(),
164                                         "vartree": vartree(self.root, categories=settings.categories, settings=settings),
165                                         "porttree": portagetree(self.root, settings=settings),
166                                         "bintree": binarytree(self.root, os.path.join(self.root, "usr/portage/packages"), settings=settings)
167                                 }
168                         }
169
170                 for root, root_trees in trees.items():
171                         settings = root_trees["vartree"].settings
172                         settings._init_dirs()
173                         setconfig = load_default_config(settings, root_trees)
174                         root_trees["root_config"] = RootConfig(settings, root_trees, setconfig)
175                 
176                 return settings, trees
177
178         def run(self, myfiles, myopts={}, myaction=None):
179                 myopts["--pretend"] = True
180                 myopts["--quiet"] = True
181                 myopts["--root"] = self.root
182                 myopts["--config-root"] = self.root
183                 myopts["--root-deps"] = "rdeps"
184                 # Add a fake _test_ option that can be used for
185                 # conditional test code.
186                 myopts["_test_"] = True
187
188                 portage.util.noiselimit = -2
189                 myparams = create_depgraph_params(myopts, myaction)
190                 success, mydepgraph, favorites = backtrack_depgraph(
191                         self.settings, self.trees, myopts, myparams, myaction, myfiles, None)
192                 result = ResolverPlaygroundResult(success, mydepgraph, favorites)
193                 portage.util.noiselimit = 0
194
195                 return result
196
197         def cleanup(self):
198                 shutil.rmtree(self.root)
199
200 class ResolverPlaygroundResult(object):
201         def __init__(self, success, mydepgraph, favorites):
202                 self.success = success
203                 self.depgraph = mydepgraph
204                 self.favorites = favorites
205                 self.mergelist = None
206
207                 if self.depgraph._dynamic_config._serialized_tasks_cache is not None:
208                         self.mergelist = []
209                         for x in self.depgraph._dynamic_config._serialized_tasks_cache:
210                                 if isinstance(x, Blocker):
211                                         self.mergelist.append(x.atom)
212                                 else:
213                                         self.mergelist.append(x.cpv)