Skip to content

Commit

Permalink
Sort appcast items by version
Browse files Browse the repository at this point in the history
Ensure that the highest (compatible) version is used regardless of
appcast feed's order.

Fixes #273.
  • Loading branch information
vslavik committed Nov 22, 2024
1 parent f66e205 commit 8563fca
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 13 deletions.
9 changes: 3 additions & 6 deletions src/appcast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -347,9 +347,6 @@ void XMLCALL OnEndElement(void *data, const char *name)
if (item.IsValid() && is_compatible_with_windows_version(item))
{
ctxt.all_items.push_back(item);

// FIXME: this is premature, we should sort appcast items by date and pick the newest (as Sparkle does)
XML_StopParser(ctxt.parser, XML_TRUE);
}
}
}
Expand Down Expand Up @@ -411,7 +408,7 @@ void XMLCALL OnText(void *data, const char *s, int len)
Appcast class
*--------------------------------------------------------------------------*/

Appcast Appcast::Load(const std::string& xml)
std::vector<Appcast> Appcast::Load(const std::string& xml)
{
XML_Parser p = XML_ParserCreateNS(NULL, NS_SEP);
if ( !p )
Expand All @@ -436,11 +433,11 @@ Appcast Appcast::Load(const std::string& xml)
XML_ParserFree(p);

if (ctxt.all_items.empty())
return Appcast(); // invalid
return {}; // invalid

// the items were already filtered to only include those compatible with the current OS + arch
// and meeting minimum OS version requirements, so we can just return the first one
return ctxt.all_items.front();
return std::move(ctxt.all_items);
}

} // namespace winsparkle
16 changes: 10 additions & 6 deletions src/appcast.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
#define _appcast_h_

#include <string>
#include <vector>


namespace winsparkle
{
Expand Down Expand Up @@ -79,18 +81,20 @@ struct Appcast


/**
Initializes the struct with data from XML appcast feed.
Loads all updates from XML appcast feed.
The list is in the order of the feed, without any additional sorting.
If the feed contains multiple entries, only the latest one is read,
the rest is ignored. Entries that are not appliable (e.g. for different
OS) are likewise skipped.
Entries that are not appliable (e.g. for different OS) are skipped.
Throws on error.
Returns NULL if no error ocurred, but there was no update in the appcast.
Returns emty list if no error ocurred, but there was no usable update
in the appcast.
@param xml Appcast feed data.
*/
static Appcast Load(const std::string& xml);
static std::vector<Appcast> Load(const std::string& xml);

/// Returns true if the struct constains valid data.
bool IsValid() const { return !Version.empty() && (HasDownload() || !WebBrowserURL.empty()); }
Expand Down
19 changes: 18 additions & 1 deletion src/updatechecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,24 @@ void UpdateChecker::PerformUpdateCheck()
StringDownloadSink appcast_xml;
DownloadFile(url, &appcast_xml, this, Settings::GetHttpHeadersString(), Download_BypassProxies);

Appcast appcast = Appcast::Load(appcast_xml.data);
auto all = Appcast::Load(appcast_xml.data);

if (all.empty())
{
// No applicable updates in the feed.
UI::NotifyNoUpdates(ShouldAutomaticallyInstall());
return;
}

// Sort by version number and pick the latest:
std::stable_sort
(
all.begin(), all.end(),
[](const Appcast& a, const Appcast& b) { return CompareVersions(a.Version, b.Version) > 0; }
);

auto appcast = all.front();

if (!appcast.ReleaseNotesURL.empty())
CheckForInsecureURL(appcast.ReleaseNotesURL, "release notes");
if (!appcast.enclosure.DownloadURL.empty())
Expand Down

0 comments on commit 8563fca

Please sign in to comment.