internal static async Task InstallFromStream( Stream stream, LibraryIdentity library, string packagesDirectory, ILogger log) { var packagePathResolver = new DefaultPackagePathResolver(packagesDirectory); var targetPath = packagePathResolver.GetInstallPath(library.Name, library.Version); var targetNuspec = packagePathResolver.GetManifestFilePath(library.Name, library.Version); var targetNupkg = packagePathResolver.GetPackageFilePath(library.Name, library.Version); var hashPath = packagePathResolver.GetHashPath(library.Name, library.Version); // Acquire the lock on a nukpg before we extract it to prevent the race condition when multiple // processes are extracting to the same destination simultaneously await ConcurrencyUtilities.ExecuteWithFileLocked(targetNupkg, async createdNewLock => { // If this is the first process trying to install the target nupkg, go ahead // After this process successfully installs the package, all other processes // waiting on this lock don't need to install it again. if (createdNewLock && !File.Exists(targetNupkg)) { log.LogInformation($"Installing {library.Name} {library.Version}"); Directory.CreateDirectory(targetPath); using (var nupkgStream = new FileStream( targetNupkg, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite | FileShare.Delete, bufferSize: 4096, useAsync: true)) { await stream.CopyToAsync(nupkgStream); nupkgStream.Seek(0, SeekOrigin.Begin); ExtractPackage(targetPath, nupkgStream); } // DNU REFACTORING TODO: delete the hacky FixNuSpecIdCasing() and uncomment logic below after we // have implementation of NuSpecFormatter.Read() // Fixup the casing of the nuspec on disk to match what we expect var nuspecFile = Directory.EnumerateFiles(targetPath, "*" + ManifestExtension).Single(); FixNuSpecIdCasing(nuspecFile, targetNuspec, library.Name); /*var actualNuSpecName = Path.GetFileName(nuspecFile); var expectedNuSpecName = Path.GetFileName(targetNuspec); if (!string.Equals(actualNuSpecName, expectedNuSpecName, StringComparison.Ordinal)) { MetadataBuilder metadataBuilder = null; var nuspecFormatter = new NuSpecFormatter(); using (var nuspecStream = File.OpenRead(nuspecFile)) { metadataBuilder = nuspecFormatter.Read(nuspecStream); // REVIEW: any way better hardcoding "id"? metadataBuilder.SetMetadataValue("id", library.Name); } // Delete the previous nuspec file File.Delete(nuspecFile); // Write the new manifest using (var targetNuspecStream = File.OpenWrite(targetNuspec)) { nuspecFormatter.Save(metadataBuilder, targetNuspecStream); } }*/ stream.Seek(0, SeekOrigin.Begin); string packageHash; using (var sha512 = SHA512.Create()) { packageHash = Convert.ToBase64String(sha512.ComputeHash(stream)); } // Note: PackageRepository relies on the hash file being written out as the final operation as part of a package install // to assume a package was fully installed. File.WriteAllText(hashPath, packageHash); } return 0; }); }
private void WriteTargetsAndProps(PackageSpec project, List<RestoreTargetGraph> targetGraphs, NuGetv3LocalRepository repository) { // Get the runtime-independent graphs var tfmGraphs = targetGraphs.Where(g => string.IsNullOrEmpty(g.RuntimeIdentifier)).ToList(); if (tfmGraphs.Count > 1) { var name = $"{project.Name}.nuget.targets"; var path = Path.Combine(project.BaseDirectory, name); _log.LogInformation($"Generating MSBuild file {name}"); GenerateMSBuildErrorFile(path); return; } var graph = tfmGraphs[0]; var pathResolver = new DefaultPackagePathResolver(repository.RepositoryRoot); var targets = new List<string>(); var props = new List<string>(); foreach (var library in graph.Flattened.Distinct().OrderBy(g => g.Data.Match.Library)) { var package = repository.FindPackagesById(library.Key.Name).FirstOrDefault(p => p.Version == library.Key.Version); if (package != null) { var criteria = graph.Conventions.Criteria.ForFramework(graph.Framework); var contentItemCollection = new ContentItemCollection(); using (var nupkgStream = File.OpenRead(package.ZipPath)) { var reader = new PackageReader(nupkgStream); contentItemCollection.Load(reader.GetFiles()); } // Find MSBuild thingies var buildItems = contentItemCollection.FindBestItemGroup(criteria, graph.Conventions.Patterns.MSBuildFiles); if (buildItems != null) { // We need to additionally filter to items that are named "{packageId}.targets" and "{packageId}.props" // Filter by file name here and we'll filter by extension when we add things to the lists. var items = buildItems.Items .Where(item => Path.GetFileNameWithoutExtension(item.Path).Equals(package.Id, StringComparison.OrdinalIgnoreCase)) .ToList(); targets.AddRange(items .Select(c => c.Path) .Where(path => Path.GetExtension(path).Equals(".targets", StringComparison.OrdinalIgnoreCase)) .Select(path => Path.Combine(pathResolver.GetPackageDirectory(package.Id, package.Version), path.Replace('/', Path.DirectorySeparatorChar)))); props.AddRange(items .Select(c => c.Path) .Where(path => Path.GetExtension(path).Equals(".props", StringComparison.OrdinalIgnoreCase)) .Select(path => Path.Combine(pathResolver.GetPackageDirectory(package.Id, package.Version), path.Replace('/', Path.DirectorySeparatorChar)))); } } } // Generate the files as needed var targetsName = $"{project.Name}.nuget.targets"; var propsName = $"{project.Name}.nuget.props"; var targetsPath = Path.Combine(project.BaseDirectory, targetsName); var propsPath = Path.Combine(project.BaseDirectory, propsName); if (targets.Any()) { _log.LogInformation($"Generating MSBuild file {targetsName}"); GenerateImportsFile(repository, targetsPath, targets); } else if (File.Exists(targetsPath)) { File.Delete(targetsPath); } if (props.Any()) { _log.LogInformation($"Generating MSBuild file {propsName}"); GenerateImportsFile(repository, propsPath, props); } else if (File.Exists(propsPath)) { File.Delete(propsPath); } }
private LockFileTargetLibrary CreateLockFileTargetLibrary(LocalPackageInfo package, RestoreTargetGraph targetGraph, DefaultPackagePathResolver defaultPackagePathResolver, string correctedPackageName) { var lockFileLib = new LockFileTargetLibrary(); var framework = targetGraph.Framework; var runtimeIdentifier = targetGraph.RuntimeIdentifier; // package.Id is read from nuspec and it might be in wrong casing. // correctedPackageName should be the package name used by dependency graph and // it has the correct casing that runtime needs during dependency resolution. lockFileLib.Name = correctedPackageName ?? package.Id; lockFileLib.Version = package.Version; IList<string> files; var contentItems = new ContentItemCollection(); HashSet<string> referenceFilter = null; using (var nupkgStream = File.OpenRead(package.ZipPath)) { var packageReader = new PackageReader(nupkgStream); files = packageReader.GetFiles().Select(p => p.Replace(Path.DirectorySeparatorChar, '/')).ToList(); contentItems.Load(files); var dependencySet = packageReader.GetPackageDependencies().GetNearest(framework); if (dependencySet != null) { var set = dependencySet.Packages; if (set != null) { lockFileLib.Dependencies = set.ToList(); } } var referenceSet = packageReader.GetReferenceItems().GetNearest(framework); if (referenceSet != null) { referenceFilter = new HashSet<string>(referenceSet.Items, StringComparer.OrdinalIgnoreCase); } // TODO: Remove this when we do #596 // ASP.NET Core isn't compatible with generic PCL profiles if (!string.Equals(framework.Framework, FrameworkConstants.FrameworkIdentifiers.AspNetCore, StringComparison.OrdinalIgnoreCase) && !string.Equals(framework.Framework, FrameworkConstants.FrameworkIdentifiers.DnxCore, StringComparison.OrdinalIgnoreCase)) { var frameworkAssemblies = packageReader.GetFrameworkItems().GetNearest(framework); if (frameworkAssemblies != null) { foreach (var assemblyReference in frameworkAssemblies.Items) { lockFileLib.FrameworkAssemblies.Add(assemblyReference); } } } } var nativeCriteria = targetGraph.Conventions.Criteria.ForRuntime(targetGraph.RuntimeIdentifier); var managedCriteria = targetGraph.Conventions.Criteria.ForFrameworkAndRuntime(framework, targetGraph.RuntimeIdentifier); var compileGroup = contentItems.FindBestItemGroup(managedCriteria, targetGraph.Conventions.Patterns.CompileAssemblies, targetGraph.Conventions.Patterns.RuntimeAssemblies); if (compileGroup != null) { lockFileLib.CompileTimeAssemblies = compileGroup.Items.Select(t => new LockFileItem(t.Path)).ToList(); } var runtimeGroup = contentItems.FindBestItemGroup(managedCriteria, targetGraph.Conventions.Patterns.RuntimeAssemblies); if (runtimeGroup != null) { lockFileLib.RuntimeAssemblies = runtimeGroup.Items.Select(p => new LockFileItem(p.Path)).ToList(); } var resourceGroup = contentItems.FindBestItemGroup(managedCriteria, targetGraph.Conventions.Patterns.ResourceAssemblies); if (resourceGroup != null) { lockFileLib.ResourceAssemblies = resourceGroup.Items.Select(ToResourceLockFileItem).ToList(); } var nativeGroup = contentItems.FindBestItemGroup(nativeCriteria, targetGraph.Conventions.Patterns.NativeLibraries); if (nativeGroup != null) { lockFileLib.NativeLibraries = nativeGroup.Items.Select(p => new LockFileItem(p.Path)).ToList(); } // COMPAT: Support lib/contract so older packages can be consumed var contractPath = "lib/contract/" + package.Id + ".dll"; var hasContract = files.Any(path => path == contractPath); var hasLib = lockFileLib.RuntimeAssemblies.Any(); if (hasContract && hasLib && !framework.IsDesktop()) { lockFileLib.CompileTimeAssemblies.Clear(); lockFileLib.CompileTimeAssemblies.Add(new LockFileItem(contractPath)); } // Apply filters from the <references> node in the nuspec if (referenceFilter != null) { // Remove anything that starts with "lib/" and is NOT specified in the reference filter. // runtimes/* is unaffected (it doesn't start with lib/) lockFileLib.RuntimeAssemblies = lockFileLib.RuntimeAssemblies.Where(p => !p.Path.StartsWith("lib/") || referenceFilter.Contains(p.Path)).ToList(); lockFileLib.CompileTimeAssemblies = lockFileLib.CompileTimeAssemblies.Where(p => !p.Path.StartsWith("lib/") || referenceFilter.Contains(p.Path)).ToList(); } return lockFileLib; }