updates
[inav.git] / src / utils / draft_rn_settings.rb
blob8d286a548e100c6287952fe79af6c96d1f31b4f5
1 #!/usr/bin/env ruby
2 # coding: utf-8
4 ##
5 ## This file is part of INAV.
6 ##
7 ## INAV is free software. You can redistribute this software
8 ## and/or modify this software under the terms of the
9 ## GNU General Public License as published by the Free Software
10 ## Foundation, either version 3 of the License, or (at your option)
11 ## any later version.
13 ## INAV is distributed in the hope that they will be
14 ## useful, but WITHOUT ANY WARRANTY; without even the implied
15 ## warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 ## See the GNU General Public License for more details.
18 ## You should have received a copy of the GNU General Public License
19 ## along with this software.
21 ## If not, see <http://www.gnu.org/licenses/>.
24 #########################################################################
26 # Generates a formatted (Markdown) report of CLI settings differences
27 # between two INAV branches or tags. Primarily intended for inclusion
28 # in release notes.
30 # Note that the report will require review / editing before inclusing
31 # in the RN, but it will jabe done the vast majority of the work for
32 # you.
34 # Example:
36 # draft_rn_settings.rb -f 5.1.0 -t release_6.0.0 > /tmp/draft-set6.0RN.md
37 # # now review  /tmp/draft-set6.0RN.md for inclusion in the offical RN
39 # Requirments:
40 # * ruby (v3 recommended)
41 # * git
43 #########################################################################
45 require 'yaml'
46 require 'optparse'
47 require 'tmpdir'
49 base = File.join(ENV["HOME"], "Projects/fc/inav")
50 ntag = nil
51 otag = nil
53 ARGV.options do |opt|
54   opt.banner = "#{File.basename($0)} [options]"
55   opt.on('-t','--tag=TAG',  'New tag or branch') {|o|ntag=o}
56   opt.on('-f','--from-tag=TAG', 'previous release tag or branch'){|o|otag=o}
57   opt.on('-b','--base=DIR',  "Base of the INAV repo [#{base}]" ) {|o|base=o}
58   opt.on('-?', "--help", "Show this message") {puts opt.to_s; exit}
59   begin
60     opt.parse!
61   rescue
62     puts opt
63     exit
64   end
65 end
67 abort 'New tag / branch is mandatory' unless ntag
68 abort 'Old tag / branch is mandatory' unless otag
70 begin
71   Dir.chdir(base)
72 rescue
73   abort "Cannot chdir to #{base}"
74 end
76 oldyaml = File.join(Dir.tmpdir, ".setting_old.yaml")
77 newyaml = File.join(Dir.tmpdir, ".setting_new.yaml")
79 system "> #{oldyaml} git show #{otag}:src/main/fc/settings.yaml"
80 system "> #{newyaml} git show #{ntag}:src/main/fc/settings.yaml"
82 h_old = {}
83 begin
84   h_old = YAML.load_file(oldyaml)
85 rescue
86   abort "Error reading old settings yaml"
87 end
89 h_new = {}
90 begin
91   h_new = YAML.load_file(newyaml)
92 rescue
93   abort "Error reading new settings yaml"
94 end
96 ot_names = []
97 h_old["tables"].each do |t|
98   ot_names << t["name"]
99 end
101 nt_names = []
102 h_new["tables"].each do |t|
103   nt_names << t["name"]
106 puts "# Draft Rel Notes -- settings helper"
107 puts
108 puts "The following should make a reasonable first pass at new / changed / removed settings"
109 puts "Will require manual checking / refining / formatting."
111 d = nt_names.difference(ot_names).sort
112 unless d.empty?
113   puts
114   puts "# New (Tables) -- to update group values"
115   puts
116   puts "| Name | Values |"
117   puts "| ---- | ------ |"
118   d.each do |dn|
119     t = h_new["tables"].select{|k| k["name"] == dn}.first
120     unless t.nil?
121       vals = t["values"]
122       if vals[0].class == String
123         vals.map!{|a| "`#{a}`"}
124       end
125       vs = vals.join(", ")
126       puts "| #{dn} | #{vs} |"
127     end
128   end
130 puts
132 d= ot_names.difference(nt_names).sort
133 unless d.empty?
134   puts
135   puts "## Removed (tables -- check for group value later)"
136   puts
137   puts "| Name | Comment |"
138   puts "| ---- | ------ |"
139   d.each do |dn|
140     t = h_old["tables"].select{|k| k["name"] == dn}.first
141     unless t.nil?
142       puts "| #{dn} |  |"
143     end
144   end
147 d=ot_names.intersection(nt_names).sort
148 unless d.empty?
149   puts
150   puts "## Changed (table values -- check for group value later)"
151   puts
152   puts "| Name | Values |"
153   puts "| ---- | ------ |"
154   d.each do |dn|
155     tnew = h_new["tables"].select{|k| k["name"] == dn}.first
156     told = h_old["tables"].select{|k| k["name"] == dn}.first
157     unless told.nil? && tnew.nil?
158       if told["values"] != tnew["values"]
159         vals = tnew["values"].difference(told["values"])
160         if !vals.empty?
161           if vals[0].class == String
162             vals.map!{|a| "`#{a}`"}
163           end
164           newvals = vals.join(", ")
165           puts "| #{dn} | New: #{newvals} |"
166         end
168         vals = told["values"].difference(tnew["values"])
169         if !vals.empty?
170           if vals[0].class == String
171             vals.map!{|a| "`#{a}`"}
172           end
173           remvals = vals.join(", ")
174           puts "| #{dn} | Removed: #{remvals} |"
175         end
176       end
177     end
178   end
181 og_names = []
182 h_old["groups"].each do |h|
183   h["members"].each do |m|
184     og_names << m["name"]
185   end
188 ng_names = []
189 h_new["groups"].each do |h|
190   h["members"].each do |m|
191     ng_names << m["name"]
192   end
195 d = ng_names.difference(og_names).sort
196 unless d.empty?
197   puts
198   puts "## New Items"
199   puts
200   puts "| Name | Description |"
201   puts "| ---- | ------ |"
202   d.each do |dn|
203     t=nil
204     h_new["groups"].each do |hh|
205       t = hh["members"].select{|k| k["name"] == dn}.first
206       unless t.nil?
207         desc = t["description"]||""
208         minmax = []
209         if t.has_key?("min")
210           case t["min"]
211           when Integer
212             minmax[0] = t["min"]
213           when "INT16_MIN"
214             minmax[0] = -32768
215           when "INT8_MIN"
216             minmax[0] = -128
217           end
218         end
220         if t.has_key?("max")
221           case t["max"]
222           when Integer
223             minmax[1] = t["max"]
224           when "UINT16_MAX"
225             minmax[1] = 65535
226           when "INT16_MAX"
227             minmax[1] = 32767
228           when "INT8_MAX"
229             minmax[1] = 127
230           when "UINT8_MAX"
231             minmax[1] = 255
232           end
233           minmax[0] = 0 if !minmax[1].nil? && minmax[0].nil?
234         end
235         if minmax.size == 2
236           desc = [desc," Values: #{minmax[0]} - #{minmax[1]}"].join
237         end
239         default = nil
240         if t.has_key?("default_value")
241           default = t["default_value"].to_s.upcase
242           unless default.nil?
243             desc = "#{desc} Default: #{default}"
244           end
245         end
246         desc.gsub!('|',',')
247         # default_value max min
248         puts "| #{dn} | #{desc} |"
249         break
250       end
251     end
252   end
256 d = og_names.difference(ng_names).sort
257 unless d.empty?
258   puts
259   puts "## Removed Items"
260   puts
261   puts "| Name | Description |"
262   puts "| ---- | ------ |"
263   d.each do |dn|
264     puts "| #{dn} |  |"
265   end
269 d=ot_names.intersection(nt_names).sort
270 unless d.empty?
271   puts
272   puts "## Changed Items (desc, range, default -- requires checking)"
273   puts
274   puts "Most of the content here will be indicated by a change at the table level"
275   puts
276   puts "| Name | Values |"
277   puts "| ---- | ------ |"
278   d.each do |dn|
279     tnew = told = nil
280     h_new["groups"].each do |hh|
281       tnew = hh["members"].select{|k| k["name"] == dn}.first
282       break unless tnew.nil?
283     end
284     h_old["groups"].each do |hh|
285       told = hh["members"].select{|k| k["name"] == dn}.first
286       break unless told.nil?
287     end
288     # in the following tests we discard just the addtion of an attribute
289     unless (told.nil? && tnew.nil?)
290       diffs = []
291       if told["default_value"] && told["default_value"] != tnew["default_value"]
292         diffs << "Default:  #{tnew["default_value"]}"
293       end
295       if told["description"] && told["description"] != tnew["description"]
296         diffs << tnew["description"]
297       end
299       unless diffs.empty?
300         diffstr = diffs.join(" ")
301         puts "| #{dn} | #{diffstr} |"
302       end
304     end
305   end
308 puts "Last updated: #{Time.now.utc.strftime("%FT%T%Z")}"
309 begin
310   File.unlink(oldyaml, newyaml)
311 rescue