/// <nodoc /> private async Task <EvaluationResult> ValidateAndStoreIncrementalExtractState(PipConstructionHelper pipConstructionHelper, DownloadData downloadData) { var archive = downloadData.DownloadedFilePath.ToString(m_context.PathTable); var target = downloadData.ContentsFolder.Path.ToString(m_context.PathTable); try { var allFiles = new List <FileArtifact>(); var enumeratResult = FileUtilities.EnumerateDirectoryEntries(target, true, "*", (dir, fileName, attributes) => { if ((attributes & FileAttributes.Directory) == 0) { var filePath = Path.Combine(dir, fileName); allFiles.Add(FileArtifact.CreateSourceFile(AbsolutePath.Create(m_context.PathTable, filePath))); } }); if (!enumeratResult.Succeeded) { var error = new Win32Exception(enumeratResult.NativeErrorCode); m_logger.ErrorListingPackageContents(m_context.LoggingContext, downloadData.Settings.ModuleName, archive, target, error.Message); return(EvaluationResult.Error); } if (allFiles.Count == 0) { m_logger.ErrorListingPackageContents(m_context.LoggingContext, downloadData.Settings.ModuleName, archive, target, "file list is empty"); return(EvaluationResult.Error); } var sortedFiles = SortedReadOnlyArray <FileArtifact, OrdinalFileArtifactComparer> .CloneAndSort( allFiles, OrdinalFileArtifactComparer.Instance); var hashes = new Dictionary <AbsolutePath, ContentHash>(); foreach (var file in allFiles) { var hash = await GetContentHashAsync(file); hashes.Add(file.Path, hash); } var incrementalState = new ExtractIncrementalState(downloadData, sortedFiles, hashes); await incrementalState.SaveAsync(m_context); return(SealDirectory(pipConstructionHelper, downloadData, downloadData.ContentsFolder, sortedFiles)); } catch (Exception e) when(e is BuildXLException || e is IOException || e is UnauthorizedAccessException) { m_logger.ErrorExtractingArchive(m_context.LoggingContext, downloadData.Settings.ModuleName, archive, target, e.Message); return(EvaluationResult.Error); } }
/// <nodoc /> private async Task <EvaluationResult> CheckIfExtractIsNeededAsync(PipConstructionHelper pipConstructionHelper, DownloadData downloadData) { try { if (m_context.FileSystem.IsDirectory(downloadData.ContentsFolder)) { var incrementalState = await ExtractIncrementalState.TryLoadAsync(m_logger, m_context, downloadData); if (incrementalState != null) { // Check all files still have the same hash. This should use the hash cache based on USN so be very fast. foreach (var hashKv in incrementalState.Hashes) { if (!m_context.FileSystem.Exists(hashKv.Key)) { // File is not present, extraction is needed. return(EvaluationResult.Continue); } var hash = await GetContentHashAsync(hashKv.Key); if (hash != hashKv.Value) { // File has changed, extraction is needed. return(EvaluationResult.Continue); } } // All hashes verified, update the manifest await incrementalState.SaveAsync(m_context); return(SealDirectory(pipConstructionHelper, downloadData, downloadData.ContentsFolder, incrementalState.Files)); } } } catch (IOException e) { m_logger.ErrorCheckingIncrementality(m_context.LoggingContext, downloadData.Settings.ModuleName, e.Message); return(EvaluationResult.Error); } catch (UnauthorizedAccessException e) { m_logger.ErrorCheckingIncrementality(m_context.LoggingContext, downloadData.Settings.ModuleName, e.Message); return(EvaluationResult.Error); } // Extraction is needed return(EvaluationResult.Continue); }
/// <nodoc /> public static async Task <ExtractIncrementalState> TryLoadAsync(Logger logger, FrontEndContext context, DownloadData downloadData) { var manifestFilePath = downloadData.ExtractManifestFile.ToString(context.PathTable); ExtractIncrementalState result = null; if (!FileUtilities.Exists(manifestFilePath)) { return(null); } using (var reader = new StreamReader(manifestFilePath)) { var versionLine = await reader.ReadLineAsync(); if (versionLine == null || !string.Equals(versionLine, ManifestVersion, StringComparison.Ordinal)) { logger.ExtractManifestDoesNotMatch(context.LoggingContext, downloadData.Settings.ModuleName, downloadData.Settings.Url, "version", ManifestVersion, versionLine); return(null); } var urlLine = await reader.ReadLineAsync(); if (!string.Equals(urlLine, downloadData.Settings.Url, StringComparison.Ordinal)) { logger.ExtractManifestDoesNotMatch(context.LoggingContext, downloadData.Settings.ModuleName, downloadData.Settings.Url, "url", downloadData.Settings.Url, urlLine); return(null); } var archiveTypeLine = await reader.ReadLineAsync(); if (archiveTypeLine == null || !Enum.TryParse <DownloadArchiveType>(archiveTypeLine, out var archiveType) || archiveType != downloadData.Settings.ArchiveType) { logger.ExtractManifestDoesNotMatch(context.LoggingContext, downloadData.Settings.ModuleName, downloadData.Settings.Url, "archiveType", downloadData.Settings.ArchiveType.ToString(), archiveTypeLine); return(null); } var fileCountLine = await reader.ReadLineAsync(); if (fileCountLine == null || !uint.TryParse(fileCountLine, out var fileCount)) { return(null); } var hashes = new Dictionary <AbsolutePath, ContentHash>(); var files = new FileArtifact[fileCount]; for (int i = 0; i < fileCount; i++) { var filePathLine = await reader.ReadLineAsync(); if (filePathLine == null || !RelativePath.TryCreate(context.StringTable, filePathLine, out var relativeFilePath)) { return(null); } var hashLine = await reader.ReadLineAsync(); if (hashLine == null || !ContentHash.TryParse(hashLine, out var contentHash)) { return(null); } var filePath = downloadData.ContentsFolder.Path.Combine(context.PathTable, relativeFilePath); files[i] = FileArtifact.CreateSourceFile(filePath); hashes[filePath] = contentHash; } var sortedFiles = SortedReadOnlyArray <FileArtifact, OrdinalFileArtifactComparer> .SortUnsafe( files, OrdinalFileArtifactComparer.Instance); result = new ExtractIncrementalState(downloadData, sortedFiles, hashes); } return(result); }