@select_parent = [['None', nil]] + profiles.collect{ |profile| [profile.name, profile.name] }
end
-
+
+
#
#
# POST /profiles/change_parent?id=<profile id>&parent_name=<parent profile name>
end
+ #
+ #
+ # GET /profiles/compare?id1=<profile1 id>&id2=<profile2 id>
+ #
+ #
+ def compare
+ @profiles = Profile.find(:all, :conditions => ['enabled=?', true], :order => 'language asc, name')
+ if params[:id1].present? && params[:id2].present?
+ @profile1 = Profile.find(params[:id1])
+ @profile2 = Profile.find(params[:id2])
+
+ arules1 = ActiveRule.find(:all, :include => [{:active_rule_parameters => :rules_parameter}, :rule],
+ :conditions => ['active_rules.profile_id=?', @profile1.id])
+ arules2 = ActiveRule.find(:all, :order => 'rules.plugin_name, rules.plugin_rule_key', :include => [{:active_rule_parameters => :rules_parameter}, :rule],
+ :conditions => ['active_rules.profile_id=?', @profile2.id])
+
+ diffs_by_rule={}
+ arules1.each do |arule1|
+ diffs_by_rule[arule1.rule]||=RuleDiff.new(arule1.rule)
+ diffs_by_rule[arule1.rule].arule1=arule1
+ end
+ arules2.each do |arule2|
+ diffs_by_rule[arule2.rule]||=RuleDiff.new(arule2.rule)
+ diffs_by_rule[arule2.rule].arule2=arule2
+ end
+ @in1=[]
+ @in2=[]
+ @modified=[]
+ @sames=[]
+ diffs_by_rule.values.sort.each do |diff|
+ case diff.status
+ when DIFF_IN1: @in1<<diff
+ when DIFF_IN2: @in2<<diff
+ when DIFF_MODIFIED: @modified<<diff
+ when DIFF_SAME: @sames<<diff
+ end
+ end
+ end
+ end
+
+ DIFF_IN1=1
+ DIFF_IN2=2
+ DIFF_MODIFIED=3
+ DIFF_SAME=4
+
private
+ class RuleDiff
+ attr_reader :rule, :removed_params, :added_params
+ attr_accessor :arule1, :arule2
+
+ def initialize(rule)
+ @rule=rule
+ end
+
+ def status
+ @status ||=
+ begin
+ if @arule1.nil?
+ @status=(@arule2 ? DIFF_IN2 : nil)
+ else
+ if @arule2
+ # compare severity and parameters
+ @removed_params=[]
+ @added_params=[]
+ @rule.parameters.each do |param|
+ v1=@arule1.value(param.id)
+ v2=@arule2.value(param.id)
+ if v1
+ if v2
+ if v1!=v2
+ @removed_params<<@arule1.parameter(param.name)
+ @added_params<<@arule2.parameter(param.name)
+ end
+ else
+ @removed_params<<@arule1.parameter(param.name)
+ end
+ elsif v2
+ @added_params<<@arule2.parameter(param.name)
+ end
+ end
+ diff=(@arule1.priority!=@arule2.priority) || !@removed_params.empty? || !@added_params.empty?
+ @status=(diff ? DIFF_MODIFIED : DIFF_SAME)
+ else
+ @status=DIFF_IN1
+ end
+ end
+ end
+ end
+
+ def <=>(other)
+ rule.name()<=>other.rule.name
+ end
+ end
+
+ #
+ # Remove active rules that are identical in both collections (same severity and same parameters)
+ # and return a map with results {:added => X, :removed => Y, :modified => Z,
+ # :rules => {rule1 => [activeruleleft1, activeruleright1], rule2 => [activeruleleft2, nil], ...]}
+ # Assume both collections are ordered by rule key
+ #
+ def compute_diff(arules1, arules2)
+ rules = {}
+ removed = 0
+ added = 0
+ modified = 0
+ same = 0
+ begin
+ diff = false
+ #take first item of each collection
+ active_rule1 = arules1.first
+ active_rule2 = arules2.first
+ if active_rule1 != nil and active_rule2 != nil
+ order = active_rule1.rule.key <=> active_rule2.rule.key
+ if order < 0
+ active_rule2 = nil
+ rule = active_rule1.rule
+ diff = true
+ removed = removed +1
+ elsif order > 0
+ active_rule1 = nil
+ rule = active_rule2.rule
+ diff = true
+ added = added +1
+ else
+ rule = active_rule1.rule # = active_rule2.rule
+ #compare severity
+ diff = true if active_rule1.priority != active_rule2.priority
+ #compare parameters
+ rule.parameters.each do |param|
+ diff = true if active_rule1.value(param.id) != active_rule2.value(param.id)
+ end
+ if diff
+ modified = modified + 1
+ else
+ same = same +1
+ end
+ end
+ elsif active_rule1 != nil
+ #no more rule in right collection
+ diff = true
+ removed = removed +1
+ rule = active_rule1.rule
+ elsif active_rule2 != nil
+ #no more rule in left collection
+ diff = true
+ added = added +1
+ rule = active_rule2.rule
+ end
+ # remove processed rule(s)
+ arules1 = arules1.drop(1) if active_rule1 != nil
+ arules2 = arules2.drop(1) if active_rule2 != nil
+ if diff
+ rules[rule] = [active_rule1, active_rule2]
+ end
+ end while !arules1.empty? || !arules2.empty?
+ return {:same => same, :added => added, :removed => removed, :modified => modified, :rules => rules}
+ end
+
def read_file_param(configuration_file)
# configuration file is a StringIO
if configuration_file.respond_to?(:read)
end
label
end
+
+ def options_for_profiles(profiles, selected_id=nil)
+ html=""
+ profiles.group_by(&:language).each do |language, profiles|
+ html += "<optgroup label=\"#{html_escape(language)}\">"
+ profiles.each do |profile|
+ html += "<option value='#{profile.id}' #{'selected' if profile.id==selected_id}>#{html_escape(profile.name)}</option>"
+ end
+ html += "</optgroup>"
+ end
+ html
+ end
end
\ No newline at end of file
--- /dev/null
+<%= image_tag "priority/#{arule.priority}.png" %>
+
+<span class="rulename"><a onclick="window.open(this.href,'rule','height=700,width=500,scrollbars=1,resizable=1');return false;" href="<%= url_for :controller => 'rules', :action => 'show', :id => arule.rule.key, :layout => 'false' -%>"><%= h(arule.rule.name) -%></a></span> <em><%= h(arule.rule.plugin_name) -%></em>
\ No newline at end of file
--- /dev/null
+<h1 class="marginbottom10"><%= link_to 'Quality profiles', :controller => 'profiles', :action => 'index' -%> / Compare</h1>
+
+<form method="GET" class="marginbottom10">
+ <select name="id1" class="small">
+ <option value=""></option>
+ <%= options_for_profiles(@profiles, params[:id1].to_i) %>
+ </select>
+
+ <select name="id2" class="small">
+ <option value=""></option>
+ <%= options_for_profiles(@profiles, params[:id2].to_i) %>
+ </select>
+ <input type="submit" value="Compare" class="small"/>
+ <% if @profile1 && @profile2 %>
+ <a href="<%= url_for :action => 'compare', :id1 => @profile2.id, :id2 => @profile1.id -%>" id="switch" title="Switch left and right view"><%= image_tag 'switch.png'-%></a>
+ <% end %>
+</form>
+
+<% if @profile1 && @profile2 %>
+
+<table class="width100 marginbottom10" id="profile_diff_table">
+<tbody>
+
+<% unless @in1.empty? %>
+ <tr>
+ <td width="49%">
+ <table class="data width100 marginbottom10">
+ <thead>
+ <tr>
+ <th><%= @in1.size -%> rules only in <a href="<%= url_for :controller => 'rules_configuration', :action => 'index', :id => @profile1.id -%>"><%= h @profile1.name %></a></th>
+ </tr>
+ </thead>
+ <% @in1.each do |diff| %>
+ <tr id="rule_<%= u(diff.rule.key) -%>">
+ <td class="<%= cycle('even','odd', :name => 'in1')-%>">
+ <%= render :partial => 'diff_rule', :locals => {:arule => diff.arule1} %>
+ </td>
+ </tr>
+ <% end %>
+ </table>
+ </td>
+ <td width="2%"> </td>
+ <td width="49%"> </td>
+ </tr>
+<% end %>
+
+<% unless @in2.empty? %>
+ <tr>
+ <td width="49%"></td>
+ <td width="2%"> </td>
+ <td width="49%">
+ <table class="data width100 marginbottom10">
+ <thead>
+ <tr>
+ <th><%= @in2.size -%> rules only in <a href="<%= url_for :controller => 'rules_configuration', :action => 'index', :id => @profile2.id -%>"><%= h @profile2.name %></a></th>
+ </tr>
+ </thead>
+ <% @in2.each do |diff| %>
+ <tr id="rule_<%= u(diff.rule.key) -%>">
+ <td class="<%= cycle('even','odd', :name => 'in2')-%>">
+ <%= render :partial => 'diff_rule', :locals => {:arule => diff.arule2} %>
+ </td>
+ </tr>
+ <% end %>
+ </table>
+ </td>
+ </tr>
+<% end %>
+
+
+<% unless @modified.empty? %>
+<tr>
+ <td colspan="3">
+ <table class="data width100 marginbottom10">
+ <thead>
+ <tr>
+ <th width="49%"><%= @modified.size -%> rules have a different configuration<br/>
+ <a href="<%= url_for :controller => 'rules_configuration', :action => 'index', :id => @profile1.id -%>"><%= h @profile1.name %></a>
+ </th>
+ <th width="2%"></th>
+ <th width="49%"><br/><a href="<%= url_for :controller => 'rules_configuration', :action => 'index', :id => @profile2.id -%>"><%= h @profile2.name %></a></th>
+ </tr>
+ </thead>
+ <% @modified.each do |diff|
+ td_css=cycle('even','odd', :name => 'modified')
+ %>
+ <tr id="rule_<%= u(diff.rule.key) -%>">
+ <td class="<%= td_css -%>" width="49%">
+ <%= render :partial => 'diff_rule', :locals => {:arule => diff.arule1} %>
+ <% if diff.removed_params && !diff.removed_params.empty? %>
+ <ul>
+ <% diff.removed_params.each do |parameter| %>
+ <li><%= h(parameter.name) -%>: <span class="diffParam"><%= parameter.value.gsub(',', ', ') -%></span></li>
+ <% end %>
+ </ul>
+ <% end %>
+ </td>
+ <td width="2%" class="<%= td_css -%>"> </td>
+ <td class="<%= td_css -%>" width="49%">
+ <%= render :partial => 'diff_rule', :locals => {:arule => diff.arule2} %>
+ <% if diff.added_params && !diff.added_params.empty? %>
+ <ul>
+ <% diff.added_params.each do |parameter| %>
+ <li><%= h(parameter.name) -%>: <span class="diffParam"><%= parameter.value.gsub(',', ', ') -%></span></li>
+ <% end %>
+ </ul>
+ <% end %>
+ </td>
+ </tr>
+ <% end %>
+ </table>
+ </td>
+ </tr>
+<% end %>
+
+<% unless @sames.empty? %>
+<tr>
+ <td colspan="3">
+ <table class="data width100 marginbottom10">
+ <thead>
+ <tr>
+ <th><%= @sames.size -%> rules have the same configuration</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td class="even">Not displayed</td>
+ </tr>
+ </tbody>
+ </table>
+ </td>
+ </tr>
+<% end %>
+</tbody>
+</table>
+<% end %>
\ No newline at end of file
<% if administrator? %>
<div class="line-block marginbottom10">
- <ul style="float: right" class="horizontal">
- <li class="marginleft10 restore">
+ <ul class="operations">
+ <li>
+ <%= image_tag 'compare.png' -%>
+ <a href="<%= ApplicationController.root_context-%>/profiles/compare" id="compare-link">Compare profiles</a>
+ </li>
+ <li class="last">
+ <%= image_tag 'restore.gif' -%>
<a href="#" onclick="$('restore-form').show();return false;" id="restore-link">Restore profile</a>
</li>
</ul>
<tr>
<td colspan="2">
- <input type="submit" value="Restore profile"></input>
+ <input type="submit" value="Restore profile"/>
<a href="#" onclick="$('restore-form').reset();$('restore-form').hide();return false;">Cancel</a>
</td>
</tr>
.left {
text-align: left;
}
+
+.center {
+ text-align: center;
+}
+
code {
font-size: 93%;
}
.small {
font-size: 85%;
}
+em {
+ color: #AAA;
+ font-size: 85%;
+ font-style: normal;
+}
+
a.external {
background: url('../images/links/external.png') no-repeat 100% 0;
padding: 0 16px 0px 0;
ul.operations li a {
color: #555;
}
+ul.operations li img {
+ vertical-align: middle;
+ margin-right: 5px;
+}
/* RESOURCE VIEWER */
.resourceName h1 {
display: block;
background: url("../images/restore.gif") no-repeat scroll left 50% transparent;
padding: 2px 0 2px 20px;
-}
\ No newline at end of file
+}
+.compare {
+ display: block;
+ background: url("../images/compare.png") no-repeat scroll left 50% transparent;
+ padding: 2px 0 2px 20px;
+}
+
+/* Profile diff */
+.diffParam {
+ font-family: 'Bitstream Vera Sans Mono','Courier',monospace;
+}