Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

Template::Latex Frustrations . . .

by hesco (Deacon)
on May 04, 2010 at 20:57 UTC ( [id://838381] : perlquestion . print w/replies, xml ) Need Help??

hesco has asked for the wisdom of the Perl Monks concerning the following question:

Enough of the frustrations. Past time I sought a few more eyeballs on this issue.

I have this project spread across three servers at the moment: my local sandbox, my testbed server and the production server. The code below has not been deployed yet to production. An earlier version of this code is running on the testbed server and generating both a valid pdf at example.pdf and a plain text file at the computed path and file name.

On my local sandbox machine, I get only a two '\n' linefeed file which my file command describes as: 'ASCII text', and ls reports as having a length of two bytes.

I have three times now in the past two days, scp'd the sort of working module, template and configuration file from testbed, back to my sandbox and used diff to compare them with the local code which is not working. No distinctions which would explain the different result are apparent to me.

My preference would be to render the pdf in place with the generated path and file name (to prevent a race condition where two or more users might over-write one anothers example.pdf before it was moved into place. But for the moment I'd be happy to merely see the example.pdf file generated on my local sandbox. But so far I have met with no luck on that front.

My template -- drawing directly from perldoc for Template::Latex, looks like this:

[% USE Latex %] [% FILTER latex('example.pdf') %] \documentclass[letterpaper,10pt]{article} \usepackage{marvosym} . . . \end{document} [% END %]
Removing the FILTER line breaks this on the testbed server. Any and all attempts to replace example.pdf with a variable fed from the module also breaks things.

My configuration file includes a stanza like this:

[pdf] include_path='/etc/ymd/client_name/tmpl/' template='weekly_report_pdf.tt' output_path='/home/reports/pdfs/' report_type='weekly/' output='wkly_rpt__' suffix='_w'
My module includes:

package My::Module; use warnings; use strict; use File::Path; use Template::Latex; use Template::Constants qw( :debug ); use Template::Filters; use base 'CGI::FormBuilder::Config::Simple'; sub new { my $class = shift; my $ini = shift; # creates a Config::Simple object; # creates a DBI::db object return $self; } sub render_pdf_report { my $self = shift; my $field = shift; my $template = $self->{'cfg'}->param("pdf.template"); $self->{'pdf_output_path'} = $self->{'cfg'}->param("pdf.output_path" +) . $field->{'region'} . '/' . $self->{'cfg'}->param("pdf.report +_type"); $self->{'pdf_output_path'} =~ s/\ /_/g; chomp($self->{'pdf_output_path'}); unless( -d $self->{'pdf_output_path'} ){ mkpath $self->{'pdf_output_path'}; } $self->{'pdf_output'} = 'wkly_rpt_' . $field->{'region'} . '_' . $fi +eld->{'report_id'} . $self->{'cfg'}->param("pdf.suffix") . '.pdf'; $self->{'pdf_output'} =~ s/\ /_/g; chomp($self->{'pdf_output'}); $field->{'pdf_output'} = $self->{'pdf_output'}; $self->{'latex_paths'} = Template::Latex->latex_paths(); $self->{'tt'} = Template::Latex->new({ DEBUG => DEBUG_FILTERS | DEBUG_PLUGINS, INCLUDE_PATH => $self->{'cfg'}->param("pdf.include_path") +, OUTPUT_PATH => $self->{'pdf_output_path'}, LATEX_FORMAT => 'pdf' }); $Template::Latex::DEBUG = 1; $self->{'tt'}->process($template,{ field => $field },$self->{'pdf_ou +tput'},binmode => 1) || die $self->{'tt'}->error(); my $tmp_file = $self->{'pdf_output_path'} . 'example.pdf'; my $file = $self->{'pdf_output_path'} . $self->{'pdf_output'}; rename $tmp_file, $file; return; }
Running my test script generates these debug messages in my console:

[Template::Filters] store(latex_encode, ARRAY(0x9157390)) [Template::Filters] store(latex, ARRAY(0x91573c0)) [Template::Plugins] fetch(Latex, <no args>, Template::Context=HASH(0x91036c0)) [Template::Plugins] loading Template::Plugin::Latex.pm (PLUGIN_NAME) [Template::Plugins] calling Template::Plugin::Latex->load() [Template::Plugins] Latex => Template::Plugin::Latex [Template::Filters] store(latex_encode, ARRAY(0x92022c8)) [Template::Filters] store(latex, ARRAY(0x9202288)) [Template::Filters] fetch(latex, [ example.pdf ], Template::Context=HASH(0x91036c0))
and results in the following results:

ok 6 - We have correct path to: ps2pdf ok 7 - We have correct path to: dvips ok 8 - We have correct path to: bibtex ok 9 - We have correct path to: pdflatex ok 10 - We have correct path to: makeindex ok 11 - We have correct path to: latex ok 12 - Generated correct file name ok 13 - Generated the correct file path ok 14 - The file exists not ok 15 - Our file is a pdf file # TODO Not yet successfully produci +ng our pdf files # Failed (TODO) test 'Our file is a pdf file' # at t/11-pdf-report.t line 64. # 'text/plain' # doesn't match '(?-xism:application/pdf)' not ok 16 - We replicated a correct pdf file. # TODO Not yet successfu +lly producing our pdf files # Failed (TODO) test 'We replicated a correct pdf file.' # at t/11-pdf-report.t line 66. # got: 'e1c06d85ae7b8b032bef47e42e4c08f9' # expected: 'c27f1cab0f2e44184ebd8ce5361db134'
Those disparate values on test #16 being the md5 checksums of the generated (empty) file and the sample file it should match.

Can anyone advise what I might be missing here, please?

All help is appreciated.

Thanks,
-- Hugh

if( $lal && $lol ) { $life++; }
if( $insurance->rationing() ) { $people->die(); }

Replies are listed 'Best First'.
Re: Template::Latex Frustrations . . .
by CountZero (Bishop) on May 05, 2010 at 06:07 UTC
    Hugh,

    I cannot help you directly with Template::Latex as I do not use that module --and it seems from the lack of response that few of us Monks do-- but I do use LaTeX quite a lot to produce standard reports from databases. The formatting done by LaTeX can't be beaten!

    Just like you I use Template::Toolkit to produce the LaTeX source file, but rather than running it through Template::Latex or Latex::Driver (which I found rather complicated to use) I use a nice little utility called latexmk which is a make-like utility (written in Perl!) specially made to compile LaTeX-files. I call it from within my Perl-script using backticks or the system command. It has a lot of switches to configure it exactly as you like. One of the more useful functions is a clean function to get rid of the lot of temporary files LaTeX uses.

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

      CountZero:

      Thank you kindly. That is exactly what was needed to move me off of stuck. I just deployed the app tonight. I believe it to be doing the trick as I write, based on feedback from three testers (including myself).

      And the working code looks like this:

      $self->{'tt'} = Template->new({ INCLUDE_PATH => $self->{'cfg'}->param("pdf.include_path"), OUTPUT_PATH => $self->{'cfg'}->param("pdf.tmp_path") }); $self->{'tt'}->process($template,{ field => $field },$self->{'pdf_ou +tput'} . '.tex',binmode => 1) || die $self->{'tt'}->error(); my $cwd = cwd(); chdir $self->{'cfg'}->param("pdf.tmp_path"); $ENV{'USER'} = $self->{'cfg'}->param("pdf.user"); $ENV{'HOME'} = $self->{'cfg'}->param("pdf.home"); `latexmk -pdf $tmp_file.tex`; chdir $cwd; rename "$tmp_file.pdf", $file; unlink <$tmp_file.*>; $self->{'pdf_output_file'} = $file; $self->{'pdf_output_file_name'} = $self->{'pdf_output'} . '.pdf';
      As I see this posted, it seems I ought to refactor some of my config paramters which no longer point to pdf files but now to tex files. But other than that, your solution moved me forward in rather quick style.

      This is meeting all of my requirements, with respect to filing the resulting file appropriately and avoiding the risk of race conditions which would corrupt our archives. I have control over what to name the files.

      So far, the only complaint I've had about latexmk is how noisy it has been when I'm running my test suite. I'll have to review the --help on that script again. I'll bet their is a switch to quiet it down. But it was an easy install. I would be more comfortable calling methods somehow, for some reason using backticks other than in a quick throw-away script makes me nervous. But I have no idea if there is any reason for that.

      With this trick, the only thing holding me back now is my rudimentary latex skills.

      But I'd guess this will give me more reason to practice with that.

      Thanks again for the lead.

      -- Hugh

      if( $lal && $lol ) { $life++; }
      if( $insurance->rationing() ) { $people->die(); }
        Pleased to have been able to assist!

        Indeed latexmk is very loud by nature. calling it as follows:

        $result = `latexmk -pdf -f -silent $filenaam`;
        will quite it down a bit, but not totally.

        I usually add the -f (force) option, so latexmk doesn't quit at the first unresolvable error it encounters.

        the only thing holding me back now is my rudimentary latex skills
        Perhaps we should found a "LaTeXmonks" site, but thay will perhaps attract the wrong type of people! ;-)

        CountZero

        A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James