Nuget Analyzer + Spec Generator Refactoring (#281)

* General Nuget package target framework support and spec generation reworked
This commit is contained in:
Kristijan Šimić 2019-05-10 13:30:36 +02:00 коммит произвёл GitHub
Родитель a20df8073c
Коммит a9b89b4452
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
39 изменённых файлов: 445 добавлений и 591 удалений

Просмотреть файл

@ -11,7 +11,7 @@ export namespace Contents {
@@public
export const pkg: Managed.ManagedNugetPackage =
Managed.Factory.createNugetPackge(
Managed.Factory.createNugetPackage(
"Bond.Core.NET",
"3.2.0",
Contents.all,

Просмотреть файл

@ -11,7 +11,7 @@ export namespace Contents {
@@public
export const pkg: Managed.ManagedNugetPackage =
Managed.Factory.createNugetPackge(
Managed.Factory.createNugetPackage(
"Bond.NET",
"3.2.0",
Contents.all,

Просмотреть файл

@ -11,7 +11,7 @@ export namespace Contents {
@@public
export const pkg: Managed.ManagedNugetPackage =
Managed.Factory.createNugetPackge(
Managed.Factory.createNugetPackage(
"Bond.Rpc.NET",
"3.2.0",
Contents.all,

Просмотреть файл

@ -16,7 +16,7 @@ namespace Contents {
@@public
export const pkg: Managed.ManagedNugetPackage =
Managed.Factory.createNugetPackge(
Managed.Factory.createNugetPackage(
"ArtifactServices.App.Shared.Cache",
"0.0.0",
Contents.all,

Просмотреть файл

@ -16,7 +16,7 @@ namespace Contents {
@@public
export const pkg: Managed.ManagedNugetPackage =
Managed.Factory.createNugetPackge(
Managed.Factory.createNugetPackage(
"ArtifactServices.App.Shared",
"0.0.0",
Contents.all,

Просмотреть файл

@ -16,7 +16,7 @@ namespace Contents {
@@public
export const pkg: Managed.ManagedNugetPackage =
Managed.Factory.createNugetPackge(
Managed.Factory.createNugetPackage(
"Drop.App.Core",
"0.0.0",
Contents.all,

Просмотреть файл

@ -16,7 +16,7 @@ namespace Contents {
@@public
export const pkg: Managed.ManagedNugetPackage =
Managed.Factory.createNugetPackge(
Managed.Factory.createNugetPackage(
"Drop.Client",
"0.0.0",
Contents.all,

Просмотреть файл

@ -16,7 +16,7 @@ namespace Contents {
@@public
export const pkg: Managed.ManagedNugetPackage =
Managed.Factory.createNugetPackge(
Managed.Factory.createNugetPackage(
"Drop.RemotableClient.Interfaces",
"0.0.0",
Contents.all,

Просмотреть файл

@ -16,7 +16,7 @@ namespace Contents {
@@public
export const pkg: Managed.ManagedNugetPackage =
Managed.Factory.createNugetPackge(
Managed.Factory.createNugetPackage(
"Drop.RemotableClient",
"0.0.0",
Contents.all,

Просмотреть файл

@ -16,7 +16,7 @@ namespace Contents {
@@public
export const pkg: Managed.ManagedNugetPackage =
Managed.Factory.createNugetPackge(
Managed.Factory.createNugetPackage(
"ItemStore.Shared",
"0.0.0",
Contents.all,

Просмотреть файл

@ -11,7 +11,7 @@ export namespace Contents {
@@public
export const pkg: Managed.ManagedNugetPackage =
Managed.Factory.createNugetPackge(
Managed.Factory.createNugetPackage(
"Microsoft.Applications.Telemetry.Desktop",
"1.1.152",
Contents.all,

Просмотреть файл

@ -16,7 +16,7 @@ namespace Contents {
@@public
export const pkg: Managed.ManagedNugetPackage =
Managed.Factory.createNugetPackge(
Managed.Factory.createNugetPackage(
"Microsoft.VisualStudio.Services.ArtifactServices.Shared",
"0.0.0",
Contents.all,

Просмотреть файл

@ -16,7 +16,7 @@ namespace Contents {
@@public
export const pkg: Managed.ManagedNugetPackage =
Managed.Factory.createNugetPackge(
Managed.Factory.createNugetPackage(
"Microsoft.VisualStudio.Services.BlobStore.Client",
"0.0.0",
Contents.all,

Просмотреть файл

@ -16,7 +16,7 @@ namespace Contents {
@@public
export const pkg: Managed.ManagedNugetPackage =
Managed.Factory.createNugetPackge(
Managed.Factory.createNugetPackage(
"Microsoft.VisualStudio.Services.InteractiveClient",
"0.0.0",
Contents.all,

Просмотреть файл

@ -8,7 +8,7 @@ export const emptyFlattenedResult : FlattenedResult = {
visitedItems: Set.empty<Object>(),
};
/**
/**
* Flattens a deployment definition into a map of relative path to file to be stored at that relative path.
* This is typically called by the specific deploy functions before doing the actualy deployment operations.
* @param definition - The definition to flatten
@ -17,7 +17,7 @@ export const emptyFlattenedResult : FlattenedResult = {
*/
@@public
export function flatten(
definition: Definition,
definition: Definition,
handleDuplicateFile?: HandleDuplicateFileDeployment,
deploymentOptions?: DeploymentOptions): FlattenedResult {
@ -45,9 +45,9 @@ export function flatten(
*/
@@public
export function flattenRecursive(
definition: Definition,
targetFolder: RelativePath,
handleDuplicateFile: HandleDuplicateFileDeployment,
definition: Definition,
targetFolder: RelativePath,
handleDuplicateFile: HandleDuplicateFileDeployment,
currentResult: FlattenedResult,
deploymentOptions: DeploymentOptions,
provenance: Diagnostics.Provenance
@ -58,7 +58,7 @@ export function flattenRecursive(
for (let item of definition.contents) {
result = flattenItem(item, targetFolder, handleDuplicateFile, result, deploymentOptions, provenance);
}
return result;
}
@ -77,7 +77,7 @@ export function getFiles(defn: Definition) : File[] {
@@public
export function extractRelativePaths(deployment: Definition): [RelativePath,File][] {
return flatten(deployment).flattenedFiles.toArray().map(kvp => <[RelativePath, File]>[kvp[0], kvp[1].file]);
}
}
function getInitialVisitedItems(deploymentOptions: DeploymentOptions) : Set<Object> {
if (deploymentOptions && deploymentOptions.excludedDeployableItems)
@ -90,12 +90,12 @@ function getInitialVisitedItems(deploymentOptions: DeploymentOptions) : Set<Obje
function flattenItem(
item: DeployableItem,
item: DeployableItem,
targetFolder: RelativePath,
handleDuplicateFile: HandleDuplicateFileDeployment,
currentResult: FlattenedResult,
handleDuplicateFile: HandleDuplicateFileDeployment,
currentResult: FlattenedResult,
deploymentOptions: DeploymentOptions,
provenance: Diagnostics.Provenance)
provenance: Diagnostics.Provenance)
: FlattenedResult {
if (item === undefined) {
@ -114,16 +114,14 @@ function flattenItem(
if (isStaticDirectory(item)) {
return flattenStaticDirectory(item, targetFolder, handleDuplicateFile, currentResult, provenance);
}
}
if (isFile(item)) {
return flattenFile(item, targetFolder.combine(item.name), handleDuplicateFile, currentResult, provenance);
}
if (isDeployable(item)) {
// TODO: TEMPORARY HACK: ['deploy'] just a little hack until I get an LKG using the NugetSpecGenerator.cs (ie, next build)
// then I can make it a mandatory attribute of Deployable and remove this indexing call
return item['deploy'](item, targetFolder, handleDuplicateFile, currentResult, deploymentOptions, provenance);
return item.deploy(item, targetFolder, handleDuplicateFile, currentResult, deploymentOptions, provenance);
}
if (isNestedDefinition(item)) {
@ -192,7 +190,7 @@ export function flattenFile(file: File, targetFile: RelativePath, handleDuplicat
Contract.fail("Invalid handleDuplicateFile handler. It must return either 'takeA', 'takeB' or fail evaluation");
}
}
return result;
} else {
return {
@ -268,16 +266,16 @@ export function createFromFilteredStaticDirectory(staticDirectory: StaticDirecto
}
function deployFilteredStaticDirectory(
item: DeployableStaticDirectoryWithFolderFilter,
item: DeployableStaticDirectoryWithFolderFilter,
targetFolder: RelativePath,
handleDuplicateFile: HandleDuplicateFileDeployment,
handleDuplicateFile: HandleDuplicateFileDeployment,
currentResult: FlattenedResult,
deploymentOptions: Object,
provenance: Diagnostics.Provenance) : FlattenedResult {
const staticDirectory = item.staticDirectory;
const folderFilter = item.folderFilter;
let result = currentResult;
for (let file of staticDirectory.getContent()) {
@ -285,16 +283,16 @@ function deployFilteredStaticDirectory(
if (file.path.isWithin(filteredRoot)) {
const targetFile = targetFolder.combine(filteredRoot.getRelative(file.path));
result = flattenFile(file, targetFile, handleDuplicateFile, result, provenance);
}
}
}
return result;
}
// Private helper functions for type discrimination
// Private helper functions for type discrimination
function isRenamedFile(item: DeployableItem) : item is RenamedFile {
return item["targetFileName"] !== undefined;
return item["targetFileName"] !== undefined;
}
function isFile(item:DeployableItem) : item is File {
@ -307,24 +305,24 @@ function isStaticDirectory(item:DeployableItem) : item is StaticDirectory {
case "FullStaticContentDirectory":
case "PartialStaticContentDirectory":
case "SourceAllDirectory":
case "SourceTopDirectory":
case "SourceTopDirectory":
case "SharedOpaqueDirectory":
case "ExclusiveOpaqueDirectory":
case "StaticDirectory":
case "ExclusiveOpaqueDirectory":
case "StaticDirectory":
return true;
default:
default:
false;
}
}
function isNestedDefinition(item:DeployableItem) : item is NestedDefinition {
return item["subfolder"] !== undefined;
return item["subfolder"] !== undefined;
}
function isDefinition(item:DeployableItem) : item is Definition {
return item["contents"] !== undefined;
return item["contents"] !== undefined;
}
function isDeployable(item:DeployableItem) : item is Deployable {
return item["deploy"] !== undefined;
return item["deploy"] !== undefined;
}

Просмотреть файл

@ -15,9 +15,9 @@ function macOSRuntimeExtensions(file: File): boolean {
}
function ignoredAssembly(file: File): boolean {
let f = file.name;
return f.equals(a`System.Security.AccessControl.dll`)
|| f.equals(a`System.Security.Principal.Windows.dll`);
// We skip deploying those files from the .NET Core package as we need those very assemblies from their dedicated package
// to compile our platform abstraction layer, which depends on datatypes present only in the dedicated packages
return file.name === a`System.Security.AccessControl.dll` || file.name === a`System.Security.Principal.Windows.dll`;
}
const windowsRuntimeFiles = [

Просмотреть файл

@ -7,7 +7,7 @@ namespace Factory {
// Factory functions are qualifier agnostic
export declare const qualifier : {};
@@public
export function createBinaryFromFiles(binary: File, pdb?: File, documentation?: File) : Binary {
return {
@ -20,8 +20,8 @@ namespace Factory {
@@public
export function createBinary(contents: StaticDirectory, binaryLocation: RelativePath | File) : Binary {
const binaryPath = typeof binaryLocation === "File"
? (<File>binaryLocation).path
const binaryPath = typeof binaryLocation === "File"
? (<File>binaryLocation).path
: p`${contents.root}/${binaryLocation}`;
const pdbPath = binaryPath.changeExtension(".pdb");
const xmlPath = binaryPath.changeExtension(".xml");
@ -50,6 +50,12 @@ namespace Factory {
@@public
export function createNugetPackge(name: string, version: string, contents: StaticDirectory, compile: Binary[], runtime: Binary[], dependencies?: NugetPackage[]) : ManagedNugetPackage {
// TODO: Delete this method once the new Nuget changes are merged and in LKG
return createNugetPackage(name, version, contents, compile, runtime, dependencies);
}
@@public
export function createNugetPackage(name: string, version: string, contents: StaticDirectory, compile: Binary[], runtime: Binary[], dependencies?: NugetPackage[]) : ManagedNugetPackage {
return <ManagedNugetPackage>{
name: name,
version: version,

Просмотреть файл

@ -17,23 +17,23 @@ namespace Tool {
...(qualifier.targetFramework === "net472" ? [
NetFx.System.Xml.dll,
NetFx.System.Xml.Linq.dll,
importFrom("System.Collections.Immutable").pkg,
importFrom("System.Reflection.Metadata").pkg,
importFrom("System.Threading.Tasks.Extensions").pkg,
importFrom("System.Threading.Tasks.Extensions").pkg
] : []),
] : []),
importFrom("Microsoft.CodeAnalysis.Common").pkg,
importFrom("Microsoft.CodeAnalysis.CSharp").pkg,
importFrom("Microsoft.CodeAnalysis.CSharp.Workspaces").pkg,
importFrom("Microsoft.CodeAnalysis.Workspaces.Common").pkg,
// CodeAnalysis packages come with .NETStandard assemblies only. Force netstandard2.0 here as .NET 4.7.2 is
// compatible and the x-plat builds need that flavor anyway
importFrom("Microsoft.CodeAnalysis.Common").withQualifier({ targetFramework: "netstandard2.0" }).pkg,
importFrom("Microsoft.CodeAnalysis.CSharp").withQualifier({ targetFramework: "netstandard2.0" }).pkg,
importFrom("Microsoft.CodeAnalysis.CSharp.Workspaces").withQualifier({ targetFramework: "netstandard2.0" }).pkg,
importFrom("Microsoft.CodeAnalysis.Workspaces.Common").withQualifier({ targetFramework: "netstandard2.0" }).pkg,
// There is a gap in our nuget integration so temporarily adding the dependencies manually
importFrom("System.Composition.AttributedModel").pkg,
importFrom("System.Composition.Convention").pkg,
importFrom("System.Composition.Hosting").pkg,
importFrom("System.Composition.Runtime").pkg,
importFrom("System.Composition.TypedParts").pkg,
importFrom("System.Composition.AttributedModel").withQualifier({ targetFramework: "netstandard1.0" }).pkg,
importFrom("System.Composition.Convention").withQualifier({ targetFramework: "netstandard1.0" }).pkg,
importFrom("System.Composition.Hosting").withQualifier({ targetFramework: "netstandard1.0" }).pkg,
importFrom("System.Composition.Runtime").withQualifier({ targetFramework: "netstandard1.0" }).pkg,
importFrom("System.Composition.TypedParts").withQualifier({ targetFramework: "netstandard1.0" }).pkg,
],
tools: {
csc: {

Просмотреть файл

@ -14,12 +14,12 @@ interface DScriptResolver extends ResolverBase {
/** Root directory where packages are stored. */
root?: Directory;
/** List of packages with respecting path where to look for this package.
/** List of packages with respecting path where to look for this package.
* Obsolete, use 'modules' instead
*/
//@@obsolete
//@@obsolete
packages?: File[];
/** List of modules with respecting path where to look for this module. */
modules?: File[];
@ -32,26 +32,26 @@ interface DScriptResolver extends ResolverBase {
*/
interface NuGetResolver extends ResolverBase {
kind: "Nuget";
/**
* Optional configuration to fix the version of nuget to use.
* When not specified the latest one will be used.
*/
configuration?: NuGetConfiguration;
/**
* The list of respositories to use to resolve. Keys are the name, values are the urls
*/
repositories?: { [name: string]: string; };
repositories?: { [name: string]: string; };
/**
* The transitive set of NuGet packages to retrieve
*/
packages?: {id: string; version: string; alias?: string; tfm?: string; dependentPackageIdsToSkip?: string[], dependentPackageIdsToIgnore?: string[]}[];
/**
packages?: {id: string; version: string; alias?: string; tfm?: string; dependentPackageIdsToSkip?: string[], dependentPackageIdsToIgnore?: string[], forceFullFrameworkQualifiersOnly?: boolean}[];
/**
* Whether to enforce that the version range specified for dependencies in a NuGet package
* match the package version specified in the configuration file.
* match the package version specified in the configuration file.
* This is enforced if not specified */
doNotEnforceDependencyVersions?: boolean;
}
@ -99,7 +99,7 @@ interface MsBuildResolver extends ResolverBase, UntrackingSettings {
kind: "MsBuild";
/**
* The enlistment root. This may not be the location where parsing should begin;
* The enlistment root. This may not be the location where parsing should begin;
* 'rootTraversal' can override that behavior.
*/
root: Directory;
@ -123,7 +123,7 @@ interface MsBuildResolver extends ResolverBase, UntrackingSettings {
*/
additionalOutputDirectories?: Directory[];
/**
/**
* Whether pips scheduled by this resolver should run in an isolated container
* For now running in a container means that outputs will always be created in unique locations
* and merged back. No merge policies are available at this point, but they will likely be available.
@ -132,7 +132,7 @@ interface MsBuildResolver extends ResolverBase, UntrackingSettings {
*/
runInContainer?: boolean;
/**
/**
* Collection of directories to search for the required MsBuild assemblies and MsBuild.exe (a.k.a. MSBuild toolset).
* If not specified, locations in %PATH% are used.
* Locations are traversed in specification order.
@ -140,14 +140,14 @@ interface MsBuildResolver extends ResolverBase, UntrackingSettings {
msBuildSearchLocations?: Directory[];
/**
* Optional file paths for the projects or solutions that should be used to start parsing. These are relative
* Optional file paths for the projects or solutions that should be used to start parsing. These are relative
* paths with respect to the root traversal.
*
* If not provided, BuildXL will attempt to find a candidate under the root traversal. If more than one candidate
* is available, the process will fail.
*/
fileNameEntryPoints?: RelativePath[];
/**
* Targets to execute on the entry point project. If not provided, the default targets are used.
* Initial targets are mapped to /target (or /t) when invoking MSBuild for the entry point project
@ -157,7 +157,7 @@ interface MsBuildResolver extends ResolverBase, UntrackingSettings {
/**
* Environment that is exposed to MSBuild. If not defined, the current process environment is exposed
* Note: if this field is not specified any change in an environment variable will potentially cause
* Note: if this field is not specified any change in an environment variable will potentially cause
* cache misses for all pips. This is because there is no way to know which variables were actually used during the build.
* Therefore, it is recommended to specify the environment explicitly.
*/
@ -199,16 +199,16 @@ interface MsBuildResolver extends ResolverBase, UntrackingSettings {
keepProjectGraphFile?: boolean;
/**
* Whether each project has implicit access to the transitive closure of its references.
* Whether each project has implicit access to the transitive closure of its references.
* Turning this option on may imply a decrease in build performance but many existing MSBuild repos rely on an equivalent feature.
* Defaults to false.
*/
enableTransitiveProjectReferences?: boolean;
/**
* When true, MSBuild projects are not treated as first class citizens and MSBuild is instructed to build each project using the legacy mode,
* When true, MSBuild projects are not treated as first class citizens and MSBuild is instructed to build each project using the legacy mode,
* which relies on SDK conventions to respect the boundaries of a project and not build dependencies. The legacy mode is less restrictive than the
* default mode, where explicit project references to represent project dependencies are strictly enforced, but a decrease in build performance and
* default mode, where explicit project references to represent project dependencies are strictly enforced, but a decrease in build performance and
* other build failures may occur (e.g. double writes due to overbuilds).
* Defaults to false.
*/
@ -226,25 +226,25 @@ interface MsBuildResolver extends ResolverBase, UntrackingSettings {
*/
interface NinjaResolver extends ResolverBase {
kind: "Ninja";
/**
* High-level targets to explore
* TODO: This probably shouldn't be the user's responsibilty
*/
* TODO: This probably shouldn't be the user's responsibilty
*/
targets?: string[];
/**
* The root of the project. This should be the directory containing the build.ninja file
* The root of the project. This should be the directory containing the build.ninja file
* (or the corresponding .ninja build file if it's named differently).
* If not present, specFile should be specified and its parent will be the projectRoot
*/
projectRoot?: Directory;
projectRoot?: Directory;
/* The build file, typically build.ninja. If null, f`${projectRoot}/build.ninja` is used */
specFile?: File;
/**
* The name of the module exposed to other DScript projects.
* The name of the module exposed to other DScript projects.
* This should be unique across modules.
*/
moduleName: string;
@ -253,7 +253,7 @@ interface NinjaResolver extends ResolverBase {
* Preserve intermediate outputs used to construct the graph,
* that is, the arguments passed to the tools and the JSON reperesentation
* of the dependency graph. Useful for debugging.
* If not present, we don't keep the outputs.
* If not present, we don't keep the outputs.
*/
keepToolFiles?: boolean;
@ -278,14 +278,14 @@ interface NinjaResolver extends ResolverBase {
*/
interface CMakeResolver extends ResolverBase {
kind: "CMake";
/**
* The root of the project. This should be the directory containing the CMakeLists.txt file
*/
projectRoot: Directory;
/**
* The name of the module exposed to other DScript projects.
* The root of the project. This should be the directory containing the CMakeLists.txt file
*/
projectRoot: Directory;
/**
* The name of the module exposed to other DScript projects.
* This should be unique across modules.
*/
moduleName: string;
@ -297,17 +297,17 @@ interface CMakeResolver extends ResolverBase {
buildDirectory: RelativePath;
/**
* When cmake is first run in an empty build tree, it creates a CMakeCache.txt file
* and populates it with customizable settings for the project.
* This option may be used to specify a setting that takes priority over the projects default value.
* When cmake is first run in an empty build tree, it creates a CMakeCache.txt file
* and populates it with customizable settings for the project.
* This option may be used to specify a setting that takes priority over the projects default value.
* [https://cmake.org/cmake/help/v3.6/manual/cmake.1.html]
*
*
* These values will be passed to the CMake generator as -D<name>=<value> arguments
* The value can be 'undefined', in which case the variable will be unset (-U<name> will be passed as an argument)
*/
cacheEntries?: { [name: string]: string; };
/**
/**
* Collection of directories to search for cmake.exe.
* If not specified, locations in %PATH% are used.
* Locations are traversed in specification order.
@ -334,8 +334,8 @@ interface ToolConfiguration {
}
interface ResolverBase {
/**
* Optional name of the resolver
/**
* Optional name of the resolver
* When provided BuildXL will give better error messages and
* allows grouping in the viewer
**/

Просмотреть файл

@ -40,7 +40,8 @@ export function withRuntimeContracts(args: Managed.Arguments, contractsLevel?: C
return args.merge<Managed.Arguments>({
defineConstants: getContractsSymbols(contractsLevel || ContractLevel.full, isDebug),
references: [
importFrom("RuntimeContracts").pkg
// Use .NETStandard as target framework, as its compatible with both .NET 4.7.2 and .NETCore
importFrom("RuntimeContracts").withQualifier({targetFramework: 'netstandard2.0'}).pkg
],
tools: {
csc: {
@ -78,7 +79,7 @@ export function getContractsSymbols(level: ContractsLevel, enableContractsQuanti
}
/** Returns analyzers dll for RuntimeContracts nuget package. */
export function getAnalyzers() : Managed.Binary[] {
export function getAnalyzers() : Managed.Binary[] {
return dlls(importFrom("RuntimeContracts.Analyzer").withQualifier({targetFramework: 'netstandard1.3'}).pkg);
}

Просмотреть файл

@ -18,7 +18,7 @@ export const pkg: Managed.ManagedNugetPackage = (() => {
case "net451":
case "net461":
case "net472":
return Managed.Factory.createNugetPackge(
return Managed.Factory.createNugetPackage(
package.name,
package.version,
package.contents,

Просмотреть файл

@ -36,7 +36,7 @@ namespace PrivatePackages {
Nuget.createAssemblyLayout(importFrom("BuildXL.Utilities").withQualifier(net472Qualifier).Native.dll),
Nuget.createAssemblyLayout(importFrom("BuildXL.Utilities").withQualifier(net472Qualifier).Storage.dll),
...importFrom("RuntimeContracts").withQualifier({ targetFramework: net472Qualifier.targetFramework }).pkg.runtime,
...importFrom("RuntimeContracts").withQualifier({ targetFramework: "netstandard2.0" }).pkg.runtime,
{
subfolder: r`content`,

Просмотреть файл

@ -21,17 +21,17 @@ namespace BuildXL.FrontEnd.Core
/// </remarks>
internal readonly struct PackageHashFile
{
// The hash file version is separated to cover the following cases:
// The hash file version is separated to cover the following cases:
// * the file format itself, and
// * the format of the generated specs.
// If the file format changes, we have to ignore the files on disk,
// buf if the file format is the same and only generated specs format has changed,
// then we can reuse files from disk and force specs regeneration.
// The file format change will force specs regeneration.
// The file format change will force specs regeneration.
// Change the version if the nuget spec generation has changed in a backward incompatible way.
private const string HashFileFormatVersion = "8";
private const string GeneratedSpecsVersion = "13";
private const string GeneratedSpecsVersion = "14";
/// <summary>
/// The minimal number of lines for the hash file.

Просмотреть файл

@ -20,9 +20,9 @@ namespace Nuget {
NetFx.System.Xml.Linq.dll
),
Sdk.dll,
Core.dll,
Script.dll,
Sdk.dll,
TypeScript.Net.dll,
importFrom("BuildXL.Cache.ContentStore").Hashing.dll,
@ -40,7 +40,7 @@ namespace Nuget {
importFrom("BuildXL.Utilities").Script.Constants.dll,
importFrom("NuGet.Versioning").pkg,
...BuildXLSdk.tplPackages,
],
internalsVisibleTo: [

Просмотреть файл

@ -42,12 +42,7 @@ namespace BuildXL.FrontEnd.Nuget
/// <summary>
/// Supported target frameworks of the package.
/// </summary>
/// <remarks>
/// For each supported framework, a set of fallback frameworks may be available. Fallback frameworks
/// are computed based on the moniker compatibility matrix specified in <see cref="Nuget.NugetFrameworkMonikers"/>
/// Fallback frameworks are a stop gap till the compatibility matrix is supported dynamically
/// </remarks>
public MultiValueDictionary<Moniker, Moniker> TargetFrameworkWithFallbacks { get; }
public List<Moniker> TargetFrameworks { get; }
/// <summary>
/// Package assembly references per framework
@ -84,10 +79,13 @@ namespace BuildXL.FrontEnd.Nuget
/// <nodoc />
public List<string> DependentPackageIdsToSkip => PackageOnDisk.Package.DependentPackageIdsToSkip ?? new List<string>() { };
/// <nodoc />
public List<string> DependentPackageIdsToIgnore => PackageOnDisk.Package.DependentPackageIdsToIgnore ?? new List<string>() { };
/// <nodoc />
public bool ForceFullFrameworkQualifiersOnly => PackageOnDisk.Package.ForceFullFrameworkQualifiersOnly;
/// <summary>
/// A compound framework is a target framework that contains '+' or '-' (e.g 'portable-net45+win8+wpa81'). This means that different
/// target framework folders can be compatible with the same known moniker (e.g. 'portable-net45+win8+wpa81' and 'net45' are both compatible with
@ -122,7 +120,7 @@ namespace BuildXL.FrontEnd.Nuget
NugetFrameworkMonikers = nugetFrameworkMonikers;
m_packagesOnConfig = packagesOnConfig;
m_doNotEnforceDependencyVersions = doNotEnforceDependencyVersions;
TargetFrameworkWithFallbacks = new MultiValueDictionary<Moniker, Moniker>();
TargetFrameworks = new List<Moniker>();
}
/// <summary>
@ -147,175 +145,15 @@ namespace BuildXL.FrontEnd.Nuget
var analyzedPackage = new NugetAnalyzedPackage(context, nugetFrameworkMonikers, nuSpec, packageOnDisk,
packagesOnConfig, doNotEnforceDependencyVersions);
analyzedPackage.ParseManagedSemantics();
if (!analyzedPackage.TryParseDependenciesFromNuSpec())
{
return null;
}
analyzedPackage.ParseManagedSemantics();
analyzedPackage.UpdateForMissingQualifierConversionFunction();
return analyzedPackage;
}
/// <summary>
/// Given a dictionary of packageID -> NugetAnalyzedPackage that is closed under dependencies (if a nuget package A depends on B, if
/// A is in the dictionary then B is in the dictionary), updates the set of supported target frameworks for each package considering its package
/// dependencies.
/// </summary>
/// <remarks>
/// The way the patch works is as follows:
/// - For a managed package, the set of supported frameworks is explicit given the package directory structure, so it is left as is
/// - For a non-managed package, the patched set of supported frameworks is the union of the supported frameworks of all its dependencies, considering
/// that all its dependencies were already patched
/// </remarks>
public static bool TryPatchSupportedTargetFrameworksForPackageExtent(NugetFrameworkMonikers nugetFrameworkMonikers, IDictionary<string, NugetAnalyzedPackage> packageExtent, out NugetFailure failure)
{
// We topo sort the list of packages, where dependents are always after their dependencies
if (!TryToposortPackages(packageExtent, out List<NugetAnalyzedPackage> sortedAnalyzedPackages, out failure))
{
return false;
}
// We traverse the list from head to tail, so when we retrieve a dependency, it is already patched
foreach (var analyzedPackage in sortedAnalyzedPackages)
{
var targetFrameworkWithFallBacks = analyzedPackage.TargetFrameworkWithFallbacks;
// If the package is managed, the qualifier space is already the right one
if (analyzedPackage.IsManagedPackage)
{
/*
* TODO:Nuget: Another workaround to make Nuget packages that are already exposing .NET Standard targets compatible to .NET Framework 452 qualifiers,
* unfortunately we have many of those in use with BuildXL already e.g. ProtocolReader. This makes coercing between .NETStandard1.1 packages and
* .NET Framework 4.5.1 work, until we have proper support built in. If we encounter more packages with different .NETStandard this would
* at least be the only place we introduce more special casing.
*/
if (targetFrameworkWithFallBacks.Count == 1)
{
if (targetFrameworkWithFallBacks.Keys.FirstOrDefault().Equals(nugetFrameworkMonikers.NetStandard10) ||
targetFrameworkWithFallBacks.Keys.FirstOrDefault().Equals(nugetFrameworkMonikers.NetStandard11))
{
targetFrameworkWithFallBacks.Add(nugetFrameworkMonikers.Net472);
targetFrameworkWithFallBacks.Add(nugetFrameworkMonikers.Net462);
targetFrameworkWithFallBacks.Add(nugetFrameworkMonikers.Net461);
targetFrameworkWithFallBacks.Add(nugetFrameworkMonikers.Net46);
targetFrameworkWithFallBacks.Add(nugetFrameworkMonikers.Net452);
targetFrameworkWithFallBacks.Add(nugetFrameworkMonikers.Net451);
targetFrameworkWithFallBacks.Add(nugetFrameworkMonikers.Net45);
}
}
continue;
}
// Otherwise, we compute the union of the qualifier spaces of its dependencies
foreach (var dependency in analyzedPackage.Dependencies)
{
Contract.Assert(packageExtent.Keys.Contains(dependency.GetPackageIdentity()));
var analyzedDependency = packageExtent[dependency.GetPackageIdentity()];
CombineTargetFrameworksForUnmanagedPackage(targetFrameworkWithFallBacks, analyzedDependency.TargetFrameworkWithFallbacks);
}
}
return true;
}
/// <summary>
/// Combines the elements of targetFrameworksToCombine into targetFrameworks. The keys of targetFrameworkToCombine are added to targetFrameworks.
/// Additionally, for each key in targetFrameworkToCombine, each of the frameworks in the list of values are added as keys as well.
/// </summary>
/// <remarks>
/// The result is a 'flattened' version of the frameworks and fallbacks, which are enough for an unmanaged package, since we are only
/// interested in computing the qualifier space, there is no libs/refs generation, for which distinct fallbacks are needed.
/// </remarks>
private static void CombineTargetFrameworksForUnmanagedPackage(
MultiValueDictionary<PathAtom, PathAtom> targetFrameworks,
MultiValueDictionary<PathAtom, PathAtom> targetFrameworksToCombine)
{
foreach (var targetFrameworkToCombine in targetFrameworksToCombine.Keys)
{
targetFrameworks.Add(targetFrameworkToCombine);
foreach (var fallbackToCombine in targetFrameworksToCombine[targetFrameworkToCombine])
{
targetFrameworks.Add(fallbackToCombine);
}
}
}
/// <summary>
/// Sorts analyzedPackages into sortedPackages such that given a package A in sortedPackages, its dependencies are always in the
/// tail of A.
/// </summary>
/// <returns>
/// Returns true if the packages were successfully sorted, and in that case failure is null. An unsuccessfull sort is always due
/// to a cycle in the package references. In that case, failure contains one package involved in the cycle.
/// TODO: Consider enhancing the failure case with information about the whole cycle, for better diagnostics
/// </returns>
private static bool TryToposortPackages(
IDictionary<string, NugetAnalyzedPackage> analyzedPackages, out List<NugetAnalyzedPackage> sortedPackages, out NugetFailure failure)
{
sortedPackages = new List<NugetAnalyzedPackage>(analyzedPackages.Count);
// All packages start as unmarked, and none as temporary marked. We loop until all packages are marked
var unmarkedPackages = new HashSet<NugetAnalyzedPackage>(analyzedPackages.Values);
var temporaryMarkedPackages = new HashSet<NugetAnalyzedPackage>();
while (unmarkedPackages.Any())
{
var aPackage = unmarkedPackages.First();
if (!TryVisit(analyzedPackages, unmarkedPackages, temporaryMarkedPackages, aPackage, sortedPackages))
{
sortedPackages = null;
failure = new NugetFailure(aPackage.PackageOnDisk.Package, NugetFailure.FailureType.CyclicPackageDependency);
return false;
}
}
failure = null;
return true;
}
/// <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;
}
private void ParseManagedSemantics()
{
var stringTable = m_context.PathTable.StringTable;
@ -374,26 +212,9 @@ namespace BuildXL.FrontEnd.Nuget
{
IsManagedPackage = true;
if (!TargetFrameworkWithFallbacks.ContainsKey(targetFramework.Moniker))
if (!TargetFrameworks.Contains(targetFramework.Moniker))
{
bool comaptibleMonikerAlreadyPresent = false;
if (NugetFrameworkMonikers.CompatibilityMatrix.ContainsKey(targetFramework.Moniker))
{
foreach (var compatibleMoniker in NugetFrameworkMonikers.CompatibilityMatrix[targetFramework.Moniker])
{
if (TargetFrameworkWithFallbacks.ContainsKey(compatibleMoniker))
{
comaptibleMonikerAlreadyPresent = true;
break;
}
}
}
if (!comaptibleMonikerAlreadyPresent)
{
// If nuspec does not specify target frameworks, we need to infer from the layout
TargetFrameworkWithFallbacks.Add(targetFramework.Moniker);
}
TargetFrameworks.Add(targetFramework.Moniker);
}
// The magic marker is there so the framework is declared as supported, but no actual files are listed
@ -407,6 +228,24 @@ namespace BuildXL.FrontEnd.Nuget
}
}
if (TargetFrameworks.Count == 0)
{
var history = ForceFullFrameworkQualifiersOnly ?
NugetFrameworkMonikers.FullFrameworkVersionHistory :
NugetFrameworkMonikers.WellknownMonikers.ToList();
// TODO: Remove this once we have a LKG with ForceFullFrameworkQualifiersOnly on spec generation
if (Id.Equals("Bond.NET"))
{
history = NugetFrameworkMonikers.FullFrameworkVersionHistory;
}
foreach (var moniker in history)
{
TargetFrameworks.Add(moniker);
}
}
// For the refs without lib, copy them to refs.
foreach (var kv in libs)
{
@ -532,44 +371,38 @@ namespace BuildXL.FrontEnd.Nuget
{
if (group.Attribute("targetFramework") != null && NugetFrameworkMonikers.TargetFrameworkNameToMoniker.TryGetValue(group.Attribute("targetFramework").Value, out Moniker targetFramework))
{
// If there is at least one valid dependency for a known framework, then the package is defined as managed
IsManagedPackage = group.Elements().Any();
TargetFrameworkWithFallbacks.Add(targetFramework);
// TODO:Nuget: Clean this up once we got end to end TFM support inside our Nuget toolchain, this is needed to not break backwards compatibility
if (string.IsNullOrEmpty(this.Tfm) &&
(targetFramework.Equals(NugetFrameworkMonikers.NetCore) ||
targetFramework.Equals(NugetFrameworkMonikers.NetStandard10) ||
targetFramework.Equals(NugetFrameworkMonikers.NetStandard11) ||
targetFramework.Equals(NugetFrameworkMonikers.NetStandard12) ||
targetFramework.Equals(NugetFrameworkMonikers.NetStandard13) ||
targetFramework.Equals(NugetFrameworkMonikers.NetStandard14) ||
targetFramework.Equals(NugetFrameworkMonikers.NetStandard15) ||
targetFramework.Equals(NugetFrameworkMonikers.NetStandard16)))
if (group.Elements().Any())
{
continue;
}
// If there is at least one valid dependency for a known framework, then the package is defined as managed
IsManagedPackage = true;
// If the package has a pinned tfm and the groups tfm does not match, skip the groups dependency resolution
if (!string.IsNullOrEmpty(this.Tfm) && NugetFrameworkMonikers.TargetFrameworkNameToMoniker.TryGetValue(this.Tfm, out Moniker pinnedTfm) && !PathAtom.Equals(pinnedTfm, targetFramework))
{
continue;
}
foreach (
var dependency in
group.Elements().Where(
el => string.Equals(el.Name.LocalName, "dependency", StringComparison.Ordinal)))
{
var grouppedDependency = ReadDependencyElement(dependency);
if (grouppedDependency == null && !(ignoreAllDependencies || ignoreIdLookupTable.Contains(dependency.Attribute("id")?.Value?.Trim())))
// Only add the group dependency target framework if the nuget package itself also contains specific assemblies of the same version
if (!TargetFrameworks.Contains(targetFramework) && (References.Keys.Any(tfm => tfm.Moniker == targetFramework) || Libraries.Keys.Any(tfm => tfm.Moniker == targetFramework)))
{
return false;
TargetFrameworks.Add(targetFramework);
}
if (grouppedDependency != null && !skipAllDependencies && !skipIdLookupTable.Contains(grouppedDependency.GetPackageIdentity()))
// If the package has a pinned tfm and the groups tfm does not match, skip the groups dependency resolution
if (!string.IsNullOrEmpty(this.Tfm) && NugetFrameworkMonikers.TargetFrameworkNameToMoniker.TryGetValue(this.Tfm, out Moniker pinnedTfm) && !PathAtom.Equals(pinnedTfm, targetFramework))
{
dependenciesPerFramework.Add(targetFramework, grouppedDependency);
continue;
}
foreach (
var dependency in
group.Elements().Where(
el => string.Equals(el.Name.LocalName, "dependency", StringComparison.Ordinal)))
{
var grouppedDependency = ReadDependencyElement(dependency);
if (grouppedDependency == null && !(ignoreAllDependencies || ignoreIdLookupTable.Contains(dependency.Attribute("id")?.Value?.Trim())))
{
return false;
}
if (grouppedDependency != null && !skipAllDependencies && !skipIdLookupTable.Contains(grouppedDependency.GetPackageIdentity()))
{
dependenciesPerFramework.Add(targetFramework, grouppedDependency);
}
}
}
}
@ -634,9 +467,9 @@ namespace BuildXL.FrontEnd.Nuget
private bool TryResolveNugetPackageVersion(
Dictionary<string, INugetPackage> packagesOnConfig,
INugetPackage requestorPackage,
string id,
string version,
bool doNotEnforceDependencyVersions,
string id,
string version,
bool doNotEnforceDependencyVersions,
out INugetPackage nugetPackage,
out string errorMessage)
{
@ -731,38 +564,5 @@ namespace BuildXL.FrontEnd.Nuget
errorMessage = string.Format(CultureInfo.InvariantCulture, "Could not parse version '{0}'.", version);
return false;
}
/// <summary>
/// DScript still lacks a compatibility function for qualifiers, so we temporary patch that here.
/// </summary>
/// <remarks>
/// We currently patch net45, net451, net452, net46, net472, netstandard2.0 and netcoreapp2.2
/// </remarks>
private void UpdateForMissingQualifierConversionFunction()
{
// Order matters as older versions get replaced by newer ones if they are marked accordingly in the compatibility matrix
UpdateForMissingQualifierConversionFunction(NugetFrameworkMonikers.Net451);
//UpdateForMissingQualifierConversionFunction(NugetFrameworkMonikers.Net452);
//UpdateForMissingQualifierConversionFunction(NugetFrameworkMonikers.Net46);
UpdateForMissingQualifierConversionFunction(NugetFrameworkMonikers.Net461);
UpdateForMissingQualifierConversionFunction(NugetFrameworkMonikers.NetStandard20);
UpdateForMissingQualifierConversionFunction(NugetFrameworkMonikers.NetCoreApp22);
UpdateForMissingQualifierConversionFunction(NugetFrameworkMonikers.Net472);
}
private void UpdateForMissingQualifierConversionFunction(Moniker moniker)
{
// Check if a compatible one is good for the TargetFrameworks
foreach (var compatibleMoniker in NugetFrameworkMonikers.CompatibilityMatrix[moniker])
{
if (TargetFrameworkWithFallbacks.ContainsKey(compatibleMoniker) && !TargetFrameworkWithFallbacks.ContainsKey(moniker))
{
// Add the framework as compatible with this package for now.
TargetFrameworkWithFallbacks.Add(compatibleMoniker, moniker);
break;
}
}
}
}
}

Просмотреть файл

@ -1,44 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Collections.Generic;
using System.Diagnostics.ContractsLight;
using System.Linq;
using BuildXL.Utilities;
namespace BuildXL.FrontEnd.Nuget
{
/// <summary>
/// Contains extension methods for <see cref="NugetAnalyzedPackage"/>.
/// </summary>
public static class NugetAnalyzedPackageExtensions
{
/// <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;
}
/// <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();
}
}
}

Просмотреть файл

@ -1,7 +1,9 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using BuildXL.Utilities;
using BuildXL.Utilities.Collections;
@ -14,7 +16,7 @@ namespace BuildXL.FrontEnd.Nuget
{
/// <nodoc />
public PathAtom Net10 { get; }
/// <nodoc />
public PathAtom Net11 { get; }
@ -75,6 +77,9 @@ namespace BuildXL.FrontEnd.Nuget
/// <nodoc />
public PathAtom NetStandard20 { get; }
/// <nodoc />
public PathAtom NetStandard21 { get; }
/// <nodoc />
public PathAtom NetCoreApp20 { get; }
@ -84,6 +89,9 @@ namespace BuildXL.FrontEnd.Nuget
/// <nodoc />
public PathAtom NetCoreApp22 { get; }
/// <nodoc />
public PathAtom NetCoreApp30 { get; }
/// <nodoc />
public PathAtom BuildFolderName { get; }
@ -96,10 +104,11 @@ namespace BuildXL.FrontEnd.Nuget
/// <nodoc />
public HashSet<PathAtom> WellknownMonikers { get; }
/// <summary>
/// Compatibility matrix. If the key is desired, the values are ordered by preference of matches
/// </summary>
public MultiValueDictionary<PathAtom, PathAtom> CompatibilityMatrix { get; }
/// <nodoc />
public readonly List<PathAtom> FullFrameworkVersionHistory;
/// <nodoc />
public readonly List<PathAtom> NetCoreVersionHistory;
/// <nodoc />
public Dictionary<string, PathAtom> TargetFrameworkNameToMoniker { get; }
@ -111,65 +120,46 @@ namespace BuildXL.FrontEnd.Nuget
RefFolderName = PathAtom.Create(stringTable, "ref");
WellknownMonikers = new HashSet<PathAtom>();
CompatibilityMatrix = new MultiValueDictionary<PathAtom, PathAtom>();
TargetFrameworkNameToMoniker = new Dictionary<string, PathAtom>();
FullFrameworkVersionHistory = new List<PathAtom>();
NetCoreVersionHistory = new List<PathAtom>();
NetStandard10 = Register(stringTable, "netstandard1.0", ".NETStandard1.0");
NetStandard11 = Register(stringTable, "netstandard1.1", ".NETStandard1.1");
NetStandard12 = Register(stringTable, "netstandard1.2", ".NETStandard1.2");
NetStandard13 = Register(stringTable, "netstandard1.3", ".NETStandard1.3");
NetStandard14 = Register(stringTable, "netstandard1.4", ".NETStandard1.4");
NetStandard15 = Register(stringTable, "netstandard1.5", ".NETStandard1.5");
NetStandard16 = Register(stringTable, "netstandard1.6", ".NETStandard1.6");
NetStandard20 = Register(stringTable, "netstandard2.0", ".NETStandard2.0");
NetStandard10 = Register(stringTable, "netstandard1.0", ".NETStandard1.0", NetCoreVersionHistory);
NetStandard11 = Register(stringTable, "netstandard1.1", ".NETStandard1.1", NetCoreVersionHistory);
NetStandard12 = Register(stringTable, "netstandard1.2", ".NETStandard1.2", NetCoreVersionHistory);
NetStandard13 = Register(stringTable, "netstandard1.3", ".NETStandard1.3", NetCoreVersionHistory);
NetStandard14 = Register(stringTable, "netstandard1.4", ".NETStandard1.4", NetCoreVersionHistory);
NetStandard15 = Register(stringTable, "netstandard1.5", ".NETStandard1.5", NetCoreVersionHistory);
NetStandard16 = Register(stringTable, "netstandard1.6", ".NETStandard1.6", NetCoreVersionHistory);
NetStandard20 = Register(stringTable, "netstandard2.0", ".NETStandard2.0", NetCoreVersionHistory);
NetCoreApp20 = Register(stringTable, "netcoreapp2.0", ".NETCoreApp2.0", NetCoreVersionHistory);
NetCoreApp21 = Register(stringTable, "netcoreapp2.1", ".NETCoreApp2.1", NetCoreVersionHistory);
NetCoreApp22 = Register(stringTable, "netcoreapp2.2", ".NETCoreApp2.2", NetCoreVersionHistory);
NetCoreApp30 = Register(stringTable, "netcoreapp3.0", ".NETCoreApp3.0", NetCoreVersionHistory);
NetStandard21 = Register(stringTable, "netstandard2.1", ".NETStandard2.1", NetCoreVersionHistory);
NetCoreApp20 = Register(stringTable, "netcoreapp2.0", ".NETCoreApp2.0");
NetCoreApp21 = Register(stringTable, "netcoreapp2.1", ".NETCoreApp2.1");
NetCoreApp22 = Register(stringTable, "netcoreapp2.2", ".NETCoreApp2.2");
Net10 = Register(stringTable, "net10", ".NETFramework1.0");
Net11 = Register(stringTable, "net11", ".NETFramework1.1");
Net20 = Register(stringTable, "net20", ".NETFramework2.0");
Net35 = Register(stringTable, "net35", ".NETFramework3.5");
Net40 = Register(stringTable, "net40", ".NETFramework4.0");
Net45 = Register(stringTable, "net45", ".NETFramework4.5");
Net451 = Register(stringTable, "net451", ".NETFramework4.5.1");
Net452 = Register(stringTable, "net452", ".NETFramework4.5.2");
Net46 = Register(stringTable, "net46", ".NETFramework4.6");
Net461 = Register(stringTable, "net461", ".NETFramework4.6.1");
Net462 = Register(stringTable, "net462", ".NETFramework4.6.2");
Net472 = Register(stringTable, "net472", ".NETFramework4.7.2");
RegisterCompatibility(Net451, Net45, Net40, Net35, Net20, NetStandard12, NetStandard11, NetStandard10, Net11, Net10);
//RegisterCompatibility(Net452, Net451, Net45, Net40, Net35);
//RegisterCompatibility(Net46, NetStandard13, NetStandard12, NetStandard11, NetStandard10, Net452, Net451, Net45, Net40, Net35);
// The fallback logic is: to use .net 4x version for .net 4.6.1
RegisterCompatibility(Net461, Net46, Net452, Net451, Net45, Net40, NetStandard20, NetStandard16, NetStandard15, NetStandard14, NetStandard13, NetStandard12, NetStandard11, NetStandard10, Net35, Net20, Net11, Net10);
RegisterCompatibility(Net472, Net461, Net46, Net452, Net451, Net45, Net40, NetStandard20, NetStandard16, NetStandard15, NetStandard14, NetStandard13, NetStandard12, NetStandard11, NetStandard10, Net35, Net20, Net11, Net10);
RegisterCompatibility(NetStandard20, NetStandard16, NetStandard15, NetStandard14, NetStandard13, NetStandard12, NetStandard11, NetStandard10);
RegisterCompatibility(NetCoreApp22, NetCoreApp21, NetCoreApp20, NetStandard20, NetStandard16, NetStandard15, NetStandard14, NetStandard13, NetStandard12, NetStandard11, NetStandard10);
Net10 = Register(stringTable, "net10", ".NETFramework1.0", FullFrameworkVersionHistory);
Net11 = Register(stringTable, "net11", ".NETFramework1.1", FullFrameworkVersionHistory);
Net20 = Register(stringTable, "net20", ".NETFramework2.0", FullFrameworkVersionHistory);
Net35 = Register(stringTable, "net35", ".NETFramework3.5", FullFrameworkVersionHistory);
Net40 = Register(stringTable, "net40", ".NETFramework4.0", FullFrameworkVersionHistory);
Net45 = Register(stringTable, "net45", ".NETFramework4.5", FullFrameworkVersionHistory);
Net451 = Register(stringTable, "net451", ".NETFramework4.5.1", FullFrameworkVersionHistory);
Net452 = Register(stringTable, "net452", ".NETFramework4.5.2", FullFrameworkVersionHistory);
Net46 = Register(stringTable, "net46", ".NETFramework4.6", FullFrameworkVersionHistory);
Net461 = Register(stringTable, "net461", ".NETFramework4.6.1", FullFrameworkVersionHistory);
Net462 = Register(stringTable, "net462", ".NETFramework4.6.2", FullFrameworkVersionHistory);
Net472 = Register(stringTable, "net472", ".NETFramework4.7.2", FullFrameworkVersionHistory);
}
private PathAtom Register(StringTable stringTable, string smallMoniker, string largeMoniker)
private PathAtom Register(StringTable stringTable, string smallMoniker, string largeMoniker, List<PathAtom> versions)
{
var pathAtom = PathAtom.Create(stringTable, smallMoniker);
TargetFrameworkNameToMoniker.Add(largeMoniker, pathAtom);
WellknownMonikers.Add(pathAtom);
versions.Add(pathAtom);
return pathAtom;
}
private void RegisterCompatibility(PathAtom moniker, params PathAtom[] compatibility)
{
if (compatibility != null && compatibility.Length > 0)
{
CompatibilityMatrix.Add(moniker, compatibility);
}
}
}
}

Просмотреть файл

@ -1,6 +1,7 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.ContractsLight;
@ -25,6 +26,8 @@ namespace BuildXL.FrontEnd.Nuget
private readonly PackageOnDisk m_packageOnDisk;
private readonly NugetAnalyzedPackage m_analyzedPackage;
private readonly NugetFrameworkMonikers m_nugetFrameworkMonikers;
private readonly PathAtom m_xmlExtension;
private readonly PathAtom m_pdbExtension;
@ -34,6 +37,7 @@ namespace BuildXL.FrontEnd.Nuget
m_pathTable = pathTable;
m_analyzedPackage = analyzedPackage;
m_packageOnDisk = analyzedPackage.PackageOnDisk;
m_nugetFrameworkMonikers = new NugetFrameworkMonikers(pathTable.StringTable);
m_xmlExtension = PathAtom.Create(pathTable.StringTable, ".xml");
m_pdbExtension = PathAtom.Create(pathTable.StringTable, ".pdb");
@ -115,68 +119,80 @@ namespace BuildXL.FrontEnd.Nuget
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.");
Contract.Assert(analyzedPackage.TargetFrameworks.Count != 0, "Managed package must have at least one target framework.");
foreach (var framework in analyzedPackage.TargetFrameworkWithFallbacks)
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 })
{
// Emit the fallback cases first:
foreach (var fallback in framework.Value)
FindAllCompatibleFrameworkMonikers(analyzedPackage, (List<PathAtom> monikers) =>
{
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)
if (monikers.Count == 0)
{
compile.Add(CreateSimpleBinary(assembly));
return;
}
}
// Runtime items
if (TryGetValueForFrameworkAndFallbacks(analyzedPackage.Libraries, new NugetTargetFramework(framework.Key), out IReadOnlyList<RelativePath> libAssemblies))
{
foreach (var assembly in libAssemblies)
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))
{
runtime.Add(CreateSimpleBinary(assembly));
foreach (var assembly in refAssemblies)
{
compile.Add(CreateSimpleBinary(assembly));
}
}
}
// Dependency items
if (analyzedPackage.DependenciesPerFramework.TryGetValue(
framework.Key,
out IReadOnlyList<INugetPackage> dependencySpecificFrameworks))
{
foreach (var dependencySpecificFramework in dependencySpecificFrameworks)
// Runtime items
if (TryGetValueForFrameworkAndFallbacks(analyzedPackage.Libraries, new NugetTargetFramework(monikers.First()), out IReadOnlyList<RelativePath> libAssemblies))
{
dependencies.Add(CreateImportFromForDependency(dependencySpecificFramework));
foreach (var assembly in libAssemblies)
{
runtime.Add(CreateSimpleBinary(assembly));
}
}
}
dependencies.AddRange(analyzedPackage.Dependencies.Select(CreateImportFromForDependency));
// 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(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)
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;
@ -192,17 +208,6 @@ namespace BuildXL.FrontEnd.Nuget
return true;
}
if (m_analyzedPackage.NugetFrameworkMonikers.CompatibilityMatrix.TryGetValue(framework.Moniker, out var compatibleFrameworks))
{
foreach (var compatibleFramework in compatibleFrameworks)
{
if (map.TryGetValue(new NugetTargetFramework(compatibleFramework), out value))
{
return true;
}
}
}
return false;
}
@ -275,13 +280,50 @@ namespace BuildXL.FrontEnd.Nuget
);
}
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>));
}
}
private bool TryCreateQualifier(NugetAnalyzedPackage analyzedPackage, out IStatement statement)
{
if (analyzedPackage.HasTargetFrameworks())
List<PathAtom> compatibleTfms = new List<PathAtom>();
FindAllCompatibleFrameworkMonikers(analyzedPackage,
(List<PathAtom> monikers) => compatibleTfms.AddRange(monikers),
m_nugetFrameworkMonikers.FullFrameworkVersionHistory,
m_nugetFrameworkMonikers.NetCoreVersionHistory);
if (compatibleTfms.Count > 0)
{
var targetFrameworks = analyzedPackage.GetTargetFrameworksInStableOrder(m_pathTable);
// { targetFramework: 'tf1' | 'tf2' }
var qualifierType = UnionType(propertyName: "targetFramework", literalTypes: targetFrameworks);
// { targetFramework: 'tf1' | 'tf2' | ... }
var qualifierType = UnionType(propertyName: "targetFramework", literalTypes: compatibleTfms.Select(m => m.ToString(m_pathTable.StringTable)).ToArray());
statement = Qualifier(qualifierType);
return true;
}

Просмотреть файл

@ -684,14 +684,6 @@ namespace BuildXL.FrontEnd.Nuget
Logger.Log.NugetRegeneratingNugetSpecs(m_context.LoggingContext);
var result = new Dictionary<string, Possible<AbsolutePath>>(analyzedPackages.Count);
if (!NugetAnalyzedPackage.TryPatchSupportedTargetFrameworksForPackageExtent(m_nugetFrameworkMonikers, analyzedPackages, out var failure))
{
// In order to not complicate the result type, in case of a failure in patching the extent, we add it as a dummy package.
// Observe the package name is not really used when there is a failure.
result.Add("__dummy__", failure);
return result;
}
var generatedSpecsCount = 0;
foreach (var analyzedPackage in analyzedPackages.Values)
{
@ -786,7 +778,7 @@ namespace BuildXL.FrontEnd.Nuget
try
{
// Sadly nuget goes all over the disk to chain configs, but when it comes to the credentials it decides not to properly merge them.
// Sadly nuget goes all over the disk to chain configs, but when it comes to the credentials it decides not to properly merge them.
// So for now we have to hack and read the credentials from the users profile and stick them in the local config....
if (FileUtilities.Exists(localNuGetConfigPath))
{

Просмотреть файл

@ -14,12 +14,12 @@ interface DScriptResolver {
/** Root directory where packages are stored. */
root?: Directory;
/** List of packages with respecting path where to look for this package.
/** List of packages with respecting path where to look for this package.
* Obsolete, use 'modules' instead
*/
//@@obsolete
//@@obsolete
packages?: File[];
/** List of modules with respecting path where to look for this module. */
modules?: File[];
@ -31,27 +31,27 @@ interface DScriptResolver {
* Custom resolver that uses NuGet for getting packages.
*/
interface NuGetResolver {
kind: "Nuget";
kind: "Nuget";
/**
* Optional configuration to fix the version of nuget to use.
* When not specified the latest one will be used.
*/
configuration?: NuGetConfiguration;
/**
* The list of respositories to use to resolve. Keys are the name, values are the urls
*/
repositories?: { [name: string]: string; };
repositories?: { [name: string]: string; };
/**
* The transitive set of NuGet packages to retrieve
*/
packages?: {id: string; version: string; alias?: string; tfm?: string; dependentPackageIdsToSkip?: string[]; dependentPackageIdsToIgnore?: string[]}[];
/**
packages?: {id: string; version: string; alias?: string; tfm?: string; dependentPackageIdsToSkip?: string[]; dependentPackageIdsToIgnore?: string[], forceFullFrameworkQualifiersOnly?: boolean}[];
/**
* Whether to enforce that the version range specified for dependencies in a NuGet package
* match the package version specified in the configuration file.
* match the package version specified in the configuration file.
* This is enforced if not specified */
doNotEnforceDependencyVersions?: boolean;
}
@ -64,7 +64,7 @@ interface MsBuildResolver {
kind: "MsBuild";
/**
* The enlistment root. This may not be the location where parsing should begin;
* The enlistment root. This may not be the location where parsing should begin;
* 'rootTraversal' can override that behavior.
*/
root: Directory;
@ -103,7 +103,7 @@ interface MsBuildResolver {
*/
untrackedDirectoryScopes?: Directory[];
/**
/**
* Whether pips scheduled by this resolver should run in an isolated container
* For now running in a container means that outputs will always be created in unique locations
* and merged back. No merge policies are available at this point, but they will likely be available.
@ -112,7 +112,7 @@ interface MsBuildResolver {
*/
runInContainer?: boolean;
/**
/**
* Collection of directories to search for the required MsBuild assemblies and MsBuild.exe (aka toolset).
* If not specified, locations in %PATH% are used.
* Locations are traversed in specification order.
@ -133,7 +133,7 @@ interface MsBuildResolver {
/**
* Environment that is exposed to MSBuild. If not defined, the current process environment is exposed
* Note: if this field is not specified any change in an environment variable will potentially cause
* Note: if this field is not specified any change in an environment variable will potentially cause
* cache misses for all pips. This is because there is no way to know which variables were actually used during the build.
* Therefore, it is recommended to specify the environment explicitly.
*/

Просмотреть файл

@ -23,16 +23,17 @@ namespace Test.BuildXL.FrontEnd.Nuget
private static readonly INugetPackage s_systemCollectionsConcurrent = new NugetPackage() { Id = "System.Collections.Concurrent", Version = "4.0.12" };
private static readonly Dictionary<string, INugetPackage> s_packagesOnConfig = new Dictionary<string, INugetPackage>
{
[s_myPackage.Id] = s_myPackage,
[s_systemCollections.Id] = s_systemCollections,
[s_systemCollectionsConcurrent.Id] = s_systemCollectionsConcurrent
};
{
[s_myPackage.Id] = s_myPackage,
[s_systemCollections.Id] = s_systemCollections,
[s_systemCollectionsConcurrent.Id] = s_systemCollectionsConcurrent
};
public NuSpecGeneratorTests(ITestOutputHelper output)
{
m_output = output;
m_context = FrontEndContext.CreateInstanceForTesting();
var monikers = new NugetFrameworkMonikers(m_context.StringTable);
m_packageGenerator = new PackageGenerator(m_context, monikers);
}
@ -40,8 +41,8 @@ namespace Test.BuildXL.FrontEnd.Nuget
[Fact]
public void GenerateNuSpec()
{
var epectedpackageRoot = "../../../pkgs/TestPkg.1.999";
var expectedpackageRoot = "../../../pkgs/TestPkg.1.999";
var pkg = m_packageGenerator.AnalyzePackage(
@"<?xml version='1.0' encoding='utf-8'?>
<package xmlns='http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd'>
@ -60,54 +61,65 @@ namespace Test.BuildXL.FrontEnd.Nuget
</dependencies>
</metadata>
</package>",
s_packagesOnConfig);
s_packagesOnConfig, new string[] { "lib/net45/my.dll", "lib/net451/my.dll"});
var spec = new NugetSpecGenerator(m_context.PathTable, pkg).CreateScriptSourceFile(pkg);
var text = spec.ToDisplayStringV2();
m_output.WriteLine(text);
string expectedSpec = string.Format(@"import {{Transformer}} from ""Sdk.Transformers"";
import * as Managed from ""Sdk.Managed"";
export declare const qualifier: {{targetFramework: ""net472"" | ""net461"" | ""net451"" | ""net45""}};
export declare const qualifier: {{targetFramework: ""net45"" | ""net451"" | ""net452"" | ""net46"" | ""net461"" | ""net462"" | ""net472""}};
const packageRoot = Contents.packageRoot;
namespace Contents {{
export declare const qualifier: {{
}};
export const packageRoot = d`{0}`;
export const packageRoot = d`../../../pkgs/TestPkg.1.999`;
@@public
export const all: StaticDirectory = Transformer.sealDirectory(packageRoot, [f`${{packageRoot}}/TestPkg.nuspec`]);
export const all: StaticDirectory = Transformer.sealDirectory(
packageRoot,
[f`${{packageRoot}}/lib/net45/my.dll`, f`${{packageRoot}}/lib/net451/my.dll`, f`${{packageRoot}}/TestPkg.nuspec`]
);
}}
@@public
export const pkg: Managed.ManagedNugetPackage = (() => {{
switch (qualifier.targetFramework) {{
case ""net45"":
return Managed.Factory.createNugetPackge(
return Managed.Factory.createNugetPackage(
""TestPkg"",
""1.999"",
Contents.all,
[],
[],
[importFrom(""System.Collections"").pkg, importFrom(""System.Collections.Concurrent"").pkg]
[Managed.Factory.createBinaryFromFiles(f`${{packageRoot}}/lib/net45/my.dll`)],
[Managed.Factory.createBinaryFromFiles(f`${{packageRoot}}/lib/net45/my.dll`)],
[
...addIfLazy(qualifier.targetFramework === ""net45"", () => [importFrom(""System.Collections"").pkg, importFrom(""System.Collections.Concurrent"").pkg]),
]
);
case ""net461"":
case ""net472"":
case ""net451"":
return Managed.Factory.createNugetPackge(
case ""net452"":
case ""net46"":
case ""net461"":
case ""net462"":
case ""net472"":
return Managed.Factory.createNugetPackage(
""TestPkg"",
""1.999"",
Contents.all,
[],
[],
[importFrom(""System.Collections"").pkg, importFrom(""System.Collections.Concurrent"").pkg]
[Managed.Factory.createBinaryFromFiles(f`${{packageRoot}}/lib/net451/my.dll`)],
[Managed.Factory.createBinaryFromFiles(f`${{packageRoot}}/lib/net451/my.dll`)],
[
...addIfLazy(qualifier.targetFramework === ""net451"", () => [importFrom(""System.Collections"").pkg, importFrom(""System.Collections.Concurrent"").pkg]),
]
);
default:
Contract.fail(""Unsupported target framework"");
}};
}}
)();", epectedpackageRoot);
)();", expectedpackageRoot);
Assert.Equal(expectedSpec, text);
}
}

Просмотреть файл

@ -170,7 +170,7 @@ namespace Test.BuildXL.FrontEnd.Nuget
Assert.Equal(packageRelativePath, pkg.Libraries[new NugetTargetFramework(m_monikers.Net45)].First().ToString(m_context.StringTable));
}
[Fact(Skip = "Assumptions no longer correct with current Nuget workarounds for .NET Core")]
[Fact]
public void TestManagedDependenciesImpliesAManagedPackage()
{
var pkg = AnalyzePackage(
@ -194,10 +194,8 @@ namespace Test.BuildXL.FrontEnd.Nuget
s_packagesOnConfig);
Assert.True(pkg.IsManagedPackage);
Assert.True(pkg.TargetFrameworkWithFallbacks.ContainsKey(m_monikers.Net45));
// TODO:Nuget: Add this back once we don't use a hack to collapse 4.5.1 dependencies to use 4.5 entries and thus enable .NET Core
// Assert.True(pkg.TargetFrameworkWithFallbacks.ContainsKey(m_monikers.Net451));
Assert.True(pkg.TargetFrameworks.Contains(m_monikers.Net45));
Assert.True(pkg.TargetFrameworks.Contains(m_monikers.Net451));
}
private NugetAnalyzedPackage AnalyzePackage(string xml, Dictionary<string, INugetPackage> packagesOnConfig, params string[] relativePaths)

Просмотреть файл

@ -1,20 +1,48 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Collections.Generic;
using System.Linq;
using BuildXL.Utilities;
using BuildXL.Utilities.Configuration;
using BuildXL.Utilities.Configuration.Mutable;
using BuildXL.FrontEnd.Nuget;
using BuildXL.FrontEnd.Sdk;
using Xunit;
namespace Test.BuildXL.FrontEnd.Nuget
{
public class NugetFrameworkMonikersTest
{
private readonly FrontEndContext m_context;
private readonly NugetFrameworkMonikers m_monikers;
private readonly PackageGenerator m_packageGenerator;
private static readonly INugetPackage s_myPackage = new NugetPackage() { Id = "MyPkg", Version = "1.99" };
private static readonly INugetPackage s_systemCollections = new NugetPackage() { Id = "System.Collections", Version = "4.0.11" };
private static readonly INugetPackage s_systemCollectionsConcurrent = new NugetPackage() { Id = "System.Collections.Concurrent", Version = "4.0.12" };
private static readonly Dictionary<string, INugetPackage> s_packagesOnConfig = new Dictionary<string, INugetPackage>
{
[s_myPackage.Id] = s_myPackage,
[s_systemCollections.Id] = s_systemCollections,
[s_systemCollectionsConcurrent.Id] = s_systemCollectionsConcurrent
};
public NugetFrameworkMonikersTest()
{
m_context = FrontEndContext.CreateInstanceForTesting();
m_monikers = new NugetFrameworkMonikers(m_context.StringTable);
m_packageGenerator = new PackageGenerator(m_context, m_monikers);
}
[Fact]
public void TestNuget451()
{
// Perform a random sample for .net 452 things. Otherwise there are too many combinations.
// This just guarantees a basic functionality of the Register function.
// Perform a random sample for some target framework moniker scenarios. Otherwise there are too many combinations.
// This just guarantees a basic functionality of the moniker management and spec generator functionality.
var stringTable = new PathTable().StringTable;
var monikers = new NugetFrameworkMonikers(stringTable);
@ -25,10 +53,34 @@ namespace Test.BuildXL.FrontEnd.Nuget
// Is well known
Assert.True(monikers.WellknownMonikers.Contains(monikers.Net451));
// 4.5.1 is compatible with 4.5
Assert.True(monikers.CompatibilityMatrix.ContainsKey(monikers.Net451));
Assert.True(monikers.CompatibilityMatrix[monikers.Net451].Contains(monikers.Net45));
// 4.5 is compatible with 4.5.1 and newer monikers, not older ones!
var analyzedPackage = m_packageGenerator.AnalyzePackage(
@"<?xml version='1.0' encoding='utf-8'?>
<package xmlns='http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd'>
<metadata>
<id>MyPkg</id>
<version>1.999</version>
<dependencies>
<group targetFramework='.NETFramework4.5'>
<dependency id='System.Collections' version='4.0.11' />
<dependency id='System.Collections.Concurrent' version='4.0.12' />
</group>
</dependencies>
</metadata>
</package>", s_packagesOnConfig, new string[] { "lib/net45/my.dll" });
List<PathAtom> compatibleTfms = new List<PathAtom>();
NugetSpecGenerator.FindAllCompatibleFrameworkMonikers(analyzedPackage,
(List<PathAtom> m) => compatibleTfms.AddRange(m),
m_monikers.FullFrameworkVersionHistory,
m_monikers.NetCoreVersionHistory);
Assert.False(compatibleTfms.Contains(m_monikers.Net40));
Assert.True(compatibleTfms.Contains(m_monikers.Net45));
Assert.True(compatibleTfms.Contains(m_monikers.Net451));
Assert.True(compatibleTfms.Contains(m_monikers.Net472));
// Mapping tests
Assert.Equal(monikers.Net451, monikers.TargetFrameworkNameToMoniker[".NETFramework4.5.1"]);
}
}

Просмотреть файл

@ -23,7 +23,7 @@ namespace Script.TestBase {
importFrom("BuildXL.Utilities").Configuration.dll,
importFrom("BuildXL.Utilities.UnitTests").TestUtilities.dll,
importFrom("BuildXL.Utilities.UnitTests").TestUtilities.XUnit.dll,
importFrom("xunit.abstractions").pkg,
importFrom("xunit.abstractions").withQualifier({targetFramework: "netstandard2.0"}).pkg,
],
runtimeContent: [
{

Просмотреть файл

@ -41,6 +41,11 @@ namespace BuildXL.Utilities.Configuration
/// Optional dependent Nuget packages to skip when resolving dependencies, a list of Nuget package Ids
/// </summary>
List<string> DependentPackageIdsToIgnore { get; }
/// <summary>
/// Optional flag to force package spec generation to use full framework qualifiers only
/// </summary>
bool ForceFullFrameworkQualifiersOnly { get; }
}
/// <nodoc/>
@ -53,7 +58,6 @@ namespace BuildXL.Utilities.Configuration
public static string GetPackageIdentity(this INugetPackage nugetPackage)
{
Contract.Requires(!string.IsNullOrEmpty(nugetPackage.Id), "Every package should have an ID");
return !string.IsNullOrEmpty(nugetPackage.Alias) ? nugetPackage.Alias : nugetPackage.Id;
}
}

Просмотреть файл

@ -22,6 +22,7 @@ namespace BuildXL.Utilities.Configuration.Mutable
Tfm = template.Tfm;
DependentPackageIdsToSkip = template.DependentPackageIdsToSkip ?? new List<string>() { };
DependentPackageIdsToIgnore = template.DependentPackageIdsToIgnore ?? new List<string>() { };
ForceFullFrameworkQualifiersOnly = template.ForceFullFrameworkQualifiersOnly;
}
/// <inheritdoc />
@ -41,5 +42,8 @@ namespace BuildXL.Utilities.Configuration.Mutable
/// <inheritdoc />
public List<string> DependentPackageIdsToIgnore { get; private set; }
/// <inheritdoc />
public bool ForceFullFrameworkQualifiersOnly { get; private set; } = false;
}
}

Просмотреть файл

@ -20,8 +20,8 @@ namespace LogGen {
importFrom("BuildXL.Utilities").dll,
importFrom("BuildXL.Utilities").ToolSupport.dll,
importFrom("BuildXL.Utilities").CodeGenerationHelper.dll,
importFrom("Microsoft.CodeAnalysis.CSharp").pkg,
importFrom("Microsoft.CodeAnalysis.Common").pkg,
importFrom("Microsoft.CodeAnalysis.CSharp").withQualifier({ targetFramework: "netstandard2.0" }).pkg,
importFrom("Microsoft.CodeAnalysis.Common").withQualifier({ targetFramework: "netstandard2.0" }).pkg,
],
});

Просмотреть файл

@ -17,7 +17,7 @@ if NOT DEFINED DBD_TESTGEN_COUNT (
)
if NOT DEFINED TEST_COMMITID (
set TEST_COMMITID=f3d10884ab3498d83e7db7d95f50c8040f4142d5
set TEST_COMMITID=3a5fdc81d4d87a67fd519eb8dfd963e355139dcf
)
set TEST_SOLUTION_ROOT=%ENLISTMENTROOT%\Out\Tests\SMDB

Просмотреть файл

@ -142,7 +142,7 @@ config({
// RocksDb
{ id: "RocksDbSharp", version: "5.8.0-b20181023.3", alias: "RocksDbSharpSigned" },
{ id: "RocksDbNative", version: "6.0.1-b20190426.4" },
{ id: "JsonDiffPatch.Net", version: "2.1.0" },
// Event hubs
@ -169,7 +169,6 @@ config({
{ id: "Microsoft.Data.Edm", version: "5.8.2" },
// xUnit
{ id: "xunit", version: "2.4.1" },
{ id: "xunit.abstractions", version: "2.0.3", tfm: ".NETStandard2.0" },
{ id: "xunit.analyzers", version: "0.10.0" },
{ id: "xunit.assert", version: "2.4.1" },