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 *
035 */
036public class SvnDiffConsumer extends AbstractConsumer {
037    //
038    // Index: plugin.jelly
039    // ===================================================================
040    // --- plugin.jelly        (revision 124799)
041    // +++ plugin.jelly        (working copy)
042    //
043
044    private static final String INDEX_TOKEN = "Index: ";
045
046    private static final String FILE_SEPARATOR_TOKEN = "===";
047
048    private static final String START_REVISION_TOKEN = "---";
049
050    private static final String END_REVISION_TOKEN = "+++";
051
052    private static final String ADDED_LINE_TOKEN = "+";
053
054    private static final String REMOVED_LINE_TOKEN = "-";
055
056    private static final String UNCHANGED_LINE_TOKEN = " ";
057
058    private static final String CHANGE_SEPARATOR_TOKEN = "@@";
059
060    private static final String NO_NEWLINE_TOKEN = "\\ No newline at end of file";
061
062    private String currentFile;
063
064    private StringBuilder currentDifference;
065
066    private final List<ScmFile> changedFiles = new ArrayList<>();
067
068    private final Map<String, CharSequence> differences = new HashMap<>();
069
070    private final StringBuilder patch = new StringBuilder();
071
072    // ----------------------------------------------------------------------
073    //
074    // ----------------------------------------------------------------------
075
076    public SvnDiffConsumer(File workingDirectory) {
077        // empty
078    }
079
080    // ----------------------------------------------------------------------
081    // StreamConsumer Implementation
082    // ----------------------------------------------------------------------
083
084    /** {@inheritDoc} */
085    public void consumeLine(String line) {
086        if (line.startsWith(INDEX_TOKEN)) {
087            // start a new file
088            currentFile = line.substring(INDEX_TOKEN.length());
089
090            changedFiles.add(new ScmFile(currentFile, ScmFileStatus.MODIFIED));
091
092            currentDifference = new StringBuilder();
093
094            differences.put(currentFile, currentDifference);
095
096            patch.append(line).append("\n");
097
098            return;
099        }
100
101        if (currentFile == null) {
102            if (logger.isWarnEnabled()) {
103                logger.warn("Unparseable line: '" + line + "'");
104            }
105            patch.append(line).append("\n");
106            return;
107        }
108
109        if (line.startsWith(FILE_SEPARATOR_TOKEN)) {
110            // skip
111            patch.append(line).append("\n");
112        } else if (line.startsWith(START_REVISION_TOKEN)) {
113            // skip, though could parse to verify filename, start revision
114            patch.append(line).append("\n");
115        } else if (line.startsWith(END_REVISION_TOKEN)) {
116            // skip, though could parse to verify filename, end revision
117            patch.append(line).append("\n");
118        } else if (line.startsWith(ADDED_LINE_TOKEN)
119                || line.startsWith(REMOVED_LINE_TOKEN)
120                || line.startsWith(UNCHANGED_LINE_TOKEN)
121                || line.startsWith(CHANGE_SEPARATOR_TOKEN)
122                || line.equals(NO_NEWLINE_TOKEN)) {
123            // add to buffer
124            currentDifference.append(line).append("\n");
125            patch.append(line).append("\n");
126        } else {
127            // TODO: handle property differences
128
129            if (logger.isWarnEnabled()) {
130                logger.warn("Unparseable line: '" + line + "'");
131            }
132            patch.append(line).append("\n");
133            // skip to next file
134            currentFile = null;
135            currentDifference = null;
136        }
137    }
138
139    public List<ScmFile> getChangedFiles() {
140        return changedFiles;
141    }
142
143    public Map<String, CharSequence> getDifferences() {
144        return differences;
145    }
146
147    public String getPatch() {
148        return patch.toString();
149    }
150}