]> git.saurik.com Git - apt.git/blob - cmdline/apt-internal-planner.cc
CMake: Add unit tests
[apt.git] / cmdline / apt-internal-planner.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 /* #####################################################################
4
5 cover around the internal solver to be able to run it like an external
6
7 ##################################################################### */
8 /*}}}*/
9 // Include Files /*{{{*/
10 #include <config.h>
11
12 #include <apt-pkg/error.h>
13 #include <apt-pkg/cmndline.h>
14 #include <apt-pkg/init.h>
15 #include <apt-pkg/cachefile.h>
16 #include <apt-pkg/cacheset.h>
17 #include <apt-pkg/strutl.h>
18 #include <apt-pkg/edsp.h>
19 #include <apt-pkg/fileutl.h>
20 #include <apt-pkg/pkgsystem.h>
21 #include <apt-pkg/configuration.h>
22 #include <apt-pkg/packagemanager.h>
23 #include <apt-pkg/prettyprinters.h>
24 #include <apt-pkg/depcache.h>
25 #include <apt-pkg/pkgcache.h>
26 #include <apt-pkg/cacheiterators.h>
27
28 #include <apt-private/private-output.h>
29 #include <apt-private/private-cmndline.h>
30 #include <apt-private/private-main.h>
31
32 #include <string.h>
33 #include <iostream>
34 #include <sstream>
35 #include <list>
36 #include <string>
37 #include <unistd.h>
38 #include <cstdio>
39 #include <stdlib.h>
40
41 #include <apti18n.h>
42 /*}}}*/
43
44 static bool ShowHelp(CommandLine &) /*{{{*/
45 {
46 std::cout <<
47 _("Usage: apt-internal-planner\n"
48 "\n"
49 "apt-internal-planner is an interface to use the current internal\n"
50 "installation planner for the APT family like an external one,\n"
51 "for debugging or the like.\n");
52 return true;
53 }
54 /*}}}*/
55 APT_NORETURN static void DIE(std::string const &message) { /*{{{*/
56 std::cerr << "ERROR: " << message << std::endl;
57 _error->DumpErrors(std::cerr);
58 exit(EXIT_FAILURE);
59 }
60 /*}}}*/
61 static std::vector<aptDispatchWithHelp> GetCommands() /*{{{*/
62 {
63 return {};
64 }
65 /*}}}*/
66 class PMOutput: public pkgPackageManager /*{{{*/
67 {
68 FileFd &output;
69 bool const Debug;
70
71 protected:
72 virtual bool Install(PkgIterator Pkg,std::string) APT_OVERRIDE
73 {
74 //std::cerr << "INSTALL: " << APT::PrettyPkg(&Cache, Pkg) << std::endl;
75 return EDSP::WriteSolutionStanza(output, "Unpack", Cache[Pkg].InstVerIter(Cache));
76 }
77 virtual bool Configure(PkgIterator Pkg) APT_OVERRIDE
78 {
79 //std::cerr << "CONFIGURE: " << APT::PrettyPkg(&Cache, Pkg) << " " << std::endl;
80 return EDSP::WriteSolutionStanza(output, "Configure", Cache[Pkg].InstVerIter(Cache));
81 }
82 virtual bool Remove(PkgIterator Pkg,bool) APT_OVERRIDE
83 {
84 //std::cerr << "REMOVE: " << APT::PrettyPkg(&Cache, Pkg) << " " << std::endl;
85 return EDSP::WriteSolutionStanza(output, "Remove", Pkg.CurrentVer());
86 }
87 public:
88 PMOutput(pkgDepCache *Cache, FileFd &file) : pkgPackageManager(Cache), output(file),
89 Debug(_config->FindB("Debug::EDSP::WriteSolution", false))
90 {}
91
92 bool ApplyRequest(std::list<std::pair<std::string,EIPP::PKG_ACTION>> const &actions)
93 {
94 for (auto && a: actions)
95 {
96 auto const Pkg = Cache.FindPkg(a.first);
97 if (unlikely(Pkg.end() == true))
98 continue;
99 switch (a.second)
100 {
101 case EIPP::PKG_ACTION::NOOP:
102 break;
103 case EIPP::PKG_ACTION::INSTALL:
104 case EIPP::PKG_ACTION::REINSTALL:
105 FileNames[Pkg->ID] = "EIPP";
106 break;
107 case EIPP::PKG_ACTION::REMOVE:
108 break;
109 }
110 }
111 return true;
112 }
113 };
114 /*}}}*/
115 int main(int argc,const char *argv[]) /*{{{*/
116 {
117 // we really don't need anything
118 DropPrivileges();
119
120 CommandLine CmdL;
121 ParseCommandLine(CmdL, APT_CMD::APT_INTERNAL_PLANNER, &_config, NULL, argc, argv, &ShowHelp, &GetCommands);
122
123 // Deal with stdout not being a tty
124 if (!isatty(STDOUT_FILENO) && _config->FindI("quiet", -1) == -1)
125 _config->Set("quiet","1");
126
127 if (_config->FindI("quiet", 0) < 1)
128 _config->Set("Debug::EIPP::WriteSolution", true);
129
130 _config->Set("APT::System", "Debian APT planner interface");
131 _config->Set("APT::Planner", "internal");
132 _config->Set("eipp::scenario", "/nonexistent/stdin");
133 FileFd output;
134 if (output.OpenDescriptor(STDOUT_FILENO, FileFd::WriteOnly | FileFd::BufferedWrite, true) == false)
135 DIE("stdout couldn't be opened");
136 int const input = STDIN_FILENO;
137 SetNonBlock(input, false);
138
139 EDSP::WriteProgress(0, "Start up planner…", output);
140
141 if (pkgInitSystem(*_config,_system) == false)
142 DIE("System could not be initialized!");
143
144 EDSP::WriteProgress(1, "Read request…", output);
145
146 if (WaitFd(input, false, 5) == false)
147 DIE("WAIT timed out in the planner");
148
149 std::list<std::pair<std::string,EIPP::PKG_ACTION>> actions;
150 unsigned int flags;
151 if (EIPP::ReadRequest(input, actions, flags) == false)
152 DIE("Parsing the request failed!");
153 _config->Set("APT::Immediate-Configure", (flags & EIPP::Request::NO_IMMEDIATE_CONFIGURATION) == 0);
154 _config->Set("APT::Immediate-Configure-All", (flags & EIPP::Request::IMMEDIATE_CONFIGURATION_ALL) != 0);
155 _config->Set("APT::Force-LoopBreak", (flags & EIPP::Request::ALLOW_TEMPORARY_REMOVE_OF_ESSENTIALS) != 0);
156
157 EDSP::WriteProgress(5, "Read scenario…", output);
158
159 pkgCacheFile CacheFile;
160 if (CacheFile.Open(NULL, false) == false)
161 DIE("Failed to open CacheFile!");
162
163 EDSP::WriteProgress(50, "Apply request on scenario…", output);
164
165 if (EIPP::ApplyRequest(actions, CacheFile) == false)
166 DIE("Failed to apply request to depcache!");
167
168 EDSP::WriteProgress(60, "Call orderinstall on current scenario…", output);
169
170 //_config->Set("Debug::pkgOrderList", true);
171 //_config->Set("Debug::pkgPackageManager", true);
172 PMOutput PM(CacheFile, output);
173 if (PM.ApplyRequest(actions) == false)
174 DIE("Failed to apply request to packagemanager!");
175 pkgPackageManager::OrderResult const Res = PM.DoInstallPreFork();
176 std::ostringstream broken;
177 switch (Res)
178 {
179 case pkgPackageManager::Completed:
180 EDSP::WriteProgress(100, "Done", output);
181 break;
182 case pkgPackageManager::Incomplete:
183 broken << "Planner could only incompletely plan an installation order!" << std::endl;
184 _error->DumpErrors(broken, GlobalError::DEBUG);
185 EDSP::WriteError("pm-incomplete", broken.str(), output);
186 break;
187 case pkgPackageManager::Failed:
188 broken << "Planner failed to find an installation order!" << std::endl;
189 _error->DumpErrors(broken, GlobalError::DEBUG);
190 EDSP::WriteError("pm-failed", broken.str(), output);
191 break;
192 }
193
194 return DispatchCommandLine(CmdL, {});
195 }
196 /*}}}*/