| /* |
| * Copyright (C) 2022, Matthias Fromme <mfromme@dspace.de> |
| * |
| * 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. |
| * |
| * SPDX-License-Identifier: BSD-3-Clause |
| */ |
| package org.eclipse.jgit.lfs.internal; |
| |
| import java.io.File; |
| import java.io.IOException; |
| |
| import org.eclipse.jgit.annotations.Nullable; |
| import org.eclipse.jgit.dircache.DirCacheEntry; |
| import org.eclipse.jgit.errors.ConfigInvalidException; |
| import org.eclipse.jgit.lfs.errors.LfsConfigInvalidException; |
| import org.eclipse.jgit.lfs.lib.Constants; |
| import org.eclipse.jgit.lib.BlobBasedConfig; |
| import org.eclipse.jgit.lib.Config; |
| import org.eclipse.jgit.lib.ObjectId; |
| import org.eclipse.jgit.lib.Repository; |
| import org.eclipse.jgit.revwalk.RevCommit; |
| import org.eclipse.jgit.revwalk.RevTree; |
| import org.eclipse.jgit.revwalk.RevWalk; |
| import org.eclipse.jgit.storage.file.FileBasedConfig; |
| import org.eclipse.jgit.treewalk.TreeWalk; |
| |
| import static org.eclipse.jgit.lib.Constants.HEAD; |
| |
| /** |
| * Encapsulate access to the {@code .lfsconfig}. |
| * <p> |
| * According to the git lfs documentation the order to find the |
| * {@code .lfsconfig} file is: |
| * </p> |
| * <ol> |
| * <li>in the root of the working tree</li> |
| * <li>in the index</li> |
| * <li>in the HEAD; for bare repositories this is the only place that is |
| * searched</li> |
| * </ol> |
| * <p> |
| * Values from the {@code .lfsconfig} are used only if not specified in another |
| * git config file to allow local override without modifiction of a committed |
| * file. |
| * </p> |
| * |
| * @see <a href= |
| * "https://github.com/git-lfs/git-lfs/blob/main/docs/man/git-lfs-config.5.ronn">Configuration |
| * options for git-lfs</a> |
| */ |
| public class LfsConfig { |
| private Repository db; |
| private Config delegate; |
| |
| /** |
| * Create a new instance of the LfsConfig. |
| * |
| * @param db |
| * the associated repo |
| */ |
| public LfsConfig(Repository db) { |
| this.db = db; |
| } |
| |
| /** |
| * Getter for the delegate to allow lazy initialization. |
| * |
| * @return the delegate {@link Config} |
| * @throws IOException |
| */ |
| private Config getDelegate() throws IOException { |
| if (delegate == null) { |
| delegate = this.load(); |
| } |
| return delegate; |
| } |
| |
| /** |
| * Read the .lfsconfig file from the repository |
| * |
| * An empty config is returned be empty if no lfs config exists. |
| * |
| * @return The loaded lfs config |
| * |
| * @throws IOException |
| */ |
| private Config load() throws IOException { |
| Config result = null; |
| |
| if (!db.isBare()) { |
| result = loadFromWorkingTree(); |
| if (result == null) { |
| result = loadFromIndex(); |
| } |
| } |
| |
| if (result == null) { |
| result = loadFromHead(); |
| } |
| |
| if (result == null) { |
| result = emptyConfig(); |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Try to read the lfs config from a file called .lfsconfig at the top level |
| * of the working tree. |
| * |
| * @return the config, or <code>null</code> |
| * @throws IOException |
| */ |
| @Nullable |
| private Config loadFromWorkingTree() |
| throws IOException { |
| File lfsConfig = db.getFS().resolve(db.getWorkTree(), |
| Constants.DOT_LFS_CONFIG); |
| if (lfsConfig.isFile()) { |
| FileBasedConfig config = new FileBasedConfig(lfsConfig, db.getFS()); |
| try { |
| config.load(); |
| return config; |
| } catch (ConfigInvalidException e) { |
| throw new LfsConfigInvalidException( |
| LfsText.get().dotLfsConfigReadFailed, e); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Try to read the lfs config from an entry called .lfsconfig contained in |
| * the index. |
| * |
| * @return the config, or <code>null</code> if the entry does not exist |
| * @throws IOException |
| */ |
| @Nullable |
| private Config loadFromIndex() |
| throws IOException { |
| try { |
| DirCacheEntry entry = db.readDirCache() |
| .getEntry(Constants.DOT_LFS_CONFIG); |
| if (entry != null) { |
| return new BlobBasedConfig(null, db, entry.getObjectId()); |
| } |
| } catch (ConfigInvalidException e) { |
| throw new LfsConfigInvalidException( |
| LfsText.get().dotLfsConfigReadFailed, e); |
| } |
| return null; |
| } |
| |
| /** |
| * Try to read the lfs config from an entry called .lfsconfig contained in |
| * the head revision. |
| * |
| * @return the config, or <code>null</code> if the file does not exist |
| * @throws IOException |
| */ |
| @Nullable |
| private Config loadFromHead() throws IOException { |
| try (RevWalk revWalk = new RevWalk(db)) { |
| ObjectId headCommitId = db.resolve(HEAD); |
| if (headCommitId == null) { |
| return null; |
| } |
| RevCommit commit = revWalk.parseCommit(headCommitId); |
| RevTree tree = commit.getTree(); |
| TreeWalk treewalk = TreeWalk.forPath(db, Constants.DOT_LFS_CONFIG, |
| tree); |
| if (treewalk != null) { |
| return new BlobBasedConfig(null, db, treewalk.getObjectId(0)); |
| } |
| } catch (ConfigInvalidException e) { |
| throw new LfsConfigInvalidException( |
| LfsText.get().dotLfsConfigReadFailed, e); |
| } |
| return null; |
| } |
| |
| /** |
| * Create an empty config as fallback to avoid null pointer checks. |
| * |
| * @return an empty config |
| */ |
| private Config emptyConfig() { |
| return new Config(); |
| } |
| |
| /** |
| * Get string value or null if not found. |
| * |
| * First tries to find the value in the git config files. If not found tries |
| * to find data in .lfsconfig. |
| * |
| * @param section |
| * the section |
| * @param subsection |
| * the subsection for the value |
| * @param name |
| * the key name |
| * @return a String value from the config, <code>null</code> if not found |
| * @throws IOException |
| */ |
| @Nullable |
| public String getString(final String section, final String subsection, |
| final String name) throws IOException { |
| String result = db.getConfig().getString(section, subsection, name); |
| if (result == null) { |
| result = getDelegate().getString(section, subsection, name); |
| } |
| return result; |
| } |
| } |