banalize 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/PARSER.md +43 -0
- data/README.md +168 -0
- data/bin/banalize +120 -0
- data/lib/banalize.rb +64 -0
- data/lib/banalize/errors.rb +43 -0
- data/lib/banalize/exception.rb +19 -0
- data/lib/banalize/files.rb +74 -0
- data/lib/banalize/parser.rb +46 -0
- data/lib/banalize/parser/numbered.rb +102 -0
- data/lib/banalize/policy.rb +95 -0
- data/lib/banalize/policy/severity.rb +35 -0
- data/lib/banalize/registry.rb +219 -0
- data/lib/banalize/runner.rb +101 -0
- data/lib/commands/describe.rb +58 -0
- data/lib/commands/dir.rb +39 -0
- data/lib/commands/file.rb +22 -0
- data/lib/commands/list.rb +25 -0
- data/lib/core_extensions/string.rb +15 -0
- data/lib/helpers/beautify.rb +43 -0
- data/lib/policies/consistent_indents.rb +34 -0
- data/lib/policies/define_path.rb +53 -0
- data/lib/policies/exit_on_error.rb +46 -0
- data/lib/policies/exit_on_unset_variable.rb +58 -0
- data/lib/policies/indentation_style.rb +40 -0
- data/lib/policies/max_line_length.rb +43 -0
- data/lib/policies/minus_n_syntax_check +26 -0
- data/lib/policies/shebang_format.rb +15 -0
- data/lib/policies/trailing_spaces.rb +16 -0
- data/version.txt +1 -0
- metadata +136 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8a4e26483ea5692063efa9d08adb90fcbc552243
|
4
|
+
data.tar.gz: 1225cf15d13b89501f0d6bf2cdff359f2927bcf6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0ac7bff7e15664f2beb9aa862c539451f8dab4531346abfca0d1f4fff5f13c7769666440c24e50c792f10aedaeb7bedf7d8b1c41d92cb53a917c812a65abef95
|
7
|
+
data.tar.gz: 940407208055587056763facf1b72c5720a5933f35cc01284e0d54e6d84bf54259b279ae2fea15202ee44e8c9a3bc5c3f7c0947bb697a8288cbb68f62fc7b146
|
data/PARSER.md
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
|
2
|
+

|
3
|
+
|
4
|
+
Parser architecture
|
5
|
+
===========
|
6
|
+
|
7
|
+
Class Parser
|
8
|
+
-----------
|
9
|
+
|
10
|
+
Bash basic parser defines following methods:
|
11
|
+
|
12
|
+
- {Banalize::Parser#shebang} - first line of the script if it's in `#!` format or nil
|
13
|
+
- {Banalize::Parser#comments} - all block comments of the file, excluding shebang line
|
14
|
+
- {Banalize::Parser#code} - all non-comments of the script, excluding shebang line
|
15
|
+
|
16
|
+
|
17
|
+
All data returned by parser methods are instances of {Banalize::Numbered} class, i.e. they are lines of code with corresponing line number in the script file.
|
18
|
+
|
19
|
+
Class Numbered
|
20
|
+
----------------------
|
21
|
+
|
22
|
+
Class {Banalize::Numbered} provides some helper methods to make searches simpler in the script files:
|
23
|
+
|
24
|
+
- {Banalize::Numbered#grep}
|
25
|
+
|
26
|
+
Find and return lines matching regular expresion.
|
27
|
+
|
28
|
+
- {Banalize::Numbered#has?} Aliased to {Banalize::Numbered#have?}.
|
29
|
+
|
30
|
+
Search for pattern in all lines, return true or false
|
31
|
+
|
32
|
+
- {Banalize::Numbered#does\_not\_have?} Alias {Banalize::Numbered#dont_have?}
|
33
|
+
|
34
|
+
Opposite for the above method. Return true if pattern in not found.
|
35
|
+
|
36
|
+
- {Banalize::Numbered#search} - attribute accessor. It always contains result of the last grep search.
|
37
|
+
- {Banalize::Numbered#lines}
|
38
|
+
- {Banalize::Numbered#to_s} (alias: {Banalize::Numbered#inspect})
|
39
|
+
|
40
|
+
Additional parsers
|
41
|
+
===========
|
42
|
+
|
43
|
+
Will be added in the future.
|
data/README.md
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
[](http://wizcorp.jp)
|
2
|
+
|
3
|
+
**Note** See formatted documentation at http://wizcorp.github.com/Banalize
|
4
|
+
|
5
|
+
Name
|
6
|
+
===========
|
7
|
+
|
8
|
+
Banalize - static code analyzer for Bash
|
9
|
+
|
10
|
+

|
11
|
+
|
12
|
+
Version {include:file:version.txt}
|
13
|
+
-----------
|
14
|
+
|
15
|
+
Description
|
16
|
+
===========
|
17
|
+
|
18
|
+
Banalizer is syntax analyzer for bash scripts. It is modelled after ideas of [`Perl::Critic`](http://en.wikipedia.org/wiki/Perl::Critic) static analyzer for Perl. Most of the Banalizer is written in Ruby. Exception is policy files which are language agnostic, and can be written in any language: scripting or compiled.
|
19
|
+
|
20
|
+
Banalizer consists of main binary file, banalyzer libraries, command line interface (CLI) and policies.
|
21
|
+
|
22
|
+
Policy is requirement for bash script/file. For example: each script must have 'shebang' as first line.
|
23
|
+
|
24
|
+
Each policy is implemented as Ruby or other programming/scripting language file able to perform single check on single bash script file. Rest - aggregating checks, reporting, filtering etc - is handled by Banalizer.
|
25
|
+
|
26
|
+
### Severity
|
27
|
+
|
28
|
+
From [`Perl::Critic`](http://perlcritic.tigris.org/) page:
|
29
|
+
|
30
|
+
> severity is the level of importance you wish to assign to the Policy. All Policy modules are defined with a default severity value ranging from 1 (least severe) to 5 (most severe). However, you may disagree with the default severity and choose to give it a higher or lower severity, based on your own coding philosophy. You can set the severity to an integer from 1 to 5, or use one of the equivalent names:
|
31
|
+
>
|
32
|
+
> SEVERITY NAME ...is equivalent to... SEVERITY NUMBER
|
33
|
+
> ----------------------------------------------------
|
34
|
+
> gentle 5
|
35
|
+
> stern 4
|
36
|
+
> harsh 3
|
37
|
+
> cruel 2
|
38
|
+
> brutal 1
|
39
|
+
>
|
40
|
+
|
41
|
+
### Policy style
|
42
|
+
|
43
|
+
Banalizer's policy style more or less correspond to `Perl::Critic`'s policy theme with exclusion of Perl specific themes. Again quote from `Perl::Critic`:
|
44
|
+
|
45
|
+
|
46
|
+
> THEME DESCRIPTION
|
47
|
+
> --------------------------------------------------------------------------
|
48
|
+
> core All policies that ship with Perl::Critic
|
49
|
+
> pbp Policies that come directly from "Perl Best Practices"
|
50
|
+
> bugs Policies that that prevent or reveal bugs
|
51
|
+
> maintenance Policies that affect the long-term health of the code
|
52
|
+
> cosmetic Policies that only have a superficial effect
|
53
|
+
> complexity Policies that specificaly relate to code complexity
|
54
|
+
> security Policies that relate to security issues
|
55
|
+
> tests Policies that are specific to test scripts
|
56
|
+
>
|
57
|
+
|
58
|
+
See http://perlcritic.tigris.org/#THE%20POLICIES
|
59
|
+
|
60
|
+
Conventions
|
61
|
+
===========
|
62
|
+
|
63
|
+
Policies
|
64
|
+
-----------
|
65
|
+
|
66
|
+
- All policies (policy files) installed in `./lib/policies` and users home `~/.banalize/policies` directories.
|
67
|
+
|
68
|
+
- There are two classes of policies recognized by Banalizer: Ruby and _'other'_
|
69
|
+
- Ruby policy files detected by `.rb` extension. Files without `.rb` extension are considered to be 'others'
|
70
|
+
- Policy name is detected from
|
71
|
+
- file name of 'other' policy
|
72
|
+
- first argument for `banalizer` method for Ruby policy
|
73
|
+
- all names should be unique, or they will be overwritten
|
74
|
+
|
75
|
+
### Attributes
|
76
|
+
|
77
|
+
All policies have these attributes:
|
78
|
+
|
79
|
+
- policy (i.e. name)
|
80
|
+
- synopsis
|
81
|
+
- description
|
82
|
+
- severity
|
83
|
+
- style
|
84
|
+
|
85
|
+
Depending on the type of policy some of the attributes are required, some optional or can be set to reasonable default.
|
86
|
+
|
87
|
+
### Non-ruby policies (i.e. others)
|
88
|
+
|
89
|
+
Policy should conform to few rules:
|
90
|
+
|
91
|
+
1. it must return information about itself when called with parameter `config`
|
92
|
+
- Output of the `config` command is YAML formatted text
|
93
|
+
- Command returns attributes names and values of the policy
|
94
|
+
- All attributes in case of 'other' policy are optional
|
95
|
+
|
96
|
+
They are either set to default values if missing, or detected from other meta-data (like, for example, name of a policy is `$(basename file)` of policy file.
|
97
|
+
2. Policy script must be able to perform single (syntax/semantic/format) check on bash script file and:
|
98
|
+
- return non-zero status if check fails or 0 if succeeds
|
99
|
+
- return (optional) error massages on STDOUT
|
100
|
+
|
101
|
+
**Note**: Only STDOUT is honored by Banalizer.
|
102
|
+
|
103
|
+
If your check command, for example, prints to STDERR but not to STDOUT, you'd need to redirect shell streams accordingly.
|
104
|
+
|
105
|
+
#### Example config section
|
106
|
+
|
107
|
+
```yaml
|
108
|
+
---
|
109
|
+
name: $(basename $0)
|
110
|
+
style:
|
111
|
+
- :bug
|
112
|
+
- :test
|
113
|
+
severity: 5
|
114
|
+
description: Runs bash syntax check using 'bash -n' option
|
115
|
+
```
|
116
|
+
|
117
|
+
### Ruby policy
|
118
|
+
|
119
|
+
1. Ruby policy has two required items:
|
120
|
+
- name (_Note_: to avoid clashes with Ruby standard `name` method we use `policy` DSL method)
|
121
|
+
- must define method called `run`
|
122
|
+
1. Policy is defined in top-level namespace's method called `banalizer`
|
123
|
+
- name is string or Ruby symbol parameter to `banalizer` method
|
124
|
+
- additional (optional) attributes are defined as DSL methods calls inside block given to `banalizer` method
|
125
|
+
- run method is defined in the same block
|
126
|
+
1. DSL methods names correspond to policy attributes :
|
127
|
+
- policy (i.e. policy name)
|
128
|
+
- synopsis
|
129
|
+
- description
|
130
|
+
- style
|
131
|
+
- severity
|
132
|
+
1. `run` method :
|
133
|
+
- need to return result of a check as something that can be evaluated into true or false
|
134
|
+
- optionally can pass along error messages from the check, using `errors.add` DSL method to populate errors object (instance of {Banalize::Errors} class
|
135
|
+
1. Additionally Ruby policies have DSL method `default`. It sets default values for variables, that can be overridden by personal style configuration file ( See {file:CONFIGURATION.md}).
|
136
|
+
|
137
|
+
#### Examples
|
138
|
+
|
139
|
+
This is full working example of Ruby DSL policy:
|
140
|
+
|
141
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ruby
|
142
|
+
banalizer :shebang_format do
|
143
|
+
|
144
|
+
synopsis 'Format of shebang should be #!/usr/bin/env bash'
|
145
|
+
severity 5
|
146
|
+
|
147
|
+
def run
|
148
|
+
unless shebang.has?(%r{\#!/usr/bin/env\s+bash})
|
149
|
+
|
150
|
+
errors.add "First line is not in the format #!/usr/bin/env bash", 1
|
151
|
+
return false
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
157
|
+
|
158
|
+
If you want to use filename of Ruby policy as its name, do this:
|
159
|
+
|
160
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ruby
|
161
|
+
banalizer File.basename(__FILE__, '.rb').to_sym do
|
162
|
+
|
163
|
+
end
|
164
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
165
|
+
|
166
|
+
|
167
|
+
<!-- LocalWords: banalize
|
168
|
+
-->
|
data/bin/banalize
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'banalize'
|
4
|
+
|
5
|
+
include GLI::App
|
6
|
+
commands_from "commands"
|
7
|
+
version Banalize::VERSION
|
8
|
+
config_file Banalize::USER[:config]
|
9
|
+
program_desc <<-EOF
|
10
|
+
|
11
|
+
Banalize is Bash files static code analyzer. It runs each policy
|
12
|
+
corresponding to the required level of test severity and policies.
|
13
|
+
|
14
|
+
Policies are Ruby or other programming languages (Bash, perl)
|
15
|
+
executable scripts located in `lib/policies` directories.
|
16
|
+
|
17
|
+
EOF
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
flag [:group, :g], :desc => 'Use only policies included in specified group'
|
22
|
+
flag [:severity, :s], :desc => 'Use only policies of specified severity and above'
|
23
|
+
flag [:policy, :p], :desc => 'Apply single policy only (by name)'
|
24
|
+
flag [:style, :S], :desc => 'Use custom style file instead of default one.',
|
25
|
+
:default_value => Banalize::USER[:styles]
|
26
|
+
|
27
|
+
switch [:color, :c], :desc => "Use colored output"
|
28
|
+
|
29
|
+
pre do |global,command,options,args|
|
30
|
+
|
31
|
+
$color = true if global[:color]
|
32
|
+
|
33
|
+
#
|
34
|
+
# Load styles file. Styles override defaults defined in policies.
|
35
|
+
#
|
36
|
+
$styles = if global[:style] != Banalize::USER[:styles] ||
|
37
|
+
File.exist?(File.expand_path(Banalize::USER[:styles]))
|
38
|
+
begin
|
39
|
+
YAML.load_file global[:style]
|
40
|
+
rescue Banalize::BanalizeError => e
|
41
|
+
abort "#{e.class} error: Can not load styles file #{e.message}"
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
search = { }
|
47
|
+
|
48
|
+
if global[:policy]
|
49
|
+
search = global[:policy]
|
50
|
+
else
|
51
|
+
search.merge!({ :policy => global[:group] }) if global[:group]
|
52
|
+
search.merge!({ :severity => global[:severity].to_i }) if global[:severity]
|
53
|
+
end
|
54
|
+
|
55
|
+
$search = search
|
56
|
+
$policies = Banalize::Policy.search search
|
57
|
+
|
58
|
+
# - results of checks
|
59
|
+
# - count of failed checks
|
60
|
+
# - total count of checks
|
61
|
+
$res, $status, $total = { }, 0, 0
|
62
|
+
true
|
63
|
+
end
|
64
|
+
|
65
|
+
post do |global,command,options,args|
|
66
|
+
#
|
67
|
+
# output results of the check
|
68
|
+
#
|
69
|
+
unless $res.empty?
|
70
|
+
|
71
|
+
if options[:dots]
|
72
|
+
dots = ''
|
73
|
+
$res.each do |file,res|
|
74
|
+
$total += res.count
|
75
|
+
res.each do |k,v|
|
76
|
+
dots << (v[:status] ? '.' : "F".color(:red))
|
77
|
+
$status += 1 unless v[:status]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
puts dots
|
81
|
+
|
82
|
+
else
|
83
|
+
out = { }
|
84
|
+
$res.each do |file,res|
|
85
|
+
|
86
|
+
failure = res.select { |k,v| !v[:status] }
|
87
|
+
|
88
|
+
# Ignore all other keys, only bring messages up. If no errors
|
89
|
+
# switch is set. only list empty policy names
|
90
|
+
failure.map do |k,v|
|
91
|
+
failure[k] = options[:errors] ? v[:messages] : nil
|
92
|
+
end
|
93
|
+
|
94
|
+
out[file] = { "Fail" => failure } unless failure.empty?
|
95
|
+
|
96
|
+
if options[:all]
|
97
|
+
out[file] ||= {}
|
98
|
+
out[file].merge!({ "Success" => res.keys.select { |k| res[k][:status] } })
|
99
|
+
end
|
100
|
+
|
101
|
+
$total += res.count
|
102
|
+
$status += failure.count
|
103
|
+
end
|
104
|
+
|
105
|
+
print ::Banalize.beautify(out)
|
106
|
+
end
|
107
|
+
|
108
|
+
puts "\n#{$res.count} files, #{$total.to_s} checks, #{$status.to_s} failed"
|
109
|
+
end
|
110
|
+
|
111
|
+
$status
|
112
|
+
end
|
113
|
+
|
114
|
+
on_error do |exception|
|
115
|
+
exit_now! exception.message unless exception.is_a? GLI::BadCommandLine
|
116
|
+
true
|
117
|
+
end
|
118
|
+
|
119
|
+
exit run(ARGV) && $status == 0
|
120
|
+
|
data/lib/banalize.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
$: << File.dirname(__FILE__)
|
2
|
+
|
3
|
+
require 'gli'
|
4
|
+
require 'mash'
|
5
|
+
require 'active_support/inflector'
|
6
|
+
require 'active_support/core_ext'
|
7
|
+
|
8
|
+
# Order is not important, load all of them
|
9
|
+
Dir.glob("#{File.dirname(__FILE__)}/{core_extensions,helpers}/*.rb").each do |r|
|
10
|
+
require r
|
11
|
+
end
|
12
|
+
|
13
|
+
##
|
14
|
+
# This is shamelessly stolen form Rspec::DSL. Inject method `policy`
|
15
|
+
# into the top level namespace, so the we can use in policy definition
|
16
|
+
# without need to define class inheritance.
|
17
|
+
#
|
18
|
+
# Registerd policies are listed in `@@policies` array.
|
19
|
+
#
|
20
|
+
module Banalize
|
21
|
+
ROOT = File.dirname(File.dirname(__FILE__))
|
22
|
+
VERSION = File.read(ROOT+'/version.txt').chomp.strip
|
23
|
+
|
24
|
+
# Local user directory with banalize config and policies
|
25
|
+
|
26
|
+
dot_banalize = "#{Dir.home}/.banalize"
|
27
|
+
|
28
|
+
USER = {
|
29
|
+
dot_banalize: dot_banalize,
|
30
|
+
config: "#{dot_banalize}/config", # Default user config file
|
31
|
+
styles: "#{dot_banalize}/style", # Default style file
|
32
|
+
policies: "#{dot_banalize}/policies"
|
33
|
+
}
|
34
|
+
|
35
|
+
# Truncate long error lines
|
36
|
+
TRUNCATE = ENV["BANALIZE_TRUNCATE_LINES"] == 'false' ? nil : 60
|
37
|
+
|
38
|
+
module DSL
|
39
|
+
@@policies = []
|
40
|
+
def banalizer my_name, &block
|
41
|
+
klass = Banalize::Registry.register(my_name, &block)
|
42
|
+
@@policies << klass
|
43
|
+
klass
|
44
|
+
end
|
45
|
+
|
46
|
+
def policies
|
47
|
+
@@policies
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
include Banalize::DSL
|
53
|
+
|
54
|
+
require 'banalize/parser/numbered'
|
55
|
+
require 'banalize/parser'
|
56
|
+
require 'banalize/exception'
|
57
|
+
require 'banalize/registry'
|
58
|
+
|
59
|
+
require 'banalize/errors'
|
60
|
+
require 'banalize/policy/severity'
|
61
|
+
require 'banalize/policy'
|
62
|
+
require 'banalize/files'
|
63
|
+
require 'banalize/runner'
|
64
|
+
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Banalize
|
2
|
+
##
|
3
|
+
# Errors class provides stograge of error messages while running policy checks.
|
4
|
+
class Errors
|
5
|
+
|
6
|
+
def initialize klass
|
7
|
+
@klass = klass
|
8
|
+
@messages = []
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_accessor :messages
|
12
|
+
|
13
|
+
def add message, line=nil
|
14
|
+
@messages << { :message => message, :line => line }
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# Retrun true if there are no errors
|
19
|
+
def empty?
|
20
|
+
@messages.empty?
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# Retrun true if there are any errors
|
25
|
+
#
|
26
|
+
def any?
|
27
|
+
! empty?
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
##
|
32
|
+
# Convert Array of Hashes of error messages into readable form
|
33
|
+
#
|
34
|
+
def self.to_s messages=[]
|
35
|
+
return '' if messages.empty?
|
36
|
+
|
37
|
+
messages.map do |err|
|
38
|
+
"#{err[:message]}#{err[:line] ? ", on line #{err[:line]}" : ''}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|