summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Markmann <tm@ayena.de>2016-10-25 14:46:06 (GMT)
committerEdwin Mons <edwin.mons@isode.com>2016-11-14 10:41:17 (GMT)
commit6a033c0efade676403c372f8afecf95b5f9afc79 (patch)
tree14a7044b74c45838c4c4acf28c2625e8e4f57749
parent97c87cf3e9b5e150152898e7907577c3ca3fdd86 (diff)
downloadswift-6a033c0efade676403c372f8afecf95b5f9afc79.zip
swift-6a033c0efade676403c372f8afecf95b5f9afc79.tar.bz2
Add script generating Sparkle appcast feeds
This Python script parses the folder structure of Swift downloads locally and generates three appcast feeds to use for Sparkle updater. The three appcast feeds are written to the downloads folder supplied to the script. Test-Information: Ran script with Python 2.7.12 and manually checked the output. Change-Id: Ie1e71eecad4f65e48694b805878765806a3465ae
-rwxr-xr-xBuildTools/GenerateAppCastFeeds.py128
-rw-r--r--DEVELOPMENT.md3
2 files changed, 129 insertions, 2 deletions
diff --git a/BuildTools/GenerateAppCastFeeds.py b/BuildTools/GenerateAppCastFeeds.py
new file mode 100755
index 0000000..fe39e3c
--- /dev/null
+++ b/BuildTools/GenerateAppCastFeeds.py
@@ -0,0 +1,128 @@
+#!/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]
+ 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)
+
+ def __repr__(self):
+ return "Release(%s, %s, %s, %s)" % (self.version, self.url, self.sizeInBytes, self.date)
+
+def getReleaseFromAbsoluteFilePath(absolutePath, downloadsFolder, downloadsURL):
+ version = os.path.splitext(absolutePath.split('/')[-1])[0]
+ sizeInBytes = os.path.getsize(absolutePath)
+ date = datetime.datetime.fromtimestamp(os.path.getmtime(absolutePath))
+ absoluteURL = urlparse.urljoin(downloadsURL, os.path.relpath(absolutePath, downloadsFolder))
+ return Release(version, absoluteURL, sizeInBytes, date)
+
+def getReleaseFromReleaseFolder(releaseFolder, downloadsFolder, downloadsURL, 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, downloadsURL)
+ return release
+
+def getReleaseFilesInDownloadsFolder(downloadsFolder, downloadsURL, extension):
+ releasesFolder = os.path.join(downloadsFolder, "releases")
+ 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), downloadsFolder, downloadsURL, extension)
+ if release:
+ releases.append(release)
+
+ 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>
+ <pubDate>{{ item.dateString }}</pubDate>
+ <enclosure url="{{ item.url }}"
+ sparkle:version="{{ item.version }}"
+ sparkle:shortVersionString="{{ item.shortVersion }}"
+ length="{{ item.sizeInBytes }}"
+ type="application/octet-stream" />
+ </item>
+ {% endfor %}</channel>
+</rss>''')
+
+ matchingReleases = [i for i in releases if re.match(regexPattern, i.version)]
+ 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/")
+
+args = parser.parse_args()
+
+releases = getReleaseFilesInDownloadsFolder(args.downloadsFolder, args.downloadsURL, "*.dmg")
+
+releases.sort(key=lambda release: release.date, reverse=True)
+
+writeAppcastFile(filename=os.path.join(args.downloadsFolder, "swift-stable-appcast-mac.xml"),
+ title="Swift Stable Releases",
+ description="",
+ regexPattern="^Swift\-\d+(\.\d+)?(\.\d+)?$",
+ appcastURL=urlparse.urljoin(args.downloadsURL, "swift-stable-appcast-mac.xml"),
+ releases=releases)
+writeAppcastFile(filename=os.path.join(args.downloadsFolder, "swift-testing-appcast-mac.xml"),
+ title="Swift Testing Releases",
+ description="",
+ regexPattern="^Swift\-\d+(\.\d+)?(\.\d+)?(beta\d+)?(rc\d+)?$",
+ appcastURL=urlparse.urljoin(args.downloadsURL, "swift-testing-appcast-mac.xml"),
+ releases=releases)
+writeAppcastFile(filename=os.path.join(args.downloadsFolder, "swift-development-appcast-mac.xml"),
+ title="Swift Development Releases",
+ description="",
+ regexPattern="^Swift\-\d+(\.\d+)?(\.\d+)?(alpha)?(beta\d+)?(rc\d+)?(-dev\d+)?$",
+ appcastURL=urlparse.urljoin(args.downloadsURL, "swift-development-appcast-mac.xml"),
+ releases=releases)
diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md
index 3d9c1a7..3e48510 100644
--- a/DEVELOPMENT.md
+++ b/DEVELOPMENT.md
@@ -57,62 +57,61 @@ For packaging use:
```
scons
scons dist=1
```
To sign the resulting MSI file, append the `signtool_key_pfx` and `signtool_timestamp_url` parameters to the `scons dist=1` programm call, e.g.
`scons dist=1 signtool_key_pfx=C:\Users\Swift\SwiftSPC.pfx signtool_timestamp_url=http://timestamp.verisign.com/scripts/timstamp.dll`.
Notes:
- The settings `debug = 1` and `optimize = 1` are **strictly required** if you use a precompiled Qt release from the Qt Project; otherwise you will get linker errors
- On 64-bit Windows it's "Program Files (x86)" instead of "Program Files" in the
paths
- Currently only 32-bit builds of the Swift client are supported
## Automatic Software Updates
Automatic software updates allow distribution of updates directly to the end users.
This is useful for general feature updates, bug fixes and especially for security
updates.
### Automatic Software Updates for Mac OS X using Sparkle
Swift supports integration with the software update framework [Sparkle](https://sparkle-project.org/) on OS X. For security reasons,
Sparkle requires the application to be either code-signed or a bundled public DSA
key. In case you do not code-sign, you can provide the path to the public DSA key
to be bundled with the application bundle via the `sparkle_public_dsa_key` SCons
argument.
To build with Sparkle support, simply download Sparkle-1.14.0 and extract it to
`3rdParty/Sparkle/Sparkle-1.14.0`. SCons will pick it up during configuration
and build Swift with Sparkle support.
-The appcast URL is specified as a compile time preprocessor variable `SWIFT_APPCAST_URL`
-in `Swift/QtUI/QtSwift.cpp`
+The appcast URLs are specified in `Swift/QtUI/SwiftUpdateFeeds.h`.
## Building Swiften for Android
This section describes how to build Swiften for Android. It can then be used from any Android native code. This guide has been tested on OS X and Linux.
### Prerequisites
- Android SDK
- Android NDK
- Python
- Other requirements that are obtained during this guide
- LDNS
- Unbound
- OpenSSL
### Note on Supported Features
File-transfer support has not been tested on Android. Link-local features are not supported under Android.
### Supported Android NDK Level
The minimal supported Android NDK API level is 14 (see --platform parameter of make-standalone-toolchain.sh).
This is the NDK API level associated with Android 4.0. Higher Android NDK API levels however should work.
### Preparation of Build Environment
1. Fetch 3rd-party dependencies
1. LDNS
```
cd 3rdParty/Ldns
bash prepare_ldns.sh
```
2. Unbound
```
cd 3rdParty/Unbound