aboutsummaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java')
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java240
1 files changed, 39 insertions, 201 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java
index 6a945e4d39..df0f616256 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java
@@ -1,68 +1,27 @@
/*
- * Copyright (C) 2011, 2012, IBM Corporation and others.
- * and other copyright owners as documented in the project's IP log.
+ * Copyright (C) 2011, 2021 IBM Corporation and others
*
- * 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
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://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.
+ * SPDX-License-Identifier: BSD-3-Clause
*/
package org.eclipse.jgit.api;
import java.io.File;
-import java.io.FileOutputStream;
-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;
+import org.eclipse.jgit.patch.PatchApplier;
+import org.eclipse.jgit.patch.PatchApplier.Result;
/**
* Apply a patch to files and/or to the index.
@@ -76,15 +35,21 @@ public class ApplyCommand extends GitCommand<ApplyResult> {
private InputStream in;
/**
- * Constructs the command if the patch is to be applied to the index.
+ * Constructs the command.
*
* @param repo
+ * the repository this command will be used on
*/
ApplyCommand(Repository repo) {
super(repo);
+ if (repo == null) {
+ throw new NullPointerException(JGitText.get().repositoryIsRequired);
+ }
}
/**
+ * Set patch
+ *
* @param in
* the patch to apply
* @return this instance
@@ -96,172 +61,45 @@ public class ApplyCommand extends GitCommand<ApplyResult> {
}
/**
+ * {@inheritDoc}
+ *
+ * <p>
* 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 {
+ @Override
+ public ApplyResult call() throws GitAPIException {
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);
- FileOutputStream fos = new FileOutputStream(getFile(
- fh.getNewPath(),
- true));
- try {
- fos.write(bs);
- } finally {
- fos.close();
- }
- }
- r.addUpdatedFile(f);
+ setCallable(false);
+ Patch patch = new Patch();
+ try (InputStream inStream = in) {
+ patch.parse(inStream);
+ if (!patch.getErrors().isEmpty()) {
+ throw new PatchFormatException(patch.getErrors());
}
} 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);
+ ApplyResult r = new ApplyResult();
+ try {
+ PatchApplier patchApplier = new PatchApplier(repo);
+ Result applyResult = patchApplier.applyPatch(patch);
+ if (!applyResult.getErrors().isEmpty()) {
+ throw new PatchApplyException(
+ MessageFormat.format(JGitText.get().patchApplyException,
+ applyResult.getErrors()));
}
- 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;
- }
+ for (String p : applyResult.getPaths()) {
+ r.addUpdatedFile(new File(repo.getWorkTree(), p));
}
+ } catch (IOException e) {
+ throw new PatchApplyException(MessageFormat.format(JGitText.get().patchApplyException,
+ e.getMessage(), e));
}
- if (!isNoNewlineAtEndOfFile(fh))
- newLines.add(""); //$NON-NLS-1$
- if (!rt.isMissingNewlineAtEnd())
- oldLines.add(""); //$NON-NLS-1$
- if (!isChanged(oldLines, newLines))
- return; // don't touch the file
- StringBuilder sb = new StringBuilder();
- for (String l : newLines) {
- // don't bother handling line endings - if it was windows, the \r is
- // still there!
- sb.append(l).append('\n');
- }
- sb.deleteCharAt(sb.length() - 1);
- FileWriter fw = new FileWriter(f);
- fw.write(sb.toString());
- fw.close();
- }
-
- private static 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$
+ return r;
}
}