001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.maven.scm.provider.svn.command.diff;
020
021import java.io.File;
022import java.util.ArrayList;
023import java.util.HashMap;
024import java.util.List;
025import java.util.Map;
026
027import org.apache.maven.scm.ScmFile;
028import org.apache.maven.scm.ScmFileStatus;
029import org.apache.maven.scm.util.AbstractConsumer;
030
031/**
032 * @author <a href="mailto:brett@apache.org">Brett Porter</a>
033 * @author Olivier Lamy
034 */
035public class SvnDiffConsumer extends AbstractConsumer {
036    //
037    // Index: plugin.jelly
038    // ===================================================================
039    // --- plugin.jelly        (revision 124799)
040    // +++ plugin.jelly        (working copy)
041    //
042
043    private static final String INDEX_TOKEN = "Index: ";
044
045    private static final String FILE_SEPARATOR_TOKEN = "===";
046
047    private static final String START_REVISION_TOKEN = "---";
048
049    private static final String END_REVISION_TOKEN = "+++";
050
051    private static final String ADDED_LINE_TOKEN = "+";
052
053    private static final String REMOVED_LINE_TOKEN = "-";
054
055    private static final String UNCHANGED_LINE_TOKEN = " ";
056
057    private static final String CHANGE_SEPARATOR_TOKEN = "@@";
058
059    private static final String NO_NEWLINE_TOKEN = "\\ No newline at end of file";
060
061    private String currentFile;
062
063    private StringBuilder currentDifference;
064
065    private final List<ScmFile> changedFiles = new ArrayList<>();
066
067    private final Map<String, CharSequence> differences = new HashMap<>();
068
069    private final StringBuilder patch = new StringBuilder();
070
071    // ----------------------------------------------------------------------
072    //
073    // ----------------------------------------------------------------------
074
075    public SvnDiffConsumer(File workingDirectory) {
076        // empty
077    }
078
079    // ----------------------------------------------------------------------
080    // StreamConsumer Implementation
081    // ----------------------------------------------------------------------
082
083    /**
084     * {@inheritDoc}
085     */
086    public void consumeLine(String line) {
087        if (line.startsWith(INDEX_TOKEN)) {
088            // start a new file
089            currentFile = line.substring(INDEX_TOKEN.length());
090
091            changedFiles.add(new ScmFile(currentFile, ScmFileStatus.MODIFIED));
092
093            currentDifference = new StringBuilder();
094
095            differences.put(currentFile, currentDifference);
096
097            patch.append(line).append("\n");
098
099            return;
100        }
101
102        if (currentFile == null) {
103            if (logger.isWarnEnabled()) {
104                logger.warn("Unparseable line: '" + line + "'");
105            }
106            patch.append(line).append("\n");
107            return;
108        }
109
110        if (line.startsWith(FILE_SEPARATOR_TOKEN)) {
111            // skip
112            patch.append(line).append("\n");
113        } else if (line.startsWith(START_REVISION_TOKEN)) {
114            // skip, though could parse to verify filename, start revision
115            patch.append(line).append("\n");
116        } else if (line.startsWith(END_REVISION_TOKEN)) {
117            // skip, though could parse to verify filename, end revision
118            patch.append(line).append("\n");
119        } else if (line.startsWith(ADDED_LINE_TOKEN)
120                || line.startsWith(REMOVED_LINE_TOKEN)
121                || line.startsWith(UNCHANGED_LINE_TOKEN)
122                || line.startsWith(CHANGE_SEPARATOR_TOKEN)
123                || line.equals(NO_NEWLINE_TOKEN)) {
124            // add to buffer
125            currentDifference.append(line).append("\n");
126            patch.append(line).append("\n");
127        } else {
128            // TODO: handle property differences
129
130            if (logger.isWarnEnabled()) {
131                logger.warn("Unparseable line: '" + line + "'");
132            }
133            patch.append(line).append("\n");
134            // skip to next file
135            currentFile = null;
136            currentDifference = null;
137        }
138    }
139
140    public List<ScmFile> getChangedFiles() {
141        return changedFiles;
142    }
143
144    public Map<String, CharSequence> getDifferences() {
145        return differences;
146    }
147
148    public String getPatch() {
149        return patch.toString();
150    }
151}