Package org.gradle.foundation.output

Source Code of org.gradle.foundation.output.FileLinkDefinitionLord

/*
* Copyright 2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.gradle.foundation.output;

import org.gradle.foundation.output.definitions.*;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* This class holds on FileLinkDefinitions used for searching output.
*
* @author mhunsicker

*/
public class FileLinkDefinitionLord {
    private List<String> extensions = new ArrayList<String>( );

    //these are definitions where the file is between known tokens.
    private Map<Pattern,FileLinkDefinition> complexFileLinkDefinitions = new LinkedHashMap<Pattern,FileLinkDefinition>();

    //these are definitions where we only try to match based on the file extension.
    private Map<Pattern,FileLinkDefinition> extensionFileLinkDefinitions = new LinkedHashMap<Pattern,FileLinkDefinition>();

    private Pattern combinedSearchPattern;  //search pattern consisting of all of our sub search patterns

    public FileLinkDefinitionLord() {
      //this is where we define what files we find.

      //add all the file extension definitions
      addFileExtension( ".java", ":" );     //the colon handles compile errors with line numbers
      addFileExtension( ".groovy", ":" );
      addFileExtension( ".gradle", ":" );
      addFileExtension( ".xml", ":" ); //I don't think I've ever seen an xml or html file specified with a line number delimiter, but we'll try it anyway
      addFileExtension( ".html", ":" );
      addFileExtension( ".htm", ":" );

      //now add the more complex ones
      addPrefixedFileLink( "Ant Compiler Error", "[ant:javac]", ".java", ":" );       //handles java compiler errors
      addPrefixedFileLink( "Compiler Warning", "Note:", ".java", null );               //handles java compiler warnings such as deprecated APIs
      addCustomComplexFileLink( new OptionalLineNumberFileLinkDefinition( "Build File Errors", "Build file '",".gradle", "line:" ) );       //handles errors in a gradle build file
      addPrefixedFileLink( "Ant Checkstyle Error/Warning", "[ant:checkstyle]", ".java", ":" );//handles checkstyle errors/warnings
      addPrefixedFileLink( "Checkstyle Error (report xml)", "See the report at", ".xml", null );   //handles checkstyle errors. Links to the report xml file.
      addPrefixedFileLink( "Codenarc Error", "See the report at", ".html", null );      //handles Codenarc errors. Links to the report file.
      addCustomComplexFileLink( new TestReportFileLinkDefinition() );
    }

    /**
     Call this to add file extensions to look for in the output. This assumes the file path
     is the first thing on the line.
     @param extension the file extension
     @param lineNumberDelimiter optional delimiter text for line number. Whatever is after
             this will be assumed to be a line number. We'll only parse the numbers after
             this so there can be other stuff after the line number. Pass in null to ignore.
     */
    public void addFileExtension( String extension, String lineNumberDelimiter )
    {
       if( !extension.startsWith( "."  ) ) {
           extension = "." + extension;
       }

        extension = extension.toLowerCase();
       if( extensions.contains( extension ) ) //don't add extensions already added
       {
          return;
       }

       extensions.add( extension );

       String name = extension + " Files";
       ExtensionFileLinkDefinition linkDefinition = new ExtensionFileLinkDefinition(name, extension, lineNumberDelimiter);
       addToMap(extensionFileLinkDefinitions, linkDefinition );
    }

    /**
     Creates a file link definition to find file paths in the output that have a known prefix and extension.
     It also allows for an optional line number after a delimiter. This is useful if you know a certain
     message always precedes a file path.
     @param name  the name of this file link definition. Used by tests mostly.
     @param prefix  the text that is before the file path. It should be enough to make it fairly unique
     @param extension  the expected file extension. If we don't find this extension, we do not consider
             the text a file's path. If there are multiple extensions, you'll have to add multiples of these.
     @param lineNumberDelimiter optional delimiter text for line number. Whatever is after
             this will be assumed to be a line number. We'll only parse the numbers after
             this so there can be other stuff after the line number. Pass in null to ignore.

     */
    public void addPrefixedFileLink( String name, String prefix, String extension, String lineNumberDelimiter )
    {
        PrefixedFileLinkDefinition linkDefinition = new PrefixedFileLinkDefinition(name, prefix, extension, lineNumberDelimiter);
        addToMap( complexFileLinkDefinitions, linkDefinition );
    }

    private void addCustomComplexFileLink( FileLinkDefinition fileLinkDefinition )
    {
        addToMap( complexFileLinkDefinitions, fileLinkDefinition );
    }

    private void addToMap( Map<Pattern,FileLinkDefinition> destinationMap, FileLinkDefinition fileLinkDefinition )
    {
        //if you change anything, we'll destroy our combined search pattern. This will recreate it with the
        //latest settings when its next asked for.
        combinedSearchPattern = null;

        String searchExpression = fileLinkDefinition.getSearchExpression();
        Pattern pattern = Pattern.compile( searchExpression, getSearchPatternFlags() );
        destinationMap.put( pattern, fileLinkDefinition);
    }

    /**
     @return a list of known file extensions that are searched for in the output.
     */
    public List<String> getFileExtensions() { return Collections.unmodifiableList( extensions ); }

    /**
      @return a list of our FileLinkDefinitions
     */
    public List<FileLinkDefinition> getFileLinkDefinitions()
    {
        List<FileLinkDefinition> fileLinkDefinitions = new ArrayList<FileLinkDefinition>();

        fileLinkDefinitions.addAll( complexFileLinkDefinitions.values() );
        fileLinkDefinitions.addAll( extensionFileLinkDefinitions.values() );

        return Collections.unmodifiableList( fileLinkDefinitions );
    }

   private int getSearchPatternFlags() { return Pattern.CASE_INSENSITIVE; }

    /**
     * This returns the FileLinkDefinition whose search pattern 'matches' (as in 'finds', not 'equals') the
     * specified text. The tricky thing here is that multiple FileLinkDefinitions can match the text. To
     * assist this we've done two things: we first try to match it with the complex patterns (the ones that
     * try to match prefixed and suffixed text around a file's path), then if we don't find one, we'll match
     * it with a simple extension FileLinkDefinitions. The other thing is that we search the definitions in
     * order. This means the order in which the FileLinkDefinitions are added can be important. Add the more
     * definitive ones first.
     * @param text the text to use to find a match.
     * @return a FileLinkDefinition that matches the text
     */
   public FileLinkDefinition getMatchingFileLinkDefinition( String text )
   {
       FileLinkDefinition fileLinkDefinition = getMatchingFileLinkDefinition( text, complexFileLinkDefinitions );
       if( fileLinkDefinition == null ) {
           fileLinkDefinition = getMatchingFileLinkDefinition( text, extensionFileLinkDefinitions );
       }

       return fileLinkDefinition;
   }

   private static FileLinkDefinition getMatchingFileLinkDefinition( String text, Map<Pattern,FileLinkDefinition> map )
   {
      Iterator<Pattern> iterator = map.keySet().iterator();
      while( iterator.hasNext() )
      {
         Pattern pattern = iterator.next();
         Matcher matcher = pattern.matcher( text );
         if( matcher.find( 0 ) )
         {
            return map.get( pattern );
         }
      }

      return null;
   }

    public Pattern getSearchPattern()
    {
        if( combinedSearchPattern == null ) //only build it if we need to.
        {
            combinedSearchPattern = buildSearchPattern();
        }

        return combinedSearchPattern;
    }

    /**
    This iterates through all the FileLinkDefinitions and builds one giant single RegEx search pattern. This is more
    efficient than using multiple search patterns.
    */
   private Pattern buildSearchPattern()
   {
      StringBuilder criteria = new StringBuilder();
      Iterator<FileLinkDefinition> iterator = getFileLinkDefinitions().iterator();
      while( iterator.hasNext() )
      {
         FileLinkDefinition fileLinkDefinition = iterator.next();
         String searchExpression = fileLinkDefinition.getSearchExpression();

         criteria.append( "(" ).append( searchExpression ).append( ")" );

         if( iterator.hasNext() )
         {
            criteria.append( "|" );
         }
      }

      return Pattern.compile( criteria.toString(), getSearchPatternFlags() );
   }

}
TOP

Related Classes of org.gradle.foundation.output.FileLinkDefinitionLord

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.