2 people like it.
Like the snippet!
ContextAwareTask.fs
ContextAwareTask implementation from https://github.com/dotnet/Nerdbank.GitVersioning/blob/master/src/Nerdbank.GitVersioning.Tasks/ContextAwareTask.cs
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:
|
open System;
open System.IO;
open System.Linq;
open System.Reflection;
#if NETCOREAPP2_0
open System.Runtime.Loader;
#endif
open Microsoft.Build.Framework;
open Microsoft.Build.Utilities;
[<AbstractClass>]
type public ContextAwareTask () as cat =
inherit Task()
let ``type`` = cat.GetType()
let typeInfo = ``type``.GetTypeInfo()
abstract ManagedDllDirectory : string with get
default _.ManagedDllDirectory
with get() =
let codeBase = typeInfo.Assembly.CodeBase
let uri = new Uri(codeBase)
Path.GetDirectoryName(uri.LocalPath)
abstract UnmanagedDllDirectory : string with get
default _.UnmanagedDllDirectory with get () = null
abstract member ExecuteInner: unit -> bool
override this.Execute() =
#if NETCOREAPP2_0
let taskAssemblyPath = Uri(typeInfo.Assembly.CodeBase).LocalPath
let ctxt = CustomAssemblyLoader(this)
let inContextAssembly = ctxt.LoadFromAssemblyPath(taskAssemblyPath)
let innerTaskType = inContextAssembly.GetType(``type``.FullName)
let innerTask = Activator.CreateInstance(innerTaskType)
let outerProperties = ``type``.GetRuntimeProperties().ToDictionary(fun i -> i.Name);
let innerProperties = innerTaskType.GetRuntimeProperties().ToDictionary(fun i -> i.Name);
let propertiesDiscovery =
outerProperties.Values
|> Seq.filter (fun outerProperty -> outerProperty.SetMethod != null && outerProperty.GetMethod != null)
|> Seq.map
(fun outerProperty ->
let innerProperty = innerProperties.[outerProperty.Name]
(outerProperty, innerProperty))
let propertiesMap = propertiesDiscovery |> Seq.toArray
let outputPropertiesMap =
propertiesDiscovery
|> Seq.filter (fun (outerProperty, _) -> outerProperty.GetCustomAttribute<OutputAttribute>() != null)
let propertiesMap =
propertiesMap
|> Seq.map
(fun pair ->
let outerPropertyValue = (fst pair).GetValue(this)
(snd pair).SetValue(innerTask, outerPropertyValue)
pair)
let executeInnerMethod =
innerTaskType.GetMethod(nameof(this.ExecuteInner), (BindingFlags.Instance ||| BindingFlags.NonPublic))
let result = executeInnerMethod.Invoke(innerTask, Array.empty) :?> bool
let outputPropertiesMap =
outputPropertiesMap
|> Seq.map
(fun pair ->
(fst pair).SetValue(this, (snd pair).GetValue(innerTask)))
result
#else
// On .NET Framework (on Windows), we find native binaries by adding them to our PATH.
if not (this.UnmanagedDllDirectory = null) then
let pathEnvVar = Environment.GetEnvironmentVariable("PATH")
let searchPaths = pathEnvVar.Split(Path.PathSeparator)
if not (searchPaths.Contains(this.UnmanagedDllDirectory, StringComparer.OrdinalIgnoreCase)) then
let pathEnvVar = $"{pathEnvVar}{Path.PathSeparator}{this.UnmanagedDllDirectory}"
Environment.SetEnvironmentVariable("PATH", pathEnvVar)
this.ExecuteInner()
#endif
#if NETCOREAPP2_0
type private CustomAssemblyLoader(loaderTask: ContextAwareTask) =
inherit AssemblyLoadContext
let loaderTask = loaderTask
override this.Load(assemblyName: AssemblyName) : Assembly =
let assemblyPath = Path.Combine(this.loaderTask.ManagedDllDirectory, assemblyName.Name) + ".dll"
if File.Exists(assemblyPath) then
LoadFromAssemblyPath(assemblyPath)
Default.LoadFromAssemblyName(assemblyName)
override LoadUnmanagedDll(unmanagedDllName: string) : IntPtr =
let unmanagedDllPath =
Directory.EnumerateFiles(
this.loaderTask.UnmanagedDllDirectory,
$"{unmanagedDllName}.*").Concat(
Directory.EnumerateFiles(
this.loaderTask.UnmanagedDllDirectory,
$"lib{unmanagedDllName}.*"))
.FirstOrDefault()
if unmanagedDllPath != null then
this.LoadUnmanagedDllFromPath(unmanagedDllPath)
base.LoadUnmanagedDll(unmanagedDllName)
#endif
|
namespace System
namespace System.IO
namespace System.Linq
namespace System.Reflection
namespace Microsoft
namespace Microsoft.Build
namespace Microsoft.Build.Framework
Multiple items
type AbstractClassAttribute =
inherit Attribute
new : unit -> AbstractClassAttribute
--------------------
new : unit -> AbstractClassAttribute
Multiple items
type ContextAwareTask =
inherit obj
new : unit -> ContextAwareTask
abstract member ExecuteInner : unit -> bool
abstract member ManagedDllDirectory : string
abstract member UnmanagedDllDirectory : string
override Execute : unit -> 'a
override ManagedDllDirectory : string
override UnmanagedDllDirectory : string
--------------------
new : unit -> ContextAwareTask
val cat : ContextAwareTask
Multiple items
val string : value:'T -> string
--------------------
type string = String
Multiple items
type Uri =
new : uriString:string -> Uri + 5 overloads
member AbsolutePath : string
member AbsoluteUri : string
member Authority : string
member DnsSafeHost : string
member Equals : comparand:obj -> bool
member Fragment : string
member GetComponents : components:UriComponents * format:UriFormat -> string
member GetHashCode : unit -> int
member GetLeftPart : part:UriPartial -> string
...
--------------------
Uri(uriString: string) : Uri
Uri(uriString: string, uriKind: UriKind) : Uri
Uri(baseUri: Uri, relativeUri: string) : Uri
Uri(baseUri: Uri, relativeUri: Uri) : Uri
type Path =
static val DirectorySeparatorChar : char
static val AltDirectorySeparatorChar : char
static val VolumeSeparatorChar : char
static val PathSeparator : char
static val InvalidPathChars : char[]
static member ChangeExtension : path:string * extension:string -> string
static member Combine : [<ParamArray>] paths:string[] -> string + 3 overloads
static member EndsInDirectorySeparator : path:ReadOnlySpan<char> -> bool + 1 overload
static member GetDirectoryName : path:string -> string + 1 overload
static member GetExtension : path:string -> string + 1 overload
...
Path.GetDirectoryName(path: ReadOnlySpan<char>) : ReadOnlySpan<char>
Path.GetDirectoryName(path: string) : string
type unit = Unit
type bool = Boolean
val not : value:bool -> bool
type Environment =
static member CommandLine : string
static member CurrentDirectory : string with get, set
static member CurrentManagedThreadId : int
static member Exit : exitCode:int -> unit
static member ExitCode : int with get, set
static member ExpandEnvironmentVariables : name:string -> string
static member FailFast : message:string -> unit + 2 overloads
static member GetCommandLineArgs : unit -> string[]
static member GetEnvironmentVariable : variable:string -> string + 1 overload
static member GetEnvironmentVariables : unit -> IDictionary + 1 overload
...
nested type SpecialFolder
nested type SpecialFolderOption
Environment.GetEnvironmentVariable(variable: string) : string
Environment.GetEnvironmentVariable(variable: string, target: EnvironmentVariableTarget) : string
field Path.PathSeparator: char
type StringComparer =
member Compare : x:obj * y:obj -> int + 1 overload
member Equals : x:obj * y:obj -> bool + 1 overload
member GetHashCode : obj:obj -> int + 1 overload
static member Create : culture:CultureInfo * ignoreCase:bool -> StringComparer + 1 overload
static member CurrentCulture : StringComparer
static member CurrentCultureIgnoreCase : StringComparer
static member FromComparison : comparisonType:StringComparison -> StringComparer
static member InvariantCulture : StringComparer
static member InvariantCultureIgnoreCase : StringComparer
static member Ordinal : StringComparer
...
property StringComparer.OrdinalIgnoreCase: StringComparer with get
More information