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); }
public bool AddDependency(ProjectDependency dependency) { // a nuget package can contain multiple assemblies, we need to filter package references so we don't add dups. bool addDependency = !_dependencies.Any(d => { switch (d.DependencyType) { case ProjectDependencyType.Package: case ProjectDependencyType.Tool: return(d.Name == dependency.Name); default: if (d.FullPath == null && dependency.FullPath == null) { goto case ProjectDependencyType.Package; } return(d.FullPath == dependency.FullPath); } }); if (addDependency) { switch (dependency.DependencyType) { case ProjectDependencyType.Project: this.ProjectReferceGroup.Add(new XElement("ProjectReference", new XAttribute("Include", dependency.FullPath))); break; case ProjectDependencyType.Binary: this.ReferenceGroup.Add(new XElement("Reference", new XAttribute("Include", dependency.AssemblyName), new XElement("HintPath", dependency.FullPath))); break; case ProjectDependencyType.Package: this.ReferenceGroup.Add(new XElement("PackageReference", new XAttribute("Include", dependency.Name), new XAttribute("Version", dependency.Version))); break; case ProjectDependencyType.Tool: this.ReferenceGroup.Add(new XElement("DotNetCliToolReference", new XAttribute("Include", dependency.Name), new XAttribute("Version", dependency.Version))); break; } _dependencies.Add(dependency); _isSaved = false; } return(addDependency); }
public SvcutilBootstrapper(SvcutilOptions options) { this.Options = options ?? throw new ArgumentNullException(nameof(options)); this.Options.ProviderId = $"{Tool.ToolName}-bootstrap"; this.Options.Version = Tool.PackageVersion; // reset options that don't apply to the bootstrapper and that prevent bootstrapping recursion. this.Options.NoBootstrapping = true; this.Options.NoLogo = true; this.Options.NoProjectUpdates = true; // the operational context has some control over what messages to display on the UI. if (this.Options.ToolContext.HasValue && this.Options.ToolContext.Value <= OperationalContext.Global) { this.Options.ToolContext = OperationalContext.Bootstrapper; } ProjectDependency.RemoveRedundantReferences(this.Options.References); }
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 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); }
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); }
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 TValue ParseValue <TValue>(object value, OptionBase option) { ThrowInvalidValueIf(value == null, value, option); var valueType = typeof(TValue); if (value.GetType() != typeof(TValue)) { // parsing is needed, the passed in value must be a string. var stringValue = value as string; ThrowInvalidValueIf(stringValue == null, value, option); if (valueType == typeof(bool)) { // Special-case boolean values as it is common to specify them as strings in the json file. // { "myFlag" : "True" } will be resolved to { "MyFlag" : true } ThrowInvalidValueIf(!bool.TryParse(stringValue, out var boolValue), stringValue, option); value = boolValue; } else if (valueType.GetTypeInfo().IsEnum) { value = ParseEnum <TValue>(stringValue, option); } else if (valueType == typeof(CultureInfo)) { value = CreateValue <CultureInfo>(() => new CultureInfo(stringValue), option, stringValue); } else if (valueType == typeof(Uri)) { value = CreateValue <Uri>(() => new Uri(stringValue, UriKind.RelativeOrAbsolute), option, stringValue); } else if (valueType == typeof(DirectoryInfo)) { value = CreateValue <DirectoryInfo>(() => new DirectoryInfo(stringValue), option, stringValue); } else if (valueType == typeof(FileInfo)) { value = CreateValue <FileInfo>(() => new FileInfo(stringValue), option, stringValue); } else if (valueType == typeof(MSBuildProj)) { value = CreateValue <MSBuildProj>(() => MSBuildProj.FromPathAsync(stringValue, null, System.Threading.CancellationToken.None).Result, option, stringValue); } else if (valueType == typeof(FrameworkInfo)) { value = CreateValue <FrameworkInfo>(() => TargetFrameworkHelper.GetValidFrameworkInfo(stringValue), option, stringValue); } else if (valueType == typeof(ProjectDependency)) { value = CreateValue <ProjectDependency>(() => ProjectDependency.Parse(stringValue), option, stringValue); } else if (valueType == typeof(KeyValuePair <string, string>)) { value = ParseKeyValuePair(stringValue, option); } else { ThrowInvalidValueIf(true, stringValue, option); } } return((TValue)value); }
protected override void OnAfterDeserialize() { base.OnAfterDeserialize(); // Synchronize base options (VS2017 format). if (this.ReuseTypesinReferencedAssemblies == false) { this.TypeReuseMode = Svcutil.TypeReuseMode.None; } else if (this.ReuseTypesinAllReferencedAssemblies.HasValue) { this.TypeReuseMode = this.ReuseTypesinAllReferencedAssemblies == false ? Svcutil.TypeReuseMode.Specified : Svcutil.TypeReuseMode.All; } if (this.CollectionTypeReference.Count > 0) { this.CollectionTypes.AddRange(this.CollectionTypeReference); } if (this.DictionaryCollectionTypeReference.Count > 0) { this.CollectionTypes.AddRange(this.DictionaryCollectionTypeReference); } // The collections supported by the WCF CS are all part of .NET Core. foreach (var packageName in _deserializedCollectionAssemblies.Select(an => ProjectDependency.FromPackage(an, ProjectDependency.NetCoreAppPackageID, "*"))) { if (!this.References.Contains(packageName)) { this.References.Add(packageName); } } }