1 package eu.simuline.m2latex.core;
2
3 import java.io.File;
4 import java.util.Arrays;
5
6 /**
7 * Describe class AbstractLatexProcessor here.
8 *
9 *
10 * Created: Thu Nov 17 12:29:36 2016
11 *
12 * @author <a href="mailto:rei3ner@arcor.de">Ernst Reissner</a>
13 * @version 1.0
14 */
15 abstract class AbstractLatexProcessor {
16
17 // both LatexProcessor and LatexPreProcessor
18 // LaTeX and mpost with option -recorder
19 // Used only to clean,
20 // but only in LatexPreProcessor, because else clean mechanism is just xxx.yyy
21 // In the long run, this will be used by both,
22 // because it is scanned to find out dependencies
23 final static String SUFFIX_FLS = ".fls";
24 // both LatexProcessor and LatexPreProcessor, used in LatexMainDesc
25 // for LaTeX but also for mpost
26 // used to
27 final static String SUFFIX_LOG = ".log";
28
29 // both LatexProcessor and LatexPreProcessor
30 final static String SUFFIX_PDF = ".pdf";
31
32 // makeindex for glossary
33 // needed by makeglossaries and for svg-conversion (hack)
34 final static String SUFFIX_VOID = "";
35
36 // both LatexProcessor and LatexPreProcessor
37 protected final Settings settings;
38
39 // both LatexProcessor and LatexPreProcessor
40 protected final CommandExecutor executor;
41
42 // both LatexProcessor and LatexPreProcessor
43 protected final LogWrapper log;
44
45 // both LatexProcessor and LatexPreProcessor
46 protected final TexFileUtils fileUtils;
47
48 /**
49 * Creates a new <code>AbstractLatexProcessor</code> instance.
50 *
51 */
52 public AbstractLatexProcessor(Settings settings, CommandExecutor executor,
53 LogWrapper log, TexFileUtils fileUtils) {
54 this.settings = settings;
55 this.log = log;
56 this.executor = executor;
57 this.fileUtils = fileUtils;
58 }
59
60 /**
61 * Logs if an error occurred running <code>command</code>
62 * by detecting that the log file <code>logFile</code> has not been created
63 * or by detecting the error pattern <code>pattern</code>
64 * in <code>logFile</code>.
65 * <p>
66 * Logging:
67 * <ul>
68 * <li> EAP01 Running <code>command</code> failed. For details...
69 * <li> EAP02 Running <code>command</code> failed. No log file
70 * <li> WAP04 if <code>logFile</code> is not readable.
71 * <li> WFU03 cannot close
72 * </ul>
73 * @see #logWarns(File, String, String)
74 */
75 protected void logErrs(File logFile, String command, String pattern) {
76 if (logFile.exists()) {
77 // hasErrsWarns may log warnings WFU03, WAP04
78 if (hasErrsWarns(logFile, pattern)) {
79 this.log.error("EAP01: Running " + command
80 + " failed. Errors logged in '" + logFile.getName() + "'. ");
81 }
82 } else {
83 this.log.error("EAP02: Running " + command + " failed: No log file '"
84 + logFile.getName() + "' written. ");
85 }
86 }
87
88 /**
89 * Logs if a warning occurred running <code>command</code>
90 * by detecting the warning pattern <code>pattern</code>
91 * in <code>logFile</code>.
92 * If <code>logFile</code> then an error occurred
93 * making detection of warnings obsolete.
94 * <p>
95 * Logging:
96 * <ul>
97 * <li> WAP03 Running <code>command</code> emitted warnings.
98 * <li> WAP04 if <code>logFile</code> is not readable.
99 * <li> WFU03 cannot close
100 * </ul>
101 *
102 * @see #logErrs(File, String, String)
103 */
104 // for both LatexProcessor and LatexPreProcessor
105 protected void logWarns(File logFile, String command, String pattern) {
106 // hasErrsWarns may log warnings WFU03, WAP04
107 // It is ok that no log file exists,
108 // because this is treated by logErrs invoked before.
109 // TBD: this is bad design.
110 // If so, then a singlel method to log errors and warnings is needed.
111 // This may well be implemented by invoking both logErrs followed by logWarns. s
112 if (logFile.exists() && hasErrsWarns(logFile, pattern)) {
113 // logs warning WAP03: emitted warnings
114 logWarn(logFile, command);
115 }
116 }
117
118 /**
119 * <p>
120 * Logging:
121 * WAP03 Running <code>command</code> emitted warnings.
122 */
123 // invoked by logWarns(File, String, String) and
124 // LatexProcessor.logWarns(File, String)
125 protected void logWarn(File logFile, String command) {
126 this.log.warn("WAP03: Running " + command + " emitted warnings logged in '"
127 + logFile.getName() + "'. ");
128 }
129
130 /**
131 *
132 * Logging:
133 * <ul>
134 * <li> WFU03 cannot close
135 * <li> WAP04 if <code>logFile</code> is not readable.
136 * </ul>
137 */
138 // FIXME: command not clear.
139 // used in
140 // logErrs (File, String, String)
141 // logWarns(File, String, String)
142 protected boolean hasErrsWarns(File logFile, String pattern) {
143 assert logFile.exists()
144 && !logFile.isDirectory() : "Expected existing (regular) log file "
145 + logFile;
146 // may log warning WFU03 cannot close
147 FileMatch fileMatch = this.fileUtils.getMatchInFile(logFile, pattern);
148 if (fileMatch.isFileReadable()) {
149 return fileMatch.doesExprMatch();
150 }
151 this.log.warn("WAP04: Cannot read log file '" + logFile.getName()
152 + "'; may hide warnings/errors. ");
153 return false;
154 }
155
156 // for both LatexProcessor and LatexPreProcessor
157 protected boolean update(File source, File target) {
158 if (!target.exists()) {
159 return true;
160 }
161 assert source.exists()
162 && !source.isDirectory() : "Expected existing (regular) source "
163 + source;
164
165 return source.lastModified() > target.lastModified();
166 }
167
168 /**
169 * Returns an array of strings,
170 * starting with those extracted from <code>options</code> by splitting
171 * followed by a copy of <code>addArgs</code>
172 * and finally <code>file</code>.
173 * <p>
174 * CAUTION: The last two categories are added not in the parameter order,
175 * because they are given by varargs
176 *
177 * @param options
178 * the options string without enclosing blanks.
179 * The individual options in that string
180 * are expected to be separated by a single blank.
181 * @param file
182 * the file argument which is in the returned array last
183 * @param addArgs
184 * optional argument: further options
185 * inserted in the returned array just in front of the <code>file</code>.
186 * @return
187 * An array of strings:
188 * The first elements are extracted from <code>options</code>,
189 * followed by the individual elements from <code>addArgs</code>;
190 * the last entry is <code>file</code>.
191 */
192 // for both LatexProcessor and LatexPreProcessor
193 // and in tests
194 protected static String[] buildArguments(String options, File file,
195 String... addArgs) {
196 String[] optionsArr =
197 options.isEmpty() ? new String[] {} : options.split(" ");
198 String[] args =
199 Arrays.copyOf(optionsArr, optionsArr.length + addArgs.length + 1);
200 System.arraycopy(addArgs, 0, args, optionsArr.length, addArgs.length);
201 args[args.length - 1] = file.getName();
202 return args;
203 }
204 }