/// <inheritdoc cref="IArchiver.ListFiles"/> public IEnumerable <IFileInArchive> ListFiles(string archivePath) { if (!File.Exists(archivePath)) { return(Enumerable.Empty <IFileInArchive>()); } var prolibExe = new ProcessIo(_prolibPath); if (!prolibExe.TryExecute(new ProcessArgs().Append(archivePath, "-list"))) // -date mdy { throw new Exception("Error while listing files from a .pl.", new Exception(prolibExe.BatchOutput.ToString())); } var outputList = new List <IFileInArchive>(); var regex = new Regex(@"^(.+)\s+(\d+)\s+(\w+)\s+(\d+)\s+(\d{2}\/\d{2}\/\d{2}\s\d{2}\:\d{2}\:\d{2})\s(\d{2}\/\d{2}\/\d{2}\s\d{2}\:\d{2}\:\d{2})"); foreach (var output in prolibExe.StandardOutputArray) { var match = regex.Match(output); if (match.Success) { // Third match is the file type. PROLIB recognizes two file types: R (r-code file type) and O (any other file type). // Fourth is the offset, the distance, in bytes, of the start of the file from the beginning of the library. var type = match.Groups[3].Value; var newFile = new FileInProlib { PathInArchive = match.Groups[1].Value.TrimEnd(), SizeInBytes = ulong.Parse(match.Groups[2].Value), IsRcode = !string.IsNullOrEmpty(type) && type[0] == 'R' }; if (DateTime.TryParseExact(match.Groups[5].Value, @"MM/dd/yy HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out var date)) { newFile.DateAdded = date; } if (DateTime.TryParseExact(match.Groups[6].Value, @"MM/dd/yy HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out date)) { newFile.LastWriteTime = date; } outputList.Add(newFile); } } return(outputList); }
/// <inheritdoc cref="IArchiverBasic.ArchiveFileSet"/> public int ArchiveFileSet(IEnumerable <IFileToArchive> filesToArchive) { var filesToPack = filesToArchive.ToList(); filesToPack.ForEach(f => f.Processed = false); int totalFiles = filesToPack.Count; int totalFilesDone = 0; foreach (var plGroupedFiles in filesToPack.GroupBy(f => f.ArchivePath)) { string uniqueTempFolder = null; try { var archiveFolder = CreateArchiveFolder(plGroupedFiles.Key); // create a unique temp folder for this .pl uniqueTempFolder = Path.Combine(archiveFolder, $"{Path.GetFileName(plGroupedFiles.Key)}~{Path.GetRandomFileName()}"); var dirInfo = Directory.CreateDirectory(uniqueTempFolder); dirInfo.Attributes |= FileAttributes.Hidden; var subFolders = new Dictionary <string, List <FilesToMove> >(); foreach (var file in plGroupedFiles) { var subFolderPath = Path.GetDirectoryName(Path.Combine(uniqueTempFolder, file.PathInArchive)); if (!string.IsNullOrEmpty(subFolderPath)) { if (!subFolders.ContainsKey(subFolderPath)) { subFolders.Add(subFolderPath, new List <FilesToMove>()); if (!Directory.Exists(subFolderPath)) { Directory.CreateDirectory(subFolderPath); } } if (File.Exists(file.SourcePath)) { subFolders[subFolderPath].Add(new FilesToMove(file.SourcePath, Path.Combine(uniqueTempFolder, file.PathInArchive), file.PathInArchive)); } } } var prolibExe = new ProcessIo(_prolibPath) { WorkingDirectory = uniqueTempFolder }; foreach (var subFolder in subFolders) { _cancelToken?.ThrowIfCancellationRequested(); // move files to the temp subfolder Parallel.ForEach(subFolder.Value, file => { if (file.Move) { File.Move(file.Origin, file.Temp); } else { File.Copy(file.Origin, file.Temp); } }); // for files containing a space, we don't have a choice, call extract for each... foreach (var file in subFolder.Value.Where(f => f.RelativePath.Contains(" "))) { if (!prolibExe.TryExecute(new ProcessArgs().Append(plGroupedFiles.Key, "-create", "-nowarn", "-add", file.RelativePath))) { throw new ArchiverException($"Failed to pack {file.Origin.PrettyQuote()} into {plGroupedFiles.Key.PrettyQuote()} and relative archive path {file.RelativePath}.", new ArchiverException(prolibExe.BatchOutput.ToString())); } } var remainingFiles = subFolder.Value.Where(f => !f.RelativePath.Contains(" ")).ToList(); if (remainingFiles.Count > 0) { // for the other files, we can use the -pf parameter var pfContent = new StringBuilder(); pfContent.AppendLine("-create -nowarn -add"); foreach (var file in remainingFiles) { pfContent.AppendLine(file.RelativePath); } var pfPath = Path.Combine(uniqueTempFolder, $"{Path.GetFileName(plGroupedFiles.Key)}~{Path.GetRandomFileName()}.pf"); File.WriteAllText(pfPath, pfContent.ToString(), _encoding); if (!prolibExe.TryExecute(new ProcessArgs().Append(plGroupedFiles.Key, "-pf", pfPath))) { throw new ArchiverException($"Failed to pack to {plGroupedFiles.Key.PrettyQuote()}.", new Exception(prolibExe.BatchOutput.ToString())); } if (File.Exists(pfPath)) { File.Delete(pfPath); } } // move files from the temp subfolder foreach (var file in subFolder.Value) { try { if (file.Move) { File.Move(file.Temp, file.Origin); } else if (!File.Exists(file.Temp)) { throw new ArchiverException($"Failed to move back the temporary file {file.Origin} from {file.Temp}."); } } catch (Exception e) { throw new ArchiverException($"Failed to move back the temporary file {file.Origin} from {file.Temp}.", e); } totalFilesDone++; OnProgress?.Invoke(this, ArchiverEventArgs.NewProgress(plGroupedFiles.Key, file.RelativePath, Math.Round(totalFilesDone / (double)totalFiles * 100, 2))); } } // compress .pl prolibExe.TryExecute(new ProcessArgs().Append(plGroupedFiles.Key, "-compress", "-nowarn")); foreach (var file in plGroupedFiles) { file.Processed = true; } } catch (OperationCanceledException) { throw; } catch (Exception e) { throw new ArchiverException($"Failed to pack to {plGroupedFiles.Key.PrettyQuote()}.", e); } finally { // delete temp folder if (Directory.Exists(uniqueTempFolder)) { Directory.Delete(uniqueTempFolder, true); } } } return(totalFilesDone); }
/// <inheritdoc cref="IArchiver.ExtractFileSet"/> public int ExtractFileSet(IEnumerable <IFileInArchiveToExtract> filesToExtractIn) { var filesToExtract = filesToExtractIn.ToList(); filesToExtract.ForEach(f => f.Processed = false); int totalFiles = filesToExtract.Count; int totalFilesDone = 0; var prolibExe = new ProcessIo(_prolibPath); foreach (var plGroupedFiles in filesToExtract.GroupBy(f => f.ArchivePath)) { if (!File.Exists(plGroupedFiles.Key)) { continue; } // process only files that actually exist var archiveFileList = ListFiles(plGroupedFiles.Key).Select(f => f.PathInArchive).ToHashSet(); var plGroupedFilesFiltered = plGroupedFiles.Where(f => archiveFileList.Contains(f.PathInArchive)).ToList(); try { foreach (var extractDirGroupedFiles in plGroupedFilesFiltered.GroupBy(f => Path.GetDirectoryName(f.ExtractionPath))) { prolibExe.WorkingDirectory = extractDirGroupedFiles.Key; Directory.CreateDirectory(extractDirGroupedFiles.Key); // for files containing a space, we don't have a choice, call extract for each... foreach (var file in extractDirGroupedFiles.Where(deploy => deploy.PathInArchive.Contains(" "))) { _cancelToken?.ThrowIfCancellationRequested(); if (File.Exists(file.ExtractionPath)) { File.Delete(file.ExtractionPath); } if (!prolibExe.TryExecute(new ProcessArgs().Append(plGroupedFiles.Key, "-nowarn", "-yank", file.PathInArchive))) { throw new ArchiverException($"Failed to extract {file.PathInArchive.PrettyQuote()} from {plGroupedFiles.Key.PrettyQuote()}.", new Exception(prolibExe.BatchOutput.ToString())); } totalFilesDone++; OnProgress?.Invoke(this, ArchiverEventArgs.NewProgress(plGroupedFiles.Key, file.PathInArchive, Math.Round(totalFilesDone / (double)totalFiles * 100, 2))); } _cancelToken?.ThrowIfCancellationRequested(); var remainingFiles = extractDirGroupedFiles.Where(deploy => !deploy.PathInArchive.Contains(" ")).ToList(); if (remainingFiles.Count > 0) { // for the other files, we can use the -pf parameter var pfContent = new StringBuilder(); pfContent.AppendLine("-nowarn"); pfContent.AppendLine("-yank"); foreach (var file in remainingFiles) { pfContent.AppendLine(file.PathInArchive); if (File.Exists(file.ExtractionPath)) { File.Delete(file.ExtractionPath); } } var pfPath = Path.Combine(extractDirGroupedFiles.Key, $"{Path.GetFileName(plGroupedFiles.Key)}~{Path.GetRandomFileName()}.pf"); File.WriteAllText(pfPath, pfContent.ToString(), _encoding); if (!prolibExe.TryExecute(new ProcessArgs().Append(plGroupedFiles.Key, "-pf", pfPath))) { throw new ArchiverException($"Failed to extract from {plGroupedFiles.Key.PrettyQuote()}.", new Exception(prolibExe.BatchOutput.ToString())); } foreach (var file in remainingFiles) { totalFilesDone++; OnProgress?.Invoke(this, ArchiverEventArgs.NewProgress(plGroupedFiles.Key, file.PathInArchive, Math.Round(totalFilesDone / (double)totalFiles * 100, 2))); } if (File.Exists(pfPath)) { File.Delete(pfPath); } } } foreach (var file in plGroupedFiles) { file.Processed = true; } } catch (OperationCanceledException) { throw; } catch (Exception e) { throw new ArchiverException($"Failed to process {plGroupedFiles.Key.PrettyQuote()}.", e); } } return(totalFilesDone); }
/// <inheritdoc cref="IArchiver.MoveFileSet"/> public int MoveFileSet(IEnumerable <IFileInArchiveToMove> filesToMoveIn) { var filesToMove = filesToMoveIn.ToList(); filesToMove.ForEach(f => f.Processed = false); int totalFiles = filesToMove.Count; int totalFilesDone = 0; foreach (var plGroupedFiles in filesToMove.GroupBy(f => f.ArchivePath)) { string uniqueTempFolder = null; try { // process only files that actually exist var archiveFileList = ListFiles(plGroupedFiles.Key).Select(f => f.PathInArchive).ToHashSet(); var plGroupedFilesFiltered = plGroupedFiles.Where(f => archiveFileList.Contains(f.PathInArchive)).ToList(); if (!plGroupedFilesFiltered.Any()) { continue; } var archiveFolder = CreateArchiveFolder(plGroupedFiles.Key); // create a unique temp folder for this .pl uniqueTempFolder = Path.Combine(archiveFolder, $"{Path.GetFileName(plGroupedFiles.Key)}~{Path.GetRandomFileName()}"); var dirInfo = Directory.CreateDirectory(uniqueTempFolder); dirInfo.Attributes |= FileAttributes.Hidden; var subFolders = new Dictionary <string, List <FilesToMove> >(); foreach (var file in plGroupedFilesFiltered) { var subFolderPath = Path.GetDirectoryName(Path.Combine(uniqueTempFolder, file.NewRelativePathInArchive)); if (!string.IsNullOrEmpty(subFolderPath)) { if (!subFolders.ContainsKey(subFolderPath)) { subFolders.Add(subFolderPath, new List <FilesToMove>()); if (!Directory.Exists(subFolderPath)) { Directory.CreateDirectory(subFolderPath); } } subFolders[subFolderPath].Add(new FilesToMove(file.PathInArchive, Path.Combine(uniqueTempFolder, file.NewRelativePathInArchive), file.NewRelativePathInArchive)); } } var prolibExe = new ProcessIo(_prolibPath); foreach (var subFolder in subFolders) { _cancelToken?.ThrowIfCancellationRequested(); foreach (var file in subFolder.Value) { prolibExe.WorkingDirectory = Path.GetDirectoryName(file.Temp); if (!prolibExe.TryExecute(new ProcessArgs().Append(plGroupedFiles.Key, "-nowarn", "yank", file.Origin))) { throw new ArchiverException($"Failed to extract {file.Origin.PrettyQuote()} from {plGroupedFiles.Key.PrettyQuote()}.", new Exception(prolibExe.BatchOutput.ToString())); } if (!prolibExe.TryExecute(new ProcessArgs().Append(plGroupedFiles.Key, "-nowarn", "-delete", file.Origin))) { throw new ArchiverException($"Failed to delete {file.Origin.PrettyQuote()} in {plGroupedFiles.Key.PrettyQuote()}.", new ArchiverException(prolibExe.BatchOutput.ToString())); } File.Move(Path.Combine(prolibExe.WorkingDirectory, Path.GetFileName(file.Origin)), file.Temp); prolibExe.WorkingDirectory = uniqueTempFolder; prolibExe.TryExecute(new ProcessArgs().Append(plGroupedFiles.Key, "-nowarn", "-delete", file.RelativePath)); if (!prolibExe.TryExecute(new ProcessArgs().Append(plGroupedFiles.Key, "-create", "-nowarn", "-add", file.RelativePath))) { throw new ArchiverException($"Failed to pack {file.Origin.PrettyQuote()} into {plGroupedFiles.Key.PrettyQuote()} and relative archive path {file.RelativePath}.", new ArchiverException(prolibExe.BatchOutput.ToString())); } totalFilesDone++; OnProgress?.Invoke(this, ArchiverEventArgs.NewProgress(plGroupedFiles.Key, file.RelativePath, Math.Round(totalFilesDone / (double)totalFiles * 100, 2))); } } // compress .pl prolibExe.TryExecute(new ProcessArgs().Append(plGroupedFiles.Key, "-compress", "-nowarn")); // delete temp folder Directory.Delete(uniqueTempFolder, true); foreach (var file in plGroupedFiles) { file.Processed = true; } } catch (OperationCanceledException) { throw; } catch (Exception e) { throw new ArchiverException($"Failed to pack to {plGroupedFiles.Key.PrettyQuote()}.", e); } finally { // delete temp folder if (Directory.Exists(uniqueTempFolder)) { Directory.Delete(uniqueTempFolder, true); } } } return(totalFilesDone); }