- added kind of capabilities
[platform/upstream/libzypp.git] / zypp / solver / detail / Testcase.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/solver/detail/Testcase.cc
10  *
11 */
12 #include <iostream>
13 #include <fstream>
14 #include <sstream>
15 #include <streambuf>
16
17 #include "zypp/solver/detail/Testcase.h"
18 #include "zypp/base/Logger.h"
19 #include "zypp/base/LogControl.h"
20 #include "zypp/PathInfo.h"
21 #include "zypp/Product.h"
22 #include "zypp/Package.h"
23 #include "zypp/Edition.h"
24 #include "zypp/target/store/xml_escape_parser.hpp"
25 #include "zypp/capability/VersionedCap.h"
26 #include "zypp/base/String.h"
27 #include "zypp/base/PtrTypes.h"
28
29
30 /////////////////////////////////////////////////////////////////////////
31 namespace zypp
32 { ///////////////////////////////////////////////////////////////////////
33   ///////////////////////////////////////////////////////////////////////
34   namespace solver
35   { /////////////////////////////////////////////////////////////////////
36     /////////////////////////////////////////////////////////////////////
37     namespace detail
38     { ///////////////////////////////////////////////////////////////////
39         
40 #define TAB "\t"
41 #define TAB2 "\t\t"
42         
43 using namespace std;
44 using namespace zypp::capability;
45 using namespace zypp::str;
46
47 IMPL_PTR_TYPE(HelixResolvable); 
48
49 static std::string xml_escape( const std::string &text )
50 {
51   iobind::parser::xml_escape_parser parser;
52   return parser.escape(text);
53 }
54
55 static std::string xml_tag_enclose( const std::string &text, const std::string &tag, bool escape = false )
56 {
57   string result;
58   result += "<" + tag + ">";
59
60   if ( escape)
61    result += xml_escape(text);
62   else
63    result += text;
64
65   result += "</" + tag + ">";
66   return result;
67 }
68
69         
70 template<class T>
71 std::string helixXML( const T &obj ); //undefined
72
73 template<> 
74 std::string helixXML( const Edition &edition )
75 {
76     stringstream str;
77     str << xml_tag_enclose(edition.version(), "version");
78     if (!edition.release().empty())
79         str << xml_tag_enclose(edition.release(), "release");
80     if (edition.epoch() != Edition::noepoch)
81         str << xml_tag_enclose(numstring(edition.epoch()), "epoch");    
82     return str.str();
83 }
84
85 template<> 
86 std::string helixXML( const Arch &arch )
87 {
88     stringstream str;
89     str << xml_tag_enclose(arch.asString(), "arch");        
90     return str.str();    
91 }
92
93 template<> 
94 std::string helixXML( const Capability &cap )
95 {
96     stringstream str;
97     if (isKind<VersionedCap>(cap)
98         && cap.op() != Rel::NONE
99         && cap.op() != Rel::ANY
100         && !cap.edition().version().empty()) {
101         // version capability
102         str << "<dep name='" << xml_escape(cap.index()) << "' op='" << xml_escape(cap.op().asString()) <<
103             "' version='" << cap.edition().version() << "'";
104         if (!cap.edition().release().empty())
105             str << " release='" << cap.edition().release() << "'";
106         if (cap.edition().epoch() != Edition::noepoch)
107             str << " epoch='" << numstring(cap.edition().epoch()) << "'";
108     } else {
109         // anything else
110         str << "<dep name='" << xml_escape(cap.asString()) << "'";
111     }
112     str << " kind=\"" << toLower (cap.refers().asString()) << "\""
113         << " />" << endl;
114         
115     return str.str();    
116 }
117
118 template<> 
119 std::string helixXML( const CapSet &caps )
120 {
121     stringstream str;
122     CapSet::iterator it = caps.begin();
123     str << endl;
124     for ( ; it != caps.end(); ++it)
125     {
126         str << TAB2 << helixXML((*it));
127     }
128     str << TAB;
129     return str.str();
130 }
131
132 template<> 
133 std::string helixXML( const Dependencies &dep )
134 {
135     stringstream str;
136     if ( dep[Dep::PROVIDES].size() > 0 )
137         str << TAB << xml_tag_enclose(helixXML(dep[Dep::PROVIDES]), "provides") << endl;
138     if ( dep[Dep::CONFLICTS].size() > 0 )
139         str << TAB << xml_tag_enclose(helixXML(dep[Dep::CONFLICTS]), "conflicts") << endl;
140     if ( dep[Dep::OBSOLETES].size() > 0 )
141         str << TAB << xml_tag_enclose(helixXML(dep[Dep::OBSOLETES]), "obsoletes") << endl;
142     if ( dep[Dep::FRESHENS].size() > 0 )
143         str << TAB << xml_tag_enclose(helixXML(dep[Dep::FRESHENS]), "freshens") << endl;
144     if ( dep[Dep::REQUIRES].size() > 0 )
145         str << TAB << xml_tag_enclose(helixXML(dep[Dep::REQUIRES]), "requires") << endl;  
146     if ( dep[Dep::RECOMMENDS].size() > 0 )
147         str << TAB << xml_tag_enclose(helixXML(dep[Dep::RECOMMENDS]), "recommends") << endl;
148     if ( dep[Dep::ENHANCES].size() > 0 )
149         str << TAB << xml_tag_enclose(helixXML(dep[Dep::ENHANCES]), "enhances") << endl;
150     if ( dep[Dep::SUPPLEMENTS].size() > 0 )
151         str << TAB << xml_tag_enclose(helixXML(dep[Dep::SUPPLEMENTS]), "supplements") << endl;
152     if ( dep[Dep::SUGGESTS].size() > 0 )
153         str << TAB << xml_tag_enclose(helixXML(dep[Dep::SUGGESTS]), "suggests") << endl;
154     return str.str();    
155 }
156
157 std::string helixXML( const Resolvable::constPtr &resolvable )
158 {
159   stringstream str;
160   str << "<" << toLower (resolvable->kind().asString()) << ">" << endl;
161   str << TAB << xml_tag_enclose (resolvable->name(), "name", true) << endl;  
162   if ( isKind<Package>(resolvable) ) {
163       str << TAB << "<history>" << endl << TAB << "<update>" << endl;
164       str << TAB2 << helixXML (resolvable->arch()) << endl;
165       str << TAB2 << helixXML (resolvable->edition()) << endl;      
166       str << TAB << "</update>" << endl << TAB << "</history>" << endl;
167   } else {
168       str << TAB << helixXML (resolvable->arch()) << endl;      
169       str << TAB << helixXML (resolvable->edition()) << endl;            
170   }
171   str << helixXML (resolvable->deps());              
172
173   str << "</" << toLower (resolvable->kind().asString()) << ">" << endl;  
174   return str.str();
175 }
176
177 //---------------------------------------------------------------------------
178
179 Testcase::Testcase()
180     :dumpPath("/var/log/YaST2/solverTestcase")    
181 {
182 }
183
184 Testcase::Testcase(const std::string & path)
185     :dumpPath(path)
186 {
187 }
188         
189
190 Testcase::~Testcase()
191 {
192 }
193
194 bool Testcase::createTestcase(Resolver & resolver)
195 {
196     PathInfo path (dumpPath);
197
198     if ( !path.isExist() ) {
199         if (zypp::filesystem::mkdir (dumpPath)!=0) {
200             ERR << "Cannot create directory " << dumpPath << endl;
201             return false;
202         }
203     } else {
204         if (!path.isDir()) {
205             ERR << dumpPath << " is not a directory." << endl;
206             return false;
207         }
208         // remove old stuff
209         zypp::filesystem::clean_dir (dumpPath);
210     }
211     
212     zypp::base::LogControl::instance().logfile( dumpPath +"/y2log" );
213     zypp::base::LogControl::TmpExcessive excessive;
214     
215     resolver.resolvePool();
216
217     zypp::base::LogControl::instance().logfile( "/var/log/YaST2/y2log" );    
218
219     ResPool pool        = resolver.pool();
220     SourceTable         sourceTable;
221     PoolItemList        items_to_install;
222     PoolItemList        items_to_remove;    
223     HelixResolvable     system (dumpPath + "/solver-system.xml");    
224
225     for ( ResPool::const_iterator it = pool.begin(); it != pool.end(); ++it )
226     {
227         Resolvable::constPtr res = it->resolvable();
228         
229         if ( it->status().isInstalled() ) {
230             // system channel
231             system.addResolvable (res);
232         } else {
233             // source channels
234             ResObject::constPtr sourceItem = it->resolvable();
235             Source_Ref source  = sourceItem->source();
236             if (sourceTable.find (source) == sourceTable.end()) {
237                 sourceTable[source] = new HelixResolvable(dumpPath + "/"
238                                                           + numstring(source.numericId())
239                                                           + "-package.xml");
240             }
241             sourceTable[source]->addResolvable (res);
242         }
243         
244         if ( it->status().isToBeInstalled()
245              && !(it->status().isBySolver())) {
246             items_to_install.push_back (*it);
247         }
248         if ( it->status().isToBeUninstalled()
249              && !(it->status().isBySolver())) {
250             items_to_remove.push_back (*it);
251         }
252     }
253
254     // writing control file "*-test.xml"
255
256     HelixControl control (dumpPath + "/solver-test.xml",
257                           sourceTable,
258                           resolver.architecture());
259
260     for (PoolItemList::const_iterator iter = items_to_install.begin(); iter != items_to_install.end(); iter++) {
261         control.installResolvable (iter->resolvable()); 
262     }
263
264     for (PoolItemList::const_iterator iter = items_to_remove.begin(); iter != items_to_remove.end(); iter++) {
265         control.deleteResolvable (iter->resolvable());  
266     }
267
268     return true;
269 }
270
271 //---------------------------------------------------------------------------
272
273 HelixResolvable::HelixResolvable(const std::string & path)
274     :dumpFile (path)    
275 {
276     file = new ofstream(path.c_str());
277     if (!file) {
278         ZYPP_THROW (Exception( "Can't open " + path ) );
279     }
280
281     *file << "<channel><subchannel>" << endl;
282 }
283
284 HelixResolvable::~HelixResolvable()
285 {
286     *file << "</subchannel></channel>" << endl;
287 }
288     
289
290 void HelixResolvable::addResolvable(const Resolvable::constPtr &resolvable)
291 {
292     *file << helixXML (resolvable);
293 }
294
295 //---------------------------------------------------------------------------
296
297 HelixControl::HelixControl(const std::string & controlPath,
298                            const SourceTable & sourceTable,
299                            const Arch & systemArchitecture,                        
300                            const std::string & systemPath)
301     :dumpFile (controlPath) 
302 {
303     file = new ofstream(controlPath.c_str());
304     if (!file) {
305         ZYPP_THROW (Exception( "Can't open " + controlPath ) );
306     }
307
308     *file << "<?xml version=\"1.0\"?>" << endl
309           << "<!-- testcase generated by YaST -->" << endl
310           << "<test>" << endl
311           << "<setup arch=\"" << systemArchitecture << "\">" << endl
312           << TAB << "<system file=\"" << systemPath << "\"/>" << endl;
313     for ( SourceTable::const_iterator it = sourceTable.begin();
314           it != sourceTable.end(); ++it ) {
315         Source_Ref source = it->first;
316         *file << TAB << "<channel file=\"" << numstring(source.numericId())
317               << "-package.xml\" name=\"" << numstring(source.numericId())
318               << "\" />" << endl;
319     }
320     *file << "</setup>" << endl
321           << "<trial>" << endl
322           << "<showpool all=\"yes\"/>" << endl
323           << "<establish/>" << endl
324           << "<showpool all=\"true\" prefix=\">!> ESTABLISHED:\"/>" << endl;
325 }
326
327 HelixControl::HelixControl()
328     :dumpFile ("/var/log/YaST2/solverTestcase/solver-test.xml")
329 {
330     HelixControl (dumpFile);
331 }
332
333 HelixControl::~HelixControl()
334 {
335     *file << "</trial>" << endl
336           << "</test>" << endl;
337 }
338
339 void HelixControl::installResolvable(const ResObject::constPtr &resObject)
340 {
341     Source_Ref source  = resObject->source();
342     *file << "<install channel=\"" << numstring(source.numericId()) << "\" kind=\"" << toLower (resObject->kind().asString()) << "\""
343           << " name=\"" << resObject->name() << "\"" << "/>" << endl;
344 }
345     
346 void HelixControl::deleteResolvable(const ResObject::constPtr &resObject)
347 {
348     Source_Ref source  = resObject->source();    
349     *file << "<uninstall " << " kind=\"" << toLower (resObject->kind().asString()) << "\""
350           << " name=\"" << resObject->name() << "\"" << "/>" << endl;    
351 }
352
353
354       ///////////////////////////////////////////////////////////////////
355     };// namespace detail
356     /////////////////////////////////////////////////////////////////////
357     /////////////////////////////////////////////////////////////////////
358   };// namespace solver
359   ///////////////////////////////////////////////////////////////////////
360   ///////////////////////////////////////////////////////////////////////
361 };// namespace zypp
362 /////////////////////////////////////////////////////////////////////////