View Javadoc
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 }