installer/build/scripts/Build.fsx (173 lines of code) (raw):
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
// or more contributor license agreements. Licensed under the Elastic License;
// you may not use this file except in compliance with the Elastic License.
#I "../../packages/build/FAKE.x64/tools"
#I "../../packages/build/DotNetZip/lib/net20"
#r "FakeLib.dll"
#r "DotNetZip.dll"
#load "Products.fsx"
open System
open System.Diagnostics
open System.IO
open Fake
open Fake.Git
open Products.Products
open Products.Paths
open Products
open System.Text
open System.Text.RegularExpressions
open Fake.FileHelper
open Fake.AssemblyInfoFile
module Builder =
open Fake.FileSystemHelper
type AssemblyInfo = {
Path : string;
Title: string;
Description : string;
Guid: string;
Product: string;
Version: Version;
}
let patchAssemblyInformation (assemblyInfo:AssemblyInfo, isClean:bool) =
let version = assemblyInfo.Version.FullVersion
let informationalVersion = if isClean then version else version + "-" + Information.getCurrentHash()
CreateCSharpAssemblyInfo assemblyInfo.Path
[Attribute.Title assemblyInfo.Title
Attribute.Description assemblyInfo.Description
Attribute.Guid assemblyInfo.Guid
Attribute.Product assemblyInfo.Product
Attribute.Company "Elasticsearch B.V."
Attribute.Copyright "Elastic License. Copyright Elasticsearch."
Attribute.Trademark "Elasticsearch is a trademark of Elasticsearch B.V."
Attribute.Version version
Attribute.FileVersion version
Attribute.InformationalVersion informationalVersion
]
let Sign file =
let release = getBuildParam "release" = "1"
if release then
tracefn "Signing MSI"
let certificate = getBuildParam "certificate"
let password = getBuildParam "password"
let timeout = TimeSpan.FromMinutes 1.
let timestampServers = ["http://timestamp.digicert.com" ; "http://timestamp.comodoca.com" ;
"http://timestamp.globalsign.com/scripts/timestamp.dll" ; "http://tsa.starfieldtech.com" ;
"http://zeitstempel.dfn.de"]
let sign timestampServer =
let signToolExe = ToolsDir @@ "signtool/signtool.exe"
let args = ["sign"; "/debug" ; "/f"; certificate; "/p"; password; "/tr"; timestampServer; "/td" ; "SHA256" ;
"/d"; "\"Elasticsearch ODBC Driver\""; "/v"; file] |> String.concat " "
let redactedArgs = args.Replace(password, "<redacted>")
use proc = new Process()
proc.StartInfo.UseShellExecute <- false
proc.StartInfo.FileName <- signToolExe
proc.StartInfo.Arguments <- args
platformInfoAction proc.StartInfo
proc.StartInfo.RedirectStandardOutput <- true
proc.StartInfo.RedirectStandardError <- true
if isMono then
proc.StartInfo.StandardOutputEncoding <- Encoding.UTF8
proc.StartInfo.StandardErrorEncoding <- Encoding.UTF8
proc.ErrorDataReceived.Add(fun d -> if d.Data <> null then traceError d.Data)
proc.OutputDataReceived.Add(fun d -> if d.Data <> null then trace d.Data)
try
tracefn "%s %s" proc.StartInfo.FileName redactedArgs
start proc
with exn -> failwithf "Start of process %s failed. %s" proc.StartInfo.FileName exn.Message
proc.BeginErrorReadLine()
proc.BeginOutputReadLine()
if not <| proc.WaitForExit(int timeout.TotalMilliseconds) then
try
proc.Kill()
with exn ->
traceError
<| sprintf "Could not kill process %s %s after timeout." proc.StartInfo.FileName redactedArgs
failwithf "Process %s %s timed out." proc.StartInfo.FileName redactedArgs
proc.WaitForExit()
(timestampServer, proc.ExitCode)
let validExitCode =
timestampServers
|> Seq.map sign
|> Seq.takeWhile (fun (server, exitCode) -> exitCode <> 0)
|> Seq.tryFind (fun (server, exitCode) -> exitCode = 0)
match validExitCode with
| Some (server, exitCode) -> failwithf "Signing with a timestamp from %s failed with code: %i" server exitCode
| None -> tracefn "Signing succeeded."
// Using DotNetZip due to errors with CMAKE zip files: https://github.com/fsharp/FAKE/issues/775
let unzipFile(zipFolder: string, unzipFolder: string) =
use zip = Ionic.Zip.ZipFile.Read(zipFolder)
for e in zip do
e.Extract(unzipFolder, Ionic.Zip.ExtractExistingFileAction.OverwriteSilently)
let PatchAssemblyInfos (version : Version) =
let isClean = (version.FullVersion = "0.0.0")
patchAssemblyInformation ({
Path = MsiDir @@ "Properties/AssemblyInfo.cs";
Title = "Elasticsearch ODBC Installer";
Description = "MSI installer for the Elasticsearch ODBC driver.";
Guid = "44555887-c439-470c-944d-8866ec3d7067";
Product = "Elasticsearch ODBC Installer";
Version = version;
},isClean)
patchAssemblyInformation ({
Path = MsiDir @@ "../InstallerCA/Properties/AssemblyInfo.cs";
Title = "Elasticsearch ODBC Installer Custom Actions";
Description = "MSI installer custom actions for the Elasticsearch ODBC driver.";
Guid = "4498d74b-e5c5-48bb-a9d4-8cc55b7b0909";
Product = "Elasticsearch ODBC Installer Custom Actions";
Version = version;
},isClean)
patchAssemblyInformation ({
Path = SrcDir @@ "../../dsneditor/EsOdbcDsnEditor/Properties/AssemblyInfo.cs";
Title = "Elasticsearch DSN Editor";
Description = "Elasticsearch DSN Editor for managing ODBC connection strings.";
Guid = "fac0512c-e595-4bf4-acb7-617611df5715";
Product = "Elasticsearch DSN Editor";
Version = version;
},isClean)
patchAssemblyInformation ({
Path = SrcDir @@ "../../dsneditor/EsOdbcDsnEditorLauncher/Properties/AssemblyInfo.cs";
Title = "Elasticsearch DSN Editor Launcher";
Description = "Elasticsearch DSN Editor Launcher.";
Guid = "71bebff7-652e-4b26-9ec3-caef947d368c";
Product = "Elasticsearch DSN Editor Launcher";
Version = version;
},isClean)
let copyFileWithLog outDir file =
let targetDirexists = directoryExists outDir
if (targetDirexists = false) then
tracefn "%s does not exist" outDir
else
tracefn "%s exists" outDir
tracefn "Copying: %s <- %s" outDir file
CopyFile outDir file
let BuildMsi (version : Version) =
!! (MsiDir @@ "*.csproj")
|> MSBuildRelease MsiBuildDir "Build"
|> ignore
PatchAssemblyInfos version
let zipFile = getBuildParam "zipFile"
let buildDir = Regex.Replace(zipFile, "(^.*)\\\[^\\\]*\.zip$", "$1/")
unzipFile (zipFile, buildDir)
tracefn "Unzipped zip file in %s" zipFile
// sign every DLL to be part of the MSI
let unzippedDir = Regex.Replace(zipFile, "(^.*)\.zip$", "$1/")
let dllFiles = unzippedDir
|> directoryInfo
|> filesInDirMatching ("*.dll")
|> Seq.map (fun f -> f.FullName)
for dllFile in dllFiles do
Sign dllFile
let exitCode = ExecProcess (fun info ->
info.FileName <- sprintf "%sInstaller" MsiBuildDir
info.WorkingDirectory <- MsiDir
info.Arguments <- [version.FullVersion; System.IO.Path.GetFullPath(buildDir); zipFile] |> String.concat " "
) <| TimeSpan.FromMinutes 20.
if exitCode <> 0 then failwithf "Error building MSI"
let MsiFile = MsiDir
|> directoryInfo
|> filesInDirMatching ("*.msi")
|> Seq.map (fun f -> f.FullName)
|> Seq.head
Sign MsiFile
copyFileWithLog OutDir MsiFile
DeleteFile MsiFile