2010-12-14 14 views
8

Przeszukuję wyniki Google za darmo (open source) Java diff libaries, i wydaje się całkiem sporo takich (niektórzy z nich pracują nawet z ogólnymi obiektami, a nie tylko z Stringami).Czy istnieje biblioteka Diff dla języka Java obsługująca funkcję Adnotate/Blame?

przed jestem kopanie przez tony wynikach wyszukiwania, a nie znalezienie tego, czego szukam, Spytam raz pierwszy tutaj:

Czy któryś z tych bibliotek diff obsługuje funkcję jak annotate cvs czy svn winy. Chcę

  • przekazać aktualną String[] do funkcji
  • kontynuować przechodząc starsze wersje String[] do funkcji, dopóki nie użyłem się wszyscy, czy biblioteka mówi mi, że nie oryginalna linia została Pozostało niezarejestrowane (ostatnia rzecz nie jest tak naprawdę koniecznością, ale bardzo przydatna, ponieważ pobieranie starszych wersji String[] jest kosztowne, dlatego chciałbym zakończyć tak wcześnie, jak to możliwe)
  • zadzwoń do funkcji, która daje mi ìnt[], która mówi mi każda linia aktualnej wersji, w której wersji została ostatnio zmieniona lub czy w ogóle się nie zmieniła (np t zmienił się w pierwszej wersji).

Posiadanie wsparcia dla obiektów, które nie są String s jest ładne, ale nie musi. A jeśli API nie jest dokładnie takie, myślę, że mógłbym z tym żyć.

Jeśli go nie ma, czy ktoś może zaproponować bibliotekę z rozszerzalną biblioteką różnicową, w której można łatwo dodać tę cechę, najlepiej taką, która chciałaby otrzymać tę funkcję jako wkład (i nie wymaga wypełniania dokumentów, zanim zaakceptuje wkłady, takie jak projekt GNU)? Chciałbym się zgłosić (przynajmniej spróbować) dodać go tam.

Odpowiedz

2

postanowiłem wdrożyć go sobie za java-diff-utils biblioteki Dmitrija Naumenko za:

/* 
    Copyright 2010 Michael Schierl ([email protected]) 

    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 difflib.annotate; 

import java.util.*; 

import difflib.*; 

/** 
* Generates an annotated version of a revision based on a list of older 
* revisions, like <tt>cvs annotate</tt> or <tt>svn blame</tt>. 
* 
* @author <a href="[email protected]">Michael Schierl</a> 
* 
* @param <R> 
*   Type of the revision metadata 
*/ 
public class Annotate<R> { 

    private final List<R> revisions; 
    private final int[] lineNumbers; 
    private R currentRevision; 
    private final List<Object> currentLines; 
    private final List<Integer> currentLineMap; 

    /** 
    * Creates a new annotation generator. 
    * 
    * @param revision 
    *   Revision metadata for the revision to be annotated 
    * @param targetLines 
    *   Lines of the revision to be annotated 
    */ 
    public Annotate(R revision, List<?> targetLines) { 
     revisions = new ArrayList<R>(); 
     lineNumbers = new int[targetLines.size()]; 
     currentRevision = revision; 
     currentLines = new ArrayList<Object>(targetLines); 
     currentLineMap = new ArrayList<Integer>(); 
     for (int i = 0; i < lineNumbers.length; i++) { 
      lineNumbers[i] = -1; 
      revisions.add(null); 
      currentLineMap.add(i); 
     } 
    } 

    /** 
    * Check whether there are still lines that are unannotated. In that case, 
    * more older revisions should be retrieved and passed to the function. Note 
    * that as soon as you pass an empty revision, all lines will be annotated 
    * (with a later revision), therefore if you do not have any more revisions, 
    * pass an empty revision to annotate the rest of the lines. 
    */ 
    public boolean areLinesUnannotated() { 
     for (int i = 0; i < lineNumbers.length; i++) { 
      if (lineNumbers[i] == -1 || revisions.get(i) == null) 
       return true; 
     } 
     return false; 
    } 

    /** 
    * Add the previous revision and update annotation info. 
    * 
    * @param revision 
    *   Revision metadata for this revision 
    * @param lines 
    *   Lines of this revision 
    */ 
    public void addRevision(R revision, List<?> lines) { 
     Patch patch = DiffUtils.diff(currentLines, lines); 
     int lineOffset = 0; // remember number of already deleted/added lines 
     for (Delta d : patch.getDeltas()) { 
      Chunk original = d.getOriginal(); 
      Chunk revised = d.getRevised(); 
      int pos = original.getPosition() + lineOffset; 
      // delete lines 
      for (int i = 0; i < original.getSize(); i++) { 
       int origLine = currentLineMap.remove(pos); 
       currentLines.remove(pos); 
       if (origLine != -1) { 
        lineNumbers[origLine] = original.getPosition() + i; 
        revisions.set(origLine, currentRevision); 
       } 
      } 
      for (int i = 0; i < revised.getSize(); i++) { 
       currentLines.add(pos + i, revised.getLines().get(i)); 
       currentLineMap.add(pos + i, -1); 
      } 
      lineOffset += revised.getSize() - original.getSize(); 
     } 

     currentRevision = revision; 
     if (!currentLines.equals(lines)) 
      throw new RuntimeException("Patch application failed"); 
    } 

    /** 
    * Return the result of the annotation. It will be a List of the same length 
    * as the target revision, for which every entry states the revision where 
    * the line appeared last. 
    */ 
    public List<R> getAnnotatedRevisions() { 
     return Collections.unmodifiableList(revisions); 
    } 

    /** 
    * Return the result of the annotation. It will be a List of the same length 
    * as the target revision, for which every entry states the line number in 
    * the revision where the line appeared last. 
    */ 
    public int[] getAnnotatedLineNumbers() { 
     return (int[]) lineNumbers.clone(); 
    } 
} 

ja również wysłał go do Dmitrij Naumenko (z kilku przypadków testowych) w przypadku chce umieścić go.

1

Mogę się mylić, ale myślę, że adnotacja/obwinianie wymaga działania systemu kontroli wersji, ponieważ musi on uzyskać dostęp do historii pliku. Ogólna biblioteka diff nie może tego zrobić. Więc jeśli to jest twój cel, sprawdź biblioteki współpracujące z tymi VCS, takie jak svnkit. Jeśli nie, taka biblioteka może być dobrym punktem wyjścia do tego, jak przebiega adnotacja/winę, bardzo często wiąże się to ze zmianą łańcucha wszystkich wersji pliku.

+0

mam wszystkie starsze wersje pliku, który jest nie problem (jak napisano w pytaniu). Po prostu nie w VCS, który wspiera Blame. Zaangażowanie ich w tymczasowy SVN tylko po to, by obwiniać jeden plik, nie jest tym, za czym jestem ... Algorytm nie jest tu najtrudniejszy (tak, dotyczy to różnicowania wszystkich wersji i śledzenia, gdzie numery linii będą się pojawiać i kiedy "znikają"), po prostu trzeba to wdrożyć :) – mihi

+1

Gotcha. Innym pomysłem byłoby przyjrzeć się kodowi źródłowemu wiki wiki. Ponieważ zazwyczaj muszą być implementowane, kod może tam być. http://c2.com/cgi/wiki?JavaWikiEngines wyświetla niektóre. – vasquez

1

Można użyć xwiki-commons-blame-api. To faktycznie korzysta code from this thread's accepted answer (Thanks to Michael Schierl for sharing this code on StackOverflow)

Można zobaczyć, jak używać go w Javie w it's unit tests.

Albo w Scala jak:

import java.util 
import org.xwiki.blame.AnnotatedContent 
import org.xwiki.blame.internal.DefaultBlameManager 

case class Revision(id: Int, 
        parentId: Option[Int] = None, 
        content: Option[String] = None) 

def createAnnotation(revisions: Seq[Revision]): Option[AnnotatedContent[Revision, String]] = { 
    val blameManager = new DefaultBlameManager() 

    val annotatedContent = revisions.foldLeft(null.asInstanceOf[AnnotatedContent[Revision, String]]){ 
     (annotation, revision) => 
     blameManager.blame(annotation, revision, splitByWords(revision.content)) 
    } 
    Option(annotatedContent) 
} 

def splitByWords(content: Option[String]): util.List[String] = { 
    val array = content.fold(Array[String]())(_.split("[^\\pL_\\pN]+")) 
    util.Arrays.asList(array:_*) 
} 
Powiązane problemy