source: trunk/gui/apps/rpdiff @ 3177

Last change on this file since 3177 was 3177, checked in by mmc, 10 years ago

Updated all of the copyright notices to reference the transfer to
the new HUBzero Foundation, LLC.

  • Property svn:executable set to *
File size: 21.3 KB
Line 
1#!/bin/sh
2# ----------------------------------------------------------------------
3#  RPDIFF
4#
5#  Compares two Rappture run files and looks for differences in the
6#  output results.  This is useful for the BOINC integration and other
7#  job execution infrastructures, so we can compare the results from
8#  multiple runs.
9#
10#    USAGE:
11#    % rpdiff <runFile1> <runFile2>
12#
13#  Exits with status 0 if the files are the same, and non-zero status
14#  if the files are different.  Prints differences on stdout.  Prints
15#  any errors on stderr.
16# ======================================================================
17#  AUTHOR:  Michael McLennan, Purdue University
18#  Copyright (c) 2004-2012  HUBzero Foundation, LLC
19#
20#  See the file "license.terms" for information on usage and
21#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
22# ======================================================================
23# \
24exec tclsh "$0" ${1+"$@"}
25# tclsh executes the rest...
26
27package require Rappture
28
29# ----------------------------------------------------------------------
30# USAGE: diff <path> <lib1> <lib2>
31#
32# Used to compare two Rappture library objects at the specified <path>
33# in <lib1> and <lib2>.  Returns "" if they are the same, and a list
34# of differences if they are not.
35# ----------------------------------------------------------------------
36proc diff {path lib1 lib2} {
37    set knowntypes {boolean choice cloud curve field group histogram image integer loader log mesh note number periodicelement phase sequence string structure table unirect2d}
38
39    set type1 [$lib1 element -as type $path]
40    set type2 [$lib2 element -as type $path]
41    if {($type1 eq "" && $type2 ne "") || ($type1 ne "" && $type2 eq "")} {
42        return "missing component at $path"
43    } elseif {$type1 ne $type2} {
44        return "component mismatch at $path"
45    }
46
47    set diffs ""
48    switch -- $type1 {
49        input - output - group - phase {
50            set cpath1 [$lib1 children -as path $path]
51            set cpath2 [$lib2 children -as path $path]
52
53            # scan through all components in lib1 and diff against lib2
54            foreach cp $cpath1 {
55                set ct [$lib1 element -as type $cp]
56                if {[lsearch $knowntypes $ct] < 0} {
57                    # this isn't a real rappture object -- skip it
58                    set i [lsearch -exact $cpath2 $cp]
59                    if {$i >= 0} {
60                        set cpath2 [lreplace $cpath2 $i $i]
61                    }
62                    continue
63                }
64
65                set i [lsearch -exact $cpath2 $cp]
66                if {$i < 0} {
67                    lappend diffs "missing missing component at $cp"
68                } else {
69                    set cpath2 [lreplace $cpath2 $i $i]
70                    eval lappend diffs [diff $cp $lib1 $lib2]
71                }
72            }
73
74            # components left over that are in lib2 but not in lib1?
75            foreach cp $cpath2 {
76                lappend diffs "missing component at $cp"
77            }
78        }
79
80        boolean {
81            eval lappend diffs [diffattrs {
82                about.label about.description default
83            } $path $lib1 $lib2]
84
85            set v1 [$lib1 get $path.current]
86            if {$v1 ne "" && [catch {expr $v1} newval] == 0} { set v1 $newval }
87
88            set v2 [$lib2 get $path.current]
89            if {$v2 ne "" && [catch {expr $v2} newval] == 0} { set v2 $newval }
90
91            if {$v1 ne $v2} {
92                lappend diffs "value mismatch at $path.current"
93            }
94        }
95        choice {
96            eval lappend diffs [diffattrs {
97                about.label about.description default
98            } $path $lib1 $lib2]
99
100            set v1 [$lib1 get $path.current]
101            set v2 [$lib2 get $path.current]
102            if {$v1 ne $v2} {
103                lappend diffs "value mismatch at $path.current"
104            }
105        }
106        cloud {
107            eval lappend diffs [diffattrs {
108                about.label about.description units hide
109            } $path $lib1 $lib2]
110
111            eval lappend diffs [diffdatalines $path.points $lib1 $lib2]
112        }
113        curve {
114            eval lappend diffs [diffattrs {
115                about.label about.description
116                xaxis.label xaxis.description xaxis.units
117                yaxis.label yaxis.description yaxis.units
118            } $path $lib1 $lib2]
119
120            set cpath2 [$lib2 children -as path $path.component]
121            foreach elem [$lib1 children -as path $path.component] {
122                set i [lsearch -exact $cpath2 $elem]
123                if {$i >= 0} {
124                    set cpath2 [lreplace $cpath2 $i $i]
125                }
126
127                set data1 [$lib1 get $elem]
128                set data2 [$lib2 get $elem]
129                if {[llength $data1] != [llength $data2]} {
130                    lappend diffs "value mismatch at $elem"
131                    break
132                }
133
134                foreach d1 $data1 d2 $data2 {
135                    if {[Rappture::objects::ObjVal::cmpdbl $d1 $d2] != 0} {
136                        lappend diffs "value mismatch at $elem"
137                        break
138                    }
139                }
140            }
141            foreach elem $cpath2 {
142                # anything left in lib2 that's not in lib1?
143                lappend diffs "missing component at $elem"
144            }
145        }
146        field {
147            eval lappend diffs [diffattrs {
148                about.label about.description
149            } $path $lib1 $lib2]
150
151            set cpath2 [$lib2 children -as path -type component $path]
152            foreach elem [$lib1 children -as path -type component $path] {
153                set i [lsearch -exact $cpath2 $elem]
154                if {$i >= 0} {
155                    set cpath2 [lreplace $cpath2 $i $i]
156                }
157
158                # the flow attributes may or may not exist
159                eval lappend diffs [diffattrs {
160                    flow.label flow.description
161                } $elem $lib1 $lib2]
162
163                # must have the same dx (if defined)
164                set v1 [$lib1 get $elem.dx]
165                set v2 [$lib2 get $elem.dx]
166                if {$v1 ne $v2} {
167                    lappend diffs "value mismatch at $elem.dx"
168                    continue
169                }
170
171                # must have the same mesh
172                set v1 [$lib1 get $elem.mesh]
173                set v2 [$lib2 get $elem.mesh]
174                if {$v1 ne $v2} {
175                    lappend diffs "value mismatch at $elem.mesh"
176                    continue
177                }
178
179                # must have the same values
180                eval lappend diffs [diffdatalines $elem.values $lib1 $lib2]
181            }
182            foreach elem $cpath2 {
183                # anything left in lib2 that's not in lib1?
184                lappend diffs "missing component at $elem"
185            }
186        }
187        histogram {
188            eval lappend diffs [diffattrs {
189                about.label about.description
190                xaxis.label xaxis.description xaxis.units
191                yaxis.label yaxis.description yaxis.units
192            } $path $lib1 $lib2]
193
194            set cpath2 [$lib2 children -as path $path.component]
195            foreach elem [$lib1 children -as path $path.component] {
196                set i [lsearch -exact $cpath2 $elem]
197                if {$i >= 0} {
198                    set cpath2 [lreplace $cpath2 $i $i]
199                }
200
201                eval lappend diffs [diffdatalines $elem $lib1 $lib2]
202            }
203            foreach elem $cpath2 {
204                # anything left in lib2 that's not in lib1?
205                lappend diffs "missing component at $elem"
206            }
207        }
208        image {
209            eval lappend diffs [diffattrs {
210                about.label about.description resize convert
211            } $path $lib1 $lib2]
212
213            set v1 [$lib1 get $path.current]
214            set v2 [$lib2 get $path.current]
215            if {$v1 ne $v2} {
216                lappend diffs "value mismatch at $path.current"
217            }
218        }
219        integer {
220            eval lappend diffs [diffattrs {
221                about.label about.description min max default
222            } $path $lib1 $lib2]
223
224            set v1 [$lib1 get $path.current]
225            set v2 [$lib2 get $path.current]
226            if {[string is integer -strict $v1]
227                  && [string is integer -strict $v2]} {
228                if {$v1 != $v2} {
229                    lappend diffs "value mismatch at $path.current"
230                }
231            } elseif {$v1 ne $v2} {
232                lappend diffs "value mismatch at $path.current"
233            }
234        }
235        log {
236            set v1 [$lib1 get $path]
237            set v2 [$lib2 get $path]
238            if {$v1 ne $v2} {
239                lappend diffs "value mismatch at $path"
240            }
241        }
242        mesh {
243            eval lappend diffs [diffattrs {
244                about.label about.description units hide
245            } $path $lib1 $lib2]
246
247            # look for differences in nodes
248            set cpath2 [$lib2 children -as path -type node $path]
249            foreach elem [$lib1 children -as path -type node $path] {
250                set i [lsearch -exact $cpath2 $elem]
251                if {$i >= 0} {
252                    set cpath2 [lreplace $cpath2 $i $i]
253                }
254
255                eval lappend diffs [diffdatalines $elem $lib1 $lib2]
256            }
257            foreach elem $cpath2 {
258                # anything left in lib2 that's not in lib1?
259                lappend diffs "missing component at $elem"
260            }
261
262            # look for differences in elements
263            set cpath2 [$lib2 children -as path -type element $path]
264            foreach elem [$lib1 children -as path -type element $path] {
265                set i [lsearch -exact $cpath2 $elem]
266                if {$i >= 0} {
267                    set cpath2 [lreplace $cpath2 $i $i]
268                }
269
270                set v1 [$lib1 get $elem.node]
271                set v2 [$lib2 get $elem.node]
272                if {$v1 ne $v2} {
273                    lappend diffs "value mismatch at $path.node"
274                }
275            }
276            foreach elem $cpath2 {
277                # anything left in lib2 that's not in lib1?
278                lappend diffs "missing component at $elem"
279            }
280        }
281        note {
282            eval lappend diffs [diffattrs {contents} $path $lib1 $lib2]
283        }
284        number {
285            eval lappend diffs [diffattrs {
286                about.label about.description about.icon
287                min max units color default
288            } $path $lib1 $lib2]
289
290            set v1 [$lib1 get $path.current]
291            set v2 [$lib2 get $path.current]
292            if {[string is double -strict $v1]
293                  && [string is double -strict $v2]} {
294                if {[Rappture::objects::ObjVal::cmpdbl $v1 $v2] != 0} {
295                    lappend diffs "value mismatch at $path.current"
296                }
297            } elseif {$v1 ne $v2} {
298                lappend diffs "value mismatch at $path.current"
299            }
300        }
301        sequence {
302            eval lappend diffs [diffattrs {
303                about.label about.description index.label
304            } $path $lib1 $lib2]
305
306            set cpath2 [$lib2 children -as path -type element $path]
307            foreach elem [$lib1 children -as path -type element $path] {
308                set i [lsearch -exact $cpath2 $elem]
309                if {$i >= 0} {
310                    set cpath2 [lreplace $cpath2 $i $i]
311                }
312
313                # must have the same index
314                set v1 [$lib1 get $elem.index]
315                set v2 [$lib2 get $elem.index]
316                if {$v1 ne $v2} {
317                    lappend diffs "value mismatch at $elem.index"
318                    continue
319                }
320
321                # must have the same values
322                set parts1 [lsort [$lib1 children -as path $elem]]
323                set parts2 [lsort [$lib2 children -as path $elem]]
324                if {$parts1 ne $parts2} {
325                    lappend diffs "value mismatch at $elem"
326                    continue
327                }
328
329                foreach p $parts1 {
330                    set ptype [$lib1 element -as type $p]
331                    if {[lsearch $knowntypes $ptype] >= 0} {
332                        eval lappend diffs [diff $p $lib1 $lib2]
333                    }
334                }
335            }
336            foreach elem $cpath2 {
337                # anything left in lib2 that's not in lib1?
338                lappend diffs "missing component at $elem"
339            }
340        }
341        string {
342            eval lappend diffs [diffattrs {
343                about.label about.description default size hints
344            } $path $lib1 $lib2]
345
346            set v1 [$lib1 get $path.current]
347            set v2 [$lib2 get $path.current]
348            if {$v1 ne $v2} {
349                lappend diffs "value mismatch at $path.current"
350            }
351        }
352        structure {
353            eval lappend diffs [diffattrs {
354                about.label about.description
355            } $path $lib1 $lib2]
356
357            # check all parameters associated with the structure
358            set cpath2 [$lib2 children -as path $path.current.parameters]
359            foreach elem [$lib1 children -as path $path.current.parameters] {
360                set i [lsearch -exact $cpath2 $elem]
361                if {$i >= 0} {
362                    set cpath2 [lreplace $cpath2 $i $i]
363                }
364                eval lappend diffs [diff $elem $lib1 $lib2]
365            }
366            foreach elem $cpath2 {
367                # anything left in lib2 that's not in lib1?
368                lappend diffs "missing component at $elem"
369            }
370
371            # check all components in the structure
372            set cpath2 [$lib2 children -as path $path.current.components]
373            foreach elem [$lib1 children -as path $path.current.components] {
374                set i [lsearch -exact $cpath2 $elem]
375                if {$i >= 0} {
376                    set cpath2 [lreplace $cpath2 $i $i]
377                }
378
379                switch -- [$lib1 element -as type $elem] {
380                    box {
381                        eval lappend diffs [diffattrs {
382                            about.label about.color about.icon material
383                        } $elem $lib1 $lib2]
384
385                        set c2 [$lib2 children -as path -type corner $elem]
386                        foreach c [$lib1 children -as path -type corner $elem] {
387                            set i [lsearch -exact $c2 $c]
388                            if {$i >= 0} {
389                                set c2 [lreplace $c2 $i $i]
390                            }
391
392                            set v1 [$lib1 get $c]
393                            set v2 [$lib2 get $c]
394                            if {$v1 ne $v2} {
395                                lappend diffs "value mismatch at $c"
396                            }
397                        }
398                        foreach c $c2 {
399                            # anything left in lib2 that's not in lib1?
400                            lappend diffs "missing component at $c"
401                        }
402                    }
403                    molecule {
404                        eval lappend diffs [diffattrs {
405                            about.emblems formula
406                        } $elem $lib1 $lib2]
407
408                        # check for PDB data
409                        set v1 [$lib1 get $elem.pdb]
410                        set v2 [$lib2 get $elem.pdb]
411                        if {$v1 ne $v2} {
412                            lappend diffs "value mismatch at $elem.pdb"
413                        }
414
415                        # check for the old-style atom data
416                        set c2 [$lib2 children -as path -type atom $elem]
417                        foreach c [$lib1 children -as path -type atom $elem] {
418                            set i [lsearch -exact $c2 $c]
419                            if {$i >= 0} {
420                                set c2 [lreplace $c2 $i $i]
421                            }
422
423                            set v1 [$lib1 get $c.symbol]
424                            set v2 [$lib2 get $c.symbol]
425                            if {$v1 ne $v2} {
426                                lappend diffs "value mismatch at $c"
427                            }
428
429                            set df [diffdatalines $c.xyz $lib1 $lib2]
430                            if {$df ne ""} {
431                                eval lappend diffs $df
432                            }
433                        }
434                        foreach c $c2 {
435                            # anything left in lib2 that's not in lib1?
436                            lappend diffs "missing component at $c"
437                        }
438                    }
439                    default {
440                        error "don't know how to diff $elem"
441                    }
442                }
443            }
444            foreach elem $cpath2 {
445                # anything left in lib2 that's not in lib1?
446                lappend diffs "missing component at $elem"
447            }
448        }
449        table {
450            eval lappend diffs [diffattrs {
451                about.label about.description
452            } $path $lib1 $lib2]
453
454            set cpath2 [$lib2 children -as path -type column $path]
455            foreach elem [$lib1 children -as path -type column $path] {
456                set i [lsearch -exact $cpath2 $elem]
457                if {$i >= 0} {
458                    set cpath2 [lreplace $cpath2 $i $i]
459                }
460
461                eval lappend diffs [diffattrs {label units} $elem $lib1 $lib2]
462            }
463            foreach elem $cpath2 {
464                # anything left in lib2 that's not in lib1?
465                lappend diffs "missing component at $elem"
466            }
467
468            # make sure the table data matches
469            eval lappend diffs [diffdatalines $path.data $lib1 $lib2]
470        }
471        unirect2D {
472            eval lappend diffs [diffattrs {
473                about.label about.description hide
474                xaxis.label xaxis.units xaxis.numpoints
475                yaxis.label yaxis.units yaxis.numpoints
476            } $path $lib1 $lib2]
477
478            foreach elem {xaxis.min xaxis.max yaxis.min yaxis.max} {
479                set v1 [$lib1 get $path.$elem]
480                set v2 [$lib2 get $path.$elem]
481
482                if {[string is double -strict $v1]
483                      && [string is double -strict $v2]} {
484                    if {[Rappture::objects::ObjVal::cmpdbl $v1 $v2] != 0} {
485                        lappend diffs "value mismatch at $path.$elem"
486                    }
487                } elseif {$v1 ne $v2} {
488                    lappend diffs "value mismatch at $path.$elem"
489                }
490            }
491        }
492        default {
493            error "don't know how to compare type \"$type\""
494        }
495    }
496    return $diffs
497}
498
499# ----------------------------------------------------------------------
500# USAGE: diffattrs <attrList> <path> <lib1> <lib2>
501#
502# Used internally by the "diff" proc to look for a list of attributes
503# at the given <path> and see if there are any differences.  It is
504# considered a difference if the attribute is defined on one object
505# but not another, or if the string values are different.  Returns ""
506# if they are the same, and a list of differences if they are not.
507# ----------------------------------------------------------------------
508proc diffattrs {attrlist path lib1 lib2} {
509    set diffs ""
510    foreach name $attrlist {
511        set t1 [$lib1 element -as type $path.$name]
512        set t2 [$lib2 element -as type $path.$name]
513        if {$t1 ne "" || $t2 ne ""} {
514            if {[$lib1 get $path.$name] ne [$lib2 get $path.$name]} {
515                lappend diffs "attribute mismatch at $path.$name"
516            }
517        }
518    }
519    return $diffs
520}
521
522# ----------------------------------------------------------------------
523# USAGE: diffdatalines <path> <lib1> <lib2>
524#
525# Used internally by the "diff" proc to look for a list of attributes
526# at the given <path> and see if there are any differences.  It is
527# considered a difference if the attribute is defined on one object
528# but not another, or if the string values are different.  Returns ""
529# if they are the same, and a list of differences if they are not.
530# ----------------------------------------------------------------------
531proc diffdatalines {path lib1 lib2} {
532    set diffs ""
533
534    set data1 [split [string trim [$lib1 get $path]] \n]
535    set data2 [split [string trim [$lib2 get $path]] \n]
536    if {[llength $data1] != [llength $data2]} {
537        return [list "value mismatch at $path"]
538    }
539
540    foreach line1 $data1 line2 $data2 {
541        if {[llength $line1] != [llength $line2]} {
542            return [list "value mismatch at $path"]
543        }
544        foreach d1 $line1 d2 $line2 {
545            if {[string is double -strict $d1]
546                  && [string is double -strict $d2]} {
547                if {[Rappture::objects::ObjVal::cmpdbl $d1 $d2] != 0} {
548                    return [list "value mismatch at $path"]
549                }
550            } elseif {$d1 ne $d2} {
551                return [list "value mismatch at $path"]
552            }
553        }
554    }
555    return ""
556}
557
558# ======================================================================
559if {$argc != 2} {
560    puts stderr "USAGE: rpdiff file1.xml file2.xml"
561    exit 9
562}
563set lib1 [Rappture::library [lindex $argv 0]]
564set lib2 [Rappture::library [lindex $argv 1]]
565
566# compute the differences
567set diffs [diff output $lib1 $lib2]
568
569if {[llength $diffs] == 0} {
570    exit 0
571}
572
573# print a list of differences and exit
574foreach mesg $diffs {
575    puts $mesg
576}
577exit 1
Note: See TracBrowser for help on using the repository browser.