/// <summary> /// Extract the files given RelativePathInPack /// </summary> /// <param name="files"></param> public void ExtractFiles(List <string> files) { _prolibExe.StartInfo.WorkingDirectory = _plExtractionFolder; // create the subfolders needed to extract each file foreach (var folder in files.Select(Path.GetDirectoryName).Distinct(StringComparer.CurrentCultureIgnoreCase)) { try { Directory.CreateDirectory(Path.Combine(_plExtractionFolder, folder)); } catch (Exception e) { ErrorHandler.LogError(e); } } // for files containing a space, we don't have a choice, call delete for each... foreach (var file in files.Where(deploy => deploy.ContainsFast(" "))) { _prolibExe.Arguments = _archivePath.Quoter() + " -extract " + file.Quoter(); if (!_prolibExe.TryDoWait(true)) { ErrorHandler.LogError(new Exception(_prolibExe.ErrorOutput.ToString()), "Erreur durant l'extraction de fichiers depuis une .pl"); } } var remainingFiles = files.Where(deploy => !deploy.ContainsFast(" ")).ToList(); if (remainingFiles.Count > 0) { // for the other files, we can use the -pf parameter var pfContent = new StringBuilder(); pfContent.AppendLine("-extract"); foreach (var file in remainingFiles) { pfContent.AppendLine(file); } var pfPath = _plExtractionFolder + Path.GetFileName(_archivePath) + "~" + Path.GetRandomFileName() + ".pf"; try { File.WriteAllText(pfPath, pfContent.ToString(), Encoding.Default); } catch (Exception e) { ErrorHandler.LogError(e); } _prolibExe.Arguments = _archivePath.Quoter() + " -pf " + pfPath.Quoter(); if (!_prolibExe.TryDoWait(true)) { ErrorHandler.LogError(new Exception(_prolibExe.ErrorOutput.ToString()), "Erreur durant l'extraction de fichiers depuis une .pl"); } try { if (File.Exists(pfPath)) { File.Delete(pfPath); } } catch (Exception e) { ErrorHandler.LogError(e); } } }
public void PackFileSet(IDictionary <string, FileToDeployInPack> files, CompressionLevel compLevel, EventHandler <ArchiveProgressEventArgs> progressHandler) { var archiveFolder = Path.GetDirectoryName(_archivePath); if (!string.IsNullOrEmpty(archiveFolder)) { _prolibExe.StartInfo.WorkingDirectory = archiveFolder; } // for files containing a space, we don't have a choice, call delete for each... foreach (var file in files.Values.Where(deploy => deploy.RelativePathInPack.ContainsFast(" "))) { _prolibExe.Arguments = _archivePath.ProQuoter() + " -delete " + file.RelativePathInPack.ProQuoter(); var isOk = _prolibExe.TryDoWait(true); if (progressHandler != null) { progressHandler(this, new ArchiveProgressEventArgs(ArchiveProgressType.FinishFile, file.RelativePathInPack, isOk ? null : new Exception(_prolibExe.ErrorOutput.ToString()))); } } var remainingFiles = files.Values.Where(deploy => !deploy.RelativePathInPack.ContainsFast(" ")).ToList(); if (remainingFiles.Count > 0) { // for the other files, we can use the -pf parameter var pfContent = new StringBuilder(); pfContent.AppendLine("-delete"); foreach (var file in remainingFiles) { pfContent.AppendLine(file.RelativePathInPack); } Exception ex = null; var pfPath = _archivePath + "~" + Path.GetRandomFileName() + ".pf"; try { File.WriteAllText(pfPath, pfContent.ToString(), Encoding.Default); } catch (Exception e) { ex = e; } _prolibExe.Arguments = _archivePath.ProQuoter() + " -pf " + pfPath.ProQuoter(); var isOk = _prolibExe.TryDoWait(true); try { if (ex == null) { File.Delete(pfPath); } } catch (Exception e) { ex = e; } if (progressHandler != null) { foreach (var file in files.Values.Where(deploy => !deploy.RelativePathInPack.ContainsFast(" "))) { progressHandler(this, new ArchiveProgressEventArgs(ArchiveProgressType.FinishFile, file.RelativePathInPack, ex ?? (isOk ? null : new Exception(_prolibExe.ErrorOutput.ToString())))); } } } }
/// <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); }