private bool TryCreateQualifier(NugetAnalyzedPackage analyzedPackage, out IStatement statement) { List <PathAtom> compatibleTfms = new List <PathAtom>(); if (analyzedPackage.IsNetStandardPackageOnly) { compatibleTfms.AddRange(m_nugetFrameworkMonikers.NetStandardToFullFrameworkCompatibility); } FindAllCompatibleFrameworkMonikers(analyzedPackage, (List <PathAtom> monikers) => compatibleTfms.AddRange(monikers), m_nugetFrameworkMonikers.FullFrameworkVersionHistory, m_nugetFrameworkMonikers.NetCoreVersionHistory); if (compatibleTfms.Count > 0) { // { targetFramework: 'tf1' | 'tf2' | ... } var qualifierType = UnionType( (propertyName: "targetFramework", literalTypes: compatibleTfms.Select(m => m.ToString(m_pathTable.StringTable))), (propertyName: "targetRuntime", literalTypes: m_nugetFrameworkMonikers.SupportedTargetRuntimes) ); statement = Qualifier(qualifierType); return(true); } statement = null; return(false); }
internal static void FindAllCompatibleFrameworkMonikers(NugetAnalyzedPackage analyzedPackage, Action <List <PathAtom> > callback, params List <PathAtom>[] tfmHistory) { if (analyzedPackage.TargetFrameworks.Count > 0) { foreach (var versionHistory in tfmHistory) { var indices = analyzedPackage.TargetFrameworks .Select(moniker => versionHistory.IndexOf(moniker)) .Where(idx => idx != -1) .OrderBy(x => x).ToList(); if (indices.IsNullOrEmpty()) { continue; } for (int i = 0; i < indices.Count(); i++) { int start = indices[i]; int count = (i + 1) > indices.Count() - 1 ? versionHistory.Count() - start : (indices[i + 1] - indices[i]); callback(versionHistory.GetRange(start, count)); } } } else { callback(default(List <PathAtom>)); } }
/// <summary> /// Constructs a new NugetAnalyzed Package. /// </summary> /// <remarks> /// In case of failure it will log a detailed message and return null. /// </remarks> public static NugetAnalyzedPackage TryAnalyzeNugetPackage( FrontEndContext context, NugetFrameworkMonikers nugetFrameworkMonikers, XDocument nuSpec, PackageOnDisk packageOnDisk, Dictionary <string, INugetPackage> packagesOnConfig, bool doNotEnforceDependencyVersions) { Contract.Requires(context != null); Contract.Requires(nuSpec != null); Contract.Requires(packageOnDisk != null); Contract.Requires(packageOnDisk.NuSpecFile.IsValid); var analyzedPackage = new NugetAnalyzedPackage(context, nugetFrameworkMonikers, nuSpec, packageOnDisk, packagesOnConfig, doNotEnforceDependencyVersions); if (!analyzedPackage.TryParseDependenciesFromNuSpec()) { return(null); } analyzedPackage.ParseManagedSemantics(); analyzedPackage.UpdateForMissingQualifierConversionFunction(); return(analyzedPackage); }
/// <summary> /// Performs a depth first search with cycle detection. All descendants of analyzedPackage are pushed into result after it. /// </summary> /// <returns> /// Whether there is a cycle that involves analyzedPackage /// </returns> private static bool TryVisit( IDictionary <string, NugetAnalyzedPackage> allAnalyzedPackages, HashSet <NugetAnalyzedPackage> unmarkedPackages, HashSet <NugetAnalyzedPackage> temporaryMarkedPackages, NugetAnalyzedPackage analyzedPackage, IList <NugetAnalyzedPackage> result) { if (temporaryMarkedPackages.Contains(analyzedPackage)) { // This is a cycle! return(false); } if (unmarkedPackages.Contains(analyzedPackage)) { var isRemoved = unmarkedPackages.Remove(analyzedPackage); Contract.Assert(isRemoved); temporaryMarkedPackages.Add(analyzedPackage); foreach (var dependency in analyzedPackage.Dependencies) { Contract.Assert(allAnalyzedPackages.ContainsKey(dependency.GetPackageIdentity())); var analyzedDependency = allAnalyzedPackages[dependency.GetPackageIdentity()]; TryVisit(allAnalyzedPackages, unmarkedPackages, temporaryMarkedPackages, analyzedDependency, result); } isRemoved = temporaryMarkedPackages.Remove(analyzedPackage); Contract.Assert(isRemoved); result.Add(analyzedPackage); } return(true); }
/// <nodoc /> public NugetSpecGenerator(PathTable pathTable, NugetAnalyzedPackage analyzedPackage) { m_pathTable = pathTable; m_analyzedPackage = analyzedPackage; m_packageOnDisk = analyzedPackage.PackageOnDisk; m_xmlExtension = PathAtom.Create(pathTable.StringTable, ".xml"); m_pdbExtension = PathAtom.Create(pathTable.StringTable, ".pdb"); }
private bool TryCreateQualifier(NugetAnalyzedPackage analyzedPackage, out IStatement statement) { if (analyzedPackage.HasTargetFrameworks()) { var targetFrameworks = analyzedPackage.GetTargetFrameworksInStableOrder(m_pathTable); // { targetFramework: 'tf1' | 'tf2' } var qualifierType = UnionType(propertyName: "targetFramework", literalTypes: targetFrameworks); statement = Qualifier(qualifierType); return(true); } statement = null; return(false); }
/// <summary> /// Returns a list of target frameworks of a <paramref name="analyzedPackage"/> in sorted order. /// </summary> public static string[] GetTargetFrameworksInStableOrder(this NugetAnalyzedPackage analyzedPackage, PathTable pathTable) { Contract.Requires(HasTargetFrameworks(analyzedPackage)); var targetFrameworks = new HashSet <string>(); foreach (var kv in analyzedPackage.TargetFrameworkWithFallbacks) { targetFrameworks.Add(kv.Key.ToString(pathTable.StringTable)); foreach (var fallback in kv.Value) { targetFrameworks.Add(fallback.ToString(pathTable.StringTable)); } } return(targetFrameworks.OrderByDescending(f => f).ToArray()); }
private IStatement CreatePackageVariableDeclaration(NugetAnalyzedPackage package) { IExpression pkgExpression; TypeReferenceNode pkgType; if (package.IsManagedPackage) { // If the package is managed, it is a 'ManagedNugetPackage' and we create a switch based on the current qualifie // that defines contents, compile, runtime and dependency items pkgType = new TypeReferenceNode("Managed", "ManagedNugetPackage"); // Computes the switch cases, based on the target framework List <ICaseClause> cases = CreateSwitchCasesForTargetFrameworks(package, pkgType); pkgExpression = new CallExpression( new ParenthesizedExpression( new ArrowFunction( CollectionUtilities.EmptyArray <IParameterDeclaration>(), new SwitchStatement( PropertyAccess("qualifier", "targetFramework"), new DefaultClause( new ExpressionStatement( new CallExpression( PropertyAccess("Contract", "fail"), new LiteralExpression("Unsupported target framework")))), cases)))); } else { // If the package is not managed, it is a 'NugetPackage' with just contents and dependencies pkgType = new TypeReferenceNode("NugetPackage"); pkgExpression = ObjectLiteral( (name: "contents", PropertyAccess("Contents", "all")), (name: "dependencies", Array(package.Dependencies.Select(CreateImportFromForDependency).ToArray())), (name: "version", new LiteralExpression(package.Version))); } return (new VariableDeclarationBuilder() .Name("pkg") .Visibility(Visibility.Public) .Initializer(pkgExpression) .Type(pkgType) .Build()); }
public ISourceFile CreateScriptSourceFile(NugetAnalyzedPackage analyzedPackage) { var sourceFileBuilder = new SourceFileBuilder(); // 0. Import {Transformer} from "Sdk.Transformers" to be able to seal directories sourceFileBuilder.Statement(ImportDeclaration(new [] { "Transformer" }, "Sdk.Transformers")); // 1. Optional import of managed sdk. if (analyzedPackage.IsManagedPackage) { // import * as Managed from 'Sdk.Managed'; sourceFileBuilder .Statement(ImportDeclaration(alias: "Managed", moduleName: "Sdk.Managed")) .SemicolonAndBlankLine(); } // 2. Optional qualifier if (TryCreateQualifier(analyzedPackage, out var qualifierStatement)) { sourceFileBuilder .Statement(qualifierStatement) .SemicolonAndBlankLine(); } // 3. Declare a public directory that points to the package root, for convenience reasons sourceFileBuilder .Statement(new VariableDeclarationBuilder().Name("packageRoot").Initializer(PropertyAccess("Contents", "packageRoot")).Build()) .SemicolonAndBlankLine(); // Create a sealed directory declaration with all the package content sourceFileBuilder .Statement(CreatePackageContents()) .SemicolonAndBlankLine(); // @@public export const pkg = ... sourceFileBuilder.Statement(CreatePackageVariableDeclaration(analyzedPackage)); return(sourceFileBuilder.Build()); }
/// <summary> /// Constructs a new NugetAnalyzed Package. /// </summary> /// <remarks> /// In case of failure it will log a detailed message and return null. /// </remarks> public static NugetAnalyzedPackage TryAnalyzeNugetPackage( FrontEndContext context, NugetFrameworkMonikers nugetFrameworkMonikers, [CanBeNull] XDocument nuSpec, PackageOnDisk packageOnDisk, Dictionary <string, INugetPackage> packagesOnConfig, bool doNotEnforceDependencyVersions) { Contract.Requires(context != null); Contract.Requires(packageOnDisk != null); var analyzedPackage = new NugetAnalyzedPackage(context, nugetFrameworkMonikers, packageOnDisk, packagesOnConfig, doNotEnforceDependencyVersions); analyzedPackage.ParseManagedSemantics(); if (nuSpec != null && !analyzedPackage.TryParseDependenciesFromNuSpec(nuSpec)) { return(null); } return(analyzedPackage); }
private List <ICaseClause> CreateSwitchCasesForTargetFrameworks(NugetAnalyzedPackage analyzedPackage, ITypeNode pkgType) { var cases = new List <ICaseClause>(); Contract.Assert(analyzedPackage.TargetFrameworks.Count != 0, "Managed package must have at least one target framework."); var valid = analyzedPackage.TargetFrameworks.Exists(moniker => m_nugetFrameworkMonikers.FullFrameworkVersionHistory.Contains(moniker) || m_nugetFrameworkMonikers.NetCoreVersionHistory.Contains(moniker)); Contract.Assert(valid, "Target framework monikers must exsist and be registered with internal target framework version helpers."); foreach (var versionHistory in new List <PathAtom>[] { m_nugetFrameworkMonikers.FullFrameworkVersionHistory, m_nugetFrameworkMonikers.NetCoreVersionHistory }) { FindAllCompatibleFrameworkMonikers(analyzedPackage, (List <PathAtom> monikers) => { if (monikers.Count == 0) { return; } cases.AddRange(monikers.Take(monikers.Count - 1).Select(m => new CaseClause(new LiteralExpression(m.ToString(m_pathTable.StringTable))))); var compile = new List <IExpression>(); var runtime = new List <IExpression>(); var dependencies = new List <IExpression>(); // Compile items if (TryGetValueForFrameworkAndFallbacks(analyzedPackage.References, new NugetTargetFramework(monikers.First()), out IReadOnlyList <RelativePath> refAssemblies)) { foreach (var assembly in refAssemblies) { compile.Add(CreateSimpleBinary(assembly)); } } // Runtime items if (TryGetValueForFrameworkAndFallbacks(analyzedPackage.Libraries, new NugetTargetFramework(monikers.First()), out IReadOnlyList <RelativePath> libAssemblies)) { foreach (var assembly in libAssemblies) { runtime.Add(CreateSimpleBinary(assembly)); } } // Dependency items if (analyzedPackage.DependenciesPerFramework.TryGetValue(monikers.First(), out IReadOnlyList <INugetPackage> dependencySpecificFrameworks)) { foreach (var dependencySpecificFramework in dependencySpecificFrameworks) { dependencies.Add(CreateImportFromForDependency(dependencySpecificFramework)); } } cases.Add( new CaseClause( new LiteralExpression(monikers.Last().ToString(m_pathTable.StringTable)), new ReturnStatement( new CallExpression( PropertyAccess("Managed", "Factory", "createNugetPackage"), new LiteralExpression(analyzedPackage.Id), new LiteralExpression(analyzedPackage.Version), PropertyAccess("Contents", "all"), Array(compile), Array(runtime), Array(new CallExpression(new Identifier("...addIfLazy"), new BinaryExpression( new PropertyAccessExpression("qualifier", "targetFramework"), SyntaxKind.EqualsEqualsEqualsToken, new LiteralExpression(monikers.First().ToString(m_pathTable.StringTable)) ), new ArrowFunction( CollectionUtilities.EmptyArray <IParameterDeclaration>(), Array(dependencies) ) )) ) ) ) ); }, versionHistory); } return(cases); }
private List <ICaseClause> CreateSwitchCasesForTargetFrameworks(NugetAnalyzedPackage analyzedPackage, ITypeNode pkgType) { var cases = new List <ICaseClause>(); Contract.Assert(analyzedPackage.TargetFrameworks.Count != 0, "Managed package must have at least one target framework."); var valid = analyzedPackage.TargetFrameworks.Exists(moniker => m_nugetFrameworkMonikers.FullFrameworkVersionHistory.Contains(moniker) || m_nugetFrameworkMonikers.NetCoreVersionHistory.Contains(moniker)); Contract.Assert(valid, "Target framework monikers must exsist and be registered with internal target framework version helpers."); var allFullFrameworkDeps = m_nugetFrameworkMonikers.FullFrameworkVersionHistory .SelectMany(m => analyzedPackage.DependenciesPerFramework.TryGetValue(m, out IReadOnlyList <INugetPackage> dependencySpecificFrameworks) ? dependencySpecificFrameworks : new List <INugetPackage>()) .GroupBy(pkg => pkg.Id) .Select(grp => grp.OrderBy(pkg => pkg.Version).Last()); foreach (var versionHistory in new List <PathAtom>[] { m_nugetFrameworkMonikers.FullFrameworkVersionHistory, m_nugetFrameworkMonikers.NetCoreVersionHistory }) { FindAllCompatibleFrameworkMonikers(analyzedPackage, (List <PathAtom> monikers) => { if (monikers.Count == 0) { return; } if (analyzedPackage.IsNetStandardPackageOnly) { cases.AddRange(m_nugetFrameworkMonikers.NetStandardToFullFrameworkCompatibility.Select(m => new CaseClause(new LiteralExpression(m.ToString(m_pathTable.StringTable))))); } cases.AddRange(monikers.Take(monikers.Count - 1).Select(m => new CaseClause(new LiteralExpression(m.ToString(m_pathTable.StringTable))))); var compile = new List <IExpression>(); var runtime = new List <IExpression>(); var dependencies = new List <IExpression>(); // Compile items if (TryGetValueForFrameworkAndFallbacks(analyzedPackage.References, new NugetTargetFramework(monikers.First()), out IReadOnlyList <RelativePath> refAssemblies)) { compile.AddRange(refAssemblies.Select(r => CreateSimpleBinary(r))); } // Runtime items if (TryGetValueForFrameworkAndFallbacks(analyzedPackage.Libraries, new NugetTargetFramework(monikers.First()), out IReadOnlyList <RelativePath> libAssemblies)) { runtime.AddRange(libAssemblies.Select(l => CreateSimpleBinary(l))); } // For full framework dependencies we unconditionally include all the distinct dependencies from the nuspec file, // .NETStandard dependencies are only included if the moniker and the parsed target framework match! if (m_nugetFrameworkMonikers.IsFullFrameworkMoniker(monikers.First())) { dependencies.AddRange(allFullFrameworkDeps.Select(dep => CreateImportFromForDependency(dep))); } else { if (analyzedPackage.DependenciesPerFramework.TryGetValue(monikers.First(), out IReadOnlyList <INugetPackage> dependencySpecificFrameworks)) { dependencies.AddRange(dependencySpecificFrameworks.Select(dep => CreateImportFromForDependency(dep))); } } cases.Add( new CaseClause( new LiteralExpression(monikers.Last().ToString(m_pathTable.StringTable)), new ReturnStatement( new CallExpression( PropertyAccess("Managed", "Factory", "createNugetPackage"), new LiteralExpression(analyzedPackage.Id), new LiteralExpression(analyzedPackage.Version), PropertyAccess("Contents", "all"), Array(compile), Array(runtime), m_nugetFrameworkMonikers.IsFullFrameworkMoniker(monikers.Last()) ? Array(dependencies) : Array(new CallExpression(new Identifier("...addIfLazy"), new BinaryExpression( new PropertyAccessExpression("qualifier", "targetFramework"), SyntaxKind.EqualsEqualsEqualsToken, new LiteralExpression(monikers.First().ToString(m_pathTable.StringTable)) ), new ArrowFunction( CollectionUtilities.EmptyArray <IParameterDeclaration>(), Array(dependencies) ) )) ) ) ) ); }, versionHistory); } return(cases); }
private List <ICaseClause> CreateSwitchCasesForTargetFrameworks(NugetAnalyzedPackage analyzedPackage, ITypeNode pkgType) { var cases = new List <ICaseClause>(); Contract.Assert(analyzedPackage.TargetFrameworkWithFallbacks.Count != 0, "Managed package must have at least one target framework."); foreach (var framework in analyzedPackage.TargetFrameworkWithFallbacks) { // Emit the fallback cases first: foreach (var fallback in framework.Value) { var fallbackString = fallback.ToString(m_pathTable.StringTable); cases.Add(new CaseClause(new LiteralExpression(fallbackString))); } var compile = new List <IExpression>(); var runtime = new List <IExpression>(); var dependencies = new List <IExpression>(); // Compile items if (TryGetValueForFrameworkAndFallbacks(analyzedPackage.References, new NugetTargetFramework(framework.Key), out IReadOnlyList <RelativePath> refAssemblies)) { foreach (var assembly in refAssemblies) { compile.Add(CreateSimpleBinary(assembly)); } } // Runtime items if (TryGetValueForFrameworkAndFallbacks(analyzedPackage.Libraries, new NugetTargetFramework(framework.Key), out IReadOnlyList <RelativePath> libAssemblies)) { foreach (var assembly in libAssemblies) { runtime.Add(CreateSimpleBinary(assembly)); } } // Dependency items if (analyzedPackage.DependenciesPerFramework.TryGetValue( framework.Key, out IReadOnlyList <INugetPackage> dependencySpecificFrameworks)) { foreach (var dependencySpecificFramework in dependencySpecificFrameworks) { dependencies.Add(CreateImportFromForDependency(dependencySpecificFramework)); } } dependencies.AddRange(analyzedPackage.Dependencies.Select(CreateImportFromForDependency)); cases.Add( new CaseClause( new LiteralExpression(framework.Key.ToString(m_pathTable.StringTable)), new ReturnStatement( new CallExpression( PropertyAccess("Managed", "Factory", "createNugetPackge"), new LiteralExpression(analyzedPackage.Id), new LiteralExpression(analyzedPackage.Version), PropertyAccess("Contents", "all"), Array(compile), Array(runtime), Array(dependencies) ) ) ) ); } return(cases); }
/// <summary> /// Returns true if a <paramref name="analyzedPackage"/> has at least one target framework. /// </summary> public static bool HasTargetFrameworks(this NugetAnalyzedPackage analyzedPackage) { return(analyzedPackage.TargetFrameworkWithFallbacks.Count != 0); }