misc fixes to LM
[light-and-matter.git] / scripts / custom / 200_check_spotter_labels.pl
blobf0deebb8c2980e46b34637853bf0f2621da0cdc6
1 #!/usr/bin/perl
3 use strict;
5 # This script's job is to check for inconsistencies in the labeling of problems
6 # between spotter xml and problems.csv.
8 use XML::Simple;
9 use File::Basename;
10 use Data::Dumper;
11 use Cwd 'abs_path';
13 my $book = $ARGV[0];
14 my $csv_file = $ARGV[1];
15 my $xml_fragment_file = "spotter_labels"; # created in cwd, which is the main dir, not scripts/custom
16 my $xml_file = "/home/bcrowell/Documents/programming/spotter/answers/$book.xml";
18 my $whoami = basename($0); # http://stackoverflow.com/questions/4600192/how-to-get-the-name-of-perl-script-that-is-running
20 if (! -e $xml_file) {
21 print STDERR "warning in $whoami, file $xml_file doesn't exist; this is normal for sr\n";
22 exit(0);
25 sub barf {
26 my $message = shift;
27 print STDERR "error in $whoami\n";
28 print STDERR $message,"\n";
29 exit(-1);
32 my @errors = ();
34 # -------- read problems.csv --------------------------------------------
36 if (!-e $csv_file) {
37 # This script gets run by preflight, so if the book has never been compiled before in this
38 # directory, problems.csv won't exist. That's OK, just exit silently.
39 exit(0);
42 # fields:
43 # book = mnemonic such as lm, fund, ...
44 # ch = chapter (without any leading zero)
45 # num
46 # name = (see note below)
47 # soln = 0 or 1, boolean indicating whether the problem has a solution in the back of the book
49 my %csv_info = ();
50 my $xml_fragment = "<!-- labels output by $whoami to file $xml_fragment_file -->\n";
51 open(F,"<$csv_file") or barf("error opening $csv_file for input, $!");
52 while(my $line=<F>) {
53 if ($line =~ /(.*),(.*),(.*),(.*),(.*)/) {
54 my ($csv_book,$ch,$num,$label,$solution) = ($1,$2,$3,$4,$5);
55 if ($csv_book eq $book && $label ne 'deleted') {
56 if (exists $csv_info{$label}) {
57 push @errors,"label $label is defined more than once in $csv_file ; this means that the xml fragment in $xml_fragment_file will not work";
59 $xml_fragment = $xml_fragment . "<num id=\"$label\" label=\"$num\"/>\n";
60 $csv_info{$label} = [$csv_book,$ch,$num,$solution];
64 close F;
65 open(F,">$xml_fragment_file") or barf("error opening $xml_fragment_file for output, $!");
66 print F $xml_fragment;
67 close F;
69 # -------- read existing spotter xml --------------------------------------------
71 # The following dies with an error in the case where the xml file doesn't exist.
72 my $xml = eval{
73 XML::Simple::XMLin($xml_file,ForceArray =>['toc_level','toc','problem','find','ans','var'])
75 if ($@) {
76 barf("error parsing $xml_file, $@");
79 # num elements look like <num id="foo" label="17"/>
81 my $nums = $xml->{'num'}; # ref to an array of all the top-level nums in the file
82 if (! defined $nums) {
83 barf("file $xml_file contains no num elements??");
86 foreach my $label(keys %$nums) {
87 my $foo = $nums->{$label};
88 my $id;
89 # XML::Simple behaves differently depending on whether there's only 1 or more than one <num> in the file.
90 if (ref $foo) {
91 $id = $foo->{'label'};
93 else {
94 barf("There only seems to be one <num> in $xml_file, which I can't handle due to an idiosyncrasy in XML::Simple.");
96 if (!exists $csv_info{$label}) {
97 push @errors,"label $label exists in $xml_file , but not in $csv_file ; if the problem is new, do a make problems to fix this";
99 else {
100 my $x = $csv_info{$label};
101 my $csv_id = $x->[2];
102 if ($csv_id ne $id) {
103 push @errors,"label $label is defined as $id in $xml_file , but as $csv_id in $csv_file";
108 if (@errors>0) {
109 print STDERR (scalar @errors) . " errors in $whoami :\n";
110 print STDERR " Some of these may be fixable simply by cutting and pasting the xml fragment in $xml_fragment_file into $xml_file\n";
111 foreach my $error(@errors) {
112 print STDERR " $error\n";
114 print STDERR "$whoami dying with errors\n";
115 exit(-1);