ios_parser 0.5.1-java

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,24 @@
1
+ banner exec ^C
2
+
3
+ / /
4
+ (\/_//`)
5
+ / '/
6
+ 0 0 \
7
+ / \
8
+ / __/ \
9
+ /, _/ \ \_
10
+ `-./ ) | ~^~^~^~^~^~^~^~\~.
11
+ ( / \_}
12
+ | / |
13
+ ; | \ /
14
+ \/ ,/ \ |
15
+ / /~~|~|~~~~~~|~|\ |
16
+ / / | | | | `\ \
17
+ / / | | | | \ \
18
+ / ( | | | | \ \
19
+ jgs /,_) /__) /__) /,_/
20
+ '''''"""""'''""""""'''""""""''"""""'''''
21
+
22
+ Welcome to the Goat Rodeo!!
23
+
24
+ ^C
@@ -0,0 +1,25 @@
1
+ $LOAD_PATH.unshift File.expand_path('lib', __dir__)
2
+ require 'ios_parser/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'ios_parser'
6
+ s.version = IOSParser.version
7
+ s.summary = 'convert network switch and router config files to '\
8
+ 'structured data'
9
+ s.authors = ['Ben Miller']
10
+ s.email = 'bjmllr@gmail.com'
11
+ s.homepage = 'https://github.com/bjmllr/ios_parser'
12
+ s.license = 'GPL-3.0'
13
+ s.files = `git ls-files`.split("\n")
14
+ s.test_files = `git ls-files -- {spec,features}/*`.split("\n")
15
+
16
+ if RUBY_PLATFORM == 'java'
17
+ s.platform = 'java'
18
+ else
19
+ s.extensions << 'ext/ios_parser/c_lexer/extconf.rb'
20
+ end
21
+
22
+ s.add_development_dependency 'rake-compiler', '~>0.9'
23
+ s.add_development_dependency 'rspec', '~>3.2'
24
+ s.add_development_dependency 'rubocop', '~> 0.54' if RUBY_VERSION > '2.1'
25
+ end
@@ -0,0 +1,91 @@
1
+ require 'json'
2
+ require_relative 'queryable'
3
+
4
+ module IOSParser
5
+ class IOS
6
+ class Command
7
+ include Enumerable
8
+ include Queryable
9
+ attr_accessor :args, :commands, :parent, :pos, :document
10
+
11
+ def initialize(args: [], commands: [],
12
+ parent: nil, pos: nil, document: nil)
13
+ @args = args
14
+ @commands = commands
15
+ @parent = parent
16
+ @pos = pos
17
+ @document = document
18
+ end
19
+
20
+ def name
21
+ args[0]
22
+ end
23
+
24
+ def ==(other)
25
+ args == other.args && commands == other.commands
26
+ end
27
+
28
+ def eql?(other)
29
+ self == other && self.class == other.class
30
+ end
31
+
32
+ def line
33
+ args.join(' ')
34
+ end
35
+
36
+ def path
37
+ parent ? parent.path + [parent.line] : []
38
+ end
39
+
40
+ def indentation(base: 0)
41
+ ' ' * (path.length - base)
42
+ end
43
+
44
+ def each
45
+ yield self
46
+ commands.each { |command| command.each { |cmd| yield cmd } }
47
+ end
48
+
49
+ def inspect
50
+ "<IOSParser::IOS::Command:0x#{object_id.to_s(16)} "\
51
+ "@args=#{args.inspect}, "\
52
+ "@commands=#{commands.inspect}, "\
53
+ "@pos=#{pos.inspect}, "\
54
+ "@document=<IOSParser::IOS::Document:0x#{document.object_id.to_s(16)}>>"
55
+ end
56
+
57
+ def to_s(dedent: false)
58
+ indent_opts = { base: dedent ? path.length : 0 }
59
+ map { |cmd| "#{cmd.indentation(indent_opts)}#{cmd.line}\n" }.join
60
+ end
61
+
62
+ def to_hash
63
+ {
64
+ args: args,
65
+ commands: commands.map(&:to_hash),
66
+ pos: pos
67
+ }
68
+ end
69
+
70
+ def to_json
71
+ JSON.dump(to_hash)
72
+ end
73
+
74
+ class << self
75
+ def from_hash(hash, parent = nil)
76
+ hash[:parent] = parent
77
+ [:args, :commands, :pos].each do |key|
78
+ val = hash.delete(key.to_s)
79
+ hash[key] ||= val
80
+ end
81
+
82
+ hash[:commands] ||= []
83
+ hash[:commands].each_index do |i|
84
+ hash[:commands][i] = from_hash(hash[:commands][i])
85
+ end
86
+ new(hash)
87
+ end
88
+ end
89
+ end # class Command
90
+ end # class IOS
91
+ end # module IOSParser
@@ -0,0 +1,54 @@
1
+ require 'json'
2
+ require_relative 'queryable'
3
+ require_relative 'command'
4
+
5
+ module IOSParser
6
+ class IOS
7
+ class Document
8
+ include Enumerable
9
+ include Queryable
10
+ attr_accessor :commands, :parent, :source
11
+
12
+ def initialize(source)
13
+ @commands = []
14
+ @parent = nil
15
+ @source = source
16
+ end
17
+
18
+ [:[], :push].each do |method|
19
+ define_method(method) { |*args| commands.send(method, *args) }
20
+ end
21
+
22
+ def each
23
+ commands.each { |command| command.each { |cmd| yield cmd } }
24
+ end
25
+
26
+ def to_s(dedent: false)
27
+ base = dedent ? indentation : 0
28
+ map { |cmd| "#{cmd.indentation(base: base)}#{cmd.line}\n" }.join
29
+ end
30
+
31
+ def to_hash
32
+ { commands: commands.map(&:to_hash) }
33
+ end
34
+
35
+ def to_json
36
+ JSON.dump(to_hash)
37
+ end
38
+
39
+ class << self
40
+ def from_hash(hash)
41
+ hash[:parent] = parent
42
+ [:commands, :source].each do |key|
43
+ val = hash.delete(key.to_s)
44
+ hash[key] = val unless hash.key?(key)
45
+ end
46
+
47
+ new(source).tap do |doc|
48
+ doc.push(*(hash[:commands].map { |c| Command.from_hash(c) }))
49
+ end
50
+ end
51
+ end # class << self
52
+ end # class Document
53
+ end # class IOS
54
+ end # class IOSParser
@@ -0,0 +1,219 @@
1
+ module IOSParser
2
+ class IOS
3
+ module Queryable
4
+ def find_all(expr, &blk)
5
+ _find_all(MatcherReader.query_expression(expr), &blk)
6
+ end
7
+
8
+ def find(expr, &blk)
9
+ _find(MatcherReader.query_expression(expr), &blk)
10
+ end
11
+
12
+ def _find_all(expr, &blk)
13
+ [].tap do |ret|
14
+ commands.each do |command|
15
+ if match_expr(expr, command)
16
+ ret << command
17
+ yield(command) if blk
18
+ end
19
+
20
+ ret.push(*command._find_all(expr, &blk))
21
+ end
22
+ end
23
+ end
24
+
25
+ def match_expr(expr, command)
26
+ expr.each_pair.all? { |pred, arg| Matcher.send(pred, arg, command) }
27
+ end
28
+
29
+ def _find(expr, &blk)
30
+ _find_all(expr) do |command|
31
+ yield(command) if blk
32
+ return command
33
+ end
34
+ nil
35
+ end
36
+
37
+ module MatcherReader
38
+ class << self
39
+ def query_expression(raw)
40
+ case raw
41
+ when Hash then query_expression_hash(raw)
42
+ when Proc then { procedure: procedure(raw) }
43
+ when Regexp then { line: line(raw) }
44
+ when String, Array then { starts_with: starts_with(raw) }
45
+ else raise("Invalid query: #{raw.inspect}")
46
+ end
47
+ end
48
+ alias parent query_expression
49
+ alias any_child query_expression
50
+ alias no_child query_expression
51
+
52
+ def query_expression_hash(original)
53
+ raw = original.dup
54
+ raw.each_pair { |pred, arg| raw[pred] &&= send(pred, arg) }
55
+ raw
56
+ end
57
+
58
+ def name(expr)
59
+ expr
60
+ end
61
+
62
+ def starts_with(expr)
63
+ case expr
64
+ when String then expr.split
65
+ when Array then expr
66
+ else raise("Invalid #{__method__} condition in query: #{expr}")
67
+ end
68
+ end
69
+ alias contains starts_with
70
+ alias ends_with starts_with
71
+
72
+ def procedure(expr)
73
+ unless expr.respond_to?(:call)
74
+ raise("Invalid procedure in query: #{expr}")
75
+ end
76
+ expr
77
+ end
78
+
79
+ def line(expr)
80
+ case expr
81
+ when String, Regexp then expr
82
+ when Array then expr.join(' ')
83
+ else raise("Invalid line condition in query: #{expr}")
84
+ end
85
+ end
86
+
87
+ def array_wrap_and_map(expr)
88
+ (expr.respond_to?(:map) && !expr.is_a?(Hash) ? expr : [expr])
89
+ .map { |e| query_expression(e) }
90
+ end
91
+ alias any array_wrap_and_map
92
+ alias all array_wrap_and_map
93
+ alias none array_wrap_and_map
94
+ alias not array_wrap_and_map
95
+ alias not_all array_wrap_and_map
96
+
97
+ def depth(expr)
98
+ unless expr.is_a?(Integer) || (expr.is_a?(Range) &&
99
+ expr.first.is_a?(Integer) &&
100
+ expr.last.is_a?(Integer))
101
+ raise("Invalid depth constraint in query: #{expr}")
102
+ end
103
+ expr
104
+ end
105
+ end # class << self
106
+ end # module MatcherReader
107
+
108
+ module Matcher
109
+ class << self
110
+ def name(expr, command)
111
+ expr === command.name
112
+ end
113
+
114
+ def starts_with(req_ary, command)
115
+ (0..req_ary.length - 1).all? do |i|
116
+ compare_string_or_case(req_ary[i], command.args[i])
117
+ end
118
+ end
119
+
120
+ def contains(req_ary, command)
121
+ (0..command.args.length - req_ary.length).any? do |j|
122
+ (0..req_ary.length - 1).all? do |i|
123
+ compare_string_or_case(req_ary[i], command.args[i + j])
124
+ end
125
+ end
126
+ end
127
+
128
+ def ends_with(req_ary, command)
129
+ (1..req_ary.length).all? do |i|
130
+ compare_string_or_case(req_ary[-i], command.args[-1])
131
+ end
132
+ end
133
+
134
+ def compare_string_or_case(a_object, b_object)
135
+ case a_object
136
+ when String
137
+ a_object == b_object.to_s
138
+ else
139
+ a_object === b_object
140
+ end
141
+ end
142
+
143
+ def procedure(expr, command)
144
+ expr.call(command)
145
+ end
146
+
147
+ def line(expr, command)
148
+ expr === command.line
149
+ end
150
+
151
+ def parent(expr, command)
152
+ expr.each_pair.all? do |pred, arg|
153
+ command.parent && send(pred, arg, command.parent)
154
+ end
155
+ end
156
+
157
+ def any_child(expr, command)
158
+ command.find(expr)
159
+ end
160
+
161
+ def no_child(expr, command)
162
+ !command.find(expr)
163
+ end
164
+
165
+ def any(expressions, command)
166
+ expressions.any? do |expr|
167
+ expr.each_pair.any? do |pred, arg|
168
+ send(pred, arg, command)
169
+ end
170
+ end
171
+ end
172
+
173
+ def all(expressions, command)
174
+ expressions.all? do |expr|
175
+ expr.each_pair.all? do |pred, arg|
176
+ send(pred, arg, command)
177
+ end
178
+ end
179
+ end
180
+
181
+ def not_all(expressions, command)
182
+ !expressions.all? { |expr| all([expr], command) }
183
+ end
184
+ alias not not_all
185
+
186
+ def none(expressions, command)
187
+ expressions.none? { |expr| all([expr], command) }
188
+ end
189
+
190
+ def depth(expr, command)
191
+ case expr
192
+ when Integer then depth_exact(expr, command)
193
+ when Range then depth_range(expr, command)
194
+ end
195
+ end
196
+
197
+ def depth_exact(expr, command)
198
+ _depth(expr, command) == expr
199
+ end
200
+
201
+ def depth_range(expr, command)
202
+ _depth(expr.last, command) > expr.first
203
+ end
204
+
205
+ def _depth(max, command)
206
+ level = 0
207
+ ptr = command
208
+ while ptr.parent
209
+ ptr = ptr.parent
210
+ level += 1
211
+ return Float::MIN if level > max
212
+ end
213
+ level
214
+ end
215
+ end # class << self
216
+ end # module Matcher
217
+ end # module Queryable
218
+ end # class IOS
219
+ end # module IOSParser
@@ -0,0 +1,73 @@
1
+ require_relative 'ios/document'
2
+
3
+ module IOSParser
4
+ class IOS
5
+ attr_accessor :document
6
+ attr_accessor :lexer
7
+ attr_accessor :source
8
+ attr_writer :tokens
9
+
10
+ def initialize(parent: nil, lexer: IOSParser::Lexer.new)
11
+ @document = Document.new(nil)
12
+ @parent = parent
13
+ @lexer = lexer
14
+ end
15
+
16
+ def tokens
17
+ @tokens ||= lexer.call(@source)
18
+ end
19
+
20
+ def call(source)
21
+ unless source.respond_to? :each_char
22
+ raise ArgumentError, 'Provided configuration source is invalid.'
23
+ end
24
+ @source = source
25
+ @document.source = source
26
+ @document.push(*section) until tokens.empty?
27
+ @document
28
+ end
29
+
30
+ def section(parent = nil)
31
+ [].tap do |commands|
32
+ until tokens.empty? || tokens.first.last == :DEDENT
33
+ commands.push(command(parent, @document))
34
+ end
35
+ tokens.shift # discard :DEDENT
36
+ end
37
+ end
38
+
39
+ def command(parent = nil, document = nil)
40
+ pos = tokens.first.first
41
+ opts = { args: arguments, parent: parent, document: document, pos: pos }
42
+
43
+ Command.new(opts).tap do |cmd|
44
+ cmd.commands = subsections(cmd)
45
+ end
46
+ end
47
+
48
+ def arguments_to_discard
49
+ [:INDENT, :DEDENT,
50
+ :CERTIFICATE_BEGIN, :CERTIFICATE_END,
51
+ :BANNER_BEGIN, :BANNER_END]
52
+ end
53
+
54
+ def arguments
55
+ [].tap do |args|
56
+ until tokens.empty? || tokens.first.last == :EOL
57
+ _, arg = tokens.shift
58
+ args << arg unless arguments_to_discard.include?(arg)
59
+ end
60
+ tokens.shift # discard :EOL
61
+ end
62
+ end
63
+
64
+ def subsections(parent = nil)
65
+ if !tokens.empty? && tokens.first.last == :INDENT
66
+ tokens.shift # discard :INDENT
67
+ section(parent)
68
+ else
69
+ []
70
+ end
71
+ end
72
+ end
73
+ end