-
Notifications
You must be signed in to change notification settings - Fork 2
/
Helpers.fs
371 lines (302 loc) · 13.2 KB
/
Helpers.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
namespace Aardvark.Fake
open System
open System.Reflection
open System.IO
open System.IO.Compression
open Fake
open Fake.Core
open Fake.IO
open System.Runtime.InteropServices
[<AutoOpen>]
module PathHelpersAssembly =
type Path with
static member ChangeFilename(path : string, newName : string -> string) =
let dir = Path.GetDirectoryName(path)
let name = Path.GetFileNameWithoutExtension path
let ext = Path.GetExtension(path)
Path.Combine(dir, (newName name) + ext)
module AssemblyResources =
open System
open Mono.Cecil
open System.IO
open System.IO.Compression
open System.Collections.Generic
let rec addFolderToArchive (path : string) (folder : string) (archive : ZipArchive) =
let files = Directory.GetFiles(folder)
for f in files do
printfn "adding file: %A" f
archive.CreateEntryFromFile(f, Path.Combine(path, Path.GetFileName f)) |> ignore
()
let sd = Directory.GetDirectories(folder)
for d in sd do
let p = Path.Combine(path, Path.GetFileName d)
addFolderToArchive p d archive
let useDir d f =
let old = System.Environment.CurrentDirectory
System.Environment.CurrentDirectory <- d
try
let r = f ()
r
finally
System.Environment.CurrentDirectory <- old
let addFolder' (folder : string) (assemblyPath : string) (symbols : bool) =
useDir (Path.Combine("bin","Release")) (fun () ->
let pdbPath = Path.ChangeExtension(assemblyPath, "pdb")
let symbols =
// only process symbols if they exist and we are on not on unix like systems (they use mono symbols).
// this means: at the moment only windows packages support pdb debugging.
File.Exists (pdbPath) && System.Environment.OSVersion.Platform <> PlatformID.Unix && symbols
let bytes = new MemoryStream(File.ReadAllBytes assemblyPath)
let pdbStream =
if symbols then
new MemoryStream(File.ReadAllBytes pdbPath)
else
null
let r = ReaderParameters()
if symbols then
r.SymbolReaderProvider <- Mono.Cecil.Pdb.PdbReaderProvider()
r.SymbolStream <- pdbStream
r.ReadSymbols <- symbols
let a = AssemblyDefinition.ReadAssembly(bytes,r)
//let a = AssemblyDefinition.ReadAssembly(assemblyPath,ReaderParameters(ReadSymbols=symbols))
// remove the old resource (if any)
let res = a.MainModule.Resources |> Seq.tryFind (fun r -> r.Name = "native.zip")
match res with
| Some res -> a.MainModule.Resources.Remove res |> ignore
| None -> ()
let temp = System.IO.Path.GetTempFileName()
let data =
try
let mem = File.OpenWrite(temp)
let archive = new ZipArchive(mem, ZipArchiveMode.Create, true)
addFolderToArchive "" folder archive
// create and add the new resource
archive.Dispose()
mem.Close()
Trace.logfn "archive size: %d bytes" (FileInfo(temp).Length)
let b = File.ReadAllBytes(temp) //mem.ToArray()
Trace.logfn "archived native dependencies with size: %d bytes" b.Length
b
finally
File.Delete(temp)
let r = EmbeddedResource("native.zip", ManifestResourceAttributes.Public, data)
a.MainModule.Resources.Add(r)
a.Write(assemblyPath, WriterParameters(WriteSymbols = symbols))
//a.Write(WriterParameters(WriteSymbols=symbols))
a.Dispose()
//
// let pdbPath = Path.ChangeExtension(assemblyPath, ".pdb")
// let tempPath = Path.ChangeFilename(assemblyPath, fun a -> a + "Tmp")
// let tempPdb = Path.ChangeExtension(tempPath, ".pdb")
//
// a.Write( tempPath, WriterParameters(WriteSymbols=symbols))
// a.Dispose()
//
// File.Delete assemblyPath
// File.Move(tempPath, assemblyPath)
//
// if File.Exists tempPdb then
// File.Delete pdbPath
// File.Move(tempPdb, pdbPath)
Trace.logfn "added native resources to %A" (Path.GetFileName assemblyPath)
)
let addFolder (folder : string) (assemblyPath : string) =
addFolder' folder assemblyPath true
let getFilesAndFolders (folder : string) =
if Directory.Exists folder then Directory.GetFileSystemEntries folder
else [||]
let copy (dstFolder : string) (source : string) =
let f = FileInfo source
if f.Exists then
if Directory.Exists dstFolder |> not then Directory.CreateDirectory dstFolder |> ignore
Shell.copyFile dstFolder source
else
let di = DirectoryInfo source
if di.Exists then
let dst = Path.Combine(dstFolder, di.Name)
if Directory.Exists dst |> not then Directory.CreateDirectory dst |> ignore
Shell.copyRecursive source dst true |> ignore
()
let copyDependencies (folder : string) (targets : seq<string>) =
let arch =
match RuntimeInformation.OSArchitecture with
| Architecture.X64 -> "AMD64"
| Architecture.X86 -> "x86"
| _ -> "unknown"
let targets = targets |> Seq.toArray
let platform =
if RuntimeInformation.IsOSPlatform OSPlatform.Windows then "windows"
elif RuntimeInformation.IsOSPlatform OSPlatform.OSX then "mac"
elif RuntimeInformation.IsOSPlatform OSPlatform.Linux then "linux"
else "windows"
for t in targets do
getFilesAndFolders(Path.Combine(folder, platform, arch))
|> Seq.iter (copy t)
getFilesAndFolders(Path.Combine(folder, platform))
|> Array.filter (fun f ->
let n = Path.GetFileName(f)
n <> "x86" && n <> "AMD64"
)
|> Seq.iter (copy t)
getFilesAndFolders(Path.Combine(folder, arch))
|> Seq.iter (copy t)
getFilesAndFolders(folder)
|> Array.filter (fun f ->
let n = Path.GetFileName(f)
n <> "x86" && n <> "AMD64" && n <> "windows" && n <> "linux" && n <> "mac"
)
|> Seq.iter (copy t)
module Helpers =
open Fake.Core
open Fake.Tools.Git
let initializeContext () =
let execContext = Context.FakeExecutionContext.Create false "build.fsx" [ ]
Context.setExecutionContext (Context.RuntimeContext.Fake execContext)
module Proc =
module Parallel =
open System
let locker = obj()
let colors =
[| ConsoleColor.Blue
ConsoleColor.Yellow
ConsoleColor.Magenta
ConsoleColor.Cyan
ConsoleColor.DarkBlue
ConsoleColor.DarkYellow
ConsoleColor.DarkMagenta
ConsoleColor.DarkCyan |]
let print color (colored: string) (line: string) =
lock locker
(fun () ->
let currentColor = Console.ForegroundColor
Console.ForegroundColor <- color
Console.Write colored
Console.ForegroundColor <- currentColor
Console.WriteLine line)
let onStdout index name (line: string) =
let color = colors.[index % colors.Length]
if isNull line then
print color $"{name}: --- END ---" ""
else if String.isNotNullOrEmpty line then
print color $"{name}: " line
let onStderr name (line: string) =
let color = ConsoleColor.Red
if isNull line |> not then
print color $"{name}: " line
let redirect (index, (name, createProcess)) =
createProcess
|> CreateProcess.redirectOutputIfNotRedirected
|> CreateProcess.withOutputEvents (onStdout index name) (onStderr name)
let printStarting indexed =
for (index, (name, c: CreateProcess<_>)) in indexed do
let color = colors.[index % colors.Length]
let wd =
c.WorkingDirectory
|> Option.defaultValue ""
let exe = c.Command.Executable
let args = c.Command.Arguments.ToStartInfo
print color $"{name}: {wd}> {exe} {args}" ""
let run cs =
cs
|> Seq.toArray
|> Array.indexed
|> fun x -> printStarting x; x
|> Array.map redirect
|> Array.Parallel.map Proc.run
let createProcess exe arg dir =
CreateProcess.fromRawCommandLine exe arg
|> CreateProcess.withWorkingDirectory dir
|> CreateProcess.ensureExitCode
let dotnet = createProcess "dotnet"
let npm =
let npmPath =
match ProcessUtils.tryFindFileOnPath "npm" with
| Some path -> path
| None ->
"npm was not found in path. Please install it and make sure it's available from your path. " +
"See https://safe-stack.github.io/docs/quickstart/#install-pre-requisites for more info"
|> failwith
createProcess npmPath
let run proc arg dir =
proc arg dir
|> Proc.run
|> ignore
let runParallel processes =
processes
|> Proc.Parallel.run
|> ignore
let runOrDefault args =
try
match args with
| [| target |] -> Target.runOrDefault target
| _ -> Target.runOrDefault "Run"
0
with e ->
printfn "%A" e
1
module NugetInfo =
let defaultValue (fallback : 'a) (o : Option<'a>) =
match o with
| Some o -> o
| None -> fallback
let private adjust (v : PreRelease) =
let o =
let number = v.Values |> List.tryPick (function PreReleaseSegment.Numeric n -> Some n | _ -> None)
match number with
| Some n -> sprintf "%s%04d" v.Name (int n)
| None -> v.Name
{ v with
Origin = o
Values = [AlphaNumeric o]
}
let nextVersion (major : bool) (prerelease : bool) (v : string) =
let v : SemVerInfo = SemVer.parse v
let version =
match v.PreRelease with
| Some _ when prerelease -> { v with Original = None }
| Some _ -> { v with PreRelease = None; Original = None }
| _ ->
match major with
| false -> { v with Patch = v.Patch + 1u; Original = None }
| true -> { v with Minor = v.Minor + 1u; Patch = 0u; Original = None }
if prerelease then
let incrementPreRelease (s : PreReleaseSegment) =
let prefix = "prerelease"
let increment (number : string) =
match System.Int32.TryParse number with
| true, n -> Some <| bigint (n + 1)
| _ -> None
match s with
| Numeric n -> Numeric (n + bigint 1)
| AlphaNumeric str as o ->
if str.StartsWith prefix then
increment (str.Substring prefix.Length)
|> Option.map Numeric
|> Option.defaultValue o
else
o
let pre =
version.PreRelease |> Option.map (fun p ->
{ p with Values = p.Values |> List.map incrementPreRelease }
)
let def =
{
Origin = "prerelease1"
Name = "prerelease"
Values = [ AlphaNumeric "prerelease"; Numeric (bigint 1) ]
}
{ version with PreRelease = pre |> defaultValue def |> adjust |> Some }.ToString()
else
{ version with PreRelease = None}.ToString()
let assemblyVersion (vstr : string) =
let v : SemVerInfo = SemVer.parse vstr
sprintf "%d.%d.0.0" v.Major v.Minor
let getGitTag() =
let ok,msg,errors = CommandHelper.runGitCommand "." "describe --abbrev=0"
if ok && msg.Length >= 1 then
let tag = msg.[0]
tag
else
let err = sprintf "no tag: %A" errors
Trace.traceError err
failwith err