diff --git a/src/app/FakeLib/Appcast.fs b/src/app/FakeLib/Appcast.fs
new file mode 100644
index 00000000000..809a1550c53
--- /dev/null
+++ b/src/app/FakeLib/Appcast.fs
@@ -0,0 +1,155 @@
+/// Contains code to configure FAKE for Appcast handling
+module Fake.Appcast
+open System.Xml
+open System.Xml.Linq
+
+
+//private XMLHelper inspired by https://nbevans.wordpress.com/2015/04/15/super-skinny-xml-document-generation-with-f/
+let private XDeclaration version encoding standalone = XDeclaration(version, encoding, standalone)
+let private XName expandedName = XName.Get(expandedName)
+let private XDocument xdecl content = XDocument(xdecl, content |> Seq.map (fun v -> v :> obj) |> Seq.toArray)
+let private XElement expandedName content = XElement(XName expandedName, content |> Seq.map (fun v -> v :> obj) |> Seq.toArray) :> obj
+let private XAttribute expandedName value = XAttribute(XName expandedName, value) :> obj
+let private XAttributeXName expandedName value = Linq.XAttribute(expandedName, value) :> obj
+
+/// Sparkel namespace used for RSS extension
+let private sparkle = XNamespace.Get("http://www.andymatuschak.org/xml-namespaces/sparkle")
+
+/// Mime type of the download file
+type MimeType =
+ /// Octetstream use for exe or zip files
+ | OctetStream
+ /// Custom mimetype
+ | Custom of string
+
+/// Download details for the appcast
+type AppcastItem = {
+ /// The name of the update
+ title : string;
+ /// Date when update is published
+ pubdate : System.DateTime;
+ /// URI where the update files are found
+ url : System.Uri;
+ /// Machine readable version number used to determine if an update is available by the client (should follow semver)
+ version : string;
+ /// Optional human readable version number. This will be shown to the user if present otherwise
+ /// the technical version number will be used
+ shortVersion : string option;
+ /// Mime type of the update file, usualy octetstream
+ mimetype : MimeType
+ /// Optional DSA signature for the archive. It is recommended to use this if the app itself is not signed
+ dsaSignature : string option;
+ /// Optional miminal system version for the update
+ minimumSystemVersion : string option;
+ /// Length of the file in bytes
+ length : int64;
+}
+
+/// Configuration data for the appcast
+type Appcast = {
+ /// A titel, usually the app name
+ title : string;
+ /// Short description
+ description : string;
+ /// Language of your app
+ language : string;
+ /// Updates published to client, can habe multiple updates e.g. for different OS versions
+ items : AppcastItem list;
+}
+
+/// writes an appcast to a file
+/// ##Parameters
+///
+/// - `path` - The file where the appcast should be written
+/// - `cast` - The appcast to write
+/// ##Sample
+/// // This target creates the app cast for our app. I contains two version 1.X and 2.X while 2.X requires at least OS X 10.10 Yosemite.
+/// Target "CreateAppcast" (fun _ ->
+/// let server = "https://example.com/files/"
+/// let fileLength file =
+/// let info = new System.IO.FileInfo(file)
+/// info.Length
+///
+/// let latestSize = fileLength "build/download-2.0.1.zip"
+/// let legacySize = fileLength "build/download-1.1.4.zip"
+///
+/// {
+/// title = "My Awesome App"
+/// description = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus."
+/// language = "en"
+/// items = [
+/// {
+/// title = "Hawk Nickel Greyhound"
+/// pubdate = System.DateTime.Now
+/// url = new System.Uri(server + "download-2.0.1.zip")
+/// version = "2014" // This our internal build number
+/// shortVersion = Some("2.0.1") //This is what we show to the user
+/// mimetype = OctetStream
+/// minimumSystemVersion = Some("10.10")
+/// length = latestSize
+/// dsaSignature = None
+/// };
+/// {
+/// title = "Sparrow Platinum Beagle"
+/// pubdate = System.DateTime.Now
+/// url = new System.Uri(server + "download-1.1.4.zip")
+/// version = "1142" // This our internal build number
+/// shortVersion = Some("1.1.4") //This is what we show to the user
+/// mimetype = OctetStream
+/// length = legacySize
+/// minimumSystemVersion = None
+/// dsaSignature = None
+/// }
+/// ]
+/// } |> writeAppcast "build/updates.xml"
+/// )
+let writeAppcast (path : string) (cast : Appcast) =
+ let toXml (cast : Appcast) =
+ let mtToString mimetype =
+ match mimetype with
+ | OctetStream -> "application/octet-stream"
+ | Custom(s) -> s
+ let choose a b =
+ match a with
+ | Some(c) -> c
+ | None -> b
+ let appendSome option consequence content =
+ match option with
+ | Some(data) -> (consequence data) :: content
+ | None -> content
+
+
+ let item (e : AppcastItem) =
+ let appendMinimumVersion = appendSome e.minimumSystemVersion (fun d -> XAttributeXName (sparkle + "minimumSystemVersion") d)
+ let appendSig = appendSome e.dsaSignature (fun d -> XAttributeXName (sparkle + "dsaSignature") d)
+
+ XElement "item" [
+ XElement "title" e.title
+ XElement "pubDate" (e.pubdate.ToString("r"))
+ XElement "enclosure" ([
+ XAttribute "url" e.url
+ XAttributeXName (sparkle + "version") e.version
+ XAttribute "type" (mtToString e.mimetype)
+ XAttribute "length" e.length
+ XAttributeXName (sparkle + "shortVersionString") (choose e.shortVersion e.version)
+ ]
+ |> appendMinimumVersion
+ |> appendSig)
+ ]
+
+ let doc = XDocument (XDeclaration "1.0" "UTF-8" "no") [
+ XElement "rss" [
+ XAttribute "version" "2.0"
+ XAttributeXName (XNamespace.Xmlns + "sparkle") "http://www.andymatuschak.org/xml-namespaces/sparkle"
+ XAttributeXName (XNamespace.Xmlns + "dc") "http://purl.org/dc/elements/1.1/"
+ XElement "channel" ([
+ XElement "title" cast.title
+ XElement "description" cast.description
+ XElement "language" cast.language]
+ @ List.map item cast.items)
+ ]
+ ]
+ doc
+ let xml = toXml cast
+ use writer = XmlWriter.Create(path)
+ xml.Save(writer)
\ No newline at end of file
diff --git a/src/app/FakeLib/FakeLib.fsproj b/src/app/FakeLib/FakeLib.fsproj
index 62ad2572b02..a23969d2fdd 100644
--- a/src/app/FakeLib/FakeLib.fsproj
+++ b/src/app/FakeLib/FakeLib.fsproj
@@ -166,6 +166,7 @@
+