in src/NuGet.Core/NuGet.Commands/RestoreCommand/LockFileBuilder.cs [39:290]
public LockFile CreateLockFile(LockFile previousLockFile,
PackageSpec project,
IEnumerable<RestoreTargetGraph> targetGraphs,
IReadOnlyList<NuGetv3LocalRepository> localRepositories,
RemoteWalkContext context,
LockFileBuilderCache lockFileBuilderCache)
{
var lockFile = new LockFile()
{
Version = _lockFileVersion
};
var previousLibraries = previousLockFile?.Libraries.ToDictionary(l => ValueTuple.Create(l.Name, l.Version));
if (project.RestoreMetadata?.ProjectStyle == ProjectStyle.PackageReference)
{
AddProjectFileDependenciesForPackageReference(project, lockFile, targetGraphs.AsList());
}
// Record all libraries used
var libraryItems = targetGraphs
.SelectMany(g => g.Flattened) // All GraphItem<RemoteResolveResult> resolved in the graph.
.Distinct(GraphItemKeyComparer<RemoteResolveResult>.Instance) // Distinct list of GraphItems. Two items are equal only if the itmes' Keys are equal.
.OrderBy(x => x.Data.Match.Library);
foreach (var item in libraryItems)
{
var library = item.Data.Match.Library;
if (project.Name.Equals(library.Name, StringComparison.OrdinalIgnoreCase))
{
// Do not include the project itself as a library.
continue;
}
if (library.Type == LibraryType.Project || library.Type == LibraryType.ExternalProject)
{
// Project
var localMatch = (LocalMatch)item.Data.Match;
string path = null;
string msBuildProject = null;
// Set the relative path if a path exists
// For projects without project.json this will be empty
if (!string.IsNullOrEmpty(localMatch.LocalLibrary.Path))
{
path = PathUtility.GetRelativePath(
project.FilePath,
localMatch.LocalLibrary.Path,
'/');
}
// The msbuild project path if it exists
object msbuildPath;
if (localMatch.LocalLibrary.Items.TryGetValue(KnownLibraryProperties.MSBuildProjectPath, out msbuildPath))
{
var msbuildRelativePath = PathUtility.GetRelativePath(
project.FilePath,
(string)msbuildPath,
'/');
msBuildProject = msbuildRelativePath;
}
var projectLib = new LockFileLibrary()
{
MSBuildProject = msBuildProject,
Name = library.Name,
Path = path,
Version = library.Version,
Type = LibraryType.Project,
};
lockFile.Libraries.Add(projectLib);
}
else if (library.Type == LibraryType.Package)
{
// Packages
var packageInfo = NuGetv3LocalRepositoryUtility.GetPackage(localRepositories, library.Name, library.Version);
// Add the library if it was resolved, unresolved packages are not added to the assets file.
if (packageInfo != null)
{
var package = packageInfo.Package;
var resolver = packageInfo.Repository.PathResolver;
var sha512 = package.Sha512;
var path = PathUtility.GetPathWithForwardSlashes(resolver.GetPackageDirectory(package.Id, package.Version));
LockFileLibrary lockFileLib = null;
LockFileLibrary previousLibrary = null;
if (previousLibraries?.TryGetValue(ValueTuple.Create(package.Id, package.Version), out previousLibrary) == true)
{
// Check that the previous library is still valid
if (previousLibrary != null
&& StringComparer.Ordinal.Equals(path, previousLibrary.Path)
&& StringComparer.Ordinal.Equals(sha512, previousLibrary.Sha512))
{
// When deciding whether the lock file has changed,
// we compare the new lock file to the previous (in-memory) lock file.
lockFileLib = previousLibrary;
}
}
// Create a new lock file library if one doesn't exist already.
if (lockFileLib == null)
{
lockFileLib = CreateLockFileLibrary(package, sha512, path);
}
// Create a new lock file library
lockFile.Libraries.Add(lockFileLib);
}
}
}
Dictionary<ValueTuple<string, NuGetVersion>, LockFileLibrary> libraries = EnsureUniqueLockFileLibraries(lockFile);
var librariesWithWarnings = new HashSet<LibraryIdentity>();
var rootProjectStyle = project.RestoreMetadata?.ProjectStyle ?? ProjectStyle.Unknown;
// Add the targets
foreach (var targetGraph in targetGraphs
.OrderBy(graph => graph.Framework.ToString(), StringComparer.Ordinal)
.ThenBy(graph => graph.RuntimeIdentifier, StringComparer.Ordinal))
{
var target = new LockFileTarget
{
TargetFramework = targetGraph.Framework,
RuntimeIdentifier = targetGraph.RuntimeIdentifier,
TargetAlias = targetGraph.TargetAlias,
};
var flattenedFlags = IncludeFlagUtils.FlattenDependencyTypes(_includeFlagGraphs, project, targetGraph);
// Check if warnings should be displayed for the current framework.
var tfi = project.GetTargetFramework(targetGraph.Framework);
bool warnForImportsOnGraph = tfi.Warn
&& (target.TargetFramework is FallbackFramework
|| target.TargetFramework is AssetTargetFallbackFramework);
foreach (var graphItem in targetGraph.Flattened.OrderBy(x => x.Key))
{
var library = graphItem.Key;
// include flags
LibraryIncludeFlags includeFlags;
if (!flattenedFlags.TryGetValue(library.Name, out includeFlags))
{
includeFlags = ~LibraryIncludeFlags.ContentFiles;
}
if (library.Type == LibraryType.Project || library.Type == LibraryType.ExternalProject)
{
if (project.Name.Equals(library.Name, StringComparison.OrdinalIgnoreCase))
{
// Do not include the project itself as a library.
continue;
}
var projectLib = LockFileUtils.CreateLockFileTargetProject(
graphItem,
library,
includeFlags,
targetGraph,
rootProjectStyle);
target.Libraries.Add(projectLib);
}
else if (library.Type == LibraryType.Package)
{
var packageInfo = NuGetv3LocalRepositoryUtility.GetPackage(localRepositories, library.Name, library.Version);
if (packageInfo == null)
{
continue;
}
var package = packageInfo.Package;
var libraryDependency = tfi.Dependencies.FirstOrDefault(e => e.Name.Equals(library.Name, StringComparison.OrdinalIgnoreCase));
(LockFileTargetLibrary targetLibrary, bool usedFallbackFramework) = LockFileUtils.CreateLockFileTargetLibrary(
libraryDependency?.Aliases,
libraries[ValueTuple.Create(library.Name, library.Version)],
package,
targetGraph,
dependencyType: includeFlags,
targetFrameworkOverride: null,
dependencies: graphItem.Data.Dependencies,
cache: lockFileBuilderCache);
target.Libraries.Add(targetLibrary);
// Log warnings if the target library used the fallback framework
if (warnForImportsOnGraph && !librariesWithWarnings.Contains(library))
{
if (target.TargetFramework is FallbackFramework)
{
// PackageTargetFallback works different from AssetTargetFallback so the warning logic for PTF cannot be optimized.
var nonFallbackFramework = new NuGetFramework(target.TargetFramework);
var targetLibraryWithoutFallback = LockFileUtils.CreateLockFileTargetLibrary(
libraryDependency?.Aliases,
libraries[ValueTuple.Create(library.Name, library.Version)],
package,
targetGraph,
targetFrameworkOverride: nonFallbackFramework,
dependencyType: includeFlags,
dependencies: graphItem.Data.Dependencies,
cache: lockFileBuilderCache);
usedFallbackFramework = !targetLibrary.Equals(targetLibraryWithoutFallback);
}
if (usedFallbackFramework)
{
var libraryName = DiagnosticUtility.FormatIdentity(library);
var message = string.Format(CultureInfo.CurrentCulture,
Strings.Log_ImportsFallbackWarning,
libraryName,
GetFallbackFrameworkString(target.TargetFramework),
new NuGetFramework(target.TargetFramework));
var logMessage = RestoreLogMessage.CreateWarning(
NuGetLogCode.NU1701,
message,
library.Name,
targetGraph.TargetGraphName);
_logger.Log(logMessage);
// only log the warning once per library
librariesWithWarnings.Add(library);
}
}
}
}
EnsureUniqueLockFileTargetLibraries(target);
lockFile.Targets.Add(target);
}
PopulatePackageFolders(localRepositories.Select(repo => repo.RepositoryRoot).Distinct(), lockFile);
AddCentralTransitiveDependencyGroupsForPackageReference(project, lockFile, targetGraphs, _logger);
// Add the original package spec to the lock file.
lockFile.PackageSpec = project;
return lockFile;
}