aspnetcore/src/dotnet-user-secrets/Internal/ProjectIdResolver.cs

125 lines
4.2 KiB
C#

// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.Extensions.CommandLineUtils;
using Microsoft.Extensions.Tools.Internal;
namespace Microsoft.Extensions.SecretManager.Tools.Internal
{
public class ProjectIdResolver
{
private const string DefaultConfig = "Debug";
private readonly IReporter _reporter;
private readonly string _targetsFile;
private readonly string _workingDirectory;
public ProjectIdResolver(IReporter reporter, string workingDirectory)
{
_workingDirectory = workingDirectory;
_reporter = reporter;
_targetsFile = FindTargetsFile();
}
public string Resolve(string project, string configuration)
{
var finder = new MsBuildProjectFinder(_workingDirectory);
var projectFile = finder.FindMsBuildProject(project);
_reporter.Verbose(Resources.FormatMessage_Project_File_Path(projectFile));
configuration = !string.IsNullOrEmpty(configuration)
? configuration
: DefaultConfig;
var outputFile = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
try
{
var args = new[]
{
"msbuild",
projectFile,
"/nologo",
"/t:_ExtractUserSecretsMetadata", // defined in SecretManager.targets
"/p:_UserSecretsMetadataFile=" + outputFile,
"/p:Configuration=" + configuration,
"/p:CustomAfterMicrosoftCommonTargets=" + _targetsFile,
"/p:CustomAfterMicrosoftCommonCrossTargetingTargets=" + _targetsFile,
};
var psi = new ProcessStartInfo
{
FileName = DotNetMuxer.MuxerPathOrDefault(),
Arguments = ArgumentEscaper.EscapeAndConcatenate(args),
RedirectStandardOutput = true,
RedirectStandardError = true
};
#if DEBUG
_reporter.Verbose($"Invoking '{psi.FileName} {psi.Arguments}'");
#endif
var process = Process.Start(psi);
process.WaitForExit();
if (process.ExitCode != 0)
{
_reporter.Verbose(process.StandardOutput.ReadToEnd());
_reporter.Verbose(process.StandardError.ReadToEnd());
throw new InvalidOperationException(Resources.FormatError_ProjectFailedToLoad(projectFile));
}
var id = File.ReadAllText(outputFile)?.Trim();
if (string.IsNullOrEmpty(id))
{
throw new InvalidOperationException(Resources.FormatError_ProjectMissingId(projectFile));
}
return id;
}
finally
{
TryDelete(outputFile);
}
}
private string FindTargetsFile()
{
var assemblyDir = Path.GetDirectoryName(typeof(ProjectIdResolver).Assembly.Location);
var searchPaths = new[]
{
Path.Combine(AppContext.BaseDirectory, "assets"),
Path.Combine(assemblyDir, "assets"),
AppContext.BaseDirectory,
assemblyDir,
};
var targetPath = searchPaths.Select(p => Path.Combine(p, "SecretManager.targets")).FirstOrDefault(File.Exists);
if (targetPath == null)
{
_reporter.Error("Fatal error: could not find SecretManager.targets");
return null;
}
return targetPath;
}
private static void TryDelete(string file)
{
try
{
if (File.Exists(file))
{
File.Delete(file);
}
}
catch
{
// whatever
}
}
}
}