archimate 1.1.1 → 1.2.1
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 +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
|