/** * \cond LICENSE * Arara -- the cool TeX automation tool * Copyright (c) 2012, Paulo Roberto Massa Cereda * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. Neither the name of the project's author nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * \endcond * * ConfigurationLoader: This class provides an object handler for the arara * configuration file. */ // package definition package com.github.arara.utils; // needed imports import com.github.arara.Arara; import com.github.arara.exception.AraraException; import com.github.arara.model.AraraConfiguration; import com.github.arara.model.AraraFilePattern; import java.io.File; import java.io.FileReader; import java.net.URLDecoder; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang3.SystemUtils; import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.constructor.Constructor; import org.yaml.snakeyaml.error.MarkedYAMLException; import org.yaml.snakeyaml.nodes.Tag; import org.yaml.snakeyaml.representer.Representer; /** * Provides an object handler for the arara configuration file. * * @author Paulo Roberto Massa Cereda * @version 3.0a * @since 3.0 */ public class ConfigurationLoader { // list of search paths private List paths; // the application path, that is, where arara is located private String applicationPath; // list of file patterns private List filePatterns; // list of valid extensions private String[] validExtensions; // the chosen pattern private AraraFilePattern chosenFilePattern; // the localization class final static AraraLocalization localization = AraraLocalization.getInstance(); /** * Constructor. */ public ConfigurationLoader() { // create a new list of paths paths = new ArrayList(); // try to obtain the application path try { applicationPath = Arara.class.getProtectionDomain().getCodeSource().getLocation().getPath(); applicationPath = URLDecoder.decode(applicationPath, "UTF-8"); applicationPath = new File(applicationPath).getParentFile().getPath(); } catch (Exception exception) { applicationPath = ""; } } /** * Loads the configuration settings, either the default setup or through the * configuration file. * * @throws Exception An exception is thrown if something unexpected happens * during the execution of this method. */ public void load() throws Exception { // create the default patterns // for .tex files AraraFilePattern texPattern = new AraraFilePattern(); texPattern.setExtension("tex"); texPattern.setPattern("^(\\s)*%\\s+"); // for .dtx files AraraFilePattern dtxPattern = new AraraFilePattern(); dtxPattern.setExtension("dtx"); dtxPattern.setPattern("^(\\s)*%\\s+"); // for .ltx files AraraFilePattern ltxPattern = new AraraFilePattern(); ltxPattern.setExtension("ltx"); ltxPattern.setPattern("^(\\s)*%\\s+"); // create a list of default patterns List defaultPatterns = new ArrayList(); // add the default ones defaultPatterns.add(texPattern); defaultPatterns.add(dtxPattern); defaultPatterns.add(ltxPattern); // create a list of file patterns filePatterns = new ArrayList(); // create a file reference File configurationFile = new File(SystemUtils.USER_HOME + File.separator + AraraConstants.ARARACONFIG); // if there is not a configuration file if (!configurationFile.exists()) { // there's only one path to look for rules paths.add(applicationPath + File.separator + "rules"); // the only file patterns are the default ones filePatterns.addAll(defaultPatterns); // create an array of valid extensions validExtensions = new String[filePatterns.size()]; // add them according to the file patterns for (int i = 0; i < filePatterns.size(); i++) { validExtensions[i] = ".".concat(filePatterns.get(i).getExtension()); } // simply return, there's nothing more to do return; } // create the YAML representer Representer representer = new Representer(); representer.addClassTag(AraraConfiguration.class, new Tag("!config")); representer.addClassTag(AraraFilePattern.class, new Tag("!pattern")); // create the YAML parser Yaml yaml = new Yaml(new Constructor(AraraConfiguration.class), representer); // create the file reader FileReader fileReader = new FileReader(configurationFile); // set the new configuration object AraraConfiguration configuration = null; try { // try to read the configuration object configuration = (AraraConfiguration) yaml.load(fileReader); } catch (MarkedYAMLException yamlException) { // there's an error with the YAML file, so an exception is thrown AraraLogging.enableLogging(false); throw new AraraException(localization.getMessage("Error_InvalidYAMLConfigurationFile").concat("\n\n").concat(AraraUtils.extractInformationFromYAMLException(yamlException))); } catch (Exception e) { System.out.println(e.getMessage()); } // close the file reader fileReader.close(); // check if the configuration is invalid if (configuration == null) { // it's invalid, raise an exception AraraLogging.enableLogging(false); throw new AraraException(localization.getMessage("Error_InvalidConfigurationFile")); } // check if there's an available language if (configuration.getLanguage() != null) { // create a new language control LanguageController languageController = new LanguageController(); // if the language is not valid if (languageController.setLanguage(configuration.getLanguage()) == false) { // it's invalid, raise an exception AraraLogging.enableLogging(false); throw new AraraException(localization.getMessage("Error_InvalidLanguageConfigurationFile", languageController.getLanguagesList())); } } // check if there are new paths if (configuration.getPaths() != null) { // a runtime exception happened when resolving some // path names if (configuration.getPathRuntimeException() != null) { // raise an exception AraraLogging.enableLogging(false); throw new AraraException(localization.getMessage("Error_PathRuntimeErrorConfigurationFile", AraraUtils.getVariableFromException(configuration.getPathRuntimeException()))); } // a IO exception happened when checking if it was // a valid path entry if (configuration.getPathIOException() != null) { // raise an exception AraraLogging.enableLogging(false); throw new AraraException(localization.getMessage("Error_PathIOErrorConfigurationFile")); } // for every path set for (String currentPath : configuration.getPaths()) { // add it to the paths list paths.add(currentPath); } } // the last path to be added is the application path paths.add(applicationPath + File.separator + "rules"); // check if there are new file patterns if (configuration.getFiletypes() != null) { // get all file patterns List filetypes = configuration.getFiletypes(); // reorder the list of filetypes for (int i = 0; i < defaultPatterns.size(); i++) { // if the filetype is not in the default list if (!isAlreadyDefined(defaultPatterns.get(i), filetypes)) { // simply add it filePatterns.add(defaultPatterns.get(i)); } } // merge the two lists filePatterns.addAll(filetypes); // create a new array of valid extensions validExtensions = new String[filePatterns.size()]; int counter = 0; // sanity check, if there are valid extensions and patterns for (AraraFilePattern currentPattern : filePatterns) { // check if either of those fields is missing if ((currentPattern.getPattern() == null) || (currentPattern.getExtension() == null)) { // it's invalid, raise an exception AraraLogging.enableLogging(false); throw new AraraException(localization.getMessage("Error_InvalidFiletypesConfigurationFile")); } // add the dot to the extension validExtensions[counter] = ".".concat(currentPattern.getExtension()); counter++; } } else { // no new filetypes, simply merge the lists filePatterns.addAll(defaultPatterns); // create a new array for extensions validExtensions = new String[filePatterns.size()]; // iterate through all filetypes and add the extension to the array for (int i = 0; i < filePatterns.size(); i++) { validExtensions[i] = ".".concat(filePatterns.get(i).getExtension()); } } } /** * Checks if the filetype is already defined in the list, and updates the * latter if needed. * * @param filePattern The filetype object. * @param list The list to be inspected. * @return A boolean indicating if the filetype is already defined in the * list. */ private boolean isAlreadyDefined(AraraFilePattern filePattern, List list) { // iterate through all elements for (int i = 0; i < list.size(); i++) { // check if it already exists if (filePattern.getExtension().equalsIgnoreCase(list.get(i).getExtension())) { // update the element if needed if (list.get(i).getPattern() == null) { list.set(i, filePattern); } // already defined return true; } } // not found return false; } /** * Getter for the paths. * * @return The paths. */ public List getPaths() { return paths; } /** * Getter for the file patterns. * * @return The file patterns. */ public List getFilePatterns() { return filePatterns; } /** * Getter for the valid extensions available. * * @return An array containing the valid extensions. */ public String[] getValidExtensions() { return validExtensions; } /** * Setter for the chosen file pattern. * * @param extension A string containing a reference for the file extension. */ public void setChosenFilePattern(String extension) { // for every file pattern for (AraraFilePattern currentPattern : filePatterns) { // if the extension matches if (".".concat(currentPattern.getExtension()).equals(extension)) { // we found our pattern chosenFilePattern = currentPattern; // return return; } } // nothing found chosenFilePattern = null; } /** * Getter for the chosen file pattern. * * @return The chosen file pattern. */ public AraraFilePattern getChosenFilePattern() { return chosenFilePattern; } }