/// <summary> /// Note that WriteOnce.Writer is not used for AnalyzeCommand which has specific Writer classes for formattig to html, json, text unlike /// other command classes to writting to a file here is handled by the AnalyzeCommand FlushAll() method /// </summary> void ConfigFileOutput() { WriteOnce.SafeLog("AnalyzeCommand::ConfigOutput", LogLevel.Trace); WriteOnce.FlushAll();//in case called more than once //error check for no output if (string.IsNullOrEmpty(_arg_outputFile) && _arg_consoleVerbosityLevel.ToLower() == "none") { throw new Exception(ErrMsg.GetString(ErrMsg.ID.CMD_NO_OUTPUT)); } if (_arg_fileFormat == "html") { if (!string.IsNullOrEmpty(_arg_outputFile)) //dependent local files won't be there; TODO look into dir copy to target! { _arg_outputFile = String.Empty; WriteOnce.Info("output file argument ignored for html format"); } if (!_arg_outputUniqueTagsOnly) //fix #183 { throw new Exception(ErrMsg.GetString(ErrMsg.ID.ANALYZE_NODUPLICATES_HTML_FORMAT)); } if (_arg_simpleTagsOnly) //won't work for html that expects full data { throw new Exception(ErrMsg.GetString(ErrMsg.ID.ANALYZE_SIMPLETAGS_HTML_FORMAT)); } } //Set outstream _outputWriter = WriterFactory.GetWriter(_arg_fileFormat ?? "text", (string.IsNullOrEmpty(_arg_outputFile)) ? null : "text", _arg_outputTextFormat); if (!string.IsNullOrEmpty(_arg_outputFile)) { _outputWriter.TextWriter = File.CreateText(_arg_outputFile);//not needed if html output since application controlled } else { _outputWriter.TextWriter = Console.Out; } }
void ConfigOutput() { WriteOnce.SafeLog("AnalyzeCommand::ConfigOutput", LogLevel.Trace); //Set output type, format and outstream _outputWriter = WriterFactory.GetWriter(_arg_fileFormat ?? "text", (string.IsNullOrEmpty(_arg_outputFile)) ? null : "text", _arg_outputTextFormat); if (_arg_fileFormat == "html") { if (!string.IsNullOrEmpty(_arg_outputFile)) { WriteOnce.Info("output file ignored for html format"); } _outputWriter.TextWriter = Console.Out; } else if (!string.IsNullOrEmpty(_arg_outputFile)) { _outputWriter.TextWriter = File.CreateText(_arg_outputFile);//not needed if html output since application controlled } else { _outputWriter.TextWriter = Console.Out; } }
public void FlushAll() { if (_outputWriter != null) { _outputWriter.WriteApp(_appProfile); if (_outputWriter.TextWriter != null) { if (_arg_fileFormat != "html") { _outputWriter.FlushAndClose();//not required for htmt formal i.e. already closed _outputWriter = null; WriteOnce.Writer = null; //Special case to avoid writing tmp file path to output file for TagTest,TagDiff or when called as a DLL since unnecessary if (_arg_consoleVerbosityLevel.ToLower() != "none") { if (!String.IsNullOrEmpty(_arg_outputFile) && Utils.CLIExecutionContext) { WriteOnce.Info(ErrMsg.FormatString(ErrMsg.ID.ANALYZE_OUTPUT_FILE, _arg_outputFile), true, WriteOnce.ConsoleVerbosity.Medium, false); } else { WriteOnce.NewLine(); } } } else { if (!_arg_suppressBrowserOpen && Utils.CLIExecutionContext) { WriteOnce.Any(ErrMsg.FormatString(ErrMsg.ID.ANALYZE_OUTPUT_FILE, "output.html"), true, ConsoleColor.Gray, WriteOnce.ConsoleVerbosity.Low); } } } } }
/// <summary> /// Main entry from CLI /// </summary> /// <returns></returns> public override int Run() { bool issues = false; WriteOnce.Operation(ErrMsg.FormatString(ErrMsg.ID.CMD_RUNNING, "Verify Rules")); //load [each] rules file separately to report out where a failure is happening RuleSet rules = new RuleSet(WriteOnce.Log); IEnumerable <string> fileListing = new List <string>(); foreach (string rulePath in _rulePaths) { if (Directory.Exists(rulePath)) { fileListing = Directory.EnumerateFiles(rulePath, "*.json", SearchOption.AllDirectories); } else if (File.Exists(rulePath) && Path.GetExtension(rulePath) == ".json") { fileListing = new List <string>() { new string(rulePath) } } ; else { throw new OpException(ErrMsg.FormatString(ErrMsg.ID.CMD_INVALID_RULE_PATH, rulePath)); } //test loading each file foreach (string filename in fileListing) { try { rules.AddFile(filename); WriteOnce.Info(string.Format("Rule file added {0}", filename), true, WriteOnce.ConsoleVerbosity.High); } catch (Exception e) { WriteOnce.Error(string.Format("Rule file add failed {0}", filename)); WriteOnce.SafeLog(e.Message + "\n" + e.StackTrace, NLog.LogLevel.Error); issues = true; } } } //option to write validating data if (_arg_consoleVerbosityLevel.ToLower() == "high") { WritePartialRuleDetails(rules); } //final status report if (issues) { WriteOnce.Any(ErrMsg.GetString(ErrMsg.ID.VERIFY_RULES_RESULTS_FAIL), true, ConsoleColor.Red, WriteOnce.ConsoleVerbosity.Low); } else { WriteOnce.Any(ErrMsg.GetString(ErrMsg.ID.VERIFY_RULES_RESULTS_SUCCESS), true, ConsoleColor.Green, WriteOnce.ConsoleVerbosity.Low); } WriteOnce.Operation(ErrMsg.FormatString(ErrMsg.ID.CMD_COMPLETED, "Verify Rules")); WriteOnce.FlushAll(); if (!String.IsNullOrEmpty(_arg_outputFile)) { WriteOnce.Any(ErrMsg.FormatString(ErrMsg.ID.ANALYZE_OUTPUT_FILE, _arg_outputFile), true, ConsoleColor.Gray, WriteOnce.ConsoleVerbosity.Low); } return(issues ? (int)ExitCode.NotVerified : (int)ExitCode.Verified); }
/// <summary> /// Main entry from CLI /// </summary> /// <returns></returns> public override int Run() { WriteOnce.SafeLog("TagDiffCommand::Run", LogLevel.Trace); WriteOnce.Operation(ErrMsg.FormatString(ErrMsg.ID.CMD_RUNNING, "tagdiff")); ExitCode exitCode = ExitCode.CriticalError; //save to quiet analyze cmd and restore WriteOnce.ConsoleVerbosity saveVerbosity = WriteOnce.Verbosity; AnalyzeCommand.ExitCode analyzeCmdResult1 = AnalyzeCommand.ExitCode.CriticalError; AnalyzeCommand.ExitCode analyzeCmdResult2 = AnalyzeCommand.ExitCode.CriticalError; try { #region setup analyze calls string tmp1 = Path.GetTempFileName(); string tmp2 = Path.GetTempFileName(); AnalyzeCommand cmd1 = new AnalyzeCommand(new AnalyzeCommandOptions { SourcePath = _arg_src1, OutputFilePath = tmp1, OutputFileFormat = "json", CustomRulesPath = _arg_customRulesPath, IgnoreDefaultRules = _arg_ignoreDefault, FilePathExclusions = _arg_fileExclusionList, SimpleTagsOnly = true, ConsoleVerbosityLevel = "none", Log = _arg_logger }); AnalyzeCommand cmd2 = new AnalyzeCommand(new AnalyzeCommandOptions { SourcePath = _arg_src2, OutputFilePath = tmp2, OutputFileFormat = "json", CustomRulesPath = _arg_customRulesPath, IgnoreDefaultRules = _arg_ignoreDefault, FilePathExclusions = _arg_fileExclusionList, SimpleTagsOnly = true, ConsoleVerbosityLevel = "none", Log = _arg_logger }); analyzeCmdResult1 = (AnalyzeCommand.ExitCode)cmd1.Run(); analyzeCmdResult2 = (AnalyzeCommand.ExitCode)cmd2.Run(); ConfigureFileOutput(); //restore WriteOnce.Verbosity = saveVerbosity; #endregion bool equalTagsCompare1 = true; bool equalTagsCompare2 = true; //process results for each analyze call before comparing results if (analyzeCmdResult1 == AnalyzeCommand.ExitCode.CriticalError) { throw new Exception(ErrMsg.FormatString(ErrMsg.ID.CMD_CRITICAL_FILE_ERR, _arg_src1)); } else if (analyzeCmdResult2 == AnalyzeCommand.ExitCode.CriticalError) { throw new Exception(ErrMsg.FormatString(ErrMsg.ID.CMD_CRITICAL_FILE_ERR, _arg_src2)); } else if (analyzeCmdResult1 == AnalyzeCommand.ExitCode.NoMatches || analyzeCmdResult2 == AnalyzeCommand.ExitCode.NoMatches) { throw new Exception(ErrMsg.GetString(ErrMsg.ID.TAGDIFF_NO_TAGS_FOUND)); } else //compare tag results; assumed (result1&2 == AnalyzeCommand.ExitCode.Success) { //setup output here rather than top to avoid analyze command output in this command output ConfigureFileOutput(); ConfigureConsoleOutput();//recheck string file1TagsJson = File.ReadAllText(tmp1); string file2TagsJson = File.ReadAllText(tmp2); var file1Tags = JsonConvert.DeserializeObject <TagsFile>(file1TagsJson); var file2Tags = JsonConvert.DeserializeObject <TagsFile>(file2TagsJson); //can't simply compare counts as content may differ; must compare both in directions in two passes a->b; b->a WriteOnce.General(ErrMsg.FormatString(ErrMsg.ID.TAGDIFF_RESULTS_GAP, Path.GetFileName(_arg_src1), Path.GetFileName(_arg_src2)), true, WriteOnce.ConsoleVerbosity.High); equalTagsCompare1 = CompareTags(file1Tags.Tags, file2Tags.Tags); //reverse order for second pass WriteOnce.General(ErrMsg.FormatString(ErrMsg.ID.TAGDIFF_RESULTS_GAP, Path.GetFileName(_arg_src2), Path.GetFileName(_arg_src1)), true, WriteOnce.ConsoleVerbosity.High); equalTagsCompare2 = CompareTags(file2Tags.Tags, file1Tags.Tags); //final results bool resultsDiffer = !(equalTagsCompare1 && equalTagsCompare2); if (_arg_tagTestType == TagTestType.Inequality && !resultsDiffer) { exitCode = ExitCode.TestFailed; } else if (_arg_tagTestType == TagTestType.Equality && resultsDiffer) { exitCode = ExitCode.TestFailed; } else { exitCode = ExitCode.TestPassed; } WriteOnce.General(ErrMsg.FormatString(ErrMsg.ID.TAGDIFF_RESULTS_DIFFER), false); WriteOnce.Result(resultsDiffer.ToString()); WriteOnce.Operation(ErrMsg.FormatString(ErrMsg.ID.CMD_COMPLETED, "tagdiff")); if (!String.IsNullOrEmpty(_arg_outputFile) && Utils.CLIExecutionContext) { WriteOnce.Info(ErrMsg.FormatString(ErrMsg.ID.ANALYZE_OUTPUT_FILE, _arg_outputFile), true, WriteOnce.ConsoleVerbosity.Low, false); } WriteOnce.FlushAll(); } //cleanup try { File.Delete(tmp1); File.Delete(tmp2); } catch { //no action needed; } } catch (Exception e) { WriteOnce.Verbosity = saveVerbosity; if (analyzeCmdResult1 == AnalyzeCommand.ExitCode.Success && analyzeCmdResult2 == AnalyzeCommand.ExitCode.Success) //error not previously logged { WriteOnce.Error(e.Message); } else { WriteOnce.Error(e.Message, true, WriteOnce.ConsoleVerbosity.Low, false);//console but don't log again } //exit normaly for CLI callers and throw for DLL callers if (Utils.CLIExecutionContext) { return((int)ExitCode.CriticalError); } else { throw; } } finally { if (_arg_close_log_on_exit) { Utils.Logger = null; WriteOnce.Log = null; } } return((int)exitCode); }
/// <summary> /// Main entry from CLI /// </summary> /// <returns></returns> public override int Run() { WriteOnce.SafeLog("TagTestCommand::Run", LogLevel.Trace); WriteOnce.Operation(ErrMsg.FormatString(ErrMsg.ID.CMD_RUNNING, "tagtest")); //init based on true or false present argument value ExitCode exitCode = ExitCode.CriticalError; WriteOnce.ConsoleVerbosity saveVerbosity = WriteOnce.Verbosity; AnalyzeCommand.ExitCode analyzeCmdResult = AnalyzeCommand.ExitCode.CriticalError; try { //one file vs ruleset string tmp1 = Path.GetTempFileName(); //setup analyze call with silent option AnalyzeCommand cmd1 = new AnalyzeCommand(new AnalyzeCommandOptions { SourcePath = _arg_srcPath, OutputFilePath = tmp1, OutputFileFormat = "json", IgnoreDefaultRules = true, CustomRulesPath = _arg_customRulesPath, FilePathExclusions = _arg_fileExclusionList, SimpleTagsOnly = true, ConsoleVerbosityLevel = "None", Log = _arg_logger }); //get and perform initial analyze on results analyzeCmdResult = (AnalyzeCommand.ExitCode)cmd1.Run(); //must be done here to avoid losing our handle from analyze command overwriting WriteOnce.Writer ConfigureFileOutput(); //restore WriteOnce.Verbosity = saveVerbosity; if (analyzeCmdResult == AnalyzeCommand.ExitCode.CriticalError) { throw new Exception(ErrMsg.GetString(ErrMsg.ID.CMD_CRITICAL_FILE_ERR)); } else if (analyzeCmdResult == AnalyzeCommand.ExitCode.NoMatches) { WriteOnce.General(ErrMsg.FormatString(ErrMsg.ID.TAGTEST_RESULTS_TEST_TYPE, _arg_tagTestType.ToString()), false, WriteOnce.ConsoleVerbosity.Low); if (_arg_tagTestType == TagTestType.RulesPresent) { WriteOnce.Any(ErrMsg.GetString(ErrMsg.ID.TAGTEST_RESULTS_FAIL), true, ConsoleColor.Red, WriteOnce.ConsoleVerbosity.Low); } else { WriteOnce.Any(ErrMsg.GetString(ErrMsg.ID.TAGTEST_RESULTS_SUCCESS), true, ConsoleColor.Green, WriteOnce.ConsoleVerbosity.Low); } WriteOnce.Operation(ErrMsg.FormatString(ErrMsg.ID.CMD_COMPLETED, "tagtest")); exitCode = _arg_tagTestType == TagTestType.RulesPresent ? ExitCode.TestFailed : ExitCode.TestPassed; } else //assumed (result == AnalyzeCommand.ExitCode.MatchesFound) { string file1TagsJson = File.ReadAllText(tmp1); var file1Tags = JsonConvert.DeserializeObject <TagsFile>(file1TagsJson); File.Delete(tmp1); exitCode = ExitCode.TestPassed; foreach (Rule r in _rulesSet) { //supports both directions by generalizing string[] testList1 = _arg_tagTestType == TagTestType.RulesNotPresent ? r.Tags : file1Tags.Tags; string[] testList2 = _arg_tagTestType == TagTestType.RulesNotPresent ? file1Tags.Tags : r.Tags; foreach (string t in testList2) { if (TagTest(testList1, t)) { WriteOnce.Result(ErrMsg.FormatString(ErrMsg.ID.TAGTEST_RESULTS_TAGS_FOUND, t), true, WriteOnce.ConsoleVerbosity.High); } else { exitCode = ExitCode.TestFailed; WriteOnce.Result(ErrMsg.FormatString(ErrMsg.ID.TAGTEST_RESULTS_TAGS_MISSING, t), true, WriteOnce.ConsoleVerbosity.High); } if (exitCode != ExitCode.TestPassed) { break; } } if (exitCode != ExitCode.TestPassed) { break; } } //results WriteOnce.General(ErrMsg.FormatString(ErrMsg.ID.TAGTEST_RESULTS_TEST_TYPE, _arg_tagTestType.ToString()), false, WriteOnce.ConsoleVerbosity.Low); if (exitCode == ExitCode.TestFailed) { WriteOnce.Any(ErrMsg.GetString(ErrMsg.ID.TAGTEST_RESULTS_FAIL), true, ConsoleColor.Red, WriteOnce.ConsoleVerbosity.Low); } else { WriteOnce.Any(ErrMsg.GetString(ErrMsg.ID.TAGTEST_RESULTS_SUCCESS), true, ConsoleColor.Green, WriteOnce.ConsoleVerbosity.Low); } WriteOnce.Operation(ErrMsg.FormatString(ErrMsg.ID.CMD_COMPLETED, "Tagtest")); if (!String.IsNullOrEmpty(_arg_outputFile) && Utils.CLIExecutionContext) { WriteOnce.Info(ErrMsg.FormatString(ErrMsg.ID.ANALYZE_OUTPUT_FILE, _arg_outputFile), true, WriteOnce.ConsoleVerbosity.Low, false); } WriteOnce.FlushAll(); } } catch (Exception e) { WriteOnce.Verbosity = saveVerbosity; if (analyzeCmdResult == AnalyzeCommand.ExitCode.Success) //then error was not previously logged { WriteOnce.Error(e.Message); } else { WriteOnce.Error(e.Message, true, WriteOnce.ConsoleVerbosity.Low, false); } //exit normaly for CLI callers and throw for DLL callers if (Utils.CLIExecutionContext) { return((int)ExitCode.CriticalError); } else { throw; } } finally { if (_arg_close_log_on_exit) { Utils.Logger = null; WriteOnce.Log = null; } } return((int)exitCode); }
readonly int MAX_HTML_REPORT_FILE_SIZE = 1024 * 1000 * 3; //warn about potential slow rendering /// <summary> /// Registers datatypes with html framework liquid and sets up data for use within it and used /// with html partial.liquid files that are embedded as resources /// Liquid processing within partial html files only requires data ref to object while JS requires json objects /// </summary> /// <param name="app"></param> public override void WriteApp(AppProfile app) { var htmlTemplateText = File.ReadAllText(Path.Combine(Utils.GetPath(Utils.AppPath.basePath), "html/index.html")); Template.FileSystem = new EmbeddedFileSystem(Assembly.GetEntryAssembly(), "Microsoft.ApplicationInspector.CLI.html.partials"); RegisterSafeType(typeof(AppProfile)); RegisterSafeType(typeof(AppMetaData)); var htmlTemplate = Template.Parse(htmlTemplateText); var data = new Dictionary <string, object>(); data["AppProfile"] = app; var hashData = new Hash(); hashData["json"] = Newtonsoft.Json.JsonConvert.SerializeObject(data);//json serialization required for [js] access to objects hashData["application_version"] = Utils.GetVersionString(); //add dynamic sets of groups of taginfo read from preferences for Profile page List <TagGroup> tagGroupList = app.GetCategoryTagGroups("profile"); hashData["groups"] = tagGroupList; //add summary values for sorted tags lists of taginfo foreach (string outerKey in app.KeyedSortedTagInfoLists.Keys) { hashData.Add(outerKey, app.KeyedSortedTagInfoLists[outerKey]); } //add summary metadata lists hashData["cputargets"] = app.MetaData.CPUTargets; hashData["apptypes"] = app.MetaData.AppTypes; hashData["packagetypes"] = app.MetaData.PackageTypes; hashData["ostargets"] = app.MetaData.OSTargets; hashData["outputs"] = app.MetaData.Outputs; hashData["filetypes"] = app.MetaData.FileExtensions; hashData["tagcounters"] = app.MetaData.TagCountersUI; var htmlResult = htmlTemplate.Render(hashData); string htmlOutputFilePath = Path.Combine(Utils.GetPath(Utils.AppPath.basePath), "output.html"); File.WriteAllText(htmlOutputFilePath, htmlResult); //writes out json report for convenience and linking to from report page(s) String jsonReportPath = Path.Combine(Utils.GetPath(Utils.AppPath.basePath), "output.json"); Writer jsonWriter = WriterFactory.GetWriter("json", jsonReportPath); jsonWriter.TextWriter = File.CreateText(jsonReportPath); jsonWriter.WriteApp(app); jsonWriter.FlushAndClose(); //html report size warning string outputHTMLPath = Path.Combine(Utils.GetPath(Utils.AppPath.basePath), "output.html"); if (File.Exists(outputHTMLPath) && new FileInfo(outputHTMLPath).Length > MAX_HTML_REPORT_FILE_SIZE) { WriteOnce.Info(ErrMsg.GetString(ErrMsg.ID.ANALYZE_REPORTSIZE_WARN)); } if (!app.SuppressBrowserOpen) { Utils.OpenBrowser(htmlOutputFilePath); } }
//Main entry from CLI public override int Run() { WriteOnce.SafeLog("ExportTagsCommand::Run", LogLevel.Trace); WriteOnce.Operation(ErrMsg.FormatString(ErrMsg.ID.CMD_RUNNING, "Exporttags")); SortedDictionary <string, string> uniqueTags = new SortedDictionary <string, string>(); try { foreach (Rule r in _rules) { //builds a list of unique tags foreach (string t in r.Tags) { if (uniqueTags.ContainsKey(t)) { continue; } else { uniqueTags.Add(t, t); } } } //separate loop so results are sorted (Sorted type) foreach (string s in uniqueTags.Values) { WriteOnce.Result(s, true); } WriteOnce.Operation(ErrMsg.FormatString(ErrMsg.ID.CMD_COMPLETED, "Exporttags")); if (!String.IsNullOrEmpty(_arg_outputFile) && Utils.CLIExecutionContext) { WriteOnce.Info(ErrMsg.FormatString(ErrMsg.ID.ANALYZE_OUTPUT_FILE, _arg_outputFile), true, WriteOnce.ConsoleVerbosity.Low, false); } WriteOnce.FlushAll(); } catch (Exception e) { WriteOnce.Error(e.Message); //exit normaly for CLI callers and throw for DLL callers if (Utils.CLIExecutionContext) { return((int)ExitCode.CriticalError); } else { throw; } } finally { if (_arg_close_log_on_exit) { Utils.Logger = null; WriteOnce.Log = null; } } return((int)ExitCode.Success); }