puppet-cleaner 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/COPYRIGHT ADDED
@@ -0,0 +1,26 @@
1
+ Copyright (c) 2013, Gerardo Santana Gomez Garrido <gerardo.santana@gmail.com>
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions
6
+ are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright
9
+ notice, this list of conditions and the following disclaimer.
10
+ 2. Redistributions in binary form must reproduce the above copyright
11
+ notice, this list of conditions and the following disclaimer in the
12
+ documentation and/or other materials provided with the distribution.
13
+ 3. The name of the author may not be used to endorse or promote products
14
+ derived from this software without specific prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25
+ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26
+ POSSIBILITY OF SUCH DAMAGE.
data/Changelog ADDED
@@ -0,0 +1,8 @@
1
+ 0.1.0 2013-04-16
2
+ -----------------
3
+ Features:
4
+ * run puppet-clean -h to see the list of available formatters
5
+
6
+ Caveats:
7
+ * comments are assumed to occur alone in a line
8
+ * monkey patches puppet 2.7.11; it hasn't been tested on any other version
data/README.md ADDED
@@ -0,0 +1,40 @@
1
+ Puppet Cleaner
2
+ ==============
3
+
4
+ Puppet DSL source code cleaner and helper utilities
5
+
6
+ Motivation
7
+ ----------
8
+ http://santanatechnotes.blogspot.mx/2013/04/puppet-cleaner-010-released.html
9
+
10
+ Requirements
11
+ ------------
12
+
13
+ * puppet
14
+
15
+ it has been tested with puppet 2.7.11 only
16
+
17
+ Utilities
18
+ ------------
19
+
20
+ ### puppet-clean
21
+
22
+ Receives a puppet manifest file as input and outputs the result of
23
+ applying a set of transformation rules that makes it comply with
24
+ a subset of the current puppet style guide.
25
+
26
+ ### puppet-diff
27
+
28
+ Receives two puppet manifest files and outputs its difference, after
29
+ converting them to YAML. Useful for verifying what (if anything) has
30
+ changed after applying puppet-clean.
31
+
32
+ ### puppet-inspect
33
+
34
+ Receives a puppet manifest file and converts its objects (defined types,
35
+ classes and nodes) to YAML.
36
+
37
+ Help & Feedback
38
+ ------------
39
+
40
+ Mail me directly if you need help or have any feedback about it.
data/bin/puppet-clean ADDED
@@ -0,0 +1,101 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'getoptlong'
4
+ require 'puppet-cleaner'
5
+
6
+ def usage
7
+ warn <<-EOS
8
+ Usage:
9
+
10
+ #{File.basename($0)} [-h] [-t n] [-abedlmovw ] file.pp [file2.pp...]
11
+
12
+ Options:
13
+ -h, --help this help message
14
+ -d, --debug prints tokens before and after the transformation
15
+
16
+ -a, --alignfarrow aligns fat arrow (=>)
17
+ -b, --quotedbooleans removes unneeded quotes around boolean literals
18
+ -e, --ensurefirst moves 'ensure' parameter to the top
19
+ -l, --link uses ensure => link and target for symbolic links
20
+ -m, --mlcomments converts /* */ style comments into #
21
+ -o, --octalmode uses a 4 digit string for file modes
22
+ -t n, --softtabs n indents by n spaces
23
+ -v, --quotedvariables removes unneeded quotes around variables
24
+ -w, --trailingws removes trailing white space
25
+ EOS
26
+ exit 1
27
+ end
28
+
29
+ opts = GetoptLong.new(
30
+ [ '--help', '-h', GetoptLong::NO_ARGUMENT ],
31
+ [ '--debug', '-d', GetoptLong::NO_ARGUMENT ],
32
+
33
+ [ '--alignfarrow', '-a', GetoptLong::NO_ARGUMENT ],
34
+ [ '--quotedbooleans', '-b', GetoptLong::NO_ARGUMENT ],
35
+ [ '--ensurefirst', '-e', GetoptLong::NO_ARGUMENT ],
36
+ [ '--link', '-l', GetoptLong::NO_ARGUMENT ],
37
+ [ '--mlcomments', '-m', GetoptLong::NO_ARGUMENT ],
38
+ [ '--octalmode', '-o', GetoptLong::NO_ARGUMENT ],
39
+ [ '--softtabs', '-t', GetoptLong::REQUIRED_ARGUMENT ],
40
+ [ '--quotedvariables', '-v', GetoptLong::NO_ARGUMENT ],
41
+ [ '--trailingws', '-w', GetoptLong::NO_ARGUMENT ]
42
+ )
43
+
44
+ debug = false
45
+ workers = []
46
+
47
+ opts.each do |opt, arg|
48
+ case opt
49
+ when '--help'
50
+ usage
51
+ when '--debug'
52
+ debug = true
53
+ when '--alignfarrow'
54
+ workers << Puppet::Cleaner::AlignFarrow.new
55
+ when '--quotedbooleans'
56
+ workers << Puppet::Cleaner::QuotedBooleans.new
57
+ when '--ensurefirst'
58
+ workers << Puppet::Cleaner::EnsureFirst.new
59
+ when '--link'
60
+ workers << Puppet::Cleaner::Symlink.new
61
+ when '--mlcomments'
62
+ workers << Puppet::Cleaner::MultilineComments.new
63
+ when '--octalmode'
64
+ workers << Puppet::Cleaner::OctalMode.new
65
+ when '--softtabs'
66
+ tabstop = arg.to_i <= 2 ? 2 : arg.to_i
67
+ workers << Puppet::Cleaner::SoftTabs.new(tabstop)
68
+ when '--quotedvariables'
69
+ workers << Puppet::Cleaner::UnneededQuotes.new
70
+ when '--trailingws'
71
+ workers << Puppet::Cleaner::TrailingWhitespace.new
72
+ workers << Puppet::Cleaner::TrailingWhitespaceInComments.new
73
+ end
74
+ end
75
+
76
+ usage if ARGV.size < 1
77
+
78
+ ALL = [
79
+ Puppet::Cleaner::MultilineComments.new,
80
+ Puppet::Cleaner::SoftTabs.new,
81
+ Puppet::Cleaner::UnneededQuotes.new,
82
+ Puppet::Cleaner::TrailingWhitespace.new,
83
+ Puppet::Cleaner::TrailingWhitespaceInComments.new,
84
+ Puppet::Cleaner::AlignFarrow.new,
85
+ Puppet::Cleaner::OctalMode.new,
86
+ Puppet::Cleaner::EnsureFirst.new,
87
+ Puppet::Cleaner::QuotedBooleans.new,
88
+ Puppet::Cleaner::Symlink.new
89
+ ]
90
+
91
+
92
+ workers = ALL if workers.empty?
93
+
94
+ ARGV.each do |filename|
95
+ line = Puppet::Cleaner.open(filename)
96
+ line.hire(workers)
97
+ puts line.inspect if debug
98
+ line.transform!
99
+ line.show
100
+ puts line.inspect if debug
101
+ end
data/bin/puppet-diff ADDED
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'puppet-cleaner/inspect'
4
+
5
+ def usage
6
+ warn <<-EOS
7
+ Usage:
8
+ #{File.basename $0} [-h] [-w] old.pp new.pp
9
+
10
+ Options:
11
+ -h, --help this help message
12
+ -w, --write write a YAML file for each pp file if they are different
13
+ EOS
14
+ exit 1
15
+ end
16
+
17
+ opts = GetoptLong.new(
18
+ [ '--help', '-h', GetoptLong::NO_ARGUMENT ],
19
+ [ '--write', '-w', GetoptLong::NO_ARGUMENT ]
20
+ )
21
+
22
+ writedown = false
23
+
24
+ opts.each do |opt, arg|
25
+ case opt
26
+ when '--help'
27
+ usage
28
+ when '--write'
29
+ writedown = true
30
+ end
31
+ end
32
+
33
+ usage if ARGV.size != 2
34
+
35
+ filenames = ARGV
36
+
37
+ old, new = filenames.collect do |filename|
38
+ catalog = Puppet::Cleaner.inspect(filename)
39
+ catalog.to_yaml.gsub(/^.*(?:file(?:_index)?|line):.*$/, "")
40
+ end
41
+
42
+ if old != new
43
+ puts "#{filenames[0]} and #{filenames[1]} differ"
44
+
45
+ if writedown
46
+ File.open("#{filenames[0]}.yaml", "w") {|f| f.write old }
47
+ File.open("#{filenames[1]}.yaml", "w") {|f| f.write new }
48
+ end
49
+ end
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'puppet-cleaner/inspect'
4
+
5
+ def usage
6
+ warn <<-EOS
7
+ Usage:
8
+ #{File.basename $0} file.pp
9
+ EOS
10
+ exit 1
11
+ end
12
+
13
+ usage if ARGV.size != 1
14
+
15
+ filename = ARGV[0]
16
+ catalog = Puppet::Cleaner.inspect(filename)
17
+ catalog.each {|e| puts e.to_yaml }
@@ -0,0 +1,11 @@
1
+ require 'puppet/parser'
2
+
3
+ module Puppet::Cleaner
4
+ def self.inspect(filename)
5
+ Puppet[:manifest] = filename
6
+ tc = Puppet::Node::Environment.new(Puppet[:environment]).known_resource_types
7
+ catalog = [:nodes, :hostclasses, :definitions].collect {|meth| tc.send(meth) }
8
+ tc.clear
9
+ catalog
10
+ end
11
+ end
@@ -0,0 +1,108 @@
1
+ require 'puppet-cleaner/parts'
2
+
3
+ module Puppet::Cleaner
4
+ class Line
5
+ attr :position
6
+
7
+ def initialize(parts)
8
+ @parts = parts.map {|part| Part.create(part) }
9
+ @workers = Hash.new {|h, k| h[k] = []}
10
+ @position = 0
11
+ end
12
+
13
+ def hire(workers)
14
+ @workers.clear
15
+ workers.each do |worker|
16
+ worker.part_names.each {|part_name| @workers[part_name] << worker }
17
+ end
18
+ end
19
+
20
+ def transform!
21
+ start do |part|
22
+ @workers[part.name].each do |worker|
23
+ worker.operate(self)
24
+ if part.object_id != current.object_id
25
+ back!
26
+ break
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ def inspect
33
+ @parts.inject("") {|m, part| m += "#{part.name.inspect}\t#{part.value.inspect}\n"}
34
+ end
35
+
36
+ def show
37
+ start {|part| context = {:before => prev, :after => self.next}; part.show(context) }
38
+ end
39
+
40
+ def start
41
+ reset!
42
+ while !empty?
43
+ yield current
44
+ advance!
45
+ end
46
+ end
47
+
48
+ def size
49
+ @parts.size
50
+ end
51
+
52
+ def reset!
53
+ @position = 0
54
+ end
55
+
56
+ def advance!(n = 1)
57
+ @position += n
58
+ end
59
+
60
+ def back!(n = 1)
61
+ @position -= n
62
+ end
63
+
64
+ def empty?
65
+ @position >= 0 && @position >= size
66
+ end
67
+
68
+ def parts
69
+ @parts
70
+ end
71
+
72
+ def current
73
+ @parts[@position]
74
+ end
75
+
76
+ def next(n = 1)
77
+ (@position + n) >= size ? NoPart : @parts[@position + n]
78
+ end
79
+
80
+ def prev(n = 1)
81
+ (@position - n) < 0 ? NoPart : @parts[@position - n]
82
+ end
83
+
84
+ def last?
85
+ @position == (size - 1)
86
+ end
87
+
88
+ def lookup(name, ignore = [])
89
+ position = @position
90
+ while position < size && !(ignore + [name]).include?(@parts[position].name)
91
+ position += 1
92
+ end
93
+ position == size || @parts[position].name != name ? nil : position
94
+ end
95
+
96
+ def remove(pos)
97
+ @parts.delete_at(pos)
98
+ end
99
+
100
+ def insert(pos, parts)
101
+ @parts.insert(pos, *parts)
102
+ end
103
+
104
+ def append(pos, parts)
105
+ @parts.insert(pos + 1, *parts)
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,137 @@
1
+ module Puppet::Cleaner
2
+ class Part
3
+ # what makes a double quote string special
4
+ DQSPECIAL = {
5
+ "\n" => "\\n",
6
+ "\r" => "\\r",
7
+ "\t" => "\\t"
8
+ }
9
+
10
+ DQESCAPE = DQSPECIAL.dup
11
+ DQESCAPE["\""] = "\\\""
12
+ DQESCAPE["\\"] = "\\\\"
13
+ DQESCAPE["$"] = "\\$"
14
+
15
+ SQESCAPE = {
16
+ "'" => "\\'"
17
+ }
18
+
19
+ DQPATTERN = /[#{DQESCAPE.keys.map{|key| key.inspect[1..-2]}.join}]/
20
+ SQPATTERN = /[#{SQESCAPE.keys.map{|key| key.inspect[1..-2]}.join}]/
21
+
22
+ SPECIAL_ESCAPE_SEQUENCES = /[#{DQSPECIAL.keys.map{|key| key.inspect[1..-2]}.join}]/
23
+
24
+ def self.create(raw)
25
+ begin
26
+ klass = Puppet::Cleaner.const_get(raw[0].to_s.capitalize.to_sym)
27
+ klass.new(raw)
28
+ rescue NameError => e
29
+ Part.new(raw)
30
+ end
31
+ end
32
+
33
+ def initialize(raw)
34
+ @raw = raw
35
+ end
36
+
37
+ def has_special_escape_sequences?
38
+ value =~ SPECIAL_ESCAPE_SEQUENCES
39
+ end
40
+
41
+ def show(context)
42
+ print to_s
43
+ end
44
+
45
+ def name
46
+ @raw[0]
47
+ end
48
+
49
+ def name=(name)
50
+ @raw[0] = name
51
+ end
52
+
53
+ def to_s
54
+ value.to_s
55
+ end
56
+
57
+ def value
58
+ @raw[1][:value]
59
+ end
60
+
61
+ def value=(value)
62
+ @raw[1][:value] = value
63
+ end
64
+
65
+ def dqescape
66
+ value.gsub(Part::DQPATTERN) {|match| Part::DQESCAPE[match]}
67
+ end
68
+
69
+ def sqescape
70
+ ret = value.gsub(Part::SQPATTERN) {|match| Part::SQESCAPE[match]}
71
+ ret =~ /\\+$/
72
+ ret += "\\" if $& && $&.size % 2 == 1
73
+ ret
74
+ end
75
+
76
+ end
77
+
78
+ class Variable < Part
79
+ def to_s
80
+ "$#{value}"
81
+ end
82
+
83
+ def show(context)
84
+ if [:DQPRE, :DQMID].include?(context[:before].name)
85
+ print value
86
+ else
87
+ super
88
+ end
89
+ end
90
+ end
91
+
92
+ class Comment < Part
93
+ def to_s
94
+ value.empty? ? "#" : "# #{value}"
95
+ end
96
+ end
97
+
98
+ class Mlcomment < Part
99
+ def to_s
100
+ "/*#{value}*/"
101
+ end
102
+ end
103
+
104
+ class Dqpre < Part
105
+ def to_s
106
+ "\"#{dqescape}${"
107
+ end
108
+ end
109
+
110
+ class Dqmid < Part
111
+ def to_s
112
+ "}#{dqescape}${"
113
+ end
114
+ end
115
+
116
+ class Dqpost < Part
117
+ def to_s
118
+ "}#{dqescape}\""
119
+ end
120
+ end
121
+
122
+ class String < Part
123
+ def to_s
124
+ has_special_escape_sequences? ? "\"#{dqescape}\"" : "'#{sqescape}'"
125
+ end
126
+ end
127
+
128
+ class Class < Part; end
129
+
130
+ class Regex < Part
131
+ def to_s
132
+ value.inspect
133
+ end
134
+ end
135
+
136
+ NoPart = Part.new([:NOPART, {:value => ""}])
137
+ end
@@ -0,0 +1,55 @@
1
+ module Puppet::Cleaner
2
+ class AlignFarrow < Worker
3
+ def part_names
4
+ [:LBRACE]
5
+ end
6
+
7
+ def operate(line)
8
+ max, params = get_params(line)
9
+ params.each do |param|
10
+ nblanks = max - param[:name].to_s.size + 1
11
+ param[:before].value = ' '*nblanks if param[:before].value.size != nblanks
12
+ end
13
+ end
14
+
15
+ def get_params(line)
16
+ depth = 1
17
+ max = 0
18
+ pos = line.position
19
+ params = []
20
+
21
+ loop do
22
+ pos += 1
23
+ break if depth == 0 || pos >= line.parts.size
24
+ case line.parts[pos].name
25
+ when :LBRACE
26
+ depth += 1
27
+ when :RBRACE
28
+ depth -= 1
29
+ when :FARROW
30
+ next if depth != 1
31
+
32
+ if line.parts[pos - 1].name == :BLANK
33
+ name = line.parts[pos - 2]
34
+ before = line.parts[pos - 1]
35
+ else
36
+ name = line.parts[pos - 1]
37
+ before = Part.create([:BLANK, {:value => ''}])
38
+ line.insert(pos, [before])
39
+ pos += 1
40
+ end
41
+
42
+ if line.parts[pos + 1].name == :BLANK
43
+ line.parts[pos + 1].value = ' ' if line.parts[pos + 1].value != ' '
44
+ else
45
+ line.append(pos, Part.create([:BLANK, {:value => ' '}]))
46
+ end
47
+
48
+ max = name.to_s.size if name.to_s.size > max
49
+ params << {:name => name, :before => before}
50
+ end
51
+ end
52
+ [max, params]
53
+ end
54
+ end
55
+ end # module
@@ -0,0 +1,27 @@
1
+ module Puppet::Cleaner
2
+ class EnsureFirst < Worker
3
+ def part_names
4
+ [:COLON]
5
+ end
6
+
7
+ def operate(line)
8
+ pos = line.position + 1
9
+ pos += 1 while [:BLANK, :RETURN, :COMMENT, :MLCOMMENT].include?(line.parts[pos].name)
10
+ return if line.parts[pos].name == :NAME && line.parts[pos].value == 'ensure'
11
+ start, pos = get_param(line, 'ensure', line.position)
12
+ return if start.nil?
13
+
14
+ ensure_param = line.parts.slice!(start..pos)
15
+ ensure_param += [Part.create([:COMMA, {:value => ","}])] unless ensure_param[-1].name == :COMMA
16
+
17
+ pos = start
18
+ if line.parts[pos].name == :SEMIC
19
+ commapos = start - 1
20
+ commapos -= 1 while [:RETURN, :BLANK].include?(line.parts[commapos])
21
+ line.parts.delete_at(commapos)
22
+ end
23
+
24
+ line.append(line.position, ensure_param)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,18 @@
1
+ module Puppet::Cleaner
2
+ class MultilineComments < Worker
3
+ def part_names
4
+ [:MLCOMMENT]
5
+ end
6
+
7
+ def operate(line)
8
+ pos = line.position
9
+ comments = line.current.value.split("\n")
10
+ line.remove(pos)
11
+ comments.map! do |comment|
12
+ [Part.create([:COMMENT, {:value => comment}]),
13
+ Part.create([:RETURN, {:value => "\n"}])]
14
+ end
15
+ line.insert(pos, comments.flatten)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ module Puppet::Cleaner
2
+ class OctalMode < Worker
3
+ def part_names
4
+ [:FARROW]
5
+ end
6
+
7
+ def operate(line)
8
+ prev = line.prev.name == :BLANK ? line.prev(2) : line.prev
9
+ return if prev.value != "mode"
10
+ pos = line.next.name == :BLANK ? line.position + 2 : line.position + 1
11
+ mode = line.parts[pos]
12
+
13
+ if mode.value =~ /^0?[0-7]{1,4}$/
14
+ line.parts[pos] = Part.create([:STRING, {:value => mode.value.rjust(4, "0")}])
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ module Puppet::Cleaner
2
+ class QuotedBooleans
3
+ def part_names
4
+ [:STRING]
5
+ end
6
+
7
+ def operate(line)
8
+ value = line.current.value
9
+ return if !['true', 'false'].include?(value)
10
+ line.parts.delete_at(line.position)
11
+ line.insert(line.position, [Part.create([:NAME, {:value => value}])])
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,43 @@
1
+ module Puppet::Cleaner
2
+ class SoftTabs < Worker
3
+ def initialize(tabstop = 2)
4
+ @depth = 0
5
+ @tabstop = tabstop
6
+ @resource_tab = {:size => 0, :depth => nil}
7
+ end
8
+
9
+ def part_names
10
+ [:LBRACE, :RBRACE, :LBRACK, :RBRACK, :LPAREN, :RPAREN, :COLON, :SEMIC, :RETURN]
11
+ end
12
+
13
+ def operate(line)
14
+ case line.current.name
15
+ when :LBRACE, :LBRACK, :LPAREN
16
+ @depth += 1
17
+ when :RBRACE, :RBRACK, :RPAREN
18
+ @resource_tab[:size] = 0 if line.current.name == :RBRACE && @resource_tab[:depth] == @depth
19
+ @depth -= 1
20
+ when :SEMIC
21
+ @resource_tab[:size] = 0
22
+ @resource_tab[:depth] = nil
23
+ when :COLON
24
+ pos = line.position - 1
25
+ pos -= 1 while pos >= 0 && ![:LBRACE, :RETURN].include?(line.parts[pos].name)
26
+ return if pos < 0 || line.parts[pos].name != :RETURN
27
+ pos = line.position + 1
28
+ pos += 1 while pos < line.parts.size && [:BLANK, :RETURN].include?(line.parts[pos].name)
29
+ return if pos == line.parts.size || line.parts[pos].name == :LBRACE
30
+
31
+ @resource_tab[:size] = 1
32
+ @resource_tab[:depth] = @depth
33
+ when :RETURN
34
+ return if line.last? || line.next.name == :RETURN
35
+ line.append(line.position, Part.create([:BLANK, {:value => ''}])) if line.next.name != :BLANK
36
+ n = [:RBRACE, :RBRACK, :RPAREN].include?(line.next(2).name) ? 1 : 0
37
+ @resource_tab[:size] = 0 if line.next(2).name == :RBRACE && @resource_tab[:depth] == @depth
38
+ blanks = ' '*@tabstop*(@depth - n + @resource_tab[:size])
39
+ line.next.value = blanks if line.next.value != blanks
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,47 @@
1
+ module Puppet::Cleaner
2
+ class Symlink < Worker
3
+ def part_names
4
+ [:NAME]
5
+ end
6
+
7
+ def operate(line)
8
+ return if line.current.value != 'file'
9
+ pos = line.position + 1
10
+ pos += 1 while pos < line.parts.size && [:BLANK, :RETURN, :COMMENT, :MLCOMMENT].include?(line.parts[pos].name)
11
+ return if pos >= line.parts.size || line.parts[pos].name != :LBRACE
12
+
13
+ foreach_colon(line) {|colonpos|
14
+ start, pos = get_param(line, 'ensure', colonpos)
15
+ next if start.nil?
16
+ pos -= 1 if line.parts[pos].name == :COMMA
17
+ value = line.parts[pos].value
18
+ next if [:NAME, :STRING].include?(line.parts[pos].name) && %w(present absent file directory link symlink).include?(value)
19
+ next if line.parts[pos].name == :VARIABLE
20
+ ensure_param = [ [:RETURN, {:value => "\n"}], [:NAME, {:value => "ensure"}], [:FARROW, {:value => '=>'}], [:NAME, {:value => 'link'}], [:COMMA, {:value => ","}] ].map {|e| Part.create(e) }
21
+ start += 1 while line.parts[start].name != :NAME
22
+ line.parts[start].value = 'target'
23
+ line.append(colonpos, ensure_param)
24
+ }
25
+ end
26
+
27
+ def foreach_colon(line)
28
+ pos = line.position
29
+ pos += 1 while pos < line.parts.size && line.parts[pos].name != :LBRACE
30
+ depth = 1
31
+
32
+ loop do
33
+ pos += 1
34
+ break if depth == 0 || pos >= line.parts.size
35
+ case line.parts[pos].name
36
+ when :LBRACE
37
+ depth += 1
38
+ when :RBRACE
39
+ depth -= 1
40
+ when :COLON
41
+ next if depth != 1
42
+ yield pos
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,11 @@
1
+ module Puppet::Cleaner
2
+ class TrailingWhitespace < Worker
3
+ def part_names
4
+ [:BLANK]
5
+ end
6
+
7
+ def operate(line)
8
+ line.remove(line.position) if line.next.name == :RETURN
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Puppet::Cleaner
2
+ class TrailingWhitespaceInComments < Worker
3
+ def part_names
4
+ [:COMMENT]
5
+ end
6
+
7
+ def operate(line)
8
+ line.current.value.rstrip!
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,16 @@
1
+ module Puppet::Cleaner
2
+ class UnneededQuotes < Worker
3
+ def part_names
4
+ [:VARIABLE]
5
+ end
6
+
7
+ def operate(line)
8
+ return unless line.prev.name == :DQPRE && line.next.name == :DQPOST
9
+ return unless line.prev.value.empty? && line.next.value.empty?
10
+ pos = line.position
11
+ line.remove(pos + 1)
12
+ line.remove(pos - 1)
13
+ line.back!
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,59 @@
1
+ module Puppet::Cleaner
2
+ class Worker
3
+ def part_names
4
+ raise "Must be implemented in subclass"
5
+ end
6
+
7
+ def operate
8
+ raise "Must be implemented in subclass"
9
+ end
10
+
11
+ def get_param(line, param_name, pos)
12
+ depth = 1
13
+
14
+ loop do
15
+ pos += 1
16
+ break if depth == 0 || pos >= line.parts.size
17
+ case line.parts[pos].name
18
+ when :LBRACE, :COLON
19
+ depth += 1
20
+ when :RBRACE
21
+ depth -= 1
22
+ when :SEMIC
23
+ depth -= 1
24
+ when :FARROW
25
+ next if depth != 1
26
+
27
+ parampos = pos - 1
28
+ parampos -= 1 while [:BLANK, :RETURN].include?(line.parts[parampos].name)
29
+ next unless line.parts[parampos].name == :NAME && line.parts[parampos].value == param_name
30
+ start = parampos - 1
31
+ start -= 1 while [:BLANK, :RETURN].include?(line.parts[start].name)
32
+ start += 1
33
+
34
+ loop do
35
+ pos += 1
36
+ break if depth < 0 || pos >= line.parts.size
37
+ case line.parts[pos].name
38
+ when :LBRACE
39
+ depth += 1
40
+ when :COMMA, :SEMIC, :RBRACE
41
+ depth -= 1 if line.parts[pos].name == :RBRACE
42
+ next if depth > 1
43
+ pos += 1 if line.parts[pos].name == :RBRACE && depth == 1
44
+ pos += 1 while pos < line.parts.size && ![:COMMA, :SEMIC, :RBRACE].include?(line.parts[pos].name)
45
+ break
46
+ end
47
+ end
48
+
49
+ return nil if pos >= line.parts.size
50
+ pos -= 1 unless line.parts[pos].name == :COMMA
51
+ pos -= 1 while [:BLANK, :RETURN].include?(line.parts[pos].name)
52
+
53
+ return [start, pos]
54
+ end
55
+ end
56
+ nil
57
+ end
58
+ end
59
+ end # module
@@ -0,0 +1,2 @@
1
+ workersglob = File.join(File.dirname(__FILE__), "workers", "*.rb")
2
+ Dir[workersglob].each {|worker| require worker }
@@ -0,0 +1,36 @@
1
+ require 'puppet/parser'
2
+ require 'puppet-cleaner/line'
3
+ require 'puppet-cleaner/workers'
4
+
5
+ class Puppet::Parser::Lexer
6
+ class LexingContext < Hash
7
+ def []=(key, value)
8
+ return if key == :after && value == :BLANK
9
+ super
10
+ end
11
+ end
12
+
13
+ TOKENS[:COMMENT].skip = false
14
+ TOKENS[:MLCOMMENT].skip = false
15
+ TOKENS[:RETURN].skip = false
16
+ TOKENS.add_token :BLANK, %r{[ \t\r]+} do |lexer,value|
17
+ value.gsub!(/[\t\r]/,' ')
18
+ [self, value]
19
+ end
20
+
21
+ def lexing_context
22
+ @face_lexing_context ||= LexingContext.new.merge(@lexing_context)
23
+ end
24
+
25
+ def skip; end
26
+ end
27
+
28
+ module Puppet::Cleaner
29
+ def self.open(filename)
30
+ lexer = Puppet::Parser::Lexer.new
31
+ lexer.file = filename
32
+ tokens = lexer.fullscan
33
+ lexer.clear
34
+ Line.new(tokens[0..-2])
35
+ end
36
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: puppet-cleaner
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Gerardo Santana Gomez Garrido
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2013-04-18 00:00:00 Z
19
+ dependencies: []
20
+
21
+ description: Cleans puppet source code
22
+ email: gerardo.santana@gmail.com
23
+ executables:
24
+ - puppet-diff
25
+ - puppet-inspect
26
+ - puppet-clean
27
+ extensions: []
28
+
29
+ extra_rdoc_files: []
30
+
31
+ files:
32
+ - lib/puppet-cleaner.rb
33
+ - lib/puppet-cleaner/parts.rb
34
+ - lib/puppet-cleaner/line.rb
35
+ - lib/puppet-cleaner/inspect.rb
36
+ - lib/puppet-cleaner/workers.rb
37
+ - lib/puppet-cleaner/workers/quotedbooleans.rb
38
+ - lib/puppet-cleaner/workers/worker.rb
39
+ - lib/puppet-cleaner/workers/unneededquotes.rb
40
+ - lib/puppet-cleaner/workers/multilinecomments.rb
41
+ - lib/puppet-cleaner/workers/trailingwhitespaceincomments.rb
42
+ - lib/puppet-cleaner/workers/trailingwhitespace.rb
43
+ - lib/puppet-cleaner/workers/symlink.rb
44
+ - lib/puppet-cleaner/workers/alignfarrow.rb
45
+ - lib/puppet-cleaner/workers/ensurefirst.rb
46
+ - lib/puppet-cleaner/workers/octalmode.rb
47
+ - lib/puppet-cleaner/workers/softtabs.rb
48
+ - COPYRIGHT
49
+ - Changelog
50
+ - README.md
51
+ - bin/puppet-diff
52
+ - bin/puppet-inspect
53
+ - bin/puppet-clean
54
+ homepage: http://puppet-cleaner.rubyforge.org/
55
+ licenses: []
56
+
57
+ post_install_message:
58
+ rdoc_options: []
59
+
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ hash: 3
68
+ segments:
69
+ - 0
70
+ version: "0"
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ hash: 3
77
+ segments:
78
+ - 0
79
+ version: "0"
80
+ requirements: []
81
+
82
+ rubyforge_project: puppet-cleaner
83
+ rubygems_version: 1.8.15
84
+ signing_key:
85
+ specification_version: 3
86
+ summary: Puppet Source Code Cleaner
87
+ test_files: []
88
+