123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290 |
- /*
- * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
- * Copyright (C) 2009-2010, Google Inc.
- * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
- * Copyright (C) 2006, Shawn O. Pearce <spearce@spearce.org>
- * 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.internal.storage.file;
-
- import static org.eclipse.jgit.lib.Constants.HEAD;
- import static org.eclipse.jgit.lib.Constants.LOGS;
- import static org.eclipse.jgit.lib.Constants.R_HEADS;
- import static org.eclipse.jgit.lib.Constants.R_REFS;
- import static org.eclipse.jgit.lib.Constants.R_REMOTES;
- import static org.eclipse.jgit.lib.Constants.R_STASH;
-
- import java.io.File;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.nio.ByteBuffer;
- import java.nio.channels.FileChannel;
- import java.text.MessageFormat;
-
- import org.eclipse.jgit.internal.JGitText;
- import org.eclipse.jgit.lib.Constants;
- import org.eclipse.jgit.lib.CoreConfig;
- import org.eclipse.jgit.lib.ObjectId;
- import org.eclipse.jgit.lib.PersonIdent;
- import org.eclipse.jgit.lib.Ref;
- import org.eclipse.jgit.lib.RefUpdate;
- import org.eclipse.jgit.lib.ReflogEntry;
- import org.eclipse.jgit.lib.Repository;
- import org.eclipse.jgit.util.FS;
- import org.eclipse.jgit.util.FileUtils;
-
- /**
- * Utility for writing reflog entries
- */
- public class ReflogWriter {
-
- /**
- * Get the ref name to be used for when locking a ref's log for rewriting
- *
- * @param name
- * name of the ref, relative to the Git repository top level
- * directory (so typically starts with refs/).
- * @return the name of the ref's lock ref
- */
- public static String refLockFor(final String name) {
- return name + LockFile.SUFFIX;
- }
-
- private final Repository parent;
-
- private final File logsDir;
-
- private final File logsRefsDir;
-
- private final boolean forceWrite;
-
- /**
- * Create write for repository
- *
- * @param repository
- */
- public ReflogWriter(final Repository repository) {
- this(repository, false);
- }
-
- /**
- * Create write for repository
- *
- * @param repository
- * @param forceWrite
- * true to write to disk all entries logged, false to respect the
- * repository's config and current log file status
- */
- public ReflogWriter(final Repository repository, final boolean forceWrite) {
- final FS fs = repository.getFS();
- parent = repository;
- File gitDir = repository.getDirectory();
- logsDir = fs.resolve(gitDir, LOGS);
- logsRefsDir = fs.resolve(gitDir, LOGS + '/' + R_REFS);
- this.forceWrite = forceWrite;
- }
-
- /**
- * Get repository that reflog is being written for
- *
- * @return file repository
- */
- public Repository getRepository() {
- return parent;
- }
-
- /**
- * Create the log directories
- *
- * @throws IOException
- * @return this writer
- */
- public ReflogWriter create() throws IOException {
- FileUtils.mkdir(logsDir);
- FileUtils.mkdir(logsRefsDir);
- FileUtils.mkdir(new File(logsRefsDir,
- R_HEADS.substring(R_REFS.length())));
- return this;
- }
-
- /**
- * Locate the log file on disk for a single reference name.
- *
- * @param name
- * name of the ref, relative to the Git repository top level
- * directory (so typically starts with refs/).
- * @return the log file location.
- */
- public File logFor(String name) {
- if (name.startsWith(R_REFS)) {
- name = name.substring(R_REFS.length());
- return new File(logsRefsDir, name);
- }
- return new File(logsDir, name);
- }
-
- /**
- * Write the given {@link ReflogEntry} entry to the ref's log
- *
- * @param refName
- *
- * @param entry
- * @return this writer
- * @throws IOException
- */
- public ReflogWriter log(final String refName, final ReflogEntry entry)
- throws IOException {
- return log(refName, entry.getOldId(), entry.getNewId(), entry.getWho(),
- entry.getComment());
- }
-
- /**
- * Write the given entry information to the ref's log
- *
- * @param refName
- * @param oldId
- * @param newId
- * @param ident
- * @param message
- * @return this writer
- * @throws IOException
- */
- public ReflogWriter log(final String refName, final ObjectId oldId,
- final ObjectId newId, final PersonIdent ident, final String message)
- throws IOException {
- byte[] encoded = encode(oldId, newId, ident, message);
- return log(refName, encoded);
- }
-
- /**
- * Write the given ref update to the ref's log
- *
- * @param update
- * @param msg
- * @param deref
- * @return this writer
- * @throws IOException
- */
- public ReflogWriter log(final RefUpdate update, final String msg,
- final boolean deref) throws IOException {
- final ObjectId oldId = update.getOldObjectId();
- final ObjectId newId = update.getNewObjectId();
- final Ref ref = update.getRef();
-
- PersonIdent ident = update.getRefLogIdent();
- if (ident == null)
- ident = new PersonIdent(parent);
- else
- ident = new PersonIdent(ident);
-
- final byte[] rec = encode(oldId, newId, ident, msg);
- if (deref && ref.isSymbolic()) {
- log(ref.getName(), rec);
- log(ref.getLeaf().getName(), rec);
- } else
- log(ref.getName(), rec);
-
- return this;
- }
-
- private byte[] encode(ObjectId oldId, ObjectId newId, PersonIdent ident,
- String message) {
- final StringBuilder r = new StringBuilder();
- r.append(ObjectId.toString(oldId));
- r.append(' ');
- r.append(ObjectId.toString(newId));
- r.append(' ');
- r.append(ident.toExternalString());
- r.append('\t');
- r.append(message.replace("\r\n", " ").replace("\n", " ")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
- r.append('\n');
- return Constants.encode(r.toString());
- }
-
- private ReflogWriter log(final String refName, final byte[] rec)
- throws IOException {
- final File log = logFor(refName);
- final boolean write = forceWrite
- || (isLogAllRefUpdates() && shouldAutoCreateLog(refName))
- || log.isFile();
- if (!write)
- return this;
-
- WriteConfig wc = getRepository().getConfig().get(WriteConfig.KEY);
- FileOutputStream out;
- try {
- out = new FileOutputStream(log, true);
- } catch (FileNotFoundException err) {
- final File dir = log.getParentFile();
- if (dir.exists())
- throw err;
- if (!dir.mkdirs() && !dir.isDirectory())
- throw new IOException(MessageFormat.format(
- JGitText.get().cannotCreateDirectory, dir));
- out = new FileOutputStream(log, true);
- }
- try {
- if (wc.getFSyncRefFiles()) {
- FileChannel fc = out.getChannel();
- ByteBuffer buf = ByteBuffer.wrap(rec);
- while (0 < buf.remaining())
- fc.write(buf);
- fc.force(true);
- } else
- out.write(rec);
- } finally {
- out.close();
- }
- return this;
- }
-
- private boolean isLogAllRefUpdates() {
- return parent.getConfig().get(CoreConfig.KEY).isLogAllRefUpdates();
- }
-
- private boolean shouldAutoCreateLog(final String refName) {
- return refName.equals(HEAD) //
- || refName.startsWith(R_HEADS) //
- || refName.startsWith(R_REMOTES) //
- || refName.equals(R_STASH);
- }
- }
|