-
Notifications
You must be signed in to change notification settings - Fork 0
/
mergeDiff.m
152 lines (144 loc) · 6.04 KB
/
mergeDiff.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
function [unique] = mergeDiff(oldModel, newModel, merge)
%mergeDiff Simple diff of two Simulink models, hilighting differences.
% UNIQUE = mergeDiff(OLDMODEL, NEWMODEL{, MERGE = false}) compares block
% names and mask parameters from two similar models.
% The differences are reported in a format based on the unified format:
% http://en.wikipedia.org/wiki/Diff_utility#Unified_format
%
% If MERGE=true then OLDMODEL will be updated with parameter values and
% missing blocks from NEWMODEL.
% The merged model requires manual editing to complete the merge process.
% The blocks in the merged model are color coded upon completion.
% This function does not examine connecting lines. The user should review
% and connect these colored blocks manually to complete the merge.
%
% White - Block is unchanged
% Green - Block was missing from OLDMODEL and was copied from NEWMODEL
% Orange - Block's parameters were updated
% Red - Block is missing from NEWMODEL
% Yellow - Subsystem contains modifications
%
% Returns names of blocks unique to OLDMODEL.
%
% EXAMPLE
% % List differences between two Simulink models:
% open_system('oldmodel');
% open_system('newmodel');
% mergeDiff('oldmodel', 'newmodel');
%
% Carl Osterwisch, September 2014
if ~exist('merge', 'var')
merge = false; % Whether to merge newModel into oldModel
end
newModel = getfullname(newModel); % convert any handles into names
oldModel = getfullname(oldModel);
fprintf(1, '--- %s\n', oldModel); % original
fprintf(1, '+++ %s\n', newModel); % new
newBlocks = find_system(newModel, 'LookUnderMasks', 'all', 'type', 'block');
blocks = strrep(newBlocks, newModel, oldModel); % oldModel blocks to examine
oldBlocks = find_system(oldModel, 'LookUnderMasks', 'all', 'type', 'block');
ignoreBlock = '_'; % don't ignore any blocks
for i = 1:length(blocks)
blockName = regexprep(blocks{i}(length(oldModel)+1:end), '[^\w/]', ' ');
if strncmp(blockName, ignoreBlock, length(ignoreBlock))
continue;
end
makeCopy = false;
if ~any(strcmp(blocks{i}, oldBlocks))
% block is only in newModel
fprintf(1, '++ %s ++\n', blockName);
makeCopy = true;
else
response = 10;
% block name is common to both models
newParams = get_param(newBlocks{i}, 'DialogParameters');
oldParams = get_param(blocks{i}, 'DialogParameters');
if isstruct(newParams)
newFields = fieldnames(newParams);
else
newFields = {};
end
if isstruct(oldParams)
oldFields = fieldnames(oldParams);
else
oldFields = {};
end
% report deleted params
d = setdiff(oldFields, newFields);
if ~isempty(d)
fprintf(1, '@@ %s @@\n', blockName);
response = 1;
for j = 1:length(d)
fprintf(1, '-%s = %s\n', d{j}, num2str(get_param(blocks{i}, d{j})));
end
makeCopy = true;
end
% report changed params
for j = 1:length(newFields)
newValue = get_param(newBlocks{i}, newFields{j});
if ~isfield(oldParams, newFields{j})
% old model is missing this param
if response > 4 % show block name if first difference
fprintf(1,'@@ %s @@\n', blockName);
end
fprintf(1, '+%s = %s\n', newFields{j}, num2str(newValue));
makeCopy = true; % copy whole block
else
% param exists in both models
oldValue = get_param(blocks{i}, newFields{j});
if ~isequal(newValue, oldValue) && ~any(strcmp('read-only', ...
oldParams.(newFields{j}).Attributes))
if response > 4 % show block name if first difference
fprintf(1,'@@ %s @@\n', blockName);
end
fprintf(1, '-%s = %s\n', newFields{j}, num2str(oldValue));
fprintf(1, '+%s = %s\n', newFields{j}, num2str(newValue));
if ~merge
response = 3; % equivalent to 'n'
elseif response > 1
response = regexpi('aynq', input('Update? [y],n,a,q ', 's'));
if isempty(response)
response = 2; % default to y
end
end
if 4 == response
break
elseif response <= 2
set_param(blocks{i}, newFields{j}, newValue);
updateColor(blocks{i}, 'orange');
end
end
end
end
end
if merge && makeCopy
copyBlock(newBlocks{i}, blocks{i});
ignoreBlock = blockName; % ignore any childen of blockName
end
end
% return unique destination blocks but do not delete them
unique = setdiff(oldBlocks, blocks);
for i = 1:length(unique)
blockName = regexprep(unique{i}(length(oldModel)+1:end), '[^\w/]', ' ');
if strncmp(blockName, ignoreBlock, length(ignoreBlock))
continue;
end
ignoreBlock = blockName; % ignore children
fprintf(1, '-- %s --\n', blockName);
if merge
updateColor(unique{i}, 'red');
end
end
end
function copyBlock(srcBlock, dstBlock)
%Copies srcBlock to dstBlock.
block = add_block(srcBlock, dstBlock, 'MakeNameUnique', 'on');
updateColor(block, 'green');
end
function updateColor(block, color)
%Update block color as directed and change all parents to yellow.
if strcmp('block', get_param(block, 'type'))
set_param(block, 'BackgroundColor', color);
updateColor(get_param(block, 'parent'), 'yellow');
end
end