private async Task ApplyEdit(PackageEdit edit) { string originalPath = null; try { TempDirectory = Path.Combine(Path.GetTempPath(), "NuGetService", "HandlePackageEdits"); var directory = Path.Combine(TempDirectory, edit.Id, edit.Version); if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); } originalPath = Path.Combine(directory, "original.nupkg"); var sourceItem = FileStorage.GetFile(edit.Id, edit.Version); Trace.TraceInformation($"Name is {sourceItem.Name}, storage uri is {sourceItem.Uri}"); // Download the original file Trace.TraceInformation($"Downloading original copy of {edit.Id} {edit.Version}"); await FileStorage.DownloadAsync(sourceItem, originalPath); Trace.TraceInformation($"Downloaded original copy of {edit.Id} {edit.Version}"); // Check that a backup exists Trace.TraceInformation($"Backing up original copy of {edit.Id} {edit.Version}"); await FileStorage.BackupAsync(originalPath, edit.Id, edit.Version, edit.Hash); Trace.TraceInformation($"Backed up original copy of {edit.Id} {edit.Version}"); // Update the nupkg manifest with the new metadata using (var originalStream = File.Open(originalPath, FileMode.Open, FileAccess.ReadWrite)) { Trace.TraceInformation($"Rewriting package file for {edit.Id} {edit.Version}"); var editActionList = edit.GetEditsAsActionList(); NupkgRewriter.RewriteNupkgManifest(originalStream, editActionList); Trace.TraceInformation($"Rewrote package file for {edit.Id} {edit.Version}"); } // Snapshot the original blob Trace.TraceInformation($"Snapshotting original blob for {edit.Id} {edit.Version} ({sourceItem.Uri.AbsoluteUri})."); var snapshot = await FileStorage.SnapshotService.CreateSnapshot(sourceItem); Trace.TraceInformation($"Snapshotted original blob for {edit.Id} {edit.Version} ({sourceItem.Uri.AbsoluteUri})."); // Upload the updated file Trace.TraceInformation($"Uploading modified package file for {edit.Id} {edit.Version} to {sourceItem.Uri.AbsoluteUri}"); await FileStorage.UploadAsync(sourceItem, originalPath); Trace.TraceInformation($"Uploaded modified package file for {edit.Id} {edit.Version} to {sourceItem.Uri.AbsoluteUri}"); // Calculate new size and hash string hash; long size; using (var originalStream = File.OpenRead(originalPath)) { size = originalStream.Length; var hashAlgorithm = HashAlgorithm.Create(HashAlgorithmName); hash = Convert.ToBase64String( hashAlgorithm.ComputeHash(originalStream)); } // Update the database try { Trace.TraceInformation($"Updating package record for {edit.Id} {edit.Version}"); await UpdateDatabaseWithEdit(edit, hash, size); Trace.TraceInformation($"Updated package record for {edit.Id} {edit.Version}"); } catch (Exception exception) { // Error occurred while updaing database, roll back the blob to the snapshot // Can't do "await" in a catch block, but this should be pretty quick since it just starts the copy Trace.TraceError($"Failed to update database! {exception}"); Trace.TraceWarning( $"Rolling back updated blob for {edit.Id} {edit.Version}. Copying snapshot {snapshot.Uri.AbsoluteUri} to {sourceItem.Uri.AbsoluteUri}"); FileStorage.SnapshotService.RestoreSnapshot(sourceItem, snapshot); Trace.TraceWarning( $"Rolled back updated blob for {edit.Id} {edit.Version}. Copying snapshot {snapshot.Uri.AbsoluteUri} to {sourceItem.Uri.AbsoluteUri}"); throw; } Trace.TraceInformation("Deleting snapshot blob {2} for {0} {1}.", edit.Id, edit.Version, snapshot.Uri.AbsoluteUri); await FileStorage.SnapshotService.DeleteSnapshotAsync(snapshot); Trace.TraceInformation("Deleted snapshot blob {2} for {0} {1}.", edit.Id, edit.Version, snapshot.Uri.AbsoluteUri); } finally { if (!string.IsNullOrEmpty(originalPath) && File.Exists(originalPath)) { File.Delete(originalPath); } } }