apt  2.2.4
About: Apt (Advanced Package Tool) is a management system for software packages (Debian/Ubuntu). Release series 2.2.
  Fossies Dox: apt-2.2.4.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

statechanges.cc
Go to the documentation of this file.
1 #include <apt-pkg/cacheset.h>
2 #include <apt-pkg/configuration.h>
3 #include <apt-pkg/debsystem.h>
4 #include <apt-pkg/fileutl.h>
5 #include <apt-pkg/pkgcache.h>
7 #include <apt-pkg/statechanges.h>
8 #include <apt-pkg/strutl.h>
9 
10 #include <algorithm>
11 #include <memory>
12 
13 namespace APT
14 {
15 
17 {
18 public:
25 };
26 
27 #define APT_GETTERSETTER(Name, Container) \
28 void StateChanges::Name(pkgCache::VerIterator const &Ver) \
29 { \
30  if (Ver.end() == false) \
31  Container.push_back(Ver); \
32 }\
33 APT::VersionVector& StateChanges::Name() \
34 { \
35  return Container; \
36 }
37 APT_GETTERSETTER(Hold, d->hold)
38 APT_GETTERSETTER(Unhold, d->unhold)
39 APT_GETTERSETTER(Install, d->install)
40 APT_GETTERSETTER(Remove, d->deinstall)
41 APT_GETTERSETTER(Purge, d->purge)
42 #undef APT_GETTERSETTER
44 {
45  return d->error;
46 }
47 
49 {
50  d->hold.clear();
51  d->unhold.clear();
52  d->install.clear();
53  d->deinstall.clear();
54  d->purge.clear();
55  d->error.clear();
56 }
57 
58 bool StateChanges::empty() const
59 {
60  return d->hold.empty() &&
61  d->unhold.empty() &&
62  d->install.empty() &&
63  d->deinstall.empty() &&
64  d->purge.empty() &&
65  d->error.empty();
66 }
67 
68 bool StateChanges::Save(bool const DiscardOutput)
69 {
70  bool const Debug = _config->FindB("Debug::pkgDpkgPm", false);
71  d->error.clear();
72  if (d->hold.empty() && d->unhold.empty() && d->install.empty() && d->deinstall.empty() && d->purge.empty())
73  return true;
74 
75  std::vector<std::string> Args = debSystem::GetDpkgBaseCommand();
76  // ensure dpkg knows about the package so that it keeps the status we set
77  if (d->hold.empty() == false || d->install.empty() == false)
78  {
79  APT::VersionVector makeDpkgAvailable;
80  auto const notInstalled = [](pkgCache::VerIterator const &V) { return V.ParentPkg()->CurrentVer == 0; };
81  std::copy_if(d->hold.begin(), d->hold.end(), std::back_inserter(makeDpkgAvailable), notInstalled);
82  std::copy_if(d->install.begin(), d->install.end(), std::back_inserter(makeDpkgAvailable), notInstalled);
83 
84  if (makeDpkgAvailable.empty() == false)
85  {
86  auto const BaseArgs = Args.size();
87  Args.push_back("--merge-avail");
88  // FIXME: supported only since 1.17.7 in dpkg
89  Args.push_back("-");
90  int dummyAvail = -1;
91  if (Debug)
92  {
93  for (auto const &V: makeDpkgAvailable)
94  {
95  std::clog << "echo 'Dummy record for " << V.ParentPkg().FullName(false) << "' | ";
96  std::copy(Args.begin(), Args.end(), std::ostream_iterator<std::string>(std::clog, " "));
97  std::clog << std::endl;
98  }
99  }
100  else
101  {
102  pid_t const dpkgMergeAvail = debSystem::ExecDpkg(Args, &dummyAvail, nullptr, true);
103 
104  FILE* dpkg = fdopen(dummyAvail, "w");
105  for (auto const &V: makeDpkgAvailable)
106  fprintf(dpkg, "Package: %s\nVersion: 0~\nArchitecture: %s\nMaintainer: Dummy Example <dummy@example.org>\n"
107  "Description: dummy package record\n A record is needed to put a package on hold, so here it is.\n\n", V.ParentPkg().Name(), V.Arch());
108  fclose(dpkg);
109 
110  ExecWait(dpkgMergeAvail, "dpkg --merge-avail", true);
111  }
112  Args.erase(Args.begin() + BaseArgs, Args.end());
113  }
114  }
115  bool const dpkgMultiArch = _system->MultiArchSupported();
116 
117  Args.push_back("--set-selections");
118  if (Debug)
119  {
120  std::string state;
121  auto const dpkgName = [&](pkgCache::VerIterator const &V) {
122  pkgCache::PkgIterator P = V.ParentPkg();
123  if (strcmp(V.Arch(), "none") == 0)
124  ioprintf(std::clog, "echo '%s %s' | ", P.Name(), state.c_str());
125  else if (dpkgMultiArch == false)
126  ioprintf(std::clog, "echo '%s %s' | ", P.FullName(true).c_str(), state.c_str());
127  else
128  ioprintf(std::clog, "echo '%s:%s %s' | ", P.Name(), V.Arch(), state.c_str());
129  std::copy(Args.begin(), Args.end(), std::ostream_iterator<std::string>(std::clog, " "));
130  std::clog << std::endl;
131  };
132  for (auto const &V: d->unhold)
133  {
134  if (V.ParentPkg()->CurrentVer != 0)
135  state = "install";
136  else
137  state = "deinstall";
138  dpkgName(V);
139  }
140  if (d->purge.empty() == false)
141  {
142  state = "purge";
143  std::for_each(d->purge.begin(), d->purge.end(), dpkgName);
144  }
145  if (d->deinstall.empty() == false)
146  {
147  state = "deinstall";
148  std::for_each(d->deinstall.begin(), d->deinstall.end(), dpkgName);
149  }
150  if (d->hold.empty() == false)
151  {
152  state = "hold";
153  std::for_each(d->hold.begin(), d->hold.end(), dpkgName);
154  }
155  if (d->install.empty() == false)
156  {
157  state = "install";
158  std::for_each(d->install.begin(), d->install.end(), dpkgName);
159  }
160  }
161  else
162  {
163  int selections = -1;
164  pid_t const dpkgSelections = debSystem::ExecDpkg(Args, &selections, nullptr, DiscardOutput);
165 
166  FILE* dpkg = fdopen(selections, "w");
167  std::string state;
168  auto const dpkgName = [&](pkgCache::VerIterator const &V) {
169  pkgCache::PkgIterator P = V.ParentPkg();
170  if (strcmp(V.Arch(), "none") == 0)
171  fprintf(dpkg, "%s %s\n", P.Name(), state.c_str());
172  else if (dpkgMultiArch == false)
173  fprintf(dpkg, "%s %s\n", P.FullName(true).c_str(), state.c_str());
174  else
175  fprintf(dpkg, "%s:%s %s\n", P.Name(), V.Arch(), state.c_str());
176  };
177  for (auto const &V: d->unhold)
178  {
179  if (V.ParentPkg()->CurrentVer != 0)
180  state = "install";
181  else
182  state = "deinstall";
183  dpkgName(V);
184  }
185  if (d->purge.empty() == false)
186  {
187  state = "purge";
188  std::for_each(d->purge.begin(), d->purge.end(), dpkgName);
189  }
190  if (d->deinstall.empty() == false)
191  {
192  state = "deinstall";
193  std::for_each(d->deinstall.begin(), d->deinstall.end(), dpkgName);
194  }
195  if (d->hold.empty() == false)
196  {
197  state = "hold";
198  std::for_each(d->hold.begin(), d->hold.end(), dpkgName);
199  }
200  if (d->install.empty() == false)
201  {
202  state = "install";
203  std::for_each(d->install.begin(), d->install.end(), dpkgName);
204  }
205  fclose(dpkg);
206 
207  if (ExecWait(dpkgSelections, "dpkg --set-selections") == false)
208  {
209  std::move(d->purge.begin(), d->purge.end(), std::back_inserter(d->error));
210  d->purge.clear();
211  std::move(d->deinstall.begin(), d->deinstall.end(), std::back_inserter(d->error));
212  d->deinstall.clear();
213  std::move(d->hold.begin(), d->hold.end(), std::back_inserter(d->error));
214  d->hold.clear();
215  std::move(d->unhold.begin(), d->unhold.end(), std::back_inserter(d->error));
216  d->unhold.clear();
217  std::move(d->install.begin(), d->install.end(), std::back_inserter(d->error));
218  d->install.clear();
219  }
220  }
221  return d->error.empty();
222 }
223 
227 StateChanges::~StateChanges() = default;
228 
229 }
APT::VersionVector hold
Definition: statechanges.cc:19
APT::VersionVector install
Definition: statechanges.cc:21
APT::VersionVector unhold
Definition: statechanges.cc:20
APT::VersionVector purge
Definition: statechanges.cc:23
APT::VersionVector error
Definition: statechanges.cc:24
APT::VersionVector deinstall
Definition: statechanges.cc:22
bool empty() const
Definition: statechanges.cc:58
bool Save(bool const DiscardOutput=false)
Definition: statechanges.cc:68
APT::VersionVector & Error()
Definition: statechanges.cc:43
StateChanges & operator=(StateChanges &&)
std::unique_ptr< Private > d
Definition: statechanges.h:55
bool empty() const APT_OVERRIDE
Definition: cacheset.h:815
bool FindB(const char *Name, bool const &Default=false) const
static APT_HIDDEN std::vector< std::string > GetDpkgBaseCommand()
Definition: debsystem.cc:376
static APT_HIDDEN pid_t ExecDpkg(std::vector< std::string > const &sArgs, int *const inputFd, int *const outputFd, bool const DiscardOutput)
Definition: debsystem.cc:407
virtual bool MultiArchSupported() const =0
FILE
Configuration * _config
bool ExecWait(pid_t Pid, const char *Name, bool Reap)
Definition: fileutl.cc:942
pkgCache - Structure definitions for the cache file
pkgSystem * _system
Definition: pkgsystem.cc:24
#define APT_GETTERSETTER(Name, Container)
Definition: statechanges.cc:27
void ioprintf(ostream &out, const char *format,...)
Definition: strutl.cc:1433