Skip to content

Commit 86cda61

Browse files
committed
Refactor computing goal state and errors to be extensible
This allows FileSystemProvider to handle its special cases (i.e. rename support for a single file). FileSystemProvider did not get support for fileMappings prior to this. This will enable it to support that feature as well.
1 parent 18f1c99 commit 86cda61

File tree

2 files changed

+58
-17
lines changed

2 files changed

+58
-17
lines changed

src/LibraryManager/Providers/BaseProvider.cs

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,13 @@ public async Task<OperationResult<LibraryInstallationGoalState>> GetInstallation
165165

166166
#endregion
167167

168+
/// <summary>
169+
/// Generates the goal state for library installation based on the desired state and library information.
170+
/// </summary>
171+
/// <param name="desiredState">Specifies the target state for the library installation, including file mappings and destination paths.</param>
172+
/// <param name="library">Represents the library from which files are being installed, containing file information and validation
173+
/// methods.</param>
174+
/// <returns>Returns an operation result containing the goal state or errors encountered during the generation process.</returns>
168175
private OperationResult<LibraryInstallationGoalState> GenerateGoalState(ILibraryInstallationState desiredState, ILibrary library)
169176
{
170177
var mappings = new List<FileMapping>(desiredState.FileMappings ?? []);
@@ -212,33 +219,26 @@ private OperationResult<LibraryInstallationGoalState> GenerateGoalState(ILibrary
212219
fileFilters = fileFilters.Select(f => $"{mappingRoot}/{f}").ToList();
213220
}
214221

215-
List<string> outFiles = FileGlobbingUtility.ExpandFileGlobs(fileFilters, library.Files.Keys).ToList();
222+
List<string> filteredFiles = FileGlobbingUtility.ExpandFileGlobs(fileFilters, library.Files.Keys).ToList();
216223

217-
if (library.GetInvalidFiles(outFiles) is IReadOnlyList<string> invalidFiles
218-
&& invalidFiles.Count > 0)
224+
if (library.GetInvalidFiles(filteredFiles) is IReadOnlyList<string> { Count: > 0 } invalidFiles)
219225
{
220226
errors ??= [];
221227
errors.Add(PredefinedErrors.InvalidFilesInLibrary(desiredState.Name, invalidFiles, library.Files.Keys));
228+
filteredFiles.RemoveAll(file => invalidFiles.Contains(file));
222229
}
223230

224-
foreach (string outFile in outFiles)
225-
{
226-
// strip the source prefix
227-
string relativeOutFile = mappingRoot.Length > 0 ? outFile.Substring(mappingRoot.Length + 1) : outFile;
228-
string destinationFile = Path.Combine(HostInteraction.WorkingDirectory, destination, relativeOutFile);
229-
destinationFile = FileHelpers.NormalizePath(destinationFile);
231+
Dictionary<string, string> fileMappings = GetFileMappings(library, filteredFiles, mappingRoot, destination, desiredState, errors);
230232

233+
foreach ((string destinationFile, string sourceFile) in fileMappings)
234+
{
231235
if (!FileHelpers.IsUnderRootDirectory(destinationFile, HostInteraction.WorkingDirectory))
232236
{
233237
errors ??= [];
234238
errors.Add(PredefinedErrors.PathOutsideWorkingDirectory());
235239
continue;
236240
}
237241

238-
// include the cache folder in the path
239-
string sourceFile = GetCachedFileLocalPath(desiredState, outFile);
240-
sourceFile = FileHelpers.NormalizePath(sourceFile);
241-
242242
// map destination back to the library-relative file it originated from
243243
if (installFiles.ContainsKey(destinationFile))
244244
{
@@ -248,10 +248,8 @@ private OperationResult<LibraryInstallationGoalState> GenerateGoalState(ILibrary
248248
errors.Add(PredefinedErrors.LibraryCannotBeInstalledDueToConflicts(destinationFile, [libraryId]));
249249
continue;
250250
}
251-
else
252-
{
253-
installFiles.Add(destinationFile, sourceFile);
254-
}
251+
252+
installFiles.Add(destinationFile, sourceFile);
255253
}
256254
}
257255

@@ -264,6 +262,28 @@ private OperationResult<LibraryInstallationGoalState> GenerateGoalState(ILibrary
264262
return OperationResult<LibraryInstallationGoalState>.FromSuccess(goalState);
265263
}
266264

265+
266+
protected virtual Dictionary<string, string> GetFileMappings(ILibrary library, IReadOnlyList<string> libraryFiles, string mappingRoot, string destination, ILibraryInstallationState desiredState, List<IError> errors)
267+
{
268+
Dictionary<string, string> installFiles = new(StringComparer.OrdinalIgnoreCase);
269+
270+
foreach (string file in libraryFiles)
271+
{
272+
// strip the source prefix
273+
string relativeOutFile = mappingRoot.Length > 0 ? file.Substring(mappingRoot.Length + 1) : file;
274+
string destinationFile = Path.Combine(HostInteraction.WorkingDirectory, destination, relativeOutFile);
275+
destinationFile = FileHelpers.NormalizePath(destinationFile);
276+
277+
// include the cache folder in the path
278+
string sourceFile = GetCachedFileLocalPath(desiredState, file);
279+
sourceFile = FileHelpers.NormalizePath(sourceFile);
280+
281+
installFiles.Add(destinationFile, sourceFile);
282+
}
283+
284+
return installFiles;
285+
}
286+
267287
public bool IsSourceCacheReady(LibraryInstallationGoalState goalState)
268288
{
269289
foreach (KeyValuePair<string, string> item in goalState.InstalledFiles)

src/LibraryManager/Providers/FileSystem/FileSystemProvider.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System;
5+
using System.Collections.Generic;
56
using System.IO;
67
using System.Linq;
78
using System.Net.Http;
@@ -221,5 +222,25 @@ protected override string GetCachedFileLocalPath(ILibraryInstallationState state
221222
// be handled elsewhere.
222223
return Path.Combine(state.Name, sourceFile);
223224
}
225+
226+
/// <inheritdoc />
227+
protected override Dictionary<string, string> GetFileMappings(ILibrary library, IReadOnlyList<string> fileFilters, string mappingRoot, string destination, ILibraryInstallationState desiredState, List<IError> errors)
228+
{
229+
Dictionary<string, string> fileMappings = new();
230+
// Handle single-file edge cases for FileSystem
231+
if (library.Files.Count == 1
232+
&& fileFilters.Count == 1
233+
&& GetCachedFileLocalPath(desiredState, library.Files.Keys.First()) == library.Name)
234+
{
235+
// direct 1:1 file mapping, allowing file rename
236+
string destinationFile = Path.Combine(HostInteraction.WorkingDirectory, destination, fileFilters[0]);
237+
destinationFile = FileHelpers.NormalizePath(destinationFile);
238+
239+
fileMappings.Add(destinationFile, library.Files.Keys.First());
240+
return fileMappings;
241+
}
242+
243+
return base.GetFileMappings(library, fileFilters, mappingRoot, destination, desiredState, errors);
244+
}
224245
}
225246
}

0 commit comments

Comments
 (0)