Patch Lock File with export file
This commit is contained in:
parent
552ac6282f
commit
06ff80392e
4 changed files with 212 additions and 11 deletions
22
src/Microsoft.DotNet.ProjectModel/Graph/ExportFile.cs
Normal file
22
src/Microsoft.DotNet.ProjectModel/Graph/ExportFile.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.Graph
|
||||
{
|
||||
public class ExportFile
|
||||
{
|
||||
public static readonly string ExportFileName = "project.fragment.lock.json";
|
||||
|
||||
public int Version { get; }
|
||||
public string ExportFilePath { get; }
|
||||
|
||||
public IList<LockFileTargetLibrary> Exports { get; }
|
||||
|
||||
public ExportFile(string exportFilePath, int version, IList<LockFileTargetLibrary> exports)
|
||||
{
|
||||
ExportFilePath = exportFilePath;
|
||||
Version = version;
|
||||
Exports = exports.Any() ? exports : new List<LockFileTargetLibrary>(0);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,9 +4,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.DotNet.ProjectModel.Utilities;
|
||||
using NuGet.Versioning;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.Graph
|
||||
{
|
||||
|
@ -22,6 +19,7 @@ namespace Microsoft.DotNet.ProjectModel.Graph
|
|||
public IList<LockFilePackageLibrary> PackageLibraries { get; set; } = new List<LockFilePackageLibrary>();
|
||||
public IList<LockFileProjectLibrary> ProjectLibraries { get; set; } = new List<LockFileProjectLibrary>();
|
||||
public IList<LockFileTarget> Targets { get; set; } = new List<LockFileTarget>();
|
||||
public ExportFile ExportFile { get; set; }
|
||||
|
||||
public LockFile(string lockFilePath)
|
||||
{
|
||||
|
|
140
src/Microsoft.DotNet.ProjectModel/Graph/LockFilePatcher.cs
Normal file
140
src/Microsoft.DotNet.ProjectModel/Graph/LockFilePatcher.cs
Normal file
|
@ -0,0 +1,140 @@
|
|||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.DotNet.ProjectModel.Graph
|
||||
{
|
||||
public class LockFilePatcher
|
||||
{
|
||||
private readonly LockFile _lockFile;
|
||||
private Dictionary<string, IList<LockFileTargetLibrary>> _msbuildTargetLibraries;
|
||||
|
||||
public LockFilePatcher(LockFile lockFile)
|
||||
{
|
||||
_lockFile = lockFile;
|
||||
|
||||
var msbuildProjectLibraries = lockFile.ProjectLibraries.Where(IsMSBuildProjectLibrary);
|
||||
_msbuildTargetLibraries = msbuildProjectLibraries.ToDictionary(GetProjectLibraryKey, l => GetTargetsForLibrary(_lockFile, l));
|
||||
}
|
||||
|
||||
public void PatchIfNecessary()
|
||||
{
|
||||
var exportFilePath = GetExportFilePath(_lockFile.LockFilePath);
|
||||
|
||||
if (File.Exists(exportFilePath))
|
||||
{
|
||||
var exportFile = LockFileReader.ReadExportFile(exportFilePath);
|
||||
PatchLockWithExport(exportFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
ThrowIfAnyMsbuildLibrariesPresent();
|
||||
}
|
||||
}
|
||||
|
||||
public void ThrowIfAnyMsbuildLibrariesPresent()
|
||||
{
|
||||
if (_msbuildTargetLibraries.Any())
|
||||
{
|
||||
throw new LockFilePatchingException($"Lock file {_lockFile} contains msbuild projects but there is no export file");
|
||||
}
|
||||
}
|
||||
|
||||
private void PatchLockWithExport(ExportFile exportFile)
|
||||
{
|
||||
if (_lockFile.Version != exportFile.Version)
|
||||
{
|
||||
throw new LockFilePatchingException($"Export file {exportFile.ExportFilePath} has a different version than the lock file {_lockFile.LockFilePath}");
|
||||
}
|
||||
|
||||
var exportDict = exportFile.Exports.ToDictionary(GetTargetLibraryKey);
|
||||
|
||||
var uncoveredLibraries = _msbuildTargetLibraries.Keys.Except(exportDict.Keys);
|
||||
if (uncoveredLibraries.Any())
|
||||
{
|
||||
throw new LockFilePatchingException($"Export {exportFile.ExportFilePath} does not provide exports for all the msbuild projects in {_lockFile.LockFilePath}");
|
||||
}
|
||||
|
||||
foreach(var exportKey in exportDict.Keys)
|
||||
{
|
||||
var export = exportDict[exportKey];
|
||||
var librariesToPatch = _msbuildTargetLibraries[exportKey];
|
||||
|
||||
if (export.TargetFramework == null)
|
||||
{
|
||||
throw new LockFilePatchingException($"Export library {export.Name} could not be resolved during nuget restore");
|
||||
}
|
||||
|
||||
foreach (var libraryToPatch in librariesToPatch)
|
||||
{
|
||||
Patch(libraryToPatch, export);
|
||||
}
|
||||
}
|
||||
|
||||
_lockFile.ExportFile = exportFile;
|
||||
}
|
||||
|
||||
private static void Patch(LockFileTargetLibrary libraryToPatch, LockFileTargetLibrary export)
|
||||
{
|
||||
libraryToPatch.CompileTimeAssemblies = export.CompileTimeAssemblies;
|
||||
libraryToPatch.ContentFiles = export.ContentFiles;
|
||||
libraryToPatch.FrameworkAssemblies = export.FrameworkAssemblies;
|
||||
libraryToPatch.NativeLibraries = export.NativeLibraries;
|
||||
libraryToPatch.ResourceAssemblies = export.ResourceAssemblies;
|
||||
libraryToPatch.RuntimeAssemblies = export.RuntimeAssemblies;
|
||||
}
|
||||
|
||||
private static bool IsMSBuildProjectLibrary(LockFileProjectLibrary projectLibrary)
|
||||
{
|
||||
var hasMSbuildProjectValue = !string.IsNullOrEmpty(projectLibrary.MSBuildProject);
|
||||
var doesNotHavePathValue = string.IsNullOrEmpty(projectLibrary.Path);
|
||||
|
||||
return doesNotHavePathValue && hasMSbuildProjectValue;
|
||||
}
|
||||
|
||||
private static IList<LockFileTargetLibrary> GetTargetsForLibrary(LockFile lockFile, LockFileProjectLibrary library)
|
||||
{
|
||||
return lockFile.Targets
|
||||
.SelectMany(
|
||||
t => t.Libraries
|
||||
.Where(
|
||||
l => string.Equals(GetProjectLibraryKey(library), (GetTargetLibraryKey(l)))
|
||||
)
|
||||
)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private static object TypeName(LockFileTargetLibrary library)
|
||||
{
|
||||
return library.Name + "/" + library.Version + "/" + library.Type;
|
||||
}
|
||||
|
||||
private static string GetTargetLibraryKey(LockFileTargetLibrary library)
|
||||
{
|
||||
return library.Name + "/" + library.Version;
|
||||
}
|
||||
|
||||
private static string GetProjectLibraryKey(LockFileProjectLibrary library)
|
||||
{
|
||||
return library.Name + "/" + library.Version;
|
||||
}
|
||||
|
||||
private static string GetExportFilePath(string masterLockFilePath)
|
||||
{
|
||||
var parentDirectory = Directory.GetParent(masterLockFilePath).FullName;
|
||||
return Path.Combine(parentDirectory, ExportFile.ExportFileName);
|
||||
}
|
||||
}
|
||||
|
||||
internal class LockFilePatchingException : Exception
|
||||
{
|
||||
public LockFilePatchingException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -15,13 +15,13 @@ namespace Microsoft.DotNet.ProjectModel.Graph
|
|||
{
|
||||
public static class LockFileReader
|
||||
{
|
||||
public static LockFile Read(string lockFilePath)
|
||||
public static LockFile Read(string lockFilePath, bool patchWithExportFile = true)
|
||||
{
|
||||
using (var stream = ResilientFileStreamOpener.OpenFile(lockFilePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
return Read(lockFilePath, stream);
|
||||
return Read(lockFilePath, stream, patchWithExportFile);
|
||||
}
|
||||
catch (FileFormatException ex)
|
||||
{
|
||||
|
@ -34,21 +34,32 @@ namespace Microsoft.DotNet.ProjectModel.Graph
|
|||
}
|
||||
}
|
||||
|
||||
public static LockFile Read(string lockFilePath, Stream stream)
|
||||
public static LockFile Read(string lockFilePath, Stream stream, bool patchWithExportFile = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
var reader = new StreamReader(stream);
|
||||
var jobject = JsonDeserializer.Deserialize(reader) as JsonObject;
|
||||
|
||||
if (jobject != null)
|
||||
{
|
||||
return ReadLockFile(lockFilePath, jobject);
|
||||
}
|
||||
else
|
||||
if (jobject == null)
|
||||
{
|
||||
throw new InvalidDataException();
|
||||
}
|
||||
|
||||
var lockFile = ReadLockFile(lockFilePath, jobject);
|
||||
|
||||
var patcher = new LockFilePatcher(lockFile);
|
||||
|
||||
if (patchWithExportFile)
|
||||
{
|
||||
patcher.PatchIfNecessary();
|
||||
}
|
||||
else
|
||||
{
|
||||
patcher.ThrowIfAnyMsbuildLibrariesPresent();
|
||||
}
|
||||
|
||||
return lockFile;
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
@ -60,6 +71,36 @@ namespace Microsoft.DotNet.ProjectModel.Graph
|
|||
}
|
||||
}
|
||||
|
||||
public static ExportFile ReadExportFile(string fragmentLockFilePath)
|
||||
{
|
||||
using (var stream = ResilientFileStreamOpener.OpenFile(fragmentLockFilePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
var rootJObject = JsonDeserializer.Deserialize(new StreamReader(stream)) as JsonObject;
|
||||
|
||||
if (rootJObject == null)
|
||||
{
|
||||
throw new InvalidDataException();
|
||||
}
|
||||
|
||||
var version = ReadInt(rootJObject, "version", defaultValue: int.MinValue);
|
||||
var exports = ReadObject(rootJObject.ValueAsJsonObject("exports"), ReadTargetLibrary);
|
||||
|
||||
return new ExportFile(fragmentLockFilePath, version, exports);
|
||||
|
||||
}
|
||||
catch (FileFormatException ex)
|
||||
{
|
||||
throw ex.WithFilePath(fragmentLockFilePath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw FileFormatException.Create(ex, fragmentLockFilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static LockFile ReadLockFile(string lockFilePath, JsonObject cursor)
|
||||
{
|
||||
var lockFile = new LockFile(lockFilePath);
|
||||
|
|
Loading…
Add table
Reference in a new issue