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 false
70 ));
71
72 // Remove residue of previous build results
73 outputDirIn
74 .GlobDirectories($"{pathHash}_*")
75 .Where(p => !p.Name.Contains(contentHash.ToString()))
76 .ForEach(p => p.DeleteDirectory());
77
78 return dllPath;
79 }
80
81 internal static AbsolutePath CompileProject(AbsolutePath projectPath, AbsolutePath outputDirIn)
82 {
83 ulong projectHash = xxHash64.ComputeHash(File.ReadAllText(projectPath));
84 ulong hash = projectPath.Parent.GlobFiles("**/*.cs")
85 .Aggregate(projectHash, (h, p) =>
86 h ^ xxHash64.ComputeHash(File.ReadAllText(p))
87 );
88
89 var dllName = projectPath.NameWithoutExtension;
90 var outputDir = outputDirIn / $"{dllName}_{hash}";
91 var dllPath = outputDir / (dllName + ".dll");
92
93 if (outputDir.DirectoryExists() && dllPath.FileExists())
94 {
95 return dllPath;
96 }
97
98 $"Compiling project {projectPath}".Log();
99
100 outputDir.CreateOrCleanDirectory();
101
102 DotNetTasks.DotNetBuild(_ => _
103 .SetNoLogo(true)
104 .SetProjectFile(projectPath)
105 .SetOutputDirectory(outputDir)
106 .SetConfiguration("Debug")
107 .SetProcessWorkingDirectory(projectPath.Parent)
108 );
109
110 outputDirIn
111 .GlobDirectories($"{dllName}_*")
112 .Where(p => !p.Name.Contains(hash.ToString()))
113 .ForEach(p => p.DeleteDirectory());
114
115 return dllPath;
116 }
117
118 /// <summary>
119 /// Get the build interfaces of an input assembly inheriting Nuke.Common.INukeBuild
120 /// </summary>
121 internal static IEnumerable<Importable> GetBuildInterfaces(this Assembly assembly, AbsolutePath? sourcePath = null, bool importViaSource = false)
122 => assembly.GetTypes()
123 .Where(t => t.IsInterface)
124 .Where(t => t.GetInterfaces().Any(i => i.FullName == "Nuke.Common.INukeBuild"))
125 .Select(t => new Importable(t, sourcePath, importViaSource));
126
127 internal static void Log(this string text)
128 {
129 if (!Environment.CommandLine.Contains(" :complete"))
130 {
131 Console.WriteLine(text);
132 }
133 }
134}
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