arc_weld 0.2.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +3 -0
- data/Guardfile +58 -0
- data/LICENSE.txt +674 -0
- data/README.md +73 -0
- data/Rakefile +6 -0
- data/arc_weld.gemspec +34 -0
- data/bin/setup +7 -0
- data/bin/weld +8 -0
- data/lib/arc_weld/archive.rb +87 -0
- data/lib/arc_weld/cli/project.rb +116 -0
- data/lib/arc_weld/cli/readers/relation_csv.rb +41 -0
- data/lib/arc_weld/cli/readers/resource_csv.rb +64 -0
- data/lib/arc_weld/cli.rb +45 -0
- data/lib/arc_weld/helpers.rb +12 -0
- data/lib/arc_weld/reference.rb +51 -0
- data/lib/arc_weld/relationship.rb +96 -0
- data/lib/arc_weld/relationships/customer_of.rb +28 -0
- data/lib/arc_weld/relationships/has_alternate_interface.rb +27 -0
- data/lib/arc_weld/relationships/has_child.rb +42 -0
- data/lib/arc_weld/relationships/has_customer.rb +28 -0
- data/lib/arc_weld/relationships/has_location.rb +16 -0
- data/lib/arc_weld/relationships/in_category.rb +26 -0
- data/lib/arc_weld/relationships/in_network.rb +26 -0
- data/lib/arc_weld/relationships/in_zone.rb +41 -0
- data/lib/arc_weld/relationships/location_of.rb +28 -0
- data/lib/arc_weld/resource.rb +149 -0
- data/lib/arc_weld/resource_definitions.rb +7 -0
- data/lib/arc_weld/resources/asset.rb +33 -0
- data/lib/arc_weld/resources/asset_category.rb +40 -0
- data/lib/arc_weld/resources/customer.rb +16 -0
- data/lib/arc_weld/resources/group.rb +29 -0
- data/lib/arc_weld/resources/location.rb +18 -0
- data/lib/arc_weld/resources/network.rb +14 -0
- data/lib/arc_weld/resources/zone.rb +65 -0
- data/lib/arc_weld/templates/project-csv/.gitignore.tt +2 -0
- data/lib/arc_weld/templates/project-csv/Gemfile.tt +3 -0
- data/lib/arc_weld/templates/project-csv/Thorfile.tt +9 -0
- data/lib/arc_weld/templates/project-csv/in/assets.csv.tt +2 -0
- data/lib/arc_weld/templates/project-csv/in/categories.csv.tt +3 -0
- data/lib/arc_weld/templates/project-csv/in/customer_groups.csv.tt +3 -0
- data/lib/arc_weld/templates/project-csv/in/customers.csv.tt +3 -0
- data/lib/arc_weld/templates/project-csv/in/group_categories.csv.tt +3 -0
- data/lib/arc_weld/templates/project-csv/in/locations.csv.tt +6 -0
- data/lib/arc_weld/templates/project-csv/in/networks.csv.tt +3 -0
- data/lib/arc_weld/templates/project-csv/in/zone_locations.csv.tt +2 -0
- data/lib/arc_weld/templates/project-csv/in/zones.csv.tt +2 -0
- data/lib/arc_weld/templates/project-csv/lib/thor/README.txt.tt +2 -0
- data/lib/arc_weld/templates/project-csv/lib/thor/sample.thor.tt +7 -0
- data/lib/arc_weld/templates/project-csv/out/README-archive.txt.tt +5 -0
- data/lib/arc_weld/templates/project-csv/weld.json.tt +39 -0
- data/lib/arc_weld/version.rb +3 -0
- data/lib/arc_weld.rb +19 -0
- metadata +269 -0
data/README.md
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
# ArcWeld
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.org/ryanbreed/arc_weld.svg?branch=master)](https://travis-ci.org/ryanbreed/arc_weld)
|
4
|
+
|
5
|
+
Toolkit for generating ArcSight resources. Useful for fine-grained control
|
6
|
+
over the asset model. Currently supports generating the following resource
|
7
|
+
types:
|
8
|
+
|
9
|
+
- Asset
|
10
|
+
- AssetCategory
|
11
|
+
- Customer
|
12
|
+
- Location
|
13
|
+
- Network
|
14
|
+
- Zone
|
15
|
+
- Groups of the above resources
|
16
|
+
|
17
|
+
Basic support classes included for building resource XML archives and reading
|
18
|
+
resources from CSV files. You can also model supported relationships between
|
19
|
+
the resources using the relationship extension modules. This lets you do things
|
20
|
+
like add a location to zones, add a network to a customer, categorize resources,
|
21
|
+
etc.
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
## **WARNING**
|
26
|
+
|
27
|
+
You will completely trash your ESM if you do not understand *exactly* what
|
28
|
+
you are getting into with the archive tool. There's many reasons why not much
|
29
|
+
documentation exists on the subject. `$MANAGER_HOME/bin/arcsight archive -h`
|
30
|
+
to get started on that journey. Also, there is no guarantee that HP will
|
31
|
+
even continue to expose the archive tool interface. It could be deprecated
|
32
|
+
at any time in any release with no notice.
|
33
|
+
|
34
|
+
## Installation
|
35
|
+
|
36
|
+
Add this line to your application's Gemfile:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
gem 'arc_weld'
|
40
|
+
```
|
41
|
+
|
42
|
+
And then execute:
|
43
|
+
|
44
|
+
$ bundle
|
45
|
+
|
46
|
+
Or install it yourself as:
|
47
|
+
|
48
|
+
$ gem install arc_weld
|
49
|
+
|
50
|
+
## Usage
|
51
|
+
|
52
|
+
So far, the spec files contain the most complete description of how to use the
|
53
|
+
resource classes and relationship modules. There is a basic cli tool for
|
54
|
+
creating a csv-based model project and using that to generate the model xml.
|
55
|
+
Bear in mind that you can always break up a modeling effort into multiple smaller
|
56
|
+
projects and merge them in the target ESM if that makes more sense.
|
57
|
+
|
58
|
+
`ArcWeld::Resource` and `ArcWeld::Relationship` define the core DSL for describing
|
59
|
+
resources and relationships. The code for the resources and relationships themselves
|
60
|
+
are defined under `lib/arc_weld/resources` and `lib/arc_weld/relationships`.
|
61
|
+
|
62
|
+
Be advised - this is also an experiment for me, so some things could be better
|
63
|
+
organized. This will happen before I cut a 1.0.0.
|
64
|
+
|
65
|
+
## Licensed under GPLv3
|
66
|
+
|
67
|
+
## Development
|
68
|
+
|
69
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
70
|
+
|
71
|
+
## Contributing
|
72
|
+
|
73
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/ryanbreed/arc_weld.
|
data/Rakefile
ADDED
data/arc_weld.gemspec
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'arc_weld/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'arc_weld'
|
8
|
+
spec.version = ArcWeld::VERSION
|
9
|
+
spec.authors = ['Ryan Breed']
|
10
|
+
spec.email = ['opensource@breed.org']
|
11
|
+
|
12
|
+
spec.summary = 'Toolkit for building ArcSight resources'
|
13
|
+
spec.description = 'Toolkit for building ArcSight resources'
|
14
|
+
spec.homepage = 'https://github.com/ryanbreed/arc_weld'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.bindir = 'bin'
|
18
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_dependency 'gyoku'
|
22
|
+
spec.add_dependency 'nokogiri'
|
23
|
+
spec.add_dependency 'thor'
|
24
|
+
|
25
|
+
spec.add_development_dependency 'pry'
|
26
|
+
spec.add_development_dependency 'pry-doc'
|
27
|
+
spec.add_development_dependency 'bundler', '~> 1.10'
|
28
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
29
|
+
spec.add_development_dependency 'rspec'
|
30
|
+
spec.add_development_dependency 'guard'
|
31
|
+
spec.add_development_dependency 'guard-rspec'
|
32
|
+
spec.add_development_dependency 'guard-bundler'
|
33
|
+
spec.add_development_dependency 'simplecov'
|
34
|
+
end
|
data/bin/setup
ADDED
data/bin/weld
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$LOAD_PATH.push(File.join(File.expand_path(File.dirname(__FILE__)), '..','lib'))
|
3
|
+
require 'arc_weld'
|
4
|
+
if Dir.exist?(local_lib=File.join(Dir.pwd,'lib'))
|
5
|
+
Dir[File.join(local_lib,'*.rb')]. each {|local_lib| require local_lib }
|
6
|
+
end
|
7
|
+
|
8
|
+
ArcWeld::WeldCli.start(ARGV)
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module ArcWeld
|
2
|
+
class Archive
|
3
|
+
attr_accessor :resources, :createTime, :dtd_location
|
4
|
+
|
5
|
+
BUILD_VERSION = '6.5.1.1952.1'
|
6
|
+
BUILD_TIME = '3-6-2015_17:2:26'
|
7
|
+
TIME_FORMAT = '%m-%d-%Y_%H:%M:%S'
|
8
|
+
|
9
|
+
PARSE_DEFAULT = Nokogiri::XML::ParseOptions::DEFAULT_XML
|
10
|
+
PARSE_VALIDATE = Nokogiri::XML::ParseOptions::DEFAULT_XML | Nokogiri::XML::ParseOptions::DTDLOAD
|
11
|
+
|
12
|
+
ARCHIVE_DTD = "../../schema/xml/archive/arcsight-archive.dtd"
|
13
|
+
|
14
|
+
def initialize(*args)
|
15
|
+
Hash[*args].each {|k,v| self.send(format('%s=',k),v)}
|
16
|
+
@resources ||= []
|
17
|
+
@createTime ||= Time.new
|
18
|
+
@dtd_location ||= ARCHIVE_DTD
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def include_list
|
23
|
+
resources.map {|g| g.ref.render }.join('')
|
24
|
+
end
|
25
|
+
|
26
|
+
def add_item(item)
|
27
|
+
resources.push(item) unless resources.include?(item)
|
28
|
+
end
|
29
|
+
|
30
|
+
def add(*items)
|
31
|
+
items.each { |item| add_item(item) }
|
32
|
+
end
|
33
|
+
|
34
|
+
def dtd(location=ARCHIVE_DTD)
|
35
|
+
format('<!DOCTYPE archive SYSTEM "%s">', dtd_location)
|
36
|
+
end
|
37
|
+
|
38
|
+
def archive_creation_parameters
|
39
|
+
acp = {
|
40
|
+
ArchiveCreationParameters: {
|
41
|
+
:action => 'insert',
|
42
|
+
'excludeReferenceIDs/' => '',
|
43
|
+
:format => 'default',
|
44
|
+
'formatRoot/' => ''
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
if resources.empty?
|
49
|
+
acp[:ArchiveCreationParameters]['include/'] = ''
|
50
|
+
else
|
51
|
+
acp[:ArchiveCreationParameters][:include] = { :list! => include_list }
|
52
|
+
end
|
53
|
+
|
54
|
+
Gyoku.xml(acp, {key_converter: :none})
|
55
|
+
end
|
56
|
+
|
57
|
+
def create_time
|
58
|
+
@createTime.strftime(TIME_FORMAT)
|
59
|
+
end
|
60
|
+
|
61
|
+
def resource_content
|
62
|
+
resources.map {|res| res.render }.join('')
|
63
|
+
end
|
64
|
+
|
65
|
+
def to_h
|
66
|
+
archive_h = {
|
67
|
+
:archive! => archive_creation_parameters + resource_content,
|
68
|
+
:attributes! => {
|
69
|
+
:archive! => {
|
70
|
+
:buildVersion => BUILD_VERSION,
|
71
|
+
:buildTime => BUILD_TIME,
|
72
|
+
:createTime => create_time
|
73
|
+
}
|
74
|
+
}
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
78
|
+
def render
|
79
|
+
Gyoku.xml(to_h, {key_converter: :none} )
|
80
|
+
end
|
81
|
+
|
82
|
+
def xml(options=PARSE_DEFAULT)
|
83
|
+
Nokogiri.XML(dtd + render, nil, 'UTF-8', options)
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module ArcWeld
|
2
|
+
module Cli
|
3
|
+
class Project
|
4
|
+
include ArcWeld::Helpers
|
5
|
+
attr_accessor :name, :input_dir, :output_dir, :resource_driver,
|
6
|
+
:resource_root, :resource_inputs, :relationships, :base_model
|
7
|
+
|
8
|
+
def initialize(config)
|
9
|
+
config.each {|k,v| self.send(format('%s=',k),v)}
|
10
|
+
self
|
11
|
+
end
|
12
|
+
|
13
|
+
def resource_class_for(resource_type)
|
14
|
+
ArcWeld.const_get(constantize(resource_type))
|
15
|
+
end
|
16
|
+
|
17
|
+
def resource_input_path(resource_type)
|
18
|
+
File.join(self.input_dir, resource_inputs.fetch(resource_type))
|
19
|
+
end
|
20
|
+
|
21
|
+
def resource_reader(resource_type)
|
22
|
+
klass = ArcWeld::Cli::ResourceReaders.const_get(constantize(resource_driver))
|
23
|
+
klass.new( path: resource_input_path(resource_type),
|
24
|
+
target_class: resource_class_for(resource_type) )
|
25
|
+
end
|
26
|
+
|
27
|
+
def reader
|
28
|
+
@readers ||= Hash[
|
29
|
+
resource_inputs.keys.map { |type| [type, resource_reader(type)]}
|
30
|
+
]
|
31
|
+
end
|
32
|
+
|
33
|
+
def resources
|
34
|
+
@resources ||= Hash.new {|h,k| h[k]=Array.new }
|
35
|
+
end
|
36
|
+
|
37
|
+
def archive_resources(resource_type)
|
38
|
+
archive.resources.select {|r| r.resource_type == constantize(resource_type)}
|
39
|
+
end
|
40
|
+
|
41
|
+
def archive
|
42
|
+
@archive ||= Archive.new
|
43
|
+
end
|
44
|
+
|
45
|
+
def load_resources
|
46
|
+
reader.each do |type, type_reader|
|
47
|
+
res=type_reader.to_a
|
48
|
+
resources[type].push(*res)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def resource_group(type)
|
53
|
+
klass = ArcWeld.const_get(constantize(type))
|
54
|
+
group_name = resource_root[type]
|
55
|
+
ArcWeld::Group.new(
|
56
|
+
name: group_name,
|
57
|
+
externalID: format('weld_%s_root', type),
|
58
|
+
description: format('ArcWeld root %s group',
|
59
|
+
constantize(type)),
|
60
|
+
containedResourceType: klass.class_id,
|
61
|
+
parent_ref: klass.toplevel
|
62
|
+
)
|
63
|
+
end
|
64
|
+
|
65
|
+
def resource_roots
|
66
|
+
@roots ||= Hash[
|
67
|
+
resource_root.map do |type, group_name|
|
68
|
+
grp = resource_group(type)
|
69
|
+
resources['group'].push(grp)
|
70
|
+
[type, grp ]
|
71
|
+
end
|
72
|
+
]
|
73
|
+
end
|
74
|
+
|
75
|
+
def zone_assets
|
76
|
+
resources['asset'].each do |asset|
|
77
|
+
asset.auto_zone(*resources['zone'])
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def assign_model_relations
|
82
|
+
relationships.each do |rel|
|
83
|
+
klass = ArcWeld::Cli::RelationReaders.const_get(constantize(rel['driver']))
|
84
|
+
rel_reader = klass.new(
|
85
|
+
path: File.join(input_dir,rel['file']),
|
86
|
+
relationship_type: rel['type'] )
|
87
|
+
sources = resources[rel_reader.src_type]
|
88
|
+
dests = resources[rel_reader.dst_type]
|
89
|
+
rel_reader.relate(sources,dests)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def assign_resource_groups
|
94
|
+
resource_roots['zone'].add_children(*resources['zone'])
|
95
|
+
|
96
|
+
zone_assets
|
97
|
+
|
98
|
+
unzoned = resources['asset'].select {|a| a.in_zone.nil?}
|
99
|
+
resource_roots['asset'].add_children(*unzoned)
|
100
|
+
|
101
|
+
%w{ network customer location asset_category }.each do |type|
|
102
|
+
resource_roots[type].add_children(*resources[type])
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def generate_archive
|
107
|
+
resource_roots
|
108
|
+
load_resources
|
109
|
+
assign_resource_groups
|
110
|
+
assign_model_relations
|
111
|
+
archive.add(*resources.values.flatten)
|
112
|
+
archive
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module ArcWeld
|
2
|
+
module Cli
|
3
|
+
module RelationReaders
|
4
|
+
class Csv
|
5
|
+
include ArcWeld::Helpers
|
6
|
+
attr_accessor :path, :relationship_type,
|
7
|
+
:src_select, :dst_select,
|
8
|
+
:src_class, :dst_class
|
9
|
+
|
10
|
+
attr_reader :csv, :keys, :src_type, :dst_type
|
11
|
+
|
12
|
+
def initialize(*args)
|
13
|
+
Hash[*args].each {|k,v| self.send(format('%s=',k),v)}
|
14
|
+
@csv = CSV.open(path)
|
15
|
+
@keys = csv.readline
|
16
|
+
@src_type, @src_select, @dst_type, @dst_select = keys.flat_map do |k|
|
17
|
+
k.split(':')
|
18
|
+
end
|
19
|
+
@src_class=ArcWeld.const_get(constantize(src_type))
|
20
|
+
@dst_class=ArcWeld.const_get(constantize(dst_type))
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
def relate(sources,destinations)
|
25
|
+
csv.each do |selected_src, selected_dst|
|
26
|
+
src_instance=sources.find {|s| s.send(src_select)==selected_src}
|
27
|
+
dst_instance=destinations.find {|s| s.send(dst_select)==selected_dst}
|
28
|
+
if (src_instance.nil? || dst_instance.nil?)
|
29
|
+
STDERR.puts format('could not %s %s/%s',
|
30
|
+
relationship_type,
|
31
|
+
selected_src,
|
32
|
+
selected_dst)
|
33
|
+
else
|
34
|
+
src_instance.send(relationship_type,dst_instance)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'csv'
|
2
|
+
|
3
|
+
module ArcWeld
|
4
|
+
module Cli
|
5
|
+
module ResourceReaders
|
6
|
+
class Csv
|
7
|
+
attr_accessor :path, :target_class, :key_proc
|
8
|
+
attr_reader :keys, :csv
|
9
|
+
DEFAULT_OPTIONS = {skip_lines: %r{\A[#;]}}
|
10
|
+
|
11
|
+
def initialize(path: nil, target_class: nil, options: DEFAULT_OPTIONS)
|
12
|
+
@path, @target_class = path, target_class
|
13
|
+
@csv = CSV.open(path, 'r', options)
|
14
|
+
@key_proc ||= {}
|
15
|
+
@keys = csv.readline.map { |k| k.to_sym }
|
16
|
+
end
|
17
|
+
|
18
|
+
def read_keys
|
19
|
+
keys - processed_keys
|
20
|
+
end
|
21
|
+
|
22
|
+
def processed_keys
|
23
|
+
key_proc.keys
|
24
|
+
end
|
25
|
+
|
26
|
+
def parse(array)
|
27
|
+
row_hash = Hash[keys.zip(array)]
|
28
|
+
instance_hash = row_hash.select {|k,v| read_keys.include?(k)}
|
29
|
+
new_instance = target_class.new(instance_hash)
|
30
|
+
|
31
|
+
if processed_keys.empty?
|
32
|
+
new_instance
|
33
|
+
else
|
34
|
+
processed_hash = row_hash.select {|k,v| read_keys.include?(k)==false }
|
35
|
+
processed_hash.each do |processed_key, processed_value|
|
36
|
+
key_proc.fetch(processed_key).call(processed_key,processed_value,new_instance)
|
37
|
+
end
|
38
|
+
new_instance
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def not_at_start_record?
|
43
|
+
(csv.lineno!=1)
|
44
|
+
end
|
45
|
+
|
46
|
+
def each(rewind: not_at_start_record?)
|
47
|
+
reset_csv if rewind
|
48
|
+
csv.each {|arr| yield parse(arr) }
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_a(rewind: not_at_start_record?)
|
52
|
+
reset_csv if rewind
|
53
|
+
csv.readlines.map {|arr| parse(arr)}
|
54
|
+
end
|
55
|
+
|
56
|
+
def reset_csv
|
57
|
+
csv.rewind
|
58
|
+
*trash = csv.readline
|
59
|
+
csv.lineno
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/arc_weld/cli.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'arc_weld'
|
2
|
+
require 'arc_weld/cli/project'
|
3
|
+
require 'arc_weld/cli/readers/relation_csv'
|
4
|
+
require 'arc_weld/cli/readers/resource_csv'
|
5
|
+
require 'openssl'
|
6
|
+
require 'json'
|
7
|
+
module ArcWeld
|
8
|
+
class WeldCli < Thor
|
9
|
+
|
10
|
+
include Thor::Actions
|
11
|
+
def self.source_root
|
12
|
+
@source_root ||= File.join( File.dirname( File.expand_path(__FILE__) ),
|
13
|
+
'templates')
|
14
|
+
end
|
15
|
+
|
16
|
+
class_option :config,
|
17
|
+
type: :string,
|
18
|
+
default: 'weld.json',
|
19
|
+
desc: 'config file'
|
20
|
+
|
21
|
+
desc 'new PROJECT_NAME', 'generate new project'
|
22
|
+
option :dir,
|
23
|
+
type: :string,
|
24
|
+
default: Dir.pwd,
|
25
|
+
desc: 'create project directory here'
|
26
|
+
option :driver,
|
27
|
+
type: :string,
|
28
|
+
default: 'csv',
|
29
|
+
desc: 'driver for reading resources and relations'
|
30
|
+
def new(name)
|
31
|
+
self.destination_root = options[:dir]
|
32
|
+
@config = options.merge(name: name)
|
33
|
+
directory(format('project-%s',options[:driver]),name)
|
34
|
+
end
|
35
|
+
|
36
|
+
desc 'generate FILENAME', 'render entire model in FILENAME'
|
37
|
+
def generate(filename='model.xml')
|
38
|
+
config = JSON.parse(File.read(options[:config]))
|
39
|
+
project = ArcWeld::Cli::Project.new(config)
|
40
|
+
outfile = File.join(project.output_dir, filename)
|
41
|
+
archive = project.generate_archive
|
42
|
+
File.open(outfile,'w') {|f| f.puts archive.xml.to_s }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module ArcWeld
|
2
|
+
module Helpers
|
3
|
+
def constantize(literal)
|
4
|
+
(literal.to_s.split(%r{[ _]}).map &:capitalize).join('')
|
5
|
+
end
|
6
|
+
|
7
|
+
def uri_join(*parts)
|
8
|
+
pieces=parts.flat_map {|p| p.to_s.gsub(%r{\A/},'').gsub(%r{/\z},'')}
|
9
|
+
format('/%s', pieces.join('/'))
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module ArcWeld
|
2
|
+
class Reference
|
3
|
+
attr_accessor :type, :uri, :id, :externalID
|
4
|
+
|
5
|
+
def initialize(*args)
|
6
|
+
Hash[*args].each {|k,v| self.send(format('%s=',k),v)}
|
7
|
+
@type ||= 'Group'
|
8
|
+
end
|
9
|
+
|
10
|
+
def ref
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
def ==(other)
|
15
|
+
[:type, :uri, :id, :externalID].all? do |attr|
|
16
|
+
self.send(attr) == other.send(attr)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def identity_hash
|
21
|
+
if identity=={}
|
22
|
+
{}
|
23
|
+
else
|
24
|
+
Hash[identity.keys.map {|k| format('@%s',k.to_s)}.zip(identity.values)]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def identity
|
29
|
+
if id!=nil
|
30
|
+
{:id => id}
|
31
|
+
elsif externalID!=nil
|
32
|
+
{:externalID => externalID}
|
33
|
+
else
|
34
|
+
{}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_h
|
39
|
+
{
|
40
|
+
'ref/' => {
|
41
|
+
:@type => type,
|
42
|
+
:@uri => uri
|
43
|
+
}.merge(identity_hash)
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
def render
|
48
|
+
Gyoku.xml(to_h, key_converter: :none)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'arc_weld/relationships/customer_of'
|
2
|
+
require 'arc_weld/relationships/location_of'
|
3
|
+
require 'arc_weld/relationships/has_alternate_interface'
|
4
|
+
require 'arc_weld/relationships/has_child'
|
5
|
+
require 'arc_weld/relationships/has_customer'
|
6
|
+
require 'arc_weld/relationships/has_location'
|
7
|
+
require 'arc_weld/relationships/in_category'
|
8
|
+
require 'arc_weld/relationships/in_network'
|
9
|
+
require 'arc_weld/relationships/in_zone'
|
10
|
+
|
11
|
+
module ArcWeld
|
12
|
+
module Relationship
|
13
|
+
|
14
|
+
def self.included(klass)
|
15
|
+
klass.class_eval '@@RELATIONSHIPS = []'
|
16
|
+
klass.class_eval do
|
17
|
+
extend ClassMethods
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
def relationship_types
|
23
|
+
self.class.class_variable_get :@@RELATIONSHIPS
|
24
|
+
end
|
25
|
+
|
26
|
+
def relationship_hash
|
27
|
+
relationship_types.reduce({}) do |memo, key|
|
28
|
+
meth = format('%s_relationship',key)
|
29
|
+
if self.send(meth).nil?
|
30
|
+
memo
|
31
|
+
else
|
32
|
+
memo.merge(self.send(meth))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
module ClassMethods
|
38
|
+
def has_relationship(*args)
|
39
|
+
#puts format('defining relationship on %s', self.name)
|
40
|
+
options=case args[-1]
|
41
|
+
when Hash
|
42
|
+
args.pop
|
43
|
+
else
|
44
|
+
Hash.new(false)
|
45
|
+
end
|
46
|
+
|
47
|
+
args.each do |sym|
|
48
|
+
register_relationship(sym,options[:multiple])
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def class_relationship_types
|
53
|
+
class_variable_get :@@RELATIONSHIPS
|
54
|
+
end
|
55
|
+
|
56
|
+
def register_relationship(name, multiple=false)
|
57
|
+
unless class_relationship_types.include?(name)
|
58
|
+
class_relationship_types << name
|
59
|
+
|
60
|
+
if ArcWeld::Relationships.const_defined? constantize(name)
|
61
|
+
self.class_eval "include ArcWeld::Relationships::#{constantize(name)}"
|
62
|
+
end
|
63
|
+
# TODO: this is a horrible mess
|
64
|
+
unless self.method_defined? name
|
65
|
+
if multiple
|
66
|
+
self.class_eval do
|
67
|
+
define_method("#{name}") do
|
68
|
+
val = self.instance_variable_get("@#{name}")
|
69
|
+
if val.nil?
|
70
|
+
self.instance_variable_set("@#{name}",[])
|
71
|
+
end
|
72
|
+
self.instance_variable_get("@#{name}")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
else
|
76
|
+
self.class_eval do
|
77
|
+
define_method("#{name}") do
|
78
|
+
self.instance_variable_get("@#{name}")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
unless self.method_defined? "#{name}="
|
84
|
+
self.class_eval do
|
85
|
+
define_method("#{name}=") do |val|
|
86
|
+
self.instance_variable_set("@#{name}",val)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module ArcWeld
|
2
|
+
module Relationships
|
3
|
+
module CustomerOf
|
4
|
+
def add_customer_resource(res)
|
5
|
+
unless customer_of.include?(res)
|
6
|
+
customer_of.push(res)
|
7
|
+
res.add_customer(self)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_customer_resources(*resources)
|
12
|
+
resources.each { |res| add_customer_resource(res) }
|
13
|
+
end
|
14
|
+
|
15
|
+
def related_customer_of_references
|
16
|
+
(customer_of.map { |resource| resource.ref.render }).join
|
17
|
+
end
|
18
|
+
|
19
|
+
def customer_of_relationship
|
20
|
+
unless customer_of.empty?
|
21
|
+
{ 'customerOf' => {
|
22
|
+
'list!' => related_customer_of_references
|
23
|
+
}}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|