forked from dotnet/sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
/
NugetContentAssetPreprocessor.cs
78 lines (67 loc) · 3.13 KB
/
NugetContentAssetPreprocessor.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
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.IO.Hashing;
using NuGet.Common;
namespace Microsoft.NET.Build.Tasks
{
internal class NugetContentAssetPreprocessor : IContentAssetPreprocessor
{
private Dictionary<string, string> _preprocessorValues = new();
private string _preprocessedOutputDirectory = null;
public void ConfigurePreprocessor(string outputDirectoryBase, Dictionary<string, string> preprocessorValues)
{
_preprocessorValues = preprocessorValues ?? new Dictionary<string, string>();
_preprocessedOutputDirectory = Path.Combine(outputDirectoryBase, BuildPreprocessedContentHash(_preprocessorValues));
}
public bool Process(string originalAssetPath, string relativeOutputPath, out string pathToFinalAsset)
{
if (_preprocessedOutputDirectory == null)
{
throw new InvalidOperationException(Strings.AssetPreprocessorMustBeConfigured);
}
bool fileWritten = false;
pathToFinalAsset = Path.Combine(_preprocessedOutputDirectory, relativeOutputPath);
if (!File.Exists(pathToFinalAsset))
{
Directory.CreateDirectory(Path.GetDirectoryName(pathToFinalAsset));
using (FileStream input = File.OpenRead(originalAssetPath))
{
string result = Preprocessor.Process(input, (token) =>
{
string value;
if (!_preprocessorValues.TryGetValue(token, out value))
{
throw new BuildErrorException(Strings.UnrecognizedPreprocessorToken, $"${token}$", originalAssetPath);
}
return value;
});
File.WriteAllText(pathToFinalAsset, result);
fileWritten = true;
}
}
return fileWritten;
}
/// <summary>
/// Produces a string hash of the key/values in the dictionary. This hash is used to put all the
/// preprocessed files into a folder with the name so we know to regenerate when any of the
/// inputs change.
/// </summary>
private static string BuildPreprocessedContentHash(IReadOnlyDictionary<string, string> values)
{
using (var stream = new MemoryStream())
{
using (var streamWriter = new StreamWriter(stream, Encoding.UTF8, bufferSize: 4096, leaveOpen: true))
{
foreach (var pair in values.OrderBy(v => v.Key))
{
streamWriter.Write(pair.Key);
streamWriter.Write('\0');
streamWriter.Write(pair.Value);
streamWriter.Write('\0');
}
}
return BitConverter.ToString(XxHash3.Hash(stream.GetBuffer().AsSpan(0, (int)stream.Length))).Replace("-", "");
}
}
}
}