Package org.eclipse.jgit.storage.file

Source Code of org.eclipse.jgit.storage.file.FileRepository

/*
* Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
* Copyright (C) 2008-2010, Google Inc.
* Copyright (C) 2006-2010, Robin Rosenberg <robin.rosenberg@dewire.com>
* Copyright (C) 2006-2008, 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.storage.file;

import java.io.File;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.HashSet;
import java.util.Set;

import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.events.ConfigChangedEvent;
import org.eclipse.jgit.events.ConfigChangedListener;
import org.eclipse.jgit.events.IndexChangedEvent;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.BaseRepositoryBuilder;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefDatabase;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.storage.file.FileObjectDatabase.AlternateHandle;
import org.eclipse.jgit.storage.file.FileObjectDatabase.AlternateRepository;
import org.eclipse.jgit.util.FileUtils;
import org.eclipse.jgit.util.SystemReader;

/**
* Represents a Git repository. A repository holds all objects and refs used for
* managing source code (could by any type of file, but source code is what
* SCM's are typically used for).
*
* In Git terms all data is stored in GIT_DIR, typically a directory called
* .git. A work tree is maintained unless the repository is a bare repository.
* Typically the .git directory is located at the root of the work dir.
*
* <ul>
* <li>GIT_DIR
*   <ul>
*     <li>objects/ - objects</li>
*     <li>refs/ - tags and heads</li>
*     <li>config - configuration</li>
*     <li>info/ - more configurations</li>
*   </ul>
* </li>
* </ul>
* <p>
* This class is thread-safe.
* <p>
* This implementation only handles a subtly undocumented subset of git features.
*
*/
public class FileRepository extends Repository {
  private final FileBasedConfig systemConfig;

  private final FileBasedConfig userConfig;

  private final FileBasedConfig repoConfig;

  private final RefDatabase refs;

  private final ObjectDirectory objectDatabase;

  private FileSnapshot snapshot;

  /**
   * Construct a representation of a Git repository.
   * <p>
   * The work tree, object directory, alternate object directories and index
   * file locations are deduced from the given git directory and the default
   * rules by running {@link FileRepositoryBuilder}. This constructor is the
   * same as saying:
   *
   * <pre>
   * new FileRepositoryBuilder().setGitDir(gitDir).build()
   * </pre>
   *
   * @param gitDir
   *            GIT_DIR (the location of the repository metadata).
   * @throws IOException
   *             the repository appears to already exist but cannot be
   *             accessed.
   * @see FileRepositoryBuilder
   */
  public FileRepository(final File gitDir) throws IOException {
    this(new FileRepositoryBuilder().setGitDir(gitDir).setup());
  }

  /**
   * A convenience API for {@link #FileRepository(File)}.
   *
   * @param gitDir
   *            GIT_DIR (the location of the repository metadata).
   * @throws IOException
   *             the repository appears to already exist but cannot be
   *             accessed.
   * @see FileRepositoryBuilder
   */
  public FileRepository(final String gitDir) throws IOException {
    this(new File(gitDir));
  }

  /**
   * Create a repository using the local file system.
   *
   * @param options
   *            description of the repository's important paths.
   * @throws IOException
   *             the user configuration file or repository configuration file
   *             cannot be accessed.
   */
  public FileRepository(final BaseRepositoryBuilder options) throws IOException {
    super(options);

    systemConfig = SystemReader.getInstance().openSystemConfig(null, getFS());
    userConfig = SystemReader.getInstance().openUserConfig(systemConfig,
        getFS());
    repoConfig = new FileBasedConfig(userConfig, getFS().resolve(
        getDirectory(), Constants.CONFIG),
        getFS());

    loadSystemConfig();
    loadUserConfig();
    loadRepoConfig();

    repoConfig.addChangeListener(new ConfigChangedListener() {
      public void onConfigChanged(ConfigChangedEvent event) {
        fireEvent(event);
      }
    });

    refs = new RefDirectory(this);
    objectDatabase = new ObjectDirectory(repoConfig, //
        options.getObjectDirectory(), //
        options.getAlternateObjectDirectories(), //
        getFS(), //
        new File(getDirectory(), Constants.SHALLOW));

    if (objectDatabase.exists()) {
      final long repositoryFormatVersion = getConfig().getLong(
          ConfigConstants.CONFIG_CORE_SECTION, null,
          ConfigConstants.CONFIG_KEY_REPO_FORMAT_VERSION, 0);
      if (repositoryFormatVersion > 0)
        throw new IOException(MessageFormat.format(
            JGitText.get().unknownRepositoryFormat2,
            Long.valueOf(repositoryFormatVersion)));
    }

    if (!isBare())
      snapshot = FileSnapshot.save(getIndexFile());
  }

  private void loadSystemConfig() throws IOException {
    try {
      systemConfig.load();
    } catch (ConfigInvalidException e1) {
      IOException e2 = new IOException(MessageFormat.format(JGitText
          .get().systemConfigFileInvalid, systemConfig.getFile()
          .getAbsolutePath(), e1));
      e2.initCause(e1);
      throw e2;
    }
  }

  private void loadUserConfig() throws IOException {
    try {
      userConfig.load();
    } catch (ConfigInvalidException e1) {
      IOException e2 = new IOException(MessageFormat.format(JGitText
          .get().userConfigFileInvalid, userConfig.getFile()
          .getAbsolutePath(), e1));
      e2.initCause(e1);
      throw e2;
    }
  }

  private void loadRepoConfig() throws IOException {
    try {
      repoConfig.load();
    } catch (ConfigInvalidException e1) {
      IOException e2 = new IOException(JGitText.get().unknownRepositoryFormat);
      e2.initCause(e1);
      throw e2;
    }
  }

  /**
   * Create a new Git repository initializing the necessary files and
   * directories.
   *
   * @param bare
   *            if true, a bare repository is created.
   *
   * @throws IOException
   *             in case of IO problem
   */
  public void create(boolean bare) throws IOException {
    final FileBasedConfig cfg = getConfig();
    if (cfg.getFile().exists()) {
      throw new IllegalStateException(MessageFormat.format(
          JGitText.get().repositoryAlreadyExists, getDirectory()));
    }
    FileUtils.mkdirs(getDirectory(), true);
    refs.create();
    objectDatabase.create();

    FileUtils.mkdir(new File(getDirectory(), "branches"));
    FileUtils.mkdir(new File(getDirectory(), "hooks"));

    RefUpdate head = updateRef(Constants.HEAD);
    head.disableRefLog();
    head.link(Constants.R_HEADS + Constants.MASTER);

    final boolean fileMode;
    if (getFS().supportsExecute()) {
      File tmp = File.createTempFile("try", "execute", getDirectory());

      getFS().setExecute(tmp, true);
      final boolean on = getFS().canExecute(tmp);

      getFS().setExecute(tmp, false);
      final boolean off = getFS().canExecute(tmp);
      FileUtils.delete(tmp);

      fileMode = on && !off;
    } else {
      fileMode = false;
    }

    cfg.setInt(ConfigConstants.CONFIG_CORE_SECTION, null,
        ConfigConstants.CONFIG_KEY_REPO_FORMAT_VERSION, 0);
    cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
        ConfigConstants.CONFIG_KEY_FILEMODE, fileMode);
    if (bare)
      cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
          ConfigConstants.CONFIG_KEY_BARE, true);
    cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
        ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, !bare);
    if (SystemReader.getInstance().isMacOS())
      // Java has no other way
      cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
          ConfigConstants.CONFIG_KEY_PRECOMPOSEUNICODE, true);
    cfg.save();
  }

  /**
   * @return the directory containing the objects owned by this repository.
   */
  public File getObjectsDirectory() {
    return objectDatabase.getDirectory();
  }

  /**
   * @return the object database which stores this repository's data.
   */
  public ObjectDirectory getObjectDatabase() {
    return objectDatabase;
  }

  /** @return the reference database which stores the reference namespace. */
  public RefDatabase getRefDatabase() {
    return refs;
  }

  /**
   * @return the configuration of this repository
   */
  public FileBasedConfig getConfig() {
    if (systemConfig.isOutdated()) {
      try {
        loadSystemConfig();
      } catch (IOException e) {
        throw new RuntimeException(e);
      }
    }
    if (userConfig.isOutdated()) {
      try {
        loadUserConfig();
      } catch (IOException e) {
        throw new RuntimeException(e);
      }
    }
    if (repoConfig.isOutdated()) {
        try {
          loadRepoConfig();
        } catch (IOException e) {
          throw new RuntimeException(e);
        }
    }
    return repoConfig;
  }

  /**
   * Objects known to exist but not expressed by {@link #getAllRefs()}.
   * <p>
   * When a repository borrows objects from another repository, it can
   * advertise that it safely has that other repository's references, without
   * exposing any other details about the other repository.  This may help
   * a client trying to push changes avoid pushing more than it needs to.
   *
   * @return unmodifiable collection of other known objects.
   */
  public Set<ObjectId> getAdditionalHaves() {
    HashSet<ObjectId> r = new HashSet<ObjectId>();
    for (AlternateHandle d : objectDatabase. myAlternates()) {
      if (d instanceof AlternateRepository) {
        Repository repo;

        repo = ((AlternateRepository) d).repository;
        for (Ref ref : repo.getAllRefs().values()) {
          if (ref.getObjectId() != null)
            r.add(ref.getObjectId());
          if (ref.getPeeledObjectId() != null)
            r.add(ref.getPeeledObjectId());
        }
        r.addAll(repo.getAdditionalHaves());
      }
    }
    return r;
  }

  /**
   * Add a single existing pack to the list of available pack files.
   *
   * @param pack
   *            path of the pack file to open.
   * @param idx
   *            path of the corresponding index file.
   * @throws IOException
   *             index file could not be opened, read, or is not recognized as
   *             a Git pack file index.
   */
  public void openPack(final File pack, final File idx) throws IOException {
    objectDatabase.openPack(pack, idx);
  }

  @Override
  public void scanForRepoChanges() throws IOException {
    getAllRefs(); // This will look for changes to refs
    detectIndexChanges();
  }

  /**
   * Detect index changes.
   */
  private void detectIndexChanges() {
    if (isBare())
      return;

    File indexFile = getIndexFile();
    if (snapshot == null)
      snapshot = FileSnapshot.save(indexFile);
    else if (snapshot.isModified(indexFile))
      notifyIndexChanged();
  }

  @Override
  public void notifyIndexChanged() {
    snapshot = FileSnapshot.save(getIndexFile());
    fireEvent(new IndexChangedEvent());
  }

  /**
   * @param refName
   * @return a {@link ReflogReader} for the supplied refname, or null if the
   *         named ref does not exist.
   * @throws IOException the ref could not be accessed.
   */
  public ReflogReader getReflogReader(String refName) throws IOException {
    Ref ref = getRef(refName);
    if (ref != null)
      return new ReflogReader(this, ref.getName());
    return null;
  }
}
TOP

Related Classes of org.eclipse.jgit.storage.file.FileRepository

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.