diff --git a/Resources/SampleAppcast.xml b/Resources/SampleAppcast.xml
index 2a4a2df581..dfc2b3db63 100755
--- a/Resources/SampleAppcast.xml
+++ b/Resources/SampleAppcast.xml
@@ -6,35 +6,39 @@
enVersion 2.0 (2 bugs fixed; 3 new features)
+ http://sparkle-project.org
+ 2.0
http://you.com/app/2.0.html
- http://sparkle-project.org
Wed, 09 Jan 2006 19:20:11 +0000
-
+ 10.11Version 1.5 (8 bugs fixed; 2 new features)
+ http://sparkle-project.org
+ 1.5
http://you.com/app/1.5.html
- http://sparkle-project.org
Wed, 01 Jan 2006 12:20:11 +0000
-
+ 10.11Version 1.4 (5 bugs fixed; 2 new features)
+ http://sparkle-project.org
http://you.com/app/1.4.html
- http://sparkle-project.org
+ 241
+ 1.4Wed, 25 Dec 2005 12:20:11 +0000
-
+ 10.11
diff --git a/Sparkle/SUAppcastItem.m b/Sparkle/SUAppcastItem.m
index b7aaee4709..e1fd3b89ac 100644
--- a/Sparkle/SUAppcastItem.m
+++ b/Sparkle/SUAppcastItem.m
@@ -312,23 +312,28 @@ - (nullable instancetype)initWithDictionary:(NSDictionary *)dict relativeToURL:(
{
self = [super init];
if (self) {
+ _title = [(NSString *)[dict objectForKey:SURSSElementTitle] copy];
+
NSDictionary *enclosure = [dict objectForKey:SURSSElementEnclosure];
// Try to find a version string.
- // Finding the new version number from the RSS feed is a little bit hacky. There are two ways:
+ // Finding the new version number from the RSS feed is a little bit hacky. There are a few ways:
// 1. A "sparkle:version" attribute on the enclosure tag, an extension from the RSS spec.
- // 2. If there isn't a version attribute, Sparkle will parse the path in the enclosure, expecting
+ // 2. If there isn't a version attribute, see if there is a version element (this is now the recommended path).
+ // 3. If there isn't a version element, Sparkle will parse the path in the enclosure, expecting
// that it will look like this: http://something.com/YourApp_0.5.zip. It'll read whatever's between the last
// underscore and the last period as the version number. So name your packages like this: APPNAME_VERSION.extension.
// The big caveat with this is that you can't have underscores in your version strings, as that'll confuse Sparkle.
// Feel free to change the separator string to a hyphen or something more suited to your needs if you like.
NSString *newVersion = [enclosure objectForKey:SUAppcastAttributeVersion];
if (newVersion == nil) {
- newVersion = [dict objectForKey:SUAppcastAttributeVersion]; // Get version from the item, in case it's a download-less item (i.e. paid upgrade).
+ // Get version from the item
+ newVersion = [dict objectForKey:SUAppcastElementVersion];
}
- if (newVersion == nil) // no sparkle:version attribute anywhere?
+ if (newVersion == nil)
{
- SULog(SULogLevelError, @"warning: <%@> for URL '%@' is missing %@ attribute. Version comparison may be unreliable. Please always specify %@", SURSSElementEnclosure, [enclosure objectForKey:SURSSAttributeURL], SUAppcastAttributeVersion, SUAppcastAttributeVersion);
+ // No sparkle:version element/attribute anywhere?
+ SULog(SULogLevelError, @"warning: Item '%@' is missing '<%@>' element. Version comparison may be unreliable. Please always specify %@", _title, SUAppcastElementVersion, SUAppcastElementVersion);
// Separate the url by underscores and take the last component, as that'll be closest to the end,
// then we remove the extension. Hopefully, this will be the version.
@@ -340,13 +345,12 @@ - (nullable instancetype)initWithDictionary:(NSDictionary *)dict relativeToURL:(
if (!newVersion) {
if (error) {
- *error = [NSString stringWithFormat:@"Feed item lacks %@ attribute, and version couldn't be deduced from file name (would have used last component of a file name like AppName_1.3.4.zip)", SUAppcastAttributeVersion];
+ *error = [NSString stringWithFormat:@"Feed item lacks %@ element, and version couldn't be deduced from file name (would have used last component of a file name like AppName_1.3.4.zip)", SUAppcastElementVersion];
}
return nil;
}
_propertiesDictionary = [[NSDictionary alloc] initWithDictionary:dict];
- _title = [(NSString *)[dict objectForKey:SURSSElementTitle] copy];
_dateString = [(NSString *)[dict objectForKey:SURSSElementPubDate] copy];
_itemDescription = [(NSString *)[dict objectForKey:SURSSElementDescription] copy];
diff --git a/Sparkle/SUConstants.h b/Sparkle/SUConstants.h
index a1e65b6679..a1f2669c52 100644
--- a/Sparkle/SUConstants.h
+++ b/Sparkle/SUConstants.h
@@ -77,6 +77,8 @@ extern NSString *const SUAppcastAttributeVersion;
extern NSString *const SUAppcastAttributeOsType;
extern NSString *const SUAppcastAttributeInstallationType;
+extern NSString *const SUAppcastElementVersion;
+extern NSString *const SUAppcastElementShortVersionString;
extern NSString *const SUAppcastElementCriticalUpdate;
extern NSString *const SUAppcastElementDeltas;
extern NSString *const SUAppcastElementMinimumAutoupdateVersion;
diff --git a/Sparkle/SUConstants.m b/Sparkle/SUConstants.m
index f1aad287cd..d1c75802d1 100644
--- a/Sparkle/SUConstants.m
+++ b/Sparkle/SUConstants.m
@@ -73,6 +73,8 @@
NSString *const SUAppcastAttributeOsType = @"sparkle:os";
NSString *const SUAppcastAttributeInstallationType = @"sparkle:installationType";
+NSString *const SUAppcastElementVersion = SUAppcastAttributeVersion;
+NSString *const SUAppcastElementShortVersionString = SUAppcastAttributeShortVersionString;
NSString *const SUAppcastElementCriticalUpdate = @"sparkle:criticalUpdate";
NSString *const SUAppcastElementDeltas = @"sparkle:deltas";
NSString *const SUAppcastElementMinimumAutoupdateVersion = @"sparkle:minimumAutoupdateVersion";
diff --git a/TestApplication/sparkletestcast.xml b/TestApplication/sparkletestcast.xml
index b74b0220e8..ebb17b93dd 100644
--- a/TestApplication/sparkletestcast.xml
+++ b/TestApplication/sparkletestcast.xml
@@ -6,6 +6,7 @@
enVersion 2.0
+ 2.0
@@ -17,7 +18,7 @@
]]>
Sat, 26 Jul 2014 15:20:11 +0000
-
+
diff --git a/Tests/Resources/testappcast.xml b/Tests/Resources/testappcast.xml
index f78862d1d2..5922b83042 100644
--- a/Tests/Resources/testappcast.xml
+++ b/Tests/Resources/testappcast.xml
@@ -6,26 +6,26 @@
Version 2.0descSat, 26 Jul 2014 15:20:11 +0000
+
Version 3.0
+ 3.086400
-
+ Version 4.0
+ 4.0Sat, 26 Jul 2014 15:20:13 +0000
-
+ 17.0.0Version 5.0
-
+ 5.0
+ 2.0.0
diff --git a/Tests/Resources/testappcast_info_updates.xml b/Tests/Resources/testappcast_info_updates.xml
index e1e5074e17..a8a86a3d03 100644
--- a/Tests/Resources/testappcast_info_updates.xml
+++ b/Tests/Resources/testappcast_info_updates.xml
@@ -23,19 +23,18 @@
Version 4.0Sat, 26 Jul 2014 15:20:13 +0000
-
+ 4.0
+
http://sparkle-project.org
-
- For unit test only
Version 3.0
+ 3.02.0
-
+ Version 2.0
-
+ 2.0
+
diff --git a/Tests/Resources/testlocalizedreleasenotesappcast.xml b/Tests/Resources/testlocalizedreleasenotesappcast.xml
index ee21cd0aa9..5e0d3f7e89 100644
--- a/Tests/Resources/testlocalizedreleasenotesappcast.xml
+++ b/Tests/Resources/testlocalizedreleasenotesappcast.xml
@@ -5,8 +5,9 @@
Version 6.0
+ 6.0Sat, 26 Jul 2019 15:20:13 +0000
-
+ https://sparkle-project.org/#works
https://sparkle-project.org/#localized_notes_link_works
diff --git a/Tests/SUAppcastTest.swift b/Tests/SUAppcastTest.swift
index d3c25fd9c4..b593a098fe 100644
--- a/Tests/SUAppcastTest.swift
+++ b/Tests/SUAppcastTest.swift
@@ -30,6 +30,7 @@ class SUAppcastTest: XCTestCase {
XCTAssertEqual("desc", items[0].itemDescription)
XCTAssertEqual("Sat, 26 Jul 2014 15:20:11 +0000", items[0].dateString)
XCTAssertTrue(items[0].isCriticalUpdate)
+ XCTAssertEqual(items[0].versionString, "2.0")
// This is the best release matching our system version
XCTAssertEqual("Version 3.0", items[1].title)
@@ -37,6 +38,7 @@ class SUAppcastTest: XCTestCase {
XCTAssertNil(items[1].dateString)
XCTAssertTrue(items[1].isCriticalUpdate)
XCTAssertEqual(items[1].phasedRolloutInterval, 86400)
+ XCTAssertEqual(items[1].versionString, "3.0")
XCTAssertEqual("Version 4.0", items[2].title)
XCTAssertNil(items[2].itemDescription)
@@ -58,6 +60,7 @@ class SUAppcastTest: XCTestCase {
XCTAssertEqual(bestAppcastItem, items[1])
XCTAssertEqual(deltaItem!.fileURL!.lastPathComponent, "3.0_from_1.0.patch")
+ XCTAssertEqual(deltaItem!.versionString, "3.0")
// Test latest delta update item available
var latestDeltaItem: SUAppcastItem?
diff --git a/generate_appcast/FeedXML.swift b/generate_appcast/FeedXML.swift
index f84f12a345..8159fa4767 100644
--- a/generate_appcast/FeedXML.swift
+++ b/generate_appcast/FeedXML.swift
@@ -71,7 +71,13 @@ func writeAppcast(appcastDestPath: URL, updates: [ArchiveItem]) throws {
var numItems = 0
for update in updates {
var item: XMLElement
- let existingItems = try channel.nodes(forXPath: "item[enclosure[@sparkle:version=\"\(update.version)\"]]")
+
+ var existingItems = try channel.nodes(forXPath: "item[enclosure[@\(SUAppcastAttributeVersion)=\"\(update.version)\"]]")
+ if existingItems.count == 0 {
+ // Fall back to see if any items are using the element version variant
+ existingItems = try channel.nodes(forXPath: "item[\(SUAppcastElementVersion)=\"\(update.version)\"]")
+ }
+
let createNewItem = existingItems.count == 0
// Update all old items, but aim for less than 5 in new feeds
@@ -93,6 +99,20 @@ func writeAppcast(appcastDestPath: URL, updates: [ArchiveItem]) throws {
if nil == findElement(name: "pubDate", parent: item) {
item.addChild(XMLElement.element(withName: "pubDate", stringValue: update.pubDate) as! XMLElement)
}
+
+ var versionElement = findElement(name: SUAppcastElementVersion, parent: item)
+ if nil == versionElement {
+ versionElement = XMLElement.element(withName: SUAppcastElementVersion, uri: sparkleNS) as? XMLElement
+ item.addChild(versionElement!)
+ }
+ versionElement?.setChildren([text(update.version)])
+
+ var shortVersionElement = findElement(name: SUAppcastElementShortVersionString, parent: item)
+ if nil == shortVersionElement {
+ shortVersionElement = XMLElement.element(withName: SUAppcastElementShortVersionString, uri: sparkleNS) as? XMLElement
+ item.addChild(shortVersionElement!)
+ }
+ shortVersionElement?.setChildren([text(update.shortVersion)])
if let html = update.releaseNotesHTML {
let descElement = findOrCreateElement(name: "description", parent: item)
@@ -157,8 +177,6 @@ func writeAppcast(appcastDestPath: URL, updates: [ArchiveItem]) throws {
}
var attributes = [
XMLNode.attribute(withName: "url", stringValue: archiveURL) as! XMLNode,
- XMLNode.attribute(withName: SUAppcastAttributeVersion, uri: sparkleNS, stringValue: update.version) as! XMLNode,
- XMLNode.attribute(withName: SUAppcastAttributeShortVersionString, uri: sparkleNS, stringValue: update.shortVersion) as! XMLNode,
XMLNode.attribute(withName: "length", stringValue: String(update.fileSize)) as! XMLNode,
XMLNode.attribute(withName: "type", stringValue: update.mimeType) as! XMLNode,
]
@@ -181,8 +199,6 @@ func writeAppcast(appcastDestPath: URL, updates: [ArchiveItem]) throws {
for delta in update.deltas {
var attributes = [
XMLNode.attribute(withName: "url", stringValue: URL(string: delta.archivePath.lastPathComponent.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlPathAllowed)!, relativeTo: update.archiveURL)!.absoluteString) as! XMLNode,
- XMLNode.attribute(withName: SUAppcastAttributeVersion, uri: sparkleNS, stringValue: update.version) as! XMLNode,
- XMLNode.attribute(withName: SUAppcastAttributeShortVersionString, uri: sparkleNS, stringValue: update.shortVersion) as! XMLNode,
XMLNode.attribute(withName: SUAppcastAttributeDeltaFrom, uri: sparkleNS, stringValue: delta.fromVersion) as! XMLNode,
XMLNode.attribute(withName: "length", stringValue: String(delta.fileSize)) as! XMLNode,
XMLNode.attribute(withName: "type", stringValue: "application/octet-stream") as! XMLNode,