diff --git a/NuGet.config b/NuGet.config
index e2979ff6..0f08cd2b 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -4,7 +4,7 @@
-
+
diff --git a/eng/Version.Details.props b/eng/Version.Details.props
index c1806d5c..f9a1127a 100644
--- a/eng/Version.Details.props
+++ b/eng/Version.Details.props
@@ -6,19 +6,17 @@ This file should be imported by eng/Versions.props
- 10.0.0-beta.25513.109
- 2.0.0
-
- 17.11.31
- 17.11.31
+ 18.0.3
+ 18.0.3
+ 10.0.0-beta.25555.106
+ 2.0.1
- $(MicrosoftDotNetArcadeSdkPackageVersion)
- $(SystemCommandLinePackageVersion)
-
$(MicrosoftBuildPackageVersion)
$(MicrosoftBuildTasksCorePackageVersion)
+ $(MicrosoftDotNetArcadeSdkPackageVersion)
+ $(SystemCommandLinePackageVersion)
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index ac5ec951..bb3d8982 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -1,25 +1,25 @@
-
+
-
+
https://github.com/dotnet/dotnet
- 3a0c62bf027fbcb8683a13e78a5b21ae19028ca3
+ e17b0d08def649f30aed9c09cf4a2c5741a3c76c
-
+
https://github.com/dotnet/dotnet
- 3a0c62bf027fbcb8683a13e78a5b21ae19028ca3
+ e17b0d08def649f30aed9c09cf4a2c5741a3c76c
-
- https://github.com/dotnet/msbuild
- 933b72e36e86c22ba73e8b8148488f8298bb73c7
+
+ https://github.com/dotnet/dotnet
+ e17b0d08def649f30aed9c09cf4a2c5741a3c76c
-
- https://github.com/dotnet/msbuild
- 933b72e36e86c22ba73e8b8148488f8298bb73c7
+
+ https://github.com/dotnet/dotnet
+ e17b0d08def649f30aed9c09cf4a2c5741a3c76c
diff --git a/eng/Versions.props b/eng/Versions.props
index c19d7d61..36828ab8 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -14,6 +14,6 @@
6.12.1
- 8.0.5
+ 9.0.0
diff --git a/eng/common/SetupNugetSources.ps1 b/eng/common/SetupNugetSources.ps1
index fc8d6180..65ed3a8a 100644
--- a/eng/common/SetupNugetSources.ps1
+++ b/eng/common/SetupNugetSources.ps1
@@ -1,6 +1,7 @@
# This script adds internal feeds required to build commits that depend on internal package sources. For instance,
-# dotnet6-internal would be added automatically if dotnet6 was found in the nuget.config file. In addition also enables
-# disabled internal Maestro (darc-int*) feeds.
+# dotnet6-internal would be added automatically if dotnet6 was found in the nuget.config file. Similarly,
+# dotnet-eng-internal and dotnet-tools-internal are added if dotnet-eng and dotnet-tools are present.
+# In addition, this script also enables disabled internal Maestro (darc-int*) feeds.
#
# Optionally, this script also adds a credential entry for each of the internal feeds if supplied.
#
@@ -173,4 +174,16 @@ foreach ($dotnetVersion in $dotnetVersions) {
}
}
+# Check for dotnet-eng and add dotnet-eng-internal if present
+$dotnetEngSource = $sources.SelectSingleNode("add[@key='dotnet-eng']")
+if ($dotnetEngSource -ne $null) {
+ AddOrEnablePackageSource -Sources $sources -DisabledPackageSources $disabledSources -SourceName "dotnet-eng-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet-eng-internal/nuget/$feedSuffix" -Creds $creds -Username $userName -pwd $Password
+}
+
+# Check for dotnet-tools and add dotnet-tools-internal if present
+$dotnetToolsSource = $sources.SelectSingleNode("add[@key='dotnet-tools']")
+if ($dotnetToolsSource -ne $null) {
+ AddOrEnablePackageSource -Sources $sources -DisabledPackageSources $disabledSources -SourceName "dotnet-tools-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet-tools-internal/nuget/$feedSuffix" -Creds $creds -Username $userName -pwd $Password
+}
+
$doc.Save($filename)
diff --git a/eng/common/SetupNugetSources.sh b/eng/common/SetupNugetSources.sh
index dd2564ae..b2163abb 100755
--- a/eng/common/SetupNugetSources.sh
+++ b/eng/common/SetupNugetSources.sh
@@ -1,8 +1,9 @@
#!/usr/bin/env bash
# This script adds internal feeds required to build commits that depend on internal package sources. For instance,
-# dotnet6-internal would be added automatically if dotnet6 was found in the nuget.config file. In addition also enables
-# disabled internal Maestro (darc-int*) feeds.
+# dotnet6-internal would be added automatically if dotnet6 was found in the nuget.config file. Similarly,
+# dotnet-eng-internal and dotnet-tools-internal are added if dotnet-eng and dotnet-tools are present.
+# In addition, this script also enables disabled internal Maestro (darc-int*) feeds.
#
# Optionally, this script also adds a credential entry for each of the internal feeds if supplied.
#
@@ -66,10 +67,8 @@ EnableInternalPackageSource() {
grep -i " /dev/null
if [ "$?" == "0" ]; then
echo "Enabling internal source '$PackageSourceName'."
- # Remove the disabled entry
- local OldDisableValue=""
- local NewDisableValue=""
- sed -i.bak "s|$OldDisableValue|$NewDisableValue|" "$ConfigFile"
+ # Remove the disabled entry (including any surrounding comments or whitespace on the same line)
+ sed -i.bak "//d" "$ConfigFile"
# Add the source name to PackageSources for credential handling
PackageSources+=("$PackageSourceName")
@@ -175,6 +174,18 @@ for DotNetVersion in ${DotNetVersions[@]} ; do
fi
done
+# Check for dotnet-eng and add dotnet-eng-internal if present
+grep -i " /dev/null
+if [ "$?" == "0" ]; then
+ AddOrEnablePackageSource "dotnet-eng-internal" "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet-eng-internal/nuget/$FeedSuffix"
+fi
+
+# Check for dotnet-tools and add dotnet-tools-internal if present
+grep -i " /dev/null
+if [ "$?" == "0" ]; then
+ AddOrEnablePackageSource "dotnet-tools-internal" "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet-tools-internal/nuget/$FeedSuffix"
+fi
+
# I want things split line by line
PrevIFS=$IFS
IFS=$'\n'
diff --git a/eng/common/core-templates/steps/install-microbuild.yml b/eng/common/core-templates/steps/install-microbuild.yml
index d6b9878f..f2248ebf 100644
--- a/eng/common/core-templates/steps/install-microbuild.yml
+++ b/eng/common/core-templates/steps/install-microbuild.yml
@@ -11,23 +11,22 @@ parameters:
# Unfortunately, _SignType can't be used to exclude the use of the service connection in non-real sign scenarios. The
# variable is not available in template expression. _SignType has a very large proliferation across .NET, so replacing it is tough.
microbuildUseESRP: true
- # Location of the MicroBuild output folder
- # NOTE: There's something that relies on this being in the "default" source directory for tasks such as Signing to work properly.
- microBuildOutputFolder: '$(Build.SourcesDirectory)'
continueOnError: false
steps:
- ${{ if eq(parameters.enableMicrobuild, 'true') }}:
- ${{ if eq(parameters.enableMicrobuildForMacAndLinux, 'true') }}:
- # Needed to download the MicroBuild plugin nupkgs on Mac and Linux when nuget.exe is unavailable
+ # Installing .NET 8 is required to use the MicroBuild signing plugin on non-Windows platforms
- task: UseDotNet@2
displayName: Install .NET 8.0 SDK for MicroBuild Plugin
inputs:
packageType: sdk
version: 8.0.x
- installationPath: ${{ parameters.microBuildOutputFolder }}/.dotnet
- workingDirectory: ${{ parameters.microBuildOutputFolder }}
+ # Installing the SDK in a '.dotnet-microbuild' directory is required for signing.
+ # See target FindDotNetPathForMicroBuild in arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/Sign.proj
+ # Do not remove '.dotnet-microbuild' from the path without changing the corresponding logic.
+ installationPath: $(Agent.TempDirectory)/.dotnet-microbuild
condition: and(succeeded(), ne(variables['Agent.Os'], 'Windows_NT'))
- script: |
@@ -65,7 +64,7 @@ steps:
ConnectedPMEServiceName: 248d384a-b39b-46e3-8ad5-c2c210d5e7ca
env:
TeamName: $(_TeamName)
- MicroBuildOutputFolderOverride: ${{ parameters.microBuildOutputFolder }}
+ MicroBuildOutputFolderOverride: $(Agent.TempDirectory)/MicroBuild
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
continueOnError: ${{ parameters.continueOnError }}
condition: and(succeeded(), eq(variables['Agent.Os'], 'Windows_NT'), in(variables['_SignType'], 'real', 'test'))
@@ -85,7 +84,7 @@ steps:
ConnectedPMEServiceName: c24de2a5-cc7a-493d-95e4-8e5ff5cad2bc
env:
TeamName: $(_TeamName)
- MicroBuildOutputFolderOverride: ${{ parameters.microBuildOutputFolder }}
+ MicroBuildOutputFolderOverride: $(Agent.TempDirectory)/MicroBuild
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
continueOnError: ${{ parameters.continueOnError }}
condition: and(succeeded(), ne(variables['Agent.Os'], 'Windows_NT'), eq(variables['_SignType'], 'real'))
diff --git a/global.json b/global.json
index e25e6ecf..f22164a1 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,6 @@
{
"sdk": {
- "version": "10.0.100-rc.1.25451.107",
+ "version": "10.0.100-rc.2.25502.107",
"allowPrerelease": true,
"rollForward": "latestFeature",
"paths": [
@@ -10,10 +10,10 @@
"errorMessage": "The required .NET SDK wasn't found. Please run ./eng/common/dotnet.cmd/sh to install it."
},
"tools": {
- "dotnet": "10.0.100-rc.1.25451.107"
+ "dotnet": "10.0.100-rc.2.25502.107"
},
"msbuild-sdks": {
- "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25513.109",
+ "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25555.106",
"Microsoft.Build.NoTargets": "3.7.0"
}
}
diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props
index a1ab4835..ad5b1a5b 100644
--- a/src/Directory.Packages.props
+++ b/src/Directory.Packages.props
@@ -13,10 +13,6 @@
-
-
-
-
@@ -24,6 +20,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Microsoft.Build.Tasks.Git.UnitTests/GitConfigTests.cs b/src/Microsoft.Build.Tasks.Git.UnitTests/GitConfigTests.cs
index 0b506b1a..c0d7a6c7 100644
--- a/src/Microsoft.Build.Tasks.Git.UnitTests/GitConfigTests.cs
+++ b/src/Microsoft.Build.Tasks.Git.UnitTests/GitConfigTests.cs
@@ -20,6 +20,26 @@ private static GitConfig LoadFromString(string gitDirectory, string configPath,
=> new GitConfig.Reader(gitDirectory, gitDirectory, GitEnvironment.Empty, _ => new StringReader(configContent)).
LoadFrom(configPath);
+ [Theory]
+ [InlineData("sha1", ObjectFormat.Sha1)]
+ [InlineData("sha256", ObjectFormat.Sha256)]
+ internal void TryParseObjectFormat_Valid(string str, ObjectFormat expected)
+ {
+ Assert.Equal(expected, GitConfig.ParseObjectFormat(str));
+ }
+
+ [Theory]
+ [InlineData("")]
+ [InlineData("Sha1")]
+ [InlineData("sha-1")]
+ [InlineData("sha-256")]
+ [InlineData("sha384")]
+ [InlineData("sha512")]
+ internal void TryParseObjectFormat_Invalid(string str)
+ {
+ Assert.Throws(() => GitConfig.ParseObjectFormat(str));
+ }
+
[Fact]
public void Sections()
{
diff --git a/src/Microsoft.Build.Tasks.Git.UnitTests/GitReferenceResolverTests.cs b/src/Microsoft.Build.Tasks.Git.UnitTests/GitReferenceResolverTests.cs
index c61fb555..cd8a8c16 100644
--- a/src/Microsoft.Build.Tasks.Git.UnitTests/GitReferenceResolverTests.cs
+++ b/src/Microsoft.Build.Tasks.Git.UnitTests/GitReferenceResolverTests.cs
@@ -33,13 +33,40 @@ public void ResolveReference()
Assert.Equal("0000000000000000000000000000000000000000", resolver.ResolveReference("ref: refs/heads/br1"));
Assert.Equal("0000000000000000000000000000000000000000", resolver.ResolveReference("ref: refs/heads/br2"));
- // branch without commits (emtpy repository) will have not file in refs/heads:
+ // branch without commits (empty repository) will have not file in refs/heads:
Assert.Null(resolver.ResolveReference("ref: refs/heads/none"));
Assert.Null(resolver.ResolveReference("ref: refs/heads/rec1 "));
Assert.Null(resolver.ResolveReference("ref: refs/heads/none" + string.Join("/", Path.GetInvalidPathChars())));
}
+ [Fact]
+ public void ResolveReference_SHA256()
+ {
+ using var temp = new TempRoot();
+
+ var gitDir = temp.CreateDirectory();
+
+ var commonDir = temp.CreateDirectory();
+ var refsHeadsDir = commonDir.CreateDirectory("refs").CreateDirectory("heads");
+
+ // SHA256 hash (64 characters)
+ refsHeadsDir.CreateFile("master").WriteAllText("0000000000000000000000000000000000000000000000000000000000000000");
+ refsHeadsDir.CreateFile("br1").WriteAllText("ref: refs/heads/br2");
+ refsHeadsDir.CreateFile("br2").WriteAllText("ref: refs/heads/master");
+
+ var resolver = new GitReferenceResolver(gitDir.Path, commonDir.Path);
+
+ // Verify SHA256 hash is accepted directly
+ Assert.Equal(
+ "0123456789ABCDEFabcdef00000000000000000000000000000000000000000000",
+ resolver.ResolveReference("0123456789ABCDEFabcdef00000000000000000000000000000000000000000000"));
+
+ Assert.Equal("0000000000000000000000000000000000000000000000000000000000000000", resolver.ResolveReference("ref: refs/heads/master"));
+ Assert.Equal("0000000000000000000000000000000000000000000000000000000000000000", resolver.ResolveReference("ref: refs/heads/br1"));
+ Assert.Equal("0000000000000000000000000000000000000000000000000000000000000000", resolver.ResolveReference("ref: refs/heads/br2"));
+ }
+
[Fact]
public void ResolveReference_Errors()
{
@@ -59,8 +86,14 @@ public void ResolveReference_Errors()
Assert.Throws(() => resolver.ResolveReference("ref: xyz/heads/rec1"));
Assert.Throws(() => resolver.ResolveReference("ref:refs/heads/rec1"));
Assert.Throws(() => resolver.ResolveReference("refs/heads/rec1"));
+
+ // Invalid SHA1 hash lengths
Assert.Throws(() => resolver.ResolveReference(new string('0', 39)));
Assert.Throws(() => resolver.ResolveReference(new string('0', 41)));
+
+ // Invalid SHA256 hash lengths
+ Assert.Throws(() => resolver.ResolveReference(new string('0', 63)));
+ Assert.Throws(() => resolver.ResolveReference(new string('0', 65)));
}
[Fact]
@@ -87,6 +120,31 @@ 2222222222222222222222222222222222222222 refs/heads/br2
Assert.Equal("2222222222222222222222222222222222222222", resolver.ResolveReference("ref: refs/heads/br2"));
}
+ [Fact]
+ public void ResolveReference_Packed_SHA256()
+ {
+ using var temp = new TempRoot();
+
+ var gitDir = temp.CreateDirectory();
+
+ // Packed refs with SHA256 hashes (64 characters)
+ gitDir.CreateFile("packed-refs").WriteAllText(
+@"# pack-refs with: peeled fully-peeled sorted
+1111111111111111111111111111111111111111111111111111111111111111 refs/heads/master
+2222222222222222222222222222222222222222222222222222222222222222 refs/heads/br2
+");
+ var commonDir = temp.CreateDirectory();
+ var refsHeadsDir = commonDir.CreateDirectory("refs").CreateDirectory("heads");
+
+ refsHeadsDir.CreateFile("br1").WriteAllText("ref: refs/heads/br2");
+
+ var resolver = new GitReferenceResolver(gitDir.Path, commonDir.Path);
+
+ Assert.Equal("1111111111111111111111111111111111111111111111111111111111111111", resolver.ResolveReference("ref: refs/heads/master"));
+ Assert.Equal("2222222222222222222222222222222222222222222222222222222222222222", resolver.ResolveReference("ref: refs/heads/br1"));
+ Assert.Equal("2222222222222222222222222222222222222222222222222222222222222222", resolver.ResolveReference("ref: refs/heads/br2"));
+ }
+
[Fact]
public void ReadPackedReferences()
{
@@ -110,6 +168,29 @@ 7777777777777777777777777777777777777777 refs/heads/br
}, actual.Select(e => $"{e.Key}:{e.Value}"));
}
+ [Fact]
+ public void ReadPackedReferences_SHA256()
+ {
+ var packedRefs =
+@"# pack-refs with:
+1111111111111111111111111111111111111111111111111111111111111111 refs/heads/master
+2222222222222222222222222222222222222222222222222222222222222222 refs/heads/br
+^3333333333333333333333333333333333333333333333333333333333333333
+4444444444444444444444444444444444444444444444444444444444444444 x
+5555555555555555555555555555555555555555555555555555555555555555 y
+6666666666666666666666666666666666666666666666666666666666666666 y z
+7777777777777777777777777777777777777777777777777777777777777777 refs/heads/br
+";
+
+ var actual = GitReferenceResolver.ReadPackedReferences(new StringReader(packedRefs), "");
+
+ AssertEx.SetEqual(new[]
+ {
+ "refs/heads/br:2222222222222222222222222222222222222222222222222222222222222222",
+ "refs/heads/master:1111111111111111111111111111111111111111111111111111111111111111"
+ }, actual.Select(e => $"{e.Key}:{e.Value}"));
+ }
+
[Theory]
[InlineData("# pack-refs with:")]
[InlineData("# pack-refs with:xyz")]
diff --git a/src/Microsoft.Build.Tasks.Git.UnitTests/GitRepositoryTests.cs b/src/Microsoft.Build.Tasks.Git.UnitTests/GitRepositoryTests.cs
index 7ba9993d..7cc4eb83 100644
--- a/src/Microsoft.Build.Tasks.Git.UnitTests/GitRepositoryTests.cs
+++ b/src/Microsoft.Build.Tasks.Git.UnitTests/GitRepositoryTests.cs
@@ -226,6 +226,7 @@ public void OpenRepository_Version1_Extensions()
preciousObjects = true
partialClone = promisor_remote
worktreeConfig = true
+ objectformat = sha256
");
Assert.True(GitRepository.TryFindRepository(gitDir.Path, out var location));
@@ -264,6 +265,36 @@ public void OpenRepository_Version1_UnknownExtension()
Assert.Throws(() => GitRepository.OpenRepository(src.Path, new GitEnvironment(homeDir.Path)));
}
+ [Fact]
+ public void OpenRepository_Version1_ObjectFormatExtension()
+ {
+ using var temp = new TempRoot();
+
+ var homeDir = temp.CreateDirectory();
+
+ var workingDir = temp.CreateDirectory();
+ var gitDir = workingDir.CreateDirectory(".git");
+
+ gitDir.CreateFile("HEAD").WriteAllText("ref: refs/heads/master");
+ gitDir.CreateDirectory("refs").CreateDirectory("heads").CreateFile("master").WriteAllText("0000000000000000000000000000000000000000");
+ gitDir.CreateDirectory("objects");
+
+ gitDir.CreateFile("config").WriteAllText(@"
+[core]
+ repositoryformatversion = 1
+[extensions]
+ objectformat = sha256");
+
+ var src = workingDir.CreateDirectory("src");
+
+ // Should not throw - objectformat extension should be supported
+ var repository = GitRepository.OpenRepository(src.Path, new GitEnvironment(homeDir.Path));
+ Assert.NotNull(repository);
+ Assert.Equal(gitDir.Path, repository.GitDirectory);
+ Assert.Equal(gitDir.Path, repository.CommonDirectory);
+ Assert.Equal(workingDir.Path, repository.WorkingDirectory);
+ }
+
[Fact]
public void OpenRepository_VersionNotSupported()
{
diff --git a/src/Microsoft.Build.Tasks.Git/GitDataReader/GitConfig.cs b/src/Microsoft.Build.Tasks.Git/GitDataReader/GitConfig.cs
index 5d57c7b6..1b120a46 100644
--- a/src/Microsoft.Build.Tasks.Git/GitDataReader/GitConfig.cs
+++ b/src/Microsoft.Build.Tasks.Git/GitDataReader/GitConfig.cs
@@ -5,11 +5,9 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
-using System.Diagnostics;
-using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
-using System.Text;
+using System.Runtime.Serialization;
namespace Microsoft.Build.Tasks.Git
{
@@ -17,12 +15,57 @@ internal sealed partial class GitConfig
{
public static readonly GitConfig Empty = new GitConfig(ImmutableDictionary>.Empty);
+ private const int SupportedGitRepoFormatVersion = 1;
+
+ public const string CoreSectionName = "core";
+ public const string ExtensionsSectionName = "extensions";
+
+ public const string ObjectFormatVariableName = "objectFormat";
+ public const string RepositoryFormatVersionVariableName = "repositoryformatversion";
+
+ private static readonly ImmutableArray s_knownExtensions = ["noop", "preciousObjects", "partialclone", "worktreeConfig", ObjectFormatVariableName];
+
public readonly ImmutableDictionary> Variables;
+ ///
+ /// The parsed value of "extensions.objectFormat" variable.
+ ///
+ public ObjectFormat ObjectFormat { get; }
+
+ ///
public GitConfig(ImmutableDictionary> variables)
{
NullableDebug.Assert(variables != null);
Variables = variables;
+
+ ObjectFormat = GetVariableValue(ExtensionsSectionName, ObjectFormatVariableName) is { } objectFormatStr
+ ? ParseObjectFormat(objectFormatStr)
+ : ObjectFormat.Sha1;
+ }
+
+ ///
+ internal void ValidateFormat()
+ {
+ // See https://github.com/git/git/blob/master/Documentation/technical/repository-version.txt
+ string? versionStr = GetVariableValue(CoreSectionName, RepositoryFormatVersionVariableName);
+ if (TryParseInt64Value(versionStr, out var version) && version > SupportedGitRepoFormatVersion)
+ {
+ throw new NotSupportedException(string.Format(Resources.UnsupportedRepositoryVersion, versionStr, SupportedGitRepoFormatVersion));
+ }
+
+ if (version == 1)
+ {
+ // All variables defined under extensions section must be known, otherwise a git implementation is not allowed to proced.
+ foreach (var variable in Variables)
+ {
+ if (variable.Key.SectionNameEquals(ExtensionsSectionName) &&
+ !s_knownExtensions.Contains(variable.Key.VariableName, StringComparer.OrdinalIgnoreCase))
+ {
+ throw new NotSupportedException(string.Format(
+ Resources.UnsupportedRepositoryExtension, variable.Key.VariableName, string.Join(", ", s_knownExtensions)));
+ }
+ }
+ }
}
// for testing:
@@ -125,5 +168,14 @@ internal static bool TryParseInt64Value(string? str, out long value)
return true;
}
+
+ // internal for testing
+ internal static ObjectFormat ParseObjectFormat(string value)
+ => value switch
+ {
+ "sha1" => ObjectFormat.Sha1,
+ "sha256" => ObjectFormat.Sha256,
+ _ => throw new InvalidDataException(),
+ };
}
}
diff --git a/src/Microsoft.Build.Tasks.Git/GitDataReader/GitReferenceResolver.cs b/src/Microsoft.Build.Tasks.Git/GitDataReader/GitReferenceResolver.cs
index 7d970c09..13840b2d 100644
--- a/src/Microsoft.Build.Tasks.Git/GitDataReader/GitReferenceResolver.cs
+++ b/src/Microsoft.Build.Tasks.Git/GitDataReader/GitReferenceResolver.cs
@@ -21,21 +21,23 @@ internal sealed class GitReferenceResolver
private readonly string _commonDirectory;
private readonly string _gitDirectory;
+ private readonly ObjectFormat _objectFormat;
// maps refs/heads references to the correspondign object ids:
private readonly Lazy> _lazyPackedReferences;
- public GitReferenceResolver(string gitDirectory, string commonDirectory)
+ public GitReferenceResolver(string gitDirectory, string commonDirectory, ObjectFormat objectFormat)
{
Debug.Assert(PathUtils.IsNormalized(gitDirectory));
Debug.Assert(PathUtils.IsNormalized(commonDirectory));
_gitDirectory = gitDirectory;
_commonDirectory = commonDirectory;
+ _objectFormat = objectFormat;
_lazyPackedReferences = new Lazy>(() => ReadPackedReferences(_gitDirectory));
}
- private static ImmutableDictionary ReadPackedReferences(string gitDirectory)
+ private ImmutableDictionary ReadPackedReferences(string gitDirectory)
{
// https://git-scm.com/docs/git-pack-refs
@@ -62,7 +64,7 @@ private static ImmutableDictionary ReadPackedReferences(string g
}
// internal for testing
- internal static ImmutableDictionary ReadPackedReferences(TextReader reader, string path)
+ internal ImmutableDictionary ReadPackedReferences(TextReader reader, string path)
{
var builder = ImmutableDictionary.CreateBuilder();
@@ -254,7 +256,7 @@ internal static string ReadReferenceFromFile(string path)
private string? ResolvePackedReference(string reference)
=> _lazyPackedReferences.Value.TryGetValue(reference, out var objectId) ? objectId : null;
- private static bool IsObjectId(string reference)
- => reference.Length == 40 && reference.All(CharUtils.IsHexadecimalDigit);
+ private bool IsObjectId(string reference)
+ => reference.Length == _objectFormat.HashLength * 2 && reference.All(CharUtils.IsHexadecimalDigit);
}
}
diff --git a/src/Microsoft.Build.Tasks.Git/GitDataReader/GitRepository.cs b/src/Microsoft.Build.Tasks.Git/GitDataReader/GitRepository.cs
index fc7446ea..4b677924 100644
--- a/src/Microsoft.Build.Tasks.Git/GitDataReader/GitRepository.cs
+++ b/src/Microsoft.Build.Tasks.Git/GitDataReader/GitRepository.cs
@@ -13,8 +13,6 @@ namespace Microsoft.Build.Tasks.Git
{
internal sealed class GitRepository
{
- private const int SupportedGitRepoFormatVersion = 1;
-
private const string CommonDirFileName = "commondir";
private const string GitDirName = ".git";
private const string GitDirPrefix = "gitdir: ";
@@ -24,9 +22,6 @@ internal sealed class GitRepository
private const string GitModulesFileName = ".gitmodules";
- private static readonly ImmutableArray s_knownExtensions =
- ImmutableArray.Create("noop", "preciousObjects", "partialclone", "worktreeConfig");
-
public GitConfig Config { get; }
public GitIgnore Ignore => _lazyIgnore.Value;
@@ -68,7 +63,7 @@ internal GitRepository(GitEnvironment environment, GitConfig config, string gitD
WorkingDirectory = workingDirectory;
Environment = environment;
- _referenceResolver = new GitReferenceResolver(gitDirectory, commonDirectory);
+ _referenceResolver = new GitReferenceResolver(gitDirectory, commonDirectory, config.ObjectFormat);
_lazySubmodules = new Lazy<(ImmutableArray, ImmutableArray)>(ReadSubmodules);
_lazyIgnore = new Lazy(LoadIgnore);
_lazyHeadCommitSha = new Lazy(ReadHeadCommitSha);
@@ -121,29 +116,10 @@ public static GitRepository OpenRepository(GitRepositoryLocation location, GitEn
var reader = new GitConfig.Reader(location.GitDirectory, location.CommonDirectory, environment);
var config = reader.Load();
+ config.ValidateFormat();
var workingDirectory = GetWorkingDirectory(config, location);
- // See https://github.com/git/git/blob/master/Documentation/technical/repository-version.txt
- string? versionStr = config.GetVariableValue("core", "repositoryformatversion");
- if (GitConfig.TryParseInt64Value(versionStr, out var version) && version > SupportedGitRepoFormatVersion)
- {
- throw new NotSupportedException(string.Format(Resources.UnsupportedRepositoryVersion, versionStr, SupportedGitRepoFormatVersion));
- }
-
- if (version == 1)
- {
- // All variables defined under extensions section must be known, otherwise a git implementation is not allowed to proced.
- foreach (var variable in config.Variables)
- {
- if (variable.Key.SectionNameEquals("extensions") && !s_knownExtensions.Contains(variable.Key.VariableName, StringComparer.OrdinalIgnoreCase))
- {
- throw new NotSupportedException(string.Format(
- Resources.UnsupportedRepositoryExtension, variable.Key.VariableName, string.Join(", ", s_knownExtensions)));
- }
- }
- }
-
return new GitRepository(environment, config, location.GitDirectory, location.CommonDirectory, workingDirectory);
}
diff --git a/src/Microsoft.Build.Tasks.Git/GitDataReader/ObjectFormat.cs b/src/Microsoft.Build.Tasks.Git/GitDataReader/ObjectFormat.cs
new file mode 100644
index 00000000..5fb67a8b
--- /dev/null
+++ b/src/Microsoft.Build.Tasks.Git/GitDataReader/ObjectFormat.cs
@@ -0,0 +1,31 @@
+// Licensed to the.NET Foundation under one or more agreements.
+// The.NET Foundation licenses this file to you under the MIT license.
+// See the License.txt file in the project root for more information.
+
+using System;
+
+namespace Microsoft.Build.Tasks.Git;
+
+///
+/// Format of object names.
+/// https://git-scm.com/docs/hash-function-transition.html#_object_format
+///
+internal enum ObjectFormat
+{
+ Sha1 = 1,
+ Sha256 = 2,
+}
+
+internal static class ObjectFormatExtensions
+{
+ extension(ObjectFormat self)
+ {
+ public int HashLength
+ => self switch
+ {
+ ObjectFormat.Sha1 => 20,
+ ObjectFormat.Sha256 => 32,
+ _ => throw new InvalidOperationException()
+ };
+ }
+}