-
Notifications
You must be signed in to change notification settings - Fork 222
/
Copy pathLockManagementService.cs
135 lines (133 loc) · 6.45 KB
/
LockManagementService.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
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
namespace Kiota.Builder.Lock;
/// <summary>
/// A service that manages the lock file for a Kiota project implemented using the file system.
/// </summary>
public class LockManagementService : ILockManagementService
{
private const string LockFileName = "kiota-lock.json";
/// <inheritdoc/>
public IEnumerable<string> GetDirectoriesContainingLockFile(string searchDirectory)
{
ArgumentException.ThrowIfNullOrEmpty(searchDirectory);
var files = Directory.GetFiles(searchDirectory, LockFileName, SearchOption.AllDirectories);
return files.Select(Path.GetDirectoryName).Where(x => !string.IsNullOrEmpty(x)).OfType<string>();
}
/// <inheritdoc/>
public Task<KiotaLock?> GetLockFromDirectoryAsync(string directoryPath, CancellationToken cancellationToken = default)
{
ArgumentException.ThrowIfNullOrEmpty(directoryPath);
return GetLockFromDirectoryInternalAsync(directoryPath, cancellationToken);
}
private static async Task<KiotaLock?> GetLockFromDirectoryInternalAsync(string directoryPath, CancellationToken cancellationToken)
{
var lockFilePath = Path.Combine(directoryPath, LockFileName);
if (File.Exists(lockFilePath))
{
#pragma warning disable CA2007
await using var fileStream = File.OpenRead(lockFilePath);
#pragma warning restore CA2007
var result = await GetLockFromStreamInternalAsync(fileStream, cancellationToken).ConfigureAwait(false);
if (result is not null && IsDescriptionLocal(result.DescriptionLocation) && !Path.IsPathRooted(result.DescriptionLocation))
{
result.DescriptionLocation = Path.GetFullPath(Path.Combine(directoryPath, result.DescriptionLocation));
}
return result;
}
return null;
}
/// <inheritdoc/>
public Task<KiotaLock?> GetLockFromStreamAsync(Stream stream, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(stream);
return GetLockFromStreamInternalAsync(stream, cancellationToken);
}
private static async Task<KiotaLock?> GetLockFromStreamInternalAsync(Stream stream, CancellationToken cancellationToken)
{
return await JsonSerializer.DeserializeAsync(stream, context.KiotaLock, cancellationToken).ConfigureAwait(false);
}
/// <inheritdoc/>
public Task WriteLockFileAsync(string directoryPath, KiotaLock lockInfo, CancellationToken cancellationToken = default)
{
ArgumentException.ThrowIfNullOrEmpty(directoryPath);
ArgumentNullException.ThrowIfNull(lockInfo);
return WriteLockFileInternalAsync(directoryPath, lockInfo, cancellationToken);
}
private static readonly JsonSerializerOptions options = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true,
};
private static readonly KiotaLockGenerationContext context = new(options);
private static async Task WriteLockFileInternalAsync(string directoryPath, KiotaLock lockInfo, CancellationToken cancellationToken)
{
var lockFilePath = Path.Combine(directoryPath, LockFileName);
#pragma warning disable CA2007
await using var fileStream = File.Open(lockFilePath, FileMode.Create);
#pragma warning restore CA2007
lockInfo.DescriptionLocation = GetRelativeDescriptionPath(lockInfo.DescriptionLocation, lockFilePath);
await JsonSerializer.SerializeAsync(fileStream, lockInfo, context.KiotaLock, cancellationToken).ConfigureAwait(false);
}
private static bool IsDescriptionLocal(string descriptionPath) => !descriptionPath.StartsWith("http", StringComparison.OrdinalIgnoreCase);
private static string GetRelativeDescriptionPath(string descriptionPath, string lockFilePath)
{
if (IsDescriptionLocal(descriptionPath) &&
Path.GetDirectoryName(lockFilePath) is string lockFileDirectoryPath)
return Path.GetRelativePath(lockFileDirectoryPath, descriptionPath);
return descriptionPath;
}
/// <inheritdoc/>
public Task BackupLockFileAsync(string directoryPath, CancellationToken cancellationToken = default)
{
ArgumentException.ThrowIfNullOrEmpty(directoryPath);
return BackupLockFileInternalAsync(directoryPath);
}
private static Task BackupLockFileInternalAsync(string directoryPath)
{
var lockFilePath = Path.Combine(directoryPath, LockFileName);
if (File.Exists(lockFilePath))
{
var backupFilePath = GetBackupFilePath(directoryPath);
var targetDirectory = Path.GetDirectoryName(backupFilePath);
if (string.IsNullOrEmpty(targetDirectory)) return Task.CompletedTask;
if (!Directory.Exists(targetDirectory))
Directory.CreateDirectory(targetDirectory);
File.Copy(lockFilePath, backupFilePath, true);
}
return Task.CompletedTask;
}
/// <inheritdoc/>
public Task RestoreLockFileAsync(string directoryPath, CancellationToken cancellationToken = default)
{
ArgumentException.ThrowIfNullOrEmpty(directoryPath);
return RestoreLockFileInternalAsync(directoryPath);
}
private static Task RestoreLockFileInternalAsync(string directoryPath)
{
var lockFilePath = Path.Combine(directoryPath, LockFileName);
var targetDirectory = Path.GetDirectoryName(lockFilePath);
if (string.IsNullOrEmpty(targetDirectory)) return Task.CompletedTask;
if (!Directory.Exists(targetDirectory))
Directory.CreateDirectory(targetDirectory);
var backupFilePath = GetBackupFilePath(directoryPath);
if (File.Exists(backupFilePath))
{
File.Copy(backupFilePath, lockFilePath, true);
}
return Task.CompletedTask;
}
private static readonly ThreadLocal<HashAlgorithm> HashAlgorithm = new(SHA256.Create);
private static string GetBackupFilePath(string outputPath)
{
var hashedPath = BitConverter.ToString((HashAlgorithm.Value ?? throw new InvalidOperationException("unable to get hash algorithm")).ComputeHash(Encoding.UTF8.GetBytes(outputPath))).Replace("-", string.Empty, StringComparison.OrdinalIgnoreCase);
return Path.Combine(Path.GetTempPath(), Constants.TempDirectoryName, "backup", hashedPath, LockFileName);
}
}