/// <summary> /// Generate an html report for the current deployment /// </summary> public string FormatDeploymentResults() { StringBuilder currentReport = new StringBuilder(); currentReport.Append(@"<h2>Results :</h2>"); currentReport.Append(@"<div class='IndentDiv'>"); if (HasBeenCancelled) { // the process has been canceled currentReport.Append(@"<div><img style='padding-right: 20px;' src='Warning30x30' height='15px'>The deployment has been canceled by the user</div>"); } else if (CompilationHasFailed) { // provide info on the possible error! currentReport.Append(@"<div><img style='padding-right: 20px;' src='Error30x30' height='15px'>At least one process has ended in error, the compilation has been canceled</div>"); if (_proCompilation.CompilationFailedOnMaxUser) { currentReport.Append(@"<div><img style='padding-right: 20px;' src='Help30x30' height='15px'>One or more processes started for this compilation tried to connect to the database and failed because the maximum number of connection has been reached (error 748). To correct this problem, you can either :<br><li>reduce the number of processes to use for each core of your computer</li><li>or increase the maximum of connections for your database (-n parameter in the PROSERVE command)</li></div>"); } } else if (_deploymentErrorOccured) { currentReport.Append(@"<div><img style='padding-right: 20px;' src='Error30x30' height='15px'>Le déploiement a échoué</div>"); } var listLinesCompilation = new List <Tuple <int, string> >(); StringBuilder line = new StringBuilder(); var totalDeployedFiles = 0; var nbDeploymentError = 0; var nbCompilationError = 0; var nbCompilationWarning = 0; // compilation errors foreach (var fileInError in _proCompilation.ListFilesToCompile.Where(file => file.Errors != null)) { bool hasError = fileInError.Errors.Exists(error => error.Level >= ErrorLevel.Error); bool hasWarning = fileInError.Errors.Exists(error => error.Level < ErrorLevel.Error); if (hasError || hasWarning) { // only add compilation errors line.Clear(); line.Append("<div %ALTERNATE%style=\"background-repeat: no-repeat; background-image: url('" + (hasError ? "Error30x30" : "Warning30x30") + "'); padding-left: 35px; padding-top: 6px; padding-bottom: 6px;\">"); line.Append(ProExecutionCompile.FormatCompilationResultForSingleFile(fileInError.SourcePath, fileInError, null)); line.Append("</div>"); listLinesCompilation.Add(new Tuple <int, string>(hasError ? 3 : 2, line.ToString())); } if (hasError) { nbCompilationError++; } else if (hasWarning) { nbCompilationWarning++; } } // for each deploy step var listLinesByStep = new Dictionary <int, List <Tuple <int, string> > > { { 0, new List <Tuple <int, string> >() } }; foreach (var kpv in _filesToDeployPerStep) { // group either by directory name or by pack name var groupDirectory = kpv.Value.GroupBy(deploy => deploy.GroupKey).Select(deploys => deploys.ToList()).ToList(); foreach (var group in groupDirectory.OrderByDescending(list => list.First().DeployType).ThenBy(list => list.First().GroupKey)) { var deployFailed = group.Exists(deploy => !deploy.IsOk); var first = group.First(); line.Clear(); line.Append("<div %ALTERNATE%style=\"background-repeat: no-repeat; background-image: url('" + (deployFailed ? "Error30x30" : "Ok30x30") + "'); padding-left: 35px; padding-top: 6px; padding-bottom: 6px;\">"); line.Append(first.ToStringGroupHeader()); foreach (var fileToDeploy in group.OrderBy(deploy => deploy.To)) { line.Append(fileToDeploy.ToStringDescription(kpv.Key <= 1 ? _proEnv.BaseLocalPath : _proEnv.BaseCompilationPath)); } line.Append("</div>"); if (!listLinesByStep.ContainsKey(kpv.Key)) { listLinesByStep.Add(kpv.Key, new List <Tuple <int, string> >()); } listLinesByStep[kpv.Key].Add(new Tuple <int, string>(deployFailed ? 3 : 1, line.ToString())); if (deployFailed) { nbDeploymentError += group.Count(deploy => !deploy.IsOk); } else { totalDeployedFiles += group.Count; } } } // compilation currentReport.Append(@"<div style='padding-top: 7px; padding-bottom: 7px;'>Compiling <b>" + _proCompilation.NbFilesToCompile + "</b> files : <b>" + Utils.GetNbFilesPerType(_proCompilation.GetListOfFileToCompile.Select(compile => compile.SourcePath).ToList()).Aggregate("", (current, kpv) => current + (@"<img style='padding-right: 5px;' src='" + Utils.GetExtensionImage(kpv.Key.ToString(), true) + "' height='15px'><span style='padding-right: 12px;'>x" + kpv.Value + "</span>")) + "</b></div>"); // compilation time currentReport.Append(@"<div><img style='padding-right: 20px;' src='Clock' height='15px'>Total elapsed time for the compilation : <b>" + _proCompilation.TotalCompilationTime + @"</b></div>"); if (nbCompilationError > 0) { currentReport.Append("<div><img style='padding-right: 20px;' src='Error30x30' height='15px'>" + nbCompilationError + " files with compilation error(s)</div>"); } if (nbCompilationWarning > 0) { currentReport.Append("<div><img style='padding-right: 20px;' src='Warning30x30' height='15px'>" + nbCompilationWarning + " files with compilation warning(s)</div>"); } if (_proCompilation.NumberOfFilesTreated - nbCompilationError - nbCompilationWarning > 0) { currentReport.Append("<div><img style='padding-right: 20px;' src='Ok30x30' height='15px'>" + (_proCompilation.NumberOfFilesTreated - nbCompilationError - nbCompilationWarning) + " files compiled correctly</div>"); } // deploy currentReport.Append(@"<div style='padding-top: 7px; padding-bottom: 7px;'>Deploying <b>" + totalDeployedFiles + "</b> files : <b>" + Utils.GetNbFilesPerType(_filesToDeployPerStep.SelectMany(pair => pair.Value).Select(deploy => deploy.To).ToList()).Aggregate("", (current, kpv) => current + (@"<img style='padding-right: 5px;' src='" + Utils.GetExtensionImage(kpv.Key.ToString(), true) + "' height='15px'><span style='padding-right: 12px;'>x" + kpv.Value + "</span>")) + "</b></div>"); // deployment time currentReport.Append(@"<div><img style='padding-right: 20px;' src='Clock' height='15px'>Total elapsed time for the deployment : <b>" + TotalDeploymentTime + @"</b></div>"); if (nbDeploymentError > 0) { currentReport.Append("<div><img style='padding-right: 20px;' src='Error30x30' height='15px'>" + nbDeploymentError + " files not deployed</div>"); } if (totalDeployedFiles - nbDeploymentError > 0) { currentReport.Append("<div><img style='padding-right: 20px;' src='Ok30x30' height='15px'>" + (totalDeployedFiles - nbDeploymentError) + " files deployed correctly</div>"); } // compilation if (listLinesCompilation.Count > 0) { currentReport.Append("<h3>Compilation details :</h3>"); var boolAlternate = false; foreach (var listLine in listLinesCompilation.OrderByDescending(tuple => tuple.Item1)) { currentReport.Append(listLine.Item2.Replace("%ALTERNATE%", boolAlternate ? "class='AlternatBackColor' " : "class='NormalBackColor' ")); boolAlternate = !boolAlternate; } } // deployment steps foreach (var listLinesKpv in listLinesByStep.Where(pair => pair.Value != null && pair.Value.Count > 0)) { currentReport.Append("<h3>Deployment step " + listLinesKpv.Key + " details :</h3>"); var boolAlternate2 = false; foreach (var listLine in listLinesKpv.Value.OrderByDescending(tuple => tuple.Item1)) { currentReport.Append(listLine.Item2.Replace("%ALTERNATE%", boolAlternate2 ? "class='AlternatBackColor' " : "class='NormalBackColor' ")); boolAlternate2 = !boolAlternate2; } } currentReport.Append(@"</div>"); return(currentReport.ToString()); }
/// <summary> /// Compiles the list of files given /// </summary> public bool CompileFiles(List <FileToCompile> filesToCompile) { if (filesToCompile == null || filesToCompile.Count == 0) { EndOfCompilation(); return(true); } // init StartingTime = DateTime.Now; NbFilesToCompile = filesToCompile.Count; // now we do a list of those files, sorted from the biggest (in size) to the smallest file filesToCompile.Sort((file1, file2) => file2.Size.CompareTo(file1.Size)); // we want to dispatch all those files in a fair way among the Prowin processes we will create... var numberOfProcesses = MonoProcess ? 1 : Math.Max(NumberOfProcessesPerCore, 1) * Environment.ProcessorCount; // ensure that each process will at least take in 10 files, starting a new process for 1 file to compile isn't efficient! numberOfProcesses = Math.Min(numberOfProcesses, NbFilesToCompile / 10); var fileLists = new List <List <FileToCompile> >(); var currentProcess = 0; foreach (var file in filesToCompile) { // create a new process when needed if (currentProcess >= fileLists.Count) { fileLists.Add(new List <FileToCompile>()); } // assign the file to the current process fileLists[currentProcess].Add(file); // we will assign the next file to the next process... currentProcess++; if (currentProcess == numberOfProcesses) { currentProcess = 0; } } _processesRunning = fileLists.Count; // init the compilation on each process _processes.Clear(); for (int i = 0; i < fileLists.Count; i++) { var exec = new ProExecutionCompile(ProEnv) { Files = fileLists[i], NeedDatabaseConnection = true, NoBatch = true, IsTestMode = IsTestMode, IsAnalysisMode = IsAnalysisMode }; exec.OnExecutionOk += OnExecutionOk; exec.OnExecutionFailed += OnExecutionFailed; exec.OnCompilationOk += OnExecCompilationOk; if (RFilesOnly) { exec.CompileWithDebugList = false; exec.CompileWithXref = false; exec.CompileWithListing = false; } _processes.Add(exec); } // launch the compile process return(_processes.All(exec => exec.Start())); }
/// <summary> /// Creates a list of files to deploy after a compilation, /// for each Origin file will correspond one (or more if it's a .cls) .r file, /// and one .lst if the option has been checked /// </summary> public static List <FileToDeploy> GetFilesToDeployAfterCompilation(ProExecutionCompile execution) { var outputList = new List <FileToDeploy>(); try { var filesCompiled = execution.Files.ToList(); // Handle the case of .cls files, for which several .r code are compiled foreach (var clsFile in execution.Files.Where(file => file.SourcePath.EndsWith(ProExecutionHandleCompilation.ExtCls, StringComparison.CurrentCultureIgnoreCase))) { // if the file we compiled inherits from another class or if another class inherits of our file, // there is more than 1 *.r file generated. Moreover, they are generated in their package folders // for each *.r file in the compilation output directory foreach (var rCodeFilePath in Directory.EnumerateFiles(clsFile.CompilationOutputDir, "*" + ProExecutionHandleCompilation.ExtR, SearchOption.AllDirectories)) { try { // find the path of the source var relativePath = rCodeFilePath.Replace(clsFile.CompilationOutputDir, "").TrimStart('\\'); // if this is actually the .cls file we want to compile, the .r file isn't necessary directly in the compilation dir like we expect, // it can be in folders corresponding to the package of the class if (Path.GetFileNameWithoutExtension(clsFile.SourcePath ?? "").Equals(Path.GetFileNameWithoutExtension(relativePath))) { // correct .r path clsFile.CompOutputR = rCodeFilePath; continue; } // otherwise, try to get the source .cls for this .r var sourcePath = execution.ProEnv.FindFirstFileInPropath(Path.ChangeExtension(relativePath, ProExecutionHandleCompilation.ExtCls)); // if the source isn't already in the files that needed to be compiled, we add it if (!string.IsNullOrEmpty(sourcePath) && !filesCompiled.Exists(compiledFile => compiledFile.SourcePath.Equals(sourcePath))) { filesCompiled.Add(new FileToCompile(sourcePath) { CompilationOutputDir = clsFile.CompilationOutputDir, CompiledSourcePath = sourcePath, CompOutputR = rCodeFilePath }); } } catch (Exception e) { ErrorHandler.LogError(e); } } } // for each .r foreach (var compiledFile in filesCompiled) { if (string.IsNullOrEmpty(compiledFile.CompOutputR)) { continue; } foreach (var deployNeeded in execution.ProEnv.Deployer.GetTargetsNeeded(compiledFile.SourcePath, 0, DeployTransferRuleTarget.File)) { string targetRPath; if (execution.ProEnv.CompileLocally) { targetRPath = Path.Combine(deployNeeded.TargetBasePath, Path.GetFileName(compiledFile.CompOutputR)); } else { targetRPath = Path.Combine(deployNeeded.TargetBasePath, compiledFile.CompOutputR.Replace(compiledFile.CompilationOutputDir, "").TrimStart('\\')); } // add .r and .lst (if needed) to the list of files to deploy outputList.Add(deployNeeded.Set(compiledFile.CompOutputR, targetRPath)); // listing if (execution.CompileWithListing && !string.IsNullOrEmpty(compiledFile.CompOutputLis)) { outputList.Add(deployNeeded.Copy(compiledFile.CompOutputLis, Path.ChangeExtension(targetRPath, ProExecutionHandleCompilation.ExtLis))); } // xref if (execution.CompileWithXref && !string.IsNullOrEmpty(compiledFile.CompOutputXrf)) { outputList.Add(deployNeeded.Copy(compiledFile.CompOutputXrf, Path.ChangeExtension(targetRPath, execution.UseXmlXref ? ProExecutionHandleCompilation.ExtXrfXml : ProExecutionHandleCompilation.ExtXrf))); } // debug-list if (execution.CompileWithDebugList && !string.IsNullOrEmpty(compiledFile.CompOutputDbg)) { outputList.Add(deployNeeded.Copy(compiledFile.CompOutputDbg, Path.ChangeExtension(targetRPath, ProExecutionHandleCompilation.ExtDbg))); } } } } catch (Exception e) { ErrorHandler.ShowErrors(e, "Failed to find .r codes to deploy"); } return(outputList); }
/// <summary> /// Generate an html report for the current deployment /// </summary> public string FormatDeploymentReport() { StringBuilder currentReport = new StringBuilder(); currentReport.Append("<div class='NormalBackColor'>"); currentReport.Append(@" <table class='ToolTipName' style='margin-bottom: 0px; width: 100%'> <tr> <td rowspan='2' style='width: 95px; padding-left: 10px'><img src='Report_64x64' width='64' height='64' /></td> <td class='NotificationTitle'>Deployment report</td> </tr> <tr> <td class='NotificationSubTitle'>" + (HasBeenCancelled ? "<img style='padding-right: 2px;' src='Warning30x30' height='25px'>Canceled by the user" : (!CompilationHasFailed ? "<img style='padding-right: 2px;' src='Ok30x30' height='25px'>" + (IsTestMode ? "Test done!" : "Done!") : " <img style='padding-right: 2px;' src='Error30x30' height='25px'>An error has occurred...")) + @"</td> </tr> </table>"); currentReport.Append(@"<h2 style='margin-top: 8px; margin-bottom: 8px;'>Parameters :</h2>"); currentReport.Append(@" <div style='margin-left: 8px; margin-right: 8px;'> <table style='width: 100%' class='NormalBackColor'> <tr><td style='width: 40%; padding-right: 20px'>Compilation starting time :</td><td><b>" + _proCompilation.StartingTime + @"</b></td></tr> <tr><td style='padding-right: 20px'>Number of cores detected on this computer :</td><td><b>" + Environment.ProcessorCount + @" cores</b></td></tr> <tr><td style='padding-right: 20px'>Number of Prowin processes used for the compilation :</td><td><b>" + _proCompilation.TotalNumberOfProcesses + @" processes</b></td></tr> <tr><td style='padding-right: 20px'>Forced to mono process? :</td><td><b>" + _proCompilation.MonoProcess + (_proEnv.IsDatabaseSingleUser ? " (connected to database in single user mode!)" : "") + @"</b></td></tr> <tr><td style='width: 40%; padding-right: 20px'>Total number of files being compile :</td><td><b>" + _proCompilation.NbFilesToCompile + @" files</b></td></tr> <tr><td style='width: 40%; padding-right: 20px'>Source directory :</td><td><b>" + _currentProfile.SourceDirectory.ToHtmlLink() + @"</b></td></tr> <tr><td style='width: 40%; padding-right: 20px'>Target deployment directory :</td><td><b>" + _proEnv.BaseCompilationPath.ToHtmlLink() + @"</b></td></tr> </table> </div>"); currentReport.Append(@"<h2 style='margin-top: 8px; margin-bottom: 8px;'>Results :</h2>"); if (HasBeenCancelled) { // the process has been canceled currentReport.Append(@"<div><img style='padding-right: 20px; padding-left: 5px;' src='Warning30x30' height='15px'>The deployment has been canceled by the user</div>"); } else if (CompilationHasFailed) { // provide info on the possible error! currentReport.Append(@"<div><img style='padding-right: 20px; padding-left: 5px;' src='Error30x30' height='15px'>At least one process has ended in error, the compilation has been canceled</div>"); if (_proCompilation.CompilationFailedOnMaxUser) { currentReport.Append(@"<div><img style='padding-right: 20px; padding-left: 5px;' src='Help' height='15px'>One or more processes started for this compilation tried to connect to the database and failed because the maximum number of connection has been reached (error 748). To correct this problem, you can either :<br><li>reduce the number of processes to use for each core of your computer</li><li>or increase the maximum of connections for your database (-n parameter in the PROSERVE command)</li></div>"); } } var listLinesCompilation = new List <Tuple <int, string> >(); StringBuilder line = new StringBuilder(); var totalDeployedFiles = 0; var nbDeploymentError = 0; var nbCompilationError = 0; var nbCompilationWarning = 0; // compilation errors foreach (var fileInError in _proCompilation.ListFilesToCompile.Where(file => file.Errors != null)) { bool hasError = fileInError.Errors.Exists(error => error.Level >= ErrorLevel.Error); bool hasWarning = fileInError.Errors.Exists(error => error.Level < ErrorLevel.Error); if (hasError || hasWarning) { // only add compilation errors line.Clear(); line.Append("<div %ALTERNATE%style=\"background-repeat: no-repeat; background-image: url('" + (hasError ? "Error30x30" : "Warning30x30") + "'); padding-left: 40px; padding-top: 6px; padding-bottom: 6px;\">"); line.Append(ProExecutionCompile.FormatCompilationResultForSingleFile(fileInError.SourcePath, fileInError, null)); line.Append("</div>"); listLinesCompilation.Add(new Tuple <int, string>(hasError ? 3 : 2, line.ToString())); } if (hasError) { nbCompilationError++; } else if (hasWarning) { nbCompilationWarning++; } } // for each deploy step var listLinesByStep = new Dictionary <int, List <Tuple <int, string> > > { { 0, new List <Tuple <int, string> >() } }; foreach (var kpv in _filesToDeployPerStep) { // group either by directory name or by pack name var groupDirectory = kpv.Value.GroupBy(deploy => deploy.GroupKey).Select(deploys => deploys.ToList()).ToList(); foreach (var group in groupDirectory.OrderByDescending(list => list.First().DeployType).ThenBy(list => list.First().GroupKey)) { var deployFailed = group.Exists(deploy => !deploy.IsOk); var first = group.First(); line.Clear(); line.Append("<div %ALTERNATE%style=\"background-repeat: no-repeat; background-image: url('" + (deployFailed ? "Error30x30" : "Ok30x30") + "'); padding-left: 40px; padding-top: 6px; padding-bottom: 6px;\">"); line.Append(first.ToStringGroupHeader()); foreach (var fileToDeploy in group.OrderBy(deploy => deploy.To)) { line.Append(fileToDeploy.ToStringDescription(kpv.Key <= 1 ? _currentProfile.SourceDirectory : _proEnv.BaseCompilationPath)); } line.Append("</div>"); if (!listLinesByStep.ContainsKey(kpv.Key)) { listLinesByStep.Add(kpv.Key, new List <Tuple <int, string> >()); } listLinesByStep[kpv.Key].Add(new Tuple <int, string>(deployFailed ? 3 : 1, line.ToString())); if (deployFailed) { nbDeploymentError += group.Count(deploy => !deploy.IsOk); } else { totalDeployedFiles += group.Count; } } } // compilation currentReport.Append(@"<div style='padding-top: 7px; padding-bottom: 7px;'>Compiling <b>" + _proCompilation.NbFilesToCompile + "</b> files : <b>" + Utils.GetNbFilesPerType(_proCompilation.GetListOfFileToCompile.Select(compile => compile.SourcePath).ToList()).Aggregate("", (current, kpv) => current + (@"<img style='padding-right: 5px;' src='" + Utils.GetExtensionImage(kpv.Key.ToString(), true) + "' height='15px'><span style='padding-right: 12px;'>x" + kpv.Value + "</span>")) + "</b></div>"); // compilation time currentReport.Append(@"<div><img style='padding-right: 20px; padding-left: 5px;' src='Time' height='15px'>Total elapsed time for the compilation : <b>" + _proCompilation.TotalCompilationTime + @"</b></div>"); if (nbCompilationError > 0) { currentReport.Append("<div><img style='padding-right: 20px; padding-left: 5px;' src='Error30x30' height='15px'>" + nbCompilationError + " files with compilation error(s)</div>"); } if (nbCompilationWarning > 0) { currentReport.Append("<div><img style='padding-right: 20px; padding-left: 5px;' src='Warning30x30' height='15px'>" + nbCompilationWarning + " files with compilation warning(s)</div>"); } if (_proCompilation.NumberOfFilesTreated - nbCompilationError - nbCompilationWarning > 0) { currentReport.Append("<div><img style='padding-right: 20px; padding-left: 5px;' src='Ok30x30' height='15px'>" + (_proCompilation.NumberOfFilesTreated - nbCompilationError - nbCompilationWarning) + " files compiled correctly</div>"); } // deploy currentReport.Append(@"<div style='padding-top: 7px; padding-bottom: 7px;'>Deploying <b>" + totalDeployedFiles + "</b> files : <b>" + Utils.GetNbFilesPerType(_filesToDeployPerStep.SelectMany(pair => pair.Value).Select(deploy => deploy.To).ToList()).Aggregate("", (current, kpv) => current + (@"<img style='padding-right: 5px;' src='" + Utils.GetExtensionImage(kpv.Key.ToString(), true) + "' height='15px'><span style='padding-right: 12px;'>x" + kpv.Value + "</span>")) + "</b></div>"); // deployment time currentReport.Append(@"<div><img style='padding-right: 20px; padding-left: 5px;' src='Time' height='15px'>Total elapsed time for the deployment : <b>" + TotalDeploymentTime + @"</b></div>"); if (nbDeploymentError > 0) { currentReport.Append("<div><img style='padding-right: 20px; padding-left: 5px;' src='Error30x30' height='15px'>" + nbDeploymentError + " files not deployed</div>"); } if (totalDeployedFiles - nbDeploymentError > 0) { currentReport.Append("<div><img style='padding-right: 20px; padding-left: 5px;' src='Ok30x30' height='15px'>" + (totalDeployedFiles - nbDeploymentError) + " files deployed correctly</div>"); } // compilation if (listLinesCompilation.Count > 0) { currentReport.Append("<h3 style='margin-top: 7px; margin-bottom: 7px;'>Compilation details :</h3>"); var boolAlternate = false; foreach (var listLine in listLinesCompilation.OrderByDescending(tuple => tuple.Item1)) { currentReport.Append(listLine.Item2.Replace("%ALTERNATE%", boolAlternate ? "class='AlternatBackColor' " : "class='NormalBackColor' ")); boolAlternate = !boolAlternate; } } // deployment steps foreach (var listLinesKpv in listLinesByStep) { currentReport.Append("<h3 style='margin-top: 7px; margin-bottom: 7px;'>Deployment step " + listLinesKpv.Key + " details :</h3>"); var boolAlternate2 = false; foreach (var listLine in listLinesKpv.Value.OrderByDescending(tuple => tuple.Item1)) { currentReport.Append(listLine.Item2.Replace("%ALTERNATE%", boolAlternate2 ? "class='AlternatBackColor' " : "class='NormalBackColor' ")); boolAlternate2 = !boolAlternate2; } } currentReport.Append("</div>"); return(currentReport.ToString()); }