Package de.whitewashing.php.cs.command

Source Code of de.whitewashing.php.cs.command.CodeSniffer$StupidStandardsOutputParser

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package de.whitewashing.php.cs.command;

import java.io.BufferedReader;
import java.util.concurrent.ExecutionException;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.netbeans.api.extexecution.ExecutionDescriptor;
import org.netbeans.api.extexecution.ExecutionService;
import org.netbeans.api.extexecution.ExternalProcessBuilder;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.cookies.EditorCookie;
import org.openide.cookies.LineCookie;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.loaders.DataObjectNotFoundException;
import org.openide.util.Exceptions;
import org.openide.loaders.DataObject;
import org.openide.text.Line;

/**
*
* @author benny
*/
public class CodeSniffer {

    public static final String PARAM_STANDARD = "--standard=%s";
    public static final String PARAM_REPORT = "--report=xml";

    private String shellScript;
    private String codingStandard;
    private boolean showWarnings;

    public void setShellScript(String shellScript) {
        this.shellScript = shellScript;
    }
   

    public CodeSniffer(String shellScript, String codingStandard, boolean showWarnings) {
        this.shellScript = shellScript;
        this.codingStandard = codingStandard;
        this.showWarnings = showWarnings;
    }

    public boolean isEnabled() {
        if(this.shellScript == null || this.shellScript.equals("")) {
            return false;
        } else {
            File shellFile = new File(this.shellScript);
            return shellFile.isFile() && shellFile.canExecute();
        }
    }
   
    public String getVersion() {
        if(!isEnabled()) {
            return "?";
        }
       
        ExternalProcessBuilder procBuilder = new ExternalProcessBuilder(this.shellScript)
                .addArgument("--version");

        try {
            ProcessExecutor executor = new ProcessExecutor();
            Reader executedProcess = executor.execute(procBuilder);
           
            // Handle PHP Exceptions
            handlePhpExceptions(executedProcess);
           
            String versionLine = this.getStringFromReader(executedProcess);
            Pattern pattern = Pattern.compile("(?:CodeSniffer.*?)(?:v\\.?(?:ersion)?\\s+)([0-9]+\\.[0-9]+(?:\\.[0-9]+)?)", Pattern.CASE_INSENSITIVE);
            Matcher m = pattern.matcher(versionLine);
            if(!m.find()) {
                return "?";
            }
           
            return m.group(1);
        } catch(CodeSnifferPhpException e) {
            DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(e.getMessage(), NotifyDescriptor.ERROR_MESSAGE));
            return "?";
        } catch(java.io.IOException e) {
            return "?";
        }
    }

    public List<String> getAvailableStandards() {
        if (this.isEnabled() == false) {
            return new ArrayList<String>();
        }
       
        try {
            ExternalProcessBuilder procBuilder = new ExternalProcessBuilder(this.shellScript)
                    .addArgument("-i");

            ProcessExecutor executor = new ProcessExecutor();
            StupidStandardsOutputParser parser = new StupidStandardsOutputParser();

            Reader executedProcess = executor.execute(procBuilder);

            // Handle PHP Exceptions
            handlePhpExceptions(executedProcess);
           
            return parser.parse(executedProcess);
        } catch(java.io.IOException e) {
            DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(e.getMessage(), NotifyDescriptor.ERROR_MESSAGE));
        }
       
        return new ArrayList<String>();
    }

    public CodeSnifferXmlLogResult execute(FileObject fo) {
        return execute(fo, false);
    }

    public CodeSnifferXmlLogResult execute(FileObject fo, boolean annotateLines) {
        final File parent = FileUtil.toFile(fo.getParent());

        if(parent == null || this.isEnabled() == false) {
            return CodeSnifferXmlLogResult.empty();
        }
       
        // Executes PHPCS
        ExternalProcessBuilder externalProcessBuilder;
        if (this.showWarnings) {
            externalProcessBuilder = new ExternalProcessBuilder(this.shellScript)
                .workingDirectory(parent)
                .addArgument(String.format(PARAM_STANDARD, this.codingStandard))
                .addArgument(PARAM_REPORT)
                .addArgument(fo.getNameExt());
        } else {
            externalProcessBuilder = new ExternalProcessBuilder(this.shellScript)
                .workingDirectory(parent)
                .addArgument(String.format(PARAM_STANDARD, this.codingStandard))
                .addArgument(PARAM_REPORT)
                .addArgument("-n")
                .addArgument(fo.getNameExt());
        }
       
        CodeSnifferXmlLogParser parser = new CodeSnifferXmlLogParser();
        Reader executedProcess = new ProcessExecutor().execute(externalProcessBuilder);

        CodeSnifferXmlLogResult rs = CodeSnifferXmlLogResult.empty();
        try {
            // Handle PHP Exceptions
            handlePhpExceptions(executedProcess);

            // Parse response
            rs = parser.parse(executedProcess);
            if(annotateLines) {
                annotateWithCodingStandardHints(fo, rs);
            }

            // Check if we have no errors at all
            if(rs.getCsErrors().isEmpty() && rs.getCsWarnings().isEmpty())
                DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message("Great!\nNo errors or warnings found.", NotifyDescriptor.INFORMATION_MESSAGE));
        } catch(java.io.IOException e) {
            DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(e.getMessage(), NotifyDescriptor.ERROR_MESSAGE));
        }

        // Progress bar finish
        return rs;
    }

    private void annotateWithCodingStandardHints(FileObject fo, CodeSnifferXmlLogResult rs) {
        CodeSnifferFileListener l = new CodeSnifferFileListener();
        l.setLogResult(rs);
        fo.addFileChangeListener(l);
       
        try {
            DataObject d = DataObject.find(fo);
            LineCookie cookie = d.getCookie(LineCookie.class);
           
            Line.Set lineSet = null;
            Line line = null;
            for (int i = 0; i < rs.getCsErrors().size(); i++) {
                lineSet = cookie.getLineSet();
                line = lineSet.getOriginal(rs.getCsErrors().get(i).getLineNum());
                rs.getCsErrors().get(i).attach(line);
            }

            for (int i = 0; i < rs.getCsWarnings().size(); i++) {
                lineSet = cookie.getLineSet();
                line = lineSet.getOriginal(rs.getCsWarnings().get(i).getLineNum());
                rs.getCsWarnings().get(i).attach(line);
            }
        } catch (DataObjectNotFoundException ex) {
            Exceptions.printStackTrace(ex);
        }
    }
   
    /**
     * Creates a simple string from the given input reader.
     * This method will not handle exceptions.
     *
     * @param reader The raw input stream.
     *
     * @return String
     */
    private String getStringFromReader(Reader reader)
        throws IOException
    {
        return new BufferedReader(reader).readLine();
    }

    /**
     * Small utility class that is used to execute an external CodeSniffer process.
     */
    class ProcessExecutor {

        /**
         * Executes the given process and returns a reader instance with the
         * STDOUT result of the process.
         *
         * @param builder A configured process builder instance.
         *
         * @return Reader
         */
        public Reader execute(ExternalProcessBuilder builder) {
            builder = builder.redirectErrorStream(true);
            CodeSnifferOutput output = new CodeSnifferOutput();

            ExecutionDescriptor descriptor = new ExecutionDescriptor()
                    .frontWindow(false)
                    .controllable(false)
                    .outProcessorFactory(output);

            ExecutionService service = ExecutionService.newService(builder, descriptor, "PHP Coding Standards");
            Future<Integer> task = service.run();
            try {
                task.get();
            } catch (InterruptedException ex) {
                Exceptions.printStackTrace(ex);
            } catch (ExecutionException ex) {
                Exceptions.printStackTrace(ex);
            }

            return output.getReader();
        }
    }
   
    /**
     * Reads the stream searching for fatal errors when executing PHPCS
     */
    public void handlePhpExceptions(Reader reader)
        throws CodeSnifferPhpException, IOException
    {
        BufferedReader output = new BufferedReader(reader);
        String ln;
        while((ln = output.readLine()) != null) {
            String message = "";

            // Treats fatal errors and parse errors that PHP may throw
            if(ln.indexOf("Fatal error:") >= 0 || ln.indexOf("Parse error:") >= 0) {
                if(ln.indexOf("Fatal error:") >= 0) {
                    Matcher m = Pattern.compile(
                            "Fatal error:\\s+(.*(?:line\\s+|:)[0-9]+)",
                            Pattern.CASE_INSENSITIVE
                    ).matcher(ln);
                    if(m.find())
                        message = m.group(1);
                } else if(ln.indexOf("Parse error:") >= 0) {
                    Matcher m = Pattern.compile(
                            "Parse error:\\s+(.*(?:line\\s+|:)[0-9]+)",
                            Pattern.CASE_INSENSITIVE
                    ).matcher(ln);
                    if(m.find())
                        message = m.group(1);
                }

                String finalMessage = "A fatal error occured, check your PHPCS installation.";
                if(!message.equals(""))
                    finalMessage += "\nError:\n" + message;

                reader.reset();
                throw new CodeSnifferPhpException(finalMessage);
            }
        }
       
        reader.reset();
    }

    /**
     * Utility class that parses the textual output of the CodeSniffer -i option
     * and creates a list of available coding standards.
     */
    class StupidStandardsOutputParser {

        private final String DEFAULT_STANDARDS = "Zend, PEAR, PHPCS, Squiz and MySource";

        private List<String> parse(Reader reader) {
            String output = this.getStringFromReader(reader);
           
            List<String> standards = new ArrayList<String>();

            String[] parts = output.split(" and ");
            standards.add(parts[1].trim());

            parts = parts[0].split(",");
            for (int i = 1; i < parts.length; ++i) {
                standards.add(parts[i].trim());
            }

            parts = parts[0].split(" ");
            standards.add(parts[parts.length - 1].trim());

            return standards;
        }

        /**
         * Creates a simple string from the given input reader. This method will
         * return a default set of CodeSniffer standards when an IOException
         * occures during the parsing process.
         *
         * @param reader The raw input stream with codesniffer data.
         *
         * @return String
         */
        private String getStringFromReader(Reader reader) {
            try {
                return CodeSniffer.this.getStringFromReader(reader);
            } catch (IOException e) {
                return this.DEFAULT_STANDARDS;
            }
        }
    }
}
TOP

Related Classes of de.whitewashing.php.cs.command.CodeSniffer$StupidStandardsOutputParser

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.