Ticket #1757: changestats.pl

File changestats.pl, 4.2 KB (added by alpha123, 11 years ago)
Line 
1#!/usr/bin/perl
2
3use strict;
4use warnings;
5use feature 'unicode_strings';
6use utf8;
7
8use Getopt::Long;
9use XML::DOM;
10
11my $mod_root = '../../../binaries/data/mods';
12
13my $mod = 'public';
14my $key;
15my $change;
16my $only_print;
17
18GetOptions('mod|m=s' => \$mod, 'key|k=s' => \$key, 'change|c=i' => \$change, 'print|p' => \$only_print);
19
20my @classes = @ARGV;
21
22
23sub get_filename
24{
25 my ($mod, $template_name) = @_;
26 $template_name =~ s|^/||; # Remove a leading /
27 return "$mod_root/$mod/simulation/templates/$template_name";
28}
29
30sub array_contains_array
31{
32 # Check if the first array argument contains all the elements of the second one.
33 # There's probably a more efficient way to do this.
34 my ($array1, $array2) = @_;
35 my @array1 = @$array1;
36 my @array2 = @$array2;
37
38 foreach my $element (@array2) {
39 if (!grep(/^$element$/, @array1)) {
40 return 0;
41 }
42 }
43 return 1;
44}
45
46sub minimum_one_decimal
47{
48 # Ensure $num has at least one decimal place.
49 # This is because values in templates always have a decimal place.
50 my ($num) = @_;
51 if ($num == int($num)) {
52 return sprintf('%.01f', $num);
53 }
54 return sprintf('%g\n', $num);
55}
56
57sub get_templates
58{
59 my ($mod, $subdir) = @_;
60 $subdir = $subdir || '';
61 opendir my $template_dir, "$mod_root/$mod/simulation/templates/$subdir";
62 my @templates = readdir $template_dir;
63 closedir $template_dir;
64 return map { "$subdir/$_"; } grep(/^[^.]/, @templates); # Remove directories that start with a dot.
65}
66
67sub get_template_classes
68{
69 my ($parser, $template_file) = @_;
70 my @classes = ();
71 my $template = $parser->parsefile($template_file);
72 my $entity = $template->getDocumentElement;
73
74 # Merge this template's classes with all its inherited classes.
75 my $parent = $entity->getAttributeNode('parent');
76 if ($parent) {
77 @classes = get_template_classes($parser, get_filename($mod, $parent->getNodeValue) . '.xml');
78 }
79
80 my $identity = $entity->getElementsByTagName('Identity')->item(0);
81 if ($identity) {
82 my $class_tokens = $identity->getElementsByTagName('Classes')->item(0);
83 if ($class_tokens) {
84 push @classes, split(' ', $class_tokens->getFirstChild->getNodeValue); # The firstChild is the text node.
85 }
86 }
87
88 $template->dispose;
89 return @classes;
90}
91
92sub matching_templates
93{
94 my ($mod, $templates, $desired_classes) = @_;
95 my @templates = @$templates;
96 my @desired_classes = @$desired_classes;
97 my @matching;
98 my $parser = new XML::DOM::Parser;
99
100 foreach my $template_name (@templates) {
101 my $template_file = get_filename($mod, $template_name);
102 if (-d $template_file) {
103 my @more_templates = get_templates($mod, $template_name);
104 push @matching, matching_templates($mod, \@more_templates, \@desired_classes);
105 }
106 else {
107 my @classes = get_template_classes($parser, $template_file);
108 if (array_contains_array(\@classes, \@desired_classes)) {
109 push @matching, $template_file;
110 }
111 }
112 }
113 return @matching;
114}
115
116my @all_templates = get_templates($mod);
117my @matching_files = matching_templates($mod, \@all_templates, \@classes);
118
119print join("\n", map { substr $_, 56; } @matching_files), "\n"; # 56 is the length of $mod_root/simulation/templates/
120exit if $only_print;
121
122my $parser = new XML::DOM::Parser;
123foreach my $template_file (@matching_files) {
124 my $template = $parser->parsefile($template_file);
125 my @query = split '/', $key;
126 my @elements = $template->getElementsByTagName(shift @query);
127 foreach my $element_name (@query) {
128 @elements = map { $_->getElementsByTagName($element_name); } @elements;
129 }
130
131 foreach my $element (@elements) {
132 my $value = $element->getFirstChild->getNodeValue;
133 $element->getFirstChild->setNodeValue(minimum_one_decimal $value + $change);
134 my $nv = $element->getFirstChild->getNodeValue;
135 }
136
137 # Can't use printToFile because it messes up Unicode characters.
138 open(my $output_file, '>:utf8', $template_file);
139 print $output_file $template->toString;
140 $template->dispose;
141}
142
143print scalar(@matching_files), " files matched (fewer were actually modified).\n";