updatepackagefilter.cpp
1 //------------------------------------------------------------------------------
2 // updatepackagefilter.cpp
3 //------------------------------------------------------------------------------
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program 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
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; 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 "updater/autoupdater.h"
28 #include "strings.h"
29 #include "version.h"
30 #include <QCoreApplication>
31 #include <QFile>
32 #include <cassert>
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  bool useFallbackMainProgramName;
47  QMap<QString, QList<QString> > ignoredPackagesRevisions;
48  QMap<QString, UpdatePackageFilter::PluginInfo> plugins;
49 
50  bool hasMainProgramPackage(const QList<UpdatePackage> &packages) const
51  {
52  foreach (const UpdatePackage &pkg, packages)
53  {
55  {
56  return true;
57  }
58  }
59  return false;
60  }
61 
62  const QString &mainProgramPackageNameOrFallback() const
63  {
64  return !useFallbackMainProgramName ?
67  }
68 };
69 
70 DPointered(UpdatePackageFilter)
73 
74 {
75  d->bWasAnyUpdatePackageIgnored = false;
76 }
77 
78 UpdatePackageFilter::~UpdatePackageFilter()
79 {
80 }
81 
82 QMap<QString, UpdatePackageFilter::PluginInfo> UpdatePackageFilter::collectPluginInfo()
83 {
84  QMap<QString, PluginInfo> infos;
85  const QList<PluginLoader::Plugin*> plugins = gPlugins->plugins();
86  foreach (const PluginLoader::Plugin* plugin, plugins)
87  {
88  PluginInfo pluginInfo;
89  pluginInfo.name = plugin->info()->data()->name;
90  pluginInfo.revision = QString::number(plugin->info()->data()->version);
91  QString prefixedName = AutoUpdater::PLUGIN_PREFIX + pluginInfo.name.toLower().replace(" ", "");
92  infos.insert(prefixedName, pluginInfo);
93  }
94  return infos;
95 }
96 
97 QList<UpdatePackage> UpdatePackageFilter::filter(const QList<UpdatePackage>& packages)
98 {
99  QList<UpdatePackage> filtered;
100  d->plugins = collectPluginInfo();
101  QList<UpdatePackage> packagesOnIgnoredList;
102  d->useFallbackMainProgramName = !d->hasMainProgramPackage(packages);
103  foreach (UpdatePackage pkg, packages)
104  {
105  if (isDifferentThanInstalled(pkg))
106  {
107  if (!isOnIgnoredList(pkg.name, pkg.revision))
108  {
109  filtered << pkg;
110  }
111  else
112  {
113  packagesOnIgnoredList << pkg;
114  }
115  }
116  }
117  if (!filtered.isEmpty())
118  {
119  // If we do an update of at least one package, we also need to update
120  // all packages that were previously ignored.
121  filtered.append(packagesOnIgnoredList);
122  packagesOnIgnoredList.clear();
123  }
124  d->bWasAnyUpdatePackageIgnored = !packagesOnIgnoredList.isEmpty();
125  return filtered;
126 }
127 
128 bool UpdatePackageFilter::isDifferentThanInstalled(UpdatePackage& pkg) const
129 {
130  if (pkg.name == d->mainProgramPackageNameOrFallback())
131  {
132  QString localRevision = QString::number(Version::revisionNumber());
133  if (localRevision != pkg.revision)
134  {
136  return true;
137  }
138  }
139  else if (pkg.name == AutoUpdater::WADSEEKER_PACKAGE_NAME)
140  {
141  QString localRevision = WadseekerVersionInfo::version();
142  if (localRevision != pkg.revision)
143  {
144  pkg.currentlyInstalledDisplayVersion = localRevision;
145  return true;
146  }
147  }
148  else if (pkg.name == AutoUpdater::QT_PACKAGE_NAME)
149  {
150  // For OS X PowerPC is no longer getting Qt updates so it will
151  // always be on 4.8. Similarly i386 will be used as a legacy
152  // platform (the number of 32-bit only Intel Macs is tiny and
153  // the version of Qt5 we're launching with requires Lion or
154  // higher. Thus only 64-bit Intel Macs need to even bother
155  // checking this package.
156 #if !defined(Q_OS_MAC) || defined(__x86_64__)
157  if (QString(Version::qtPackageVersion()) != pkg.revision)
158  {
159  pkg.currentlyInstalledDisplayVersion = Version::qtPackageVersion();
160  return true;
161  }
162  // Workaround for auto-updater bug that made itself apparent
163  // in Doomseeker 1.1~beta builds. Bug caused every even
164  // numbered file in auxiliary packages not to be installed. As
165  // Qt is such auxiliary package in 1.1~beta, some files
166  // failed to install.
167  bool checkBrokenQt = false;
168 #ifdef Q_OS_WIN32
169  checkBrokenQt = true;
170 #endif
171  if (checkBrokenQt && !isQtInstallOk())
172  {
173  pkg.currentlyInstalledDisplayVersion = Version::qtPackageVersion() + tr("-BROKEN");
174  return true;
175  }
176 #endif
177  }
178  else
179  {
180  // Plugin node.
181  if (d->plugins.contains(pkg.name))
182  {
183  PluginInfo pluginInfo = d->plugins[pkg.name];
184  if (pluginInfo.revision != pkg.revision)
185  {
186  pkg.currentlyInstalledDisplayVersion = pluginInfo.revision;
187  return true;
188  }
189  }
190  }
191  return false;
192 }
193 
194 bool UpdatePackageFilter::isQtInstallOk() const
195 {
196  QStringList files;
197  files << "libeay32.dll" << "ssleay32.dll";
198  foreach (const QString &filename, files)
199  {
200  QString fileLocation = Strings::combinePaths(
201  QCoreApplication::applicationDirPath(), filename);
202  QFile file(fileLocation);
203  if (!file.exists())
204  {
205  return false;
206  }
207  }
208  return true;
209 }
210 
211 bool UpdatePackageFilter::isOnIgnoredList(const QString& package, const QString &revision) const
212 {
213  const QList<QString>& list = d->ignoredPackagesRevisions[package];
214  return list.contains(revision);
215 }
216 
217 void UpdatePackageFilter::setIgnoreRevisions(
218  const QMap<QString, QList<QString> >& packagesRevisions)
219 {
220  d->ignoredPackagesRevisions = packagesRevisions;
221 }
222 
224 {
225  return d->bWasAnyUpdatePackageIgnored;
226 }
static QString combinePaths(QString pathFront, QString pathEnd)
Definition: strings.cpp:147
static QString versionRevision()
Combines version and revision strings.
Definition: version.cpp:74
static const QString FALLBACK_MAIN_PROGRAM_PACKAGE_NAME
Support for downgrading to monolithic Doomseeker package.
Definition: autoupdater.h:135
QString revision
Revision used for version comparison.
Definition: updatepackage.h:71
static const QString PLUGIN_PREFIX
Prefix for all plugins packages names.
Definition: autoupdater.h:125
EnginePlugin * info() const
Main plugin interface.
Filters UpdatePackage information basing on what is requested by the program.
bool wasAnyUpdatePackageIgnored() const
After filter() flag which says if any package was ignored.
static const QString MAIN_PROGRAM_PACKAGE_NAME
Package name for the main program.
Definition: autoupdater.h:131
QString currentlyInstalledDisplayVersion
Currently installed version, displayed to the user.
Definition: updatepackage.h:37
QString name
Name of the package (program name or plugin name).
Definition: updatepackage.h:63