]>
git.saurik.com Git - apt.git/blob - apt-pkg/edsp.cc
8414c6a23058a17c6272fb07e99b2c6a86a6f43d
1 // -*- mode: cpp; mode: fold -*-
3 /* ######################################################################
4 Set of methods to help writing and reading everything needed for EDSP
5 ##################################################################### */
7 // Include Files /*{{{*/
10 #include <apt-pkg/error.h>
11 #include <apt-pkg/cacheset.h>
12 #include <apt-pkg/depcache.h>
13 #include <apt-pkg/pkgcache.h>
14 #include <apt-pkg/cacheiterators.h>
15 #include <apt-pkg/progress.h>
16 #include <apt-pkg/fileutl.h>
17 #include <apt-pkg/edsp.h>
18 #include <apt-pkg/tagfile.h>
19 #include <apt-pkg/strutl.h>
35 // we could use pkgCache::DepType and ::Priority, but these would be localized stringsā¦
36 const char * const PrioMap
[] = { 0 , "important" , "required" , "standard" ,
38 const char * const DepMap
[] = { "" , "Depends" , "Pre-Depends" , "Suggests" ,
39 "Recommends" , "Conflicts" , "Replaces" ,
40 "Obsoletes" , "Breaks" , "Enhances" };
43 // WriteScenarioVersion /*{{{*/
44 static void WriteScenarioVersion ( pkgDepCache
& Cache
, FILE * output
, pkgCache :: PkgIterator
const & Pkg
,
45 pkgCache :: VerIterator
const & Ver
)
47 fprintf ( output
, "Package: %s \n " , Pkg
. Name ());
48 fprintf ( output
, "Source: %s \n " , Ver
. SourcePkgName ());
49 fprintf ( output
, "Architecture: %s \n " , Ver
. Arch ());
50 fprintf ( output
, "Version: %s \n " , Ver
. VerStr ());
51 fprintf ( output
, "Source-Version: %s \n " , Ver
. SourceVerStr ());
52 if ( Pkg
. CurrentVer () == Ver
)
53 fprintf ( output
, "Installed: yes \n " );
54 if ( Pkg
-> SelectedState
== pkgCache :: State :: Hold
||
55 ( Cache
[ Pkg
]. Keep () == true && Cache
[ Pkg
]. Protect () == true ))
56 fprintf ( output
, "Hold: yes \n " );
57 fprintf ( output
, "APT-ID: %d \n " , Ver
-> ID
);
58 fprintf ( output
, "Priority: %s \n " , PrioMap
[ Ver
-> Priority
]);
59 if (( Pkg
-> Flags
& pkgCache :: Flag :: Essential
) == pkgCache :: Flag :: Essential
)
60 fprintf ( output
, "Essential: yes \n " );
61 fprintf ( output
, "Section: %s \n " , Ver
. Section ());
62 if (( Ver
-> MultiArch
& pkgCache :: Version :: Allowed
) == pkgCache :: Version :: Allowed
)
63 fprintf ( output
, "Multi-Arch: allowed \n " );
64 else if (( Ver
-> MultiArch
& pkgCache :: Version :: Foreign
) == pkgCache :: Version :: Foreign
)
65 fprintf ( output
, "Multi-Arch: foreign \n " );
66 else if (( Ver
-> MultiArch
& pkgCache :: Version :: Same
) == pkgCache :: Version :: Same
)
67 fprintf ( output
, "Multi-Arch: same \n " );
68 std :: set
< string
> Releases
;
69 for ( pkgCache :: VerFileIterator I
= Ver
. FileList (); I
. end () == false ; ++ I
) {
70 pkgCache :: PkgFileIterator File
= I
. File ();
71 if ( File
. Flagged ( pkgCache :: Flag :: NotSource
) == false ) {
72 string Release
= File
. RelStr ();
74 Releases
. insert ( Release
);
77 if (! Releases
. empty ()) {
78 fprintf ( output
, "APT-Release: \n " );
79 for ( std :: set
< string
>:: iterator R
= Releases
. begin (); R
!= Releases
. end (); ++ R
)
80 fprintf ( output
, " %s \n " , R
-> c_str ());
82 fprintf ( output
, "APT-Pin: %d \n " , Cache
. GetPolicy (). GetPriority ( Ver
));
83 if ( Cache
. GetCandidateVersion ( Pkg
) == Ver
)
84 fprintf ( output
, "APT-Candidate: yes \n " );
85 if (( Cache
[ Pkg
]. Flags
& pkgCache :: Flag :: Auto
) == pkgCache :: Flag :: Auto
)
86 fprintf ( output
, "APT-Automatic: yes \n " );
89 // WriteScenarioDependency /*{{{*/
90 static void WriteScenarioDependency ( FILE * output
, pkgCache :: VerIterator
const & Ver
)
92 std :: string dependencies
[ pkgCache :: Dep :: Enhances
+ 1 ];
94 for ( pkgCache :: DepIterator Dep
= Ver
. DependsList (); Dep
. end () == false ; ++ Dep
)
96 if ( Dep
. IsImplicit () == true )
99 dependencies
[ Dep
-> Type
]. append ( ", " );
100 dependencies
[ Dep
-> Type
]. append ( Dep
. TargetPkg (). Name ());
101 if ( Dep
-> Version
!= 0 )
102 dependencies
[ Dep
-> Type
]. append ( " (" ). append ( pkgCache :: CompTypeDeb ( Dep
-> CompareOp
)). append ( " " ). append ( Dep
. TargetVer ()). append ( ")" );
103 if (( Dep
-> CompareOp
& pkgCache :: Dep :: Or
) == pkgCache :: Dep :: Or
)
105 dependencies
[ Dep
-> Type
]. append ( " | " );
111 for ( int i
= 1 ; i
< pkgCache :: Dep :: Enhances
+ 1 ; ++ i
)
112 if ( dependencies
[ i
]. empty () == false )
113 fprintf ( output
, " %s : %s \n " , DepMap
[ i
], dependencies
[ i
]. c_str ()+ 2 );
115 for ( pkgCache :: PrvIterator Prv
= Ver
. ProvidesList (); Prv
. end () == false ; ++ Prv
)
117 if ( Prv
. IsMultiArchImplicit () == true )
119 provides
. append ( ", " ). append ( Prv
. Name ());
120 if ( Prv
-> ProvideVersion
!= 0 )
121 provides
. append ( " (= " ). append ( Prv
. ProvideVersion ()). append ( ")" );
123 if ( provides
. empty () == false )
124 fprintf ( output
, "Provides: %s \n " , provides
. c_str ()+ 2 );
127 // WriteScenarioLimitedDependency /*{{{*/
128 static void WriteScenarioLimitedDependency ( FILE * output
,
129 pkgCache :: VerIterator
const & Ver
,
130 APT :: PackageSet
const & pkgset
)
132 std :: string dependencies
[ pkgCache :: Dep :: Enhances
+ 1 ];
133 bool orGroup
= false ;
134 for ( pkgCache :: DepIterator Dep
= Ver
. DependsList (); Dep
. end () == false ; ++ Dep
)
136 if ( Dep
. IsImplicit () == true )
138 if ( orGroup
== false )
140 if ( pkgset
. find ( Dep
. TargetPkg ()) == pkgset
. end ())
142 dependencies
[ Dep
-> Type
]. append ( ", " );
144 else if ( pkgset
. find ( Dep
. TargetPkg ()) == pkgset
. end ())
146 if (( Dep
-> CompareOp
& pkgCache :: Dep :: Or
) == pkgCache :: Dep :: Or
)
148 dependencies
[ Dep
-> Type
]. erase ( dependencies
[ Dep
-> Type
]. end ()- 3 , dependencies
[ Dep
-> Type
]. end ());
152 dependencies
[ Dep
-> Type
]. append ( Dep
. TargetPkg (). Name ());
153 if ( Dep
-> Version
!= 0 )
154 dependencies
[ Dep
-> Type
]. append ( " (" ). append ( pkgCache :: CompTypeDeb ( Dep
-> CompareOp
)). append ( " " ). append ( Dep
. TargetVer ()). append ( ")" );
155 if (( Dep
-> CompareOp
& pkgCache :: Dep :: Or
) == pkgCache :: Dep :: Or
)
157 dependencies
[ Dep
-> Type
]. append ( " | " );
163 for ( int i
= 1 ; i
< pkgCache :: Dep :: Enhances
+ 1 ; ++ i
)
164 if ( dependencies
[ i
]. empty () == false )
165 fprintf ( output
, " %s : %s \n " , DepMap
[ i
], dependencies
[ i
]. c_str ()+ 2 );
167 for ( pkgCache :: PrvIterator Prv
= Ver
. ProvidesList (); Prv
. end () == false ; ++ Prv
)
169 if ( Prv
. IsMultiArchImplicit () == true )
171 if ( pkgset
. find ( Prv
. ParentPkg ()) == pkgset
. end ())
173 provides
. append ( ", " ). append ( Prv
. Name ());
175 if ( provides
. empty () == false )
176 fprintf ( output
, "Provides: %s \n " , provides
. c_str ()+ 2 );
179 static bool SkipUnavailableVersions ( pkgDepCache
& Cache
, pkgCache :: PkgIterator
const & Pkg
, pkgCache :: VerIterator
const & Ver
) /*{{{*/
181 /* versions which aren't current and aren't available in
182 any "online" source file are bad, expect if they are the choosen
183 candidate: The exception is for build-dep implementation as it creates
184 such pseudo (package) versions and removes them later on again.
185 We filter out versions at all so packages in 'rc' state only available
186 in dpkg/status aren't passed to solvers as they can't be installed. */
187 if ( Pkg
-> CurrentVer
!= 0 )
189 if ( Cache
. GetCandidateVersion ( Pkg
) == Ver
)
191 for ( pkgCache :: VerFileIterator I
= Ver
. FileList (); I
. end () == false ; ++ I
)
192 if ( I
. File (). Flagged ( pkgCache :: Flag :: NotSource
) == false )
197 // EDSP::WriteScenario - to the given file descriptor /*{{{*/
198 bool EDSP :: WriteScenario ( pkgDepCache
& Cache
, FILE * output
, OpProgress
* Progress
)
200 if ( Progress
!= NULL
)
201 Progress
-> SubProgress ( Cache
. Head (). VersionCount
, _ ( "Send scenario to solver" ));
203 std :: vector
< std :: string
> archs
= APT :: Configuration :: getArchitectures ();
204 for ( pkgCache :: PkgIterator Pkg
= Cache
. PkgBegin (); Pkg
. end () == false ; ++ Pkg
)
206 std :: string
const arch
= Pkg
. Arch ();
207 if ( std :: find ( archs
. begin (), archs
. end (), arch
) == archs
. end ())
209 for ( pkgCache :: VerIterator Ver
= Pkg
. VersionList (); Ver
. end () == false ; ++ Ver
, ++ p
)
211 if ( SkipUnavailableVersions ( Cache
, Pkg
, Ver
))
213 WriteScenarioVersion ( Cache
, output
, Pkg
, Ver
);
214 WriteScenarioDependency ( output
, Ver
);
215 fprintf ( output
, " \n " );
216 if ( Progress
!= NULL
&& p
% 100 == 0 )
217 Progress
-> Progress ( p
);
223 // EDSP::WriteLimitedScenario - to the given file descriptor /*{{{*/
224 bool EDSP :: WriteLimitedScenario ( pkgDepCache
& Cache
, FILE * output
,
225 APT :: PackageSet
const & pkgset
,
226 OpProgress
* Progress
)
228 if ( Progress
!= NULL
)
229 Progress
-> SubProgress ( Cache
. Head (). VersionCount
, _ ( "Send scenario to solver" ));
231 for ( APT :: PackageSet :: const_iterator Pkg
= pkgset
. begin (); Pkg
!= pkgset
. end (); ++ Pkg
, ++ p
)
232 for ( pkgCache :: VerIterator Ver
= Pkg
. VersionList (); Ver
. end () == false ; ++ Ver
)
234 if ( SkipUnavailableVersions ( Cache
, Pkg
, Ver
))
236 WriteScenarioVersion ( Cache
, output
, Pkg
, Ver
);
237 WriteScenarioLimitedDependency ( output
, Ver
, pkgset
);
238 fprintf ( output
, " \n " );
239 if ( Progress
!= NULL
&& p
% 100 == 0 )
240 Progress
-> Progress ( p
);
242 if ( Progress
!= NULL
)
247 // EDSP::WriteRequest - to the given file descriptor /*{{{*/
248 bool EDSP :: WriteRequest ( pkgDepCache
& Cache
, FILE * output
, bool const Upgrade
,
249 bool const DistUpgrade
, bool const AutoRemove
,
250 OpProgress
* Progress
)
252 if ( Progress
!= NULL
)
253 Progress
-> SubProgress ( Cache
. Head (). PackageCount
, _ ( "Send request to solver" ));
256 for ( pkgCache :: PkgIterator Pkg
= Cache
. PkgBegin (); Pkg
. end () == false ; ++ Pkg
, ++ p
)
258 if ( Progress
!= NULL
&& p
% 100 == 0 )
259 Progress
-> Progress ( p
);
261 pkgDepCache :: StateCache
& P
= Cache
[ Pkg
];
262 if ( P
. Delete () == true )
264 else if ( P
. NewInstall () == true || P
. Upgrade () == true || P
. ReInstall () == true ||
265 ( P
. Mode
== pkgDepCache :: ModeKeep
&& ( P
. iFlags
& pkgDepCache :: Protected
) == pkgDepCache :: Protected
))
269 req
-> append ( " " ). append ( Pkg
. FullName ());
271 fprintf ( output
, "Request: EDSP 0.5 \n " );
273 const char * arch
= _config
-> Find ( "APT::Architecture" ). c_str ();
274 std :: vector
< string
> archs
= APT :: Configuration :: getArchitectures ();
275 fprintf ( output
, "Architecture: %s \n " , arch
);
276 fprintf ( output
, "Architectures:" );
277 for ( std :: vector
< string
>:: const_iterator a
= archs
. begin (); a
!= archs
. end (); ++ a
)
278 fprintf ( output
, " %s " , a
-> c_str ());
279 fprintf ( output
, " \n " );
281 if ( del
. empty () == false )
282 fprintf ( output
, "Remove: %s \n " , del
. c_str ()+ 1 );
283 if ( inst
. empty () == false )
284 fprintf ( output
, "Install: %s \n " , inst
. c_str ()+ 1 );
286 fprintf ( output
, "Upgrade: yes \n " );
287 if ( DistUpgrade
== true )
288 fprintf ( output
, "Dist-Upgrade: yes \n " );
289 if ( AutoRemove
== true )
290 fprintf ( output
, "Autoremove: yes \n " );
291 auto const solver
= _config
-> Find ( "APT::Solver" , "internal" );
292 fprintf ( output
, "Solver: %s \n " , solver
. c_str ());
293 auto const solverconf
= std :: string ( "APT::Solver::" ) + solver
+ "::" ;
294 if ( _config
-> FindB ( solverconf
+ "Strict-Pinning" , _config
-> FindB ( "APT::Solver::Strict-Pinning" , true )) == false )
295 fprintf ( output
, "Strict-Pinning: no \n " );
296 auto const solverpref
= _config
-> Find ( solverconf
+ "Preferences" , _config
-> Find ( "APT::Solver::Preferences" , "" ));
297 if ( solverpref
. empty () == false )
298 fprintf ( output
, "Preferences: %s \n " , solverpref
. c_str ());
299 fprintf ( output
, " \n " );
303 // EDSP::ReadResponse - from the given file descriptor /*{{{*/
304 bool EDSP :: ReadResponse ( int const input
, pkgDepCache
& Cache
, OpProgress
* Progress
) {
305 /* We build an map id to mmap offset here
306 In theory we could use the offset as ID, but then VersionCount
307 couldn't be used to create other versionmappings anymore and it
308 would be too easy for a (buggy) solver to segfault APTā¦ */
309 unsigned long long const VersionCount
= Cache
. Head (). VersionCount
;
310 unsigned long VerIdx
[ VersionCount
];
311 for ( pkgCache :: PkgIterator P
= Cache
. PkgBegin (); P
. end () == false ; ++ P
) {
312 for ( pkgCache :: VerIterator V
= P
. VersionList (); V
. end () == false ; ++ V
)
313 VerIdx
[ V
-> ID
] = V
. Index ();
314 Cache
[ P
]. Marked
= true ;
315 Cache
[ P
]. Garbage
= false ;
319 in
. OpenDescriptor ( input
, FileFd :: ReadOnly
);
320 pkgTagFile
response (& in
, 100 );
321 pkgTagSection section
;
323 std :: set
< decltype ( Cache
. PkgBegin ()-> ID
)> seenOnce
;
324 while ( response
. Step ( section
) == true ) {
326 if ( section
. Exists ( "Install" ) == true )
328 else if ( section
. Exists ( "Remove" ) == true )
330 else if ( section
. Exists ( "Progress" ) == true ) {
331 if ( Progress
!= NULL
) {
332 string msg
= section
. FindS ( "Message" );
333 if ( msg
. empty () == true )
334 msg
= _ ( "Prepare for receiving solution" );
335 Progress
-> SubProgress ( 100 , msg
, section
. FindI ( "Percentage" , 0 ));
338 } else if ( section
. Exists ( "Error" ) == true ) {
339 std :: string msg
= SubstVar ( SubstVar ( section
. FindS ( "Message" ), " \n . \n " , " \n\n " ), " \n " , " \n " );
340 if ( msg
. empty () == true ) {
341 msg
= _ ( "External solver failed without a proper error message" );
342 _error
-> Error ( " %s " , msg
. c_str ());
344 _error
-> Error ( "External solver failed with: %s " , msg
. substr ( 0 , msg
. find ( ' \n ' )). c_str ());
345 if ( Progress
!= NULL
)
347 std :: cerr
<< "The solver encountered an error of type: " << section
. FindS ( "Error" ) << std :: endl
;
348 std :: cerr
<< "The following information might help you to understand what is wrong:" << std :: endl
;
349 std :: cerr
<< msg
<< std :: endl
<< std :: endl
;
351 } else if ( section
. Exists ( "Autoremove" ) == true )
356 size_t const id
= section
. FindULL ( type
. c_str (), VersionCount
);
357 if ( id
== VersionCount
) {
358 _error
-> Warning ( "Unable to parse %s request with id value ' %s '!" , type
. c_str (), section
. FindS ( type
. c_str ()). c_str ());
360 } else if ( id
> Cache
. Head (). VersionCount
) {
361 _error
-> Warning ( "ID value ' %s ' in %s request stanza is to high to refer to a known version!" , section
. FindS ( type
. c_str ()). c_str (), type
. c_str ());
365 pkgCache :: VerIterator
Ver ( Cache
. GetCache (), Cache
. GetCache (). VerP
+ VerIdx
[ id
]);
366 auto const Pkg
= Ver
. ParentPkg ();
367 if ( type
== "Autoremove" ) {
368 Cache
[ Pkg
]. Marked
= false ;
369 Cache
[ Pkg
]. Garbage
= true ;
370 } else if ( seenOnce
. emplace ( Pkg
-> ID
). second
== false ) {
371 _error
-> Warning ( "Ignoring %s stanza received for package %s which already had a previous stanza effecting it!" , type
. c_str (), Pkg
. FullName ( false ). c_str ());
372 } else if ( type
== "Install" ) {
373 if ( Pkg
. CurrentVer () == Ver
) {
374 _error
-> Warning ( "Ignoring Install stanza received for version %s of package %s which is already installed!" ,
375 Ver
. VerStr (), Pkg
. FullName ( false ). c_str ());
377 Cache
. SetCandidateVersion ( Ver
);
378 Cache
. MarkInstall ( Pkg
, false , 0 , false );
380 } else if ( type
== "Remove" ) {
381 if ( Pkg
-> CurrentVer
== 0 )
382 _error
-> Warning ( "Ignoring Remove stanza received for version %s of package %s which isn't installed!" ,
383 Ver
. VerStr (), Pkg
. FullName ( false ). c_str ());
384 else if ( Pkg
. CurrentVer () != Ver
)
385 _error
-> Warning ( "Ignoring Remove stanza received for version %s of package %s which isn't the installed version %s !" ,
386 Ver
. VerStr (), Pkg
. FullName ( false ). c_str (), Pkg
. CurrentVer (). VerStr ());
388 Cache
. MarkDelete ( Ver
. ParentPkg (), false );
394 // ReadLine - first line from the given file descriptor /*{{{*/
395 // ---------------------------------------------------------------------
396 /* Little helper method to read a complete line into a string. Similar to
397 fgets but we need to use the low-level read() here as otherwise the
398 listparser will be confused later on as mixing of fgets and read isn't
399 a supported action according to the manpages and results are undefined */
400 static bool ReadLine ( int const input
, std :: string
& line
) {
405 while (( data
= read ( input
, & one
, sizeof ( one
))) != - 1 ) {
412 if ( line
. empty () == true && isblank ( one
) != 0 )
419 // StringToBool - convert yes/no to bool /*{{{*/
420 // ---------------------------------------------------------------------
421 /* we are not as lazy as we are in the global StringToBool as we really
422 only accept yes/no here - but we will ignore leading spaces */
423 static bool StringToBool ( char const * answer
, bool const defValue
) {
424 for (; isspace (* answer
) != 0 ; ++ answer
);
425 if ( strncasecmp ( answer
, "yes" , 3 ) == 0 )
427 else if ( strncasecmp ( answer
, "no" , 2 ) == 0 )
430 _error
-> Warning ( "Value ' %s ' is not a boolean 'yes' or 'no'!" , answer
);
434 // EDSP::ReadRequest - first stanza from the given file descriptor /*{{{*/
435 bool EDSP :: ReadRequest ( int const input
, std :: list
< std :: string
> & install
,
436 std :: list
< std :: string
> & remove
, bool & upgrade
,
437 bool & distUpgrade
, bool & autoRemove
)
445 while ( ReadLine ( input
, line
) == true )
447 // Skip empty lines before request
448 if ( line
. empty () == true )
450 // The first Tag must be a request, so search for it
451 if ( line
. compare ( 0 , 8 , "Request:" ) != 0 )
454 while ( ReadLine ( input
, line
) == true )
456 // empty lines are the end of the request
457 if ( line
. empty () == true )
460 std :: list
< std :: string
> * request
= NULL
;
461 if ( line
. compare ( 0 , 8 , "Install:" ) == 0 )
466 else if ( line
. compare ( 0 , 7 , "Remove:" ) == 0 )
471 else if ( line
. compare ( 0 , 8 , "Upgrade:" ) == 0 )
472 upgrade
= StringToBool ( line
. c_str () + 9 , false );
473 else if ( line
. compare ( 0 , 13 , "Dist-Upgrade:" ) == 0 )
474 distUpgrade
= StringToBool ( line
. c_str () + 14 , false );
475 else if ( line
. compare ( 0 , 11 , "Autoremove:" ) == 0 )
476 autoRemove
= StringToBool ( line
. c_str () + 12 , false );
477 else if ( line
. compare ( 0 , 13 , "Architecture:" ) == 0 )
478 _config
-> Set ( "APT::Architecture" , line
. c_str () + 14 );
479 else if ( line
. compare ( 0 , 14 , "Architectures:" ) == 0 )
481 std :: string
const archs
= line
. c_str () + 15 ;
482 _config
-> Set ( "APT::Architectures" , SubstVar ( archs
, " " , "," ));
484 else if ( line
. compare ( 0 , 7 , "Solver:" ) == 0 )
485 ; // purely informational line
487 _error
-> Warning ( "Unknown line in EDSP Request stanza: %s " , line
. c_str ());
491 size_t end
= line
. length ();
493 size_t begin
= line
. rfind ( ' ' );
494 if ( begin
== std :: string :: npos
)
496 request
-> push_back ( line
. substr ( 0 , end
));
499 else if ( begin
< end
)
500 request
-> push_back ( line
. substr ( begin
+ 1 , end
));
502 end
= line
. find_last_not_of ( ' ' );
503 } while ( end
!= std :: string :: npos
);
509 // EDSP::ApplyRequest - first stanza from the given file descriptor /*{{{*/
510 bool EDSP :: ApplyRequest ( std :: list
< std :: string
> const & install
,
511 std :: list
< std :: string
> const & remove
,
514 for ( std :: list
< std :: string
>:: const_iterator i
= install
. begin ();
515 i
!= install
. end (); ++ i
) {
516 pkgCache :: PkgIterator P
= Cache
. FindPkg (* i
);
518 _error
-> Warning ( "Package %s is not known, so can't be installed" , i
-> c_str ());
520 Cache
. MarkInstall ( P
, false );
523 for ( std :: list
< std :: string
>:: const_iterator i
= remove
. begin ();
524 i
!= remove
. end (); ++ i
) {
525 pkgCache :: PkgIterator P
= Cache
. FindPkg (* i
);
527 _error
-> Warning ( "Package %s is not known, so can't be installed" , i
-> c_str ());
534 // EDSP::WriteSolution - to the given file descriptor /*{{{*/
535 bool EDSP :: WriteSolution ( pkgDepCache
& Cache
, FILE * output
)
537 bool const Debug
= _config
-> FindB ( "Debug::EDSP::WriteSolution" , false );
538 for ( pkgCache :: PkgIterator Pkg
= Cache
. PkgBegin (); Pkg
. end () == false ; ++ Pkg
)
540 if ( Cache
[ Pkg
]. Delete () == true )
542 fprintf ( output
, "Remove: %d \n " , Pkg
. CurrentVer ()-> ID
);
544 fprintf ( output
, "Package: %s \n Version: %s \n " , Pkg
. FullName (). c_str (), Pkg
. CurrentVer (). VerStr ());
546 else if ( Cache
[ Pkg
]. NewInstall () == true || Cache
[ Pkg
]. Upgrade () == true )
548 pkgCache :: VerIterator
const CandVer
= Cache
. GetCandidateVersion ( Pkg
);
549 fprintf ( output
, "Install: %d \n " , CandVer
-> ID
);
551 fprintf ( output
, "Package: %s \n Version: %s \n " , Pkg
. FullName (). c_str (), CandVer
. VerStr ());
553 else if ( Cache
[ Pkg
]. Garbage
== true )
555 fprintf ( output
, "Autoremove: %d \n " , Pkg
. CurrentVer ()-> ID
);
557 fprintf ( output
, "Package: %s \n Version: %s \n " , Pkg
. FullName (). c_str (), Pkg
. CurrentVer (). VerStr ());
561 fprintf ( output
, " \n " );
567 // EDSP::WriteProgess - pulse to the given file descriptor /*{{{*/
568 bool EDSP :: WriteProgress ( unsigned short const percent
, const char * const message
, FILE * output
) {
569 fprintf ( output
, "Progress: %s \n " , TimeRFC1123 ( time ( NULL
)). c_str ());
570 fprintf ( output
, "Percentage: %d \n " , percent
);
571 fprintf ( output
, "Message: %s \n\n " , message
);
576 // EDSP::WriteError - format an error message to be send to file descriptor /*{{{*/
577 bool EDSP :: WriteError ( char const * const uuid
, std :: string
const & message
, FILE * output
) {
578 fprintf ( output
, "Error: %s \n " , uuid
);
579 fprintf ( output
, "Message: %s \n\n " , SubstVar ( SubstVar ( message
, " \n\n " , " \n . \n " ), " \n " , " \n " ). c_str ());
583 // EDSP::ExecuteSolver - fork requested solver and setup ipc pipes {{{*/
584 pid_t
EDSP :: ExecuteSolver ( const char * const solver
, int * const solver_in
, int * const solver_out
, bool ) {
585 std :: vector
< std :: string
> const solverDirs
= _config
-> FindVector ( "Dir::Bin::Solvers" );
587 for ( std :: vector
< std :: string
>:: const_iterator dir
= solverDirs
. begin ();
588 dir
!= solverDirs
. end (); ++ dir
) {
589 file
= flCombine (* dir
, solver
);
590 if ( RealFileExists ( file
. c_str ()) == true )
595 if ( file
. empty () == true )
597 _error
-> Error ( "Can't call external solver ' %s ' as it is not in a configured directory!" , solver
);
600 int external
[ 4 ] = {- 1 , - 1 , - 1 , - 1 };
601 if ( pipe ( external
) != 0 || pipe ( external
+ 2 ) != 0 )
603 _error
-> Errno ( "Resolve" , "Can't create needed IPC pipes for EDSP" );
606 for ( int i
= 0 ; i
< 4 ; ++ i
)
607 SetCloseExec ( external
[ i
], true );
609 pid_t Solver
= ExecFork ();
611 dup2 ( external
[ 0 ], STDIN_FILENO
);
612 dup2 ( external
[ 3 ], STDOUT_FILENO
);
613 const char * calling
[ 2 ] = { file
. c_str (), 0 };
614 execv ( calling
[ 0 ], ( char **) calling
);
615 std :: cerr
<< "Failed to execute solver '" << solver
<< "'!" << std :: endl
;
621 if ( WaitFd ( external
[ 1 ], true , 5 ) == false )
623 _error
-> Errno ( "Resolve" , "Timed out while Waiting on availability of solver stdin" );
627 * solver_in
= external
[ 1 ];
628 * solver_out
= external
[ 2 ];
631 bool EDSP :: ExecuteSolver ( const char * const solver
, int * solver_in
, int * solver_out
) {
632 if ( ExecuteSolver ( solver
, solver_in
, solver_out
, true ) == 0 )
637 // EDSP::ResolveExternal - resolve problems by asking external for help {{{*/
638 bool EDSP :: ResolveExternal ( const char * const solver
, pkgDepCache
& Cache
,
639 bool const upgrade
, bool const distUpgrade
,
640 bool const autoRemove
, OpProgress
* Progress
) {
641 int solver_in
, solver_out
;
642 pid_t
const solver_pid
= EDSP :: ExecuteSolver ( solver
, & solver_in
, & solver_out
, true );
646 FILE * output
= fdopen ( solver_in
, "w" );
648 return _error
-> Errno ( "Resolve" , "fdopen on solver stdin failed" );
650 if ( Progress
!= NULL
)
651 Progress
-> OverallProgress ( 0 , 100 , 5 , _ ( "Execute external solver" ));
652 EDSP :: WriteRequest ( Cache
, output
, upgrade
, distUpgrade
, autoRemove
, Progress
);
653 if ( Progress
!= NULL
)
654 Progress
-> OverallProgress ( 5 , 100 , 20 , _ ( "Execute external solver" ));
655 EDSP :: WriteScenario ( Cache
, output
, Progress
);
658 if ( Progress
!= NULL
)
659 Progress
-> OverallProgress ( 25 , 100 , 75 , _ ( "Execute external solver" ));
660 if ( EDSP :: ReadResponse ( solver_out
, Cache
, Progress
) == false )
663 return ExecWait ( solver_pid
, solver
);