Skip to content

Commit

Permalink
Merge pull request #899 from andersosthus/squirrel
Browse files Browse the repository at this point in the history
Added Squirrel helpers to generate Squirrel installers
  • Loading branch information
forki committed Aug 10, 2015
2 parents f8684a9 + 894f6d7 commit 0ea027f
Show file tree
Hide file tree
Showing 4 changed files with 259 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/app/FakeLib/FakeLib.fsproj
Expand Up @@ -162,6 +162,7 @@
<Compile Include="CMake.fs" />
<None Include="app.config" />
<Compile Include="RaygunHelper.fs" />
<Compile Include="SquirrelHelper.fs" />
</ItemGroup>
<ItemGroup>
<Reference Include="ICSharpCode.SharpZipLib">
Expand Down
126 changes: 126 additions & 0 deletions src/app/FakeLib/SquirrelHelper.fs
@@ -0,0 +1,126 @@
/// Contains types and utility functions related to creating [Squirrel](https://github.com/Squirrel/Squirrel.Windows) installer.
module Fake.Squirrel

open Fake
open System
open System.Text

/// The [Squirrel](https://github.com/Squirrel/Squirrel.Windows) Console Parameters type.
/// FAKE will use [SquirrelDefaults](fake-squirrel.html) for values not provided.
///
/// For reference, see: [Squirrel Command Line Options](https://github.com/Squirrel/Squirrel.Windows/blob/master/docs/advanced-releasify.md)
type SquirrelParams =
{
/// The output directory for the generated installer
ReleaseDir : string

/// The working directory.
WorkingDir : string option

/// The full path to an optional setup.exe template
BootstrapperExe : string option

/// The full path to an optional animated gif to be displayed during installation
LoadingGif : string option

/// The path to Squirrel: `squirrel.exe`
ToolPath : string

/// Maximum time to allow Squirrel to run before being killed.
TimeOut : TimeSpan

/// Sign the installer with signtool.exe
SignExecutable : bool option

/// The code signing certificate to be used for signing
SigningKeyFile : string option

/// The secret key for the code signing certificate
SigningSecret : string option}

/// The Squirrel default parameters.
///
/// ## Defaults
///
/// - `ReleaseDir` - `""`
/// - `WorkingDir` - `None`
/// - `BootstrapperExe` - `None`
/// - `LoadingGif` - `None`
/// - `ToolPath` - The `squirrel.exe` path if it exists in a subdirectory of the current directory.
/// - `TimeOut` - 10 minutes
/// - `SignExecutable` - `None`
/// - `SigningSecret` - `None`
/// - `SigningSecret` - `None`
let SquirrelDefaults =
let toolname = "Squirrel.exe"
{
ReleaseDir = ""
WorkingDir = None
BootstrapperExe = None
LoadingGif = None
ToolPath = findToolInSubPath toolname (currentDirectory @@ "tools" @@ "Squirrel")
TimeOut = TimeSpan.FromMinutes 10.
SignExecutable = None
SigningKeyFile = None
SigningSecret = None }

let private createSigningArgs (parameters : SquirrelParams) =
new StringBuilder()
|> appendWithoutQuotes "--signWithParams=\"/a"
|> appendWithoutQuotes "/a"
|> appendIfSome parameters.SigningKeyFile (sprintf "/f %s")
|> appendIfSome parameters.SigningSecret (sprintf "/p %s")
|> appendWithoutQuotes "\""
|> toText

let internal buildSquirrelArgs parameters nugetPackage=
new StringBuilder()
|> appendIfNotNullOrEmpty nugetPackage "--releasify="
|> appendIfNotNullOrEmpty parameters.ReleaseDir "--releaseDir="
|> appendIfSome parameters.LoadingGif (sprintf "--loadingGif= %s")
|> appendIfSome parameters.BootstrapperExe (sprintf "--bootstrapperExe= %s")
|> appendIfSome parameters.SignExecutable (fun s -> createSigningArgs parameters)
|> toText

module internal ResultHandling =
let (|OK|Failure|) = function
| 0 -> OK
| x -> Failure x

let buildErrorMessage = function
| OK -> None
| Failure errorCode ->
Some (sprintf "Squirrel reported an error (Error Code %d)" errorCode)

let failBuildIfSquirrelReportedError =
buildErrorMessage
>> Option.iter failwith

/// Creates a Squirrel installer for given NuGet package
/// Will fail if Squirrel terminates with non-zero exit code.
///
/// ## Parameters
///
/// - `setParams` - Function used to manipulate the default `SquirrelParams` value.
/// - `nugetPackage` - The package to create an installer for
///
/// ## Sample usage
///
/// Target "CreatePackage" (fun _ ->
/// SquirrelPack (fun p -> {p with WorkingDir = "./tmp"}) "./my.nuget"
/// )
let SquirrelPack setParams nugetPackage =
traceStartTask "Squirrel" ""
let parameters = SquirrelDefaults |> setParams
let args = buildSquirrelArgs parameters nugetPackage
trace args

let result =
ExecProcess (fun info ->
info.FileName <- parameters.ToolPath
info.WorkingDirectory <- defaultArg parameters.WorkingDir "."
info.Arguments <- args) parameters.TimeOut

ResultHandling.failBuildIfSquirrelReportedError result

traceEndTask "Squirrel" ""
131 changes: 131 additions & 0 deletions src/test/Test.FAKECore/SquirrelHelperSpec.cs
@@ -0,0 +1,131 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Fake;
using Microsoft.FSharp.Core;
using FSharp.Testing;
using Machine.Specifications;

namespace Test.FAKECore.SquirrelHelperSpec
{
[Subject(typeof(Squirrel), "runner argument construction")]
internal abstract class BuildArgumentsSpecsBase
{
protected static Squirrel.SquirrelParams Parameters;
protected static string[] Assemblies;
protected static string Arguments;
protected static string NuGetPackage = "my.nuget";

Establish context = () =>
{
Parameters = Squirrel.SquirrelDefaults;
Assemblies = new[] { "test.dll", "other.dll" };
};

Because of = () =>
{
Arguments = Squirrel.buildSquirrelArgs(Parameters, NuGetPackage);
Console.WriteLine(Arguments);
};
}

internal class When_using_the_default_parameters
: BuildArgumentsSpecsBase
{
It should_not_include_releasify = () => Arguments.ShouldContain("--releasify=" + NuGetPackage);
It should_not_include_releasedir = () => Arguments.ShouldNotContain("--releaseDir=");
It should_not_include_loading_gif = () => Arguments.ShouldNotContain("--loadingGif=");
It should_not_include_bootstrapper_exe = () => Arguments.ShouldNotContain("--bootstrapperExe=");
}

internal class When_specifying_nuget_package
: BuildArgumentsSpecsBase
{
It should_include_nuget_package = () => Arguments.ShouldContain("--releasify=" + NuGetPackage);
}

internal class When_specifying_release_dir
: BuildArgumentsSpecsBase
{
const string ReleaseDir = "releasedir";
Establish context = () => Parameters = Parameters.With(p => p.ReleaseDir, ReleaseDir);

It should_include_release_dir = () => Arguments.ShouldContain("--releaseDir=" + ReleaseDir);
}

internal class When_specifying_loading_gif
: BuildArgumentsSpecsBase
{
const string LoadingGif = "spinner.gif";
Establish context = () => Parameters = Parameters.With(p => p.LoadingGif, FSharpOption<string>.Some(LoadingGif));

It should_include_loading_gif_param = () => Arguments.ShouldContain("--loadingGif=");
It should_include_loading_gif_file = () => Arguments.ShouldContain(LoadingGif);
}

internal class When_specifying_bootstrapper_exe
: BuildArgumentsSpecsBase
{
const string BootstrapperExe = "bootstrap.exe";
Establish context = () => Parameters = Parameters.With(p => p.BootstrapperExe, FSharpOption<string>.Some(BootstrapperExe));

It should_include_bootstrapper_param = () => Arguments.ShouldContain("--bootstrapperExe=");
It should_include_bootstrapper_file = () => Arguments.ShouldContain(BootstrapperExe);
}

internal class When_requesting_package_signing_with_default_parameters
: BuildArgumentsSpecsBase
{
Establish context = () => Parameters = Parameters.With(p => p.SignExecutable, FSharpOption<bool>.Some(true));

It should_include_signWithParams = () => Arguments.ShouldContain("--signWithParams=\"");
It should_include_param_a = () => Arguments.ShouldContain("/a");
It should_not_include_signing_key_file = () => Arguments.ShouldNotContain("/f");
It should_not_include_signing_key_secret = () => Arguments.ShouldNotContain("/s");
}

internal class When_requesting_package_signing_with_signing_file
: BuildArgumentsSpecsBase
{
const string SignKeyFile = "signing.pfx";
Establish context = () => Parameters = Parameters
.With(p => p.SignExecutable, FSharpOption<bool>.Some(true))
.With(p => p.SigningKeyFile, FSharpOption<string>.Some(SignKeyFile));

It should_include_signWithParams = () => Arguments.ShouldContain("--signWithParams=\"");
It should_include_param_a = () => Arguments.ShouldContain("/a");
It should_include_signing_key_file = () => Arguments.ShouldContain("/f " + SignKeyFile);
It should_not_include_signing_key_secret = () => Arguments.ShouldNotContain("/s");
}

internal class When_requesting_package_signing_with_signing_secret
: BuildArgumentsSpecsBase
{
const string SignSecret = "mysecret";
Establish context = () => Parameters = Parameters
.With(p => p.SignExecutable, FSharpOption<bool>.Some(true))
.With(p => p.SigningSecret, FSharpOption<string>.Some(SignSecret));

It should_include_signWithParams = () => Arguments.ShouldContain("--signWithParams=\"");
It should_include_param_a = () => Arguments.ShouldContain("/a");
It should_not_include_signing_key_file = () => Arguments.ShouldNotContain("/f ");
It should_include_signing_key_secret = () => Arguments.ShouldContain("/p " + SignSecret);
}

internal class When_requesting_package_signing_with_parameters
: BuildArgumentsSpecsBase
{
const string SignKeyFile = "signing.pfx";
const string SignSecret = "mysecret";
Establish context = () => Parameters = Parameters
.With(p => p.SignExecutable, FSharpOption<bool>.Some(true))
.With(p => p.SigningKeyFile, FSharpOption<string>.Some(SignKeyFile))
.With(p => p.SigningSecret, FSharpOption<string>.Some(SignSecret));

It should_include_signWithParams = () => Arguments.ShouldContain("--signWithParams=\"");
It should_include_param_a = () => Arguments.ShouldContain("/a");
It should_include_signing_key_file = () => Arguments.ShouldContain("/f " + SignKeyFile);
It should_include_signing_key_secret = () => Arguments.ShouldContain("/p " + SignSecret);
}
}
1 change: 1 addition & 0 deletions src/test/Test.FAKECore/Test.FAKECore.csproj
Expand Up @@ -89,6 +89,7 @@
<Compile Include="PackageMgt\PackagesConfigSpecs.cs" />
<Compile Include="SemVerHelperSpecs.cs" />
<Compile Include="ProjectSystemSpecs.cs" />
<Compile Include="SquirrelHelperSpec.cs" />
<Compile Include="TeamCitySpecs.cs" />
<Compile Include="BasicStringHelperSpecs.cs" />
<Compile Include="FileHandling\SubfolderSpecs.cs" />
Expand Down

0 comments on commit 0ea027f

Please sign in to comment.