rake4latex 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,156 @@
1
+ =begin rdoc
2
+ call_rake4latex.rb offers an easy and fast interface
3
+ to rake4latex.
4
+
5
+ Just call it from the shell:
6
+ call_rake4latex.rb my_file
7
+
8
+ my_file.tex will be compiled to my_file.pdf.
9
+
10
+ For details, please use the help:
11
+ call_rake4latex.rb -h
12
+
13
+ For complex documents you may want define your own rakefile
14
+ and use rake.
15
+
16
+ It is recommended to copy this file to a location in your
17
+ search path for executable files.
18
+ =end
19
+
20
+ require 'rake4latex'
21
+ require 'optparse'
22
+
23
+ #Anlegen des Parsers
24
+ opts = OptionParser.new()
25
+ opts.banner = "Usage: call_rake4latex.rb [options] filename" #Usage-zeile
26
+ opts.separator "Call LaTeX as often as needed."
27
+ opts.separator ""
28
+ opts.separator "Examples:"
29
+ opts.separator "call_rake4latex testdocument.pdf"
30
+ opts.separator " Create testdocument.pdf via pdflatex"
31
+ opts.separator " Starts only if testdocument.tex is newer then testdocument.pdf."
32
+ opts.separator ""
33
+ opts.separator "call_rake4latex -f testdocument"
34
+ opts.separator " Touch 'testdocument.tex' (set the modification date)"
35
+ opts.separator " Create testdocument.pdf via pdflatex"
36
+ opts.separator ""
37
+ opts.separator "Specific options:"
38
+
39
+ #
40
+ #List of task to be done after the TeX-call.
41
+ #
42
+ TASK_BEFORE_TeX = [] #only task where we need the filenem
43
+ TASK_AFTER_TeX = []
44
+ PARSE_MESSAGES = true
45
+
46
+
47
+ =begin
48
+ Shortcuts
49
+ =end
50
+ opts.on('-f', "--force", "Force an initial TeX-run") { |v|
51
+ TASK_BEFORE_TeX << :force
52
+ }
53
+
54
+ #
55
+ #fixme:
56
+ #Warum gibt es immer einen TeX-Lauf mit dieser Option?
57
+ #
58
+ opts.on('-d', '--dep', "--dependecies", "Build dependecies") { |v|
59
+ TASK_BEFORE_TeX << :dependecies
60
+ }
61
+ opts.on("-i", "--ignore", "--ignore-error", "Allow LaTeX errors") { |v|
62
+ puts "Allow LaTeX errors" if PARSE_MESSAGES
63
+ Rake.application.set_latexrunner_default(:texerrors_allowed, true)
64
+ }
65
+
66
+ opts.on("-s", "--statistic", "Show the statistic after TeX-run") { |v|
67
+ puts "Show the statistic after TeX-run" if PARSE_MESSAGES
68
+ TASK_BEFORE_TeX << :statistic #Set filename
69
+ TASK_AFTER_TeX << :statistic
70
+ }
71
+ opts.on("-c", "--clean", "Clean after TeX-run (delete auxiliary files)") { |v|
72
+ puts "Clean after TeX-run" if PARSE_MESSAGES
73
+ TASK_AFTER_TeX << :clean
74
+ }
75
+
76
+ =begin
77
+ Main options
78
+ =end
79
+ # Soll der Parameter Optional sein, kann [] verwendet werden.
80
+ opts.on("--touch FILE", "Touch FILE") { |v|
81
+ puts "Touch #{v.inspect}" if PARSE_MESSAGES
82
+ task :touch => v
83
+ task :default => :touch
84
+ }
85
+
86
+
87
+ #
88
+ opts.on("--task TASK", "Define a rake-task") { |v|
89
+ puts "Set task #{v.inspect}" if PARSE_MESSAGES
90
+ task :default => v
91
+ }
92
+
93
+ #
94
+ opts.on("--task_after TASK", "Define a rake-task after the TeX-run") { |v|
95
+ puts "Set task #{v.inspect} after LaTeX" if PARSE_MESSAGES
96
+ TASK_AFTER_TeX << v
97
+ }
98
+
99
+ =begin
100
+ LaTeXRunner-options
101
+ =end
102
+ #
103
+ opts.on("--maxrun MAXRUN", "Maximum MAXRUN TeX calls") { |v|
104
+ puts "Set maximum TeX-Runs #{v.inspect}" if PARSE_MESSAGES
105
+ Rake.application.set_latexrunner_default(:maxruns, v.to_i)
106
+ #~ LaTeXRunner::DEFAULT_SETTINGS[:maxruns] =
107
+ }
108
+
109
+ opts.on("-l", "--loglevel LEVEL", "Log Level for the logger (1=debug, 2=info(default), 3=warn 4=error)") { |v|
110
+ puts "Set loglevel to #{v.inspect}" if PARSE_MESSAGES
111
+ Rake.application.set_latexrunner_default(:loglevel, v.to_i)
112
+ }
113
+
114
+
115
+
116
+ #Parsen der Parameter mit Exception bei ung�ltigen Parametern
117
+ begin
118
+ opts.parse!
119
+ ARGV.each{|arg|
120
+ target = arg.ext('pdf')
121
+ puts "Define target #{target}"
122
+ set4clean(arg)
123
+ TASK_BEFORE_TeX.each{|task|
124
+ case task
125
+ when :force
126
+ puts "Force an initial TeX-run (touch #{target.ext('tex')})" if PARSE_MESSAGES
127
+ task (:touch => target.ext('tex'))
128
+ task (:default => :touch)
129
+ when :dependecies
130
+ puts "Build dependecies for #{target.ext('tex')}" if PARSE_MESSAGES
131
+ LaTeXDependencies.get_dependecies(target.ext('tex'), :inputs, :flat).each{|dep|
132
+ puts " => #{dep.inspect}" if PARSE_MESSAGES
133
+ task (target => dep)
134
+ }
135
+ when :statistic
136
+ task (:statistic => target.ext('tex'))
137
+ else
138
+ raise ArgumentError, "Undefined option #{task.inspect}"
139
+ end
140
+ }
141
+ task( :default => target )
142
+ }
143
+ rescue OptionParser::MissingArgument, OptionParser::InvalidOption => err
144
+ puts "Error:\t#{err}"
145
+ #Ausgabe der Schnittstelle
146
+ puts opts
147
+ end
148
+
149
+ #
150
+ #Set tasks after the LaTeX-call
151
+ TASK_AFTER_TeX.each{|task|
152
+ task (:default => task)
153
+ }
154
+
155
+ app = Rake.application
156
+ app[:default].invoke
data/lib/rake4latex.rb ADDED
@@ -0,0 +1,377 @@
1
+ =begin rdoc
2
+ ==Introduction
3
+ This file contains definitions to build a rakefile for LaTeX-documents.
4
+
5
+ A not-so minimal rakefile looks like this:
6
+ require 'rake4latex'
7
+ #Needed for some actions without a previous TeX-call
8
+ task :basefile => 'testdocument.tex'
9
+ #We want to build a PDF
10
+ file 'testdocument.pdf' => 'testdocument.tex'
11
+
12
+ #Force the compilation
13
+ task :touch => 'testdocument.tex'
14
+
15
+ #Define the default tasks
16
+ task :default => :touch
17
+ task :default => 'testdocument.pdf'
18
+ task :default => :statistic
19
+ task :default => :clean
20
+
21
+ #Make the rakefile self-executable
22
+ if $0 == __FILE__
23
+ app = Rake.application
24
+ app[:default].invoke
25
+ end
26
+
27
+ You can generate this template with:
28
+ require 'rake4latex'
29
+ puts Rake4LaTeX.template( [basename] )
30
+
31
+ ==Multiple runs
32
+ One of the problems with writing a Makefile for LaTeX is that often latex needs
33
+ to be run more than once on the same file, before obtaining the final output.
34
+ Moreover, every LaTeX package may require other runs basing on different conditions
35
+ and maybe even requiring some other program to be run between latex invocations.
36
+
37
+ Makefile normally expect a defined sequence of prerequisites.
38
+ Prerequisites are known before the action takes care.
39
+ Some dependecies of (La)TeX-documents creates ther prerequisites after the
40
+ (La)TeX-run (e.g. new index entries).
41
+
42
+ The approach followed here is to define "Post-Prerequisites".
43
+ The virtual target :latex_dependecies contains all this "Post-Prerequisites".
44
+ After a TeX-run, each Post-Prerequisites is checked.
45
+ For each post-prerequisites you must define a rule (in the following called postprereq.
46
+
47
+ The prerequisites of postprereq are checked for changes.
48
+ To detect changes, the Hash-Code of the prerequisite-files before and after
49
+ the TeX-run are compared (the comparison of the time stamp makes no sense,
50
+ TeX always(*) recreate the files).
51
+
52
+ <small>*) Forget the \nofiles-command</small>
53
+
54
+ See the examples-section hot to define your own custom action.
55
+
56
+ To avoid problems of endless loops, a there's a maximum number of runs, which is
57
+ 5 by default. The user can change it in the runner.
58
+
59
+ ==Dependencies
60
+ You must define your dependencies your own (but there is a help to do so, see next next section)
61
+
62
+ Example:
63
+ file 'testdocument.dvi' => ['testdocument.tex', 'testincludes/testinclude1.tex']
64
+
65
+
66
+ ===Determine Dependecies: LaTeXDependencies.get_dependecies( )
67
+ You can automatically compute dependencies for the latex task:
68
+ LaTeXDependencies.new(filename).get_dependecies( *options )
69
+ Options may be:
70
+ * :inputs:
71
+
72
+ The input file (the one which is passed to latex) is read, and the arguments of the
73
+ <tt>\includeonly</tt>, <tt>\include</tt> and <tt>\input</tt> latex commands are
74
+ extracted. Each of this these files is scanned again for dependecies.
75
+
76
+ The result is a nested array with all dependecies.
77
+
78
+ * :flat:
79
+ The (nested) result is flatted and double entries are deleted.
80
+
81
+ You can use it already direct in your dependecies definition:
82
+ file 'testdocument.dvi' => LaTeXDependencies.new('testdocument.tex').get_dependecies( *options )
83
+
84
+ ===Dependecies for BibTeX
85
+ BibTeX depends on two files:
86
+ * aux file with the list of the cites.
87
+ * bib-file(s) with the data of the literature.
88
+
89
+ You can define the dependecies of bib-file in your rakefile:
90
+ file 'testdocument.pdf' => 'testdocument.bib'
91
+ file 'testdocument.bbl' => 'testdocument.bib'
92
+ You need both definietions.
93
+ The pdf-dependecy is needed to start a new TeX-run,
94
+ The bbl-dependecy is needed to start a new BibTeX-run.
95
+
96
+ ==Supported tools and packages
97
+
98
+ ===Supported tools
99
+ The following tools are supported by rake4latex:
100
+ * Makeindex with makeidx.sty
101
+ * BibTeX
102
+
103
+ ===Supported (checked) packages
104
+ The rake process to generate the document is independent of any
105
+ package.
106
+ But some packages requires additional TeX-runs.
107
+ The following packages are tested and work fine:
108
+ * minitoc
109
+ * longtable
110
+ * supertabular
111
+ * splitindex (splitindex is replaced by internal routines)
112
+
113
+ Untested packages:
114
+ * glossary
115
+ * multiind/index (not planned to check, please use splitindex or inform me about your need)
116
+
117
+ ==Adding new tasks
118
+ ===Normal tasks
119
+ Task to generate pictures or other stuff needed to
120
+ build your LaTeX project can be added like normal
121
+ rake-tasks.
122
+
123
+ ===TeX-related tasks
124
+ Some task must be executed after a TeX-run.
125
+ This tasks must be created with <tt>tex_postrule</tt>
126
+ instead of the rake-method <tt>rule</tt>.
127
+
128
+ The tasks for makeindex and bibTeX are already defined.
129
+
130
+ ====Example makeindex
131
+ An example for this tasks is makeindex.
132
+ After a TeX-run you must check, if there are are new or changed
133
+ index entries.
134
+
135
+ The makeindex-task looks like this:
136
+ desc "Call Makeindex"
137
+ tex_postrule '.ind' => '.idx' do |t|
138
+ sh "makeindex #{t.source}"
139
+ end
140
+
141
+ That's it to get an index.
142
+
143
+ After a TeX-run, the prerequisites of rule '.ind' is checked for changes
144
+ (Hash-Code of the idx-file before and after the TeX-Run).
145
+ If there is a change, the rule is called.
146
+ And if the .ind-file changed, an additional TeX-call is forced.
147
+
148
+ ====Example BibTeX
149
+ BibTeX is a bit more complicated:
150
+ tex_postrule '.bbl' => '.aux' do |t, args |
151
+ sh "bibtex #{t.source}"
152
+ end
153
+
154
+ With this rule, BibTeX is called every times the aux-file changed
155
+ (if we use BibTeX or not).
156
+ We need a modified pre-check, if the BibTeX-call is necessary:
157
+ tex_postrule_check '.bbl' do |args|
158
+ auxfile = args[:task].name.ext('aux')
159
+ File.exist?(auxfile) and #there is a aux-file
160
+ ( args[:checksums][auxfile] == :changed ) and #the aux-file changed
161
+ ( necessary and File.read(auxfile) =~ /bibdata/ )#and we use bibtex
162
+ end
163
+
164
+
165
+ See also section 'Multiple runs'
166
+
167
+ ==Known Bugs and Problems
168
+ *Only pdflatex/xelatex/lualatex/latex to create the target,
169
+ no ps-files, no ps2pdf.
170
+ **Intended for the next release
171
+ * Two runs for new documents, when only one is needed.\\
172
+ After the first run, the aux-file is created,
173
+ so rake4latex detect a reason to rerun.
174
+ Solution would be to make a log-file analyse.
175
+ ** No plan to solve it.
176
+ Not a big problem, and why you need a rakefile for such simple tex-files?
177
+ * No usage of kpsewhich\\
178
+ LaTeXDependencies#get_dependecies checks dependecies only relative to
179
+ the file location.
180
+ kpsewhich is not used.
181
+ ** Would be nice escpecially for BibTeX and scan for \bibliography{xxx}
182
+ ** Low priority
183
+
184
+ =end
185
+
186
+ <<weiter
187
+ fixmes
188
+ == weiterer Aufbau rake abh�ngigkeiten
189
+ - glossary
190
+ rule '.glo' => '.aux' '.glo' do |t|
191
+ (glossaries?)
192
+
193
+ ==task statistic/log-analyse
194
+
195
+ ==application::texrunner als array?
196
+
197
+ Rake.template(basename) erzeugt rakefile
198
+ app = Rake.application
199
+ #~ app.set_latexrunner_default(:maxruns, 1)
200
+ #~ app.set_latexrunner_default(:loglevel, Log4r::DEBUG)
201
+ #~ app.set_latexrunner_default(:texerrors_allowed, true)
202
+ app[:default].invoke
203
+
204
+ rail �berarbeiten
205
+
206
+ Compilierungswege dvi -> ps -> pdf
207
+
208
+ prob:
209
+ wie erkennen ob
210
+ - dvi2ps + ps2pdf
211
+ - dvipdfm
212
+
213
+ weiter
214
+
215
+
216
+ #~ ==Problems
217
+ #~ * the action which checks for changed references causes a second latex invocation
218
+ #~ every time the .aux file changes.
219
+ #~ I don't know enough of the contents of the
220
+ #~ .aux file to parse it, but I need to base the decision on it, because messages
221
+ #~ such as "rerun to get cross-references right" in the latex log file aren't
222
+ #~ reliable (for example, the when the hyperref package is used, they aren't
223
+ #~ produced)
224
+
225
+ require 'log4r'
226
+ #Create a dummy-Logger to define the constants Log4r::DEBUG...
227
+
228
+ Log4r::Logger.new("test")
229
+ #~ gem 'rake', '=0.8.7'
230
+ require 'rake'
231
+ require 'md5'
232
+
233
+ class Rake::Application
234
+ =begin rdoc
235
+ Sets a default option for the LaTeXRunner.
236
+
237
+ The options are stored and used for new LaTeXRunners.
238
+
239
+ Example:
240
+ app.set_latexrunner_default(:loglevel, Log4r::DEBUG)
241
+
242
+ You could also access LaTeXRunner::DEFAULT_SETTINGS directly.
243
+ But with this method you get also a check if the option exists.
244
+ =end
245
+ def set_latexrunner_default( key, option )
246
+ if ! LaTeXRunner::DEFAULT_SETTINGS.keys.include?(key)
247
+ raise ArgumentError, "Undefined key #{key.inspect} for LaTeXRunner" unless @latexrunner
248
+ @latexrunner.logger.warn("Undefined key #{key.inspect} for LaTeXRunner")
249
+ end
250
+ LaTeXRunner::DEFAULT_SETTINGS[key] = option
251
+ end
252
+ =begin rdoc
253
+ Get the related actual LaTeXRunner.
254
+ =end
255
+ attr_reader :latexrunner
256
+ =begin rdoc
257
+ Define a LaTeXRunner.
258
+
259
+ This LaTeXRunner may be used via Rake#application#latexrunner to get the logger.
260
+ =end
261
+ def latexrunner=( latexrunner )
262
+ raise ArgumentError, "LaTeXRunner is no LaTeXRunner but #{t.class}" unless latexrunner.is_a?(LaTeXRunner)
263
+ if @latexrunner
264
+ @latexrunner.logger.warn( "LaTeXRunner replaced by other runner")
265
+ end
266
+ @latexrunner = latexrunner
267
+ @latexrunner.logger.debug( "Set LaTeXRunner #{@latexrunner.main_file} as default runner in Rake::Application")
268
+ end
269
+ end #Rake::Application
270
+
271
+ =begin rdoc
272
+ Define the files to be deleted with clean and clobber.
273
+
274
+ There is no global definition to delete all files,
275
+ only the help file for the selected basename is taken.
276
+
277
+ Helpfiles for splitindex are not added. You can do it manual:
278
+ CLEAN.add("testdocument-*") #splitidx-helpfiles
279
+
280
+ This method is called by task 'basename'
281
+ =end
282
+ def set4clean( basename )
283
+ #fixme splitindex-dateien
284
+ FileList["#{basename.ext('*')}"].each do |file|
285
+ #Set the cleaning actions
286
+ case file
287
+ when /\.(tex)\Z/
288
+ when /\.(aux|log|out|toc|lot|lof|nav|snm)\Z/
289
+ CLEAN.include(file)
290
+ when /\.(maf|ptc\d*|mtc\d*|stc\d*)\Z/ #minitoc
291
+ CLEAN.include(file)
292
+ when /\.(ilg|idx|ind)\Z/ #Index-Files
293
+ CLEAN.include(file)
294
+ when /\.(blg|bbl)\Z/ #BibTeX-Files
295
+ CLEAN.include(file)
296
+ when /\.(rai|rao|RAO)\Z/ #Rail-Files
297
+ CLEAN.include(file)
298
+ when /\.(dvi|pdf|ps)\Z/
299
+ CLOBBER.include(file)
300
+ else
301
+ #~ @logger.warn("Unknown help file #{file}")
302
+ end
303
+ end
304
+ CLEAN.uniq!
305
+ CLOBBER.uniq!
306
+ end
307
+
308
+ =begin rdoc
309
+ Define a task to be executed after each TeX run.
310
+
311
+ The task name is added to LaTeXRunner::Post_Prerequisites.
312
+ LaTeXRunner#run_latex_once will loop on all tasks in LaTeXRunner::Post_Prerequisites.
313
+ =end
314
+ def tex_postrule(*args, &block)
315
+ #~ rules = rule(*args, &block)
316
+ Rake::Task.create_rule(*args, &block) #@rules << [pattern, deps, block]
317
+ #
318
+ if args.size == 1 #normal rule without arguments
319
+ LaTeXRunner::Post_Prerequisites << args.first.keys.first
320
+ else #rule with arguments (args.last is a hash with :needs)
321
+ LaTeXRunner::Post_Prerequisites << args.first
322
+ end
323
+ end
324
+ =begin rdoc
325
+ Define a procedure to decide, if the post process should be
326
+ called.
327
+
328
+ The task name is added to LaTeXRunner::Post_Prerequisites_check.
329
+ LaTeXRunner#run_latex_once will loop on all tasks in LaTeXRunner::Post_Prerequisites_check.
330
+
331
+ The block will be called with a hash, the block must accept this one parameter.
332
+
333
+ Inside the block you have access to:
334
+ * :task: The task for which you test.
335
+ * :checksums: the checksums of the files before the TeX-run.
336
+ * :logger: the logger of the related task
337
+
338
+ The block must return false or the reason for a call (e.g. "testdocument.aux changed")
339
+
340
+ Example: See BibTeX-definition.
341
+ =end
342
+ def tex_postrule_check(rulename, &block)
343
+ raise "No block for postrule_check #{rulename}" unless block_given?
344
+ raise "Wrong number of arguments for postrule_check #{rulename}" unless block.arity == 1
345
+ LaTeXRunner::Post_Prerequisites_check[rulename] ||= [] << block
346
+ end
347
+
348
+ #
349
+ #Load the sub-files
350
+ #
351
+ require 'rake4latex/clean' #modified rake/clean
352
+ require 'rake4latex/latexrunner'
353
+ require 'rake4latex/latexdependencies'
354
+ require 'rake4latex/splitindex'
355
+ require 'rake4latex/rules'
356
+ require 'rake4latex/tex_statistic'
357
+ require 'rake4latex/template'
358
+
359
+
360
+ #Do some development tests
361
+ if $0 == __FILE__
362
+ #~ require 'yaml'
363
+ #~ puts LaTeXRunner.find_included_files( 'test/testdocument.tex' ).to_yaml
364
+
365
+ task :acroread => 'test/testdocument.pdf'
366
+ #~ task :default => :acroread
367
+
368
+ #~ app = Rake.application
369
+ #~ app[:default].invoke
370
+
371
+ #~ LaTeXRunner.new(
372
+ #~ :main_file => 'test/testdocument.tex',
373
+ #~ :maxruns => 1.0/0,
374
+ #~ :program => :latex,
375
+ #~ :dummy => nil
376
+ #~ )
377
+ end