archimate 1.1.1 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +0 -47
- data/lib/archimate.rb +0 -11
- data/lib/archimate/cli/archi.rb +0 -8
- data/lib/archimate/data_model/diffable_array.rb +64 -64
- data/lib/archimate/version.rb +1 -1
- metadata +2 -32
- data/exe/archidiff +0 -7
- data/exe/archidiff-summary +0 -7
- data/exe/archimerge +0 -7
- data/exe/fmtxml +0 -7
- data/lib/archimate/cli/conflict_resolver.rb +0 -39
- data/lib/archimate/cli/diff.rb +0 -31
- data/lib/archimate/cli/diff_summary.rb +0 -101
- data/lib/archimate/cli/merge.rb +0 -49
- data/lib/archimate/cli/merger.rb +0 -109
- data/lib/archimate/diff.rb +0 -17
- data/lib/archimate/diff/archimate_array_reference.rb +0 -113
- data/lib/archimate/diff/archimate_identified_node_reference.rb +0 -41
- data/lib/archimate/diff/archimate_node_attribute_reference.rb +0 -70
- data/lib/archimate/diff/archimate_node_reference.rb +0 -80
- data/lib/archimate/diff/change.rb +0 -49
- data/lib/archimate/diff/conflict.rb +0 -31
- data/lib/archimate/diff/conflicts.rb +0 -89
- data/lib/archimate/diff/conflicts/base_conflict.rb +0 -53
- data/lib/archimate/diff/conflicts/deleted_items_child_updated_conflict.rb +0 -30
- data/lib/archimate/diff/conflicts/deleted_items_referenced_conflict.rb +0 -63
- data/lib/archimate/diff/conflicts/path_conflict.rb +0 -51
- data/lib/archimate/diff/delete.rb +0 -41
- data/lib/archimate/diff/difference.rb +0 -113
- data/lib/archimate/diff/insert.rb +0 -43
- data/lib/archimate/diff/merge.rb +0 -70
- data/lib/archimate/diff/move.rb +0 -51
data/lib/archimate/cli/merge.rb
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "parallel"
|
4
|
-
|
5
|
-
module Archimate
|
6
|
-
module Cli
|
7
|
-
class Merge
|
8
|
-
include Logging
|
9
|
-
|
10
|
-
attr_reader :base, :local, :remote, :merged_file
|
11
|
-
|
12
|
-
def self.merge(base_file, remote_file, local_file, merged_file)
|
13
|
-
Logging.debug { "Reading base file: #{base_file}, local file: #{local_file}, remote file: #{remote_file}" }
|
14
|
-
base, local, remote = Parallel.map([base_file, local_file, remote_file], in_processes: 3) do |file|
|
15
|
-
Archimate.read(file)
|
16
|
-
end
|
17
|
-
Logging.debug { "Merged file is #{merged_file}" }
|
18
|
-
|
19
|
-
Merge.new(base, local, remote, merged_file).run_merge
|
20
|
-
end
|
21
|
-
|
22
|
-
def initialize(base, local, remote, merged_file)
|
23
|
-
@base = base
|
24
|
-
@local = local
|
25
|
-
@remote = remote
|
26
|
-
@merged_file = merged_file
|
27
|
-
@merge = Archimate::Diff::Merge.new
|
28
|
-
end
|
29
|
-
|
30
|
-
def run_merge
|
31
|
-
debug { "Starting merging" }
|
32
|
-
merged, conflicts = @merge.three_way(base, local, remote)
|
33
|
-
# TODO: there should be no conflicts here
|
34
|
-
debug do
|
35
|
-
<<~MSG
|
36
|
-
Done merging
|
37
|
-
#{conflicts}
|
38
|
-
MSG
|
39
|
-
end
|
40
|
-
|
41
|
-
File.open(merged_file, "w") do |file|
|
42
|
-
# TODO: this should be controlled by the options and the defaulted to the read format
|
43
|
-
debug { "Serializing" }
|
44
|
-
Archimate::FileFormats::ArchiFileWriter.write(merged, file)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
data/lib/archimate/cli/merger.rb
DELETED
@@ -1,109 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Archimate
|
4
|
-
module Cli
|
5
|
-
# Merger is a class that is a decorator on Archimate::DataModel::Model
|
6
|
-
# to provide the capability to merge another model into itself
|
7
|
-
#
|
8
|
-
# TODO: provide for a conflict resolver instance
|
9
|
-
# TODO: provide an option to determine if potential matches are merged
|
10
|
-
# or if the conflict resolver should be asked.
|
11
|
-
class Merger # < SimpleDelegator
|
12
|
-
# def initialize(primary_model, conflict_resolver)
|
13
|
-
# super(primary_model)
|
14
|
-
# @resolver = conflict_resolver
|
15
|
-
# end
|
16
|
-
|
17
|
-
# What merge does:
|
18
|
-
# For all entities: (other than Model...):
|
19
|
-
# - PropertyDefinition
|
20
|
-
# - View
|
21
|
-
# - Viewpoint
|
22
|
-
# Entity:
|
23
|
-
# look for a matching entity: with result
|
24
|
-
# 1. Found a matching entity: goto entity merge
|
25
|
-
# 2. Found no matching entity, but id conflicts: gen new id, goto add entity
|
26
|
-
# 3. Found no matching entity: goto add entity
|
27
|
-
# entity merge:
|
28
|
-
# 1. merge (with func from deduper)
|
29
|
-
# add entity:
|
30
|
-
# 1. add entity to model
|
31
|
-
# add remapping entry to map from entities other model id to id in this model
|
32
|
-
# Relationship:
|
33
|
-
# def merge(other_model)
|
34
|
-
# other_model.entities.each do |entity|
|
35
|
-
# # TODO: matching entity should use the same criteria that DuplicateEntities uses.
|
36
|
-
# my_entity = find_matching_entity(entity)
|
37
|
-
# if my_entity
|
38
|
-
# end
|
39
|
-
# end
|
40
|
-
|
41
|
-
# TODO: handle inner text of elements
|
42
|
-
# TODO: handle merging by element type
|
43
|
-
|
44
|
-
def hash_to_attr(h)
|
45
|
-
h.map { |k, v| "#{k}=\"#{v}\"" }.join(" ")
|
46
|
-
end
|
47
|
-
|
48
|
-
def e_to_s(e)
|
49
|
-
"#{e.name} #{hash_to_attr(e.attributes)}"
|
50
|
-
end
|
51
|
-
|
52
|
-
# Merge node1, node2
|
53
|
-
# For node
|
54
|
-
# For each child
|
55
|
-
# If has a matching child
|
56
|
-
def merge(doc1, doc2)
|
57
|
-
doc2.children.each do |e|
|
58
|
-
next if e.name == "text" && e.text.strip.empty?
|
59
|
-
# p = e.path
|
60
|
-
# if p =~ /\[\d+\]$/
|
61
|
-
# p = p.gsub(/\[\d+\]$/, "[@name=\"#{e.attr("name")}\"]")
|
62
|
-
# end
|
63
|
-
# puts "Looking for #{p}"``
|
64
|
-
# matches = doc1.xpath(p)
|
65
|
-
css = ">#{e.name}"
|
66
|
-
# puts css
|
67
|
-
css += "[name=\"#{e.attr('name')}\"]" if e.attributes.include?("name")
|
68
|
-
css += "[xsi|type=\"#{e.attr('xsi:type')}\"]" if e.attributes.include?("xsi:type")
|
69
|
-
matches = doc1.css(css)
|
70
|
-
if !matches.empty? # We have a potential match
|
71
|
-
# puts "Match?"
|
72
|
-
# puts " Doc2: #{e_to_s(e)}"
|
73
|
-
# matches.each do |e1|
|
74
|
-
# puts " Doc1: #{e_to_s(e1)}"
|
75
|
-
# end
|
76
|
-
merge(matches[0], e) unless matches.size > 1
|
77
|
-
else # No match insert the node into the tree TODO: handle id conflicts
|
78
|
-
doc1.add_child(e)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
doc1
|
82
|
-
end
|
83
|
-
|
84
|
-
def id_hash_for(doc)
|
85
|
-
doc.css("[id]").each_with_object({}) do |obj, memo|
|
86
|
-
memo[obj["id"]] = obj
|
87
|
-
memo
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
def conflicting_ids(doc1, doc2)
|
92
|
-
doc_id_hash1 = id_hash_for(doc1)
|
93
|
-
doc_id_hash2 = id_hash_for(doc2)
|
94
|
-
cids = Set.new(doc_id_hash1.keys) & doc_id_hash2.keys
|
95
|
-
# puts "ID Conflicts:"
|
96
|
-
# puts cids.to_a.join(",")
|
97
|
-
cids
|
98
|
-
end
|
99
|
-
|
100
|
-
def merge_files(file1, file2)
|
101
|
-
doc1 = Nokogiri::XML(File.open(file1))
|
102
|
-
doc2 = Nokogiri::XML(File.open(file2))
|
103
|
-
|
104
|
-
# cids = conflicting_ids(doc1, doc2)
|
105
|
-
merge(doc1.root, doc2.root).document
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
data/lib/archimate/diff.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
module Archimate
|
3
|
-
module Diff
|
4
|
-
require 'archimate/diff/difference'
|
5
|
-
require 'archimate/diff/archimate_node_reference'
|
6
|
-
require 'archimate/diff/archimate_identified_node_reference'
|
7
|
-
require 'archimate/diff/archimate_array_reference'
|
8
|
-
require 'archimate/diff/archimate_node_attribute_reference'
|
9
|
-
require 'archimate/diff/change'
|
10
|
-
require 'archimate/diff/conflict'
|
11
|
-
require 'archimate/diff/conflicts'
|
12
|
-
require 'archimate/diff/delete'
|
13
|
-
require 'archimate/diff/insert'
|
14
|
-
require 'archimate/diff/merge'
|
15
|
-
require 'archimate/diff/move'
|
16
|
-
end
|
17
|
-
end
|
@@ -1,113 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Archimate
|
4
|
-
module Diff
|
5
|
-
class ArchimateArrayReference < ArchimateNodeReference
|
6
|
-
using DataModel::DiffableArray
|
7
|
-
using DataModel::DiffablePrimitive
|
8
|
-
|
9
|
-
attr_reader :array_index
|
10
|
-
|
11
|
-
def initialize(array, array_index)
|
12
|
-
unless array.is_a?(Array)
|
13
|
-
raise(
|
14
|
-
TypeError,
|
15
|
-
"array argument must be an Array, was #{array.class}"
|
16
|
-
)
|
17
|
-
end
|
18
|
-
unless array_index.is_a?(Integer)
|
19
|
-
raise(
|
20
|
-
TypeError,
|
21
|
-
"array_index argument must be a Integer, was #{array_index.class} #{array_index.inspect}"
|
22
|
-
)
|
23
|
-
end
|
24
|
-
unless array_index >= 0 && array_index < array.size
|
25
|
-
raise(
|
26
|
-
ArgumentError,
|
27
|
-
"array_index argument a valid index for array #{array_index.inspect}"
|
28
|
-
)
|
29
|
-
end
|
30
|
-
super(array)
|
31
|
-
@array_index = array_index
|
32
|
-
end
|
33
|
-
|
34
|
-
def value
|
35
|
-
archimate_node[array_index]
|
36
|
-
end
|
37
|
-
|
38
|
-
def to_s
|
39
|
-
value.to_s
|
40
|
-
end
|
41
|
-
|
42
|
-
def lookup_in_model(model)
|
43
|
-
result = lookup_parent_in_model(model)
|
44
|
-
raise TypeError, "result was #{result.class} expected Array" unless result.is_a?(Array)
|
45
|
-
result[array_index]
|
46
|
-
end
|
47
|
-
|
48
|
-
def path(options = {})
|
49
|
-
@array_ref_path ||= [
|
50
|
-
super,
|
51
|
-
case value
|
52
|
-
when DataModel::Referenceable
|
53
|
-
value.id
|
54
|
-
else
|
55
|
-
array_index
|
56
|
-
end
|
57
|
-
].map(&:to_s).reject(&:empty?).join("/")
|
58
|
-
end
|
59
|
-
|
60
|
-
# For inserts - we can't be sure of what is available (without an expensive sort)
|
61
|
-
# So lookup the first previous value that exists in to_model and insert it after that
|
62
|
-
# value instead of a fixed index.
|
63
|
-
def find_insert_index_in_ary(ary)
|
64
|
-
return -1 if array_index.zero?
|
65
|
-
my_idx = (array_index - 1).downto(0).find(-1) do |idx|
|
66
|
-
ary.smart_include?(archimate_node[idx])
|
67
|
-
end
|
68
|
-
ary.smart_find(archimate_node[my_idx])
|
69
|
-
end
|
70
|
-
|
71
|
-
def insert(to_model)
|
72
|
-
ary_in_model = lookup_parent_in_model(to_model)
|
73
|
-
insert_idx = find_insert_index_in_ary(ary_in_model) + 1
|
74
|
-
ary_in_model.insert(insert_idx, value)
|
75
|
-
end
|
76
|
-
|
77
|
-
def delete(to_model)
|
78
|
-
ary_in_model = lookup_parent_in_model(to_model)
|
79
|
-
if ary_in_model.nil?
|
80
|
-
$stderr.puts "lookup parent in model failed for path #{path}"
|
81
|
-
return nil
|
82
|
-
end
|
83
|
-
idx = ary_in_model.smart_find(value)
|
84
|
-
if idx
|
85
|
-
ary_in_model.delete_at(idx)
|
86
|
-
else
|
87
|
-
$stderr.puts "Couldn't find item #{value.inspect} in path #{path} to delete in to_model"
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
def change(to_model, from_value)
|
92
|
-
ary_in_model = lookup_parent_in_model(to_model)
|
93
|
-
idx = ary_in_model.smart_find(from_value)
|
94
|
-
if idx.nil?
|
95
|
-
$stderr.puts "Couldn't find value #{from_value.inspect} in path #{path} to change in to_model, adding to end of list"
|
96
|
-
idx = ary_in_model.size
|
97
|
-
end
|
98
|
-
ary_in_model[idx] = value
|
99
|
-
end
|
100
|
-
|
101
|
-
def move(to_model, _from_ref)
|
102
|
-
ary_in_model = lookup_parent_in_model(to_model)
|
103
|
-
insert_idx = parent.previous_item_index(ary_in_model, value) + 1
|
104
|
-
current_idx = ary_in_model.smart_find(value)
|
105
|
-
deleted_value = ary_in_model.delete_at(current_idx)
|
106
|
-
ary_in_model.insert(
|
107
|
-
insert_idx,
|
108
|
-
deleted_value
|
109
|
-
)
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Archimate
|
4
|
-
module Diff
|
5
|
-
class ArchimateReferenceableReference < ArchimateNodeReference
|
6
|
-
using DataModel::DiffableArray
|
7
|
-
|
8
|
-
def initialize(archimate_node)
|
9
|
-
unless archimate_node.is_a?(DataModel::Referenceable)
|
10
|
-
raise(
|
11
|
-
TypeError,
|
12
|
-
"archimate_node is a #{archimate_node.class}, Referenceable was expected"
|
13
|
-
)
|
14
|
-
end
|
15
|
-
super
|
16
|
-
end
|
17
|
-
|
18
|
-
def lookup_in_model(model)
|
19
|
-
raise TypeError unless model.is_a?(DataModel::Model)
|
20
|
-
# There can be only one Model so return the model argument if
|
21
|
-
# this node reference is a Model. This escape is required in case
|
22
|
-
# the Model this is being applied to has a different id than the
|
23
|
-
# model of the attribute this reference refers to.
|
24
|
-
return model if archimate_node.is_a?(DataModel::Model)
|
25
|
-
model.lookup(archimate_node.id)
|
26
|
-
end
|
27
|
-
|
28
|
-
def to_s
|
29
|
-
archimate_node.to_s
|
30
|
-
end
|
31
|
-
|
32
|
-
def value
|
33
|
-
archimate_node
|
34
|
-
end
|
35
|
-
|
36
|
-
def parent
|
37
|
-
archimate_node.parent
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
@@ -1,70 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Archimate
|
4
|
-
module Diff
|
5
|
-
class ArchimateNodeAttributeReference < ArchimateNodeReference
|
6
|
-
attr_reader :attribute
|
7
|
-
|
8
|
-
def initialize(archimate_node, attribute)
|
9
|
-
unless archimate_node.is_a?(DataModel::ArchimateNode)
|
10
|
-
raise(
|
11
|
-
TypeError,
|
12
|
-
"archimate_node must be an ArchimateNode, was #{archimate_node.class}"
|
13
|
-
)
|
14
|
-
end
|
15
|
-
unless attribute.is_a?(Symbol)
|
16
|
-
raise(
|
17
|
-
TypeError,
|
18
|
-
"Node #{archimate_node.class} attribute must be a sym, was a #{attribute.class} value #{attribute.inspect}"
|
19
|
-
)
|
20
|
-
end
|
21
|
-
unless archimate_node.class.schema.keys.include?(attribute)
|
22
|
-
raise(
|
23
|
-
ArgumentError,
|
24
|
-
"Attribute #{attribute} invalid for class #{archimate_node.class}"
|
25
|
-
)
|
26
|
-
end
|
27
|
-
super(archimate_node)
|
28
|
-
@attribute = attribute
|
29
|
-
end
|
30
|
-
|
31
|
-
def ==(other)
|
32
|
-
super && attribute == other.attribute
|
33
|
-
end
|
34
|
-
|
35
|
-
def lookup_in_model(model)
|
36
|
-
recurse_lookup_in_model(archimate_node, model)[attribute]
|
37
|
-
end
|
38
|
-
|
39
|
-
def to_s
|
40
|
-
attribute.to_s
|
41
|
-
end
|
42
|
-
|
43
|
-
def value
|
44
|
-
archimate_node[attribute]
|
45
|
-
end
|
46
|
-
|
47
|
-
def path(options = {})
|
48
|
-
@node_attribute_ref_path ||= [
|
49
|
-
super, @attribute
|
50
|
-
].map(&:to_s).reject(&:empty?).join("/")
|
51
|
-
end
|
52
|
-
|
53
|
-
def insert(to_model)
|
54
|
-
lookup_parent_in_model(to_model).set(attribute, value)
|
55
|
-
end
|
56
|
-
|
57
|
-
def delete(to_model)
|
58
|
-
lookup_parent_in_model(to_model).delete(attribute)
|
59
|
-
end
|
60
|
-
|
61
|
-
def change(to_model, _from_value)
|
62
|
-
lookup_parent_in_model(to_model).set(attribute, value)
|
63
|
-
end
|
64
|
-
|
65
|
-
def move(_to_model)
|
66
|
-
raise "Move is not valid for ArchimateNodes"
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
@@ -1,80 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Archimate
|
4
|
-
module Diff
|
5
|
-
class ArchimateNodeReference
|
6
|
-
using DataModel::DiffablePrimitive
|
7
|
-
using DataModel::DiffableArray
|
8
|
-
|
9
|
-
attr_reader :archimate_node
|
10
|
-
|
11
|
-
# There should be only a few things that are valid here:
|
12
|
-
# 1. An archimate node and a attribute name sym
|
13
|
-
# 2. An array and index
|
14
|
-
# Produces a NodeReference instance for the given parameters
|
15
|
-
def self.for_node(node, child_node)
|
16
|
-
case node
|
17
|
-
when DataModel::ArchimateNode
|
18
|
-
ArchimateNodeAttributeReference.new(node, child_node)
|
19
|
-
when Array
|
20
|
-
ArchimateArrayReference.new(node, child_node)
|
21
|
-
else
|
22
|
-
raise TypeError, "Node references need to be either an ArchimateNode or an Array"
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def initialize(archimate_node)
|
27
|
-
unless archimate_node.is_a?(DataModel::ArchimateNode) || archimate_node.is_a?(Array)
|
28
|
-
raise(
|
29
|
-
TypeError,
|
30
|
-
"archimate_node must be an ArchimateNode or Array, was #{archimate_node.class}"
|
31
|
-
)
|
32
|
-
end
|
33
|
-
raise "new WTF? parent at path #{archimate_node.path} is a #{archimate_node.class} but isn't assigned a model" if archimate_node.in_model.nil? && !archimate_node.is_a?(DataModel::Model)
|
34
|
-
@archimate_node = archimate_node
|
35
|
-
end
|
36
|
-
|
37
|
-
def ==(other)
|
38
|
-
other.is_a?(self.class) &&
|
39
|
-
value == other.value
|
40
|
-
end
|
41
|
-
|
42
|
-
def to_s
|
43
|
-
value.to_s
|
44
|
-
end
|
45
|
-
|
46
|
-
def lookup_in_model(model)
|
47
|
-
recurse_lookup_in_model(archimate_node, model)
|
48
|
-
end
|
49
|
-
|
50
|
-
def recurse_lookup_in_model(node, model)
|
51
|
-
return nil if node.nil?
|
52
|
-
raise TypeError, "node argument must be ArchimateNode or Array, was a #{node.class}" unless node.is_a?(Array) || node.is_a?(DataModel::ArchimateNode)
|
53
|
-
raise TypeError, "model argument must be a Model, was a #{model.class}" unless model.is_a?(DataModel::Model)
|
54
|
-
if node.is_a?(DataModel::Model)
|
55
|
-
return model
|
56
|
-
elsif node.is_a?(DataModel::Referenceable)
|
57
|
-
return model.lookup(node.id)
|
58
|
-
else
|
59
|
-
node_parent_in_model = recurse_lookup_in_model(node.parent, model)
|
60
|
-
node_parent_in_model[node.parent_attribute_name] unless node_parent_in_model.nil?
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
def lookup_parent_in_model(model)
|
65
|
-
raise "WTF? parent at path #{path} is a #{parent.class} but isn't assigned a model" if parent.in_model.nil? && !parent.is_a?(DataModel::Model)
|
66
|
-
result = recurse_lookup_in_model(parent, model)
|
67
|
-
$stderr.puts "Unable to lookup parent with path #{path}" if result.nil?
|
68
|
-
result
|
69
|
-
end
|
70
|
-
|
71
|
-
def parent
|
72
|
-
archimate_node
|
73
|
-
end
|
74
|
-
|
75
|
-
def path(options = {})
|
76
|
-
@node_ref_path ||= archimate_node.path(options)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|