summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Markmann <tm@ayena.de>2016-11-17 11:07:38 (GMT)
committerTobias Markmann <tm@ayena.de>2016-11-17 14:13:56 (GMT)
commitdd6f025037faa6b946d71bbd21c729a931178176 (patch)
tree1dfc992571d6361b4b1641dbd16bd9159934660d
parent8743d5714244a63d301d73fca622f648ac374771 (diff)
downloadswift-dd6f025037faa6b946d71bbd21c729a931178176.zip
swift-dd6f025037faa6b946d71bbd21c729a931178176.tar.bz2
Fix version strings generated by GenerateAppCastFeeds.py
Check for updates on start. Test-Information: Manually verified a random sample of 50 Swift version string pairs, that Sparkle currently compares them and detects the new version. Change-Id: Ic88a5fdc5feab42cdcb4cc3c2740d4c24718eb7b
-rwxr-xr-xBuildTools/GenerateAppCastFeeds.py24
-rw-r--r--SwifTools/AutoUpdater/SparkleAutoUpdater.mm2
2 files changed, 14 insertions, 12 deletions
diff --git a/BuildTools/GenerateAppCastFeeds.py b/BuildTools/GenerateAppCastFeeds.py
index 204961b..8135134 100755
--- a/BuildTools/GenerateAppCastFeeds.py
+++ b/BuildTools/GenerateAppCastFeeds.py
@@ -1,151 +1,153 @@
#!/usr/bin/env python2
# This script generates three app cast feeds for macOS Sparkle updates from Swift releases in the download folder on the Swift website.
from xml.etree import ElementTree as ET
import argparse
import datetime
import email.utils as eut
import fnmatch
import jinja2
import os.path
import re
import time
import urllib2
import urlparse
class Release:
def __init__(self, version, absoluteURL, sizeInBytes, date):
- self.version = version
- self.shortVersion = version.split('-', 1)[1]
+ # This is the version string used for update detection.
+ self.fullVersion = version.split('-', 1)[1]
+ # This is a human readable version string, only used for presentation.
+ self.presentationVersion = version
self.url = absoluteURL
self.sizeInBytes = sizeInBytes
self.date = date
dateTumple = date.timetuple()
dateTimestamp = time.mktime(dateTumple)
self.dateString = eut.formatdate(dateTimestamp)
def __str__(self):
- return "Release(%s, %s, %s, %s)" % (self.version, self.url, self.sizeInBytes, self.date)
+ return "Release(%s, %s, %s, %s)" % (self.fullVersion, self.url, self.sizeInBytes, self.date)
def __repr__(self):
- return "Release(%s, %s, %s, %s)" % (self.version, self.url, self.sizeInBytes, self.date)
+ return "Release(%s, %s, %s, %s)" % (self.fullVersion, self.url, self.sizeInBytes, self.date)
def getReleaseFromAbsoluteFilePath(absolutePath, downloadsFolder, releasesURL):
version = os.path.splitext(absolutePath.split('/')[-1])[0]
sizeInBytes = os.path.getsize(absolutePath)
date = datetime.datetime.fromtimestamp(os.path.getmtime(absolutePath))
absoluteURL = urlparse.urljoin(releasesURL, os.path.relpath(absolutePath, downloadsFolder))
return Release(version, absoluteURL, sizeInBytes, date)
def getReleaseFromReleaseFolder(releaseFolder, downloadsFolder, releasesURL, extension):
release = None
regex = re.compile(fnmatch.translate(extension))
files = [f for f in os.listdir(releaseFolder) if os.path.isfile(os.path.join(releaseFolder, f))]
for file in files:
fileFullPath = os.path.join(releaseFolder, file)
if regex.match(fileFullPath):
release = getReleaseFromAbsoluteFilePath(fileFullPath, downloadsFolder, releasesURL)
return release
def getReleaseFilesInReleasesFolder(releasesFolder, releasesURL, extension):
releases = []
dirs = [d for d in os.listdir(releasesFolder) if os.path.isdir(os.path.join(releasesFolder, d))]
for d in dirs:
release = getReleaseFromReleaseFolder(os.path.join(releasesFolder, d), releasesFolder, releasesURL, extension)
if release:
releases.append(release)
return releases
def getReleaseFilesInDevelopmentFolder(developmentMacFolder, developmentMacURL, extension):
extensionRegex = re.compile(fnmatch.translate(extension))
devPatternRegex = re.compile(".+-dev\d+")
releases = []
files = [f for f in os.listdir(developmentMacFolder) if os.path.isfile(os.path.join(developmentMacFolder, f))]
for f in files:
# Only use dev builds from the development folder.
if devPatternRegex.match(f):
fileFullPath = os.path.join(developmentMacFolder, f)
if extensionRegex.match(fileFullPath):
releases.append(getReleaseFromAbsoluteFilePath(fileFullPath, developmentMacFolder, developmentMacURL))
return releases
def writeAppcastFile(filename, title, description, regexPattern, appcastURL, releases):
template = jinja2.Template('''<rss xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
<channel>
<title>{{ title }}</title>
<link>{{ appcast_url }}</link>
<description>{{ description }}</description>
<language>en</language>
{% for item in releases %}<item>
- <title>Swift version {{ item.version }}</title>
+ <title>Swift version {{ item.fullVersion }}</title>
<pubDate>{{ item.dateString }}</pubDate>
<enclosure url="{{ item.url }}"
- sparkle:version="{{ item.version }}"
- sparkle:shortVersionString="{{ item.shortVersion }}"
+ sparkle:version="{{ item.fullVersion }}"
+ sparkle:shortVersionString="{{ item.presentationVersion }}"
length="{{ item.sizeInBytes }}"
type="application/octet-stream" />
</item>
{% endfor %}</channel>
</rss>''')
- matchingReleases = [i for i in releases if re.match(regexPattern, i.version)]
+ matchingReleases = [i for i in releases if re.match(regexPattern, i.fullVersion)]
matchingReleases = matchingReleases[:2] # only include the first two matches in the appcast
appcastContent = template.render(title=title, appcast_url=appcastURL, description=description, releases=matchingReleases)
contentParsesOK = False
try:
x = ET.fromstring(appcastContent)
contentParsesOK = True
except :
contentParsesOK = False
if contentParsesOK:
with open(filename, 'w') as file:
file.write(appcastContent)
else:
print("Failed to generate valid appcast feed %s." % filename)
parser = argparse.ArgumentParser(description='Generate stable/testing/development appcast feeds for Sparkle updater.')
parser.add_argument('downloadsFolder', type=str, help="e.g. /Users/foo/website/downloads/")
parser.add_argument('downloadsURL', type=str, help="e.g. https://swift.im/downloads/")
parser.add_argument('outputFolder', type=str, help="e.g. /Users/foo/website/downloads/")
args = parser.parse_args()
releasesPath = os.path.join(args.downloadsFolder, "releases")
developmentMacPath = os.path.join(args.downloadsFolder, "development", "mac")
manualReleases = getReleaseFilesInReleasesFolder(releasesPath, urlparse.urljoin(args.downloadsURL, "releases/"), "*.dmg")
manualReleases.sort(key=lambda release: release.date, reverse=True)
automaticReleases = manualReleases
automaticReleases.extend(getReleaseFilesInDevelopmentFolder(developmentMacPath, urlparse.urljoin(args.downloadsURL, "development/mac/"), "*.dmg"))
automaticReleases.sort(key=lambda release: release.date, reverse=True)
writeAppcastFile(filename=os.path.join(args.outputFolder, "swift-stable-appcast-mac.xml"),
title="Swift Stable Releases",
description="",
- regexPattern="^Swift\-\d+(\.\d+)?(\.\d+)?$",
+ regexPattern="^\d+(\.\d+)?(\.\d+)?$",
appcastURL=urlparse.urljoin(args.downloadsURL, "swift-stable-appcast-mac.xml"),
releases=manualReleases)
writeAppcastFile(filename=os.path.join(args.outputFolder, "swift-testing-appcast-mac.xml"),
title="Swift Testing Releases",
description="",
- regexPattern="^Swift\-\d+(\.\d+)?(\.\d+)?(beta\d+)?(rc\d+)?$",
+ regexPattern="^\d+(\.\d+)?(\.\d+)?(beta\d+)?(rc\d+)?$",
appcastURL=urlparse.urljoin(args.downloadsURL, "swift-testing-appcast-mac.xml"),
releases=manualReleases)
writeAppcastFile(filename=os.path.join(args.outputFolder, "swift-development-appcast-mac.xml"),
title="Swift Development Releases",
description="",
- regexPattern="^Swift\-\d+(\.\d+)?(\.\d+)?(alpha)?(beta\d+)?(rc\d+)?(-dev\d+)?$",
+ regexPattern="^\d+(\.\d+)?(\.\d+)?(alpha)?(beta\d+)?(rc\d+)?(-dev\d+)?$",
appcastURL=urlparse.urljoin(args.downloadsURL, "swift-development-appcast-mac.xml"),
releases=automaticReleases)
diff --git a/SwifTools/AutoUpdater/SparkleAutoUpdater.mm b/SwifTools/AutoUpdater/SparkleAutoUpdater.mm
index ed5f094..0c296ee 100644
--- a/SwifTools/AutoUpdater/SparkleAutoUpdater.mm
+++ b/SwifTools/AutoUpdater/SparkleAutoUpdater.mm
@@ -24,39 +24,39 @@ class SparkleAutoUpdater::Private {
SparkleAutoUpdater::SparkleAutoUpdater(const std::string& appcastFeed) : d(new Private()) {
d->updater = [SUUpdater sharedUpdater];
[d->updater retain];
d->delegate = boost::intrusive_ptr<SparkleAutoUpdaterDelegate>([[SparkleAutoUpdaterDelegate alloc] init], false);
[d->delegate.get() setUpdateDownloadFinished: [&](){
d->restartToUpdate = true;
onSuggestRestartToUserToUpdate();
}];
[d->updater setDelegate: d->delegate.get()];
[d->updater setAutomaticallyChecksForUpdates: true];
// Automatically check for an update after a day.
[d->updater setUpdateCheckInterval: 86400];
[d->updater setAutomaticallyDownloadsUpdates: true];
NSURL* nsurl = [NSURL URLWithString: std2NSString(appcastFeed)];
[d->updater setFeedURL: nsurl];
}
SparkleAutoUpdater::~SparkleAutoUpdater() {
[d->updater release];
}
void SparkleAutoUpdater::setAppcastFeed(const std::string& appcastFeed) {
NSURL* nsurl = [NSURL URLWithString: std2NSString(appcastFeed)];
[d->updater setFeedURL: nsurl];
}
void SparkleAutoUpdater::checkForUpdates() {
- //[d->updater resetUpdateCycle]; // This is useful for testing to force a check ot start.
+ [d->updater resetUpdateCycle];
[d->updater checkForUpdatesInBackground];
}
bool SparkleAutoUpdater::recommendRestartToUpdate() {
return d->restartToUpdate;
}
}