From 4eeb4783d33eafeeda88186c058b8517a21e82bc Mon Sep 17 00:00:00 2001 From: Jason Tibbitts Date: Wed, 19 Apr 2017 17:40:58 -0500 Subject: [PATCH] Add rpm spec file linter (rpmlint) (#486) * Initial attempt at an rpmlint linter. * Add some basic documentation. * Play with indentation in the test file. * Another attempt to fix the rpmlint test. * Hopefully this does it. --- README.md | 1 + ale_linters/spec/rpmlint.vim | 85 +++++++++++++++++++++++++ doc/ale-spec.txt | 28 ++++++++ doc/ale.txt | 3 + test/handler/test_rpmlint_handler.vader | 29 +++++++++ 5 files changed, 146 insertions(+) create mode 100644 ale_linters/spec/rpmlint.vim create mode 100644 doc/ale-spec.txt create mode 100644 test/handler/test_rpmlint_handler.vader diff --git a/README.md b/README.md index bdc3824..325e781 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,7 @@ name. That seems to be the fairest way to arrange this table. | Puppet | [puppet](https://puppet.com), [puppet-lint](https://puppet-lint.com) | | Python | [flake8](http://flake8.pycqa.org/en/latest/), [mypy](http://mypy-lang.org/), [pylint](https://www.pylint.org/) | | reStructuredText | [proselint](http://proselint.com/)| +| RPM spec | [rpmlint](https://github.com/rpm-software-management/rpmlint) | | Ruby | [rubocop](https://github.com/bbatsov/rubocop), [ruby](https://www.ruby-lang.org) | | Rust | [rustc](https://www.rust-lang.org/), cargo (see `:help ale-integration-rust` for configuration instructions) | | SASS | [sass-lint](https://www.npmjs.com/package/sass-lint), [stylelint](https://github.com/stylelint/stylelint) | diff --git a/ale_linters/spec/rpmlint.vim b/ale_linters/spec/rpmlint.vim new file mode 100644 index 0000000..f5308af --- /dev/null +++ b/ale_linters/spec/rpmlint.vim @@ -0,0 +1,85 @@ +" Author: Jason Tibbitts +" Description: Adds support for checking RPM spec files with rpmlint + +" rpmlint will produce varions types of output: +" +" Lines like the following are output when the file is simply not able to be +" parsed by rpmspec -P: +" apcupsd.spec: E: specfile-error warning: bogus date in %changelog: Mon Oct 1 2005 - Foo +" apcupsd.spec: E: specfile-error error: %changelog not in descending chronological order +" They do not contain a line number, and there's not a whole lot that can be +" done to locate them besides grep for them. rpmlint is just passing the +" output from rpm along with the filename, an error indicator, and an error +" type. +" +" Lines like the following: +" cyrus-imapd.spec:23: W: macro-in-comment %version +" cyrus-imapd.spec:18: E: hardcoded-library-path in %_prefix/lib/%name +" indicate warnings and errors, respectively. No column numbers are provided +" +" Lines like: +" apcupsd.spec: I: checking +" apcupsd.spec: I: checking-url https://downloads.sourceforge.net/apcupsd/apcupsd-3.14.14.tar.gz (timeout 10 seconds) +" are merely informational and are only output when -v is passed. But they +" may be useful in a log to know why things are taking so long. +" +" And this is always output at the end and should just be ignored: +" 0 packages and 1 specfiles checked; 4 errors, 0 warnings. + +let g:ale_spec_rpmlint_executable = +\ get(g:, 'ale_spec_rpmlint_executable', 'rpmlint') + +let g:ale_spec_rpmlint_options = +\ get(g:, 'ale_spec_rpmlint_options', '') + +function! ale_linters#spec#rpmlint#GetExecutable(buffer) abort + return ale#Var(a:buffer, 'spec_rpmlint_executable') +endfunction + +function! ale_linters#spec#rpmlint#GetCommand(buffer) abort + return ale_linters#spec#rpmlint#GetExecutable(a:buffer) + \ . ' ' . ale#Var(a:buffer, 'spec_rpmlint_options') + \ . ' -o "NetworkEnabled False"' + \ . ' -v' + \ . ' %t' +endfunction + +function! ale_linters#spec#rpmlint#Handle(buffer, lines) abort + " let l:pat_inform = '^.\+: I: \(.+\)' + let l:pat_errwarn = '^.\+:\(\d\+\): \([EW]\): \(.\+\)' + let l:pat_baderr = '^.\+: E: \(.\+\)' + let l:output = [] + + for l:line in a:lines + let l:match_errwarn = matchlist(l:line, l:pat_errwarn) + let l:match_baderr = matchlist(l:line, l:pat_baderr) + + if len(l:match_errwarn) > 0 + let l:text = l:match_errwarn[3] + let l:type = l:match_errwarn[2] + let l:lnum = l:match_errwarn[1] + 0 + elseif len(l:match_baderr) > 0 + let l:text = l:match_baderr[1] + let l:type = 'E' + let l:lnum = 1 + else + continue + endif + + call add(l:output, { + \ 'bufnr': a:buffer, + \ 'lnum': l:lnum, + \ 'text': l:text, + \ 'type': l:type, + \}) + endfor + + return l:output +endfunction + +call ale#linter#Define('spec', { +\ 'name': 'rpmlint', +\ 'executable_callback': 'ale_linters#spec#rpmlint#GetExecutable', +\ 'command_callback': 'ale_linters#spec#rpmlint#GetCommand', +\ 'callback': 'ale_linters#spec#rpmlint#Handle', +\}) diff --git a/doc/ale-spec.txt b/doc/ale-spec.txt new file mode 100644 index 0000000..fc6be56 --- /dev/null +++ b/doc/ale-spec.txt @@ -0,0 +1,28 @@ +=============================================================================== +ALE RPM Spec Integration *ale-spec-options* + + +------------------------------------------------------------------------------- +rpmlint *ale-spec-rpmlint* + +g:ale_spec_rpmlint_executable *g:ale_spec_rpmlint_executable* + + Type: |String| + Default: `'rpmlint'` + + This variable sets executable used for rpmlint. + + +g:ale_spec_rpmlint_options *g:ale_spec_rpmlint_options* + + Type: |String| + Default: `''` + + Set this to pass extra arguments to rpmlint. + + For example, to instruct rpmlint to use a specific configuration file: + + let g:ale_spec_rpmlint_options = '-f custom.cf' + +------------------------------------------------------------------------------- + vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: diff --git a/doc/ale.txt b/doc/ale.txt index 1e33299..d3044d7 100644 --- a/doc/ale.txt +++ b/doc/ale.txt @@ -71,6 +71,8 @@ CONTENTS *ale-contents* sh....................................|ale-sh-options| shell...............................|ale-sh-shell| shellcheck..........................|ale-sh-shellcheck| + spec..................................|ale-spec-options| + rpmlint.............................|ale-spec-rpmlint| tex...................................|ale-tex-options| chktex..............................|ale-tex-chktex| lacheck.............................|ale-tex-lacheck| @@ -151,6 +153,7 @@ The following languages and tools are supported. * Puppet: 'puppet', 'puppet-lint' * Python: 'flake8', 'mypy', 'pylint' * reStructuredText: 'proselint' +* RPM spec: 'spec' * Rust: 'rustc' (see |ale-integration-rust|) * Ruby: 'rubocop' * SASS: 'sasslint', 'stylelint' diff --git a/test/handler/test_rpmlint_handler.vader b/test/handler/test_rpmlint_handler.vader new file mode 100644 index 0000000..45f5071 --- /dev/null +++ b/test/handler/test_rpmlint_handler.vader @@ -0,0 +1,29 @@ +Execute(The rpmlint handler should parse error messages correctly): + runtime ale_linters/spec/rpmlint.vim + + AssertEqual + \ [ + \ { + \ 'bufnr': 42, + \ 'lnum': 23, + \ 'text': 'macro-in-comment %version', + \ 'type': 'W', + \ }, + \ { + \ 'bufnr': 42, + \ 'lnum': 17, + \ 'text': 'hardcoded-library-path in %_prefix/lib/%name', + \ 'type': 'E', + \ }, + \ { + \ 'bufnr': 42, + \ 'lnum': 1, + \ 'text': 'specfile-error warning: bogus date in %changelog: Mon Oct 1 2005 - Foo', + \ 'type': 'E', + \ }, + \ ], + \ ale_linters#spec#rpmlint#Handle(42, [ + \ 'cyrus-imapd.spec:23: W: macro-in-comment %version', + \ 'cyrus-imapd.spec:17: E: hardcoded-library-path in %_prefix/lib/%name', + \ 'apcupsd.spec: E: specfile-error warning: bogus date in %changelog: Mon Oct 1 2005 - Foo', + \ ])