private async Task <string> ResolveDepsFilePathFromBuildConfigAsync(string outputPath, ILogger logger, CancellationToken cancellationToken) { // Since we are resolving the deps file path it means the passed in outputPath is built using the default build // configuration (debug/release). We need to resolve the configuration by looking at the most recent build in the // output path. The output should look something like 'bin\Debug\netcoreapp1.0\HelloSvcutil.deps.json' using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, $"Resolving deps.json file ...").ConfigureAwait(false)) { var fileName = $"{Path.GetFileNameWithoutExtension(this.FileName)}.deps.json"; var depsFile = string.Empty; // find the most recent deps.json files under the project's bin folder built for the project's target framework. var binFolder = await PathHelper.TryFindFolderAsync("bin", outputPath, logger, cancellationToken).ConfigureAwait(false); if (Directory.Exists(binFolder)) { var depsFiles = Directory.GetFiles(binFolder, "*", SearchOption.AllDirectories) .Where(d => Path.GetFileName(d).Equals(fileName, RuntimeEnvironmentHelper.FileStringComparison)) .Where(f => PathHelper.GetFolderName(Path.GetDirectoryName(f)) == this.TargetFramework) .Select(f => new FileInfo(f)) .OrderByDescending(f => f.CreationTimeUtc); depsFile = depsFiles.FirstOrDefault()?.FullName; } await safeLogger.WriteMessageAsync($"deps file: {depsFile}", logToUI : false).ConfigureAwait(false); return(depsFile); } }
public async Task SaveAsync(ILogger logger, CancellationToken cancellationToken) { ThrowOnDisposed(); cancellationToken.ThrowIfCancellationRequested(); if (!_isSaved) { using (await SafeLogger.WriteStartOperationAsync(logger, $"Saving project file: \"{this.FullPath}\"").ConfigureAwait(false)) { if (!Directory.Exists(this.DirectoryPath)) { Directory.CreateDirectory(this.DirectoryPath); _ownsDirectory = true; } using (StreamWriter writer = File.CreateText(this.FullPath)) { await AsyncHelper.RunAsync(() => ProjectNode.Save(writer), cancellationToken).ConfigureAwait(false); } _isSaved = true; } } }
public static async Task <string> GetSdkPathAsync(string workingDirectory, ILogger logger, CancellationToken cancellationToken) { if (s_sdkPath == null) { using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, "Resolving .NETCore SDK path ...").ConfigureAwait(false)) { #if NETCORE10 var dotnetDir = Path.GetDirectoryName(typeof(int).GetTypeInfo().Assembly.Location); #else var dotnetDir = Path.GetDirectoryName(typeof(int).Assembly.Location); #endif while (dotnetDir != null && !(File.Exists(Path.Combine(dotnetDir, "dotnet")) || File.Exists(Path.Combine(dotnetDir, "dotnet.exe")))) { dotnetDir = Path.GetDirectoryName(dotnetDir); } if (dotnetDir != null) { var sdkVersion = await GetSdkVersionAsync(workingDirectory, logger, cancellationToken).ConfigureAwait(false); if (!string.IsNullOrEmpty(sdkVersion)) { s_sdkPath = Path.Combine(dotnetDir, "sdk", sdkVersion); } } await safeLogger.WriteMessageAsync($"SDK path: \"{s_sdkPath}\"", logToUI : false).ConfigureAwait(false); } } return(s_sdkPath); }
public async Task <IEnumerable <ProjectDependency> > ResolveProjectReferencesAsync(IEnumerable <ProjectDependency> excludeDependencies, ILogger logger, CancellationToken cancellationToken) { ThrowOnDisposed(); IEnumerable <ProjectDependency> dependencies = null; if (excludeDependencies == null) { excludeDependencies = new List <ProjectDependency>(); } using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, "Resolving project references ...").ConfigureAwait(false)) { if (_targetFrameworks.Count == 1 && TargetFrameworkHelper.IsSupportedFramework(this.TargetFramework, out var frameworkInfo) && frameworkInfo.IsDnx) { await this.RestoreAsync(logger, cancellationToken).ConfigureAwait(false); var packageReferences = await ResolvePackageReferencesAsync(logger, cancellationToken).ConfigureAwait(false); var assemblyReferences = await ResolveAssemblyReferencesAsync(logger, cancellationToken).ConfigureAwait(false); dependencies = packageReferences.Union(assemblyReferences).Except(excludeDependencies); } else { await safeLogger.WriteWarningAsync(Shared.Resources.WarningMultiFxOrNoSupportedDnxVersion, logToUI : true).ConfigureAwait(false); dependencies = new List <ProjectDependency>(); } await safeLogger.WriteMessageAsync($"Resolved project reference count: {dependencies.Count()}", logToUI : false).ConfigureAwait(false); } return(dependencies); }
private async Task GenerateProjectAsync(bool keepBootstrapperDir, ILogger logger, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var projectFullPath = Path.Combine(this.Options.BootstrapPath.FullName, nameof(SvcutilBootstrapper), SvcutilBootstrapper.ProjectName); if (keepBootstrapperDir) { // creating the directory prevents the bootstrapper project from deleting it as it doesn't own it, files will not be deleted either. Directory.CreateDirectory(Path.GetDirectoryName(projectFullPath)); } // If the target framework was provided, it was validated already when processing params. // Bootstrapping is enabled only for netcoreapp or netstandard TFM, let's check. bool isSupportedTFM = TargetFrameworkHelper.IsSupportedFramework(this.Options.TargetFramework.FullName, out var frameworkInfo); Debug.Assert(frameworkInfo.IsDnx, "The bootstrapper has been enabled for a non-DNX platform!"); ToolConsole.WriteLineIf(ToolConsole.Verbosity >= Verbosity.Verbose, Resource.CreatingProjectMsg); using (await SafeLogger.WriteStartOperationAsync(logger, $"Creating project file: \"{projectFullPath}\"").ConfigureAwait(false)) { var svcutilPkgRef = ProjectDependency.FromAssembly(Path.Combine(Path.GetDirectoryName(Tool.FullPath), Tool.AssemblyName + ".dll")); this.MSBuildProj = await MSBuildProj.DotNetNewAsync(projectFullPath, logger, cancellationToken).ConfigureAwait(false); this.MSBuildProj.AddDependency(svcutilPkgRef); // NOTE: If post v2.0 NetStandard ships a different version from NetCore the table below needs to be updated! var targetFramework = frameworkInfo.FullName; if (isSupportedTFM && frameworkInfo.IsKnownDnx) { if (frameworkInfo.Name == FrameworkInfo.Netstandard) { targetFramework = FrameworkInfo.Netcoreapp + TargetFrameworkHelper.NetStandardToNetCoreVersionMap[frameworkInfo.Version]; } this.MSBuildProj.TargetFramework = targetFramework; } // else // The TFM is unknown: either, it was not provided or it is a version not yet known to the tool, // we will use the default TF from the generated project. } foreach (ProjectDependency dependency in this.Options.References) { this.MSBuildProj.AddDependency(dependency); } if (!string.IsNullOrEmpty(this.Options.RuntimeIdentifier)) { this.MSBuildProj.RuntimeIdentifier = this.Options.RuntimeIdentifier; } // Don't treat warnings as errors so the bootstrapper will succeed as often as possible. this.MSBuildProj.ClearWarningsAsErrors(); await this.MSBuildProj.SaveAsync(logger, cancellationToken).ConfigureAwait(false); }
internal async Task GenerateProgramFileAsync(ILogger logger, CancellationToken cancellationToken) { using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, "Generating Program.cs ...").ConfigureAwait(false)) { string programFilePath = Path.Combine(this.MSBuildProj.DirectoryPath, "Program.cs"); File.WriteAllText(programFilePath, s_programClass); } }
public static async Task <SafeLogger> WriteStartOperationAsync(ILogger logger, string message, bool logToUI = false) { var safeLogger = new SafeLogger(logger); safeLogger._startTime = await safeLogger.WriteStartOperationAsync(message, logToUI).ConfigureAwait(false); return(safeLogger); }
public static async Task <bool> TryAddSvcutilNuGetFeedAsync(string nugetConfigPath, string packageFeed, ILogger logger, CancellationToken cancellationToken) { bool?added = false; if (File.Exists(nugetConfigPath)) { using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, "Adding svcutil NuGet feed to existing nuget.config file ...").ConfigureAwait(false)) { try { using (var stream = File.Open(nugetConfigPath, FileMode.Open, FileAccess.ReadWrite)) { var doc = XDocument.Parse(new StreamReader(stream).ReadToEnd()); var pkgSourcesNode = doc.Element("configuration")?.Element("packageSources"); if (pkgSourcesNode != null) { added = pkgSourcesNode.Elements("add")? .Select(e => e.Attribute("value").Value.TrimEnd(Path.DirectorySeparatorChar)) .Any(v => v != null && packageFeed.Equals(v, RuntimeEnvironmentHelper.FileStringComparison)); if (added != true) { var feedName = "SvcutilNuGetFeed"; var count = 1; while (pkgSourcesNode.Elements("add").Any(e => StringComparer.OrdinalIgnoreCase.Compare(e.Attribute("key").Value, feedName) == 0)) { feedName += count++; } var addElement = new XElement("add"); addElement.Add(new XAttribute("key", feedName), new XAttribute("value", packageFeed)); pkgSourcesNode.Add(addElement); stream.Seek(0, SeekOrigin.Begin); doc.Save(stream); added = true; } else { await safeLogger.WriteMessageAsync("Feed entry already exists.", logToUI : false); } } } } catch (Exception ex) { await safeLogger.WriteErrorAsync(ex.Message, logToUI : false); } await safeLogger.WriteMessageAsync($"Feed entry added/exists: {added == true}", logToUI : false); } } return(added == true); }
internal async Task <string> GenerateParamsFileAsync(ILogger logger, CancellationToken cancellationToken) { var paramsFilePath = Path.Combine(this.MSBuildProj.DirectoryPath, s_bootstrapperParamsFileName); using (await SafeLogger.WriteStartOperationAsync(logger, $"Generating {paramsFilePath} params file ...").ConfigureAwait(false)) { await AsyncHelper.RunAsync(() => this.Options.Save(paramsFilePath), cancellationToken).ConfigureAwait(false); return(paramsFilePath); } }
public static async Task <string> GetSdkVersionAsync(string workingDirectory, ILogger logger, CancellationToken cancellationToken) { if (s_sdkVersion == null) { using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, "Resolving dotnet sdk version ...").ConfigureAwait(false)) { var procResult = await ProcessRunner.TryRunAsync("dotnet", "--version", workingDirectory, logger, cancellationToken).ConfigureAwait(false); if (procResult.ExitCode == 0) { s_sdkVersion = procResult.OutputText.Trim(); } await safeLogger.WriteMessageAsync($"dotnet sdk version:{s_sdkVersion}", logToUI : false).ConfigureAwait(false); } } return(s_sdkVersion); }
internal async Task <ProcessRunner.ProcessResult> BoostrapSvcutilAsync(bool keepBootstrapperDir, ILogger logger, CancellationToken cancellationToken) { bool redirectOutput = false; if (this.Options.ToolContext == OperationalContext.Infrastructure) { redirectOutput = true; } ProcessRunner.ProcessResult result = null; using (await SafeLogger.WriteStartOperationAsync(logger, "Bootstrapping svcutil ...").ConfigureAwait(false)) { // guard against bootstrapping recursion. if (this.Options.NoBootstrapping != true) { Debug.Fail($"The NoBootstrapping property is not set, this would cause infinite bootstrapping recursion!"); return(null); } if (this.Options.Project != null && StringComparer.OrdinalIgnoreCase.Compare(this.Options.Project.FileName, SvcutilBootstrapper.ProjectName) == 0) { Debug.Fail("Bootstrapping is enabled for the bootstrapper! This would cause an infinite bootstrapping recursion!"); return(null); } // When in Infrastructure mode (WCF CS) it is assumed the initial progress message is to be presented by the calling tool. ToolConsole.WriteLineIf(ToolConsole.ToolModeLevel != OperationalContext.Infrastructure, Resource.BootstrappingApplicationMsg); await GenerateProjectAsync(keepBootstrapperDir, logger, cancellationToken).ConfigureAwait(false); await GenerateProgramFileAsync(logger, cancellationToken).ConfigureAwait(false); var paramsFilePath = await GenerateParamsFileAsync(logger, cancellationToken).ConfigureAwait(false); await BuildBootstrapProjectAsync(logger, cancellationToken).ConfigureAwait(false); ToolConsole.WriteLineIf(ToolConsole.Verbosity >= Verbosity.Verbose, Resource.InvokingProjectMsg); result = await ProcessRunner.RunAsync("dotnet", $"run \"{paramsFilePath}\"", this.MSBuildProj.DirectoryPath, redirectOutput, logger, cancellationToken).ConfigureAwait(false); MarkupTelemetryHelper.TelemetryPostOperation(result.ExitCode == 0, "Invoke svcutil bootstrapper"); } return(result); }
private static async Task GenerateParamsFileAsync(CommandProcessorOptions options, ILogger logger, CancellationToken cancellationToken) { // params file is generated on first run, never on update and never by the bootstrapper. if (!(options.IsUpdateOperation || options.NoProjectUpdates == true)) { using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, "Generating svcutil params file ...").ConfigureAwait(false)) { var updateOptions = options.CloneAs <UpdateOptions>(); updateOptions.ProviderId = Tool.ToolName; updateOptions.Version = Tool.PackageVersion; ProjectDependency.RemoveRedundantReferences(updateOptions.References); updateOptions.MakePathsRelativeTo(options.OutputDir); var paramsFile = Path.Combine(options.OutputDir.FullName, CommandProcessorOptions.SvcutilParamsFileName); await AsyncHelper.RunAsync(() => updateOptions.Save(paramsFile), cancellationToken).ConfigureAwait(false); } } }
private static async Task <string> TryFindItemAsync(Func <string, IEnumerable <string> > EnumerateItems, string itemName, string workingDir, ILogger logger, CancellationToken cancellationToken) { // Look up the file in the folder structure starting from the specified working directory. cancellationToken.ThrowIfCancellationRequested(); using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, $"Looking for '{itemName}' up from '{workingDir}' dir ...").ConfigureAwait(false)) { var fullPath = string.Empty; try { if (!string.IsNullOrEmpty(itemName) && !string.IsNullOrEmpty(workingDir) && Directory.Exists(workingDir)) { while (string.IsNullOrEmpty(fullPath)) { fullPath = EnumerateItems(workingDir).Where(item => Path.GetFileName(item).Equals(itemName, RuntimeEnvironmentHelper.FileStringComparison)).FirstOrDefault(); if (!string.IsNullOrEmpty(fullPath)) { break; } workingDir = Path.GetDirectoryName(workingDir); if (string.IsNullOrEmpty(workingDir)) { break; } } } } catch (Exception ex) { await safeLogger.WriteMessageAsync($"Error: {ex.Message}", logToUI : false).ConfigureAwait(false); } await safeLogger.WriteMessageAsync($"Item found: {!string.IsNullOrEmpty(fullPath)}", logToUI : false).ConfigureAwait(false); return(fullPath); } }
private async Task <Assembly> LoadMSBuildAssembliesAsync(string sdkPath, ILogger logger, CancellationToken cancellationToken) { #if !NETCORE10 Assembly msbuildAssembly = null; using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, "Loading MSBuild assemblies ...").ConfigureAwait(false)) { if (Directory.Exists(sdkPath)) { foreach (var assemblyPath in Directory.GetFiles(sdkPath, "Microsoft.Build.*", SearchOption.TopDirectoryOnly)) { var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath); if (Path.GetFileNameWithoutExtension(assemblyPath) == "Microsoft.Build") { msbuildAssembly = assembly; } } } } return(msbuildAssembly); #else return(await Task.FromResult <Assembly>(null)); #endif }
public static async Task <string> TryCopyFileIfFoundAsync(string fileName, string workingDirectory, string destinationDir, ILogger logger, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var filePath = await TryFindFileAsync(fileName, workingDirectory, logger, cancellationToken).ConfigureAwait(false); if (File.Exists(filePath)) { using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, $"Copying {fileName} to {destinationDir} ...").ConfigureAwait(false)) { try { var dstFilePath = Path.Combine(destinationDir, fileName); File.Copy(filePath, dstFilePath, overwrite: true); return(dstFilePath); } catch (Exception ex) { await safeLogger.WriteErrorAsync(ex.Message, logToUI : false).ConfigureAwait(false); } } } return(null); }
internal static async Task <ToolExitCode> RunAsync(CommandProcessorOptions options, CancellationToken cancellationToken) { ImportModule importModule = null; var credsProvicer = new CmdCredentialsProvider(); ServiceDescriptor serviceDescriptor = options.Inputs.Count == 1 ? new ServiceDescriptor(options.Inputs[0].ToString(), credsProvicer, credsProvicer, credsProvicer) : new ServiceDescriptor(options.Inputs.Select(i => i.ToString()).ToList(), credsProvicer, credsProvicer, credsProvicer); // When in Infrastructure mode (WCF CS) it is assumed the metadata docs have been downloaded and passed in as wsdl files. if (options.ToolContext != OperationalContext.Infrastructure) { if (serviceDescriptor.MetadataUrl != null) { ToolConsole.WriteLine(string.Format(SR.RetreivingMetadataMsgFormat, serviceDescriptor.MetadataUrl.AbsoluteUri)); } else { var displayUri = serviceDescriptor.MetadataFiles.Count() == 1 ? serviceDescriptor.MetadataFiles.First().LocalPath : SR.WsdlOrSchemaFilesMsg; ToolConsole.WriteLine(string.Format(SR.ReadingMetadataMessageFormat, displayUri)); } } using (await SafeLogger.WriteStartOperationAsync(options.Logger, "Importing metadata ...").ConfigureAwait(false)) { try { await serviceDescriptor.ImportMetadataAsync( (wi) => importModule = new ImportModule(options, serviceDescriptor, wi), (sd) => importModule.BeforeImportMetadata(sd), (sd) => importModule.AfterImportMetadata(sd), cancellationToken).ConfigureAwait(false); } catch (Exception ex) { if (Utils.IsFatalOrUnexpected(ex)) { throw; } var exception = new ToolInputException(Utils.GetExceptionMessage(ex), ex); if (serviceDescriptor.MetadataUrl != null) { exception = new ToolMexException(exception, serviceDescriptor.MetadataUrl); } throw exception; } } using (await SafeLogger.WriteStartOperationAsync(options.Logger, "Processing Code DOM ...").ConfigureAwait(false)) { ToolConsole.WriteLine(SR.GeneratingFiles); CodeSerializer codeSerializer = new CodeSerializer(options, serviceDescriptor.MetadataDocuments); var filePath = codeSerializer.Save(importModule.CodeCompileUnit); // When in Infrastructure mode (WCF CS) it is assumed the output file path have been provided so no need to display it. ToolConsole.WriteLineIf(options.ToolContext != OperationalContext.Infrastructure, filePath, LogTag.Important); } return(ToolConsole.ExitCode); }
public async Task <Dictionary <string, string> > EvaluateProjectPropertiesAsync(string projectPath, string targetFramework, IEnumerable <string> propertyNames, IDictionary <string, string> globalProperties, ILogger logger, CancellationToken cancellationToken) { var propertyTable = new Dictionary <string, string>(); using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, $"Resolving {propertyNames.Count()} project properties ...").ConfigureAwait(false)) { ValidatePropertyNames(propertyNames); ValidatePropertyNames(globalProperties); var workingDirectory = Path.GetDirectoryName(projectPath); var sdkVersion = await GetSdkVersionAsync(workingDirectory, logger, cancellationToken).ConfigureAwait(false); var sdkPath = await GetSdkPathAsync(workingDirectory, logger, cancellationToken).ConfigureAwait(false); try { #if NETCORE var propertiesResolved = false; try { // In order for the MSBuild project evaluation API to work in .NET Core, the code must be executed directly from the .NET Core SDK assemblies. // MSBuild libraries need to be explicitly loaded from the right SDK path (the one that corresponds to the runtime executing the project) as // dependencies must be loaded from the executing runtime. This is not always possible, a newer SDK can load an older runtime; also, msbuild // scripts from a newer SDK may not be supported by an older SDKs. // Consider: A project created with the command 'dotnet new console' will target the right platform for the current SDK. Assembly msbuildAssembly = await LoadMSBuildAssembliesAsync(sdkPath, logger, cancellationToken).ConfigureAwait(false); if (msbuildAssembly != null) { var projType = msbuildAssembly.GetType("Microsoft.Build.Evaluation.Project", true, false); var projInstance = Activator.CreateInstance(projType, new object[] { projectPath, globalProperties, /*toolsVersion*/ null }); var getPropertyValue = projType.GetMethod("GetPropertyValue"); if (getPropertyValue != null) { foreach (var propertyName in propertyNames) { var propertyValue = getPropertyValue.Invoke(projInstance, new object[] { propertyName }).ToString(); propertyTable[propertyName] = propertyValue; await safeLogger.WriteMessageAsync($"Evaluated '{propertyName}={propertyValue}'", logToUI : false).ConfigureAwait(false); } propertiesResolved = true; } } } catch (Exception ex) { await safeLogger.WriteMessageAsync(ex.Message, logToUI : false).ConfigureAwait(false); } if (!propertiesResolved) { foreach (var propertyName in propertyNames) { var propertyValue = GetDefaultPropertyValue(projectPath, targetFramework, propertyName); propertyTable[propertyName] = propertyValue; await safeLogger.WriteMessageAsync($"Resolved '{propertyName}={propertyValue}'", logToUI : false).ConfigureAwait(false); } } #else // don't use GlobalProjectCollection as once a project is loaded into memory changes to the project file won't take effect until the solution is reloaded. var projCollection = new Microsoft.Build.Evaluation.ProjectCollection(globalProperties); var project = projCollection.LoadProject(projectPath); foreach (var propertyName in propertyNames) { var propertyValue = project.GetPropertyValue(propertyName); propertyTable[propertyName] = propertyValue; await safeLogger.WriteMessageAsync($"Evaluated '{propertyName}={propertyValue}'", logToUI : false).ConfigureAwait(false); } #endif // NETCORE } catch (Exception ex) { if (Utils.IsFatalOrUnexpected(ex)) { throw; } await safeLogger.WriteErrorAsync($"{ex.Message}{Environment.NewLine}{ex.StackTrace}", logToUI : false); } finally { // Ensure the dictionary is populated in any case, the client needs to validate the values but not the collection. foreach (var propertyName in propertyNames) { if (!propertyTable.ContainsKey(propertyName)) { propertyTable[propertyName] = string.Empty; } } } } return(propertyTable); }
private async Task <List <ProjectDependency> > ResolveAssemblyReferencesAsync(ILogger logger, CancellationToken cancellationToken) { ThrowOnDisposed(); cancellationToken.ThrowIfCancellationRequested(); var assemblyDependencies = new List <ProjectDependency>(); using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, $"Resolving assembly references for {this.TargetFramework} target framework ...").ConfigureAwait(false)) { await ResolveProperyValuesAsync(new string[] { "OutputPath", "TargetPath" }, logger, cancellationToken).ConfigureAwait(false); var outputPath = this._resolvedProperties["OutputPath"]; if (!Path.IsPathRooted(outputPath)) { outputPath = Path.Combine(this.DirectoryPath, outputPath.Trim(new char[] { '\"' })); } var depsFile = this.GlobalProperties.TryGetValue("Configuration", out var activeConfiguration) && !string.IsNullOrWhiteSpace(activeConfiguration) ? Path.Combine(outputPath, $"{Path.GetFileNameWithoutExtension(this.FileName)}.deps.json") : await ResolveDepsFilePathFromBuildConfigAsync(outputPath, logger, cancellationToken).ConfigureAwait(false); if (File.Exists(depsFile)) { await AsyncHelper.RunAsync(async() => { try { DependencyContext depContext = null; using (var stream = File.OpenRead(depsFile)) { depContext = new DependencyContextJsonReader().Read(stream); } var targetLib = Path.GetFileName(this._resolvedProperties["TargetPath"].Trim('\"')); if (string.IsNullOrEmpty(targetLib)) { targetLib = $"{Path.ChangeExtension(this.FileName, ".dll")}"; } foreach (var rtLib in depContext.RuntimeLibraries.Where(l => l.NativeLibraryGroups.Count == 0)) { ProjectDependency dependency = null; switch (rtLib.Type) { case "project": case "reference": foreach (var assemblyGroup in rtLib.RuntimeAssemblyGroups) { foreach (var assetPath in assemblyGroup.AssetPaths) { if (!Path.GetFileName(assetPath).Equals(targetLib, RuntimeEnvironmentHelper.FileStringComparison)) { dependency = ProjectDependency.FromAssembly(Path.Combine(outputPath, assetPath)); if (File.Exists(dependency.FullPath) && !assemblyDependencies.Contains(dependency)) { assemblyDependencies.Add(dependency); } } } } break; //case "package": default: break; } } } catch (Exception ex) { if (Utils.IsFatalOrUnexpected(ex)) { throw; } await safeLogger.WriteWarningAsync(ex.Message, logToUI: false).ConfigureAwait(false); } }, cancellationToken).ConfigureAwait(false); assemblyDependencies.Sort(); } else { await safeLogger.WriteWarningAsync("Deps file not found (project not built), unable to resolve assembly/project dependencies!", logToUI : false).ConfigureAwait(false); } await safeLogger.WriteMessageAsync($"Assembly reference count: {assemblyDependencies.Count}", logToUI : false).ConfigureAwait(false); } return(assemblyDependencies); }
public static async Task <MSBuildProj> ParseAsync(string projectText, string projectFullPath, ILogger logger, CancellationToken cancellationToken) { using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, $"Parsing project {Path.GetFileName(projectFullPath)}").ConfigureAwait(false)) { projectFullPath = Path.GetFullPath(projectFullPath); MSBuildProj msbuildProj = new MSBuildProj { FileName = Path.GetFileName(projectFullPath), DirectoryPath = Path.GetDirectoryName(projectFullPath) }; XDocument projDefinition = XDocument.Parse(projectText); var msbuildNS = XNamespace.None; if (projDefinition.Root != null && projDefinition.Root.Name != null) { msbuildNS = projDefinition.Root.Name.Namespace; } msbuildProj._msbuildNS = msbuildNS; msbuildProj.ProjectNode = projDefinition.Element(msbuildNS + "Project"); if (msbuildProj.ProjectNode == null) { throw new Exception(Shared.Resources.ErrorInvalidProjectFormat); } // The user project can declare TargetFramework and/or TargetFrameworks property. If both are provided, TargetFramework wins. // When TargetFrameworks is provided, the project is built for every entry specified in the TargetFramework property. IEnumerable <XElement> targetFrameworkElements = GetSubGroupValues(msbuildProj.ProjectNode, msbuildNS, "PropertyGroup", "TargetFramework"); if (targetFrameworkElements.Count() > 0) { // If property is specified more than once, MSBuild will resolve it by overwriting it with the last value. var targetFramework = targetFrameworkElements.Last().Value.Trim(); if (!string.IsNullOrWhiteSpace(targetFramework)) { if (targetFramework.StartsWith("net5.0-")) { targetFramework = "net5.0"; } msbuildProj._targetFrameworks.Add(targetFramework); } } if (msbuildProj._targetFrameworks.Count == 0) { // TargetFramework was not provided, check TargetFrameworks property. IEnumerable <XElement> targetFrameworksElements = GetSubGroupValues(msbuildProj.ProjectNode, msbuildNS, "PropertyGroup", "TargetFrameworks"); if (targetFrameworksElements.Count() > 0) { var targetFrameworks = targetFrameworksElements.Last().Value; foreach (var targetFx in targetFrameworks.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries).Select(p => p.Trim())) { if (!string.IsNullOrWhiteSpace(targetFx)) { msbuildProj._targetFrameworks.Add(targetFx); } } } } msbuildProj._targetFramework = TargetFrameworkHelper.GetBestFitTargetFramework(msbuildProj._targetFrameworks); // Ensure target framework is valid. FrameworkInfo frameworkInfo = TargetFrameworkHelper.GetValidFrameworkInfo(msbuildProj.TargetFramework); IEnumerable <XElement> runtimeIdentifierElements = GetSubGroupValues(msbuildProj.ProjectNode, msbuildNS, "PropertyGroup", "RuntimeIdentifier"); if (runtimeIdentifierElements.Count() > 0) { msbuildProj.RuntimeIdentifier = runtimeIdentifierElements.Last().Value.Trim(); } IEnumerable <XElement> packageReferenceElements = GetSubGroupValues(msbuildProj.ProjectNode, msbuildNS, "ItemGroup", "PackageReference"); foreach (XElement reference in packageReferenceElements) { if (!TryGetItemIdentity(reference, out var packageName)) { continue; } string version = GetItemValue(reference, "Version"); ProjectDependency packageDep = ProjectDependency.FromPackage(packageName, version); msbuildProj._dependencies.Add(packageDep); } IEnumerable <XElement> toolReferenceElements = GetSubGroupValues(msbuildProj.ProjectNode, msbuildNS, "ItemGroup", "DotNetCliToolReference"); foreach (XElement reference in toolReferenceElements) { if (!TryGetItemIdentity(reference, out var packageName)) { continue; } string version = GetItemValue(reference, "Version"); ProjectDependency packageDep = ProjectDependency.FromCliTool(packageName, version); msbuildProj._dependencies.Add(packageDep); } IEnumerable <XElement> projectReferenceElements = GetSubGroupValues(msbuildProj.ProjectNode, msbuildNS, "ItemGroup", "ProjectReference"); foreach (XElement reference in projectReferenceElements) { string projectPath = GetItemValue(reference, "Include", throwIfMissing: true); ProjectDependency projectDep = ProjectDependency.FromProject(projectPath); msbuildProj._dependencies.Add(projectDep); } IEnumerable <XElement> binReferenceElements = GetSubGroupValues(msbuildProj.ProjectNode, msbuildNS, "ItemGroup", "Reference"); foreach (XElement reference in binReferenceElements) { //Find hint path or path string binReference = GetItemIdentity(reference); if (!Path.IsPathRooted(binReference)) { string fullPath = null; bool fullPathFound = true; XElement hintPath = reference.Element("HintPath"); XElement path = reference.Element("Path"); if (path != null) { fullPath = path.Value; } else if (hintPath != null) { fullPath = hintPath.Value; } else { try { fullPath = new FileInfo(Path.Combine(msbuildProj.DirectoryPath, binReference)).FullName; } catch { } if (fullPath == null || !File.Exists(fullPath)) { fullPathFound = false; // If we're only targeting .NET Core or .NET Standard projects we throw if we can't find the full path to the assembly. if (!TargetFrameworkHelper.ContainsFullFrameworkTarget(msbuildProj._targetFrameworks)) { throw new Exception(string.Format(CultureInfo.CurrentCulture, Shared.Resources.ErrorProjectReferenceMissingFilePathFormat, binReference)); } } } if (fullPathFound) { if (System.IO.Directory.Exists(fullPath)) // IsDir? { fullPath = Path.Combine(fullPath, binReference); } else if (Directory.Exists(Path.Combine(msbuildProj.DirectoryPath, fullPath))) { fullPath = Path.Combine(msbuildProj.DirectoryPath, fullPath, binReference); } binReference = fullPath; } } ProjectDependency projectDep = ProjectDependency.FromAssembly(binReference); msbuildProj._dependencies.Add(projectDep); } // ensure we have a working directory for the ProcessRunner (ProjectPropertyResolver).. if (!Directory.Exists(msbuildProj.DirectoryPath)) { Directory.CreateDirectory(msbuildProj.DirectoryPath); msbuildProj._ownsDirectory = true; } var sdkVersion = await ProjectPropertyResolver.GetSdkVersionAsync(msbuildProj.DirectoryPath, logger, cancellationToken).ConfigureAwait(false); msbuildProj.SdkVersion = sdkVersion ?? string.Empty; return(msbuildProj); } }
public static async Task <ProcessResult> RunAsync(string processName, string processArgs, string currentDir, bool redirectOutput, bool throwOnError, IDictionary <string, string> environmentVariables, ILogger logger, CancellationToken cancellationToken) { bool isErrorLogged = false; var errorTextBldr = new StringBuilder(); var outputTextBldr = new StringBuilder(); cancellationToken.ThrowIfCancellationRequested(); if (string.IsNullOrWhiteSpace(currentDir)) { currentDir = Directory.GetCurrentDirectory(); } using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, $"Executing command [\"{currentDir}\"]{Environment.NewLine}>{processName} {processArgs}").ConfigureAwait(false)) { using (var proc = new Process()) { proc.StartInfo.WorkingDirectory = Path.GetFullPath(currentDir); proc.StartInfo.UseShellExecute = false; proc.StartInfo.CreateNoWindow = redirectOutput; proc.StartInfo.RedirectStandardError = redirectOutput; proc.StartInfo.RedirectStandardOutput = redirectOutput; proc.StartInfo.FileName = processName; proc.StartInfo.Arguments = processArgs; proc.EnableRaisingEvents = true; foreach (var environmentVar in environmentVariables.Where(e => !string.IsNullOrWhiteSpace(e.Key))) { proc.StartInfo.Environment.Add(environmentVar); } if (redirectOutput) { // The default encoding might not work while redirecting non-ANSI characters. // Standard error encoding is only supported when standard error is redirected. proc.StartInfo.StandardErrorEncoding = Encoding.UTF8; proc.StartInfo.StandardOutputEncoding = Encoding.UTF8; } proc.ErrorDataReceived += delegate(object sender, DataReceivedEventArgs e) { if (!string.IsNullOrWhiteSpace(e.Data)) { errorTextBldr.AppendLine(e.Data); safeLogger.WriteErrorAsync(e.Data, false).ConfigureAwait(false); isErrorLogged = true; } }; proc.OutputDataReceived += delegate(object sender, DataReceivedEventArgs e) { outputTextBldr.AppendLine(e.Data); safeLogger.WriteMessageAsync(e.Data, false).ConfigureAwait(false); }; proc.Start(); #if DEBUG if (DebugUtils.SvcutilDebug == 1) { try { Console.WriteLine($"Starting process in the background: {Path.GetFileName(proc.ProcessName)}, ID: {proc.Id}."); Console.WriteLine($"{Path.GetFileName(currentDir)}>{processName} {processArgs}{Environment.NewLine}"); } catch { } } #endif if (redirectOutput) { proc.BeginErrorReadLine(); proc.BeginOutputReadLine(); } await AsyncHelper.RunAsync(() => proc.WaitForExit(), () => { try { proc.Kill(); } catch { } }, cancellationToken).ConfigureAwait(false); if (!cancellationToken.IsCancellationRequested) { // allow for processing message packets a few more times as they can keep coming after the process has finished. int waitCount = 3; while (waitCount-- > 0) { proc.WaitForExit(); await Task.Delay(100); } } cancellationToken.ThrowIfCancellationRequested(); var outputText = outputTextBldr.ToString().Trim(); var errorText = errorTextBldr.ToString().Trim(); await safeLogger.WriteMessageAsync($"Exit code: {proc.ExitCode}", false).ConfigureAwait(false); if (throwOnError && (isErrorLogged || proc.ExitCode != 0)) { // avoid reporting a foreign tool's exit code. var exitCode = Path.GetFileName(processName) == Path.GetFileName(Process.GetCurrentProcess().MainModule.FileName) ? proc.ExitCode : -1; throw new ProcessException(string.IsNullOrWhiteSpace(errorText) ? outputText : errorText, exitCode); } else if (string.IsNullOrWhiteSpace(outputText)) { outputText = errorText; } return(new ProcessResult(proc.ExitCode, outputText)); } } }
internal static async Task <int> MainAsync(string[] args, ILogger logger, CancellationToken cancellationToken) { int result = -1; CommandProcessorOptions options = null; WaitForDebugger(); try { options = await CommandProcessorOptions.ParseArgumentsAsync(args, logger, cancellationToken); ValidateUICulture(options); if (options.NoTelemetry == true) { AppInsightsTelemetryClient.IsUserOptedIn = false; } ToolConsole.Init(options); ToolConsole.WriteHeaderIf(options.NoLogo != true); ThrowOnValidationErrors(options); if (options.Help == true) { ToolConsole.WriteHelp(); result = (int)ToolExitCode.Success; } else { // Show early warnings var earlyWarnings = options.Warnings; foreach (string warning in earlyWarnings.Distinct()) { ToolConsole.WriteWarning(warning); } var operationMessage = (options.IsUpdateOperation ? "Update" : "Add") + " web service reference operation started!"; using (var safeLogger = await SafeLogger.WriteStartOperationAsync(options.Logger, operationMessage).ConfigureAwait(false)) { await options.ResolveAsync(cancellationToken).ConfigureAwait(false); ThrowOnValidationErrors(options); options.ProviderId = Tool.ToolName; options.Version = Tool.PackageVersion; foreach (string warning in options.Warnings.Distinct().Except(earlyWarnings)) { ToolConsole.WriteWarning(warning); } if (options.RequiresBoostrapping) { using (var bootstrapper = new SvcutilBootstrapper(options.CloneAs <SvcutilOptions>())) { await options.SetupBootstrappingDirectoryAsync(options.Logger, cancellationToken).ConfigureAwait(false); var bootstrapResult = await bootstrapper.BoostrapSvcutilAsync(options.KeepBootstrapDir, options.Logger, cancellationToken).ConfigureAwait(false); ToolConsole.WriteLine(bootstrapResult.OutputText); result = bootstrapResult.ExitCode; } } else { result = (int) await RunAsync(options, cancellationToken).ConfigureAwait(false); } if (IsSuccess(result)) { if (!File.Exists(options.OutputFile.FullName)) { await safeLogger.WriteMessageAsync("The process completed successfully but no proxy file was found!", logToUI : false); throw new ToolArgumentException(SR.ErrUnexpectedError); } else { await GenerateParamsFileAsync(options, options.Logger, cancellationToken); if (CanAddProjectReferences(options) && !await AddProjectReferencesAsync(options.Project, options, cancellationToken).ConfigureAwait(false)) { result = (int)ToolExitCode.InputError; } } // clean up only on success to allow to troubleshoot any problems on failure. options?.Cleanup(); } } } } catch (Exception e) { result = await ProcessExceptionAsync(e, options); } finally { try { // Don't log telemetry if we're running from bootstrapper or connected service. if (options?.ToolContext <= OperationalContext.Global) { var properties = new Dictionary <string, string>() { { "IsUpdate", (options?.IsUpdateOperation).ToString() }, { "TargetFramework", options?.TargetFramework?.FullName }, { "Parameters", options?.ToTelemetryString() }, { "ExitCode", result.ToString() }, { "RequiresBootstrapping", options?.RequiresBoostrapping.ToString() }, }; var telemetryClient = await AppInsightsTelemetryClient.GetInstanceAsync(cancellationToken).ConfigureAwait(false); telemetryClient.TrackEvent("ToolRun", properties); } } catch { } } return(result); }
private async Task <List <ProjectDependency> > ResolvePackageReferencesAsync(ILogger logger, CancellationToken cancellationToken) { ThrowOnDisposed(); cancellationToken.ThrowIfCancellationRequested(); var packageDependencies = new List <ProjectDependency>(); using (var safeLogger = await SafeLogger.WriteStartOperationAsync(logger, "Resolving package references ...").ConfigureAwait(false)) { await AsyncHelper.RunAsync(async() => { try { var assetsFile = new FileInfo(Path.Combine(this.DirectoryPath, "obj", "project.assets.json")).FullName; if (File.Exists(assetsFile)) { LockFile lockFile = LockFileUtilities.GetLockFile(assetsFile, logger as NuGet.Common.ILogger); if (lockFile != null) { if (lockFile.Targets.Count == 1) { foreach (var lib in lockFile.Targets[0].Libraries) { bool isPackage = StringComparer.OrdinalIgnoreCase.Compare(lib.Type, "package") == 0; if (isPackage) { foreach (var compiletimeAssembly in lib.CompileTimeAssemblies) { if (Path.GetExtension(compiletimeAssembly.Path) == ".dll") { var dependency = ProjectDependency.FromPackage(Path.GetFileNameWithoutExtension(compiletimeAssembly.Path), lib.Name, lib.Version.ToNormalizedString()); var itemIdx = packageDependencies.IndexOf(dependency); if (itemIdx == -1) { packageDependencies.Add(dependency); } else if (dependency.IsFramework) { // packages can be described individually and/or as part of a platform metapackage in the lock file; for instance: Microsoft.CSharp is a package that is part of Microsoft.NetCore. packageDependencies[itemIdx] = dependency; } } } } } packageDependencies.Sort(); } else { await safeLogger.WriteWarningAsync(Shared.Resources.WarningMultiFxOrNoSupportedDnxVersion, logToUI: true).ConfigureAwait(false); } } else { await safeLogger.WriteWarningAsync(Shared.Resources.WarningCannotResolveProjectReferences, logToUI: true).ConfigureAwait(false); } } } catch (Exception ex) { if (Utils.IsFatalOrUnexpected(ex)) { throw; } await safeLogger.WriteWarningAsync(ex.Message, logToUI: false).ConfigureAwait(false); } }, cancellationToken).ConfigureAwait(false); await safeLogger.WriteMessageAsync($"Package reference count: {packageDependencies.Count}", logToUI : false).ConfigureAwait(false); } return(packageDependencies); }