source: subversion/applications/rendering/tilesAtHome/tahlib.pm @ 4940

Last change on this file since 4940 was 4940, checked in by deelkar, 12 years ago

implement failure counter and better fatal error handling for loop mode

File size: 9.8 KB
Line 
1use strict; 
2
3# =====================================================================
4# The following is duplicated from tilesGen.pl
5# =====================================================================
6my %Config = ReadConfig("tilesAtHome.conf", "general.conf", "authentication.conf", "layers.conf");
7my $lastmsglen = 0;
8
9my $idleFor = 0;
10my $idleSeconds = 0;
11
12my %faults; #variable to track non transient errors
13
14#-----------------------------------------------------------------------------
15# Prints status message without newline, overwrites previous message
16# (if $newline set, starts new line after message)
17#-----------------------------------------------------------------------------
18sub statusMessage 
19{
20    my ($msg, $Verbose, $currentSubTask, $progressJobs, $progressPercent, $newline) = @_;
21
22    if ($Verbose)
23    {
24        print STDERR "$msg\n";
25        return;
26    }
27
28    my $toprint = sprintf("[#%d %3d%% %s] %s%s ", $progressJobs, $progressPercent+.5, $currentSubTask, $msg, ($newline) ? "" : "...");
29    my $curmsglen = length($toprint);
30    print STDERR "\r$toprint";
31    print STDERR " " x ($lastmsglen-$curmsglen);
32    if ($newline)
33    {
34        $lastmsglen = 0;
35        print STDERR "\n";
36    }
37    else
38    {
39        $lastmsglen = $curmsglen;
40    }
41
42}
43
44#-----------------------------------------------------------------------------
45# Used to display task completion. Only for verbose mode.
46#-----------------------------------------------------------------------------
47sub doneMessage
48{
49    my ($msg,$Verbose) = @_;
50    $msg = "done" if ($msg eq "");
51
52    if ($Verbose)
53    {
54        print STDERR "$msg\n";
55        return;
56    }
57}
58
59#-----------------------------------------------------------------------------
60# A sleep function with visible countdown
61#-----------------------------------------------------------------------------
62sub talkInSleep
63{
64    my ($message, $duration,$progstart,$Verbose) = @_;
65    if ($Verbose)
66    {
67        print STDERR "$message: sleeping $duration seconds\n";
68        sleep $duration;
69        return;
70    }
71
72    for (my $i = 0; $i< $duration; $i++)
73    {
74        my $totalseconds = time() - $progstart;
75        statusMessage(sprintf("%s. Idle for %d:%02d (%d%% idle) ", 
76                $message,
77                $idleFor/60, $idleFor%60,
78                $totalseconds ? $idleSeconds * 100 / $totalseconds : 100));
79        sleep 1;
80        $idleFor++;
81        $idleSeconds++;
82    }
83}
84
85sub setIdle
86{
87    my ($idle,$setTotal) = @_;
88    if ($setTotal)
89    {
90        $idleSeconds = $idle;
91    }
92    else
93    {
94        $idleFor = $idle;
95    }
96}
97
98sub getIdle
99{
100    my $getTotal = @_;
101    if ($getTotal)
102    {
103      return $idleSeconds;
104    }
105    else
106    {
107      return $idleFor;
108    }
109}
110
111
112#-----------------------------------------------------------------------------
113# fault handling
114#-----------------------------------------------------------------------------
115sub addFault
116{
117    my ($faulttype,$diff) = @_;
118    $diff = 1 if (not $diff);
119    $faults{$faulttype} += $diff;
120    return $faults{$faulttype};
121}
122
123sub getFault
124{
125    my ($faulttype) = @_;
126    return $faults{$faulttype};
127}
128
129sub resetFault
130{
131    my ($faulttype) = @_;
132    $faults{$faulttype} = 0;
133    return "0 but true";
134}
135
136#-----------------------------------------------------------------------------
137# Run a shell command. Suppress command's stderr output unless it terminates
138# with an error code.
139#
140# Return 1 if ok, 0 on error.
141#-----------------------------------------------------------------------------
142sub runCommand
143{
144    my ($cmd,$mainPID) = @_;
145
146    # $message is deprecated, issue statusmessage prior to exec.
147    # statusMessage($message, $Config{Verbose}, $currentSubTask, $progressJobs, $progressPercent,0);
148
149
150    if ($Config{Verbose})
151    {
152        my $retval = system($cmd);
153        return ($retval<0) ? 0 : ($retval>>8) ? 0 : 1;
154    }
155
156    my $ErrorFile = $Config{WorkingDirectory}."/".$mainPID.".stderr";
157    my $retval = system("$cmd 2> $ErrorFile");
158    my $ok = 0;
159    my $ExtraInfo = "\nAdditional info about the Error(s):\n";
160
161    # <0 means that the process could not start
162    if ($retval < 0)
163    {
164        print STDERR "ERROR:\n";
165        print STDERR "  Could not run the following command:\n";
166        print STDERR "  $cmd\n";
167        print STDERR "  Please check your installation.\n";
168    } 
169    else
170    {
171        $retval = $retval >> 8;
172        if ($retval)
173        {
174            print STDERR "ERROR\n";
175            print STDERR "  The following command produced an error message:\n";
176            print STDERR "  $cmd\n";
177            print STDERR "  Debug output follows:\n";
178            open(ERR, $ErrorFile);
179            while(<ERR>)
180            {
181                print STDERR "  | $_";
182                if (grep(/preferences.xml/,$_))
183                {
184                    $ExtraInfo=$ExtraInfo."\n * Inkscape preference file corrupt. Delete ~/.inkscape/preferences.xml to continue";
185                    addFault("fatal",1); ## this error is fatal because it needs human intervention before processing can continue
186                }
187                if (grep(/infinite template recursion/,$_))
188                {
189                    $ExtraInfo=$ExtraInfo."\n * Tile too complex for Xmlstarlet, possibly an excessively long way, or too many maplint errors";
190                }
191            }
192            close(ERR);
193            print STDERR $ExtraInfo."\n\n";
194        }
195        else
196        {
197            $ok = 1;
198        }
199    }
200   
201    killafile($ErrorFile);
202    return $ok;
203}
204
205#-----------------------------------------------------------------------------
206# Delete a file if it exists
207#-----------------------------------------------------------------------------
208sub killafile($){
209  my $file = shift();
210  unlink $file if(-f $file);
211}
212
213#-----------------------------------------------------------------------------
214# GET a URL and save contents to file
215#-----------------------------------------------------------------------------
216sub DownloadFile 
217{
218    my ($URL, $File, $UseExisting) = @_;
219
220    my $ua = LWP::UserAgent->new(keep_alive => 1, timeout => 1800);
221    $ua->agent("tilesAtHome");
222    $ua->env_proxy();
223
224    if(!$UseExisting) 
225    {
226        killafile($File);
227    }
228    # Note: mirror sets the time on the file to match the server time. This
229    # is important for the handling of JobTime later.
230        $ua->mirror($URL, $File);
231
232    doneMessage(sprintf("done, %d bytes", -s $File));
233}
234
235#-----------------------------------------------------------------------------
236# Merge multiple OSM files into one, making sure that elements are present in
237# the destination file only once even if present in more than one of the input
238# files.
239#
240# This has become necessary in the course of supporting maplint, which would
241# get upset about duplicate objects created by combining downloaded stripes.
242#-----------------------------------------------------------------------------
243sub mergeOsmFiles
244{
245    my ($destFile, $sourceFiles) = @_;
246    my $existing = {};
247
248    # If there's only one file, just copy the input to the output
249    if( scalar(@$sourceFiles) == 1 )
250    {
251      copy $sourceFiles->[0], $destFile;
252      killafile ($sourceFiles->[0]) if (!$Config{Debug});
253      return;
254    }
255   
256    open (DEST, "> $destFile");
257
258    print DEST qq(<?xml version="1.0" encoding="UTF-8"?>\n);
259    my $header = 0;
260
261    foreach my $sourceFile(@{$sourceFiles})
262    {
263        open(SOURCE, $sourceFile);
264        while(<SOURCE>)
265        {
266            next if /^\s*<\?xml/;
267            # We want to copy the version number, but only the first time (obviously)
268            # Handle where the input doesn't have a version
269            if (/^\s*<osm.*(?:version=([\d.'"]+))?/)
270            {
271              if( not $header )
272              {
273                my $version = $1 || "'".$Config{"OSMVersion"}."'";
274                print DEST qq(<osm version=$version generator="tilesGen mergeOsmFiles">\n);
275                $header = 1;
276              }
277              next;
278            }
279            last if (/^\s*<\/osm>/);
280            if (/^\s*<(node|segment|way|relation) id="(\d+)".*(.)>/)
281            {
282                my ($what, $id, $slash) = ($1, $2, $3);
283                my $key = substr($what, 0, 1) . $id;
284                if (defined($existing->{$key}))
285                {
286                    # object exists already. skip!
287                    next if ($slash eq "/");
288                    while(<SOURCE>)
289                    {
290                        last if (/^\s*<\/$what>/);
291                    }
292                    next;
293                }
294                else
295                {
296                    # object didn't exist, note
297                    $existing->{$key} = 1;
298                }
299            }
300            print DEST;
301        }
302        close(SOURCE);
303        killafile ($sourceFile) if (!$Config{Debug});
304    }
305    print DEST "</osm>\n";
306    close(DEST);
307}
308
309
310#-----------------------------------------------------------------------------
311# Clean up temporary files before exit, then exit or return with error
312# depending on mode (loop, xy, ...)
313#-----------------------------------------------------------------------------
314sub cleanUpAndDie
315{
316    my ($Reason,$Mode,$Severity,$mainPID) = @_;
317
318    ## TODO: clean up *.tempdir too
319
320    print STDERR "\nExiting from $Reason\n" if ($Config{"Verbose"});
321
322    if (! $Config{"Debug"}) 
323    {
324        opendir (TEMPDIR, $Config{"WorkingDirectory"});
325        my @files = grep { /$mainPID/ } readdir(TEMPDIR); # FIXME: this will get files from other processes using the same Working Directory for low pids because the numbers will collide with tile coordinates
326        closedir (TEMPDIR);
327        while (my $file = shift @files)
328        {
329             print STDERR "deleting ".$Config{"WorkingDirectory"}."/".$file."\n" if ($Config{"Verbose"});
330             killafile($Config{"WorkingDirectory"}."/".$file);
331        }
332       
333    }
334   
335    return 0 if ($Mode eq "loop");
336    exit($Severity);
337}
338
3391;
340
Note: See TracBrowser for help on using the repository browser.