Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for appcast generation #1057

Merged
merged 5 commits into from
Jan 19, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 155 additions & 0 deletions src/app/FakeLib/Appcast.fs
Original file line number Diff line number Diff line change
@@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we have a little more docs. like a sample or something.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like this or is it to complex?

/// ##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)
1 change: 1 addition & 0 deletions src/app/FakeLib/FakeLib.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@
<Compile Include="SquirrelHelper.fs" />
<Compile Include="XCopyHelper.fs" />
<Compile Include="DynamicsCRMHelper.fs" />
<Compile Include="Appcast.fs" />
</ItemGroup>
<ItemGroup>
<Reference Include="ICSharpCode.SharpZipLib">
Expand Down