/*
 * Copyright (C) 2013, Christian Halstrick <christian.halstrick@sap.com>
 * 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.lib;

import static java.nio.charset.StandardCharsets.UTF_8;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.LinkedList;
import java.util.List;

import org.eclipse.jgit.lib.RebaseTodoLine.Action;
import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.RawParseUtils;

Offers methods to read and write files formatted like the git-rebase-todo file
Since:3.2
/** * Offers methods to read and write files formatted like the git-rebase-todo * file * * @since 3.2 */
public class RebaseTodoFile { private Repository repo;
Constructor for RebaseTodoFile.
Params:
/** * Constructor for RebaseTodoFile. * * @param repo * a {@link org.eclipse.jgit.lib.Repository} object. */
public RebaseTodoFile(Repository repo) { this.repo = repo; }
Read a file formatted like the git-rebase-todo file. The "done" file is also formatted like the git-rebase-todo file. These files can be found in .git/rebase-merge/ or .git/rebase-append/ folders.
Params:
  • path – path to the file relative to the repository's git-dir. E.g. "rebase-merge/git-rebase-todo" or "rebase-append/done"
  • includeComments – true if also comments should be reported
Throws:
Returns:the list of steps
/** * Read a file formatted like the git-rebase-todo file. The "done" file is * also formatted like the git-rebase-todo file. These files can be found in * .git/rebase-merge/ or .git/rebase-append/ folders. * * @param path * path to the file relative to the repository's git-dir. E.g. * "rebase-merge/git-rebase-todo" or "rebase-append/done" * @param includeComments * <code>true</code> if also comments should be reported * @return the list of steps * @throws java.io.IOException */
public List<RebaseTodoLine> readRebaseTodo(String path, boolean includeComments) throws IOException { byte[] buf = IO.readFully(new File(repo.getDirectory(), path)); int ptr = 0; int tokenBegin = 0; List<RebaseTodoLine> r = new LinkedList<>(); while (ptr < buf.length) { tokenBegin = ptr; ptr = RawParseUtils.nextLF(buf, ptr); int lineStart = tokenBegin; int lineEnd = ptr - 2; if (lineEnd >= 0 && buf[lineEnd] == '\r') lineEnd--; // Handle comments if (buf[tokenBegin] == '#') { if (includeComments) parseComments(buf, tokenBegin, r, lineEnd); } else { // skip leading spaces+tabs+cr tokenBegin = nextParsableToken(buf, tokenBegin, lineEnd); // Handle empty lines (maybe empty after skipping leading // whitespace) if (tokenBegin == -1) { if (includeComments) r.add(new RebaseTodoLine(RawParseUtils.decode(buf, lineStart, 1 + lineEnd))); continue; } RebaseTodoLine line = parseLine(buf, tokenBegin, lineEnd); if (line == null) continue; r.add(line); } } return r; } private static void parseComments(byte[] buf, int tokenBegin, List<RebaseTodoLine> r, int lineEnd) { RebaseTodoLine line = null; String commentString = RawParseUtils.decode(buf, tokenBegin, lineEnd + 1); try { int skip = tokenBegin + 1; // skip '#' skip = nextParsableToken(buf, skip, lineEnd); if (skip != -1) { // try to parse the line as non-comment line = parseLine(buf, skip, lineEnd); if (line != null) { // successfully parsed as non-comment line // mark this line as a comment explicitly line.setAction(Action.COMMENT); // use the read line as comment string line.setComment(commentString); } } } catch (Exception e) { // parsing as non-comment line failed line = null; } finally { if (line == null) line = new RebaseTodoLine(commentString); r.add(line); } }
Skip leading space, tab, CR and LF characters
Params:
  • buf –
  • tokenBegin –
  • lineEnd –
Returns:the token within the range of the given buf that doesn't need to be skipped, -1 if no such token found within the range (i.e. empty line)
/** * Skip leading space, tab, CR and LF characters * * @param buf * @param tokenBegin * @param lineEnd * @return the token within the range of the given {@code buf} that doesn't * need to be skipped, {@code -1} if no such token found within the * range (i.e. empty line) */
private static int nextParsableToken(byte[] buf, int tokenBegin, int lineEnd) { while (tokenBegin <= lineEnd && (buf[tokenBegin] == ' ' || buf[tokenBegin] == '\t' || buf[tokenBegin] == '\r')) tokenBegin++; if (tokenBegin > lineEnd) return -1; return tokenBegin; } private static RebaseTodoLine parseLine(byte[] buf, int tokenBegin, int lineEnd) { RebaseTodoLine.Action action = null; AbbreviatedObjectId commit = null; int nextSpace = RawParseUtils.next(buf, tokenBegin, ' '); int tokenCount = 0; while (tokenCount < 3 && nextSpace <= lineEnd) { switch (tokenCount) { case 0: String actionToken = new String(buf, tokenBegin, nextSpace - tokenBegin - 1, UTF_8); tokenBegin = nextSpace; action = RebaseTodoLine.Action.parse(actionToken); if (action == null) return null; // parsing failed break; case 1: nextSpace = RawParseUtils.next(buf, tokenBegin, ' '); String commitToken; if (nextSpace > lineEnd + 1) { commitToken = new String(buf, tokenBegin, lineEnd - tokenBegin + 1, UTF_8); } else { commitToken = new String(buf, tokenBegin, nextSpace - tokenBegin - 1, UTF_8); } tokenBegin = nextSpace; commit = AbbreviatedObjectId.fromString(commitToken); break; case 2: return new RebaseTodoLine(action, commit, RawParseUtils.decode(buf, tokenBegin, 1 + lineEnd)); } tokenCount++; } if (tokenCount == 2) return new RebaseTodoLine(action, commit, ""); //$NON-NLS-1$ return null; }
Write a file formatted like a git-rebase-todo file.
Params:
  • path – path to the file relative to the repository's git-dir. E.g. "rebase-merge/git-rebase-todo" or "rebase-append/done"
  • steps – the steps to be written
  • append – whether to append to an existing file or to write a new file
Throws:
/** * Write a file formatted like a git-rebase-todo file. * * @param path * path to the file relative to the repository's git-dir. E.g. * "rebase-merge/git-rebase-todo" or "rebase-append/done" * @param steps * the steps to be written * @param append * whether to append to an existing file or to write a new file * @throws java.io.IOException */
public void writeRebaseTodoFile(String path, List<RebaseTodoLine> steps, boolean append) throws IOException { try (OutputStream fw = new BufferedOutputStream(new FileOutputStream( new File(repo.getDirectory(), path), append))) { StringBuilder sb = new StringBuilder(); for (RebaseTodoLine step : steps) { sb.setLength(0); if (RebaseTodoLine.Action.COMMENT.equals(step.action)) sb.append(step.getComment()); else { sb.append(step.getAction().toToken()); sb.append(" "); //$NON-NLS-1$ sb.append(step.getCommit().name()); sb.append(" "); //$NON-NLS-1$ sb.append(step.getShortMessage().trim()); } sb.append('\n'); fw.write(Constants.encode(sb.toString())); } } } }