Package org.eclipse.jgit.api

Source Code of org.eclipse.jgit.api.ApplyCommand

/*
* Copyright (C) 2011, 2012, IBM Corporation and others.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
*   notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
*   copyright notice, this list of conditions and the following
*   disclaimer in the documentation and/or other materials provided
*   with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
*   names of its contributors may be used to endorse or promote
*   products derived from this software without specific prior
*   written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.api;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.PatchApplyException;
import org.eclipse.jgit.api.errors.PatchFormatException;
import org.eclipse.jgit.diff.DiffEntry.ChangeType;
import org.eclipse.jgit.diff.RawText;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.patch.FileHeader;
import org.eclipse.jgit.patch.HunkHeader;
import org.eclipse.jgit.patch.Patch;
import org.eclipse.jgit.util.FileUtils;
import org.eclipse.jgit.util.IO;

/**
* Apply a patch to files and/or to the index.
*
* @see <a href="http://www.kernel.org/pub/software/scm/git/docs/git-apply.html"
*      >Git documentation about apply</a>
* @since 2.0
*/
public class ApplyCommand extends GitCommand<ApplyResult> {

  private InputStream in;

  /**
   * Constructs the command if the patch is to be applied to the index.
   *
   * @param repo
   */
  ApplyCommand(Repository repo) {
    super(repo);
  }

  /**
   * @param in
   *            the patch to apply
   * @return this instance
   */
  public ApplyCommand setPatch(InputStream in) {
    checkCallable();
    this.in = in;
    return this;
  }

  /**
   * Executes the {@code ApplyCommand} command with all the options and
   * parameters collected by the setter methods (e.g.
   * {@link #setPatch(InputStream)} of this class. Each instance of this class
   * should only be used for one invocation of the command. Don't call this
   * method twice on an instance.
   *
   * @return an {@link ApplyResult} object representing the command result
   * @throws GitAPIException
   * @throws PatchFormatException
   * @throws PatchApplyException
   */
  public ApplyResult call() throws GitAPIException, PatchFormatException,
      PatchApplyException {
    checkCallable();
    ApplyResult r = new ApplyResult();
    try {
      final Patch p = new Patch();
      try {
        p.parse(in);
      } finally {
        in.close();
      }
      if (!p.getErrors().isEmpty())
        throw new PatchFormatException(p.getErrors());
      for (FileHeader fh : p.getFiles()) {
        ChangeType type = fh.getChangeType();
        File f = null;
        switch (type) {
        case ADD:
          f = getFile(fh.getNewPath(), true);
          apply(f, fh);
          break;
        case MODIFY:
          f = getFile(fh.getOldPath(), false);
          apply(f, fh);
          break;
        case DELETE:
          f = getFile(fh.getOldPath(), false);
          if (!f.delete())
            throw new PatchApplyException(MessageFormat.format(
                JGitText.get().cannotDeleteFile, f));
          break;
        case RENAME:
          f = getFile(fh.getOldPath(), false);
          File dest = getFile(fh.getNewPath(), false);
          if (!f.renameTo(dest))
            throw new PatchApplyException(MessageFormat.format(
                JGitText.get().renameFileFailed, f, dest));
          break;
        case COPY:
          f = getFile(fh.getOldPath(), false);
          byte[] bs = IO.readFully(f);
          FileWriter fw = new FileWriter(getFile(fh.getNewPath(),
              true));
          fw.write(new String(bs));
          fw.close();
        }
        r.addUpdatedFile(f);
      }
    } catch (IOException e) {
      throw new PatchApplyException(MessageFormat.format(
          JGitText.get().patchApplyException, e.getMessage()), e);
    }
    setCallable(false);
    return r;
  }

  private File getFile(String path, boolean create)
      throws PatchApplyException {
    File f = new File(getRepository().getWorkTree(), path);
    if (create)
      try {
        File parent = f.getParentFile();
        FileUtils.mkdirs(parent, true);
        FileUtils.createNewFile(f);
      } catch (IOException e) {
        throw new PatchApplyException(MessageFormat.format(
            JGitText.get().createNewFileFailed, f), e);
      }
    return f;
  }

  /**
   * @param f
   * @param fh
   * @throws IOException
   * @throws PatchApplyException
   */
  private void apply(File f, FileHeader fh)
      throws IOException, PatchApplyException {
    RawText rt = new RawText(f);
    List<String> oldLines = new ArrayList<String>(rt.size());
    for (int i = 0; i < rt.size(); i++)
      oldLines.add(rt.getString(i));
    List<String> newLines = new ArrayList<String>(oldLines);
    for (HunkHeader hh : fh.getHunks()) {
      StringBuilder hunk = new StringBuilder();
      for (int j = hh.getStartOffset(); j < hh.getEndOffset(); j++)
        hunk.append((char) hh.getBuffer()[j]);
      RawText hrt = new RawText(hunk.toString().getBytes());
      List<String> hunkLines = new ArrayList<String>(hrt.size());
      for (int i = 0; i < hrt.size(); i++)
        hunkLines.add(hrt.getString(i));
      int pos = 0;
      for (int j = 1; j < hunkLines.size(); j++) {
        String hunkLine = hunkLines.get(j);
        switch (hunkLine.charAt(0)) {
        case ' ':
          if (!newLines.get(hh.getNewStartLine() - 1 + pos).equals(
              hunkLine.substring(1))) {
            throw new PatchApplyException(MessageFormat.format(
                JGitText.get().patchApplyException, hh));
          }
          pos++;
          break;
        case '-':
          if (!newLines.get(hh.getNewStartLine() - 1 + pos).equals(
              hunkLine.substring(1))) {
            throw new PatchApplyException(MessageFormat.format(
                JGitText.get().patchApplyException, hh));
          }
          newLines.remove(hh.getNewStartLine() - 1 + pos);
          break;
        case '+':
          newLines.add(hh.getNewStartLine() - 1 + pos,
              hunkLine.substring(1));
          pos++;
          break;
        }
      }
    }
    if (!isNoNewlineAtEndOfFile(fh))
      newLines.add("");
    if (!rt.isMissingNewlineAtEnd())
      oldLines.add("");
    if (!isChanged(oldLines, newLines))
      return; // don't touch the file
    StringBuilder sb = new StringBuilder();
    final String eol = rt.size() == 0
        || (rt.size() == 1 && rt.isMissingNewlineAtEnd()) ? "\n" : rt
        .getLineDelimiter();
    for (String l : newLines) {
      sb.append(l);
      if (eol != null)
        sb.append(eol);
    }
    sb.deleteCharAt(sb.length() - 1);
    FileWriter fw = new FileWriter(f);
    fw.write(sb.toString());
    fw.close();
  }

  private boolean isChanged(List<String> ol, List<String> nl) {
    if (ol.size() != nl.size())
      return true;
    for (int i = 0; i < ol.size(); i++)
      if (!ol.get(i).equals(nl.get(i)))
        return true;
    return false;
  }

  private boolean isNoNewlineAtEndOfFile(FileHeader fh) {
    HunkHeader lastHunk = fh.getHunks().get(fh.getHunks().size() - 1);
    RawText lhrt = new RawText(lastHunk.getBuffer());
    return lhrt.getString(lhrt.size() - 1).equals(
        "\\ No newline at end of file"); //$NON-NLS-1$
  }
}
TOP

Related Classes of org.eclipse.jgit.api.ApplyCommand

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.