public void ProcessIo_ExitNonZero() { if (!Utils.IsRuntimeWindowsPlatform) { return; } var process = new ProcessIo(@"C:\Windows\System32\net.exe"); process.Execute(new ProcessArgs().Append("use").Append("7874987498")); Assert.AreNotEqual(0, process.ExitCode); Assert.IsTrue(process.ErrorOutputArray.Count > 0); Assert.IsTrue(process.StandardOutputArray.Count == 0); }
/// <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); }
public ProlibPackager(string archivePath, string prolibPath) { _archivePath = archivePath; _prolibExe = new ProcessIo(prolibPath); }
public ProlibExtractor(string archivePath, string prolibPath, string plExtractionFolder) { _archivePath = archivePath; _plExtractionFolder = plExtractionFolder; _prolibExe = new ProcessIo(prolibPath); }
/// <summary> /// Deploy a given list of files (can reduce the list if there are duplicated items so it returns it) /// </summary> public List <FileToDeploy> DeployFiles(List <FileToDeploy> deployToDo, Action <float> updateDeploymentPercentage = null) { int[] totalFile = { 0 }; int[] nbFilesDone = { 0 }; // make sure to transfer a given file only once at the same place (happens with .cls file since a source // can have several .r files generated if it is used in another classes) deployToDo = deployToDo .GroupBy(deploy => deploy.To) .Select(group => group.FirstOrDefault(move => Path.GetFileNameWithoutExtension(move.From ?? "").Equals(Path.GetFileNameWithoutExtension(move.Origin))) ?? group.First()) .ToList(); totalFile[0] = deployToDo.Count; // check that every target dir exist (for copy/move deployments) deployToDo .Where(deploy => deploy.DeployType == DeployType.Copy || deploy.DeployType == DeployType.Move) .GroupBy(deploy => Path.GetDirectoryName(deploy.To)) .Select(group => group.First()) .ToNonNullList() .ForEach(deploy => Utils.CreateDirectory(Path.GetDirectoryName(deploy.To))); #region for archives (zip/pl) // for archives, compute the path to the archive file (+ make sure the directory of the archive exists) deployToDo.Where(deploy => deploy.DeployType <= DeployType.Archive).ToNonNullList().ForEach(deploy => { var ext = deploy.DeployType == DeployType.Prolib ? ".pl" : ".zip"; var pos = deploy.To.LastIndexOf(ext, StringComparison.CurrentCultureIgnoreCase); if (pos >= 0) { var posEnd = pos + ext.Length; deploy.ArchivePath = deploy.To.Substring(0, posEnd); deploy.RelativePathInArchive = deploy.To.Substring(posEnd + 1); // ensure that the folder to the .archive file exists Utils.CreateDirectory(Path.GetDirectoryName(deploy.ArchivePath)); // for .zip, open the zip stream for later usage if (deploy.DeployType > DeployType.Prolib) { if (!_openedZip.ContainsKey(deploy.ArchivePath)) { try { if (!File.Exists(deploy.ArchivePath)) { _openedZip.Add(deploy.ArchivePath, ZipStorer.Create(deploy.ArchivePath, "Created with 3P @ " + DateTime.Now + "\r\n" + Config.UrlWebSite)); } else { _openedZip.Add(deploy.ArchivePath, ZipStorer.Open(deploy.ArchivePath, FileAccess.Write)); _filesToRemoveFromZip.Add(deploy.ArchivePath, new HashSet <string>()); } } catch (Exception e) { ErrorHandler.ShowErrors(e, "Couldn't create/open the .zip file"); } } // we didn't create the zip? then we need to remove this file if it exists if (_filesToRemoveFromZip.ContainsKey(deploy.ArchivePath)) { _filesToRemoveFromZip[deploy.ArchivePath].Add(deploy.RelativePathInArchive.Replace('\\', '/')); } } } }); #endregion #region for .pl deployments, we treat them before anything else // for PL, we need to MOVE each file into a temporary folder with the internal structure of the .pl file, // then move it back where it was for further deploys... var plDeployments = deployToDo .Where(deploy => deploy.DeployType == DeployType.Prolib) .ToNonNullList(); if (plDeployments.Count > 0) { // then we create a unique temporary folder for each .pl var dicPlToTempFolder = new Dictionary <string, string>(StringComparer.CurrentCultureIgnoreCase); foreach (var pathPl in plDeployments.Where(deploy => !string.IsNullOrEmpty(deploy.ArchivePath)).Select(deploy => deploy.ArchivePath).Distinct()) { // create a unique temp folder for this .pl if (!dicPlToTempFolder.ContainsKey(pathPl)) { var plDirPath = Path.GetDirectoryName(pathPl); if (plDirPath != null) { var uniqueTempFolder = Path.Combine(plDirPath, Path.GetFileName(pathPl) + "~" + Path.GetRandomFileName()); dicPlToTempFolder.Add(pathPl, uniqueTempFolder); Utils.CreateDirectory(uniqueTempFolder, FileAttributes.Hidden); } } } var prolibMessage = new StringBuilder(); // for each .pl that needs to be created... foreach (var pl in dicPlToTempFolder) { var pl1 = pl; var onePlDeployments = plDeployments .Where(deploy => !string.IsNullOrEmpty(deploy.ArchivePath) && deploy.ArchivePath.Equals(pl1.Key)) .ToNonNullList(); if (onePlDeployments.Count == 0) { continue; } // we set the temporary folder on which each file will be copied.. // Tuple : <(base) temp directory, relative path in pl, path to .pl> var dicTempFolderToPl = new Dictionary <string, Tuple <string, string, string> >(StringComparer.CurrentCultureIgnoreCase); foreach (var fileToDeploy in onePlDeployments) { if (string.IsNullOrEmpty(fileToDeploy.ArchivePath)) { continue; } if (dicPlToTempFolder.ContainsKey(fileToDeploy.ArchivePath)) { fileToDeploy.ToTemp = Path.Combine( dicPlToTempFolder[fileToDeploy.ArchivePath], fileToDeploy.To.Replace(fileToDeploy.ArchivePath, "").TrimStart('\\') ); // If not already done, remember that the *.r code in this temp folder must be integrated to this .pl file var tempSubFolder = Path.GetDirectoryName(fileToDeploy.ToTemp); if (!string.IsNullOrEmpty(tempSubFolder) && !dicTempFolderToPl.ContainsKey(tempSubFolder)) { dicTempFolderToPl.Add( tempSubFolder, new Tuple <string, string, string>( dicPlToTempFolder[fileToDeploy.ArchivePath], // path of the temp dir Path.GetDirectoryName(fileToDeploy.To.Replace(fileToDeploy.ArchivePath, "").TrimStart('\\')), // relative path in .pl fileToDeploy.ArchivePath) // path to the .pl file ); // also, create the folder Utils.CreateDirectory(tempSubFolder); } } } var prolibExe = new ProcessIo(ProEnv.ProlibPath); // for each subfolder in the .pl foreach (var plSubFolder in dicTempFolderToPl) { var onePlSubFolderDeployments = onePlDeployments .Where(deploy => plSubFolder.Key.Equals(Path.GetDirectoryName(deploy.ToTemp))) .ToNonNullList(); if (onePlSubFolderDeployments.Count == 0) { continue; } Parallel.ForEach(onePlSubFolderDeployments, deploy => { if (File.Exists(deploy.From)) { deploy.IsOk = !string.IsNullOrEmpty(deploy.ToTemp) && Utils.MoveFile(deploy.From, deploy.ToTemp); } if (deploy.IsOk) { nbFilesDone[0]++; } if (updateDeploymentPercentage != null) { updateDeploymentPercentage((float)nbFilesDone[0] / totalFile[0] * 100); } }); // now we just need to add the content of temp folders into the .pl prolibExe.StartInfo.WorkingDirectory = plSubFolder.Value.Item1; // base temp dir prolibExe.Arguments = plSubFolder.Value.Item3.ProQuoter() + " -create -nowarn -add " + Path.Combine(plSubFolder.Value.Item2, "*").ProQuoter(); if (!prolibExe.TryDoWait(true)) { prolibMessage.Append(prolibExe.ErrorOutput); } Parallel.ForEach(onePlSubFolderDeployments, deploy => { deploy.IsOk = deploy.IsOk && Utils.MoveFile(deploy.ToTemp, deploy.From); }); } // compress .pl prolibExe.StartInfo.WorkingDirectory = Path.GetDirectoryName(pl.Key) ?? ""; prolibExe.Arguments = pl.Key.ProQuoter() + " -compress -nowarn"; if (!prolibExe.TryDoWait(true)) { prolibMessage.Append(prolibExe.ErrorOutput); } // delete temp folders Utils.DeleteDirectory(pl.Value, true); } if (prolibMessage.Length > 0) { UserCommunication.Notify("Errors occured when trying to create/add files to the .pl file :<br>" + prolibMessage, MessageImg.MsgError, "Prolib output", "Errors"); } } #endregion #region for zip // remove the files that are already in the zip file or they will appear twice when we add them foreach (var kpv in _filesToRemoveFromZip) { ZipStorer zip = _openedZip[kpv.Key]; var filesToDelete = zip.ReadCentralDir().Where(zipFileEntry => kpv.Value.Contains(zipFileEntry.FilenameInZip)).ToList(); _openedZip.Remove(kpv.Key); ZipStorer.RemoveEntries(ref zip, filesToDelete); _openedZip.Add(kpv.Key, zip); } #endregion // do a deployment action for each file (parallel for MOVE and COPY) Parallel.ForEach(deployToDo.Where(deploy => deploy.DeployType >= DeployType.Copy), file => { if (DeploySingleFile(file)) { nbFilesDone[0]++; } if (updateDeploymentPercentage != null) { updateDeploymentPercentage((float)nbFilesDone[0] / totalFile[0] * 100); } }); // don't use parallel for the other types foreach (var file in deployToDo.Where(deploy => deploy.DeployType < DeployType.Copy)) { if (DeploySingleFile(file)) { nbFilesDone[0]++; } if (updateDeploymentPercentage != null) { updateDeploymentPercentage((float)nbFilesDone[0] / totalFile[0] * 100); } } #region for zip, dispose of zipStorers // also, need to dispose of the object/stream here foreach (var zipStorer in _openedZip) { zipStorer.Value.Close(); } _openedZip.Clear(); #endregion return(deployToDo); }
/// <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); }