Skip to content

Commit ef49abd

Browse files
committed
Build: clean up
1 parent f7f3ce3 commit ef49abd

9 files changed

Lines changed: 488 additions & 471 deletions

File tree

build/Building.fs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
module Building
2+
3+
open FSharp.Core
4+
open Fake.Core
5+
open Fake.DotNet
6+
open Fake.IO.FileSystemOperators
7+
8+
open Model
9+
open Dotnet
10+
11+
let rootDir = System.Environment.CurrentDirectory
12+
13+
let clean (solution:Solution) = dotnet rootDir (sprintf "clean %s --configuration Release --verbosity minimal" solution.SolutionFile)
14+
15+
let restoreWeak (solution:Solution) = dotnetWeak rootDir (sprintf "restore %s --verbosity minimal" solution.SolutionFile)
16+
let restoreStrong (solution:Solution) = dotnetStrong rootDir (sprintf "restore %s --verbosity minimal" solution.SolutionFile)
17+
18+
let buildWeak (solution:Solution) = dotnetWeak rootDir (sprintf "build %s --configuration Release --no-incremental --no-restore --verbosity minimal" solution.SolutionFile)
19+
let buildStrong (solution:Solution) = dotnetStrong rootDir (sprintf "build %s --configuration Release --no-incremental --no-restore --verbosity minimal" solution.SolutionFile)
20+
21+
let packWeak (solution:Solution) = dotnetWeak rootDir (sprintf "pack %s --configuration Release --no-restore --verbosity minimal" solution.SolutionFile)
22+
let packStrong (solution:Solution) = dotnetStrong rootDir (sprintf "pack %s --configuration Release --no-restore --verbosity minimal" solution.SolutionFile)
23+
24+
let packProjectWeak = function
25+
| VisualStudio p -> dotnetWeak rootDir (sprintf "pack %s --configuration Release --no-restore --no-build" p.ProjectFile)
26+
| _ -> failwith "Project type not supported"
27+
let packProjectStrong = function
28+
| VisualStudio p -> dotnetStrong rootDir (sprintf "pack %s --configuration Release --no-restore --no-build" p.ProjectFile)
29+
| _ -> failwith "Project type not supported"
30+
31+
let buildVS2019x86 config isIncremental subject =
32+
MSBuild.run
33+
(fun p -> {p with ToolPath = Environment.environVar "VS2019INSTALLDIR" </> @"MSBuild\Current\Bin\MSBuild.exe"})
34+
""
35+
(if isIncremental then "Build" else "Rebuild")
36+
[("Configuration", config); ("Platform","Win32")]
37+
subject
38+
|> ignore<string list>
39+
let buildVS2019x64 config isIncremental subject =
40+
MSBuild.run
41+
(fun p -> {p with ToolPath = Environment.environVar "VS2019INSTALLDIR" </> @"MSBuild\Current\Bin\MSBuild.exe"})
42+
""
43+
(if isIncremental then "Build" else "Rebuild")
44+
[("Configuration", config); ("Platform","x64")]
45+
subject
46+
|> ignore<string list>
47+
48+
let test testsDir testsProj framework =
49+
dotnet testsDir (sprintf "run --project %s --configuration Release --framework %s --no-restore --no-build" testsProj framework)

build/Documentation.fs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
module Documentation
2+
3+
open FSharp.Core
4+
open Fake.Core
5+
open Fake.IO
6+
open Fake.IO.FileSystemOperators
7+
open System
8+
9+
open Model
10+
11+
let provideDocExtraFiles extraDocs (releases:Release list) =
12+
for (fileName, docName) in extraDocs do Shell.copyFile ("docs" </> docName) fileName
13+
let menu = releases |> List.map (fun r -> sprintf "[%s](%s)" r.Title (r.ReleaseNotesFile |> String.replace "RELEASENOTES" "ReleaseNotes" |> String.replace ".md" ".html")) |> String.concat " | "
14+
for release in releases do
15+
String.concat Environment.NewLine
16+
[ "# " + release.Title + " Release Notes"
17+
menu
18+
""
19+
File.readAsString release.ReleaseNotesFile ]
20+
|> File.replaceContent ("docs" </> (release.ReleaseNotesFile |> String.replace "RELEASENOTES" "ReleaseNotes"))

build/Dotnet.fs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
module Dotnet
2+
3+
open FSharp.Core
4+
open Fake.Core
5+
open Fake.DotNet
6+
7+
let dotnet workingDir command =
8+
DotNet.exec (fun c -> { c with WorkingDirectory = workingDir}) command "" |> ignore<ProcessResult>
9+
10+
let dotnetWeak workingDir command =
11+
let properties = [ ("StrongName", "False") ]
12+
let suffix = properties |> List.map (fun (name, value) -> sprintf """ /p:%s="%s" /nr:false """ name value) |> String.concat ""
13+
DotNet.exec (fun c -> { c with WorkingDirectory = workingDir }) command suffix |> ignore<ProcessResult>
14+
15+
let dotnetStrong workingDir command =
16+
let properties = [ ("StrongName", "True") ]
17+
let suffix = properties |> List.map (fun (name, value) -> sprintf """ /p:%s="%s" /nr:false """ name value) |> String.concat ""
18+
DotNet.exec (fun c -> { c with WorkingDirectory = workingDir}) command suffix |> ignore<ProcessResult>

build/Model.fs

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
module Model
2+
3+
open FSharp.Core
4+
open Fake.Core
5+
open Fake.IO
6+
open Fake.IO.FileSystemOperators
7+
open System.IO
8+
9+
type Release =
10+
{ RepoKey: string
11+
Title: string
12+
AssemblyVersion: string
13+
PackageVersion: string
14+
ReleaseNotes: string
15+
ReleaseNotesFile: string }
16+
17+
type ZipPackage =
18+
{ Id: string
19+
Release: Release
20+
Title: string }
21+
22+
type NuGetPackage =
23+
{ Id: string
24+
Release: Release }
25+
26+
type VisualStudioProject =
27+
{ AssemblyName: string
28+
ProjectFile: string
29+
OutputDir: string
30+
Release: Release
31+
NuGetPackages: NuGetPackage list }
32+
33+
type NativeVisualStudioProject =
34+
{ BinaryName: string
35+
ProjectFile: string
36+
OutputDir: string
37+
Release: Release
38+
NuGetPackages: NuGetPackage list }
39+
40+
type NativeBashScriptProject =
41+
{ BinaryName: string
42+
BashScriptFile: string
43+
OutputDir: string
44+
Release: Release
45+
NuGetPackages: NuGetPackage list }
46+
47+
type Project =
48+
| VisualStudio of VisualStudioProject
49+
| NativeVisualStudio of NativeVisualStudioProject
50+
| NativeBashScript of NativeBashScriptProject
51+
52+
type Solution =
53+
{ Key: string
54+
SolutionFile: string
55+
Projects: Project list
56+
Release: Release
57+
ZipPackages: ZipPackage list
58+
OutputDir: string
59+
OutputLibDir: string
60+
OutputLibStrongNameDir: string
61+
OutputZipDir: string
62+
OutputNuGetDir: string }
63+
64+
type NuGetSpecification =
65+
{ NuGet: NuGetPackage
66+
NuSpecFile: string
67+
Dependencies: (string * string) list
68+
Title: string }
69+
70+
let release repoKey title releaseNotesFile : Release =
71+
let info = ReleaseNotes.load releaseNotesFile
72+
let buildPart = "0"
73+
let assemblyVersion = info.AssemblyVersion + "." + buildPart
74+
let packageVersion = info.NugetVersion
75+
let notes = info.Notes |> List.map (fun l -> l.Replace("*","").Replace("`","")) |> String.toLines
76+
{ Release.RepoKey = repoKey
77+
Title = title
78+
AssemblyVersion = assemblyVersion
79+
PackageVersion = packageVersion
80+
ReleaseNotes = notes
81+
ReleaseNotesFile = releaseNotesFile }
82+
83+
let zipPackage packageId title release =
84+
{ ZipPackage.Id = packageId
85+
Title = title
86+
Release = release }
87+
88+
let nugetPackage packageId release =
89+
{ NuGetPackage.Id = packageId
90+
Release = release }
91+
92+
let project assemblyName projectFile nuGetPackages =
93+
{ VisualStudioProject.AssemblyName = assemblyName
94+
ProjectFile = projectFile
95+
OutputDir = (Path.GetDirectoryName projectFile) </> "bin" </> "Release"
96+
NuGetPackages = nuGetPackages
97+
Release = nuGetPackages |> List.map (fun p -> p.Release) |> List.distinct |> List.exactlyOne }
98+
|> Project.VisualStudio
99+
100+
let nativeProject binaryName projectFile nuGetPackages =
101+
{ NativeVisualStudioProject.BinaryName = binaryName
102+
ProjectFile = projectFile
103+
OutputDir = (Path.GetDirectoryName projectFile) </> "bin" </> "Release"
104+
NuGetPackages = nuGetPackages
105+
Release = nuGetPackages |> List.map (fun p -> p.Release) |> List.distinct |> List.exactlyOne }
106+
|> Project.NativeVisualStudio
107+
108+
let nativeBashScriptProject binaryName bashScriptFile nuGetPackages =
109+
{ NativeBashScriptProject.BinaryName = binaryName
110+
BashScriptFile = bashScriptFile
111+
OutputDir = (Path.GetDirectoryName bashScriptFile) </> "bin" </> "Release"
112+
NuGetPackages = nuGetPackages
113+
Release = nuGetPackages |> List.map (fun p -> p.Release) |> List.distinct |> List.exactlyOne }
114+
|> Project.NativeBashScript
115+
116+
117+
let projectOutputDir = function
118+
| VisualStudio p -> p.OutputDir
119+
| NativeVisualStudio p -> p.OutputDir
120+
| NativeBashScript p -> p.OutputDir
121+
122+
let projectRelease = function
123+
| VisualStudio p -> p.Release
124+
| NativeVisualStudio p -> p.Release
125+
| NativeBashScript p -> p.Release
126+
127+
let projectNuGetPackages = function
128+
| VisualStudio p -> p.NuGetPackages
129+
| NativeVisualStudio p -> p.NuGetPackages
130+
| NativeBashScript p -> p.NuGetPackages
131+
132+
let solution key solutionFile projects zipPackages =
133+
{ Solution.Key = key
134+
SolutionFile = solutionFile
135+
Projects = projects
136+
ZipPackages = zipPackages
137+
Release = List.concat [ projects |> List.map projectRelease; zipPackages |> List.map (fun p -> p.Release) ] |> List.distinct |> List.exactlyOne
138+
OutputDir = "out" </> key
139+
OutputLibDir = "out" </> key </> "Lib"
140+
OutputLibStrongNameDir = "out" </> key </> "Lib-StrongName"
141+
OutputZipDir = "out" </> key </> "Zip"
142+
OutputNuGetDir = "out" </> key </> "NuGet" }

build/Packaging.fs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
module Packaging
2+
3+
open FSharp.Core
4+
open Fake.Core
5+
open Fake.DotNet
6+
open Fake.DotNet.NuGet
7+
open Fake.IO
8+
open Fake.IO.FileSystemOperators
9+
open Fake.IO.Globbing.Operators
10+
open System
11+
12+
open Model
13+
14+
let collectBinaries (solution:Solution) =
15+
solution.Projects |> List.iter (function
16+
| VisualStudio project -> Shell.copyDir solution.OutputLibDir project.OutputDir (fun n -> n.Contains(project.AssemblyName + ".dll") || n.Contains(project.AssemblyName + ".pdb") || n.Contains(project.AssemblyName + ".xml"))
17+
| _ -> failwith "Project type not supported")
18+
19+
let collectBinariesSN (solution:Solution) =
20+
solution.Projects |> List.iter (function
21+
| VisualStudio project -> Shell.copyDir solution.OutputLibStrongNameDir project.OutputDir (fun n -> n.Contains(project.AssemblyName + ".dll") || n.Contains(project.AssemblyName + ".pdb") || n.Contains(project.AssemblyName + ".xml"))
22+
| _ -> failwith "Project type not supported")
23+
24+
let collectNuGetPackages (solution:Solution) =
25+
solution.Projects |> List.iter (function
26+
| VisualStudio project -> Shell.copyDir solution.OutputNuGetDir project.OutputDir (fun n -> n.EndsWith(".nupkg"))
27+
| _ -> failwith "Project type not supported")
28+
29+
let provideLicense path =
30+
File.readAsString "LICENSE.md"
31+
|> String.convertTextToWindowsLineBreaks
32+
|> File.replaceContent (path </> "license.txt")
33+
34+
let provideReadme header title (release:Release) path =
35+
String.concat Environment.NewLine [header; " " + title; ""; File.readAsString release.ReleaseNotesFile]
36+
|> String.convertTextToWindowsLineBreaks
37+
|> File.replaceContent (path </> "readme.txt")
38+
39+
40+
// SIGN
41+
42+
let sign fingerprint timeserver (solution: Solution) =
43+
let files = solution.Projects |> Seq.collect (function
44+
| VisualStudio project -> !! (project.OutputDir + "/**/" + project.AssemblyName + ".dll")
45+
| _ -> failwith "Project type not supported")
46+
let fileArgs = files |> Seq.map (sprintf "\"%s\"") |> String.concat " "
47+
let optionsArgs = sprintf """/v /fd sha256 /sha1 "%s" /tr "%s" /td sha256""" fingerprint timeserver
48+
let arguments = sprintf """sign %s %s""" optionsArgs fileArgs
49+
let result =
50+
CreateProcess.fromRawCommandLine (ProcessUtils.findLocalTool "SIGNTOOL" "signtool.exe" ["""C:\Program Files (x86)\Windows Kits\10\bin\x64"""]) arguments
51+
|> CreateProcess.withTimeout (TimeSpan.FromMinutes 10.)
52+
|> Proc.run
53+
if result.ExitCode <> 0 then failwithf "Error during SignTool call "
54+
55+
let signNuGet fingerprint timeserver (solutions: Solution list) =
56+
Shell.cleanDir "obj/NuGet"
57+
solutions
58+
|> Seq.collect (fun solution -> !! (solution.OutputNuGetDir </> "*.nupkg"))
59+
|> Seq.distinct
60+
|> Seq.iter (fun file ->
61+
let args = sprintf """sign "%s" -HashAlgorithm SHA256 -TimestampHashAlgorithm SHA256 -CertificateFingerprint "%s" -Timestamper "%s""" (Path.getFullName file) fingerprint timeserver
62+
let result =
63+
CreateProcess.fromRawCommandLine "packages/build/NuGet.CommandLine/tools/NuGet.exe" args
64+
|> CreateProcess.withWorkingDirectory (Path.getFullName "obj/NuGet")
65+
|> CreateProcess.withTimeout (TimeSpan.FromMinutes 10.)
66+
|> Proc.run
67+
if result.ExitCode <> 0 then failwith "Error during NuGet sign.")
68+
Directory.delete "obj/NuGet"
69+
70+
71+
let zip (package:ZipPackage) header zipDir filesDir filesFilter =
72+
Shell.cleanDir "obj/Zip"
73+
let workPath = "obj/Zip/" + package.Id
74+
Shell.copyDir workPath filesDir filesFilter
75+
provideLicense workPath
76+
provideReadme header (sprintf "%s v%s" package.Title package.Release.PackageVersion) package.Release workPath
77+
Zip.zip "obj/Zip/" (zipDir </> sprintf "%s-%s.zip" package.Id package.Release.PackageVersion) !! (workPath + "/**/*.*")
78+
Directory.delete "obj/Zip"
79+
80+
81+
let updateNuspec (nuget:NuGetPackage) outPath dependencies (spec:NuGet.NuGet.NuGetParams) =
82+
{ spec with ToolPath = "packages/build/NuGet.CommandLine/tools/NuGet.exe"
83+
OutputPath = outPath
84+
WorkingDir = "obj/NuGet"
85+
Version = nuget.Release.PackageVersion
86+
Dependencies = dependencies
87+
ReleaseNotes = nuget.Release.ReleaseNotes
88+
Publish = false }
89+
90+
let nugetPackManually (solution:Solution) (packages:NuGetSpecification list) header =
91+
Shell.cleanDir "obj/NuGet"
92+
for pack in packages do
93+
provideLicense "obj/NuGet"
94+
provideReadme header (sprintf "%s v%s" pack.Title pack.NuGet.Release.PackageVersion) pack.NuGet.Release "obj/NuGet"
95+
NuGet.NuGet (updateNuspec pack.NuGet solution.OutputNuGetDir pack.Dependencies) pack.NuSpecFile
96+
Shell.cleanDir "obj/NuGet"
97+
Directory.delete "obj/NuGet"

build/Preparing.fs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
module Preparing
2+
3+
open FSharp.Core
4+
open Fake.Core
5+
open Fake.IO
6+
7+
open Model
8+
9+
let private regexes_sl = new System.Collections.Generic.Dictionary<string, System.Text.RegularExpressions.Regex>()
10+
let private getRegexSingleLine pattern =
11+
match regexes_sl.TryGetValue pattern with
12+
| true, regex -> regex
13+
| _ -> (System.Text.RegularExpressions.Regex(pattern, System.Text.RegularExpressions.RegexOptions.Singleline))
14+
let regex_replace_singleline pattern (replacement : string) text = (getRegexSingleLine pattern).Replace(text, replacement)
15+
16+
let patchVersionInResource path (release:Release) =
17+
File.applyReplace
18+
(String.regex_replace @"\d+\.\d+\.\d+\.\d+" release.AssemblyVersion
19+
>> String.regex_replace @"\d+,\d+,\d+,\d+" (String.replace "." "," release.AssemblyVersion))
20+
path
21+
22+
let patchVersionInProjectFile (project:Project) =
23+
match project with
24+
| VisualStudio p ->
25+
let semverSplit = p.Release.PackageVersion.IndexOf('-')
26+
let prefix = if semverSplit <= 0 then p.Release.PackageVersion else p.Release.PackageVersion.Substring(0, semverSplit)
27+
let suffix = if semverSplit <= 0 then "" else p.Release.PackageVersion.Substring(semverSplit+1)
28+
File.applyReplace
29+
(String.regex_replace """\<PackageVersion\>.*\</PackageVersion\>""" (sprintf """<PackageVersion>%s</PackageVersion>""" p.Release.PackageVersion)
30+
>> String.regex_replace """\<Version\>.*\</Version\>""" (sprintf """<Version>%s</Version>""" p.Release.PackageVersion)
31+
>> String.regex_replace """\<AssemblyVersion\>.*\</AssemblyVersion\>""" (sprintf """<AssemblyVersion>%s</AssemblyVersion>""" p.Release.AssemblyVersion)
32+
>> String.regex_replace """\<FileVersion\>.*\</FileVersion\>""" (sprintf """<FileVersion>%s</FileVersion>""" p.Release.AssemblyVersion)
33+
>> String.regex_replace """\<VersionPrefix\>.*\</VersionPrefix\>""" (sprintf """<VersionPrefix>%s</VersionPrefix>""" prefix)
34+
>> String.regex_replace """\<VersionSuffix\>.*\</VersionSuffix\>""" (sprintf """<VersionSuffix>%s</VersionSuffix>""" suffix)
35+
>> regex_replace_singleline """\<PackageReleaseNotes\>.*\</PackageReleaseNotes\>""" (sprintf """<PackageReleaseNotes>%s</PackageReleaseNotes>""" (p.Release.ReleaseNotes.Replace("<","&lt;").Replace(">","&gt;"))))
36+
p.ProjectFile
37+
| NativeVisualStudio _ -> ()
38+
| NativeBashScript _ -> ()

0 commit comments

Comments
 (0)