updatepackagefilter.cpp
1 //------------------------------------------------------------------------------
2 // updatepackagefilter.cpp
3 //------------------------------------------------------------------------------
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 // 02110-1301 USA
19 //
20 //------------------------------------------------------------------------------
21 // Copyright (C) 2012 "Zalewa" <zalewapl@gmail.com>
22 //------------------------------------------------------------------------------
23 #include "updatepackagefilter.h"
24 
25 #include "plugins/engineplugin.h"
26 #include "plugins/pluginloader.h"
27 #include "strings.hpp"
28 #include "updater/autoupdater.h"
29 #include "version.h"
30 #include <cassert>
31 #include <QCoreApplication>
32 #include <QFile>
33 #include <wadseeker/wadseekerversioninfo.h>
34 
35 class UpdatePackageFilter::PluginInfo
36 {
37 public:
38  QString name;
39  QString revision;
40 };
42 DClass<UpdatePackageFilter>
43 {
44 public:
45  bool bWasAnyUpdatePackageIgnored;
46  QMap<QString, QList<QString> > ignoredPackagesRevisions;
47  QMap<QString, UpdatePackageFilter::PluginInfo> plugins;
48 
49  bool hasMainProgramPackage(const QList<UpdatePackage> &packages) const
50  {
51  for (const UpdatePackage &pkg : packages)
52  {
54  {
55  return true;
56  }
57  }
58  return false;
59  }
60 };
61 
62 DPointered(UpdatePackageFilter)
65 
66 {
67  d->bWasAnyUpdatePackageIgnored = false;
68 }
69 
70 UpdatePackageFilter::~UpdatePackageFilter()
71 {
72 }
73 
74 QMap<QString, UpdatePackageFilter::PluginInfo> UpdatePackageFilter::collectPluginInfo()
75 {
76  QMap<QString, PluginInfo> infos;
77  const QList<PluginLoader::Plugin *> plugins = gPlugins->plugins();
78  for (const PluginLoader::Plugin *plugin : plugins)
79  {
80  PluginInfo pluginInfo;
81  pluginInfo.name = plugin->info()->data()->name;
82  pluginInfo.revision = QString::number(plugin->info()->data()->version);
83  QString prefixedName = AutoUpdater::PLUGIN_PREFIX + pluginInfo.name.toLower().replace(" ", "");
84  infos.insert(prefixedName, pluginInfo);
85  }
86  return infos;
87 }
88 
89 QList<UpdatePackage> UpdatePackageFilter::filter(const QList<UpdatePackage> &packages)
90 {
91  QList<UpdatePackage> filtered;
92  d->plugins = collectPluginInfo();
93  QList<UpdatePackage> packagesOnIgnoredList;
94  for (UpdatePackage pkg : packages)
95  {
96  if (isDifferentThanInstalled(pkg))
97  {
98  if (!isOnIgnoredList(pkg.name, pkg.revision))
99  {
100  filtered << pkg;
101  }
102  else
103  {
104  packagesOnIgnoredList << pkg;
105  }
106  }
107  }
108  if (!filtered.isEmpty())
109  {
110  // If we do an update of at least one package, we also need to update
111  // all packages that were previously ignored.
112  filtered.append(packagesOnIgnoredList);
113  packagesOnIgnoredList.clear();
114  }
115  d->bWasAnyUpdatePackageIgnored = !packagesOnIgnoredList.isEmpty();
116  return filtered;
117 }
118 
119 bool UpdatePackageFilter::isDifferentThanInstalled(UpdatePackage &pkg) const
120 {
122  {
123  QString localRevision = QString::number(Version::revisionNumber());
124  if (localRevision != pkg.revision)
125  {
127  return true;
128  }
129  }
130  else if (pkg.name == AutoUpdater::WADSEEKER_PACKAGE_NAME)
131  {
132  QString localRevision = WadseekerVersionInfo::version();
133  if (localRevision != pkg.revision)
134  {
135  pkg.currentlyInstalledDisplayVersion = localRevision;
136  return true;
137  }
138  }
139  else if (pkg.name == AutoUpdater::QT_PACKAGE_NAME)
140  {
141  // For OS X PowerPC is no longer getting Qt updates so it will
142  // always be on 4.8. Similarly i386 will be used as a legacy
143  // platform (the number of 32-bit only Intel Macs is tiny and
144  // the version of Qt5 we're launching with requires Lion or
145  // higher. Thus only 64-bit Intel Macs need to even bother
146  // checking this package.
147  #if !defined(Q_OS_DARWIN) || defined(__x86_64__)
148  if (QString(Version::qtPackageVersion()) != pkg.revision)
149  {
150  pkg.currentlyInstalledDisplayVersion = Version::qtPackageVersion();
151  return true;
152  }
153  // Workaround for auto-updater bug that made itself apparent
154  // in Doomseeker 1.1~beta builds. Bug caused every even
155  // numbered file in auxiliary packages not to be installed. As
156  // Qt is such auxiliary package in 1.1~beta, some files
157  // failed to install.
158  bool checkBrokenQt = false;
159  #ifdef Q_OS_WIN32
160  checkBrokenQt = true;
161  #endif
162  if (checkBrokenQt && !isQtInstallOk())
163  {
164  pkg.currentlyInstalledDisplayVersion = Version::qtPackageVersion() + tr("-BROKEN");
165  return true;
166  }
167  #endif
168  }
169  else
170  {
171  // Plugin node.
172  if (d->plugins.contains(pkg.name))
173  {
174  PluginInfo pluginInfo = d->plugins[pkg.name];
175  if (pluginInfo.revision != pkg.revision)
176  {
177  pkg.currentlyInstalledDisplayVersion = pluginInfo.revision;
178  return true;
179  }
180  }
181  }
182  return false;
183 }
184 
185 bool UpdatePackageFilter::isQtInstallOk() const
186 {
187  QStringList files;
188  files << "libeay32.dll" << "ssleay32.dll";
189  for (const QString &filename : files)
190  {
191  QString fileLocation = Strings::combinePaths(
192  QCoreApplication::applicationDirPath(), filename);
193  QFile file(fileLocation);
194  if (!file.exists())
195  {
196  return false;
197  }
198  }
199  return true;
200 }
201 
202 bool UpdatePackageFilter::isOnIgnoredList(const QString &package, const QString &revision) const
203 {
204  const QList<QString> &list = d->ignoredPackagesRevisions[package];
205  return list.contains(revision);
206 }
207 
208 void UpdatePackageFilter::setIgnoreRevisions(const QMap<QString, QList<QString> > &packagesRevisions)
209 {
210  d->ignoredPackagesRevisions = packagesRevisions;
211 }
212 
214 {
215  return d->bWasAnyUpdatePackageIgnored;
216 }