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