diff --git a/src/Microsoft.ComponentDetection.Detectors/dotnet/DotNetComponentDetector.cs b/src/Microsoft.ComponentDetection.Detectors/dotnet/DotNetComponentDetector.cs index 81be72d75..83e951224 100644 --- a/src/Microsoft.ComponentDetection.Detectors/dotnet/DotNetComponentDetector.cs +++ b/src/Microsoft.ComponentDetection.Detectors/dotnet/DotNetComponentDetector.cs @@ -4,6 +4,7 @@ namespace Microsoft.ComponentDetection.Detectors.DotNet; using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Reflection.PortableExecutable; @@ -56,39 +57,42 @@ public DotNetComponentDetector( public override IEnumerable Categories => ["DotNet"]; + [return: NotNullIfNotNull(nameof(path))] private string? NormalizeDirectory(string? path) => string.IsNullOrEmpty(path) ? path : Path.TrimEndingDirectorySeparator(this.pathUtilityService.NormalizePath(path)); /// - /// Given a path relative to sourceDirectory, and the same path in another filesystem, - /// determine what path could be replaced with root. + /// Given a path under sourceDirectory, and the same path in another filesystem, + /// determine what path could be replaced with sourceDirectory. /// - /// Some path under root, including the root path. - /// Path to the same file as but in a different root. + /// Some directory path under sourceDirectory, including sourceDirectory. + /// Path to the same directory as but in a different root. /// Portion of that corresponds to root, or null if it can not be rebased. - private string? GetRootRebasePath(string rootBasedPath, string? rebasePath) + private string? GetRootRebasePath(string sourceDirectoryBasedPath, string? rebasePath) { - if (string.IsNullOrEmpty(rebasePath) || string.IsNullOrEmpty(this.sourceDirectory) || string.IsNullOrEmpty(rootBasedPath)) + if (string.IsNullOrEmpty(rebasePath) || string.IsNullOrEmpty(this.sourceDirectory) || string.IsNullOrEmpty(sourceDirectoryBasedPath)) { return null; } // sourceDirectory is normalized, normalize others - rootBasedPath = this.pathUtilityService.NormalizePath(rootBasedPath); - rebasePath = this.pathUtilityService.NormalizePath(rebasePath); + sourceDirectoryBasedPath = this.NormalizeDirectory(sourceDirectoryBasedPath); + rebasePath = this.NormalizeDirectory(rebasePath); // nothing to do if the paths are the same - if (rebasePath.Equals(rootBasedPath, StringComparison.Ordinal)) + if (rebasePath.Equals(sourceDirectoryBasedPath, StringComparison.Ordinal)) { return null; } - // find the relative path under root. - var rootRelativePath = this.pathUtilityService.NormalizePath(Path.GetRelativePath(this.sourceDirectory!, rootBasedPath)); + // find the relative path under sourceDirectory. + var sourceDirectoryRelativePath = this.NormalizeDirectory(Path.GetRelativePath(this.sourceDirectory!, sourceDirectoryBasedPath)); + + this.Logger.LogDebug("Attempting to rebase {RebasePath} to {SourceDirectoryBasedPath} using relative {SourceDirectoryRelativePath}", rebasePath, sourceDirectoryBasedPath, sourceDirectoryRelativePath); // if the rebase path has the same relative portion, then we have a replacement. - if (rebasePath.EndsWith(rootRelativePath)) + if (rebasePath.EndsWith(sourceDirectoryRelativePath)) { - return rebasePath[..^rootRelativePath.Length]; + return rebasePath[..^sourceDirectoryRelativePath.Length]; } // The path didn't have a common relative path, it might have been copied from a completely different location since it was built. diff --git a/test/Microsoft.ComponentDetection.Detectors.Tests/DotNetComponentDetectorTests.cs b/test/Microsoft.ComponentDetection.Detectors.Tests/DotNetComponentDetectorTests.cs index bd0d98bb7..1067bbe9d 100644 --- a/test/Microsoft.ComponentDetection.Detectors.Tests/DotNetComponentDetectorTests.cs +++ b/test/Microsoft.ComponentDetection.Detectors.Tests/DotNetComponentDetectorTests.cs @@ -185,6 +185,12 @@ private static string ProjectAssets(string projectName, string outputPath, strin LockFile lockFile = new(); using var textWriter = new StringWriter(); + // assets file always includes a trailing separator + if (!Path.EndsInDirectorySeparator(outputPath)) + { + outputPath += Path.DirectorySeparatorChar; + } + lockFile.Targets = targetFrameworks.Select(tfm => new LockFileTarget() { TargetFramework = NuGetFramework.Parse(tfm) }).ToList(); lockFile.PackageSpec = new() {