internal static async Task InstallFromStream(Stream stream, Library library, string packagesDirectory, SHA512 sha512) { 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) { Directory.CreateDirectory(targetPath); using (var nupkgStream = new FileStream(targetNupkg, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite | FileShare.Delete)) { await stream.CopyToAsync(nupkgStream); nupkgStream.Seek(0, SeekOrigin.Begin); ExtractPackage(targetPath, nupkgStream); } // Fixup the casing of the nuspec on disk to match what we expect var nuspecFile = Directory.EnumerateFiles(targetPath, "*" + NuGet.Constants.ManifestExtension).Single(); if (!string.Equals(nuspecFile, targetNuspec, StringComparison.Ordinal)) { Manifest manifest = null; using (var nuspecStream = File.OpenRead(nuspecFile)) { manifest = Manifest.ReadFrom(nuspecStream, validateSchema: false); manifest.Metadata.Id = library.Name; } // Delete the previous nuspec file File.Delete(nuspecFile); // Write the new manifest using (var targetNuspecStream = File.OpenWrite(targetNuspec)) { manifest.Save(targetNuspecStream); } } stream.Seek(0, SeekOrigin.Begin); var nupkgSHA = Convert.ToBase64String(sha512.ComputeHash(stream)); File.WriteAllText(hashPath, nupkgSHA); } return(0); }); }
private async Task <bool> RestoreForProject(LocalPackageRepository localRepository, string projectJsonPath, string rootDirectory, string packagesDirectory) { var success = true; Reports.Information.WriteLine(string.Format("Restoring packages for {0}", projectJsonPath.Bold())); var sw = new Stopwatch(); sw.Start(); Project project; if (!Project.TryGetProject(projectJsonPath, out project)) { throw new Exception("TODO: project.json parse error"); } Func <string, string> getVariable = key => { return(null); }; ScriptExecutor.Execute(project, "prerestore", getVariable); var projectDirectory = project.ProjectDirectory; var restoreOperations = new RestoreOperations { Report = Reports.Information }; var projectProviders = new List <IWalkProvider>(); var localProviders = new List <IWalkProvider>(); var remoteProviders = new List <IWalkProvider>(); var contexts = new List <RestoreContext>(); projectProviders.Add( new LocalWalkProvider( new ProjectReferenceDependencyProvider( new ProjectResolver( projectDirectory, rootDirectory)))); localProviders.Add( new LocalWalkProvider( new NuGetDependencyResolver( packagesDirectory, new EmptyFrameworkResolver()))); var allSources = SourceProvider.LoadPackageSources(); var enabledSources = Sources.Any() ? Enumerable.Empty <PackageSource>() : allSources.Where(s => s.IsEnabled); var addedSources = Sources.Concat(FallbackSources).Select( value => allSources.FirstOrDefault(source => CorrectName(value, source)) ?? new PackageSource(value)); var effectiveSources = enabledSources.Concat(addedSources).Distinct().ToList(); foreach (var source in effectiveSources) { if (new Uri(source.Source).IsFile) { remoteProviders.Add( new RemoteWalkProvider( new PackageFolder( source.Source, Reports.Verbose))); } else { remoteProviders.Add( new RemoteWalkProvider( new PackageFeed( source.Source, source.UserName, source.Password, NoCache, Reports.Verbose))); } } foreach (var configuration in project.GetTargetFrameworks()) { var context = new RestoreContext { FrameworkName = configuration.FrameworkName, ProjectLibraryProviders = projectProviders, LocalLibraryProviders = localProviders, RemoteLibraryProviders = remoteProviders, }; contexts.Add(context); } if (!contexts.Any()) { contexts.Add(new RestoreContext { FrameworkName = ApplicationEnvironment.TargetFramework, ProjectLibraryProviders = projectProviders, LocalLibraryProviders = localProviders, RemoteLibraryProviders = remoteProviders, }); } var tasks = new List <Task <GraphNode> >(); foreach (var context in contexts) { tasks.Add(restoreOperations.CreateGraphNode(context, new Library { Name = project.Name, Version = project.Version }, _ => true)); } var graphs = await Task.WhenAll(tasks); Reports.Information.WriteLine(string.Format("{0}, {1}ms elapsed", "Resolving complete".Green(), sw.ElapsedMilliseconds)); var installItems = new List <GraphItem>(); var missingItems = new List <Library>(); ForEach(graphs, node => { if (node == null || node.Library == null) { return; } if (node.Item == null || node.Item.Match == null) { if (node.Library.Version != null && !missingItems.Contains(node.Library)) { missingItems.Add(node.Library); Reports.Information.WriteLine(string.Format("Unable to locate {0} >= {1}", node.Library.Name.Red().Bold(), node.Library.Version)); success = false; } return; } var isRemote = remoteProviders.Contains(node.Item.Match.Provider); var isAdded = installItems.Any(item => item.Match.Library == node.Item.Match.Library); if (!isAdded && isRemote) { installItems.Add(node.Item); } }); var dependencies = new Dictionary <Library, string>(); // If there is a global.json file specified, we should do SHA value verification var globalJsonFileSpecified = !string.IsNullOrEmpty(GlobalJsonFile); JToken dependenciesNode = null; if (globalJsonFileSpecified) { var globalJson = JObject.Parse(File.ReadAllText(GlobalJsonFile)); dependenciesNode = globalJson["dependencies"]; if (dependenciesNode != null) { dependencies = dependenciesNode .OfType <JProperty>() .ToDictionary(d => new Library() { Name = d.Name, Version = SemanticVersion.Parse(d.Value.Value <string>("version")) }, d => d.Value.Value <string>("sha")); } } var packagePathResolver = new DefaultPackagePathResolver(packagesDirectory); using (var sha512 = SHA512.Create()) { foreach (var item in installItems) { var library = item.Match.Library; var memStream = new MemoryStream(); await item.Match.Provider.CopyToAsync(item.Match, memStream); memStream.Seek(0, SeekOrigin.Begin); var nupkgSHA = Convert.ToBase64String(sha512.ComputeHash(memStream)); string expectedSHA; if (dependencies.TryGetValue(library, out expectedSHA)) { if (!string.Equals(expectedSHA, nupkgSHA, StringComparison.Ordinal)) { Reports.Information.WriteLine( string.Format("SHA of downloaded package {0} doesn't match expected value.".Red().Bold(), library.ToString())); success = false; continue; } } else { // Report warnings only when given global.json contains "dependencies" if (globalJsonFileSpecified && dependenciesNode != null) { Reports.Information.WriteLine( string.Format("Expected SHA of package {0} doesn't exist in given global.json file.".Yellow().Bold(), library.ToString())); } } Reports.Information.WriteLine(string.Format("Installing {0} {1}", library.Name.Bold(), library.Version)); var targetPath = packagePathResolver.GetInstallPath(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) { Directory.CreateDirectory(targetPath); using (var stream = new FileStream(targetNupkg, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite | FileShare.Delete)) { await item.Match.Provider.CopyToAsync(item.Match, stream); stream.Seek(0, SeekOrigin.Begin); ExtractPackage(targetPath, stream); } File.WriteAllText(hashPath, nupkgSHA); } return(0); }); } } ScriptExecutor.Execute(project, "postrestore", getVariable); ScriptExecutor.Execute(project, "prepare", getVariable); Reports.Information.WriteLine(string.Format("{0}, {1}ms elapsed", "Restore complete".Green().Bold(), sw.ElapsedMilliseconds)); // Print the dependency graph if (success) { var graphNum = contexts.Count; for (int i = 0; i < graphNum; i++) { PrintDependencyGraph(graphs[i], contexts[i].FrameworkName); } } return(success); }
private async Task InstallPackages(List <GraphItem> installItems, string packagesDirectory, Func <Library, string, bool> packageFilter) { var packagePathResolver = new DefaultPackagePathResolver(packagesDirectory); using (var sha512 = SHA512.Create()) { foreach (var item in installItems) { var library = item.Match.Library; var memStream = new MemoryStream(); await item.Match.Provider.CopyToAsync(item.Match, memStream); memStream.Seek(0, SeekOrigin.Begin); var nupkgSHA = Convert.ToBase64String(sha512.ComputeHash(memStream)); bool shouldInstall = packageFilter(library, nupkgSHA); if (!shouldInstall) { continue; } Reports.Information.WriteLine(string.Format("Installing {0} {1}", library.Name.Bold(), library.Version)); 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) { Directory.CreateDirectory(targetPath); using (var stream = new FileStream(targetNupkg, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite | FileShare.Delete)) { await item.Match.Provider.CopyToAsync(item.Match, stream); stream.Seek(0, SeekOrigin.Begin); ExtractPackage(targetPath, stream); } // Fixup the casing of the nuspec on disk to match what we expect var nuspecFile = Directory.EnumerateFiles(targetPath, "*" + Constants.ManifestExtension).Single(); if (!string.Equals(nuspecFile, targetNuspec, StringComparison.Ordinal)) { Manifest manifest = null; using (var stream = File.OpenRead(nuspecFile)) { manifest = Manifest.ReadFrom(stream, validateSchema: false); manifest.Metadata.Id = library.Name; } // Delete the previous nuspec file File.Delete(nuspecFile); // Write the new manifest using (var stream = File.OpenWrite(targetNuspec)) { manifest.Save(stream); } } // Ensure the manifest file name matches File.WriteAllText(hashPath, nupkgSHA); } return(0); }); } } }
internal static async Task InstallFromStream( Stream stream, Library library, string packagesDirectory, IReport information) { 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 targetHashPath = 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, action : async _ => { string packageHash; using (var sha512 = SHA512.Create()) { packageHash = Convert.ToBase64String(sha512.ComputeHash(stream)); } var actionName = "Installing"; var installedPackageHash = string.Empty; if (File.Exists(targetHashPath) && File.Exists(targetNuspec)) { installedPackageHash = File.ReadAllText(targetHashPath); actionName = "Overwriting"; } if (string.Equals(packageHash, installedPackageHash, StringComparison.Ordinal)) { information.WriteLine($"{library.Name}.{library.Version} already exists"); } else { information.WriteLine($"{actionName} {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)) { stream.Seek(0, SeekOrigin.Begin); await stream.CopyToAsync(nupkgStream); nupkgStream.Seek(0, SeekOrigin.Begin); ExtractPackage(targetPath, nupkgStream); } // Fixup the casing of the nuspec on disk to match what we expect var nuspecFile = Directory.EnumerateFiles(targetPath, "*" + NuGet.Constants.ManifestExtension).Single(); if (!string.Equals(nuspecFile, targetNuspec, StringComparison.Ordinal)) { Manifest manifest = null; using (var nuspecStream = File.OpenRead(nuspecFile)) { manifest = Manifest.ReadFrom(nuspecStream, validateSchema: false); manifest.Metadata.Id = library.Name; } // Delete the previous nuspec file File.Delete(nuspecFile); // Write the new manifest using (var targetNuspecStream = File.OpenWrite(targetNuspec)) { manifest.Save(targetNuspecStream); } } // 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(targetHashPath, packageHash); } return(0); }); }
internal static async Task InstallFromStream(Stream stream, Library library, string packagesDirectory, SHA512 sha512, bool performingParallelInstalls = false) { 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)) { var extractPath = targetPath; if (performingParallelInstalls) { // Extracting to the {id}/{version} has an issue with concurrent installs - when a package has been partially // extracted, the Restore Operation can inadvertly conclude the package is available locally and proceed to read // partially written package contents. To avoid this we'll extract the package to a sibling directory and Move it // to the target path. extractPath = Path.Combine(Path.GetDirectoryName(targetPath), Path.GetRandomFileName()); targetNupkg = Path.Combine(extractPath, Path.GetFileName(targetNupkg)); } var extractDirectory = Directory.CreateDirectory(extractPath); 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(extractPath, nupkgStream); } // Fixup the casing of the nuspec on disk to match what we expect var nuspecFile = Directory.EnumerateFiles(targetPath, "*" + NuGet.Constants.ManifestExtension).Single(); if (!string.Equals(nuspecFile, targetNuspec, StringComparison.Ordinal)) { Manifest manifest = null; using (var nuspecStream = File.OpenRead(nuspecFile)) { manifest = Manifest.ReadFrom(nuspecStream, validateSchema: false); manifest.Metadata.Id = library.Name; } // Delete the previous nuspec file File.Delete(nuspecFile); // Write the new manifest using (var targetNuspecStream = File.OpenWrite(targetNuspec)) { manifest.Save(targetNuspecStream); } } stream.Seek(0, SeekOrigin.Begin); var nupkgSHA = Convert.ToBase64String(sha512.ComputeHash(stream)); File.WriteAllText(hashPath, nupkgSHA); if (performingParallelInstalls) { extractDirectory.MoveTo(targetPath); } } return(0); }); }