Skip to content

Commit

Permalink
Allow netstandard to install contentFiles under the any tfm
Browse files Browse the repository at this point in the history
By default ContentModel translates 'any' to 'dotnet', this works for the lib folder but for scenarios such as contentFiles any does refer to all frameworks. This change updates contentModel to allow per pattern token replacement tables.

Fixes NuGet/Home#3118
  • Loading branch information
emgarten committed Jul 15, 2016
1 parent d4c1fcb commit 080e692
Show file tree
Hide file tree
Showing 11 changed files with 632 additions and 135 deletions.
172 changes: 108 additions & 64 deletions src/NuGet.Core/NuGet.Client/ManagedCodeConventions.cs
Expand Up @@ -17,23 +17,14 @@ namespace NuGet.Client
/// </summary>
public class ManagedCodeConventions
{
private static readonly ContentPropertyDefinition TfmProperty = new ContentPropertyDefinition(PropertyNames.TargetFrameworkMoniker,
table: new Dictionary<string, object>()
{
{ "any", FrameworkConstants.CommonFrameworks.DotNet }
},
parser: TargetFrameworkName_Parser,
compatibilityTest: TargetFrameworkName_CompatibilityTest,
compareTest: TargetFrameworkName_NearestCompareTest);

private static readonly ContentPropertyDefinition LocaleProperty = new ContentPropertyDefinition(PropertyNames.Locale,
parser: Locale_Parser);

private static readonly ContentPropertyDefinition AnyProperty = new ContentPropertyDefinition(
PropertyNames.AnyValue,
parser: o => o); // Identity parser, all strings are valid for any
parser: (o, t) => o); // Identity parser, all strings are valid for any
private static readonly ContentPropertyDefinition AssemblyProperty = new ContentPropertyDefinition(PropertyNames.ManagedAssembly,
parser: o => o.Equals(PackagingCoreConstants.EmptyFolder, StringComparison.Ordinal) ? o : null, // Accept "_._" as a pseudo-assembly
parser: (o, t) => o.Equals(PackagingCoreConstants.EmptyFolder, StringComparison.Ordinal) ? o : null, // Accept "_._" as a pseudo-assembly
fileExtensions: new[] { ".dll", ".winmd", ".exe" });
private static readonly ContentPropertyDefinition MSBuildProperty = new ContentPropertyDefinition(PropertyNames.MSBuild, fileExtensions: new[] { ".targets", ".props" });
private static readonly ContentPropertyDefinition SatelliteAssemblyProperty = new ContentPropertyDefinition(PropertyNames.SatelliteAssembly, fileExtensions: new[] { ".resources.dll" });
Expand All @@ -42,6 +33,19 @@ public class ManagedCodeConventions
PropertyNames.CodeLanguage,
parser: CodeLanguage_Parser);

private static readonly Dictionary<string, object> DefaultTfmAny = new Dictionary<string, object>
{
{ PropertyNames.TargetFrameworkMoniker, AnyFramework.Instance }
};

private static readonly PatternTable DotnetAnyTable = new PatternTable(new[]
{
new PatternTableEntry(
PropertyNames.TargetFrameworkMoniker,
"any",
FrameworkConstants.CommonFrameworks.DotNet)
});

private RuntimeGraph _runtimeGraph;

public ManagedCodeCriteria Criteria { get; }
Expand All @@ -53,7 +57,6 @@ public ManagedCodeConventions(RuntimeGraph runtimeGraph)
_runtimeGraph = runtimeGraph;

var props = new Dictionary<string, ContentPropertyDefinition>();
props[TfmProperty.Name] = TfmProperty;
props[AnyProperty.Name] = AnyProperty;
props[AssemblyProperty.Name] = AssemblyProperty;
props[LocaleProperty.Name] = LocaleProperty;
Expand All @@ -63,9 +66,15 @@ public ManagedCodeConventions(RuntimeGraph runtimeGraph)

props[PropertyNames.RuntimeIdentifier] = new ContentPropertyDefinition(
PropertyNames.RuntimeIdentifier,
parser: o => o, // Identity parser, all strings are valid runtime ids :)
parser: (o, t) => o, // Identity parser, all strings are valid runtime ids :)
compatibilityTest: RuntimeIdentifier_CompatibilityTest);

props[PropertyNames.TargetFrameworkMoniker] = new ContentPropertyDefinition(
PropertyNames.TargetFrameworkMoniker,
parser: TargetFrameworkName_Parser,
compatibilityTest: TargetFrameworkName_CompatibilityTest,
compareTest: TargetFrameworkName_NearestCompareTest);

Properties = new ReadOnlyDictionary<string, ContentPropertyDefinition>(props);

Criteria = new ManagedCodeCriteria(this);
Expand All @@ -92,14 +101,32 @@ private bool RuntimeIdentifier_CompatibilityTest(object criteria, object availab
}
}

private static object CodeLanguage_Parser(string name)
private static object CodeLanguage_Parser(string name, PatternTable table)
{
if (table != null)
{
object val;
if (table.TryLookup(PropertyNames.CodeLanguage, name, out val))
{
return val;
}
}

// Code language values must be alpha numeric.
return name.All(c => char.IsLetterOrDigit(c)) ? name : null;
}

private static object Locale_Parser(string name)
private static object Locale_Parser(string name, PatternTable table)
{
if (table != null)
{
object val;
if (table.TryLookup(PropertyNames.Locale, name, out val))
{
return val;
}
}

if (name.Length == 2)
{
return name;
Expand All @@ -112,16 +139,44 @@ private static object Locale_Parser(string name)
return null;
}

private static object TargetFrameworkName_Parser(string name)
private static object TargetFrameworkName_Parser(
string name,
PatternTable table)
{
var result = NuGetFramework.Parse(name);
object obj = null;

// Check for replacements
if (table != null)
{
if (table.TryLookup(PropertyNames.TargetFrameworkMoniker, name, out obj))
{
return obj;
}
}

return TargetFrameworkName_ParserCore(name);
}

private static NuGetFramework TargetFrameworkName_ParserCore(string name)
{
var result = NuGetFramework.ParseFolder(name);

if (!result.IsUnsupported)
{
return result;
}

return new NuGetFramework(name, new Version(0, 0));
// Everything should be in the folder format, but fallback to
// full parsing for legacy support.
result = NuGetFramework.ParseFrameworkName(name, DefaultFrameworkNameProvider.Instance);

if (!result.IsUnsupported)
{
return result;
}

// For unknown frameworks return the name as is.
return new NuGetFramework(name, FrameworkConstants.EmptyVersion);
}

private static bool TargetFrameworkName_CompatibilityTest(object criteria, object available)
Expand Down Expand Up @@ -290,107 +345,96 @@ internal ManagedCodePatterns(ManagedCodeConventions conventions)
conventions.Properties,
groupPatterns: new PatternDefinition[]
{
"{any}/{tfm}/{any?}",
"runtimes/{rid}/{any}/{tfm}/{any?}",
new PatternDefinition("{any}/{tfm}/{any?}", table: DotnetAnyTable),
new PatternDefinition("runtimes/{rid}/{any}/{tfm}/{any?}", table: DotnetAnyTable),
},
pathPatterns: new PatternDefinition[]
{
"{any}/{tfm}/{any?}",
"runtimes/{rid}/{any}/{tfm}/{any?}",
new PatternDefinition("{any}/{tfm}/{any?}", table: DotnetAnyTable),
new PatternDefinition("runtimes/{rid}/{any}/{tfm}/{any?}", table: DotnetAnyTable),
});

RuntimeAssemblies = new PatternSet(
conventions.Properties,
groupPatterns: new PatternDefinition[]
{
"runtimes/{rid}/lib/{tfm}/{any?}",
"lib/{tfm}/{any?}",
new PatternDefinition("lib/{assembly?}", defaults: new Dictionary<string, object>
{
{ "tfm", new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.Net, FrameworkConstants.EmptyVersion) }
})
},
new PatternDefinition("runtimes/{rid}/lib/{tfm}/{any?}", table: DotnetAnyTable),
new PatternDefinition("lib/{tfm}/{any?}", table: DotnetAnyTable),
new PatternDefinition("lib/{assembly?}", table: DotnetAnyTable,
defaults: new Dictionary<string, object>
{
{ "tfm", new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.Net, FrameworkConstants.EmptyVersion) }
})
},
pathPatterns: new PatternDefinition[]
{
"runtimes/{rid}/lib/{tfm}/{assembly}",
"lib/{tfm}/{assembly}",
new PatternDefinition("lib/{assembly}", defaults: new Dictionary<string, object>
{
{ "tfm", new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.Net, FrameworkConstants.EmptyVersion) }
})
});
new PatternDefinition("runtimes/{rid}/lib/{tfm}/{assembly}", table: DotnetAnyTable),
new PatternDefinition("lib/{tfm}/{assembly}", table: DotnetAnyTable),
new PatternDefinition("lib/{assembly}", table: DotnetAnyTable, defaults: new Dictionary<string, object>
{
{ "tfm", new NuGetFramework(FrameworkConstants.FrameworkIdentifiers.Net, FrameworkConstants.EmptyVersion) }
})
});

CompileAssemblies = new PatternSet(
conventions.Properties,
groupPatterns: new PatternDefinition[]
{
"ref/{tfm}/{any?}",
new PatternDefinition("ref/{tfm}/{any?}", table: DotnetAnyTable),
},
pathPatterns: new PatternDefinition[]
{
"ref/{tfm}/{assembly}",
new PatternDefinition("ref/{tfm}/{assembly}", table: DotnetAnyTable),
});

NativeLibraries = new PatternSet(
conventions.Properties,
groupPatterns: new PatternDefinition[]
{
"runtimes/{rid}/nativeassets/{tfm}/{any?}",
new PatternDefinition("runtimes/{rid}/native/{any?}", defaults: new Dictionary<string, object>
{
{ "tfm", AnyFramework.Instance }
})
new PatternDefinition("runtimes/{rid}/nativeassets/{tfm}/{any?}", table: DotnetAnyTable),
new PatternDefinition("runtimes/{rid}/native/{any?}", table: null, defaults: DefaultTfmAny)
},
pathPatterns: new PatternDefinition[]
{
"runtimes/{rid}/nativeassets/{tfm}/{any}",
new PatternDefinition("runtimes/{rid}/native/{any}", defaults: new Dictionary<string, object>
{
{ "tfm", AnyFramework.Instance }
})
new PatternDefinition("runtimes/{rid}/nativeassets/{tfm}/{any}", table: DotnetAnyTable),
new PatternDefinition("runtimes/{rid}/native/{any}", table: null, defaults: DefaultTfmAny)
});

ResourceAssemblies = new PatternSet(
conventions.Properties,
groupPatterns: new PatternDefinition[]
{
"runtimes/{rid}/lib/{tfm}/{locale?}/{any?}",
"lib/{tfm}/{locale?}/{any?}"
new PatternDefinition("runtimes/{rid}/lib/{tfm}/{locale?}/{any?}", table: DotnetAnyTable),
new PatternDefinition("lib/{tfm}/{locale?}/{any?}", table: DotnetAnyTable),
},
pathPatterns: new PatternDefinition[]
{
"runtimes/{rid}/lib/{tfm}/{locale}/{satelliteAssembly}",
"lib/{tfm}/{locale}/{satelliteAssembly}"
new PatternDefinition("runtimes/{rid}/lib/{tfm}/{locale}/{satelliteAssembly}", table: DotnetAnyTable),
new PatternDefinition("lib/{tfm}/{locale}/{satelliteAssembly}", table: DotnetAnyTable),
});

MSBuildFiles = new PatternSet(
conventions.Properties,
groupPatterns: new PatternDefinition[]
{
"build/{tfm}/{msbuild?}",
new PatternDefinition("build/{msbuild?}", defaults: new Dictionary<string, object>
{
{ "tfm", AnyFramework.Instance }
})
new PatternDefinition("build/{tfm}/{msbuild?}", table: DotnetAnyTable),
new PatternDefinition("build/{msbuild?}", table: null, defaults: DefaultTfmAny)
},
pathPatterns: new PatternDefinition[]
{
"build/{tfm}/{msbuild}",
new PatternDefinition("build/{msbuild}", defaults: new Dictionary<string, object>
{
{ "tfm", AnyFramework.Instance }
})
new PatternDefinition("build/{tfm}/{msbuild}", table: DotnetAnyTable),
new PatternDefinition("build/{msbuild}", table: null, defaults: DefaultTfmAny)
});

ContentFiles = new PatternSet(
conventions.Properties,
groupPatterns: new PatternDefinition[]
{
"contentFiles/{codeLanguage}/{tfm}/{any?}"
new PatternDefinition("contentFiles/{codeLanguage}/{tfm}/{any?}"),
},
pathPatterns: new PatternDefinition[]
{
"contentFiles/{codeLanguage}/{tfm}/{any?}"
new PatternDefinition("contentFiles/{codeLanguage}/{tfm}/{any?}"),
});
}
}
Expand Down

0 comments on commit 080e692

Please sign in to comment.