junoser 0.3.9 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/junoser/ruler.rb CHANGED
@@ -46,64 +46,96 @@ module Junoser
46
46
 
47
47
  str.gsub! /"groups" \(\s*s\(\s*any\s*\)\s*\)/, 'a("groups", arg, configuration)'
48
48
 
49
- %w[as-number confederation-as metric-value limit-threshold filename filter-name class-name classifier-name link-subscription per-traffic-class-bandwidth template-name].each do |key|
50
- str.gsub! %["#{key}" arg], 'arg'
51
- end
52
-
53
49
  str.gsub! '"equal-literal"', '"="'
54
50
  str.gsub! '"plus-literal"', '"+"'
55
51
  str.gsub! '"minus-literal"', '"-"'
56
52
 
57
- str.gsub!(/\((.*) \| "name"\)/) { "(#$1 | arg)" }
58
- str.gsub! '"vlan" ("all" | "vlan-name")', '"vlan" ("all" | arg)'
59
- str.gsub!(/\((.*) \| "vlan-id"\)/) { "(#$1 | arg)" }
53
+ #
54
+ # Statements can be quoted
55
+ #
60
56
  str.gsub!(/("ssh-\S+") arg/) { "#$1 (quote | arg)" }
57
+ str.gsub! '"message" arg', '"message" (quote | arg)'
61
58
  str.gsub! '"description" arg', '"description" (quote | arg)'
62
59
  str.gsub! '"as-path-prepend" arg', '"as-path-prepend" (quote | arg)'
63
- str.gsub!(/arg \| (".*")/) { "#$1 | arg" }
64
- str.gsub! '"dhcp-service" (', '("dhcp-service" | "dhcp") ('
65
60
 
66
- str.gsub!(/"inet"(.*)"inet6"/) { %["inet6"#$1"inet"] }
67
- str.gsub!(/"icmp"(.*)"icmp6"/) { %["icmp6"#$1"icmp"] }
68
- str.gsub!(/"icmp"(.*)"icmpv6"/) { %["icmpv6"#$1"icmp"] }
69
- str.gsub!(/"http"(.*)"https"/) { %["https"#$1"http"] }
70
- str.gsub!(/"snmp"(.*)"snmptrap"/) { %["snmptrap"#$1"snmp"] }
71
- %w[ccc ethernet-over-atm tcc vpls bridge].each do |encap|
72
- str.gsub!(/"ethernet"(.*)"ethernet-#{encap}"/) { %["ethernet-#{encap}"#$1"ethernet"] }
61
+ str.gsub!(/^(\s*)"as-path" arg \(\s*c\(\s*arg/) do
62
+ format(['"as-path" arg (',
63
+ ' c(',
64
+ ' quote | arg'], $1)
73
65
  end
74
- str.gsub! '"icmp6" |', '"icmp6" | "icmpv6" |'
75
- str.gsub!(/"cspf"(.*)"cspf-link"/) { %["cspf-link"#$1"cspf"] }
76
- str.gsub!(/"route-filter" (\(\s*control_route_filter_type\s*\))/) { %["route-filter" arg #{$1}.as(:oneline)] }
77
- str.gsub!(/"source-address-filter" (\(\s*control_source_address_filter_type\s*\))/) { %["source-adress-filter" arg #{$1}.as(:oneline)] }
78
66
 
79
- %w[teardown hold-time stub].each do |key|
80
- str.gsub!(/^(\s*"#{key}" \(\s*)c\(/) { "#{$1}sc(" }
67
+ str.gsub!(/^rule\(:regular_expression\) do\s*((?!end).)*\s*end/) do
68
+ <<~EOS
69
+ rule(:regular_expression) do
70
+ (quote | arg).as(:arg)
71
+ end
72
+ EOS
81
73
  end
82
- %w[file confederation].each do |key|
83
- str.gsub!(/^(\s*"#{key}" \(\s*)c\(\s*arg,/) { "#{$1}sca(" }
74
+
75
+ str.gsub!(/^rule\(:login_user_object\) do\s*arg\.as\(:arg\) \(\s*c\(\s*"full-name" arg,/) do
76
+ <<~EOS
77
+ rule(:login_user_object) do
78
+ arg.as(:arg) (
79
+ sc(
80
+ "full-name" (quote | arg),
81
+ EOS
84
82
  end
85
- %w[exact longer orlonger].each do |key|
86
- str.gsub!(/^(\s*"#{key}") arg/) { "#{$1}" }
83
+
84
+ str.gsub!(/^(\s*)"location" arg,\s*"contact" arg,/) do
85
+ format(['"location" (quote | arg),',
86
+ '"contact" (quote | arg),'], $1)
87
87
  end
88
88
 
89
+ str.gsub!(/^(\s*)"as-path" \(\s*c\(\s*"path" arg/) do
90
+ format(['"as-path" (',
91
+ ' c(',
92
+ ' "path" (quote | arg)'], $1)
93
+ end
89
94
 
90
- str.gsub!(/^(\s*)"ieee-802.3ad" \(\s*c\(\s*"lacp" \(\s*c\(/) do
91
- format(['"802.3ad" (',
92
- ' ca(',
93
- ' "lacp" (',
94
- ' c(',
95
- ' "force-up",'], $1)
95
+ str.gsub!(/^(\s*)prefix_list_items,\s*"apply-path" arg/) do
96
+ format(['"apply-path" (quote | arg),',
97
+ 'prefix_list_items'], $1)
96
98
  end
97
- str.gsub!(/^(\s*)"as-path" arg \(\s*c\(\s*arg/) do
98
- format(['"as-path" arg (',
99
- ' c(',
100
- ' quote | arg'], $1)
99
+
100
+ #
101
+ # "arg" matches anything so move to the end
102
+ #
103
+ str.gsub!(/arg \| (".*")/) { "#$1 | arg" }
104
+ str.gsub!(/^(\s*)c\(\s*arg,$/) { "#{$1}ca(" }
105
+ str.gsub!(/(rule\(:control_route_filter_type\) do\s*)s\(\s*arg,/) { "#{$1}b(" }
106
+ str.gsub!(/(rule\(:control_source_address_filter_type\) do\s*)s\(\s*arg,/) { "#{$1}b(" }
107
+ str.gsub!(/^(rule\(:trace_file_type\) do\s*)ca\(/) { "#{$1}sca(" }
108
+
109
+ str.gsub!(/^(rule\(:archive_object\) do\s*)c\(/) { "#{$1}sc(" }
110
+ str.gsub!(/^(rule\(:server_group_type\) do\s*)c\(\s*c\(\s*arg\s*\)\s*\)/) { "#{$1}s(arg, arg)" }
111
+
112
+ str.gsub!(/^(rule\(:rib_group_inet_type\) do)\s*c\(\s*arg/) do
113
+ format([$1,
114
+ ' ca(',
115
+ ' a(arg, arg)'], '')
101
116
  end
102
- str.gsub!(/^(\s*)"priority" \(\s*c\(\s*arg,\s*arg\s*\)/) do
117
+
118
+ # Fix overkill
119
+ str.gsub!(/^(\s*)"priority" \(\s*ca\(\s*arg\s*\)/) do
103
120
  format(['"priority" (',
104
121
  ' a(arg, arg)', $1])
105
122
  end
106
- str.gsub!(/^(\s*)"path" arg \(\s*c\(\s*c\(\s*"abstract",\s*c\(\s*"loose",\s*"loose-link",\s*"strict"\s*\)\s*\)\.as\(:oneline\)/) do
123
+
124
+ #
125
+ # Longer pattern first
126
+ #
127
+ str.gsub!(/"cspf"(.*)"cspf-link"/) { %["cspf-link"#$1"cspf"] }
128
+ str.gsub!(/"http"(.*)"https"/) { %["https"#$1"http"] }
129
+ str.gsub!(/"inet"(.*)"inet6"/) { %["inet6"#$1"inet"] }
130
+ str.gsub!(/"icmp"(.*)"icmp6"/) { %["icmp6"#$1"icmp"] }
131
+ str.gsub!(/"icmp"(.*)"icmpv6"/) { %["icmpv6"#$1"icmp"] }
132
+ str.gsub!(/"snmp"(.*)"snmptrap"/) { %["snmptrap"#$1"snmp"] }
133
+
134
+ %w[ccc ethernet-over-atm tcc vpls bridge].each do |encap|
135
+ str.gsub!(/"ethernet"(.*)"ethernet-#{encap}"/) { %["ethernet-#{encap}"#$1"ethernet"] }
136
+ end
137
+
138
+ str.gsub!(/^(\s*)"path" arg \(\s*c\(\s*sc\(\s*"abstract",\s*c\(\s*"loose",\s*"loose-link",\s*"strict"\s*\)\s*\)\.as\(:oneline\)/) do
107
139
  format(['"path" arg (',
108
140
  ' c(',
109
141
  ' b(',
@@ -119,48 +151,51 @@ module Junoser
119
151
  ' )', $1])
120
152
  end
121
153
 
122
- str.gsub!(/^(\s*)c\(\s*\("default"\)\s*\)/) do
123
- format(['c(',
124
- ' ("default" | arg)',
125
- ')'], $1)
126
- end
154
+ #
155
+ # Fix .xsd: Elements without "nokeyword" flag
156
+ #
157
+ str.gsub!(/\((.*) \| "name"\)/) { "(#$1 | arg)" }
158
+ str.gsub! '"vlan" ("all" | "vlan-name")', '"vlan" ("all" | arg)'
159
+ str.gsub!(/\((.*) \| "vlan-id"\)/) { "(#$1 | arg)" }
127
160
 
128
- str.gsub!(/^rule\(:regular_expression\) do\s*((?!end).)*\s*end/) do
129
- format(['rule(:regular_expression) do',
130
- ' (quote | arg).as(:arg)',
131
- 'end'])
132
- end
133
- str.gsub!(/^rule\(:login_user_object\) do\s*arg\.as\(:arg\) \(\s*c\(\s*"full-name" arg,/) do
134
- format(['rule(:login_user_object) do',
135
- ' arg.as(:arg) (',
136
- ' sc(',
137
- ' "full-name" (quote | arg),'])
161
+ %w[filename].each do |key|
162
+ str.gsub! %["#{key}" arg], 'arg'
138
163
  end
139
164
 
140
- str.gsub!(/(rule\(:control_route_filter_type\) do\s*)s\(\s*arg,/) { "#{$1}b(" }
141
- str.gsub!(/(rule\(:control_source_address_filter_type\) do\s*)s\(\s*arg,/) { "#{$1}b(" }
142
- str.gsub!(/^(rule\(:trace_file_type\) do\s*)c\(\s*arg,/) { "#{$1}sca(" }
143
- str.gsub!(/^(rule\(:archive_object\) do\s*)c\(/) { "#{$1}sc(" }
144
- str.gsub!(/^(rule\(:server_group_type\) do\s*)c\(\s*c\(\s*arg\s*\)\s*\)/) { "#{$1}s(arg, arg)" }
145
- str.gsub!(/^(rule\(:rib_group_inet_type\) do)\s*c\(\s*arg/) do
146
- format([$1,
147
- ' ca(',
148
- ' a(arg, arg)'], '')
149
- end
165
+ # "filename" fix above leaves "arg". Move to the end
166
+ str.gsub!(/^(rule\(:esp_trace_file_type\) do\s*)c\(\s*arg,/) { "#{$1}ca(" }
150
167
 
151
- str.gsub!(/^(\s*)c\(\s*arg,$/) { "#{$1}ca(" }
168
+ # Fix .xsd: system processes dhcp is valid on some platforms
169
+ str.gsub! '"dhcp-service" (', '("dhcp-service" | "dhcp") ('
152
170
 
153
- str.gsub!(/^(\s*)"location" arg,\s*"contact" arg,/) do
154
- format(['"location" (quote | arg),',
155
- '"contact" (quote | arg),'], $1)
171
+ # Fix .xsd: "icmpv6" is also acceptable
172
+ str.gsub! '"icmp6" |', '"icmp6" | "icmpv6" |'
173
+
174
+ #
175
+ # Fix .xsd: "arg" is missing
176
+ #
177
+ str.gsub!(/"route-filter" (\(\s*control_route_filter_type\s*\))/) { %["route-filter" arg #{$1}.as(:oneline)] }
178
+ str.gsub!(/"source-address-filter" (\(\s*control_source_address_filter_type\s*\))/) { %["source-adress-filter" arg #{$1}.as(:oneline)] }
179
+ %w[file].each do |key|
180
+ str.gsub!(/^(\s*"#{key}" \(\s*)c\(\s*arg,/) { "#{$1}sca(" }
156
181
  end
157
182
 
158
- str.gsub!(/^(\s*)"as-path" \(\s*c\(\s*"path" arg/) do
159
- format(['"as-path" (',
160
- ' c(',
161
- ' "path" (quote | arg)'], $1)
183
+ # Fix .xsd: Unnecessary "arg" is added
184
+ %w[exact longer orlonger].each do |key|
185
+ str.gsub!(/^(\s*"#{key}") arg/) { "#{$1}" }
186
+ end
187
+
188
+ # Fix .xsd: "ieee-802.3ad" is invalid
189
+ str.gsub! '"ieee-802.3ad"', '"802.3ad"'
190
+
191
+ # Fix .xsd: "class-of-service interfaces all unit * classifiers exp foo"
192
+ str.gsub!(/^(\s*)sc\(\s*\("default"\)\s*\)/) do
193
+ format(['c(',
194
+ ' ("default" | arg)',
195
+ ')'], $1)
162
196
  end
163
197
 
198
+ # Fix .xsd: "from-zone" arg is also required
164
199
  str.gsub!(/^(\s*)"policy" \(\s*s\(\s*arg,\s*"to-zone-name" arg,\s*c\(\s*"policy" \(\s*policy_type\s*\)\s*\)/) do
165
200
  format(['b(s("from-zone", arg, "to-zone", arg),',
166
201
  ' b("policy", policy_type',
@@ -2,62 +2,12 @@ require 'junoser'
2
2
  require 'parslet'
3
3
 
4
4
  module Junoser
5
- class DeleteTransformer < Parslet::Transform
6
- rule(config: simple(:config)) do
7
- "(#{config.to_s} .*"
8
- end
9
-
10
- rule(config: sequence(:configs)) do
11
- configs.join("\n")
12
- end
13
-
14
- rule(arg: simple(:arg)) do
15
- arg
16
- end
17
-
18
- rule(label: simple(:label)) do
19
- ")#{Regexp.escape(label.to_s)}"
20
- end
21
-
22
- rule(label: simple(:label), child: simple(:child)) do
23
- "#{Regexp.escape(label.to_s)} #{child}"
24
- end
25
-
26
- rule(label: simple(:label), child: sequence(:children)) do
27
- %[#{Regexp.escape(label.to_s)} #{children.join(' ')}]
28
- end
29
-
30
- rule(statement: simple(:statement), argument: simple(:argument)) do
31
- "#{statement} #{argument}"
32
- end
33
-
34
- rule(statement: simple(:statement), argument: sequence(:arguments)) do
35
- %[#{statement} #{arguments.join(' ')}]
36
- end
37
-
38
- rule(oneline: simple(:str)) do
39
- str
40
- end
41
-
42
- rule(oneline: sequence(:strs)) do
43
- strs.join(' ')
44
- end
45
-
46
- rule(enum: simple(:str)) do
47
- str
48
- end
49
-
50
- rule(enum: sequence(:strs)) do
51
- strs.join(' ')
52
- end
53
- end
54
-
55
5
  class Squash
56
6
  def initialize(io_or_string)
57
7
  @input = io_or_string
58
8
  @lines = []
59
9
  @parser = Junoser::Parser.new
60
- @transformer = DeleteTransformer.new
10
+ @transformer = Junoser::Transformer.new
61
11
  end
62
12
 
63
13
  def transform
@@ -65,11 +15,16 @@ module Junoser
65
15
  config.each do |l|
66
16
  l.strip!
67
17
  case l
68
- when /^set /
69
- @lines << l
70
- when /^delete /
71
- to_delete = @parser.parse(l.gsub(/^delete /, 'set '))
72
- delete_lines @transformer.apply(to_delete)
18
+ when /^(set|deactivate) /
19
+ @lines << l
20
+ when /^delete /
21
+ delete_lines delete_pattern(l.gsub(/^delete /, 'set '))
22
+ when /^activate /
23
+ delete_lines l.gsub(/^activate /, 'deactivate ')
24
+ when /^insert (.*) before (.*)/
25
+ insert_before "set #{$1}", $2
26
+ when /^insert (.*) after (.*)/
27
+ insert_after "set #{$1}", $2
73
28
  end
74
29
  end
75
30
 
@@ -80,7 +35,7 @@ module Junoser
80
35
  private
81
36
 
82
37
  def remove_subcommand(lines)
83
- lines.each_with_index do |l,i|
38
+ lines.each_with_index do |l, i|
84
39
  lines[i..-1].each do |l2|
85
40
  if l.include?(l2) and l != l2
86
41
  lines.delete(l2)
@@ -94,5 +49,44 @@ module Junoser
94
49
  l.sub!(/#{pattern}/) { $1 }
95
50
  end
96
51
  end
52
+
53
+ def split_last_token(line)
54
+ tokens = join_arg(@transformer.apply(@parser.parse(line))).split("\n")
55
+ tokens.map! { |t|
56
+ t.gsub!(/arg\((.*)\)/) { "#$1" } # Strip arg
57
+ Regexp.escape(t.strip)
58
+ }
59
+
60
+ [tokens[0..-2].join(' '), tokens.last]
61
+ end
62
+
63
+ # Ported from lib/junoser/display/config_store.rb
64
+ def join_arg(str)
65
+ str.gsub!(/\narg\((.*)\)$/) { " #$1" }
66
+ str.gsub!(/arg\((.*)\)/) { "#$1" }
67
+ str
68
+ end
69
+
70
+ def delete_pattern(line)
71
+ line, last_token = split_last_token(line)
72
+ "(#{line}\s+)#{last_token}.*"
73
+ end
74
+
75
+ def insert_before(statement_to_insert, key_statement)
76
+ key_tokens = key_statement.strip.split
77
+ key_statement = (statement_to_insert.strip.split[0..-(key_tokens.size+1)] + key_tokens).join(' ')
78
+
79
+ lines_to_insert = @lines.select { |l| l.include?(statement_to_insert) }
80
+ @lines.reject! { |l| l.include?(statement_to_insert) }
81
+
82
+ key_index = @lines.index { |l| l.include?(key_statement) }
83
+ @lines.insert(key_index, lines_to_insert).flatten!
84
+ end
85
+
86
+ def insert_after(pattern_to_insert, key_token)
87
+ @lines.reverse!
88
+ insert_before pattern_to_insert, key_token
89
+ @lines.reverse!
90
+ end
97
91
  end
98
92
  end
@@ -1,3 +1,3 @@
1
1
  module Junoser
2
- VERSION = "0.3.9"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -1,13 +1,14 @@
1
1
  module Junoser
2
2
  module Xsd
3
3
  module Base
4
- attr_reader :xml
4
+ attr_reader :xml, :parent
5
5
 
6
6
  OFFSET = ' '
7
7
 
8
8
  def initialize(xml, options={})
9
9
  @xml = xml
10
10
  @depth = options[:depth] || 0
11
+ @parent = options[:parent]
11
12
  end
12
13
 
13
14
  def config
@@ -32,13 +33,13 @@ module Junoser
32
33
  ']>'].join("\n#{OFFSET*(@depth+1)}")
33
34
  end
34
35
 
35
-
36
- private
37
-
38
36
  def oneliner?
39
37
  @oneliner ||= !xml.xpath('./xsd:annotation/xsd:appinfo/flag[text()="oneliner"]').empty?
40
38
  end
41
39
 
40
+
41
+ private
42
+
42
43
  def nokeyword?
43
44
  @nokeyword ||= !xml.xpath('./xsd:annotation/xsd:appinfo/flag[text()="nokeyword"]').empty?
44
45
  end
@@ -10,9 +10,9 @@ module Junoser
10
10
  @config ||= children.map {|child|
11
11
  case child.name
12
12
  when 'element'
13
- Junoser::Xsd::Element.new(child, depth: @depth+1)
13
+ Junoser::Xsd::Element.new(child, depth: @depth+1, parent: self)
14
14
  when 'choice'
15
- Junoser::Xsd::Choice.new(child, depth: @depth+1)
15
+ Junoser::Xsd::Choice.new(child, depth: @depth+1, parent: self)
16
16
  else
17
17
  raise "ERROR: unknown element: #{child.name}"
18
18
  end
@@ -29,6 +29,10 @@ module Junoser
29
29
  format('c(', config.map(&:to_s).join(",\n"), ')')
30
30
  end
31
31
  end
32
+
33
+ def unbounded?
34
+ xml['maxOccurs'] == 'unbounded'
35
+ end
32
36
  end
33
37
  end
34
38
  end
@@ -18,9 +18,9 @@ module Junoser
18
18
  @config ||= children.map {|child|
19
19
  case child.name
20
20
  when 'sequence'
21
- Junoser::Xsd::Sequence.new(child, depth: @depth+1)
21
+ Junoser::Xsd::Sequence.new(child, depth: @depth+1, parent: self)
22
22
  when 'simpleContent'
23
- Junoser::Xsd::SimpleContent.new(child, depth: @depth+1)
23
+ Junoser::Xsd::SimpleContent.new(child, depth: @depth+1, parent: self)
24
24
  when 'attribute'
25
25
  'arg'
26
26
  else
@@ -52,7 +52,7 @@ module Junoser
52
52
  def argument
53
53
  return unless @argument
54
54
 
55
- arg = Junoser::Xsd::Element.new(@argument, depth: @depth+1).config
55
+ arg = Junoser::Xsd::Element.new(@argument, depth: @depth+1, parent: self).config
56
56
  raise "ERROR: argument shouldn't consist of multiple elements" if arg.size > 1
57
57
 
58
58
  if root?
@@ -16,9 +16,9 @@ module Junoser
16
16
  @config ||= children.map {|child|
17
17
  case child.name
18
18
  when 'complexType'
19
- Junoser::Xsd::ComplexType.new(child, depth: @depth+1)
19
+ Junoser::Xsd::ComplexType.new(child, depth: @depth+1, parent: self)
20
20
  when 'simpleType'
21
- Junoser::Xsd::SimpleType.new(child, depth: @depth+1)
21
+ Junoser::Xsd::SimpleType.new(child, depth: @depth+1, parent: self)
22
22
  else
23
23
  raise "ERROR: unknown element: #{child.name}"
24
24
  end
@@ -70,7 +70,7 @@ module Junoser
70
70
  when @argument.name == 'simpleType'
71
71
  'arg'
72
72
  else
73
- arg = Junoser::Xsd::Element.new(@argument, depth: @depth+1).config
73
+ arg = Junoser::Xsd::Element.new(@argument, depth: @depth+1, parent: self).config
74
74
  raise "ERROR: argument shouldn't consist of multiple elements" if arg.size > 1
75
75
  arg.first.to_s.strip
76
76
  end
@@ -97,6 +97,10 @@ module Junoser
97
97
 
98
98
  def documentation
99
99
  @documentation ||= xml.xpath('./xsd:annotation/xsd:documentation').text
100
+
101
+ # Translate multiline documentation into a single line to make it parsable in further processes
102
+ @documentation.gsub! /\n\s*/, ' '
103
+
100
104
  @documentation.empty? ? nil : @documentation
101
105
  end
102
106
  end