Domanda

Sto scavando i risultati di Google gratuitamente (open source) Java Diff Libaries, e sembrano un sacco di quelli (alcuni di loro che lavorano persino con oggetti generici e non solo con le corde).

Prima di scavare tonnellate di risultati di ricerca e non trovare quello che sto cercando, chiederò prima qui:

Una di queste librerie Diff supporta una funzionalità come la colpa CVS Annota o SVN. voglio

  • Passare la corrente String[] a una funzione
  • Continua a passare versioni precedenti del String[] a una funzione, fino a quando non li ho usati tutti, o la biblioteca mi dice che nessuna linea originale è stata lasciata senza annotazione (l'ultima cosa non è davvero un must ma molto utile da quando ha recuperato versioni precedenti delle versioni String[] è costoso quindi mi piacerebbe fermarmi il prima possibile)
  • Chiama una funzione che mi dà un ìnt[] Questo mi dice per ogni riga della versione attuale, in quale versione è stata modificata l'ultima volta o se non è stata cambiata affatto (cioè l'ultima modifica nella prima versione).

Avere supporto per oggetti che non lo sono StringS è carino, ma non deve. E se l'API non è esattamente così, immagino che potrei conviverci.

Se non c'è nessuno, qualcuno può suggerire una libreria diffamata in cui quella funzionalità può essere aggiunta facilmente, preferibilmente una che vorrebbe ricevere quella funzione come contributo (e non richiede che tonnellate di scartoffie siano riempite prima di accettare contributi, come il Progetto GNU)? Vorrei fare volontariato per (almeno provare a) aggiungerlo lì, allora.

È stato utile?

Soluzione

Ho deciso di implementarlo da solo per Dmitry Naumenko Java-Diff-Utils biblioteca:

/*
   Copyright 2010 Michael Schierl (schierlm@gmx.de)

   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="schierlm@gmx.de">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();
    }
}

L'ho anche inviato a Dmitry Naumenko (con alcuni casi di test) nel caso in cui voglia includerlo.

Altri suggerimenti

Potrei sbagliare, ma penso che annotare/colpa abbia bisogno di un sistema di controllo della versione per funzionare, poiché deve accedere alla cronologia del file. Una differenziata generica non può farlo. Quindi, se questo è il tuo obiettivo, dai un'occhiata alle biblioteche che funzionano con quei VC, come Svnkit. In caso contrario, una tale biblioteca può essere un buon punto di partenza su come viene fatto annotare/colpa, molto spesso ciò implica differenze nella catena di tutte le versioni di un file.

Puoi usareXWIKI-MOMMONS-BAME-API. In realtà usa Codice dalla risposta accettata da questo thread (Grazie a Michael Schierl per aver condiviso questo codice su StackOverflow)

Puoi vedere come usarlo in java in Sono test unitari.

O in Scala come:

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:_*)
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top