diff options
Diffstat (limited to 'org.eclipse.jgit/src/org/eclipse/jgit/lib/AbbrevConfig.java')
-rw-r--r-- | org.eclipse.jgit/src/org/eclipse/jgit/lib/AbbrevConfig.java | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AbbrevConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AbbrevConfig.java new file mode 100644 index 0000000000..9109cfd769 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AbbrevConfig.java @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2022, Matthias Sohn <matthias.sohn@sap.com> and others + * + * 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.lib; + +import static org.eclipse.jgit.lib.Constants.OBJECT_ID_ABBREV_STRING_LENGTH; +import static org.eclipse.jgit.lib.TypedConfigGetter.UNSET_INT; + +import java.text.MessageFormat; + +import org.eclipse.jgit.api.errors.InvalidConfigurationException; +import org.eclipse.jgit.internal.JGitText; + +/** + * Git configuration option <a + * href=https://git-scm.com/docs/git-config#Documentation/git-config.txt-coreabbrev"> + * core.abbrev</a> + * + * @since 6.1 + */ +public final class AbbrevConfig { + private static final String VALUE_NO = "no"; //$NON-NLS-1$ + + private static final String VALUE_AUTO = "auto"; //$NON-NLS-1$ + + /** + * The minimum value of abbrev + */ + public static final int MIN_ABBREV = 4; + + /** + * Cap configured core.abbrev to range between minimum of 4 and number of + * hex-digits of a full object id. + * + * @param len + * configured number of hex-digits to abbreviate object ids to + * @return core.abbrev capped to range between minimum of 4 and number of + * hex-digits of a full object id + */ + public static int capAbbrev(int len) { + return Math.min(Math.max(MIN_ABBREV, len), + Constants.OBJECT_ID_STRING_LENGTH); + } + + /** + * No abbreviation + */ + public final static AbbrevConfig NO = new AbbrevConfig( + Constants.OBJECT_ID_STRING_LENGTH); + + /** + * Parse string value of core.abbrev git option for a given repository + * + * @param repo + * repository + * @return the parsed AbbrevConfig + * @throws InvalidConfigurationException + * if value of core.abbrev is invalid + */ + public static AbbrevConfig parseFromConfig(Repository repo) + throws InvalidConfigurationException { + Config config = repo.getConfig(); + String value = config.getString(ConfigConstants.CONFIG_CORE_SECTION, + null, ConfigConstants.CONFIG_KEY_ABBREV); + if (value == null || value.equalsIgnoreCase(VALUE_AUTO)) { + return auto(repo); + } + if (value.equalsIgnoreCase(VALUE_NO)) { + return NO; + } + try { + int len = config.getIntInRange(ConfigConstants.CONFIG_CORE_SECTION, + ConfigConstants.CONFIG_KEY_ABBREV, MIN_ABBREV, + Constants.OBJECT_ID_STRING_LENGTH, UNSET_INT); + if (len == UNSET_INT) { + // Unset was checked above. If we get UNSET_INT here, then + // either the value was UNSET_INT, or it was an invalid value + // (not an integer, or out of range), and EGit's + // ReportingTypedGetter caught the exception and has logged a + // warning. In either case we should fall back to some sane + // default. + len = OBJECT_ID_ABBREV_STRING_LENGTH; + } + return new AbbrevConfig(len); + } catch (IllegalArgumentException e) { + throw new InvalidConfigurationException(MessageFormat + .format(JGitText.get().invalidCoreAbbrev, value), e); + } + } + + /** + * An appropriate value is computed based on the approximate number of + * packed objects in a repository, which hopefully is enough for abbreviated + * object names to stay unique for some time. + * + * @param repo + * @return appropriate value computed based on the approximate number of + * packed objects in a repository + */ + private static AbbrevConfig auto(Repository repo) { + long count = repo.getObjectDatabase().getApproximateObjectCount(); + if (count == -1) { + return new AbbrevConfig(OBJECT_ID_ABBREV_STRING_LENGTH); + } + // find msb, round to next power of 2 + int len = 63 - Long.numberOfLeadingZeros(count) + 1; + // With the order of 2^len objects, we expect a collision at + // 2^(len/2). But we also care about hex chars, not bits, and + // there are 4 bits per hex. So all together we need to divide + // by 2; but we also want to round odd numbers up, hence adding + // one before dividing. + len = (len + 1) / 2; + // for small repos use at least fallback length + return new AbbrevConfig(Math.max(len, OBJECT_ID_ABBREV_STRING_LENGTH)); + } + + /** + * All other possible abbreviation lengths. Valid range 4 to number of + * hex-digits of an unabbreviated object id (40 for SHA1 object ids, jgit + * doesn't support SHA256 yet). + */ + private int abbrev; + + /** + * @param abbrev + */ + private AbbrevConfig(int abbrev) { + this.abbrev = capAbbrev(abbrev); + } + + /** + * Get the configured abbreviation length for object ids. + * + * @return the configured abbreviation length for object ids + */ + public int get() { + return abbrev; + } + + @Override + public String toString() { + return Integer.toString(abbrev); + } +}
\ No newline at end of file |