private void Analyze_Async_Compare(object state) { AppxPackageComparisonResult resultNoResource = new AppxPackageComparisonResult(); AppxPackageComparisonResult resultWithResource = new AppxPackageComparisonResult(); try { List <string> packagePaths = state as List <string>; List <AppxPackageReader> readerList = new List <AppxPackageReader>(); List <AppxPackage> allMainPackages = new List <AppxPackage>(); List <AppxPackage> allResourcePackages = new List <AppxPackage>(); foreach (string path in packagePaths) { AppxPackageReader r = new AppxPackageReader(path); readerList.Add(r); r.Run(); // async } foreach (AppxPackageReader r in readerList) { r.Wait(); // make sure package reader has completed if (r.ErrorEncountered) { ShowError("Error Reading Package.", r.ErrorText); return; } allMainPackages.AddRange(r.MainPackages); allResourcePackages.AddRange(r.ResourcePackages); } List <AppxPackage> allPackages = new List <AppxPackage>(); allPackages.AddRange(allMainPackages); allPackages.AddRange(allResourcePackages); // Get the result for no resource packages resultNoResource = GetInterPackageDupFiles(resultNoResource, allMainPackages); resultNoResource = GetCrossPackageDeDupdFiles(resultNoResource, allMainPackages); resultNoResource = AnalyzeFileSpaceSavings(resultNoResource, allMainPackages); // Get the result with resource packages resultWithResource = GetInterPackageDupFiles(resultWithResource, allResourcePackages); resultWithResource = GetCrossPackageDeDupdFiles(resultWithResource, allPackages); resultWithResource = AnalyzeFileSpaceSavings(resultWithResource, allPackages); } catch { // TBD } // update UI on main thread this.Dispatcher.BeginInvoke(new OutputComparisonDataToUIDelegate(OutputComparisonDataToUI), resultNoResource, resultWithResource); }
private AppxPackageComparisonResult AnalyzeFileSpaceSavings(AppxPackageComparisonResult result, List <AppxPackage> allAppxPackages) { // Unoptimized Size of Apps foreach (AppxPackage package in allAppxPackages) { result.UnoptimizedSizeOfApps += package.UncompressedSize; } // Optimzied Size of Apps foreach (string fileHash in result.CrossPackageDeDupdFiles.Keys) { result.OptimizedSizeOfApps += result.CrossPackageDeDupdFiles[fileHash].First().UncompressedSize; } return(result); }
private AppxPackageComparisonResult GetCrossPackageDeDupdFiles(AppxPackageComparisonResult result, List <AppxPackage> packages) { if (packages.Count <= 1) { return(result); } foreach (AppxPackage package in packages) { // TBD : if the packages are the same package but different architecture we'll still use all of them. // merge all lists together result.CrossPackageDeDupdFiles = result.CrossPackageDeDupdFiles .Concat(package.BlockMap) .GroupBy(kvp => kvp.Key) .ToDictionary(g => g.Key, g => g.SelectMany(v => v.Value).ToList()); } return(result); }
private List <DataGridResult> PopulateComparisonGrid(AppxPackageComparisonResult result) { List <DataGridResult> dataGridResult = new List <DataGridResult>(); foreach (string fileHash in result.CrossPackageDeDupdFiles.Keys) { if (result.CrossPackageDeDupdFiles[fileHash].Count > 1) { DataGridResult item = new DataGridResult() { FileName = Path.GetFileName(result.CrossPackageDeDupdFiles[fileHash].First().FileName), FileSize = string.Format("{0:#,#}", result.CrossPackageDeDupdFiles[fileHash].First().UncompressedSize), FileCount = result.CrossPackageDeDupdFiles[fileHash].Count.ToString(), }; dataGridResult.Add(item); } } return(dataGridResult); }
private AppxPackageComparisonResult GetInterPackageDupFiles(AppxPackageComparisonResult result, List <AppxPackage> packages) { foreach (AppxPackage package in packages) { // Iterate through each file in the block map foreach (string fileHash in package.BlockMap.Keys) { // if we find something that has more than one file hash (more than one of the same file) // remember it if (package.BlockMap[fileHash].Count() > 1) { if (!result.InterPackageDuplicateFiles.ContainsKey(package)) { result.InterPackageDuplicateFiles.Add(package, new List <List <AppxBlockMapFile> >()); } result.InterPackageDuplicateFiles[package].Add(package.BlockMap[fileHash]); } } } return(result); }
private void OutputComparisonDataToUI(AppxPackageComparisonResult resultNoResource, AppxPackageComparisonResult resultWithResource) { try { FileGrid.ItemsSource = PopulateComparisonGrid(resultWithResource); NameNoRP.Text = "No Resource Packs:"; OptimizedSizeOfAppsNoResource.Text = "Size "; UnoptimizedSizeOfAppsNoResource.Text = "Orig Size "; NameWithRP.Text = "With Resource Packs:"; OptimizedSizeOfAppsWithResource.Text = "Size "; UnoptimizedSizeOfAppsWithResource.Text = "Orig Size "; PopulateUI(resultNoResource.OptimizedSizeOfApps, resultNoResource.UnoptimizedSizeOfApps, resultWithResource.OptimizedSizeOfApps, resultWithResource.UnoptimizedSizeOfApps); ResetUI(); } catch { // TBD } }
private void Analyze_Async_Update(object state) { AppxPackageComparisonResult result = new AppxPackageComparisonResult(); try { List <string> packagePaths = state as List <string>; // make sure there are only two packages if (packagePaths.Count > 2) { ShowError("Too many packages", "There can only be 2 packages selected for an update check."); return; } else if (packagePaths.Count < 2) { ShowError("Too few packages", "There must be 2 packages selected for an update check."); return; } string firstPackagePath = packagePaths[0]; string secondPackagePath = packagePaths[1]; // make sure they're both the same package type if (0 != Path.GetExtension(firstPackagePath).ToLower() .CompareTo( Path.GetExtension(secondPackagePath).ToLower())) { ShowError("Different Package Types", "The packages must be of the same type (e.g. both .appxbundle or both .appx)"); return; } AppxManifest firstPackageManifest = AppxPackageReader.GetManifestFromPath(firstPackagePath); AppxManifest secondPackageManifest = AppxPackageReader.GetManifestFromPath(secondPackagePath); string errorMsg; if (!firstPackageManifest.IsUpdate(secondPackageManifest, out errorMsg)) { ShowError("Identities not suited for update", errorMsg); return; } AppxPackageReader incommingPackageReader; AppxPackageReader outgoingpackageReader; // firstPackageManifest is incomming (newer) if (firstPackageManifest.ComparePackageVersions(secondPackageManifest) > 0) { incommingPackageReader = new AppxPackageReader(firstPackagePath); outgoingpackageReader = new AppxPackageReader(secondPackagePath); } // secondPackageManifest is incomming (newer) else { outgoingpackageReader = new AppxPackageReader(firstPackagePath); incommingPackageReader = new AppxPackageReader(secondPackagePath); } // read the packages incommingPackageReader.Run(); outgoingpackageReader.Run(); // get all the packages List <AppxPackage> incommingPackageSet = new List <AppxPackage>(); List <AppxPackage> outgoingPackageSet = new List <AppxPackage>(); incommingPackageReader.Wait(); incommingPackageSet.AddRange(incommingPackageReader.MainPackages); incommingPackageSet.AddRange(incommingPackageReader.ResourcePackages); outgoingpackageReader.Wait(); outgoingPackageSet.AddRange(outgoingpackageReader.MainPackages); outgoingPackageSet.AddRange(outgoingpackageReader.ResourcePackages); // get the list of block map files Dictionary <string, List <AppxBlockMapFile> > incommingPackageFiles = new Dictionary <string, List <AppxBlockMapFile> >(); foreach (AppxPackage p in incommingPackageSet) { incommingPackageFiles = incommingPackageFiles.Concat(p.BlockMap) .GroupBy(kvp => kvp.Key) .ToDictionary(g => g.Key, g => g.SelectMany(v => v.Value).ToList()); } Dictionary <string, List <AppxBlockMapFile> > outgoingPackageFiles = new Dictionary <string, List <AppxBlockMapFile> >(); foreach (AppxPackage p in outgoingPackageSet) { outgoingPackageFiles = outgoingPackageFiles.Concat(p.BlockMap) .GroupBy(kvp => kvp.Key) .ToDictionary(g => g.Key, g => g.SelectMany(v => v.Value).ToList()); } // Determine the hardlinked files List <string> sameFileHashes = new List <string>(); foreach (string key in incommingPackageFiles.Keys) { // if it's the same if (outgoingPackageFiles.ContainsKey(key)) { sameFileHashes.Add(key); foreach (AppxBlockMapFile a in incommingPackageFiles[key]) { result.BytesHardlinked += a.UncompressedSize; } ChangeResult cr = new ChangeResult() { Package = incommingPackageFiles[key].First().ParentPackage.Manifest.FullName(), FileName = incommingPackageFiles[key].First().FileName, BlockHash = incommingPackageFiles[key].First().FinalFileHash, Size = incommingPackageFiles[key].First().UncompressedSize, }; result.FileHardLinkChangeResults.Add(cr.FileName, cr); } } // remove hardlinked files foreach (string key in sameFileHashes) { incommingPackageFiles.Remove(key); outgoingPackageFiles.Remove(key); } //get full list of blocks Dictionary <string, List <AppxBlockMapBlock> > incommingPackageBlocks = new Dictionary <string, List <AppxBlockMapBlock> >(); Dictionary <string, List <AppxBlockMapBlock> > outgoingPackageBlocks = new Dictionary <string, List <AppxBlockMapBlock> >(); foreach (List <AppxBlockMapFile> list in incommingPackageFiles.Values) { foreach (AppxBlockMapFile file in list) { foreach (AppxBlockMapBlock block in file.Blocks) { if (!incommingPackageBlocks.ContainsKey(block.Hash)) { incommingPackageBlocks.Add(block.Hash, new List <AppxBlockMapBlock>()); } incommingPackageBlocks[block.Hash].Add(block); } } } foreach (List <AppxBlockMapFile> list in outgoingPackageFiles.Values) { foreach (AppxBlockMapFile file in list) { foreach (AppxBlockMapBlock block in file.Blocks) { if (!outgoingPackageBlocks.ContainsKey(block.Hash)) { outgoingPackageBlocks.Add(block.Hash, new List <AppxBlockMapBlock>()); } outgoingPackageBlocks[block.Hash].Add(block); } } } // Determine Copied / Downloaded foreach (string hash in incommingPackageBlocks.Keys) { // if its going to be copied if (outgoingPackageBlocks.ContainsKey(hash)) { result.BlocksCopied += incommingPackageBlocks[hash].First().CompressedSize *(ulong)incommingPackageBlocks[hash].Count; ChangeResult cr = new ChangeResult() { Package = incommingPackageBlocks[hash].First().ParentFile.ParentPackage.Manifest.FullName(), FileName = incommingPackageBlocks[hash].First().ParentFile.FileName, BlockHash = incommingPackageBlocks[hash].First().Hash, Size = incommingPackageBlocks[hash].First().ParentFile.UncompressedSize, }; if (!result.BlockCopiedChangeResults.ContainsKey(cr.FileName)) { result.BlockCopiedChangeResults.Add(cr.FileName, cr); } } // if its going to be downloaded else if (!outgoingPackageBlocks.ContainsKey(hash)) { result.BlocksDownloaded += incommingPackageBlocks[hash].First().CompressedSize *(ulong)incommingPackageBlocks[hash].Count; ChangeResult cr = new ChangeResult() { Package = incommingPackageBlocks[hash].First().ParentFile.ParentPackage.Manifest.FullName(), FileName = incommingPackageBlocks[hash].First().ParentFile.FileName, BlockHash = incommingPackageBlocks[hash].First().Hash, Size = incommingPackageBlocks[hash].First().ParentFile.UncompressedSize, }; if (!result.BlockDownloadChangeResults.ContainsKey(cr.FileName)) { result.BlockDownloadChangeResults.Add(cr.FileName, cr); } } } foreach (string hash in outgoingPackageBlocks.Keys) { // if its going to be deleted if (!incommingPackageBlocks.ContainsKey(hash)) { result.BlocksDeleted += outgoingPackageBlocks[hash].First().CompressedSize *(ulong)outgoingPackageBlocks[hash].Count; ChangeResult cr = new ChangeResult() { Package = outgoingPackageBlocks[hash].First().ParentFile.ParentPackage.Manifest.FullName(), FileName = outgoingPackageBlocks[hash].First().ParentFile.FileName, BlockHash = outgoingPackageBlocks[hash].First().Hash, Size = outgoingPackageBlocks[hash].First().ParentFile.UncompressedSize, }; if (!result.BlockDeletedChangeResults.ContainsKey(cr.FileName)) { result.BlockDeletedChangeResults.Add(cr.FileName, cr); } } } } catch (Exception ex) { } this.Dispatcher.BeginInvoke(new OutputUpdateComparisonDataToUIDelegate(OutputUpdateComparisonDataToUI), result); }
private async void OutputUpdateComparisonDataToUI(AppxPackageComparisonResult result) { try { //FileGrid.ItemsSource = PopulateComparisonGridUpdate(result); string filename = @"c:\temp\output.txt"; File.AppendAllText(filename, "HardLinked Files" + Environment.NewLine); foreach (ChangeResult cr in result.FileHardLinkChangeResults.Values) { File.AppendAllText(filename, "Package: " + cr.Package + "\tFile: " + cr.FileName + "\tSize: " + cr.Size + Environment.NewLine); } File.AppendAllText(filename, "" + Environment.NewLine); File.AppendAllText(filename, "" + Environment.NewLine); File.AppendAllText(filename, "" + Environment.NewLine); File.AppendAllText(filename, "Downloaded Files" + Environment.NewLine); foreach (ChangeResult cr in result.BlockDownloadChangeResults.Values) { File.AppendAllText(filename, "Package: " + cr.Package + "\tFile: " + cr.FileName + "\t\t\tSize: " + cr.Size + Environment.NewLine); } File.AppendAllText(filename, "" + Environment.NewLine); File.AppendAllText(filename, "" + Environment.NewLine); File.AppendAllText(filename, "" + Environment.NewLine); File.AppendAllText(filename, "Files with similar blocks" + Environment.NewLine); foreach (ChangeResult cr in result.BlockCopiedChangeResults.Values) { File.AppendAllText(filename, "Package: " + cr.Package + "\tFile: " + cr.FileName + "\t\t\tSize: " + cr.Size + Environment.NewLine); } File.AppendAllText(filename, "" + Environment.NewLine); File.AppendAllText(filename, "" + Environment.NewLine); File.AppendAllText(filename, "" + Environment.NewLine); File.AppendAllText(filename, "Deleted Files" + Environment.NewLine); foreach (ChangeResult cr in result.BlockDeletedChangeResults.Values) { File.AppendAllText(filename, "Package: " + cr.Package + "\tFile: " + cr.FileName + "\t\t\tSize: " + cr.Size + Environment.NewLine); } OptimizedSizeOfAppsNoResource.Text = "Hardlinked "; UnoptimizedSizeOfAppsNoResource.Text = "Downloaded "; OptimizedSizeOfAppsWithResource.Text = "Deleted "; UnoptimizedSizeOfAppsWithResource.Text = "Blocks Copied "; PopulateUI(result.BytesHardlinked, result.BlocksDownloaded, result.BlocksDeleted, result.BlocksCopied); NameNoRP.Text = ""; NameWithRP.Text = ""; ResetUI(); } catch (Exception ex) { // TBD } }