forked from dotnet/sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
/
LockFileCache.cs
136 lines (117 loc) · 4.63 KB
/
LockFileCache.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
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
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using Microsoft.Build.Framework;
using NuGet.Common;
using NuGet.ProjectModel;
namespace Microsoft.NET.Build.Tasks
{
internal class LockFileCache
{
private IBuildEngine4 _buildEngine;
private Logger _log;
public LockFileCache(TaskBase task)
{
_buildEngine = task.BuildEngine4;
_log = task.Log;
}
public LockFile GetLockFile(string path)
{
if (string.IsNullOrEmpty(path))
{
throw new BuildErrorException(Strings.AssetsFileNotSet);
}
if (!Path.IsPathRooted(path))
{
throw new BuildErrorException(Strings.AssetsFilePathNotRooted, path);
}
string lockFileKey = GetTaskObjectKey(path);
LockFile result;
object existingLockFileTaskObject = _buildEngine?.GetRegisteredTaskObject(lockFileKey, RegisteredTaskObjectLifetime.Build);
if (existingLockFileTaskObject == null)
{
result = LoadLockFile(path);
_buildEngine?.RegisterTaskObject(lockFileKey, result, RegisteredTaskObjectLifetime.Build, true);
}
else
{
result = (LockFile)existingLockFileTaskObject;
}
return result;
}
private static string GetTaskObjectKey(string lockFilePath)
{
return $"{nameof(LockFileCache)}:{lockFilePath}";
}
private LockFile LoadLockFile(string path)
{
// https://github.com/NuGet/Home/issues/6732
//
// LockFileUtilties.GetLockFile has odd error handling:
//
// 1. Exceptions creating TextReader from path (after up to 3 tries) will
// bubble out.
//
// 2. There's an up-front File.Exists that returns null without logging
// anything.
//
// 3. Any other exception whatsoever is logged by its Message property
// alone, and an empty, non-null lock file is returned.
//
// This wrapper will never return null or empty lock file and instead throw
// if the assets file is not found or cannot be read for any other reason.
LockFile lockFile;
try
{
lockFile = LockFileUtilities.GetLockFile(
path,
new ThrowOnLockFileLoadError(_log));
}
catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException)
{
// Case 1
throw new BuildErrorException(
string.Format(Strings.ErrorReadingAssetsFile, ex.Message),
ex);
}
if (lockFile == null)
{
// Case 2
// NB: Cannot be moved to our own up-front File.Exists check or else there would be
// a race where we still need to handle null for delete between our check and
// NuGet's.
throw new BuildErrorException(Strings.AssetsFileNotFound, path);
}
return lockFile;
}
// Case 3
// Force an exception on errors reading the lock file
// Non-errors are not logged today, but push them to the build log in case they are in the future.
private sealed class ThrowOnLockFileLoadError : LoggerBase
{
private Logger _log;
public ThrowOnLockFileLoadError(Logger log)
{
_log = log;
}
public override void Log(ILogMessage message)
{
if (message.Level == LogLevel.Error)
{
throw new BuildErrorException(
string.Format(Strings.ErrorReadingAssetsFile, message.Message));
}
_log.Log(
new Message(
level: message.Level == LogLevel.Warning ? MessageLevel.Warning : MessageLevel.NormalImportance,
code: message.Code == NuGetLogCode.Undefined ? default : message.Code.ToString(),
file: message.ProjectPath,
text: message.Message));
}
public override System.Threading.Tasks.Task LogAsync(ILogMessage message)
{
Log(message);
return Task.CompletedTask;
}
}
}
}