junoser 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.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +69 -0
- data/Rakefile +37 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/example/vsrx-12.1.x47.rb +38421 -0
- data/exe/junoser +51 -0
- data/junoser.gemspec +27 -0
- data/lib/junoser/cli.rb +55 -0
- data/lib/junoser/development.rb +2 -0
- data/lib/junoser/display/base.rb +40 -0
- data/lib/junoser/display/config_store.rb +52 -0
- data/lib/junoser/display/set.rb +82 -0
- data/lib/junoser/display/structure.rb +29 -0
- data/lib/junoser/display.rb +16 -0
- data/lib/junoser/parser.rb +38453 -0
- data/lib/junoser/ruler.rb +173 -0
- data/lib/junoser/transformer.rb +41 -0
- data/lib/junoser/version.rb +3 -0
- data/lib/junoser/xsd/base.rb +54 -0
- data/lib/junoser/xsd/choice.rb +33 -0
- data/lib/junoser/xsd/complex_type.rb +74 -0
- data/lib/junoser/xsd/element.rb +100 -0
- data/lib/junoser/xsd/enumeration.rb +30 -0
- data/lib/junoser/xsd/parsable.rb +33 -0
- data/lib/junoser/xsd/restriction.rb +34 -0
- data/lib/junoser/xsd/sequence.rb +39 -0
- data/lib/junoser/xsd/simple_content.rb +31 -0
- data/lib/junoser.rb +3 -0
- metadata +146 -0
data/exe/junoser
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'pathname'
|
5
|
+
|
6
|
+
$: << File.expand_path('../../lib', Pathname.new(__FILE__).realpath)
|
7
|
+
|
8
|
+
require 'junoser/cli'
|
9
|
+
|
10
|
+
|
11
|
+
command = nil
|
12
|
+
opts = OptionParser.new do |opts|
|
13
|
+
opts.banner = 'junoser: an juniper configuration parser'
|
14
|
+
opts.define_head 'Usage: junoser [options] [path]'
|
15
|
+
opts.separator ''
|
16
|
+
opts.separator 'Options:'
|
17
|
+
|
18
|
+
opts.on '-c', '--check', 'Verify syntax' do
|
19
|
+
command = :check
|
20
|
+
end
|
21
|
+
|
22
|
+
opts.on '-d', '--display-set', 'Translate to "display set" form' do
|
23
|
+
command = :display_set
|
24
|
+
end
|
25
|
+
|
26
|
+
opts.on '-s', '--structured', 'Translate to structured form' do
|
27
|
+
command = :struct
|
28
|
+
end
|
29
|
+
|
30
|
+
opts.on_tail '-h', '--help', 'Show this message' do
|
31
|
+
puts opts
|
32
|
+
exit
|
33
|
+
end
|
34
|
+
|
35
|
+
opts.on_tail '-v', '--version', 'Show version' do
|
36
|
+
puts Junoser::VERSION
|
37
|
+
end
|
38
|
+
end
|
39
|
+
opts.parse!
|
40
|
+
|
41
|
+
case command
|
42
|
+
when :check
|
43
|
+
Junoser::Cli.commit_check $<
|
44
|
+
when :display_set
|
45
|
+
Junoser::Cli.display_set $<
|
46
|
+
when :struct
|
47
|
+
Junoser::Cli.struct $<
|
48
|
+
else
|
49
|
+
puts opts
|
50
|
+
abort
|
51
|
+
end
|
data/junoser.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'junoser/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "junoser"
|
8
|
+
spec.version = Junoser::VERSION
|
9
|
+
spec.authors = ["Shintaro Kojima"]
|
10
|
+
spec.email = ["goodies@codeout.net"]
|
11
|
+
|
12
|
+
spec.summary = %q{PEG parser for JUNOS configuration.}
|
13
|
+
spec.description = %q{PEG parser to vefiry and translate into different formats for JUNOS configuration.}
|
14
|
+
spec.homepage = "https://github.com/codeout/sakura-cli"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.bindir = "exe"
|
18
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "parslet"
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.9"
|
24
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
25
|
+
spec.add_development_dependency "activesupport"
|
26
|
+
spec.add_development_dependency "nokogiri"
|
27
|
+
end
|
data/lib/junoser/cli.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'parslet'
|
2
|
+
require 'junoser/display'
|
3
|
+
require 'junoser/parser'
|
4
|
+
|
5
|
+
|
6
|
+
module Junoser
|
7
|
+
module Cli
|
8
|
+
class << self
|
9
|
+
def commit_check(io_or_string)
|
10
|
+
config = if io_or_string.respond_to?(:read)
|
11
|
+
$<.read
|
12
|
+
else
|
13
|
+
io_or_string.to_s
|
14
|
+
end
|
15
|
+
|
16
|
+
if Junoser::Display.display_set?(config)
|
17
|
+
commit_check_display_set config
|
18
|
+
else
|
19
|
+
commit_check_structured config
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def display_set(io_or_string)
|
24
|
+
Junoser::Display::Set.new(io_or_string).transform
|
25
|
+
end
|
26
|
+
|
27
|
+
def struct(io_or_string)
|
28
|
+
Junoser::Display::Structure.new(io_or_string).transform
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def commit_check_structured(config)
|
35
|
+
Junoser::Display::Set.new(config).commit_check
|
36
|
+
end
|
37
|
+
|
38
|
+
def commit_check_display_set(config)
|
39
|
+
parser = Junoser::Parser.new
|
40
|
+
failed = false
|
41
|
+
|
42
|
+
config.split("\n").each do |line|
|
43
|
+
begin
|
44
|
+
parser.parse line
|
45
|
+
rescue Parslet::ParseFailed
|
46
|
+
$stderr.puts "Invalid syntax: #{line}"
|
47
|
+
failed = true
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
abort if failed
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Junoser
|
2
|
+
module Display
|
3
|
+
module Base
|
4
|
+
attr_accessor :output
|
5
|
+
|
6
|
+
def initialize(io_or_string)
|
7
|
+
@input = io_or_string
|
8
|
+
@output = $stdout
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def read_io_or_string
|
15
|
+
return @read_io_or_string if @read_io_or_string
|
16
|
+
|
17
|
+
config = if @input.respond_to?(:read)
|
18
|
+
@input.read
|
19
|
+
else
|
20
|
+
@input.to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
@read_io_or_string = remove_blank_and_comment(config)
|
24
|
+
@read_io_or_string = unify_carriage_return(@read_io_or_string)
|
25
|
+
end
|
26
|
+
|
27
|
+
def remove_blank_and_comment(str)
|
28
|
+
str.gsub! /#.*/, ''
|
29
|
+
str.gsub! /\/\*((?!\*\/).)*\*\//m, ''
|
30
|
+
str.gsub! /\n\s*/, "\n"
|
31
|
+
str.strip
|
32
|
+
end
|
33
|
+
|
34
|
+
def unify_carriage_return(str)
|
35
|
+
str.gsub! /\r\n?/, "\n"
|
36
|
+
str
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Junoser
|
4
|
+
module Display
|
5
|
+
class ConfigStore
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
OFFSET = ' '
|
9
|
+
|
10
|
+
def initialize(depth=0)
|
11
|
+
@hash = {}
|
12
|
+
@depth = depth
|
13
|
+
end
|
14
|
+
|
15
|
+
def push(str)
|
16
|
+
store = self
|
17
|
+
|
18
|
+
join_arg(str).split("\n").each_with_index do |element, index|
|
19
|
+
store[element] ||= self.class.new(index+1)
|
20
|
+
store = store[element]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
alias << push
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
str = ''
|
27
|
+
|
28
|
+
each do |k, v|
|
29
|
+
if v.empty?
|
30
|
+
str << OFFSET*@depth << "#{k};\n"
|
31
|
+
else
|
32
|
+
str << OFFSET*@depth << "#{k} {\n"
|
33
|
+
str << v.to_s.chop << "\n"
|
34
|
+
str << OFFSET*@depth << "}\n"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
str
|
39
|
+
end
|
40
|
+
|
41
|
+
def_delegators :@hash, :[], :[]=, :each, :empty?
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def join_arg(str)
|
46
|
+
str.gsub!(/\narg\((.*)\)$/) { " #$1" }
|
47
|
+
str.gsub!(/arg\((.*)\)/) { "#$1" }
|
48
|
+
str
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'junoser/display/base'
|
2
|
+
|
3
|
+
module Junoser
|
4
|
+
module Display
|
5
|
+
class Set
|
6
|
+
include Base
|
7
|
+
|
8
|
+
def transform
|
9
|
+
process do |current_stack, str|
|
10
|
+
@output.puts transform_line(current_stack, str)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def commit_check(&block)
|
15
|
+
parser = Junoser::Parser.new
|
16
|
+
failed = false
|
17
|
+
|
18
|
+
process do |current_stack, str|
|
19
|
+
config = transform_line(current_stack, str)
|
20
|
+
|
21
|
+
begin
|
22
|
+
parser.parse config
|
23
|
+
rescue Parslet::ParseFailed
|
24
|
+
$stderr.puts "Invalid syntax:\n#{struct(current_stack.dup, str)}"
|
25
|
+
failed = true
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
abort if failed
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def process(&block)
|
36
|
+
stack = []
|
37
|
+
|
38
|
+
read_io_or_string.split("\n").each do |line|
|
39
|
+
case line
|
40
|
+
when /(.*){/
|
41
|
+
stack.push $1.strip
|
42
|
+
when '}'
|
43
|
+
stack.pop
|
44
|
+
when /((?!\[).*)\[(.*)\];/
|
45
|
+
$2.split("\s").each do |i|
|
46
|
+
yield stack, "#{$1.strip} #{i}"
|
47
|
+
end
|
48
|
+
when /(.*);/
|
49
|
+
yield stack, $1
|
50
|
+
else
|
51
|
+
raise "ERROR* unknown statement: #{line}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def transform_line(current_stack, str)
|
57
|
+
statement = if current_stack.empty?
|
58
|
+
str
|
59
|
+
else
|
60
|
+
statement = "#{current_stack.join(' ')} #{str}"
|
61
|
+
end
|
62
|
+
|
63
|
+
if statement.gsub!('inactive: ', '')
|
64
|
+
"deactivate #{statement}"
|
65
|
+
else
|
66
|
+
"set #{statement}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def struct(stack, statement, offset=2)
|
71
|
+
width = 2
|
72
|
+
if label = stack.shift
|
73
|
+
%[#{" "*offset}#{label} {
|
74
|
+
#{struct(stack, statement, width+offset)}
|
75
|
+
#{" "*offset}}]
|
76
|
+
else
|
77
|
+
%[#{" "*offset}#{statement};]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'junoser/display/config_store'
|
2
|
+
require 'junoser/parser'
|
3
|
+
require 'junoser/transformer'
|
4
|
+
|
5
|
+
module Junoser
|
6
|
+
module Display
|
7
|
+
class Structure
|
8
|
+
include Base
|
9
|
+
|
10
|
+
def initialize(io_or_string)
|
11
|
+
super
|
12
|
+
@config = Junoser::Display::ConfigStore.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def transform
|
16
|
+
parser = Junoser::Parser.new
|
17
|
+
transform = Junoser::Transformer.new
|
18
|
+
|
19
|
+
read_io_or_string.split("\n").each do |line|
|
20
|
+
transformed = transform.apply(parser.parse(line))
|
21
|
+
raise "ERROR: parse failed" unless transformed.is_a?(String)
|
22
|
+
@config << transformed
|
23
|
+
end
|
24
|
+
|
25
|
+
@output.puts @config.to_s
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'junoser/display/set'
|
2
|
+
require 'junoser/display/structure'
|
3
|
+
|
4
|
+
module Junoser
|
5
|
+
module Display
|
6
|
+
class << self
|
7
|
+
def display_set?(str)
|
8
|
+
str =~ /\Aset|deactivate/
|
9
|
+
end
|
10
|
+
|
11
|
+
def structured?(str)
|
12
|
+
!display_set?(str)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|