puppet-cleaner 0.1.0

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.
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
+