| /* |
| * 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 |
| * the repository the AbbrevConfig shall be computed for |
| * @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; |
| |
| /** |
| * Create an {@code AbbrevConfig} |
| * |
| * @param abbrev |
| * abbreviation length |
| */ |
| 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); |
| } |
| } |