示例#1
0
        private bool TestFile(string fileName)
        {
            bool result = true;

            // See if file name is a valid rule ID and preload default values
            string defaultId = Path.GetFileNameWithoutExtension(fileName);

            string[]? languages = null;
            Rule fileRule = _rules.FirstOrDefault(x => x.Id == defaultId);

            if (fileRule != null)
            {
                languages = fileRule.AppliesTo;
            }

            // Load file header and content
            string fileHeader  = string.Empty;
            string fileContent = File.ReadAllText(fileName);
            Regex  reg         = new Regex("^={3,}\\s+", RegexOptions.Multiline);
            Match  match       = reg.Match(fileContent);

            if (match.Success)
            {
                fileHeader  = fileContent.Substring(0, match.Index);
                fileContent = fileContent.Substring(match.Index + match.Length);
            }

            languages = GetLanguges(fileHeader, languages);
            Dictionary <int, List <string> > expecations = GetExpectations(fileHeader, defaultId);

            RuleProcessor processor = new RuleProcessor(_rules);

            processor.EnableSuppressions = false;
            processor.SeverityLevel      = Severity.Critical | Severity.Important | Severity.Moderate | Severity.BestPractice | Severity.ManualReview;

            Issue[] issues = processor.Analyze(fileContent, languages);

            List <KeyValuePair <Location, string> > unexpected = new List <KeyValuePair <Location, string> >();

            foreach (Issue issue in issues)
            {
                AddToCoverageList(issue.Rule.Id);

                // if issue on this line was expected remove it from expecations
                int line = issue.StartLocation.Line;
                if (expecations.ContainsKey(line) && expecations[line].Contains(issue.Rule.Id))
                {
                    expecations[line].Remove(issue.Rule.Id);
                }
                // otherwise add it to unexpected
                else
                {
                    unexpected.Add(new KeyValuePair <Location, string>(issue.StartLocation, issue.Rule.Id));
                }
            }

            if (unexpected.Count > 0 || expecations.Any(x => x.Value.Count > 0))
            {
                result = false;
                Console.Error.WriteLine("file:{0}", fileName);
                foreach (KeyValuePair <Location, string> pair in unexpected)
                {
                    Console.Error.WriteLine("\tline:{0},{1} unexpected {2}", pair.Key.Line, pair.Key.Column, pair.Value);
                }

                foreach (int line in expecations.Keys)
                {
                    if (expecations[line].Count > 0)
                    {
                        foreach (string id in expecations[line])
                        {
                            string exists = string.Empty;
                            if (_rules.FirstOrDefault(x => x.Id == id) == null)
                            {
                                exists = " (no such rule) ";
                            }

                            Console.Error.WriteLine("\tline:{0} expecting {1}{2}", line, id, exists);
                        }
                    }
                }

                Console.Error.WriteLine();
            }

            return(result);
        }
        /// <summary>
        /// Add default and/or custom rules paths
        /// Iterate paths and add to ruleset
        /// </summary>
        void ConfigRules()
        {
            WriteOnce.SafeLog("AnalyzeCommand::ConfigRules", LogLevel.Trace);

            RuleSet       rulesSet  = new RuleSet(Program.Logger);
            List <string> rulePaths = new List <string>();

            if (!_arg_ignoreDefaultRules)
            {
                rulePaths.Add(Utils.GetPath(Utils.AppPath.defaultRules));
            }

            if (!string.IsNullOrEmpty(_arg_customRulesPath))
            {
                rulePaths.Add(_arg_customRulesPath);
            }

            foreach (string rulePath in rulePaths)
            {
                if (Directory.Exists(rulePath))
                {
                    rulesSet.AddDirectory(rulePath);
                }
                else if (File.Exists(rulePath))
                {
                    rulesSet.AddFile(rulePath);
                }
                else
                {
                    throw new OpException(ErrMsg.FormatString(ErrMsg.ID.CMD_INVALID_RULE_PATH, rulePath));
                }
            }

            //error check based on ruleset not path enumeration
            if (rulesSet.Count() == 0)
            {
                throw new OpException(ErrMsg.GetString(ErrMsg.ID.CMD_NORULES_SPECIFIED));
            }

            //instantiate a RuleProcessor with the added rules and exception for dependency
            _rulesProcessor = new RuleProcessor(rulesSet, _arg_confidence, _arg_outputUniqueTagsOnly, _arg_simpleTagsOnly, Program.Logger);

            if (_arg_outputUniqueTagsOnly)
            {
                List <TagException> tagExceptions;
                if (File.Exists(Utils.GetPath(Utils.AppPath.tagCounterPref)))
                {
                    tagExceptions = JsonConvert.DeserializeObject <List <TagException> >(File.ReadAllText(Utils.GetPath(Utils.AppPath.tagCounterPref)));
                    string[] exceptions = new string[tagExceptions.Count];
                    for (int i = 0; i < tagExceptions.Count; i++)
                    {
                        exceptions[i] = tagExceptions[i].Tag;
                    }
                    _rulesProcessor.UniqueTagExceptions = exceptions;
                }
            }

            _appProfile      = new AppProfile(_arg_sourcePath, rulePaths, false, _arg_simpleTagsOnly, _arg_outputUniqueTagsOnly);
            _appProfile.Args = "analyze -f " + _arg_fileFormat + " -u " + _arg_outputUniqueTagsOnly.ToString().ToLower() + " -v " +
                               WriteOnce.Verbosity.ToString() + " -x " + _arg_confidence + " -i " + _arg_ignoreDefaultRules.ToString().ToLower();
        }
示例#3
0
        public int Run()
        {
            if (_suppressError)
            {
                Console.SetError(StreamWriter.Null);
            }

            if (!Directory.Exists(_path) && !File.Exists(_path))
            {
                Console.Error.WriteLine("Error: Not a valid file or directory {0}", _path);

                return((int)ExitCode.CriticalError);
            }

            Verifier verifier = null;

            if (_rulespath.Count() > 0)
            {
                // Setup the rules
                verifier = new Verifier(_rulespath);
                if (!verifier.Verify())
                {
                    return((int)ExitCode.CriticalError);
                }

                if (verifier.CompiledRuleset.Count() == 0 && _ignoreDefaultRules)
                {
                    Console.Error.WriteLine("Error: No rules were loaded. ");
                    return((int)ExitCode.CriticalError);
                }
            }

            RuleSet rules = new RuleSet();

            if (verifier != null)
            {
                rules = verifier.CompiledRuleset;
            }

            if (!_ignoreDefaultRules)
            {
                Assembly assembly = Assembly.GetExecutingAssembly();
                string   filePath = "Microsoft.DevSkim.CLI.Resources.devskim-rules.json";
                Stream   resource = assembly.GetManifestResourceStream(filePath);
                using (StreamReader file = new StreamReader(resource))
                {
                    rules.AddString(file.ReadToEnd(), filePath, null);
                }
            }

            // Initialize the processor
            RuleProcessor processor = new RuleProcessor(rules);

            if (_severities.Count() > 0)
            {
                processor.SeverityLevel = 0;
                foreach (string severityText in _severities)
                {
                    Severity severity;
                    if (ParseSeverity(severityText, out severity))
                    {
                        processor.SeverityLevel |= severity;
                    }
                    else
                    {
                        Console.Error.WriteLine("Invalid severity: {0}", severityText);
                        return((int)ExitCode.CriticalError);
                    }
                }
            }

            Writer outputWriter = WriterFactory.GetWriter(_fileFormat,
                                                          (string.IsNullOrEmpty(_outputFile)) ? null : "text",
                                                          _outputFormat);

            if (string.IsNullOrEmpty(_outputFile))
            {
                outputWriter.TextWriter = Console.Out;
            }
            else
            {
                outputWriter.TextWriter = File.CreateText(_outputFile);
            }

            int filesAnalyzed = 0;
            int filesSkipped  = 0;
            int filesAffected = 0;
            int issuesCount   = 0;

            // We can pass either a file or a directory; if it's a file, make an IEnumerable out of it.
            IEnumerable <string> fileListing;

            if (!Directory.Exists(_path))
            {
                fileListing = new List <string>()
                {
                    _path
                };
            }
            else
            {
                fileListing = Directory.EnumerateFiles(_path, "*.*", SearchOption.AllDirectories);
            }

            // Iterate through all files
            foreach (string filename in fileListing)
            {
                string language = Language.FromFileName(filename);

                // Skip files written in unknown language
                if (string.IsNullOrEmpty(language))
                {
                    filesSkipped++;
                    continue;
                }

                filesAnalyzed++;
                string  fileText = File.ReadAllText(filename);
                Issue[] issues   = processor.Analyze(fileText, language);

                if (issues.Count() > 0)
                {
                    filesAffected++;
                    issuesCount += issues.Count();
                    Console.Error.WriteLine("file:{0}", filename);

                    // Iterate through each issue
                    foreach (Issue issue in issues)
                    {
                        Console.Error.WriteLine("\tregion:{0},{1},{2},{3} - {4} [{5}] - {6}",
                                                issue.StartLocation.Line,
                                                issue.StartLocation.Column,
                                                issue.EndLocation.Line,
                                                issue.EndLocation.Column,
                                                issue.Rule.Id,
                                                issue.Rule.Severity,
                                                issue.Rule.Name);

                        IssueRecord record = new IssueRecord()
                        {
                            Filename   = filename,
                            Filesize   = fileText.Length,
                            TextSample = fileText.Substring(issue.Boundary.Index, issue.Boundary.Length),
                            Issue      = issue
                        };

                        outputWriter.WriteIssue(record);
                    }

                    Console.Error.WriteLine();
                }
            }

            outputWriter.FlushAndClose();

            Console.Error.WriteLine("Issues found: {0} in {1} files", issuesCount, filesAffected);
            Console.Error.WriteLine("Files analyzed: {0}", filesAnalyzed);
            Console.Error.WriteLine("Files skipped: {0}", filesSkipped);

            return((int)ExitCode.NoIssues);
        }