/// <summary> /// Checks that the target framework of the current runner can load the extension assembly. For example, .NET Core /// cannot load .NET Framework assemblies and vice-versa. /// </summary> /// <param name="runnerAsm">The executing runner</param> /// <param name="extensionAsm">The extension we are attempting to load</param> internal static bool CanLoadTargetFramework(Assembly runnerAsm, ExtensionAssembly extensionAsm) { if (runnerAsm == null) { return(true); } var extHelper = new TargetFrameworkHelper(extensionAsm.FilePath); var runnerHelper = new TargetFrameworkHelper(runnerAsm.Location); if (runnerHelper.FrameworkName?.StartsWith(".NETStandard") == true) { throw new NUnitEngineException($"{runnerAsm.FullName} test runner must target .NET Core or .NET Framework, not .NET Standard"); } else if (runnerHelper.FrameworkName?.StartsWith(".NETCoreApp") == true) { if (extHelper.FrameworkName?.StartsWith(".NETStandard") != true && extHelper.FrameworkName?.StartsWith(".NETCoreApp") != true) { log.Info($".NET Core runners require .NET Core or .NET Standard extension for {extensionAsm.FilePath}"); return(false); } } else if (extHelper.FrameworkName?.StartsWith(".NETCoreApp") == true) { log.Info($".NET Framework runners cannot load .NET Core extension {extensionAsm.FilePath}"); return(false); } return(true); }
public ExtensionAssembly(string filePath, bool fromWildCard) { FilePath = filePath; FromWildCard = fromWildCard; Assembly = GetAssemblyDefinition(); _targetFrameworkHelper = new TargetFrameworkHelper(Assembly); }
/// <summary> /// Does actual query to Packag Index to find packages where a given type is defined. /// Note: At diagnostic level there no way to know in which document, project or workspace /// we are for a given SyntaxNode (or it's SyntaxNodeAnalysisContext) since diagnostics /// work at csc.exe level (in command line for example) and there no container objects defined /// at that time. /// Thus we will display information about all packages returned form index to suggest user where /// type can be located, however when user clicks Ctrl+. we would display only code fixes for packages /// that satisfy current project target frameworks list. /// </summary> protected override IEnumerable <string> AnalyzeNode(TIdentifierNameSyntax node) { var projectFilter = GetProjectFilter(); if (!projectFilter.IsProjectSupported(node.GetLocation().SourceTree.FilePath)) { return(null); } var typeName = node.ToString(); var packagesWithGivenType = _packageSearcher.Search(typeName); if (!packagesWithGivenType.Any()) { return(null); } var projectTargetFrameworks = _targetFrameworkProvider.GetTargetFrameworks(node.GetLocation().SourceTree.FilePath); // Note: allowHigherVersions=true here since we want to show diagnostic message for type if it exists in some package // for discoverability (tooltip) but we would not supply a code fix if package already installed in the project with // any version, user needs to upgrade on his own. // Note2: the problem here is that we don't know if type exist in older versions of the package or not and to store // all package versions in index might slow things down. If we receive feedback that we need ot be more smart here // we should consider adding all package versions to the local index. return(GetFriendlyPackagesString(TargetFrameworkHelper.GetSupportedPackages(packagesWithGivenType, projectTargetFrameworks, allowHigherVersions: true) .Take(MaxPackageSuggestions))); }
static string GetBestTFM(BaselineProject baselineProject, bool keepCurrentTfm, string?specifiedTFM, bool usePreviewSDK) { if (string.IsNullOrWhiteSpace(specifiedTFM)) { // Let's figure this out, friends var tfmForApps = TargetFrameworkHelper.FindHighestInstalledTargetFramework(usePreviewSDK); if (keepCurrentTfm) { specifiedTFM = baselineProject.GetTfm(); } else if (baselineProject.ProjectStyle == ProjectStyle.WindowsDesktop || baselineProject.ProjectStyle == ProjectStyle.MSTest) { specifiedTFM = tfmForApps; } else if (baselineProject.OutputType == ProjectOutputType.Library) { specifiedTFM = MSBuildFacts.Netstandard20; } else if (baselineProject.OutputType == ProjectOutputType.Exe) { specifiedTFM = tfmForApps; } else { // Default is to just use what exists in the project specifiedTFM = baselineProject.GetTfm(); } } return(specifiedTFM); }
/// <summary> /// Checks that the target framework of the current runner can load the extension assembly. For example, .NET Core /// cannot load .NET Framework assemblies and vice-versa. /// </summary> /// <param name="runnerAsm">The executing runner</param> /// <param name="extensionAsm">The extension we are attempting to load</param> internal static void ValidateTargetFramework(Assembly runnerAsm, ExtensionAssembly extensionAsm) { if (runnerAsm == null) { return; } var extHelper = new TargetFrameworkHelper(extensionAsm.FilePath); var runnerHelper = new TargetFrameworkHelper(runnerAsm.Location); if (runnerHelper.FrameworkName?.StartsWith(".NETStandard") == true) { throw new NUnitEngineException("Test runners must target .NET Core or .NET Framework, not .NET Standard"); } else if (runnerHelper.FrameworkName?.StartsWith(".NETCoreApp") == true) { if (extHelper.FrameworkName?.StartsWith(".NETStandard") != true && extHelper.FrameworkName?.StartsWith(".NETCoreApp") != true) { throw new NUnitEngineException(".NET Core runners require .NET Core or .NET Standard extensions"); } } else if (extHelper.FrameworkName?.StartsWith(".NETCoreApp") == true) { throw new NUnitEngineException(".NET Framework runners cannot load .NET Core extensions"); } }
/// <summary> /// Use Mono.Cecil to get information about an assembly and /// apply it to the package using special internal keywords. /// </summary> /// <param name="package"></param> static void ApplyImageSettings(TestPackage package) { Guard.ArgumentNotNull(package, nameof(package)); var assembly = new TargetFrameworkHelper(package.FullName); var targetVersion = assembly.TargetRuntimeVersion; if (targetVersion.Major > 0) { log.Debug($"Assembly {package.FullName} uses version {targetVersion}"); package.Settings[EnginePackageSettings.ImageRuntimeVersion] = targetVersion; } var frameworkName = assembly.FrameworkName; if (!string.IsNullOrEmpty(frameworkName)) { log.Debug($"Assembly {package.FullName} targets {frameworkName}"); package.Settings[EnginePackageSettings.ImageTargetFrameworkName] = frameworkName; } package.Settings[EnginePackageSettings.ImageRequiresX86] = assembly.RequiresX86; if (assembly.RequiresX86) { log.Debug($"Assembly {package.FullName} will be run x86"); package.Settings[EnginePackageSettings.RunAsX86] = true; } package.Settings[EnginePackageSettings.ImageRequiresDefaultAppDomainAssemblyResolver] = assembly.RequiresAssemblyResolver; if (assembly.RequiresAssemblyResolver) { log.Debug($"Assembly {package.FullName} requires default app domain assembly resolver"); } }
public void InstallPackage(Workspace workspace, Document document, IPackageIndexModelInfo packageInfo, IEnumerable <ProjectMetadata> projects, CancellationToken cancellationToken = default(CancellationToken)) { Debug.Assert(packageInfo != null); ThreadHelper.JoinableTaskFactory.RunAsync(async delegate { foreach (var project in projects) { try { var container = _serviceProvider.GetService <IComponentModel, SComponentModel>(); var projectSpecificInstallers = container.DefaultExportProvider.GetExportedValues <IProjectPackageInstaller>(); if (projectSpecificInstallers != null && projectSpecificInstallers.Any()) { var supportedInstaller = projectSpecificInstallers.FirstOrDefault(x => x.SupportsProject(project.ProjectPath)); if (supportedInstaller != null) { if (await SafeExecuteActionAsync( delegate { var frameworksToInstall = new List <FrameworkName>(); foreach (var projectFrameworkMetadata in project.TargetFrameworks) { if (TargetFrameworkHelper.AreCompatible(projectFrameworkMetadata, packageInfo.TargetFrameworks)) { frameworksToInstall.Add(TargetFrameworkHelper.GetFrameworkName(projectFrameworkMetadata.TargetFrameworkShortName)); } } return(supportedInstaller.InstallPackageAsync(project.ProjectPath, packageInfo.PackageName, packageInfo.PackageVersion, frameworksToInstall, cancellationToken)); })) { continue; // package installed successfully } } } } catch (Exception e) { // we should not throw here, since it would create an exception that may be // visible to the user, instead just dump into debugger output or to package // manager console. // TODO Package manager console? Debug.Write(e.ToString()); } } }); }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { var document = context.Document; var span = context.Span; var diagnostics = context.Diagnostics; var cancellationToken = context.CancellationToken; var project = document.Project; var diagnostic = diagnostics.First(); var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var token = root.FindToken(span.Start, findInsideTrivia: true); var ancestors = token.GetAncestors <SyntaxNode>(); if (!ancestors.Any()) { return; } var node = ancestors.FirstOrDefault(n => n.Span.Contains(span) && n != root); if (node == null) { return; } var placeSystemNamespaceFirst = true; if (!cancellationToken.IsCancellationRequested) { if (CanAddImport(node, cancellationToken)) { var typeName = node.ToString(); var projectTargetFrameworks = _targetFrameworkProvider.GetTargetFrameworks(document.FilePath); // Note: allowHigherVersions=false here since we don't want to provide code fix that adds another // dependency for the same package but different version, user should upgrade it on his own when // see Diagnostic suggestion var packagesWithGivenType = TargetFrameworkHelper.GetSupportedPackages(_packageSearcher.Search(typeName), projectTargetFrameworks, allowHigherVersions: false) .Take(MaxPackageSuggestions); foreach (var typeInfo in packagesWithGivenType) { cancellationToken.ThrowIfCancellationRequested(); var namespaceName = typeInfo.FullName.Contains(".") ? Path.GetFileNameWithoutExtension(typeInfo.FullName) : null; if (!string.IsNullOrEmpty(namespaceName)) { var action = new AddPackageCodeAction(_packageInstaller, typeInfo, ActionTitle, (c) => AddImportAsync(node, namespaceName, document, placeSystemNamespaceFirst, cancellationToken)); context.RegisterCodeFix(action, diagnostic); } } } } }
public static int Run(string?project, string?workspace, string?msbuildPath, string?tfm, bool allowPreviews, bool diffOnly, bool noBackup, bool keepCurrentTfms) { if (!string.IsNullOrWhiteSpace(project) && !string.IsNullOrWhiteSpace(workspace)) { Console.WriteLine("Cannot specify both a project and a workspace."); return(-1); } if (!string.IsNullOrWhiteSpace(tfm) && keepCurrentTfms) { Console.WriteLine($"Both '{nameof(tfm)}' and '{nameof(keepCurrentTfms)}' cannot be specified. Please pick one."); return(-1); } try { msbuildPath = MSBuildHelpers.HookAssemblyResolveForMSBuild(msbuildPath); if (string.IsNullOrWhiteSpace(msbuildPath)) { Console.WriteLine("Could not find an MSBuild."); return(-1); } if (!string.IsNullOrWhiteSpace(tfm)) { tfm = tfm.Trim(); if (!TargetFrameworkHelper.IsValidTargetFramework(tfm)) { Console.WriteLine($"Invalid framework specified for --target-framework: '{tfm}'"); return(-1); } } var workspacePath = string.Empty; MSBuildConversionWorkspaceType workspaceType; if (!string.IsNullOrWhiteSpace(project)) { workspacePath = Path.GetFullPath(project, Environment.CurrentDirectory); workspaceType = MSBuildConversionWorkspaceType.Project; } else { var(isSolution, workspaceFilePath) = MSBuildConversionWorkspaceFinder.FindWorkspace(Environment.CurrentDirectory, workspace); workspaceType = isSolution ? MSBuildConversionWorkspaceType.Solution : MSBuildConversionWorkspaceType.Project; workspacePath = workspaceFilePath; } var workspaceLoader = new MSBuildConversionWorkspaceLoader(workspacePath, workspaceType); // do not create backup if --diff-only specified noBackup = noBackup || diffOnly; var msbuildWorkspace = workspaceLoader.LoadWorkspace(workspacePath, noBackup); foreach (var item in msbuildWorkspace.WorkspaceItems) { if (diffOnly) { var differ = new Differ(item.UnconfiguredProject.FirstConfiguredProject, item.SdkBaselineProject.Project.FirstConfiguredProject); differ.GenerateReport(Directory.GetParent(workspacePath).FullName); } else { var converter = new Converter(item.UnconfiguredProject, item.SdkBaselineProject, item.ProjectRootElement); converter.Convert(item.ProjectRootElement.FullPath, tfm, keepCurrentTfms, allowPreviews); } } } catch (Exception e) { Console.WriteLine(e.ToString()); return(-1); } Console.WriteLine("Conversion complete!"); return(0); }
/// <summary> /// Use Mono.Cecil to get information about all assemblies and /// apply it to the package using special internal keywords. /// </summary> /// <param name="package"></param> private static void ApplyImageData(TestPackage package) { string packageName = package.FullName; Version targetVersion = new Version(0, 0); string frameworkName = null; bool requiresX86 = false; bool requiresAssemblyResolver = false; // We are doing two jobs here: (1) in the else clause (below) // we get information about a single assembly and record it, // (2) in the if clause, we recursively examine all subpackages // and then apply policies for promulgating each setting to // a containing package. We could implement the policy part at // a higher level, but it seems simplest to do it right here. if (package.SubPackages.Count > 0) { foreach (var subPackage in package.SubPackages) { ApplyImageData(subPackage); // Collect the highest version required Version v = subPackage.GetSetting(InternalEnginePackageSettings.ImageRuntimeVersion, new Version(0, 0)); if (v > targetVersion) { targetVersion = v; } // Collect highest framework name // TODO: This assumes lexical ordering is valid - check it string fn = subPackage.GetSetting(InternalEnginePackageSettings.ImageTargetFrameworkName, ""); if (fn != "") { if (frameworkName == null || fn.CompareTo(frameworkName) < 0) { frameworkName = fn; } } // If any assembly requires X86, then the aggregate package requires it if (subPackage.GetSetting(InternalEnginePackageSettings.ImageRequiresX86, false)) { requiresX86 = true; } if (subPackage.GetSetting(InternalEnginePackageSettings.ImageRequiresDefaultAppDomainAssemblyResolver, false)) { requiresAssemblyResolver = true; } } } else if (File.Exists(packageName) && PathUtils.IsAssemblyFileType(packageName)) { var assembly = new TargetFrameworkHelper(packageName); targetVersion = assembly.TargetRuntimeVersion; log.Debug($"Assembly {packageName} uses version {targetVersion}"); frameworkName = assembly.FrameworkName; log.Debug($"Assembly {packageName} targets {frameworkName}"); if (assembly.RequiresX86) { requiresX86 = true; log.Debug($"Assembly {packageName} will be run x86"); } if (assembly.RequiresAssemblyResolver) { requiresAssemblyResolver = true; log.Debug($"Assembly {packageName} requires default app domain assembly resolver"); } } if (targetVersion.Major > 0) { package.Settings[InternalEnginePackageSettings.ImageRuntimeVersion] = targetVersion; } if (!string.IsNullOrEmpty(frameworkName)) { package.Settings[InternalEnginePackageSettings.ImageTargetFrameworkName] = frameworkName; } package.Settings[InternalEnginePackageSettings.ImageRequiresX86] = requiresX86; if (requiresX86) { package.Settings[EnginePackageSettings.RunAsX86] = true; } package.Settings[InternalEnginePackageSettings.ImageRequiresDefaultAppDomainAssemblyResolver] = requiresAssemblyResolver; }
public static int Run(string?project, string?workspace, string?msbuildPath, string?tfm, bool forceWebConversion, bool preview, bool diffOnly, bool noBackup, bool keepCurrentTfms, bool update, bool mauiConversion, bool forceRemoveCustomImports) { if (update) { UpdateTryConvert.Update(); return(0); } if (!string.IsNullOrWhiteSpace(project) && !string.IsNullOrWhiteSpace(workspace)) { Console.WriteLine("Cannot specify both a project and a workspace."); return(-1); } if (!string.IsNullOrWhiteSpace(tfm) && keepCurrentTfms) { Console.WriteLine($"Both '{nameof(tfm)}' and '{nameof(keepCurrentTfms)}' cannot be specified. Please pick one."); return(-1); } try { //For Xamarin Projects, set MSBuild path to VSInstallation Dir via Environment Variable if (mauiConversion) { var vsinstalldir = Environment.GetEnvironmentVariable("VSINSTALLDIR"); if (!string.IsNullOrEmpty(vsinstalldir)) { msbuildPath = MSBuildHelpers.HookAssemblyResolveForMSBuild(Path.Combine(vsinstalldir, "MSBuild", "Current", "Bin")); } else { string vsPath = new VisualStudioLocator().GetLatestVisualStudioPath(); if (string.IsNullOrWhiteSpace(vsPath)) { Console.WriteLine("Error locating VS Install Directory. Try setting Environment Variable VSINSTALLDIR."); return(-1); } else { msbuildPath = MSBuildHelpers.HookAssemblyResolveForMSBuild(Path.Combine(vsPath, "MSBuild", "Current", "Bin")); } } } else { msbuildPath = MSBuildHelpers.HookAssemblyResolveForMSBuild(msbuildPath); } if (string.IsNullOrWhiteSpace(msbuildPath)) { Console.WriteLine("Could not find an MSBuild."); return(-1); } if (!string.IsNullOrWhiteSpace(tfm)) { tfm = tfm.Trim(); if (!TargetFrameworkHelper.IsValidTargetFramework(tfm)) { Console.WriteLine($"Invalid framework specified for --target-framework: '{tfm}'"); return(-1); } } else { tfm = TargetFrameworkHelper.FindHighestInstalledTargetFramework(preview, msbuildPath); } var workspacePath = string.Empty; MSBuildConversionWorkspaceType workspaceType; if (!string.IsNullOrWhiteSpace(project)) { workspacePath = Path.GetFullPath(project, Environment.CurrentDirectory); workspaceType = MSBuildConversionWorkspaceType.Project; } else { var(isSolution, workspaceFilePath) = MSBuildConversionWorkspaceFinder.FindWorkspace(Environment.CurrentDirectory, workspace); workspaceType = isSolution ? MSBuildConversionWorkspaceType.Solution : MSBuildConversionWorkspaceType.Project; workspacePath = workspaceFilePath; } var workspaceLoader = new MSBuildConversionWorkspaceLoader(workspacePath, workspaceType); // do not create backup if --diff-only specified noBackup = noBackup || diffOnly; var msbuildWorkspace = workspaceLoader.LoadWorkspace(workspacePath, noBackup, tfm, keepCurrentTfms, forceWebConversion); if (msbuildWorkspace.WorkspaceItems.Length is 0) { Console.WriteLine("No projects converted."); return(0); } foreach (var item in msbuildWorkspace.WorkspaceItems) { if (diffOnly) { var differ = new Differ(item.UnconfiguredProject.FirstConfiguredProject, item.SdkBaselineProject.Project.FirstConfiguredProject); var parent = Directory.GetParent(workspacePath); if (parent is null) { differ.GenerateReport(workspacePath); } else { differ.GenerateReport(parent.FullName); } } else { var converter = new Converter(item.UnconfiguredProject, item.SdkBaselineProject, item.ProjectRootElement, noBackup, forceRemoveCustomImports); converter.Convert(item.ProjectRootElement.FullPath); } } } catch (Exception e) { Console.WriteLine(e.ToString()); return(-1); } Console.WriteLine("Conversion complete!"); return(0); }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { var document = context.Document; var projects = _projectMetadataProvider.GetProjects(document.FilePath); if (projects == null || !projects.Any()) { // project is unsupported return; } var span = context.Span; var diagnostics = context.Diagnostics; var cancellationToken = context.CancellationToken; var project = document.Project; var diagnostic = diagnostics.First(); var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var token = root.FindToken(span.Start, findInsideTrivia: true); var ancestors = token.GetAncestors <SyntaxNode>(); if (!ancestors.Any()) { return; } var node = ancestors.FirstOrDefault(n => n.Span.Contains(span) && n != root); if (node == null) { return; } var placeSystemNamespaceFirst = true; if (!cancellationToken.IsCancellationRequested) { // get distinct frameworks from all projects current file belongs to var suggestions = Analyzer.GetSuggestions(node, projects); foreach (var packageInfo in suggestions.Take(MaxPackageSuggestions)) { cancellationToken.ThrowIfCancellationRequested(); var namespaceName = packageInfo.GetNamespace(); AddPackageCodeAction action = null; if (string.IsNullOrEmpty(namespaceName)) { // namspaces suggestions don't need to add another namespace action = new AddPackageCodeAction(_packageInstaller, packageInfo, projects.Where(x => TargetFrameworkHelper.SupportsProjectTargetFrameworks(packageInfo, x.TargetFrameworks)).ToList(), ActionTitle, (c) => Task.FromResult(document)); } else if (CanAddImport(node, cancellationToken)) { action = new AddPackageCodeAction(_packageInstaller, packageInfo, projects.Where(x => TargetFrameworkHelper.SupportsProjectTargetFrameworks(packageInfo, x.TargetFrameworks)).ToList(), ActionTitle, (c) => AddImportAsync(node, namespaceName, document, placeSystemNamespaceFirst, cancellationToken)); } context.RegisterCodeFix(action, diagnostic); } } }