diff options
Diffstat (limited to 'org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConfig.java')
-rw-r--r-- | org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConfig.java | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConfig.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConfig.java new file mode 100644 index 0000000000..0469337b1f --- /dev/null +++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/internal/LfsConfig.java @@ -0,0 +1,226 @@ +/* + * 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 + * if an IO error occurred + */ + 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 + * if an IO error occurred + */ + 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 + * if an IO error occurred + */ + @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 + * if an IO error occurred + */ + @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 + * if an IO error occurred + */ + @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 + * if an IO error occurred + */ + @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; + } +} |