All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.netbeans.modules.diff.cmdline.CmdlineDiffProvider Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.netbeans.modules.diff.cmdline;

import java.io.*;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;

import org.netbeans.api.diff.Difference;
import org.netbeans.spi.diff.DiffProvider;
import org.openide.ErrorManager;

/**
 * The parser of an external diff utility compatible with Unix diff output.
 *
 * 

The implementtaion is interruptible by Thread.interrupt(). * On interrupt it kills external program and throws InterruptedIOException, * * @author Martin Entlicher */ public class CmdlineDiffProvider extends DiffProvider implements java.io.Serializable { //private static final String REVISION_STR = "retrieving revision"; public static final String DIFF_REGEXP = "(^[0-9]+(,[0-9]+|)[d][0-9]+$)|"+ "(^[0-9]+(,[0-9]+|)[c][0-9]+(,[0-9]+|)$)|"+ "(^[0-9]+[a][0-9]+(,[0-9]+|)$)"; private static final int BUFF_LENGTH = 1024; private String diffCmd; private transient Pattern pattern; //private transient StringBuffer firstText; //private transient StringBuffer secondText; static final long serialVersionUID =4101521743158176210L; /** Creates new CmdlineDiffProvider * @param diffCmd The diff command. Must contain "{0}" and "{1}", which * will be replaced with the files being compared. */ public CmdlineDiffProvider(String diffCmd) { this.diffCmd = diffCmd; try { pattern = Pattern.compile(DIFF_REGEXP); } catch (PatternSyntaxException resex) {} //firstText = new StringBuffer(); //secondText = new StringBuffer(); } public CmdlineDiffProvider() { this("diff {0} {1}"); // NOI18N } public static CmdlineDiffProvider createDefault() { return new CmdlineDiffProvider(); // NOI18N } /** * Set a new diff command. * @param diffCmd The diff command. Must contain "{0}" and "{1}", which * will be replaced with the files being compared. */ public void setDiffCommand(String diffCmd) { this.diffCmd = diffCmd; } /** * Get the diff command being used. */ public String getDiffCommand() { return diffCmd; } private static boolean checkEmpty(String str, String element) { if (str == null || str.length() == 0) { /* if (this.stderrListener != null) { String[] elements = { "Bad format of diff result: "+element }; // NOI18N stderrListener.match(elements); } */ //Edeb("Bad format of diff result: "+element); // NOI18N return true; } return false; } /** * Get the display name of this diff provider. */ public String getDisplayName() { return NbBundle.getMessage(CmdlineDiffProvider.class, "displayName"); } /** * Get a short description of this diff provider. */ public String getShortDescription() { return NbBundle.getMessage(CmdlineDiffProvider.class, "shortDescription"); } /** * Create the differences of the content two streams. * @param r1 the first source * @param r2 the second source to be compared with the first one. * @return the list of differences found, instances of {@link Difference}; * or null when some error occured. */ public Difference[] computeDiff(Reader r1, Reader r2) throws IOException { File f1 = null; File f2 = null; try { f1 = FileUtil.normalizeFile(Files.createTempFile("TempDiff".intern(), null).toFile()); f2 = FileUtil.normalizeFile(Files.createTempFile("TempDiff".intern(), null).toFile()); FileWriter fw1 = new FileWriter(f1); FileWriter fw2 = new FileWriter(f2); char[] buffer = new char[BUFF_LENGTH]; int length; while((length = r1.read(buffer)) > 0) fw1.write(buffer, 0, length); while((length = r2.read(buffer)) > 0) fw2.write(buffer, 0, length); r1.close(); r2.close(); fw1.close(); fw2.close(); return createDiff(f1, f2); } finally { if (f1 != null) f1.delete(); if (f2 != null) f2.delete(); } } /** * Create the differences of the content of two FileObjects. * @param fo1 the first FileObject * @param fo2 the second FileObject to be compared with the first one. * @return the list of differences found, instances of {@link Difference}; * or null when some error occured. */ public Difference[] computeDiff(FileObject fo1, FileObject fo2) throws IOException { File f1 = FileUtil.toFile(fo1); File f2 = FileUtil.toFile(fo2); if (f1 != null && f2 != null) { return createDiff(f1, f2); } else { return null; } } /** * Executes (possibly broken) external program. */ private Difference[] createDiff(File f1, File f2) throws IOException { final StringBuffer firstText = new StringBuffer(); final StringBuffer secondText = new StringBuffer(); if (pattern == null) { try { pattern = Pattern.compile(DIFF_REGEXP); } catch (PatternSyntaxException resex) { throw (IOException) ErrorManager.getDefault().annotate( new IOException(), resex.getLocalizedMessage()); } //firstText = new StringBuffer(); //secondText = new StringBuffer(); } diffCmd = diffCmd.replace("\"{0}\"", "{0}").replace("\"{1}\"", "{1}"); // compatibility // NOI18N String firstPath; String secondPath; if (Utilities.isWindows()) { firstPath = "\"" + f1.getAbsolutePath() + "\""; // NOI18N secondPath = "\"" + f2.getAbsolutePath() + "\""; // NOI18N } else { firstPath = f1.getAbsolutePath(); secondPath = f2.getAbsolutePath(); } final String cmd = java.text.MessageFormat.format(diffCmd, firstPath, secondPath); final Process p[] = new Process[1]; final Object[] ret = new Object[1]; Runnable cancellableProcessWrapper = new Runnable() { public void run() { try { ErrorManager.getDefault().log("#69616 CDP: executing: " + cmd); // NOI18N synchronized(p) { p[0] = Runtime.getRuntime().exec(cmd); } Reader stdout = new InputStreamReader(p[0].getInputStream()); char[] buffer = new char[BUFF_LENGTH]; StringBuffer outBuffer = new StringBuffer(); int length; List differences = new ArrayList(); while ((length = stdout.read(buffer)) > 0) { for (int i = 0; i < length; i++) { if (buffer[i] == '\n') { //stdoutNextLine(outBuffer.toString(), differences); outputLine(outBuffer.toString(), pattern, differences, firstText, secondText); outBuffer.delete(0, outBuffer.length()); } else { if (buffer[i] != 13) { outBuffer.append(buffer[i]); } } } } if (outBuffer.length() > 0) outputLine(outBuffer.toString(), pattern, differences, firstText, secondText); setTextOnLastDifference(differences, firstText, secondText); ret[0] = differences.toArray(new Difference[0]); } catch (IOException ioex) { ret[0] = (IOException) ErrorManager.getDefault().annotate(ioex, NbBundle.getMessage(CmdlineDiffProvider.class, "runtimeError", cmd)); } } }; Thread t = new Thread(cancellableProcessWrapper, "Diff.exec()"); // NOI18N t.start(); try { t.join(); synchronized(ret) { if (ret[0] instanceof IOException) { throw (IOException) ret[0]; } return (Difference[]) ret[0]; } } catch (InterruptedException e) { synchronized(p[0]) { p[0].destroy(); } throw new InterruptedIOException(); } } public static void setTextOnLastDifference(List differences, StringBuffer firstText, StringBuffer secondText) { if (differences.size() > 0) { String t1 = firstText.toString(); if (t1.length() == 0) t1 = null; String t2 = secondText.toString(); if (t2.length() == 0) t2 = null; Difference d = (Difference) differences.remove(differences.size() - 1); differences.add(new Difference(d.getType(), d.getFirstStart(), d.getFirstEnd(), d.getSecondStart(), d.getSecondEnd(), t1, t2)); firstText.delete(0, firstText.length()); secondText.delete(0, secondText.length()); } } /** * This method is called, with elements of the output data. * @param elements the elements of output data. */ //private void outputData(String[] elements, List differences) { public static void outputLine(String elements, Pattern pattern, List differences, StringBuffer firstText, StringBuffer secondText) { //diffBuffer.append(elements[0]+"\n"); // NOI18N //D.deb("diff match: "+elements[0]); // NOI18N //System.out.println("diff outputData: "+elements[0]); // NOI18N int index = 0, commaIndex = 0; int n1 = 0, n2 = 0, n3 = 0, n4 = 0; String nStr; if (pattern.matcher(elements).matches()) { setTextOnLastDifference(differences, firstText, secondText); } else { if (elements.startsWith("< ")) { firstText.append(elements.substring(2) + "\n"); } if (elements.startsWith("> ")) { secondText.append(elements.substring(2) + "\n"); } return ; } if ((index = elements.indexOf('a')) >= 0) { //DiffAction action = new DiffAction(); try { n1 = Integer.parseInt(elements.substring(0, index)); index++; commaIndex = elements.indexOf(',', index); if (commaIndex < 0) { nStr = elements.substring(index); if (checkEmpty(nStr, elements)) return; n3 = Integer.parseInt(nStr); n4 = n3; } else { nStr = elements.substring(index, commaIndex); if (checkEmpty(nStr, elements)) return; n3 = Integer.parseInt(nStr); nStr = elements.substring(commaIndex+1); if (nStr == null || nStr.length() == 0) n4 = n3; else n4 = Integer.parseInt(nStr); } } catch (NumberFormatException e) { /* if (this.stderrListener != null) { String[] debugOut = { "NumberFormatException "+e.getMessage() }; // NOI18N stderrListener.match(debugOut); } */ //Edeb("NumberFormatException "+e.getMessage()); // NOI18N return; } //action.setAddAction(n1, n3, n4); //diffActions.add(action); differences.add(new Difference(Difference.ADD, n1, 0, n3, n4)); } else if ((index = elements.indexOf('d')) >= 0) { //DiffAction action = new DiffAction(); commaIndex = elements.lastIndexOf(',', index); try { if (commaIndex < 0) { n1 = Integer.parseInt(elements.substring(0, index)); n2 = n1; } else { nStr = elements.substring(0, commaIndex); if (checkEmpty(nStr, elements)) return; n1 = Integer.parseInt(nStr); nStr = elements.substring(commaIndex+1, index); if (checkEmpty(nStr, elements)) return; n2 = Integer.parseInt(nStr); } nStr = elements.substring(index+1); if (checkEmpty(nStr, elements)) return; n3 = Integer.parseInt(nStr); } catch (NumberFormatException e) { /* if (this.stderrListener != null) { String[] debugOut = { "NumberFormatException "+e.getMessage() }; // NOI18N stderrListener.match(debugOut); } */ //Edeb("NumberFormatException "+e.getMessage()); // NOI18N return; } //action.setDeleteAction(n1, n2, n3); //diffActions.add(action); differences.add(new Difference(Difference.DELETE, n1, n2, n3, 0)); } else if ((index = elements.indexOf('c')) >= 0) { //DiffAction action = new DiffAction(); commaIndex = elements.lastIndexOf(',', index); try { if (commaIndex < 0) { n1 = Integer.parseInt(elements.substring(0, index)); n2 = n1; } else { nStr = elements.substring(0, commaIndex); if (checkEmpty(nStr, elements)) return; n1 = Integer.parseInt(nStr); nStr = elements.substring(commaIndex+1, index); if (checkEmpty(nStr, elements)) return; n2 = Integer.parseInt(nStr); } index++; commaIndex = elements.indexOf(',', index); if (commaIndex < 0) { nStr = elements.substring(index); if (checkEmpty(nStr, elements)) return; n3 = Integer.parseInt(nStr); n4 = n3; } else { nStr = elements.substring(index, commaIndex); if (checkEmpty(nStr, elements)) return; n3 = Integer.parseInt(nStr); nStr = elements.substring(commaIndex+1); if (nStr == null || nStr.length() == 0) n4 = n3; else n4 = Integer.parseInt(nStr); } } catch (NumberFormatException e) { /* if (this.stderrListener != null) { String[] debugOut = { "NumberFormatException "+e.getMessage() }; // NOI18N stderrListener.match(debugOut); } */ //Edeb("NumberFormatException "+e.getMessage()); // NOI18N return; } //action.setChangeAction(n1, n2, n3, n4); //diffActions.add(action); differences.add(new Difference(Difference.CHANGE, n1, n2, n3, n4)); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy