rake4latex 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/{call_rake4latex.rb → bin/call_rake4latex.rb} +6 -3
  2. data/{readme_call_rake4latex.txt → bin/readme_call_rake4latex.txt} +0 -0
  3. data/lib/rake4latex.rb +106 -42
  4. data/lib/rake4latex/analyse_texfile.rb +375 -0
  5. data/lib/rake4latex/base.rb +40 -10
  6. data/lib/rake4latex/latexrunner.rb +20 -7
  7. data/lib/rake4latex/rake4latex.yaml +4 -0
  8. data/lib/rake4latex/rules.rb +59 -26
  9. data/lib/rake4latex/tex_statistic.rb +405 -375
  10. data/lib/rake4latex_dtx.rb +83 -0
  11. data/readme.html +150 -28
  12. data/readme.txt +118 -20
  13. data/test/_expected/bibtex_test_build_rakefile.txt +49 -0
  14. data/test/_expected/dtx_test.txt +12 -0
  15. data/test/_expected/dtx_test_sty.txt +2 -0
  16. data/test/_expected/error_test.txt +4 -0
  17. data/test/_expected/error_test_ignore_error.txt +5 -0
  18. data/test/_expected/error_test_overview.txt +16 -0
  19. data/test/_expected/error_test_statistic.txt +3 -0
  20. data/test/_expected/gloss_test_build_rakefile.txt +56 -0
  21. data/test/_expected/includes_test_build_rakefile.txt +55 -0
  22. data/test/_expected/{rail_test_error.txt → rail_error_test.txt} +0 -0
  23. data/test/_expected/splitindex_test_build_rakefile.txt +56 -0
  24. data/test/_expected/supertabular_test_statistic.txt +2 -29
  25. data/test/_expected/varioref_test.txt +6 -0
  26. data/test/_expected/varioref_test_ignore_error.txt +11 -0
  27. data/test/_expected/z_complex_test_overview.txt +62 -0
  28. data/test/_expected/z_complex_test_statistic.txt +9 -0
  29. data/test/bibtex/rakefile.rb +6 -0
  30. data/test/dtx/rakefile.rb +31 -0
  31. data/test/error/rakefile.rb +32 -0
  32. data/test/error/testdocument.tex +14 -0
  33. data/test/gloss/rakefile.rb +9 -1
  34. data/test/includes/rakefile.rb +6 -0
  35. data/test/rail/rakefile.rb +1 -5
  36. data/test/rail_error/rakefile.rb +38 -0
  37. data/test/{rail → rail_error}/testrail_error.tex +0 -0
  38. data/test/splitindex/rakefile.rb +8 -1
  39. data/test/supertabular/rakefile.rb +2 -2
  40. data/test/unittest_rake4latex.rb +61 -72
  41. data/test/unittest_rake4latex_testcases.rb +79 -0
  42. data/test/varioref/rakefile.rb +37 -0
  43. data/test/varioref/testdocument.tex +33 -0
  44. data/test/z_complex/rakefile.rb +3 -1
  45. metadata +42 -10
  46. data/lib/rake4latex/latexdependencies.rb +0 -105
  47. data/lib/rake4latex/template.rb +0 -60
@@ -9,8 +9,20 @@ require 'rake'
9
9
  require 'md5'
10
10
  require 'log4r' #1.0.5
11
11
 
12
+ module Rake
13
+ class Task
14
+ =begin rdoc
15
+ Define and get the related TeXRunner.
16
+ The value is set by Rake4LaTeX::LaTeXRunner#run_latex_once
17
+ and can be used by the tex_postrule.
18
+ =end
19
+ attr_accessor :texrunner
20
+ end
21
+ end
22
+
23
+
12
24
  module Rake4LaTeX
13
- VERSION = '0.1.0'
25
+ VERSION = '0.1.1'
14
26
 
15
27
  #With this creation we define the constants Log4r::DEBUG...
16
28
  Logger = Log4r::Logger.new("LaTeXRunner")
@@ -47,7 +59,11 @@ But with this method you get also a check if the option exists.
47
59
  end
48
60
 
49
61
  =begin rdoc
50
- Load the Programs with parameters for Rake4LaTeX.build_cmd.
62
+ Definition of the programms and there call parameters.
63
+
64
+ There is a basic definition, you may redefine the values with your
65
+ local definitions.
66
+ You can define your local definition in a file 'rake4latex.yaml'.
51
67
 
52
68
  Each program is a Hash:
53
69
  program:
@@ -59,18 +75,22 @@ Each program is a Hash:
59
75
  optional: flag, if the parameter is optional.
60
76
  space_separated: between name and value is a space.
61
77
  =end
78
+ Programms = {}
62
79
 
63
- #fixme: incremental reading: global + local overwrites
80
+ =begin rdoc
81
+ Load the Programs with parameters for Rake4LaTeX.build_cmd.
82
+ =end
64
83
  [
65
84
  "#{File.dirname(__FILE__)}/rake4latex.yaml",
66
85
  #ocra-settings:
67
86
  #a src\lib\rake4latex\rake4latex.yaml
68
87
  #a lib\ruby\gems\1.8\gems\rake4latex-0.1.0\lib\rake4latex\base.rb
69
88
  "#{File.dirname(__FILE__)}/../../../../../../../../src/lib/rake4latex/rake4latex.yaml", #for ocra-version (exe)
89
+ "./rake4latex.yaml", #local re-definition
70
90
  ].each{| setting_file |
71
91
  if File.exist?(setting_file)
72
- Programms = YAML.load(File.read(setting_file))
73
- break
92
+ #Take the "more local" definition.
93
+ Programms.replace(YAML.load(File.read(setting_file)).merge(Programms))
74
94
  end
75
95
  }
76
96
  if ! defined? Programms
@@ -86,9 +106,13 @@ Bases is the configuration in Programms.
86
106
  'parameters' contains the parameters for the call.
87
107
  The keys must fit to the settings in Rake4LaTeX::Programms .
88
108
  =end
89
- def self.build_cmd( programm, parameters = {} )
109
+ def self.build_cmd( programm, parameters = {}, task = nil )
90
110
 
91
- configuration = Programms[programm]
111
+ if task #take the LaTeXRunner specific settings
112
+ configuration = task.texrunner.programms[programm]
113
+ else #take the global settings
114
+ configuration = Programms[programm]
115
+ end
92
116
  if ! configuration
93
117
  Rake4LaTeX::Logger.fatal( "No configuration for #{programm.inspect}") if Rake4LaTeX::Logger.fatal?
94
118
  return false
@@ -122,7 +146,7 @@ only the help file for the selected basename is taken.
122
146
  Helpfiles for splitindex are not added. You can do it manual:
123
147
  CLEAN.add("testdocument-*") #splitidx-helpfiles
124
148
 
125
- This method is called by task 'basename'
149
+ This method is called by task 'basename'.
126
150
  =end
127
151
  def self.set4clean( basename )
128
152
  #fixme splitindex-dateien
@@ -136,12 +160,16 @@ This method is called by task 'basename'
136
160
  CLEAN.include(file)
137
161
  when /\.(ilg|idx|ind)\Z/ #Index-Files
138
162
  CLEAN.include(file)
163
+ when /\.(glo|gls)\Z/ #Glossary-Files
164
+ CLEAN.include(file)
139
165
  when /\.(blg|bbl)\Z/ #BibTeX-Files
140
166
  CLEAN.include(file)
141
167
  when /\.(rai|rao|RAO)\Z/ #Rail-Files
142
168
  CLEAN.include(file)
143
169
  when /\.(dvi|pdf|ps)\Z/
144
170
  CLOBBER.include(file)
171
+ when /\.overview.txt\Z/ #rake4latex, task :log_overview
172
+ CLOBBER.include(file)
145
173
  else
146
174
  #~ @logger.warn("Unknown help file #{file}")
147
175
  end
@@ -158,6 +186,8 @@ Define a task to be executed after each TeX run.
158
186
 
159
187
  The task name is added to LaTeXRunner::Post_Prerequisites.
160
188
  LaTeXRunner#run_latex_once will loop on all tasks in LaTeXRunner::Post_Prerequisites.
189
+
190
+ In the task definition you have access to the TeXRunner via Rake::Task#texrunner .
161
191
  =end
162
192
  def tex_postrule(*args, &block)
163
193
  #~ rules = rule(*args, &block)
@@ -181,6 +211,7 @@ The block will be called with a hash, the block must accept this one parameter.
181
211
  Inside the block you have access to:
182
212
  * :task: The task for which you test.
183
213
  * :checksums: the checksums of the files before the TeX-run.
214
+ * :texrunner: The actual TeXRunner, calling the pre-check.
184
215
  * :logger: the logger of the related task
185
216
 
186
217
  The block must return false or the reason for a call (e.g. "testdocument.aux changed")
@@ -198,8 +229,7 @@ end
198
229
  #
199
230
  require 'rake4latex/clean' #modified rake/clean
200
231
  require 'rake4latex/latexrunner'
201
- require 'rake4latex/latexdependencies'
232
+ require 'rake4latex/analyse_texfile'
202
233
  require 'rake4latex/splitindex'
203
234
  require 'rake4latex/rules'
204
235
  require 'rake4latex/tex_statistic'
205
- require 'rake4latex/template'
@@ -1,5 +1,3 @@
1
-
2
-
3
1
  module Rake4LaTeX
4
2
  =begin rdoc
5
3
  Class which encapsulates all the information needed to call latex
@@ -70,12 +68,17 @@ The settings contain the following values:
70
68
  #~ @logger = Log4r::Logger.new("LaTeXRunner #{settings[:main_file]}")
71
69
  #~ @logger.outputters = Log4r::StdoutOutputter.new('log_stdout')
72
70
 
71
+ #Copy the programms.
72
+ #This allows us to overwrite the program settings for a special LaTeXRunner.
73
+ @programms = Programms.dup
74
+
73
75
  DEFAULT_SETTINGS.merge(settings).each{|key, value|
74
76
  #~ puts "#{key}: #{value}"
75
77
  case key
76
78
  when :main_file; @main_file = value
77
79
  when :maxruns; @maxruns = value
78
80
  when :program; self.program = value
81
+ when :programms; @programms.merge!(value)
79
82
  when :options; @options = value
80
83
  when :loglevel; @logger.level = value
81
84
  when :texerrors_allowed; @texerrors_allowed = value
@@ -121,9 +124,12 @@ The settings contain the following values:
121
124
  # The full path of the input directory. It is determined automatically during initialization
122
125
  attr_reader :full_input_dir
123
126
 
124
- # The looger for the LaTeX-Run.
127
+ # The logger for the LaTeX-Run.
125
128
  attr_reader :logger
126
129
 
130
+ # Hash with Programm settings. by default Rake4LaTeX::Programms.
131
+ attr_reader :programms
132
+
127
133
  # Flag if TeX should be started again.
128
134
  def rerun_necessary?()
129
135
  @rerun_necessary and ( maxruns > @texruns )
@@ -158,7 +164,7 @@ The settings contain the following values:
158
164
  run_latex_once(cmd)
159
165
  end
160
166
  end
161
- #Guarentee that help files are deleted fin clean.
167
+ #Guarentee that help files are deleted in clean.
162
168
  Rake4LaTeX.set4clean( @basename )
163
169
 
164
170
  plural_s = "#{@texruns} run#{@texruns>1 ? 's': ''}"
@@ -188,8 +194,10 @@ The settings contain the following values:
188
194
  latex_output = `#{cmd}`
189
195
  if $? != 0
190
196
  @logger.fatal("There where #@program errors. See #{@main_file.ext('.log')} for details")
191
- raise RuntimeError, "There where #@program errors. "\
192
- "See #{@main_file.ext('.log')} for details" unless @texerrors_allowed
197
+ #~ @logger.fatal("Errors: #{TeX_Statistic.new(@main_file.ext('.log')).stat[@main_file.ext('.log')][:latex_errors].inspect}")
198
+ #~ raise RuntimeError, "There where #@program errors. "\
199
+ #~ "See #{@main_file.ext('.log')} for details" unless @texerrors_allowed
200
+ exit unless @texerrors_allowed
193
201
  end
194
202
 
195
203
  helpfiles = %w{aux toc lof lot}
@@ -247,6 +255,8 @@ The settings contain the following values:
247
255
  next
248
256
  end
249
257
 
258
+ post_prereq.texrunner = self #Set the connection to the TeXRunner
259
+
250
260
  #Starts only, if prerequisites of post_prereq exist and was regenerated by TeX.
251
261
  #Here we make an additional check if we need the post_prereq.
252
262
  post_prereq.prerequisites.each{|post_prereq_pre|
@@ -256,7 +266,10 @@ The settings contain the following values:
256
266
  @logger.debug("Make precheck for #{pre}" )
257
267
  Post_Prerequisites_check[pre].each{|precheck|
258
268
  #Call the pre-check with the task...
259
- reason4call = precheck.call(:task => post_prereq, :checksums => checksums, :logger => @logger)
269
+ reason4call = precheck.call( :task => post_prereq,
270
+ :checksums => checksums,
271
+ :texrunner => self,
272
+ :logger => @logger)
260
273
  break if reason4call #we need only one reason to start the task.
261
274
  }
262
275
  else #make the standard check (
@@ -20,16 +20,20 @@ latex:
20
20
  - value_key: :filename
21
21
  makeindex:
22
22
  cmd: makeindex
23
+ comment: makeindex -s style.ist -t base.glg -o base.gls base.glo
23
24
  parameters:
24
25
  - name: -s
25
26
  value_key: :format
26
27
  optional: true
28
+ space_separated: true
27
29
  - name: -o
28
30
  value_key: :file_out
29
31
  optional: true
32
+ space_separated: true
30
33
  - name: -t
31
34
  value_key: :file_log
32
35
  optional: true
36
+ space_separated: true
33
37
  - value_key: :file_in
34
38
  pdflatex:
35
39
  cmd: pdflatex
@@ -51,21 +51,51 @@ task :basefile do |task|
51
51
  end
52
52
  task :default => :basefile
53
53
 
54
+ desc "Build a log-overview file"
55
+ task :log_overview => :basefile do
56
+ Rake.application[:statistic].prerequisites.each{|pre|
57
+ next if pre == 'basefile' #exclude task :basefile
58
+ stat = Rake4LaTeX::TeX_Statistic.new(pre)
59
+ #Filename also used in set4clean
60
+ File.open("#{pre.ext()}.overview.txt", 'w'){|f|
61
+ f << stat.overview()
62
+ }
63
+ }
64
+ end
65
+
66
+ desc "Archive all log-files to zip-file"
67
+ task :log_archive => :basefile do
68
+ require 'zip/zipfilesystem'
69
+ Zip::ZipFile.open("rake4latex_log_archive.zip", Zip::ZipFile::CREATE ){|zip|
70
+ puts "Pack #{zip.name}"
71
+ #Store all Files to be deleted
72
+ CLEAN.each{|filename|
73
+ zip.file.open(File.basename(filename), 'w'){|f| f << File.open(filename,"rb") {|io| io.read} }
74
+ }
75
+ Rake.application[:statistic].prerequisites.each{|pre|
76
+ next if pre == 'basefile' #exclude task :basefile
77
+ stat = Rake4LaTeX::TeX_Statistic.new(pre)
78
+ zip.file.open("#{pre}.overview.txt", 'w'){|f|
79
+ f << stat.overview()
80
+ }
81
+ }
82
+ } #close zip-file
83
+ end
54
84
 
55
85
  #
56
86
  #Reset the timestamp of a file (can be used to force the first compilation)
57
87
  #
58
88
  desc "Touch - reset timestamp"
59
- task :touch do |t|
60
- t.prerequisites.each{|pre|
89
+ task :touch do |task|
90
+ task.prerequisites.each{|pre|
61
91
  FileUtils.touch(pre)
62
92
  }
63
93
  end
64
94
 
65
95
  desc "Build a dvi-file with LaTeX"
66
- rule '.dvi' => '.tex' do |t|
96
+ rule '.dvi' => '.tex' do |task|
67
97
  runner = Rake4LaTeX::LaTeXRunner.new(
68
- :main_file => t.source,
98
+ :main_file => task.source,
69
99
  :program => :latex,
70
100
  :dummy => nil
71
101
  )
@@ -73,9 +103,9 @@ rule '.dvi' => '.tex' do |t|
73
103
  end
74
104
 
75
105
  desc "Build a ps-file from dvi"
76
- rule '.ps' => '.dvi' do |t|
77
- Rake4LaTeX::Logger.info("Call dvips for <#{t.source}>")
78
- cmd = Rake4LaTeX.build_cmd( 'dvips', :filename => t.source )
106
+ rule '.ps' => '.dvi' do |task|
107
+ Rake4LaTeX::Logger.info("Call dvips for <#{task.source}>")
108
+ cmd = Rake4LaTeX.build_cmd( 'dvips', :filename => task.source )
79
109
 
80
110
  stdout, stderr = catch_screen_output{
81
111
  sh cmd
@@ -90,12 +120,13 @@ end
90
120
 
91
121
 
92
122
  desc "Call Makeindex"
93
- tex_postrule '.ind' => '.idx' do |t, args |
123
+ tex_postrule '.ind' => '.idx' do |task|
94
124
  #check for splitidx
95
- splitidx = Rake4LaTeX::Splitindex.new(t.source, Rake4LaTeX::Logger)
125
+ splitidx = Rake4LaTeX::Splitindex.new(task.source, Rake4LaTeX::Logger)
96
126
  if splitidx.makeindex? #standard index, no splitidx
97
127
  #makeindex writes to stderr -> catch it
98
- cmd = Rake4LaTeX.build_cmd( 'makeindex', :file_in => t.source )
128
+ cmd = Rake4LaTeX.build_cmd( 'makeindex', { :file_in => task.source }, task )
129
+ task.texrunner.logger.debug("\t#{cmd}")
99
130
  stdout, stderr = catch_screen_output{
100
131
  sh cmd
101
132
  }
@@ -150,57 +181,59 @@ tex_postrule_check '.bbl' do |args|
150
181
  end
151
182
 
152
183
  #Define the rule
153
- tex_postrule '.bbl' => '.aux' do |t|
154
- cmd = Rake4LaTeX.build_cmd( 'bibtex', :source => t.source )
184
+ tex_postrule '.bbl' => '.aux' do |task|
185
+ cmd = Rake4LaTeX.build_cmd( 'bibtex', {:source => task.source}, task )
186
+ task.texrunner.logger.debug("Call bibTeX: #{cmd}")
155
187
  stdout, stderr = catch_screen_output{
156
188
  puts `#{cmd}`
157
189
  }
158
190
  if $? != 0
159
- Rake4LaTeX::Logger.fatal("There where BibTeX errors. \n#{stdout}")
191
+ task.texrunner.logger.fatal("There where BibTeX errors. \n#{stdout}")
160
192
  end
161
193
  end
162
194
 
163
195
  #Support for rail
164
196
  #http://www.ctan.org/tex-archive/support/rail/
165
197
  desc "Call Rail"
166
- tex_postrule '.rao' => '.rai' do |t|
198
+ tex_postrule '.rao' => '.rai' do |task|
167
199
  #Rail works only with filenames with 8 characters.
168
200
  #So we use stdin.
169
- cmd = Rake4LaTeX.build_cmd( 'rail', :railfile => t.source )
170
- Rake4LaTeX::Logger.debug("Call rail: #{cmd}")
201
+ cmd = Rake4LaTeX.build_cmd( 'rail', :railfile => task.source )
202
+ task.texrunner.logger.debug("Call rail: #{cmd}")
171
203
  stdout, stderr = catch_screen_output{
172
204
  puts `#{cmd}`
173
205
  }
174
206
  error = false
175
207
  if $? != 0
176
- Rake4LaTeX::Logger.fatal("There where Rail errors.")
208
+ task.texrunner.logger.fatal("There where Rail errors.")
177
209
  error = true
178
210
  end
179
211
  stderr.each{|errline|
180
- Rake4LaTeX::Logger.error("Rail error: #{errline.strip}")
212
+ task.texrunner.logger.error("Rail error: #{errline.strip}")
181
213
  error = true
182
214
  }
183
215
  if error
184
- Rake4LaTeX::Logger.warn("No rail diagramms generated")
216
+ task.texrunner.logger.warn("No rail diagramms generated")
185
217
  else
186
218
  #Now we have to save the result and delete some stuff.
187
219
  stdout.sub!(/^(This is Rail.*)/, '%\1') #%This is Rail, Version 1.1 #0
188
220
  stdout.sub!(/^(\(stdin.*)/, '%\1')
189
221
  stdout.sub!(/^\)/, '%\1)') #last line
190
- File.open(t.source.ext('rao'), 'w'){|f| f << stdout }
222
+ File.open(task.source.ext('rao'), 'w'){|f| f << stdout }
191
223
  end
224
+ CLEAN.include(task.source)
225
+ CLEAN.include(task.name)
192
226
  end
193
227
 
194
228
 
195
-
196
-
197
229
  desc "Build a statistic for TeX project"
198
- task :statistic => :basefile do |t|
199
- puts "Statistics:"
200
- t.prerequisites.each{|pre|
230
+ task :statistic => :basefile do |task|
231
+ task.prerequisites.each{|pre|
201
232
  next if pre == 'basefile' #exclude task :basefile
202
233
  stat = Rake4LaTeX::TeX_Statistic.new(pre)
203
- puts stat
234
+ puts "Statistic for #{pre}:"
235
+ puts stat.stat_summary.map{|e| " #{e}"}
236
+ #~ puts stat
204
237
  }
205
238
  end
206
239
 
@@ -7,11 +7,92 @@ begin
7
7
  rescue LoadError
8
8
  require 'yaml'
9
9
  end
10
+
11
+ =begin fixmes
12
+ under/overfull:
13
+ * Grouping
14
+ * Grenzwert
15
+
16
+ Filesplit verbessern (testcase equal_log_analyse)
17
+ =end
18
+
19
+
10
20
  module Rake4LaTeX
21
+ =begin
22
+ Informations about one TeX-Message
23
+ =end
24
+ class TeXMessage
25
+ #List of supported message types.
26
+ TYPES = [
27
+ :latex_errors,
28
+ :latex_warnings,
29
+ :package_errors,
30
+ :package_warnings,
31
+ :warnings,
32
+ :output, :source_information, #for statistic
33
+ :overfull_boxes, :underfull_boxes,
34
+ ]
35
+ @@seq = 0
36
+ =begin rdoc
37
+ Define a new TeX-Message.
38
+
39
+ line: Source code line of the tex-file, where the message was created.
40
+ No number, may be something line '621-625'.
41
+ =end
42
+ def initialize(type, logline, message, details = {}, page = nil, source = nil, line = nil)
43
+ @type = type
44
+ #~ Rake4LaTeX::Logger.error("undefined TeX-message type #{@type.inspect}") if ! TYPES.include?(@type)
45
+ @message = message
46
+ @details = details
47
+ @page = page
48
+ @source = source
49
+ @line = line
50
+ @logline = logline
51
+ @nextlines = []
52
+ end
53
+ #Type of the message
54
+ #* Error
55
+ #* Warning
56
+ #* ...
57
+ attr_reader :type
58
+ #Message text of the message
59
+ attr_reader :message
60
+ #Hash with details for the message (special informations...)
61
+ attr_reader :details
62
+ #Next page in the generated document.
63
+ #The previous page should be the location, where the effect of the error should be visible.
64
+ attr_reader :page
65
+ #TeX-Sourcefile. Place, where the error should be corrected.
66
+ attr_reader :source
67
+ #Line in the TeX-Sourcefile. Place, where the error should be corrected.
68
+ #No number, may be something line '621-625'.
69
+ attr_accessor :line
70
+ #Line in the log line
71
+ attr_reader :logline
72
+ #Sort by line of occurence in the log.
73
+ def <=> ( mess )
74
+ @logline <=> mess.logline
75
+ end
76
+ #collect additional lines for the message.
77
+ attr_reader :nextlines
78
+ #Add the following line(s) to the message
79
+ def << (logline)
80
+ @nextlines << logline
81
+ end
82
+ end #TeXMessage
83
+
84
+ =begin rdoc
85
+ Get an overview on status of a generated TeX-Project.
86
+ * Analoyse log for
87
+ *LaTeX
88
+ *BibTeX if used
89
+ *makeindex if used
90
+ =end
11
91
  class TeX_Statistic
12
92
  #Define the main file for the log-analyse.
13
93
  def initialize( filename )
14
94
  @stat = {}
95
+ @texmessages = []
15
96
 
16
97
  @texfile = filename.ext('tex')
17
98
  if ! File.exist?(@texfile)
@@ -21,10 +102,10 @@ class TeX_Statistic
21
102
 
22
103
  #Analyse TeX-log
23
104
  if File.exist?(@texfile.ext('log'))
24
- @stat[@texfile.ext('log')] = log_analyse( File.read(@texfile.ext('log')))
105
+ @texmessages = log_analyse_content( File.read(@texfile.ext('log')),nil,nil)
106
+ @stat[@texfile.ext('log')] = texmessages2hash(:messages => @texmessages) #option , :page_info ??
25
107
  else
26
- @stat['_'] ||= {}
27
- @stat['_'][:log] = "No log-file #{File.read(@texfile.ext('log'))} found"
108
+ @stat[@texfile.ext('log')] ||= [ "No log-file #{@texfile.ext('log')} found" ]
28
109
  end #File.exist?(@texfile.ext('log'))
29
110
 
30
111
  #Analyse BibTeX-log
@@ -39,225 +120,229 @@ class TeX_Statistic
39
120
  }
40
121
 
41
122
  end
42
- #
123
+ #Hash with a status overview on the logs of the TeX-project.
43
124
  attr_reader :stat
44
- #Analyse the TeX-log file.
45
- #
46
- #The log-text is splitted into files and pages and analysed separatly.
47
- #
48
- # ----TESTVERSION----
49
- def log_analyse_by_file_page(logfilename)
125
+ #Array with TeXMessage-object. Contains messages of the TeX-log.
126
+ attr_reader :texmessages
127
+
128
+ #Regexp to detect new pages in result file.
129
+ #New pages looks like "[1.1\n" or [9.9]
130
+ PAGE_PATTERN = /^\[(\d+\.\d+)[\]\s]/
131
+ #Container for some data
132
+ #* count: numbers of open ( in file, needed to detect end of file
133
+ #* logcontent: Extract of the log-file, contains only the parts for the actual source file
134
+ #* logstart: Line in log-file
135
+ FILEDATA_STRUCT = Struct.new('FILEDATA', :name, :startpage, :logstart, :count, :logcontent )
136
+
137
+ =begin rdoc
138
+ Analyse the TeX-log file.
139
+
140
+ The log-text is splitted into files and pages and analysed separatly.
141
+
142
+ ----TESTVERSION----
143
+ Errors:
144
+ Somewhere is an offset 4 loglines
145
+ =end
146
+ def log_analyse_by_file(logfilename)
50
147
  log = File.read(logfilename)
51
148
  stat = {}
149
+ texmessages = []
150
+
52
151
 
53
152
  #Analyse log for page and source file
54
153
  page = nil #store the actual page
55
154
  file = nil #store the actual file
56
155
  filestack = [] #
57
- filecount = Hash.new(0) #numbers of open ( in file, needed to detect end of file
58
- filecontent = {nil => ''}#content of a file. The content of sub-includes are not part of this content.
156
+ filelist = { nil => FILEDATA_STRUCT.new(nil, 0, 0, 1, '' ) }
157
+ logline = 0
158
+ #~ filecount = Hash.new(0) #numbers of open ( in file, needed to detect end of file
159
+ #~ filestartpage = {} #Page, where the source is started.
160
+ #~ filecontent = {nil => ''}#content of a file. The content of sub-includes are not part of this content.
59
161
 
60
- #New pages looks like "[1.1\n" or [9.9]
61
- page_pattern = /^\[(\d+\.\d+)[\]\s]/
62
162
  # inputs looks like "(./filename_en.toc \n" or "(./filename.lot)"
63
- file_pattern = /\(((?:\.|c:)\/.*?)[\)\n]/
163
+ file_pattern = %r{\((?:\.|c:)\/.*?[\)\n]}
64
164
 
65
165
  #Splitt at the file- and page-patterns and at ( and )
66
166
  #If the ( ) are balanced, then we can detect a file end with )
67
167
  #
68
- log.split(/(#{file_pattern}|\(|\)|#{page_pattern})/ ).each{|x|
168
+ log.split(/(#{file_pattern}|\(|\)|#{PAGE_PATTERN})/ ).each{|x|
169
+ logline += x.count("\n")
69
170
  case x #x[0]
70
171
  when file_pattern
71
172
  if x[-1,1] == ')'
72
173
  #~ puts "open and close #{file} on page #{page} #{filestack.inspect}" if file =~ /^\./
174
+ filelist[file].logcontent << x
73
175
  else
176
+ filelist[file].logcontent << x
74
177
  file = x.strip.sub(/\(/,'')
75
178
  filestack << file
76
- filecount[file] += 1
77
- filecontent[file] = ''
179
+ filelist[file] = FILEDATA_STRUCT.new(file, page, logline, 1, '' )
78
180
  #~ puts "open #{file} on page #{page} #{filestack.inspect}" if file =~ /^\./
79
181
  end
80
- when page_pattern
182
+ when PAGE_PATTERN
81
183
  page = $1
184
+ #~ if x =~ /76/
185
+ #~ puts x.inspect
186
+ #~ puts page.inspect
187
+ #~ puts logline
188
+ #~ puts file
189
+ #~ end
190
+ filelist[file].logcontent << x
191
+ #Add page to all open log collection.
192
+ #Without this, we would ignore all pages between the insertion of an include.
193
+ filelist.each{| name, filedata | filedata.logcontent << "\n#{x} ##ADDED to log #{logline + 1}##\n" }
82
194
  when '('
83
- filecount[file] += 1
84
- filecontent[file] << x
85
- when ')'
86
- filecount[file] = filecount[file] - 1
87
- if filecount[file] == 0
195
+ filelist[file].count+= 1
196
+ filelist[file].logcontent << x
197
+ when ')'
198
+ filelist[file].count = filelist[file].count - 1
199
+ if filelist[file].count == 0
88
200
  filestack.pop
89
201
  #~ puts "close #{file} on page #{page} #{filestack.inspect}" if file =~ /^\./
90
- stat = log_analyse_content(filecontent[file], file, page)
202
+ texmessages.concat(log_analyse_content(filelist[file].logcontent, filelist[file].name, filelist[file].startpage, filelist[file].logstart ))
91
203
  if ! stat.empty?
92
204
  #hier stats sammeln (je vor/hinter input gab es meldungen)
93
- puts '============'
94
- puts file
95
- puts stat.to_yaml
205
+ #~ puts '============'
206
+ #~ puts file
207
+ #~ puts stat.to_yaml
96
208
  end
97
209
  #~ filecontent.delete(file)
98
- filecontent[file] = ''
210
+ filelist[file].logcontent = ''
99
211
  file = filestack.last
100
212
  else
101
- filecontent[file] << x
213
+ filelist[file].logcontent << x
102
214
  end
103
215
  else
104
- filecontent[file] << x
216
+ filelist[file].logcontent << x
105
217
  end
106
218
  #~ puts "%6s : %s" % [page, file ]
107
219
  }
108
- puts filestack.inspect
220
+ #Get unclear messages (top file?)
221
+ texmessages.concat(log_analyse_content(filelist[nil].logcontent, filelist[nil].name, filelist[nil].startpage, filelist[nil].logstart ))
222
+ #~ puts filestack.inspect
223
+ texmessages
109
224
  end
225
+ =begin rdoc
226
+ Analyse the content of an extract of the TeX-log file and
227
+ collect the messages as TeXMessage-objects.
110
228
 
111
- #Analyse the content of an extract of the TeX-log file.
112
- #
113
- def log_analyse_content(log, file, page)
114
- stat = {}
115
- filepage = [" (",
116
- file ? "in #{file}" : '',
117
- page ? " on page #{page}" : '',
118
- ")"].join
119
-
120
- log.each{|logline|
121
- logline.strip!
122
- case logline
123
- when /Package (.*) Error: (.*)/
124
- stat[:package_error] ||= {}
125
- stat[:package_error][$1] ||= [] << $2
126
- stat[:package_error][$1].last << filepage
127
- when /LaTeX Error:\s*(.*)/
128
- ( stat[:latex_error] ||= [] ) << $1
129
- stat[:latex_error].last << filepage
130
- when /Error:/
131
- (stat[:error] ||= [] ) << logline
132
- stat[:error].last << filepage
133
- #~ puts "!#{logline}"
134
- when /Package (.*) Warning: (.*)/
135
- stat[:package_warning] ||= {}
136
- stat[:package_warning][$1] ||= [] << $2
137
- stat[:package_warning][$1].last << filepage
138
- when /LaTeX Warning:\s*(.*)/
139
- (stat[:latex_warning] ||= [] ) << $1
140
- stat[:latex_warning].last << filepage
141
- when /Warning/
142
- #~ puts "!#{logline}"
143
- (stat[:warnings] ||= [] ) << logline
144
- stat[:warnings].last << filepage
145
- #~ when /Package (.*) Info: (.*)/ #A lot of messages
146
- #~ stat[:package_info] ||= {}
147
- #~ stat[:package_info][$1] ||= [] << $2
148
- when /Output written on (.*) \((\d*) pages, (\d*) bytes\)/
149
- raise "Double output in #{logfilename}" if stat[:output]
150
- stat[:output] = {
151
- :name => $1, :pages => $2, :bytes => $3,
152
- :kbytes => ($3.to_i / 1024 )
153
- }
154
- when /Overfull \\hbox \((.*) too wide\) in paragraph at lines (.*)/
155
- ( stat[:overfull] ||= [] ) << "#{$1} at lines #{$2}"
156
- stat[:overfull].last << filepage
157
- #~ next if $1.to_i() < @options[:overfull]
158
- #~ stat[:overfull] ||= [] << last_message = "#{$1} at lines #{$2}"
159
- #~ get_next_lines = 1 #?test
160
- when /Underfull (.*box) \(badness (.*)\) (detected|in paragraph) at lines? (.*)/
161
- #~ next if $1.to_i() < @options[:underfull]
162
- ( stat[:underfull] ||= [] )<< last_message = "badness #{$2} at lines #{$4}"
163
- stat[:underfull].last << filepage
164
- #~ get_next_lines = 1 #?test
165
- else
166
- #~ puts " #{logline}"
167
- end
168
- }
169
- stat
170
- end #log_analyse
171
-
172
-
173
- #Analyse the content of a TeX-log file.
174
- #
175
- def log_analyse(log)
176
- stat = {}
177
-
178
- log.each{|logline|
229
+ file, startpage and logstart are only needed for the splitted analyse to get the initial values.
230
+ =end
231
+ def log_analyse_content(log, file, startpage, logstart = 0)
232
+ page = startpage
233
+ messages =[]
234
+ linecorrection = logstart + 1
235
+ get_next_lines = nil
236
+ log.each_with_index{|logline, loc_lineno|
179
237
  logline.strip!
238
+ #Check if the message is continued on next line
239
+ case get_next_lines
240
+ when Numeric #Counter to add the next x lines to the previous message
241
+ messages.last << logline
242
+ if get_next_lines ==1
243
+ get_next_lines = nil
244
+ else
245
+ get_next_lines = get_next_lines - 1
246
+ end
247
+ next
248
+ when Regexp
249
+ if logline =~ get_next_lines
250
+ messages.last << $~.post_match
251
+ messages.last.line = $1 if logline =~ /on input line (\d+)/
252
+ next
253
+ else
254
+ get_next_lines = nil
255
+ end
256
+ end
257
+ lineno = loc_lineno + linecorrection
180
258
  case logline
259
+ when PAGE_PATTERN
260
+ page = $1
261
+ if logline =~ /##ADDED to log (\d+)##/
262
+ linecorrection = $1.to_i - loc_lineno - 1 #resync the log line number
263
+ end
181
264
  when /Package (.*) Error: (.*)/
182
- stat[:package_error] ||= {}
183
- stat[:package_error][$1] ||= [] << $2
265
+ messages << TeXMessage.new(:package_errors, lineno, $2, {:package => $1 }, page, file)
184
266
  when /LaTeX Error:\s*(.*)/
185
- ( stat[:latex_error] ||= [] ) << $1
267
+ messages << TeXMessage.new(:latex_errors, lineno, $1, {}, page, file)
186
268
  when /Error:/
187
- (stat[:error] ||= [] ) << logline
188
- #~ puts "!#{logline}"
269
+ messages << TeXMessage.new(:error, lineno, logline, {}, page, file)
189
270
  when /Package (.*) Warning: (.*)/
190
- stat[:package_warning] ||= {}
191
- stat[:package_warning][$1] ||= [] << $2
271
+ get_next_lines = /\(#{$1}\)\s*/
272
+ messages << TeXMessage.new(:package_warnings, lineno, $2, {:package => $1 }, page, file)
192
273
  when /LaTeX Warning:\s*(.*)/
193
- (stat[:latex_warning] ||= [] ) << $1
274
+ messages << TeXMessage.new(:latex_warnings, lineno, $1, {}, page, file)
194
275
  when /Warning/
195
- #~ puts "!#{logline}"
196
- (stat[:warnings] ||= [] ) << logline
197
- #~ when /Package (.*) Info: (.*)/ #A lot of messages
198
- #~ stat[:package_info] ||= {}
199
- #~ stat[:package_info][$1] ||= [] << $2
276
+ messages << TeXMessage.new(:warnings, lineno, logline, {}, page, file)
277
+ when /Package (.*) Info: (.*)/ #A lot of messages
278
+ messages << TeXMessage.new(:package_info, lineno, $2, {:package => $1 }, page, file)
200
279
  when /Output written on (.*) \((\d*) pages, (\d*) bytes\)/
201
280
  raise "Double output in #{logfilename}" if stat[:output]
202
- stat[:output] = {
203
- :name => $1, :pages => $2, :bytes => $3,
204
- :kbytes => ($3.to_i / 1024 )
205
- }
281
+ messages << TeXMessage.new(:output, lineno, logline, {
282
+ :name => $1, :pages => $2, :bytes => $3, :kbytes => ($3.to_i / 1024 )},
283
+ page, file)
206
284
  when /Overfull \\hbox \((.*) too wide\) in paragraph at lines (.*)/
207
- ( stat[:overfull] ||= [] ) << "#{$1} at lines #{$2}"
208
- #~ next if $1.to_i() < @options[:overfull]
209
- #~ stat[:overfull] ||= [] << last_message = "#{$1} at lines #{$2}"
210
- #~ get_next_lines = 1 #?test
285
+ #~ messages << TeXMessage.new(:overfull_boxes, lineno, "#{$1} at lines #{$2}", {:wide => $1.to_i }, page, file, $2)
286
+ messages << TeXMessage.new(:overfull_boxes, lineno, logline, {:wide => $1.to_i }, page, file, $2)
287
+ get_next_lines = 1
211
288
  when /Underfull (.*box) \(badness (.*)\) (detected|in paragraph) at lines? (.*)/
212
- #~ next if $1.to_i() < @options[:underfull]
213
- ( stat[:underfull] ||= [] )<< last_message = "badness #{$2} at lines #{$4}"
214
- #~ get_next_lines = 1 #?test
289
+ #~ messages << TeXMessage.new(:underfull_boxes, lineno, "badness #{$2} at lines #{$4}", {:badness => $2.to_i }, page, file, $4)
290
+ messages << TeXMessage.new(:underfull_boxes, lineno, logline, {:badness => $2.to_i }, page, file, $4)
291
+ get_next_lines = 1 #oder bis / []/
292
+ #fixme...
293
+ when /^!\s*(.*)/ #Undefined control sequence.
294
+ messages << TeXMessage.new(:latex_errors, lineno, $1, {}, page, file)
215
295
  else
216
296
  #~ puts " #{logline}"
217
297
  end
218
298
  }
219
- stat
299
+ messages
220
300
  end #log_analyse
221
- #Analyse the BibTeX-Logfile
301
+
302
+ =begin rdoc
303
+ Analyse a bibTeX-log.
304
+ =end
222
305
  def blg_analyse(logfilename)
223
306
  stat = {}
224
307
  File.readlines(logfilename).each{ |logline|
225
308
  case logline
226
309
  when /Database file #(.*): (.*)/
227
- stat[:info] ||= [] << "Database file #{$2} used"
310
+ stat[:source_information] ||= [] << "Database file #{$2} used"
228
311
  when /Warning--I didn't find a database entry for "(.*)"/
229
- stat[:warn] ||= [] << "Databaseentry #{$1} missing"
312
+ ( stat[:warnings] ||= [] ) << "Databaseentry #{$1} missing"
230
313
  when /Warning--Empty definition in (.*)/
231
- stat[:warn] ||= [] << "Empty definition #{$1}"
314
+ ( stat[:warnings] ||= [] ) << "Empty definition #{$1}"
232
315
  when /Warning--(.*)/
233
- stat[:warn] ||= [] << "#{$1}"
316
+ ( stat[:warnings] ||= [] ) << "#{$1}"
234
317
  when /I couldn't open (.*) file (.*)/
235
- stat[:error] ||= [] << "#{$1} #{$2} not found"
318
+ ( stat[:errors] ||= [] ) << "#{$1} #{$2} not found"
236
319
  when /I found no (.*) commands---while reading file(.*)/
237
- stat[:warn] ||= [] << "found no #{$1} in #{$2}"
320
+ ( stat[:warnings] ||= [] ) << "found no #{$1} in #{$2}"
238
321
  when /(.*)---line (.*) of file(.*)/
239
322
  #line-number ist unsinnig
240
- stat[:error] ||= [] << "#{$1} in #{$3}"
323
+ ( stat[:errors] ||= [] ) << "#{$1} in #{$3}"
241
324
  end
242
325
  }
243
326
  stat
244
- end #log_analyse
245
- #Analyse the makeindex-log
327
+ end #blg_analyse
328
+ =begin rdoc
329
+ Analyse the makeindex-log.
330
+ =end
246
331
  def ilg_analyse(logfilename)
247
332
  stat = {}
248
333
  error = nil
249
334
  File.readlines(logfilename).each{ |logline|
250
335
  if error #Index error announced in previous line
251
- stat[:error] ||= [] << "#{logline.chomp.sub(/.*--/, "")} #{error}"
336
+ ( stat[:errors] ||= [] ) << "#{logline.chomp.sub(/.*--/, "")} #{error}"
252
337
  error = nil
253
338
  else
254
339
  case logline
255
340
  when /Scanning input file (.*)\...done \((.*) entries accepted, (.*) rejected\)./
256
- #~ stat[:info] ||= [] << "input file #{$1} (#{$2} entries accepted, #{$3} rejected)"
257
- stat[:output] ||= []
258
- stat[:output] << "Input file: #{$1}"
259
- stat[:output] << "Entries accepted: #{$2}"
260
- stat[:output] << "Entries rejected: #{$3}"
341
+ #~ stat[:source_information] ||= [] << "input file #{$1} (#{$2} entries accepted, #{$3} rejected)"
342
+ stat[:source_information] ||= []
343
+ stat[:source_information] << "Input file: #{$1}"
344
+ stat[:source_information] << "Entries accepted: #{$2}"
345
+ stat[:source_information] << "Entries rejected: #{$3}"
261
346
  #~ when /done \((.*) entries accepted, (.*) rejected\)./
262
347
  #~ result[:rejected] += $2.to_i() if $2.to_i() > 0
263
348
  when /!! Input index error \(file = (.*), line = (.*)\):/
@@ -267,248 +352,193 @@ class TeX_Statistic
267
352
  end #if error
268
353
  }
269
354
  stat
270
- end #log_analyse
355
+ end #ilg_analyse
356
+
357
+ =begin rdoc
358
+ Define the defaults for TeX_Statistic#texmessages2hash
359
+ =end
360
+ Defaults_texmessages2hash = {
361
+ :messages => :texmessages, #replaced with @texmessages
362
+ :page_info => true,
363
+ :source_info => false,
364
+ :loglineno_info => true,
365
+ :nextlines_info => false,
366
+ }
271
367
 
272
- def to_s()
273
- <<stat
274
- #{@texfile}:
275
- #{@stat.to_yaml}
276
- stat
277
- end
278
- end #TeX_Statistic
279
- end #Rake4LaTeX
368
+ =begin rdoc
369
+ Take messages and convert them into a hash for quick analyses.
280
370
 
371
+ Options is a hash with flags, which informations should be added.
372
+ Defaults can be seen in Defaults_texmessages2hash.
373
+ =end
374
+ def texmessages2hash( options )
375
+ options = Defaults_texmessages2hash.dup.merge(options)
376
+ options[:messages] = @texmessages if options[:messages] == :texmessages
281
377
 
282
- if $0 == __FILE__
283
- require 'rake'
284
- #~ puts TeX_Statistic.new('../testdocument.tex')
285
- #~ puts TeX_Statistic.new('C:/usr/Festo/_Projects/PriceCatalog/PriceCatalogTool_en.pdf')
286
- s = TeX_Statistic.new('logtest_pcat/PriceCatalogTool_en.pdf')
287
- #~ puts s.stat['logtest_pcat/PriceCatalogTool_en.log'].to_yaml
288
-
289
- #Test
290
- #~ s.log_analyse_file_page('logtest_pcat/PriceCatalogTool_en.log')
291
- s.log_analyse_by_file_page('logtest_pcat/PriceCatalogTool_en.log')
292
- end
378
+ #Return-Hash.
379
+ #Collects the datas.
380
+ stat = {}
381
+ options[:messages].sort.each{|mess|
382
+ text = [ mess.message ]
383
+ if mess.source and options[:source_info]
384
+ text << " (#{mess.source}#{mess.line ? ":#{mess.line}" : '' })"
385
+ end
386
+ text << " [page#{mess.page}]" if mess.page and options[:page_info]
387
+ text << " [log##{mess.logline}]" if options[:loglineno_info]
388
+ text << " - #{mess.nextlines}" if options[:nextlines_info]
389
+ text = text.join()
390
+
391
+ case mess.type
392
+ when :package_info
393
+ next
394
+ when :package_warnings, :package_errors
395
+ stat[mess.type] ||= {}
396
+ (stat[mess.type][mess.details[:package]] ||= [] ) << text
397
+ else
398
+ ( stat[mess.type] ||= [] ) << text
399
+ end
400
+ }
401
+ stat
402
+ end #texmessages2hash
403
+ =begin rdoc
404
+ Build a very quick overview on actual status.
293
405
 
294
- __END__
406
+ Each tool gets one line.
295
407
 
296
- TeX:
297
- logfile.each{|logline|
298
- #The previous message is continued, get the rest here
299
- if get_next_lines > 0
300
- get_next_lines -= 1
301
- case logline
302
- #Get the line number
303
- when /l\.([0-9]*) (.*)/
304
- last_message << " #{$2} (line #{$1})".strip
305
- #fixme: get also next line (pdflualatex/invalid utf?)
306
- else
307
- last_message << " (#{logline.chomp()})"
308
- end
309
- last_message = nil
310
- next #continue with the next warning/error
311
- end #last_message
312
-
313
- #In case of errors, get the line number where it happens
314
- if jump_to_numberline
315
- case logline
316
- #skip text
317
- when /Type H <return> for immediate help./,
318
- /^[\.\s]*$/ #empty line
319
- #Get the line number
320
- when /l\.([0-9]*) (.*)/
321
- last_message << " #{$2} (line #{$1})".strip
322
- jump_to_numberline = false #numberline reached, continue with log-analyses
323
- #fixme: collect text in between?
324
- when /See the (.*) package documentation for explanation./
325
- last_message << " (package #{$1})"
326
- else
327
- last_message << " #{logline.strip} ||"
328
- end
329
- next #continue with the next warning/error
330
- end #jump_to_numberline = true; last_message = result[:error].last
408
+ Example:
409
+ - "Document: 14 errors, 15 warnings, 44 overfull boxes, 70 underfull boxes (testdocument.log)"
410
+ - "Bibliography: 1 error (testdocument.blg)"
411
+ - "Index: 21 entries (testdocument-changes.ilg)"
412
+ - "Index: 38 entries (testdocument-BMEcat.ilg)"
413
+ - "Index: 1 error (testdocument-idx.ilg)"
414
+ - "Index: 139 entries (testdocument-Fields.ilg)"
331
415
 
332
- last_message = nil
333
- $logline = logline #Only for test surposes
334
- case logline
335
- when /^! (.*)/
336
- case $1
337
- #Error messages with line code
338
- when /LaTeX Error:\s*(.*)/,
339
- /(Undefined control sequence.)/,
340
- /(Missing [\$|\{|\}|\\cr] inserted.)/,
341
- /(Dimension too large.)/,
342
- /(Text line contains an invalid utf-8 sequence.)/, #pdflualatex
343
- /(Argument of .* has an extra \})./,
344
- /(Paragraph ended before .* was complete.)/,
345
- /(Misplaced .+)/,
346
- /(Extra \}, or forgotten [\$|\\\\endgroup])/,
347
- /You can't use `\\\\end' in internal vertical mode/
348
- #~ /(! Emergency stop.)/,
349
- #~ /(! Huge page cannot be shipped out.)/
350
- :last_entry_to_avoid_comma_error
351
- result[:error] << last_message = $1
352
- jump_to_numberline = true;
353
- #LaTeX-Errors without line.
354
- when /(Emergency stop|Huge page cannot be.*)/,
355
- /(File ended while scanning use of .*)/,
356
- /(==> Fatal error occurred, no output PDF file produced!)/
357
- result[:error] << last_message = $1
358
- when /Package (.*) Error: (.*)/
359
- result[:error] << last_message = "#{$1}.sty:\t#{$2}"
360
- jump_to_numberline = true
361
- when /Extra alignment tab has been changed to \\cr./
362
- result[:error] << last_message = "tabular: wrong alignment"
363
- when /pdfTeX warning .*?: (.*)/
364
- result[:warning] << last_message = "pdftex: #{$1}"
365
- else
366
- result[:error] << last_message = "New error to runtex: #{logline.strip}"
367
- #~ jump_to_numberline = true; last_message = result[:error].last = result[:error].last
368
- @job.log.warn( "#{__FILE__} Uncatched error? <#{$1.inspect}>") if @job.log.warn?
369
- end
370
- when /(job aborted, no legal \\end found)/,
371
- /(==> Fatal error occurred, no output PDF file produced!)/
372
- result[:error] << last_message = $1
373
- when /Package gloss Info: Writing gloss file (.*).aux/ #Check for gloss.sty
374
- @job << BibTeX.new( @job, :source => "#{$1}.aux", :target => "#{$1}.bbl", :log => "#{$1}.blg" )
375
- when /Package hyperref Warning: old toc file detected, not used; run LaTeX again/
376
- @job.please_rerun("(old toc)")
377
- when /LaTeX Warning: Label(s) may have changed. Rerun to get cross-references right./
378
- @job.please_rerun("Labels/Toc changed")
379
- when /Package longtable Warning: Table widths have changed. Rerun LaTeX./
380
- @job.please_rerun("Longtable requires additional calculation)")
381
- when /LaTeX Warning: Label (.*)/
382
- result[:label]<< last_message = $1
383
- when /LaTeX Warning: (Reference .*)/
384
- result[:label]<< last_message = $1
385
- when /LaTeX Warning: Citation (.*)/
386
- result[:citation]<< last_message = $1
387
- when /LaTeX Warning: (.*)/
388
- result[:warning] << last_message = $1
389
- when /Package hyperref Warning: (.*)/
390
- result[:warning_hyper]<< last_message = "#{$1}"
391
- when /Package rail Warning: Railroad diagram \{(\d*)\} doesn't match on input line (\d*)./
392
- @job.log.debug( "#{@step} Rerun necessary (Rail diagram #{$1} on line #{$2})") if @job.log.debug?
393
- if @job.stop_rerun?(:rail)
394
- @job.log.warn( "#{@step} Rail-Rerun blocked by previous error") if @job.log.warn?
395
- else
396
- @job.please_rerun( "Rail diagram #{$1} on line #{$2} changed")
397
- @job << Rail.new( @job, :source => "#{@job.basename}.rai", :target => "#{@job.basename}.rao" )
398
- end
399
- when /Package rail Warning: Railroad diagram\(s\) may have changed./
400
- @job.log.debug( "#{@step} Rerun necessary (Rail diagram changed)") if @job.log.debug?
401
- if @job.stop_rerun?(:rail)
402
- @job.log.warn( "#{@step} Rail-Rerun blocked by previous error") if @job.log.warn?
403
- else
404
- @job.please_rerun( "Rail diagram changed")
405
- @job << Rail.new( @job, :source => "#{@job.basename}.rai", :target => "#{@job.basename}.rao" )
406
- end
407
- #~ when /Package: rail / #Package: rail 1998/05/19
408
- #~ @job.log.debug( "#{@step} Package rail detected") if @job.log.debug?
409
- #~ @job << Rail.new( @job ) ??
410
- when /Package (.*) Warning: (.*)/
411
- result[:warning] << last_message = "#{$1}:\t#{$2}"
412
- when /Using splitted index at (.*)/ ##Find Splittindex
413
- @job.log.debug( "#{@step} Found splitindex for #{$1}") if @job.log.debug?
414
- @job << Splitindex.new(@job, :source => $1 )
415
- #This message is posted, if index2 is used.
416
- #I hope the responsible person for index.sty will take my changes.
417
- #If the name is very long, there is a break in the Filename.
418
- when /Package index2 Info: (.*) (.*)/
419
- @job.log.debug( "#{@step} Index #{$1} detected (->#{$2})") if @job.log.debug?
420
- @job.log.warn( "#{@step} Warning: Name #{$2} perhaps cutted") if @job.log.warn? and $1.size != $2.size
421
- @job << Makeindex.new( @job,
422
- :name => "Index2-#{$1}",
423
- :file_in => $1, #"#{@job.basename}.idx",
424
- :file_out => $2, #"#{@job.basename}.ind",
425
- :file_log => "#{$1}.ilg"
426
- #~ :format => glossaries_format
427
- )
428
- #If you use index.sty:
429
- #Unfortenalty there are some missing information to complete the task.
430
- #Please use index2.sty
431
- when /Writing index file (\S*)/
432
- @job.log.debug( "#{@step} Index #{$1} detected") if @job.log.debug?
433
-
434
- if $1 == @job.basename + '.idx' #'normal' standard index
435
- name = 'Index'
436
- format = nil
437
- if @job.filename =~ /\.dtx$/
438
- name << '/dtx'
439
- format = 'gind.ist'
440
- end
441
- @job << Makeindex.new( @job,
442
- :name => name,
443
- :file_in => "#{@job.basename}.idx",
444
- :file_out => "#{@job.basename}.ind",
445
- :file_log => "#{@job.basename}.ilg",
446
- :format => format
447
- )
448
- else
449
- @job.log.warn( "#{@step} Warning: index.sty is not supported, please use index2 (#{$1})") if @job.log.warn?
450
- @job.helpfiles << $1
451
- end
452
- #This message is created by
453
- #- glossaries (-> already catched by aux-analyses)
454
- #- ltxdoc.cls (for dtx.files)
455
- when /Writing glossary file (\S*)/
456
- glossfile = $1
457
- @job.log.debug( "#{@step} Glossary #{glossfile} detected") if @job.log.debug?
458
-
459
- if @job.filename =~ /\.dtx$/ and glossfile =~ /.glo$/ #ltxdoc.cls
460
- @job << Makeindex.new( @job,
461
- :name => 'Glossary/dtx',
462
- :file_in => glossfile,
463
- :file_out => "#{@job.basename}.gls",
464
- :file_log => "#{@job.basename}.glg",
465
- :format => 'gglo.ist'
466
- )
467
- else
468
- #Possible with usage of glossaries.sty -> catched by aux-analyses
469
- @job.log.debug( "#{@step} Glossary in non-dtx found #{glossfile}") if @job.log.debug?
416
+ =end
417
+ def stat_summary()
418
+ result = []
419
+ @stat.each{|key, values|
420
+ stat = {}
421
+ values.each{|logkey,logvalues|
422
+ stat[key] ||= []
423
+ case logkey
424
+ when :source_information, :output
425
+ logvalues.each{|mess|
426
+ case mess
427
+ when /Entries accepted: (\d*)/
428
+ stat[:ok] = $1.to_i unless $1 == '0'
429
+ when /Entries rejected: (\d*)/
430
+ stat[:reject] = $1.to_i unless $1 == '0'
431
+ when /Database file (.+) used/
432
+ ( stat[:source] ||= [] ) << $1
433
+ when /Output written on .* \((\d*) pages, (\d*) bytes\)/
434
+ stat[:pages] = $1.to_i
435
+ when /Input file:/
436
+ else
437
+ #~ puts mess.inspect
438
+ end
439
+ }
440
+ when String
441
+ #~ stat[key] = logkey
442
+ puts logkey.inspect
443
+ raise "?Undefined String-Handling in stat_overview"
444
+ else #count messages
445
+ stat[logkey] = logvalues.size
470
446
  end
471
- #Add minitocs to helpfiles
472
- when /\(minitoc\)\s*Writing (.*\.mtc\d*)/
473
- @job.log.debug( "#{@step} Found minitoc-helpfile") if @job.log.debug?
474
- @job.helpfiles << $1
475
- when /Output written on (.*) \((.*) pages?, (.*) bytes\)/
476
- result[:file] = $1
477
- result[:pages] = $2.to_i
478
- result[:size] = "#{$3.to_i / 1024}KB"
447
+ } #values
448
+
449
+ #Build summary line
450
+ summary = []
451
+ if stat[:pages]
452
+ summary << "#{stat[:pages]} page"
453
+ summary.last << "s" if stat[:pages] > 1
454
+ end
455
+ if stat[:source]
456
+ summary << "Used #{stat[:source].join(', ')}"
457
+ end
458
+ errors = (stat[:error] ? stat[:error] : 0 ) +
459
+ (stat[:latex_errors] ? stat[:latex_errors] : 0 ) +
460
+ (stat[:package_errors] ? stat[:package_errors] : 0 )
461
+ if errors > 0
462
+ summary << "#{errors} error"
463
+ summary.last << 's' if errors > 1
464
+ end
465
+ case stat[:ok]
466
+ when 0, nil #no report
467
+ when 1; summary << "#{stat[:ok]} entry"
468
+ else; summary << "#{stat[:ok]} entries"
469
+ end
470
+ case stat[:reject]
471
+ when 0, nil
472
+ when 1; summary << "#{stat[:reject]} rejected entry"
473
+ else; summary << "#{stat[:reject]} rejected entries"
474
+ end
479
475
 
480
- filedata = []
481
- filedata << "#{result[:file]}"
482
- filedata << "#{result[:pages]} Page#{'s' if result[:pages] > 1}" if result[:pages]
483
- filedata << result[:size] if result[:size]
484
- filedata << "#{result[:error].size} Error#{'s' if result[:error].size > 1}" unless result[:error].empty?
485
- filedata << "#{result[:overfull].size} Overfull box#{'es' if result[:overfull].size > 1} (> #{@options[:overfull]})" unless result[:overfull].empty?
486
- filedata << "#{result[:underfull].size} Underfull box#{'es' if result[:underfull].size > 1} (> #{@options[:underfull]})" unless result[:underfull].empty?
487
- #~ result[:fileinfo] = "#{result[:file]} (#{filedata.join(', ')})" unless filedata.empty?
488
- result[:fileinfo] = filedata
489
- last_message = nil
490
- end #case logline
491
- } #each.loglines
492
- return result
493
- end #analyse_logfile
494
-
495
-
496
- Rail:
497
- stderr.each{ |errline|
498
- case errline
499
- when /(.*), line (.*): (.*)/
500
- #$1: Filename (e.g. 'stdin')
501
- @result[:error] << "Line #{$2}: #{$3}"
502
- @job.stop_rerun( :rail, "Rail: #{$3} on line #{$2}") #block rerun for rail
476
+ warnings = (stat[:warnings] ? stat[:warnings] : 0 ) +
477
+ (stat[:latex_warnings] ? stat[:latex_warnings] : 0 ) +
478
+ (stat[:package_warnings] ? stat[:package_warnings] : 0 )
479
+ if warnings > 0
480
+ summary << "#{warnings} warning"
481
+ summary.last << 's' if warnings > 1
503
482
  end
504
- }
505
-
506
- stdout.each{ |stdout_line|
507
- case stdout_line
508
- when /This is Rail, Version (.*)\s/
509
- @result[:info] << "Rail version #{$1} was called"
510
- when /(Der Prozess kann nicht auf die Datei zugreifen, .*)/
511
- @result[:error] << "#{$1}"
483
+ if stat[:overfull_boxes]
484
+ summary << "#{stat[:overfull_boxes]} overfull box"
485
+ summary.last << 'es' if stat[:overfull_boxes] > 1
512
486
  end
513
- }
487
+ if stat[:underfull_boxes]
488
+ summary << "#{stat[:underfull_boxes]} underfull box"
489
+ summary.last << 'es' if stat[:underfull_boxes] > 1
490
+ end
491
+
492
+ #Put summary to result-array
493
+ #The result contains a sort-number, which is deleted in the end
494
+ case key
495
+ when /log\Z/; result << "%-13s: %s (%s)" % [ '1Document', summary.join(', '), key]
496
+ when /blg\Z/; result << "%-13s: %s (%s)" % [ '2Bibliography', summary.join(', '), key]
497
+ when /ilg\Z/; result << "%-13s: %s (%s)" % [ '3Index', summary.join(', '), key]
498
+ else
499
+ #fixme
500
+ puts "#{__FILE__}##{__LINE__}: Unknown #{key}"
501
+ result << "?? #{key}: #{summary.join(', ') }"
502
+ end
503
+ } #@stat
504
+ #Retrun the result in the wanted order, but without the sort-number.
505
+ result.sort.map{|e| e[1..-1] }
506
+ end
507
+ =begin rdoc
508
+ Build a more complex overview.
509
+ Contains:
510
+ * Summary (method #stat_summary)
511
+ * All errors and warnings from TeX and the tools.
512
+ * A detailed analyses for the TeX-log (including some buge in the analyse).
513
+ =end
514
+ def overview()
515
+ overview = []
516
+ overview << "Log-overview for #{@texfile}"
517
+ overview << stat_summary.map{|e| " #{e}"}
518
+ overview << stat.to_yaml
519
+ #And the TeX-errors in details (buggy)
520
+ overview << "========\n Detailed analyse of #{@texfile.ext('log')}\n========"
521
+ overview << "###########\n##The following list may contain wrong line assignments\n###########"
522
+ overview << texmessages2hash({
523
+ :messages => log_analyse_by_file(@texfile.ext('log')),
524
+ :page_info => true, #add page information
525
+ :loglineno_info => true,
526
+ :nextlines_info => true,
527
+ :source_info => true, #add source code information, only in log_analyse_by_file_page
528
+ }).to_yaml
529
+ overview.join("\n")
530
+ end #overview()
531
+
532
+ =begin rdoc
533
+ Return a quick overview. See stat_overview()
534
+ =end
535
+ def to_s()
536
+ stat_overview()
537
+ end
538
+ end #TeX_Statistic
539
+ end #Rake4LaTeX
540
+
514
541
 
542
+ #~ if $0 == __FILE__
543
+ #~ Dir.chdir('../../test/'){ require 'test_tex_statistic.rb' }
544
+ #~ end