Nuke.Cola
Loading...
Searching...
No Matches
DotnetCommon.cs
1using System.Reflection;
2using Nuke.Common.IO;
3using Nuke.Common.Tooling;
4using Nuke.Common.Tools.DotNet;
5using Nuke.Common.Tools.MSBuild;
6using Nuke.Common.Utilities.Collections;
7using Dotnet.Script.Core.Commands;
8using Dotnet.Script.DependencyModel.Logging;
9using Dotnet.Script.DependencyModel.Environment;
10using Standart.Hash.xxHash;
11using Dotnet.Script.Core;
12using Microsoft.CodeAnalysis;
13
15
16internal record ScriptDllLocation(
17 AbsolutePath Path,
18 ulong ContentHash,
19 uint PathHash
20);
21
22internal static class DotnetCommon
23{
24 private static LogFactory? DotnetScriptLogFactoryInstance = null;
25 private static LogFactory DotnetScriptLogFactory => DotnetScriptLogFactoryInstance
26 ??= new(type => (level, message, except) =>
27 {
28 if (level > LogLevel.Debug)
29 message.Log();
30 });
31
32 internal static ScriptDllLocation GetDllLocationOfScript(AbsolutePath scriptPath, AbsolutePath outputDirIn)
33 {
34 uint pathHash = xxHash32.ComputeHash(scriptPath);
35 ulong hash = xxHash64.ComputeHash(scriptPath.ReadAllText());
36 var dllName = hash.ToString();
37 var outputDir = outputDirIn / (pathHash.ToString() + "_" + dllName);
38 return new(outputDir / (dllName + ".dll"), hash, pathHash);
39 }
40
41 /// <summary>
42 /// Compiles a C# script into a DLL with dotnet-script, which needs to be installed
43 /// at least into the context of the provided working directory before using this
44 /// function. The resulting binary will have a GUID as a file name.
45 /// </summary>
46 /// <param name="scriptPath">Path to a *.csx file</param>
47 /// <param name="outputDirIn">
48 /// The parent directory in which the directory of published binaries will be put
49 /// </param>
50 /// <returns>The path of the newly created DLL</returns>
51 internal static AbsolutePath CompileScript(AbsolutePath scriptPath, AbsolutePath outputDirIn)
52 {
53 var (dllPath, contentHash, pathHash) = GetDllLocationOfScript(scriptPath, outputDirIn);
54
55 if (dllPath.FileExists())
56 return dllPath;
57
58 $"Compiling script {scriptPath}".Log();
59
60 dllPath.Parent.CreateOrCleanDirectory();
61 new PublishCommand(ScriptConsole.Default, DotnetScriptLogFactory).Execute(new(
62 new(scriptPath),
63 dllPath.Parent,
64 contentHash.ToString(),
65 PublishType.Library,
66 OptimizationLevel.Debug,
67 [],
68 ScriptEnvironment.Default.RuntimeIdentifier,
69 null,
70 false
71 ));
72
73 // Remove residue of previous build results
74 outputDirIn
75 .GlobDirectories($"{pathHash}_*")
76 .Where(p => !p.Name.Contains(contentHash.ToString()))
77 .ForEach(p => p.DeleteDirectory());
78
79 return dllPath;
80 }
81
82 internal static AbsolutePath CompileProject(AbsolutePath projectPath, AbsolutePath outputDirIn)
83 {
84 ulong projectHash = xxHash64.ComputeHash(File.ReadAllText(projectPath));
85 ulong hash = projectPath.Parent.GlobFiles("**/*.cs")
86 .Aggregate(projectHash, (h, p) =>
87 h ^ xxHash64.ComputeHash(File.ReadAllText(p))
88 );
89
90 var dllName = projectPath.NameWithoutExtension;
91 var outputDir = outputDirIn / $"{dllName}_{hash}";
92 var dllPath = outputDir / (dllName + ".dll");
93
94 if (outputDir.DirectoryExists() && dllPath.FileExists())
95 {
96 return dllPath;
97 }
98
99 $"Compiling project {projectPath}".Log();
100
101 outputDir.CreateOrCleanDirectory();
102
103 DotNetTasks.DotNetBuild(_ => _
104 .SetNoLogo(true)
105 .SetProjectFile(projectPath)
106 .SetOutputDirectory(outputDir)
107 .SetConfiguration("Debug")
108 .SetProcessWorkingDirectory(projectPath.Parent)
109 );
110
111 outputDirIn
112 .GlobDirectories($"{dllName}_*")
113 .Where(p => !p.Name.Contains(hash.ToString()))
114 .ForEach(p => p.DeleteDirectory());
115
116 return dllPath;
117 }
118
119 /// <summary>
120 /// Get the build interfaces of an input assembly inheriting Nuke.Common.INukeBuild
121 /// </summary>
122 internal static IEnumerable<Importable> GetBuildInterfaces(this Assembly assembly, AbsolutePath? sourcePath = null, bool importViaSource = false)
123 => assembly.GetTypes()
124 .Where(t => t.IsInterface)
125 .Where(t => t.GetInterfaces().Any(i => i.FullName == "Nuke.Common.INukeBuild"))
126 .Select(t => new Importable(t, sourcePath, importViaSource));
127
128 internal static void Log(this string text)
129 {
130 if (!Environment.CommandLine.Contains(" :complete"))
131 {
132 Console.WriteLine(text);
133 }
134 }
135}
static AbsolutePath CompileScript(AbsolutePath scriptPath, AbsolutePath outputDirIn)
Compiles a C# script into a DLL with dotnet-script, which needs to be installed at least into the con...
static IEnumerable< Importable > GetBuildInterfaces(this Assembly assembly, AbsolutePath? sourcePath=null, bool importViaSource=false)
Get the build interfaces of an input assembly inheriting Nuke.Common.INukeBuild.
record class Importable(Type Interface, AbsolutePath? Source=null, bool ImportViaSource=false)
A record for storing compiled build plugin interfaces.
Definition Importable.cs:18