Remove ProjectJson solution and its tests
It is moved to cli-migration repo
This commit is contained in:
parent
b6a2c01cf6
commit
093bf72c3c
237 changed files with 92 additions and 29475 deletions
src/Microsoft.DotNet.ProjectJsonMigration
ConstantPackageVersions.csDefaultMigrationRuleSet.csDotnetSupportedPackageVersionsCsvProvider.csIDotnetSupportedPackageVersionsProvider.csLocalizableStrings.csMSBuildExtensions.cs
Microsoft.DotNet.Internal.ProjectModel
AnalyzerOptions.csBuildWorkspace.csCommonCompilerOptions.cs
Compilation
AnalyzerAssembly.csLibraryAsset.csLibraryAssetExtension.csLibraryAssetGroup.csLibraryExport.csLibraryExportBuilder.csLibraryExporter.csLibraryResourceAssembly.cs
CompilationOutputFiles.csConstants.csDependencyContextBuilder.csDesignTimeWorkspace.csDiagnosticMessage.csDiagnosticMessageSeverity.csDirectoryNames.csEnvironmentNames.csErrorCodes.DotNet.csErrorCodes.NuGet.csFileFormatException.csFileNameSuffixes.csPreprocessor
FileSystemGlobbing
Abstractions
FilePatternMatch.csInternal
ILinearPattern.csIPathSegment.csIPattern.csIPatternContext.csIRaggedPattern.csMatcherContext.cs
Matcher.csMatcherExtensions.csPatternMatchingResult.csPathSegments
CurrentPathSegment.csLiteralPathSegment.csParentPathSegment.csRecursiveWildcardSegment.csWildcardPathSegment.cs
PatternContexts
PatternContext.csPatternContextLinear.csPatternContextLinearExclude.csPatternContextLinearInclude.csPatternContextRagged.csPatternContextRaggedExclude.csPatternContextRaggedInclude.cs
PatternTestResult.csPatterns
Util
Files
ExcludeContext.csIncludeContext.csIncludeEntry.csIncludeFilesResolver.csNamedResourceReader.csPackIncludeEntry.csPatternGroup.csPatternsCollectionHelper.csProjectFilesCollection.cs
GlobalSettings.csGraph
IProjectReader.csInternal
LibraryDescription.csMSBuildProjectDescription.csOutputPaths.csOutputPathsCalculator.csPackOptions.csPackageDescription.csProject.csProjectContext.csProjectContextBuilder.csProjectContextCollection.csProjectContextIdentity.csProjectDescription.csProjectExtensions.csProjectFileDependencyGroup.csProjectModelPlatformExtensions.csProjectPathHelper.csProjectReader.csProjectReaderSettings.csProjectRootResolver.csResolution
|
@ -1,19 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.ProjectJsonMigration
|
|
||||||
{
|
|
||||||
internal class ConstantPackageVersions
|
|
||||||
{
|
|
||||||
public const string AspNetToolsVersion = "1.0.0";
|
|
||||||
public const string AspNet110ToolsVersion = "1.1.0";
|
|
||||||
public const string AspNetLTSPackagesVersion = "1.0.3";
|
|
||||||
public const string EntityFrameworkLTSPackagesVersion = "1.0.3";
|
|
||||||
public const string TestSdkPackageVersion = "15.0.0-preview-20170106-08";
|
|
||||||
public const string XUnitPackageVersion = "2.2.0-beta5-build3474";
|
|
||||||
public const string XUnitRunnerPackageVersion = "2.2.0-beta5-build1225";
|
|
||||||
public const string MstestTestAdapterVersion = "1.1.8-rc";
|
|
||||||
public const string MstestTestFrameworkVersion = "1.0.8-rc";
|
|
||||||
public const string BundleMinifierToolVersion = "2.2.301";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using Microsoft.DotNet.ProjectJsonMigration.Rules;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.ProjectJsonMigration
|
|
||||||
{
|
|
||||||
internal class DefaultMigrationRuleSet : IMigrationRule
|
|
||||||
{
|
|
||||||
private IMigrationRule[] Rules => new IMigrationRule[]
|
|
||||||
{
|
|
||||||
new AddDefaultsToProjectRule(),
|
|
||||||
new MigrateRootOptionsRule(),
|
|
||||||
new MigrateTFMRule(),
|
|
||||||
new MigrateBuildOptionsRule(),
|
|
||||||
new MigrateJsonPropertiesRule(),
|
|
||||||
new MigratePackOptionsRule(),
|
|
||||||
new MigrateRuntimeOptionsRule(),
|
|
||||||
new MigrateRuntimesRule(),
|
|
||||||
new MigratePublishOptionsRule(),
|
|
||||||
new MigrateProjectDependenciesRule(),
|
|
||||||
new MigratePackageDependenciesAndToolsRule(),
|
|
||||||
new MigrateConfigurationsRule(),
|
|
||||||
new MigrateScriptsRule(),
|
|
||||||
new MigrateAssemblyInfoRule(),
|
|
||||||
new RemoveDefaultsFromProjectRule(),
|
|
||||||
new CleanOutputProjectRule(),
|
|
||||||
new SaveOutputProjectRule(),
|
|
||||||
new MigrateWebSdkRule()
|
|
||||||
};
|
|
||||||
|
|
||||||
public void Apply(MigrationSettings migrationSettings, MigrationRuleInputs migrationRuleInputs)
|
|
||||||
{
|
|
||||||
foreach (var rule in Rules)
|
|
||||||
{
|
|
||||||
MigrationTrace.Instance.WriteLine(string.Format(LocalizableStrings.ExecutingMigrationRule, nameof(DefaultMigrationRuleSet), rule.GetType().Name));
|
|
||||||
rule.Apply(migrationSettings, migrationRuleInputs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,72 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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.IO;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.ProjectJsonMigration
|
|
||||||
{
|
|
||||||
internal class DotnetSupportedPackageVersionsCsvProvider : IDotnetSupportedPackageVersionsProvider
|
|
||||||
{
|
|
||||||
public void AddDotnetSupportedPackageVersions(
|
|
||||||
IDictionary<PackageDependencyInfo, PackageDependencyInfo> projectDependenciesPackages)
|
|
||||||
{
|
|
||||||
var dotnetSupportedPackageVersionsPath =
|
|
||||||
Path.Combine(AppContext.BaseDirectory, "dotnet-supported-package-versions.csv");
|
|
||||||
using (var reader = new StreamReader(File.OpenRead(dotnetSupportedPackageVersionsPath)))
|
|
||||||
{
|
|
||||||
SkipHeader(reader);
|
|
||||||
while (!reader.EndOfStream)
|
|
||||||
{
|
|
||||||
var line = reader.ReadLine();
|
|
||||||
var values = line.Split(',');
|
|
||||||
var packageName = values[0];
|
|
||||||
var ltsVersion = values[1];
|
|
||||||
var ftsVersion = values[2];
|
|
||||||
|
|
||||||
if (HasVersion(ltsVersion))
|
|
||||||
{
|
|
||||||
projectDependenciesPackages.Add(
|
|
||||||
new PackageDependencyInfo
|
|
||||||
{
|
|
||||||
Name = packageName,
|
|
||||||
Version = $"[,{ltsVersion})"
|
|
||||||
},
|
|
||||||
new PackageDependencyInfo
|
|
||||||
{
|
|
||||||
Name = packageName,
|
|
||||||
Version = ltsVersion
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if(HasVersion(ftsVersion))
|
|
||||||
{
|
|
||||||
var version = HasVersion(ltsVersion) ? $"({ltsVersion},{ftsVersion})" : $"[,{ftsVersion})";
|
|
||||||
projectDependenciesPackages.Add(
|
|
||||||
new PackageDependencyInfo
|
|
||||||
{
|
|
||||||
Name = packageName,
|
|
||||||
Version = version
|
|
||||||
},
|
|
||||||
new PackageDependencyInfo
|
|
||||||
{
|
|
||||||
Name = packageName,
|
|
||||||
Version = ftsVersion
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SkipHeader(StreamReader reader)
|
|
||||||
{
|
|
||||||
reader.ReadLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool HasVersion(string version)
|
|
||||||
{
|
|
||||||
return !string.IsNullOrEmpty(version);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.ProjectJsonMigration
|
|
||||||
{
|
|
||||||
internal interface IDotnetSupportedPackageVersionsProvider
|
|
||||||
{
|
|
||||||
void AddDotnetSupportedPackageVersions(
|
|
||||||
IDictionary<PackageDependencyInfo, PackageDependencyInfo> projectDependenciesPackages);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,130 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.ProjectJsonMigration
|
|
||||||
{
|
|
||||||
internal class LocalizableStrings
|
|
||||||
{
|
|
||||||
public const string DoubleMigrationError = "Detected double project migration: {0}";
|
|
||||||
|
|
||||||
public const string CannotMergeMetadataError = "Cannot merge metadata with the same name and different values";
|
|
||||||
|
|
||||||
public const string NoXprojFileGivenError = "{0}: No xproj file given.";
|
|
||||||
|
|
||||||
public const string MultipleXprojFilesError = "Multiple xproj files found in {0}, please specify which to use";
|
|
||||||
|
|
||||||
public const string NullMSBuildProjectTemplateError = "Expected non-null MSBuildProjectTemplate in MigrationSettings";
|
|
||||||
|
|
||||||
public const string CannotMigrateProjectWithCompilerError = "Cannot migrate project {0} using compiler {1}";
|
|
||||||
|
|
||||||
public const string ExpectedElementToBeOfTypeNotTypeError = "Expected element to be of type {0}, but got {1}";
|
|
||||||
|
|
||||||
public const string ProjAlreadyExistsError = "{0} already exists. Has migration already been run?";
|
|
||||||
|
|
||||||
public const string NullDestinationElementError = "expected destinationElement to not be null";
|
|
||||||
|
|
||||||
public const string DiagnosticMessageTemplate = "{0} (line: {1}, file: {2})";
|
|
||||||
|
|
||||||
public const string CannotMergeItemsOfDifferentTypesError = "Cannot merge items of different types.";
|
|
||||||
|
|
||||||
public const string CannotMergeItemsWithoutCommonIncludeError = "Cannot merge items without a common include.";
|
|
||||||
|
|
||||||
public const string PropertyTransformApplicatorWrongElementTypeError = "Expected element to be of type {0}, but got {1}";
|
|
||||||
|
|
||||||
public const string UnexpectedTypeError = "Unexpected type {0}";
|
|
||||||
|
|
||||||
public const string MIGRATE1011 = "Deprecated Project";
|
|
||||||
|
|
||||||
public const string MIGRATE1012 = "Project not Restored";
|
|
||||||
|
|
||||||
public const string MIGRATE1013 = "No Project";
|
|
||||||
|
|
||||||
public const string MIGRATE1013Arg = "The project.json specifies no target frameworks in {0}";
|
|
||||||
|
|
||||||
public const string MIGRATE1014 = "Unresolved Dependency";
|
|
||||||
|
|
||||||
public const string MIGRATE1014Arg = "Unresolved project dependency ({0})";
|
|
||||||
|
|
||||||
public const string MIGRATE1015 = "File Overwrite";
|
|
||||||
|
|
||||||
public const string MIGRATE1016 = "Unsupported Script Variable";
|
|
||||||
|
|
||||||
public const string MIGRATE1016Arg = "{0} is currently an unsupported script variable for project migration";
|
|
||||||
|
|
||||||
public const string MIGRATE1017 = "Multiple Xproj Files";
|
|
||||||
|
|
||||||
public const string MIGRATE1018 = "Dependency Project not found";
|
|
||||||
|
|
||||||
public const string MIGRATE1018Arg = "Dependency project not found ({0})" ;
|
|
||||||
|
|
||||||
public const string MIGRATE1019 = "Unsupported Script Event Hook";
|
|
||||||
|
|
||||||
public const string MIGRATE1019Arg = "{0} is an unsupported script event hook for project migration";
|
|
||||||
|
|
||||||
public const string MIGRATE20011 = "Multi-TFM";
|
|
||||||
|
|
||||||
public const string MIGRATE20012 = "Configuration Exclude";
|
|
||||||
|
|
||||||
public const string MIGRATE20013 = "Non-Csharp App";
|
|
||||||
|
|
||||||
public const string MIGRATE20018 = "Files specified under PackOptions";
|
|
||||||
|
|
||||||
public const string IncludesNotEquivalent = "{0}.{1} includes not equivalent.";
|
|
||||||
|
|
||||||
public const string UpdatesNotEquivalent = "{0}.{1} updates not equivalent.";
|
|
||||||
|
|
||||||
public const string ExcludesNotEquivalent = "{0}.{1} excludes not equivalent.";
|
|
||||||
|
|
||||||
public const string RemovesNotEquivalent = "{0}.{1} removes not equivalent.";
|
|
||||||
|
|
||||||
public const string MetadataDoesntExist = "{0}.{1} metadata doesn't exist {{ {2} {3} }}";
|
|
||||||
|
|
||||||
public const string MetadataHasAnotherValue = "{0}.{1} metadata has another value {{ {2} {3} {4} }}";
|
|
||||||
|
|
||||||
public const string AddingMetadataToItem = "{0}: Adding metadata to {1} item: {{ {2}, {3}, {4} }}";
|
|
||||||
|
|
||||||
public const string SkipMigrationAlreadyMigrated = "{0}: Skip migrating {1}, it is already migrated.";
|
|
||||||
|
|
||||||
public const string ExecutingRule = "Executing rule: {0}";
|
|
||||||
|
|
||||||
public const string NoConfigurationOrFrameworkFoundInProject = "{0}: No configuration or framework build options found in project";
|
|
||||||
|
|
||||||
public const string MigratingCountTargetFrameworks = "Migrating {0} target frameworks";
|
|
||||||
|
|
||||||
public const string MigratingFramework = "Migrating framework {0}";
|
|
||||||
|
|
||||||
public const string ImportsTransformNullFor = "{0}: imports transform null for {1}";
|
|
||||||
|
|
||||||
public const string MigratingCountXprojToCsprojReferences = "{0}: Migrating {1} xproj to csproj references";
|
|
||||||
|
|
||||||
public const string ExecutingMigrationRule = "{0}: Executing migration rule {1}";
|
|
||||||
|
|
||||||
public const string ItemTransformApplicatorHeader = "{0}: Item {{ ItemType: {1}, Condition: {2}, Include: {3}, Exclude: {4}, Update: {5} }}";
|
|
||||||
|
|
||||||
public const string ItemTransformApplicatorItemGroup = "{0}: ItemGroup {{ Condition: {1} }}";
|
|
||||||
|
|
||||||
public const string ItemTransformAppliatorItemCompletelyMerged = "{0}: Item completely merged";
|
|
||||||
|
|
||||||
public const string ItemTransformApplicatorAddItemHeader = "{0}: AddItemToItemGroup {{ ItemType: {1}, Condition: {2}, Include: {3}, Exclude: {4}, Update: {5} }}";
|
|
||||||
|
|
||||||
public const string ItemTransformApplicatorMergingItemWithExistingItems = "{0}: Merging Item with {1} existing items with a different condition chain.";
|
|
||||||
|
|
||||||
public const string ItemTransformApplicatorEncompassedIncludes = "{0}: encompassed includes {1}";
|
|
||||||
|
|
||||||
public const string ItemTransformApplicatorEncompassedUpdates = "{0}: encompassed updates {1}";
|
|
||||||
|
|
||||||
public const string ItemTransformApplicatorRemovingItem = "{0}: Removing Item {{ ItemType: {1}, Condition: {2}, Include: {3}, Exclude: {4} }}";
|
|
||||||
|
|
||||||
public const string ItemTransformApplicatorIgnoringItem = "{0}: Ignoring Item {{ ItemType: {1}, Condition: {2}, Include: {3}, Exclude: {4} }}";
|
|
||||||
|
|
||||||
public const string ItemTransformApplicatorMergingItemWithExistingItemsSameChain = "{0}: Merging Item with {1} existing items with the same condition chain.";
|
|
||||||
|
|
||||||
public const string ItemTransformApplicatorAddingMergedItem = "{0}: Adding Merged Item {{ ItemType: {1}, Condition: {2}, Include: {3}, Exclude: {4} }}";
|
|
||||||
|
|
||||||
public const string MergingProperty = "Merging property, output merged property";
|
|
||||||
|
|
||||||
public const string IgnoringMergedProperty = "Ignoring fully merged property";
|
|
||||||
|
|
||||||
public const string PropertyInfo = "{0}: {1}, {{ Name={2}, Value={3} }}";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,259 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.Build.Construction;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.ProjectJsonMigration
|
|
||||||
{
|
|
||||||
public static class MSBuildExtensions
|
|
||||||
{
|
|
||||||
public static IEnumerable<string> GetEncompassedIncludes(this ProjectItemElement item,
|
|
||||||
ProjectItemElement otherItem, TextWriter trace = null)
|
|
||||||
{
|
|
||||||
if (otherItem.IsEquivalentToExceptIncludeUpdateAndExclude(item, trace) &&
|
|
||||||
new HashSet<string>(otherItem.Excludes()).IsSubsetOf(new HashSet<string>(item.Excludes())))
|
|
||||||
{
|
|
||||||
return otherItem.IntersectIncludes(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Enumerable.Empty<string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<string> GetEncompassedUpdates(this ProjectItemElement item,
|
|
||||||
ProjectItemElement otherItem, TextWriter trace = null)
|
|
||||||
{
|
|
||||||
if (otherItem.IsEquivalentToExceptIncludeUpdateAndExclude(item, trace) &&
|
|
||||||
new HashSet<string>(otherItem.Excludes()).IsSubsetOf(new HashSet<string>(item.Excludes())))
|
|
||||||
{
|
|
||||||
return otherItem.IntersectUpdates(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Enumerable.Empty<string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool IsEquivalentTo(this ProjectItemElement item, ProjectItemElement otherItem, TextWriter trace = null)
|
|
||||||
{
|
|
||||||
// Different includes
|
|
||||||
if (item.IntersectIncludes(otherItem).Count() != item.Includes().Count())
|
|
||||||
{
|
|
||||||
trace?.WriteLine(String.Format(LocalizableStrings.IncludesNotEquivalent, nameof(MSBuildExtensions), nameof(IsEquivalentTo)));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.IntersectUpdates(otherItem).Count() != item.Updates().Count())
|
|
||||||
{
|
|
||||||
trace?.WriteLine(String.Format(LocalizableStrings.UpdatesNotEquivalent, nameof(MSBuildExtensions), nameof(IsEquivalentTo)));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Different Excludes
|
|
||||||
if (item.IntersectExcludes(otherItem).Count() != item.Excludes().Count())
|
|
||||||
{
|
|
||||||
trace?.WriteLine(String.Format(LocalizableStrings.ExcludesNotEquivalent, nameof(MSBuildExtensions), nameof(IsEquivalentTo)));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return item.IsEquivalentToExceptIncludeUpdateAndExclude(otherItem, trace);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool IsEquivalentToExceptIncludeUpdateAndExclude(this ProjectItemElement item, ProjectItemElement otherItem, TextWriter trace = null)
|
|
||||||
{
|
|
||||||
// Different remove
|
|
||||||
if (item.Remove != otherItem.Remove)
|
|
||||||
{
|
|
||||||
trace?.WriteLine(String.Format(LocalizableStrings.RemovesNotEquivalent, nameof(MSBuildExtensions), nameof(IsEquivalentTo)));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Different Metadata
|
|
||||||
var metadataTuples = otherItem.Metadata.Select(m => Tuple.Create(m, item)).Concat(
|
|
||||||
item.Metadata.Select(m => Tuple.Create(m, otherItem)));
|
|
||||||
foreach (var metadataTuple in metadataTuples)
|
|
||||||
{
|
|
||||||
var metadata = metadataTuple.Item1;
|
|
||||||
var itemToCompare = metadataTuple.Item2;
|
|
||||||
|
|
||||||
var otherMetadata = itemToCompare.GetMetadataWithName(metadata.Name);
|
|
||||||
if (otherMetadata == null)
|
|
||||||
{
|
|
||||||
trace?.WriteLine(String.Format(LocalizableStrings.MetadataDoesntExist, nameof(MSBuildExtensions), nameof(IsEquivalentTo), metadata.Name, metadata.Value));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!metadata.ValueEquals(otherMetadata))
|
|
||||||
{
|
|
||||||
trace?.WriteLine(String.Format(LocalizableStrings.MetadataHasAnotherValue, nameof(MSBuildExtensions), nameof(IsEquivalentTo), metadata.Name, metadata.Value, otherMetadata.Value));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ISet<string> ConditionChain(this ProjectElement projectElement)
|
|
||||||
{
|
|
||||||
var conditionChainSet = new HashSet<string>();
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(projectElement.Condition))
|
|
||||||
{
|
|
||||||
conditionChainSet.Add(projectElement.Condition);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var parent in projectElement.AllParents)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(parent.Condition))
|
|
||||||
{
|
|
||||||
conditionChainSet.Add(parent.Condition);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return conditionChainSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool ConditionChainsAreEquivalent(this ProjectElement projectElement, ProjectElement otherProjectElement)
|
|
||||||
{
|
|
||||||
return projectElement.ConditionChain().SetEquals(otherProjectElement.ConditionChain());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<ProjectPropertyElement> PropertiesWithoutConditions(
|
|
||||||
this ProjectRootElement projectRoot)
|
|
||||||
{
|
|
||||||
return ElementsWithoutConditions(projectRoot.Properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<ProjectItemElement> ItemsWithoutConditions(
|
|
||||||
this ProjectRootElement projectRoot)
|
|
||||||
{
|
|
||||||
return ElementsWithoutConditions(projectRoot.Items);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<string> Includes(
|
|
||||||
this ProjectItemElement item)
|
|
||||||
{
|
|
||||||
return SplitSemicolonDelimitedValues(item.Include);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<string> Updates(
|
|
||||||
this ProjectItemElement item)
|
|
||||||
{
|
|
||||||
return SplitSemicolonDelimitedValues(item.Update);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<string> Excludes(
|
|
||||||
this ProjectItemElement item)
|
|
||||||
{
|
|
||||||
return SplitSemicolonDelimitedValues(item.Exclude);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<string> Removes(
|
|
||||||
this ProjectItemElement item)
|
|
||||||
{
|
|
||||||
return SplitSemicolonDelimitedValues(item.Remove);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<string> AllConditions(this ProjectElement projectElement)
|
|
||||||
{
|
|
||||||
return new string[] { projectElement.Condition }.Concat(projectElement.AllParents.Select(p=> p.Condition));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<string> IntersectIncludes(this ProjectItemElement item, ProjectItemElement otherItem)
|
|
||||||
{
|
|
||||||
return item.Includes().Intersect(otherItem.Includes());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<string> IntersectUpdates(this ProjectItemElement item, ProjectItemElement otherItem)
|
|
||||||
{
|
|
||||||
return item.Updates().Intersect(otherItem.Updates());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<string> IntersectExcludes(this ProjectItemElement item, ProjectItemElement otherItem)
|
|
||||||
{
|
|
||||||
return item.Excludes().Intersect(otherItem.Excludes());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void RemoveIncludes(this ProjectItemElement item, IEnumerable<string> includesToRemove)
|
|
||||||
{
|
|
||||||
item.Include = string.Join(";", item.Includes().Except(includesToRemove));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void RemoveUpdates(this ProjectItemElement item, IEnumerable<string> updatesToRemove)
|
|
||||||
{
|
|
||||||
item.Update = string.Join(";", item.Updates().Except(updatesToRemove));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void UnionIncludes(this ProjectItemElement item, IEnumerable<string> includesToAdd)
|
|
||||||
{
|
|
||||||
item.Include = string.Join(";", item.Includes().Union(includesToAdd));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void UnionExcludes(this ProjectItemElement item, IEnumerable<string> excludesToAdd)
|
|
||||||
{
|
|
||||||
item.Exclude = string.Join(";", item.Excludes().Union(excludesToAdd));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool ValueEquals(this ProjectMetadataElement metadata, ProjectMetadataElement otherMetadata)
|
|
||||||
{
|
|
||||||
return metadata.Value.Equals(otherMetadata.Value, StringComparison.Ordinal);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void AddMetadata(this ProjectItemElement item, ICollection<ProjectMetadataElement> metadataElements, TextWriter trace = null)
|
|
||||||
{
|
|
||||||
foreach (var metadata in metadataElements)
|
|
||||||
{
|
|
||||||
item.AddMetadata(metadata, trace);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void RemoveIfEmpty(this ProjectElementContainer container)
|
|
||||||
{
|
|
||||||
if (!container.Children.Any())
|
|
||||||
{
|
|
||||||
container.Parent.RemoveChild(container);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ProjectMetadataElement GetMetadataWithName(this ProjectItemElement item, string name)
|
|
||||||
{
|
|
||||||
return item.Metadata.FirstOrDefault(m => m.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void AddMetadata(this ProjectItemElement item, ProjectMetadataElement metadata, TextWriter trace = null)
|
|
||||||
{
|
|
||||||
var existingMetadata = item.GetMetadataWithName(metadata.Name);
|
|
||||||
|
|
||||||
if (existingMetadata != default(ProjectMetadataElement) && !existingMetadata.ValueEquals(metadata))
|
|
||||||
{
|
|
||||||
throw new Exception(LocalizableStrings.CannotMergeMetadataError);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (existingMetadata == default(ProjectMetadataElement))
|
|
||||||
{
|
|
||||||
trace?.WriteLine(String.Format(LocalizableStrings.AddingMetadataToItem, nameof(AddMetadata), item.ItemType, metadata.Name, metadata.Value, metadata.Condition));
|
|
||||||
var metametadata = item.AddMetadata(metadata.Name, metadata.Value);
|
|
||||||
metametadata.Condition = metadata.Condition;
|
|
||||||
metametadata.ExpressedAsAttribute = metadata.ExpressedAsAttribute;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SetExcludeOnlyIfIncludeIsSet(this ProjectItemElement item, string exclude)
|
|
||||||
{
|
|
||||||
item.Exclude = string.IsNullOrEmpty(item.Include) ? string.Empty : exclude;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<string> SplitSemicolonDelimitedValues(string combinedValue)
|
|
||||||
{
|
|
||||||
return string.IsNullOrEmpty(combinedValue) ? Enumerable.Empty<string>() : combinedValue.Split(';');
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<T> ElementsWithoutConditions<T>(IEnumerable<T> elements) where T : ProjectElement
|
|
||||||
{
|
|
||||||
return elements
|
|
||||||
.Where(e => string.IsNullOrEmpty(e.Condition)
|
|
||||||
&& e.AllParents.All(parent => string.IsNullOrEmpty(parent.Condition)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
internal class AnalyzerOptions : IEquatable<AnalyzerOptions>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The identifier indicating the project language as defined by NuGet.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// See https://docs.nuget.org/create/analyzers-conventions for valid values
|
|
||||||
/// </remarks>
|
|
||||||
public string LanguageId { get; }
|
|
||||||
|
|
||||||
public AnalyzerOptions(string languageId = null)
|
|
||||||
{
|
|
||||||
LanguageId = languageId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Equals(AnalyzerOptions other)
|
|
||||||
{
|
|
||||||
return !ReferenceEquals(other, null) && other.LanguageId == LanguageId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
return Equals(obj as AnalyzerOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
return LanguageId?.GetHashCode() ?? 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator ==(AnalyzerOptions left, AnalyzerOptions right)
|
|
||||||
{
|
|
||||||
if (ReferenceEquals(left, right))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (ReferenceEquals(left, null))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return left.Equals(right);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator !=(AnalyzerOptions left, AnalyzerOptions right)
|
|
||||||
{
|
|
||||||
return !(left == right);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,81 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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.Linq;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
internal class BuildWorkspace : Workspace
|
|
||||||
{
|
|
||||||
public BuildWorkspace(ProjectReaderSettings settings) : base(settings, false) { }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create an empty <see cref="WorkspaceContext" /> using the default <see cref="ProjectReaderSettings" />
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static BuildWorkspace Create() => Create(versionSuffix: string.Empty);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create an empty <see cref="WorkspaceContext" /> using the default <see cref="ProjectReaderSettings" />, with the specified Version Suffix
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="versionSuffix">The suffix to use to replace any '-*' snapshot tokens in Project versions.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static BuildWorkspace Create(string versionSuffix)
|
|
||||||
{
|
|
||||||
var settings = ProjectReaderSettings.ReadFromEnvironment();
|
|
||||||
if (!string.IsNullOrEmpty(versionSuffix))
|
|
||||||
{
|
|
||||||
settings.VersionSuffix = versionSuffix;
|
|
||||||
}
|
|
||||||
return new BuildWorkspace(settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProjectContext GetRuntimeContext(ProjectContext context, IEnumerable<string> runtimeIdentifiers)
|
|
||||||
{
|
|
||||||
if (!runtimeIdentifiers.Any())
|
|
||||||
{
|
|
||||||
return context;
|
|
||||||
}
|
|
||||||
|
|
||||||
var contexts = GetProjectContextCollection(context.ProjectDirectory);
|
|
||||||
if (contexts == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var runtimeContext = runtimeIdentifiers
|
|
||||||
.Select(r => contexts.GetTarget(context.TargetFramework, r))
|
|
||||||
.FirstOrDefault(c => c != null);
|
|
||||||
|
|
||||||
if (runtimeContext == null)
|
|
||||||
{
|
|
||||||
if (context.IsPortable)
|
|
||||||
{
|
|
||||||
// We're specializing a portable target, so synthesize a runtime target manually
|
|
||||||
// We don't cache this project context, but we'll still use the cached Project and LockFile
|
|
||||||
return CreateBaseProjectBuilder(context.ProjectFile)
|
|
||||||
.WithTargetFramework(context.TargetFramework)
|
|
||||||
.WithRuntimeIdentifiers(runtimeIdentifiers)
|
|
||||||
.Build();
|
|
||||||
}
|
|
||||||
|
|
||||||
// We are standalone, but don't support this runtime
|
|
||||||
var rids = string.Join(", ", runtimeIdentifiers);
|
|
||||||
throw new InvalidOperationException($"Can not find runtime target for framework '{context.TargetFramework}' compatible with one of the target runtimes: '{rids}'. " +
|
|
||||||
"Possible causes:" + Environment.NewLine +
|
|
||||||
"1. The project has not been restored or restore failed - run `dotnet restore`" + Environment.NewLine +
|
|
||||||
$"2. The project does not list one of '{rids}' in the 'runtimes' section." + Environment.NewLine +
|
|
||||||
"3. You may be trying to publish a library, which is not supported. Use `dotnet pack` to distribute libraries.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return runtimeContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override IEnumerable<ProjectContext> BuildProjectContexts(Project project)
|
|
||||||
{
|
|
||||||
return CreateBaseProjectBuilder(project).BuildAllTargets();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,212 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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 Microsoft.DotNet.Internal.ProjectModel.Files;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
internal class CommonCompilerOptions
|
|
||||||
{
|
|
||||||
public IEnumerable<string> Defines { get; set; }
|
|
||||||
|
|
||||||
public string LanguageVersion { get; set; }
|
|
||||||
|
|
||||||
public string Platform { get; set; }
|
|
||||||
|
|
||||||
public bool? AllowUnsafe { get; set; }
|
|
||||||
|
|
||||||
public bool? WarningsAsErrors { get; set; }
|
|
||||||
|
|
||||||
public bool? Optimize { get; set; }
|
|
||||||
|
|
||||||
public string KeyFile { get; set; }
|
|
||||||
|
|
||||||
public bool? DelaySign { get; set; }
|
|
||||||
|
|
||||||
public bool? PublicSign { get; set; }
|
|
||||||
|
|
||||||
public string DebugType { get; set; }
|
|
||||||
|
|
||||||
public bool? EmitEntryPoint { get; set; }
|
|
||||||
|
|
||||||
public bool? PreserveCompilationContext { get; set; }
|
|
||||||
|
|
||||||
public bool? GenerateXmlDocumentation { get; set; }
|
|
||||||
|
|
||||||
public IEnumerable<string> SuppressWarnings { get; set; }
|
|
||||||
|
|
||||||
public IEnumerable<string> AdditionalArguments { get; set; }
|
|
||||||
|
|
||||||
public string OutputName { get; set; }
|
|
||||||
|
|
||||||
public string CompilerName { get; set; }
|
|
||||||
|
|
||||||
public IncludeContext CompileInclude { get; set; }
|
|
||||||
|
|
||||||
public IncludeContext EmbedInclude { get; set; }
|
|
||||||
|
|
||||||
public IncludeContext CopyToOutputInclude { get; set; }
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
var other = obj as CommonCompilerOptions;
|
|
||||||
return other != null &&
|
|
||||||
LanguageVersion == other.LanguageVersion &&
|
|
||||||
Platform == other.Platform &&
|
|
||||||
AllowUnsafe == other.AllowUnsafe &&
|
|
||||||
WarningsAsErrors == other.WarningsAsErrors &&
|
|
||||||
Optimize == other.Optimize &&
|
|
||||||
KeyFile == other.KeyFile &&
|
|
||||||
DelaySign == other.DelaySign &&
|
|
||||||
PublicSign == other.PublicSign &&
|
|
||||||
DebugType == other.DebugType &&
|
|
||||||
EmitEntryPoint == other.EmitEntryPoint &&
|
|
||||||
GenerateXmlDocumentation == other.GenerateXmlDocumentation &&
|
|
||||||
PreserveCompilationContext == other.PreserveCompilationContext &&
|
|
||||||
EnumerableEquals(Defines, other.Defines) &&
|
|
||||||
EnumerableEquals(SuppressWarnings, other.SuppressWarnings) &&
|
|
||||||
EnumerableEquals(AdditionalArguments, other.AdditionalArguments) &&
|
|
||||||
OutputName == other.OutputName &&
|
|
||||||
CompilerName == other.CompilerName &&
|
|
||||||
IsEqual(CompileInclude, other.CompileInclude) &&
|
|
||||||
IsEqual(EmbedInclude, other.EmbedInclude) &&
|
|
||||||
IsEqual(CopyToOutputInclude, other.CopyToOutputInclude);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsEqual(IncludeContext first, IncludeContext second)
|
|
||||||
{
|
|
||||||
if (first == null || second == null)
|
|
||||||
{
|
|
||||||
return first == second;
|
|
||||||
}
|
|
||||||
|
|
||||||
return first.Equals(second);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool EnumerableEquals(IEnumerable<string> left, IEnumerable<string> right)
|
|
||||||
=> Enumerable.SequenceEqual(left ?? EmptyArray<string>.Value, right ?? EmptyArray<string>.Value);
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
return base.GetHashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<string> Combine(IEnumerable<string> @new, IEnumerable<string> old)
|
|
||||||
{
|
|
||||||
if (@new != null)
|
|
||||||
{
|
|
||||||
old = old ?? EmptyArray<string>.Value;
|
|
||||||
return old.Concat(@new).Distinct().ToArray();
|
|
||||||
}
|
|
||||||
return old;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CommonCompilerOptions Combine(params CommonCompilerOptions[] options)
|
|
||||||
{
|
|
||||||
var result = new CommonCompilerOptions();
|
|
||||||
foreach (var option in options)
|
|
||||||
{
|
|
||||||
// Skip null options
|
|
||||||
if (option == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Defines, suppressions, and additional arguments are always combined
|
|
||||||
result.Defines = Combine(option.Defines, result.Defines);
|
|
||||||
result.SuppressWarnings = Combine(option.SuppressWarnings, result.SuppressWarnings);
|
|
||||||
result.AdditionalArguments = Combine(option.AdditionalArguments, result.AdditionalArguments);
|
|
||||||
|
|
||||||
if (option.LanguageVersion != null)
|
|
||||||
{
|
|
||||||
result.LanguageVersion = option.LanguageVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (option.Platform != null)
|
|
||||||
{
|
|
||||||
result.Platform = option.Platform;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (option.AllowUnsafe != null)
|
|
||||||
{
|
|
||||||
result.AllowUnsafe = option.AllowUnsafe;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (option.WarningsAsErrors != null)
|
|
||||||
{
|
|
||||||
result.WarningsAsErrors = option.WarningsAsErrors;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (option.Optimize != null)
|
|
||||||
{
|
|
||||||
result.Optimize = option.Optimize;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (option.KeyFile != null)
|
|
||||||
{
|
|
||||||
result.KeyFile = option.KeyFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (option.DelaySign != null)
|
|
||||||
{
|
|
||||||
result.DelaySign = option.DelaySign;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (option.PublicSign != null)
|
|
||||||
{
|
|
||||||
result.PublicSign = option.PublicSign;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (option.DebugType != null)
|
|
||||||
{
|
|
||||||
result.DebugType = option.DebugType;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (option.EmitEntryPoint != null)
|
|
||||||
{
|
|
||||||
result.EmitEntryPoint = option.EmitEntryPoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (option.PreserveCompilationContext != null)
|
|
||||||
{
|
|
||||||
result.PreserveCompilationContext = option.PreserveCompilationContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (option.GenerateXmlDocumentation != null)
|
|
||||||
{
|
|
||||||
result.GenerateXmlDocumentation = option.GenerateXmlDocumentation;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (option.OutputName != null)
|
|
||||||
{
|
|
||||||
result.OutputName = option.OutputName;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (option.CompileInclude != null)
|
|
||||||
{
|
|
||||||
result.CompileInclude = option.CompileInclude;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (option.EmbedInclude != null)
|
|
||||||
{
|
|
||||||
result.EmbedInclude = option.EmbedInclude;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (option.CopyToOutputInclude != null)
|
|
||||||
{
|
|
||||||
result.CopyToOutputInclude = option.CopyToOutputInclude;
|
|
||||||
}
|
|
||||||
|
|
||||||
// compilerName set in the root cannot be overriden.
|
|
||||||
if (result.CompilerName == null)
|
|
||||||
{
|
|
||||||
result.CompilerName = option.CompilerName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using NuGet.Frameworks;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.Compilation
|
|
||||||
{
|
|
||||||
internal class AnalyzerReference
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The fully-qualified path to the analyzer assembly.
|
|
||||||
/// </summary>
|
|
||||||
public string AssemblyPath { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The supported language of the analyzer assembly.
|
|
||||||
/// </summary>
|
|
||||||
public string AnalyzerLanguage { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The required framework for hosting the analyzer assembly.
|
|
||||||
/// </summary>
|
|
||||||
public NuGetFramework RequiredFramework { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The required runtime for hosting the analyzer assembly.
|
|
||||||
/// </summary>
|
|
||||||
public string RuntimeIdentifier { get; }
|
|
||||||
|
|
||||||
public AnalyzerReference(
|
|
||||||
string assembly,
|
|
||||||
NuGetFramework framework,
|
|
||||||
string language,
|
|
||||||
string runtimeIdentifier)
|
|
||||||
{
|
|
||||||
AnalyzerLanguage = language;
|
|
||||||
AssemblyPath = assembly;
|
|
||||||
RequiredFramework = framework;
|
|
||||||
RuntimeIdentifier = runtimeIdentifier;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,71 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.DotNet.PlatformAbstractions;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.Utilities;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.Compilation
|
|
||||||
{
|
|
||||||
public struct LibraryAsset
|
|
||||||
{
|
|
||||||
public string Name { get; }
|
|
||||||
public string RelativePath { get; }
|
|
||||||
public string ResolvedPath { get; }
|
|
||||||
public string FileName => Path.GetFileName(RelativePath);
|
|
||||||
public Action<Stream, Stream> Transform { get; set; }
|
|
||||||
|
|
||||||
public LibraryAsset(string name, string relativePath, string resolvedPath, Action<Stream, Stream> transform = null)
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
RelativePath = relativePath;
|
|
||||||
ResolvedPath = resolvedPath;
|
|
||||||
Transform = transform;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Equals(LibraryAsset other)
|
|
||||||
{
|
|
||||||
return string.Equals(Name, other.Name)
|
|
||||||
&& string.Equals(RelativePath, other.RelativePath)
|
|
||||||
&& string.Equals(ResolvedPath, other.ResolvedPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
if (ReferenceEquals(null, obj)) return false;
|
|
||||||
return obj is LibraryAsset && Equals((LibraryAsset) obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
var combiner = HashCodeCombiner.Start();
|
|
||||||
combiner.Add(Name);
|
|
||||||
combiner.Add(RelativePath);
|
|
||||||
combiner.Add(ResolvedPath);
|
|
||||||
return combiner.CombinedHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static LibraryAsset CreateFromRelativePath(string basePath, string relativePath, Action<Stream, Stream> transform = null)
|
|
||||||
{
|
|
||||||
return new LibraryAsset(
|
|
||||||
Path.GetFileNameWithoutExtension(relativePath),
|
|
||||||
relativePath,
|
|
||||||
Path.Combine(basePath, relativePath),
|
|
||||||
transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static LibraryAsset CreateFromAbsolutePath(string basePath, string absolutePath, Action<Stream, Stream> transform = null)
|
|
||||||
{
|
|
||||||
var relativePath = absolutePath.Replace(PathUtility.EnsureTrailingSlash(basePath), string.Empty);
|
|
||||||
|
|
||||||
return new LibraryAsset(
|
|
||||||
Path.GetFileNameWithoutExtension(relativePath),
|
|
||||||
relativePath,
|
|
||||||
absolutePath,
|
|
||||||
transform);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.Compilation
|
|
||||||
{
|
|
||||||
internal static class LibraryAssetExtensions
|
|
||||||
{
|
|
||||||
private const string NativeImageSufix = ".ni";
|
|
||||||
|
|
||||||
public static AssemblyName GetAssemblyName(this LibraryAsset asset)
|
|
||||||
{
|
|
||||||
var name = asset.Name;
|
|
||||||
if (asset.Name.EndsWith(NativeImageSufix))
|
|
||||||
{
|
|
||||||
name = name.Substring(0, name.Length - NativeImageSufix.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new AssemblyName(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetTransformedFile(this LibraryAsset asset, string tempLocation, string tempName = null)
|
|
||||||
{
|
|
||||||
if (asset.Transform == null)
|
|
||||||
{
|
|
||||||
return asset.ResolvedPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
tempName = tempName ?? Path.GetFileName(asset.RelativePath);
|
|
||||||
using (var input = File.OpenRead(asset.ResolvedPath))
|
|
||||||
{
|
|
||||||
var transformedName = Path.Combine(tempLocation, tempName);
|
|
||||||
using (var output = File.OpenWrite(transformedName))
|
|
||||||
{
|
|
||||||
asset.Transform(input, output);
|
|
||||||
}
|
|
||||||
return transformedName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Stream GetTransformedStream(this LibraryAsset asset)
|
|
||||||
{
|
|
||||||
if (asset.Transform == null)
|
|
||||||
{
|
|
||||||
return File.OpenRead(asset.ResolvedPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var input = File.OpenRead(asset.ResolvedPath))
|
|
||||||
{
|
|
||||||
var output = new MemoryStream();
|
|
||||||
asset.Transform(input, output);
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System.Linq;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.Compilation
|
|
||||||
{
|
|
||||||
internal class LibraryAssetGroup
|
|
||||||
{
|
|
||||||
public LibraryAssetGroup(string runtime, params LibraryAsset[] assets) : this(runtime, (IEnumerable<LibraryAsset>)assets) { }
|
|
||||||
public LibraryAssetGroup(params LibraryAsset[] assets) : this(string.Empty, (IEnumerable<LibraryAsset>)assets) { }
|
|
||||||
public LibraryAssetGroup(IEnumerable<LibraryAsset> assets) : this(string.Empty, assets) { }
|
|
||||||
|
|
||||||
public LibraryAssetGroup(string runtime,
|
|
||||||
IEnumerable<LibraryAsset> assets)
|
|
||||||
{
|
|
||||||
Runtime = runtime;
|
|
||||||
Assets = assets.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Runtime { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a list of assets provided in this runtime group
|
|
||||||
/// </summary>
|
|
||||||
public IReadOnlyList<LibraryAsset> Assets { get; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,80 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.Compilation
|
|
||||||
{
|
|
||||||
[DebuggerDisplay("{DebuggerDisplay,nq}")]
|
|
||||||
internal class LibraryExport
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the library that produced this export
|
|
||||||
/// </summary>
|
|
||||||
public LibraryDescription Library { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a list of MSIL binaries required to run
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<LibraryAssetGroup> RuntimeAssemblyGroups { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Non assembly runtime assets.
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<LibraryAsset> RuntimeAssets { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a list of native binaries required to run
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<LibraryAssetGroup> NativeLibraryGroups { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a list of fully-qualified paths to MSIL metadata references
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<LibraryAsset> CompilationAssemblies { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get a list of embedded resource files provided by this export.
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<LibraryAsset> EmbeddedResources { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a list of fully-qualified paths to source code file references
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<LibraryAsset> SourceReferences { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get a list of analyzers provided by this export.
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<AnalyzerReference> AnalyzerReferences { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get a list of resource assemblies provided by this export.
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<LibraryResourceAssembly> ResourceAssemblies { get; }
|
|
||||||
|
|
||||||
public LibraryExport(LibraryDescription library,
|
|
||||||
IEnumerable<LibraryAsset> compileAssemblies,
|
|
||||||
IEnumerable<LibraryAsset> sourceReferences,
|
|
||||||
IEnumerable<LibraryAssetGroup> runtimeAssemblyGroups,
|
|
||||||
IEnumerable<LibraryAsset> runtimeAssets,
|
|
||||||
IEnumerable<LibraryAssetGroup> nativeLibraryGroups,
|
|
||||||
IEnumerable<LibraryAsset> embeddedResources,
|
|
||||||
IEnumerable<AnalyzerReference> analyzers,
|
|
||||||
IEnumerable<LibraryResourceAssembly> resourceAssemblies)
|
|
||||||
{
|
|
||||||
Library = library;
|
|
||||||
CompilationAssemblies = compileAssemblies;
|
|
||||||
SourceReferences = sourceReferences;
|
|
||||||
RuntimeAssemblyGroups = runtimeAssemblyGroups;
|
|
||||||
RuntimeAssets = runtimeAssets;
|
|
||||||
NativeLibraryGroups = nativeLibraryGroups;
|
|
||||||
EmbeddedResources = embeddedResources;
|
|
||||||
AnalyzerReferences = analyzers;
|
|
||||||
ResourceAssemblies = resourceAssemblies;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string DebuggerDisplay => Library.Identity.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,191 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.Compilation
|
|
||||||
{
|
|
||||||
internal class LibraryExportBuilder
|
|
||||||
{
|
|
||||||
private IList<LibraryAssetGroup> _runtimeAssemblyGroups;
|
|
||||||
|
|
||||||
private IList<LibraryAsset> _runtimeAssets;
|
|
||||||
|
|
||||||
private IList<LibraryAsset> _compilationAssemblies;
|
|
||||||
|
|
||||||
private IList<LibraryAsset> _sourceReferences;
|
|
||||||
|
|
||||||
private IList<LibraryAssetGroup> _nativeLibraryGroups;
|
|
||||||
|
|
||||||
private IList<LibraryAsset> _embeddedResources;
|
|
||||||
|
|
||||||
private IList<AnalyzerReference> _analyzerReferences;
|
|
||||||
|
|
||||||
private IList<LibraryResourceAssembly> _resourceAssemblies;
|
|
||||||
|
|
||||||
public LibraryDescription Library { get; set; }
|
|
||||||
|
|
||||||
public IEnumerable<LibraryAssetGroup> RuntimeAssemblyGroups => _runtimeAssemblyGroups;
|
|
||||||
|
|
||||||
public IEnumerable<LibraryAsset> RuntimeAssets => _runtimeAssets;
|
|
||||||
|
|
||||||
public IEnumerable<LibraryAsset> CompilationAssemblies => _compilationAssemblies;
|
|
||||||
|
|
||||||
public IEnumerable<LibraryAsset> SourceReferences => _sourceReferences;
|
|
||||||
|
|
||||||
public IEnumerable<LibraryAssetGroup> NativeLibraryGroups => _nativeLibraryGroups;
|
|
||||||
|
|
||||||
public IEnumerable<LibraryAsset> EmbeddedResources => _embeddedResources;
|
|
||||||
|
|
||||||
public IEnumerable<AnalyzerReference> AnalyzerReferences => _analyzerReferences;
|
|
||||||
|
|
||||||
public IEnumerable<LibraryResourceAssembly> ResourceAssemblies => _resourceAssemblies;
|
|
||||||
|
|
||||||
public static LibraryExportBuilder Create(LibraryDescription library = null)
|
|
||||||
{
|
|
||||||
return new LibraryExportBuilder().WithLibrary(library);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LibraryExport Build()
|
|
||||||
{
|
|
||||||
if (Library == null)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Cannot build LibraryExport withoud Library set");
|
|
||||||
}
|
|
||||||
return new LibraryExport(
|
|
||||||
Library,
|
|
||||||
CompilationAssemblies ?? EmptyArray<LibraryAsset>.Value,
|
|
||||||
SourceReferences ?? EmptyArray<LibraryAsset>.Value,
|
|
||||||
RuntimeAssemblyGroups ?? EmptyArray<LibraryAssetGroup>.Value,
|
|
||||||
RuntimeAssets ?? EmptyArray<LibraryAsset>.Value,
|
|
||||||
NativeLibraryGroups ?? EmptyArray<LibraryAssetGroup>.Value,
|
|
||||||
EmbeddedResources ?? EmptyArray<LibraryAsset>.Value,
|
|
||||||
AnalyzerReferences ?? EmptyArray<AnalyzerReference>.Value,
|
|
||||||
ResourceAssemblies ?? EmptyArray<LibraryResourceAssembly>.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LibraryExportBuilder WithLibrary(LibraryDescription libraryDescription)
|
|
||||||
{
|
|
||||||
Library = libraryDescription;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LibraryExportBuilder WithRuntimeAssemblyGroups(IEnumerable<LibraryAssetGroup> assets)
|
|
||||||
{
|
|
||||||
Replace(ref _runtimeAssemblyGroups, assets);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LibraryExportBuilder WithRuntimeAssets(IEnumerable<LibraryAsset> assets)
|
|
||||||
{
|
|
||||||
Replace(ref _runtimeAssets, assets);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LibraryExportBuilder WithCompilationAssemblies(IEnumerable<LibraryAsset> assets)
|
|
||||||
{
|
|
||||||
Replace(ref _compilationAssemblies, assets);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LibraryExportBuilder WithSourceReferences(IEnumerable<LibraryAsset> assets)
|
|
||||||
{
|
|
||||||
Replace(ref _sourceReferences, assets);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LibraryExportBuilder WithNativeLibraryGroups(IEnumerable<LibraryAssetGroup> assets)
|
|
||||||
{
|
|
||||||
Replace(ref _nativeLibraryGroups, assets);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LibraryExportBuilder WithEmbedddedResources(IEnumerable<LibraryAsset> assets)
|
|
||||||
{
|
|
||||||
Replace(ref _embeddedResources, assets);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LibraryExportBuilder WithAnalyzerReference(IEnumerable<AnalyzerReference> assets)
|
|
||||||
{
|
|
||||||
Replace(ref _analyzerReferences, assets);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LibraryExportBuilder WithResourceAssemblies(IEnumerable<LibraryResourceAssembly> assemblies)
|
|
||||||
{
|
|
||||||
Replace(ref _resourceAssemblies, assemblies);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LibraryExportBuilder AddRuntimeAssemblyGroup(LibraryAssetGroup asset)
|
|
||||||
{
|
|
||||||
Add(ref _runtimeAssemblyGroups, asset);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LibraryExportBuilder AddRuntimeAsset(LibraryAsset asset)
|
|
||||||
{
|
|
||||||
Add(ref _runtimeAssets, asset);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LibraryExportBuilder AddCompilationAssembly(LibraryAsset asset)
|
|
||||||
{
|
|
||||||
Add(ref _compilationAssemblies, asset);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LibraryExportBuilder AddSourceReference(LibraryAsset asset)
|
|
||||||
{
|
|
||||||
Add(ref _sourceReferences, asset);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LibraryExportBuilder AddNativeLibraryGroup(LibraryAssetGroup asset)
|
|
||||||
{
|
|
||||||
Add(ref _nativeLibraryGroups, asset);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LibraryExportBuilder AddEmbedddedResource(LibraryAsset asset)
|
|
||||||
{
|
|
||||||
Add(ref _embeddedResources, asset);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LibraryExportBuilder AddAnalyzerReference(AnalyzerReference asset)
|
|
||||||
{
|
|
||||||
Add(ref _analyzerReferences, asset);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LibraryExportBuilder AddResourceAssembly(LibraryResourceAssembly assembly)
|
|
||||||
{
|
|
||||||
Add(ref _resourceAssemblies, assembly);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Replace<T>(ref IList<T> list, IEnumerable<T> enumerable)
|
|
||||||
{
|
|
||||||
if (enumerable == null)
|
|
||||||
{
|
|
||||||
list = null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
list = new List<T>(enumerable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Add<T>(ref IList<T> list, T item)
|
|
||||||
{
|
|
||||||
if (list == null)
|
|
||||||
{
|
|
||||||
list = new List<T>();
|
|
||||||
}
|
|
||||||
list.Add(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,514 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.Compilation.Preprocessor;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.Files;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.Resolution;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.Utilities;
|
|
||||||
using Microsoft.DotNet.Tools.Compiler;
|
|
||||||
using NuGet.Frameworks;
|
|
||||||
using NuGet.LibraryModel;
|
|
||||||
using NuGet.ProjectModel;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.Compilation
|
|
||||||
{
|
|
||||||
internal class LibraryExporter
|
|
||||||
{
|
|
||||||
private readonly string _configuration;
|
|
||||||
private readonly string _runtime;
|
|
||||||
private readonly string[] _runtimeFallbacks;
|
|
||||||
private readonly ProjectDescription _rootProject;
|
|
||||||
private readonly string _buildBasePath;
|
|
||||||
private readonly string _solutionRootPath;
|
|
||||||
|
|
||||||
public LibraryExporter(ProjectDescription rootProject,
|
|
||||||
LibraryManager manager,
|
|
||||||
string configuration,
|
|
||||||
string runtime,
|
|
||||||
string[] runtimeFallbacks,
|
|
||||||
string buildBasePath,
|
|
||||||
string solutionRootPath)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(configuration))
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(configuration));
|
|
||||||
}
|
|
||||||
|
|
||||||
LibraryManager = manager;
|
|
||||||
_configuration = configuration;
|
|
||||||
_runtime = runtime;
|
|
||||||
_runtimeFallbacks = runtimeFallbacks;
|
|
||||||
_buildBasePath = buildBasePath;
|
|
||||||
_solutionRootPath = solutionRootPath;
|
|
||||||
_rootProject = rootProject;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LibraryManager LibraryManager { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets all the exports specified by this project, including the root project itself
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<LibraryExport> GetAllExports()
|
|
||||||
{
|
|
||||||
return ExportLibraries(_ => true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets all exports required by the project, NOT including the project itself
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public IEnumerable<LibraryExport> GetDependencies()
|
|
||||||
{
|
|
||||||
return GetDependencies(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets all exports required by the project, of the specified <see cref="LibraryType"/>, NOT including the project itself
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public IEnumerable<LibraryExport> GetDependencies(LibraryType? type)
|
|
||||||
{
|
|
||||||
// Export all but the main project
|
|
||||||
return ExportLibraries(library =>
|
|
||||||
library != _rootProject &&
|
|
||||||
LibraryIsOfType(type, library));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Retrieves a list of <see cref="LibraryExport"/> objects representing the assets
|
|
||||||
/// required from other libraries to compile this project.
|
|
||||||
/// </summary>
|
|
||||||
private IEnumerable<LibraryExport> ExportLibraries(Func<LibraryDescription, bool> condition)
|
|
||||||
{
|
|
||||||
var seenMetadataReferences = new HashSet<string>();
|
|
||||||
|
|
||||||
// Iterate over libraries in the library manager
|
|
||||||
foreach (var library in LibraryManager.GetLibraries())
|
|
||||||
{
|
|
||||||
if (!condition(library))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var compilationAssemblies = new List<LibraryAsset>();
|
|
||||||
var sourceReferences = new List<LibraryAsset>();
|
|
||||||
var analyzerReferences = new List<AnalyzerReference>();
|
|
||||||
var libraryExport = GetExport(library);
|
|
||||||
|
|
||||||
// We need to filter out source references from non-root libraries,
|
|
||||||
// so we rebuild the library export
|
|
||||||
foreach (var reference in libraryExport.CompilationAssemblies)
|
|
||||||
{
|
|
||||||
if (seenMetadataReferences.Add(reference.Name))
|
|
||||||
{
|
|
||||||
compilationAssemblies.Add(reference);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Source and analyzer references are not transitive
|
|
||||||
if (library.Parents.Contains(_rootProject))
|
|
||||||
{
|
|
||||||
sourceReferences.AddRange(libraryExport.SourceReferences);
|
|
||||||
analyzerReferences.AddRange(libraryExport.AnalyzerReferences);
|
|
||||||
}
|
|
||||||
|
|
||||||
var builder = LibraryExportBuilder.Create(library);
|
|
||||||
if (_runtime != null && _runtimeFallbacks != null)
|
|
||||||
{
|
|
||||||
// For portable apps that are built with runtime trimming we replace RuntimeAssemblyGroups and NativeLibraryGroups
|
|
||||||
// with single default group that contains asset specific to runtime we are trimming for
|
|
||||||
// based on runtime fallback list
|
|
||||||
builder.WithRuntimeAssemblyGroups(TrimAssetGroups(libraryExport.RuntimeAssemblyGroups, _runtimeFallbacks));
|
|
||||||
builder.WithNativeLibraryGroups(TrimAssetGroups(libraryExport.NativeLibraryGroups, _runtimeFallbacks));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
builder.WithRuntimeAssemblyGroups(libraryExport.RuntimeAssemblyGroups);
|
|
||||||
builder.WithNativeLibraryGroups(libraryExport.NativeLibraryGroups);
|
|
||||||
}
|
|
||||||
|
|
||||||
yield return builder
|
|
||||||
.WithCompilationAssemblies(compilationAssemblies)
|
|
||||||
.WithSourceReferences(sourceReferences)
|
|
||||||
.WithRuntimeAssets(libraryExport.RuntimeAssets)
|
|
||||||
.WithEmbedddedResources(libraryExport.EmbeddedResources)
|
|
||||||
.WithAnalyzerReference(analyzerReferences)
|
|
||||||
.WithResourceAssemblies(libraryExport.ResourceAssemblies)
|
|
||||||
.Build();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<LibraryAssetGroup> TrimAssetGroups(IEnumerable<LibraryAssetGroup> runtimeAssemblyGroups,
|
|
||||||
string[] runtimeFallbacks)
|
|
||||||
{
|
|
||||||
LibraryAssetGroup runtimeAssets;
|
|
||||||
foreach (var rid in runtimeFallbacks)
|
|
||||||
{
|
|
||||||
runtimeAssets = runtimeAssemblyGroups.GetRuntimeGroup(rid);
|
|
||||||
if (runtimeAssets != null)
|
|
||||||
{
|
|
||||||
yield return new LibraryAssetGroup(runtimeAssets.Assets);
|
|
||||||
yield break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
runtimeAssets = runtimeAssemblyGroups.GetDefaultGroup();
|
|
||||||
if (runtimeAssets != null)
|
|
||||||
{
|
|
||||||
yield return runtimeAssets;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a LibraryExport from LibraryDescription.
|
|
||||||
///
|
|
||||||
/// When the library is not resolved the LibraryExport is created nevertheless.
|
|
||||||
/// </summary>
|
|
||||||
private LibraryExport GetExport(LibraryDescription library)
|
|
||||||
{
|
|
||||||
if (!library.Resolved)
|
|
||||||
{
|
|
||||||
// For a unresolved project reference returns a export with empty asset.
|
|
||||||
return LibraryExportBuilder.Create(library).Build();
|
|
||||||
}
|
|
||||||
|
|
||||||
var libraryType = library.Identity.Type;
|
|
||||||
if (library is TargetLibraryWithAssets)
|
|
||||||
{
|
|
||||||
return ExportPackage((TargetLibraryWithAssets)library);
|
|
||||||
}
|
|
||||||
else if (Equals(LibraryType.Project, libraryType))
|
|
||||||
{
|
|
||||||
return ExportProject((ProjectDescription)library);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return ExportFrameworkLibrary(library);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private LibraryExport ExportPackage(TargetLibraryWithAssets library)
|
|
||||||
{
|
|
||||||
var builder = LibraryExportBuilder.Create(library);
|
|
||||||
builder.AddNativeLibraryGroup(new LibraryAssetGroup(PopulateAssets(library, library.NativeLibraries)));
|
|
||||||
builder.AddRuntimeAssemblyGroup(new LibraryAssetGroup(PopulateAssets(library, library.RuntimeAssemblies)));
|
|
||||||
builder.WithResourceAssemblies(PopulateResources(library, library.ResourceAssemblies));
|
|
||||||
builder.WithCompilationAssemblies(PopulateAssets(library, library.CompileTimeAssemblies));
|
|
||||||
|
|
||||||
if (library.Identity.Type.Equals(LibraryType.Package))
|
|
||||||
{
|
|
||||||
builder.WithSourceReferences(GetSharedSources((PackageDescription) library));
|
|
||||||
builder.WithAnalyzerReference(GetAnalyzerReferences((PackageDescription) library));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (library.ContentFiles.Any())
|
|
||||||
{
|
|
||||||
var parameters = PPFileParameters.CreateForProject(_rootProject.Project);
|
|
||||||
Action<Stream, Stream> transform = (input, output) => PPFilePreprocessor.Preprocess(input, output, parameters);
|
|
||||||
|
|
||||||
var sourceCodeLanguage = _rootProject.Project.GetSourceCodeLanguage();
|
|
||||||
var languageGroups = library.ContentFiles.GroupBy(file => file.CodeLanguage);
|
|
||||||
|
|
||||||
var selectedGroup = languageGroups.FirstOrDefault(g => g.Key == sourceCodeLanguage) ??
|
|
||||||
languageGroups.FirstOrDefault(g => g.Key == "any") ??
|
|
||||||
languageGroups.FirstOrDefault(g => g.Key == null);
|
|
||||||
if (selectedGroup != null)
|
|
||||||
{
|
|
||||||
foreach (var contentFile in selectedGroup)
|
|
||||||
{
|
|
||||||
if (contentFile.CodeLanguage != null &&
|
|
||||||
contentFile.CodeLanguage != "any" &&
|
|
||||||
string.Compare(contentFile.CodeLanguage, sourceCodeLanguage, StringComparison.OrdinalIgnoreCase) != 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var fileTransform = contentFile.PPOutputPath != null ? transform : null;
|
|
||||||
|
|
||||||
var fullPath = Path.Combine(library.Path, contentFile.Path);
|
|
||||||
if (contentFile.BuildAction == BuildAction.Compile)
|
|
||||||
{
|
|
||||||
builder.AddSourceReference(LibraryAsset.CreateFromRelativePath(library.Path, contentFile.Path, fileTransform));
|
|
||||||
}
|
|
||||||
else if (contentFile.BuildAction == BuildAction.EmbeddedResource)
|
|
||||||
{
|
|
||||||
builder.AddEmbedddedResource(LibraryAsset.CreateFromRelativePath(library.Path, contentFile.Path, fileTransform));
|
|
||||||
}
|
|
||||||
if (contentFile.CopyToOutput)
|
|
||||||
{
|
|
||||||
builder.AddRuntimeAsset(new LibraryAsset(contentFile.Path, contentFile.OutputPath, fullPath, fileTransform));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (library.RuntimeTargets.Any())
|
|
||||||
{
|
|
||||||
foreach (var targetGroup in library.RuntimeTargets.GroupBy(t => t.Runtime))
|
|
||||||
{
|
|
||||||
var runtime = new List<LibraryAsset>();
|
|
||||||
var native = new List<LibraryAsset>();
|
|
||||||
|
|
||||||
foreach (var lockFileRuntimeTarget in targetGroup)
|
|
||||||
{
|
|
||||||
if (string.Equals(lockFileRuntimeTarget.AssetType, "native", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
native.Add(LibraryAsset.CreateFromRelativePath(library.Path, lockFileRuntimeTarget.Path));
|
|
||||||
}
|
|
||||||
else if (string.Equals(lockFileRuntimeTarget.AssetType, "runtime", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
runtime.Add(LibraryAsset.CreateFromRelativePath(library.Path, lockFileRuntimeTarget.Path));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (runtime.Any())
|
|
||||||
{
|
|
||||||
builder.AddRuntimeAssemblyGroup(new LibraryAssetGroup(targetGroup.Key, runtime.Where(a => !PackageDependencyProvider.IsPlaceholderFile(a.RelativePath))));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (native.Any())
|
|
||||||
{
|
|
||||||
builder.AddNativeLibraryGroup(new LibraryAssetGroup(targetGroup.Key, native.Where(a => !PackageDependencyProvider.IsPlaceholderFile(a.RelativePath))));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return builder.Build();
|
|
||||||
}
|
|
||||||
|
|
||||||
private LibraryExport ExportProject(ProjectDescription project)
|
|
||||||
{
|
|
||||||
var builder = LibraryExportBuilder.Create(project);
|
|
||||||
var compilerOptions = project.Project.GetCompilerOptions(project.TargetFrameworkInfo.FrameworkName, _configuration);
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(project.TargetFrameworkInfo?.AssemblyPath))
|
|
||||||
{
|
|
||||||
// Project specifies a pre-compiled binary. We're done!
|
|
||||||
var assemblyPath = ResolvePath(project.Project, _configuration, project.TargetFrameworkInfo.AssemblyPath);
|
|
||||||
var pdbPath = Path.ChangeExtension(assemblyPath, "pdb");
|
|
||||||
|
|
||||||
var compileAsset = new LibraryAsset(
|
|
||||||
project.Project.Name,
|
|
||||||
Path.GetFileName(assemblyPath),
|
|
||||||
assemblyPath);
|
|
||||||
|
|
||||||
builder.AddCompilationAssembly(compileAsset);
|
|
||||||
builder.AddRuntimeAssemblyGroup(new LibraryAssetGroup(new[] { compileAsset }));
|
|
||||||
if (File.Exists(pdbPath))
|
|
||||||
{
|
|
||||||
builder.AddRuntimeAsset(new LibraryAsset(Path.GetFileName(pdbPath), Path.GetFileName(pdbPath), pdbPath));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (HasSourceFiles(project, compilerOptions))
|
|
||||||
{
|
|
||||||
var outputPaths = project.GetOutputPaths(_buildBasePath, _solutionRootPath, _configuration, _runtime);
|
|
||||||
|
|
||||||
var compilationAssembly = outputPaths.CompilationFiles.Assembly;
|
|
||||||
var compilationAssemblyAsset = LibraryAsset.CreateFromAbsolutePath(
|
|
||||||
outputPaths.CompilationFiles.BasePath,
|
|
||||||
compilationAssembly);
|
|
||||||
|
|
||||||
builder.AddCompilationAssembly(compilationAssemblyAsset);
|
|
||||||
|
|
||||||
if (ExportsRuntime(project))
|
|
||||||
{
|
|
||||||
var runtimeAssemblyAsset = LibraryAsset.CreateFromAbsolutePath(
|
|
||||||
outputPaths.RuntimeFiles.BasePath,
|
|
||||||
outputPaths.RuntimeFiles.Assembly);
|
|
||||||
|
|
||||||
builder.AddRuntimeAssemblyGroup(new LibraryAssetGroup(new[] { runtimeAssemblyAsset }));
|
|
||||||
builder.WithRuntimeAssets(CollectAssets(outputPaths.RuntimeFiles));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
builder.AddRuntimeAssemblyGroup(new LibraryAssetGroup(new[] { compilationAssemblyAsset }));
|
|
||||||
builder.WithRuntimeAssets(CollectAssets(outputPaths.CompilationFiles));
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.WithResourceAssemblies(outputPaths.CompilationFiles.Resources().Select(r => new LibraryResourceAssembly(
|
|
||||||
LibraryAsset.CreateFromAbsolutePath(outputPaths.CompilationFiles.BasePath, r.Path),
|
|
||||||
r.Locale)));
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.WithSourceReferences(project.Project.Files.SharedFiles.Select(f =>
|
|
||||||
LibraryAsset.CreateFromAbsolutePath(project.Path, f)
|
|
||||||
));
|
|
||||||
|
|
||||||
return builder.Build();
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool HasSourceFiles(ProjectDescription project, CommonCompilerOptions compilerOptions)
|
|
||||||
{
|
|
||||||
if (compilerOptions.CompileInclude == null)
|
|
||||||
{
|
|
||||||
return project.Project.Files.SourceFiles.Any();
|
|
||||||
}
|
|
||||||
|
|
||||||
var includeFiles = IncludeFilesResolver.GetIncludeFiles(compilerOptions.CompileInclude, "/", diagnostics: null);
|
|
||||||
|
|
||||||
return includeFiles.Any();
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<LibraryAsset> CollectAssets(CompilationOutputFiles files)
|
|
||||||
{
|
|
||||||
var assemblyPath = files.Assembly;
|
|
||||||
foreach (var path in files.All().Except(files.Resources().Select(r => r.Path)))
|
|
||||||
{
|
|
||||||
if (string.Equals(assemblyPath, path))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
yield return LibraryAsset.CreateFromAbsolutePath(files.BasePath, path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool ExportsRuntime(ProjectDescription project)
|
|
||||||
{
|
|
||||||
return project == _rootProject &&
|
|
||||||
!string.IsNullOrWhiteSpace(_runtime) &&
|
|
||||||
project.Project.HasRuntimeOutput(_configuration);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ResolvePath(Project project, string configuration, string path)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(path))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
path = PathUtility.GetPathWithDirectorySeparator(path);
|
|
||||||
|
|
||||||
path = path.Replace("{configuration}", configuration);
|
|
||||||
|
|
||||||
return Path.Combine(project.ProjectDirectory, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
private LibraryExport ExportFrameworkLibrary(LibraryDescription library)
|
|
||||||
{
|
|
||||||
// We assume the path is to an assembly. Framework libraries only export compile-time stuff
|
|
||||||
// since they assume the runtime library is present already
|
|
||||||
var builder = LibraryExportBuilder.Create(library);
|
|
||||||
if (!string.IsNullOrEmpty(library.Path))
|
|
||||||
{
|
|
||||||
builder.WithCompilationAssemblies(new[]
|
|
||||||
{
|
|
||||||
new LibraryAsset(library.Identity.Name, null, library.Path)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return builder.Build();
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<LibraryAsset> GetSharedSources(PackageDescription package)
|
|
||||||
{
|
|
||||||
return package
|
|
||||||
.PackageLibrary
|
|
||||||
.Files
|
|
||||||
.Select(f => PathUtility.GetPathWithDirectorySeparator(f))
|
|
||||||
.Where(path => path.StartsWith("shared" + Path.DirectorySeparatorChar))
|
|
||||||
.Select(path => LibraryAsset.CreateFromRelativePath(package.Path, path));
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<AnalyzerReference> GetAnalyzerReferences(PackageDescription package)
|
|
||||||
{
|
|
||||||
var analyzers = package
|
|
||||||
.PackageLibrary
|
|
||||||
.Files
|
|
||||||
.Select(f => PathUtility.GetPathWithDirectorySeparator(f))
|
|
||||||
.Where(path => path.StartsWith("analyzers" + Path.DirectorySeparatorChar) &&
|
|
||||||
path.EndsWith(".dll"));
|
|
||||||
|
|
||||||
|
|
||||||
var analyzerRefs = new List<AnalyzerReference>();
|
|
||||||
|
|
||||||
// See https://docs.nuget.org/create/analyzers-conventions for the analyzer
|
|
||||||
// NuGet specification
|
|
||||||
foreach (var analyzer in analyzers)
|
|
||||||
{
|
|
||||||
var specifiers = analyzer.Split(Path.DirectorySeparatorChar);
|
|
||||||
|
|
||||||
var assemblyPath = Path.Combine(package.Path, analyzer);
|
|
||||||
|
|
||||||
// $/analyzers/{Framework Name}{Version}/{Supported Architecture}/{Supported Programming Language}/{Analyzer}.dll
|
|
||||||
switch (specifiers.Length)
|
|
||||||
{
|
|
||||||
// $/analyzers/{analyzer}.dll
|
|
||||||
case 2:
|
|
||||||
analyzerRefs.Add(new AnalyzerReference(
|
|
||||||
assembly: assemblyPath,
|
|
||||||
framework: null,
|
|
||||||
language: null,
|
|
||||||
runtimeIdentifier: null
|
|
||||||
));
|
|
||||||
break;
|
|
||||||
|
|
||||||
// $/analyzers/{framework}/{analyzer}.dll
|
|
||||||
case 3:
|
|
||||||
analyzerRefs.Add(new AnalyzerReference(
|
|
||||||
assembly: assemblyPath,
|
|
||||||
framework: NuGetFramework.Parse(specifiers[1]),
|
|
||||||
language: null,
|
|
||||||
runtimeIdentifier: null
|
|
||||||
));
|
|
||||||
break;
|
|
||||||
|
|
||||||
// $/analyzers/{framework}/{language}/{analyzer}.dll
|
|
||||||
case 4:
|
|
||||||
analyzerRefs.Add(new AnalyzerReference(
|
|
||||||
assembly: assemblyPath,
|
|
||||||
framework: NuGetFramework.Parse(specifiers[1]),
|
|
||||||
language: specifiers[2],
|
|
||||||
runtimeIdentifier: null
|
|
||||||
));
|
|
||||||
break;
|
|
||||||
|
|
||||||
// $/analyzers/{framework}/{runtime}/{language}/{analyzer}.dll
|
|
||||||
case 5:
|
|
||||||
analyzerRefs.Add(new AnalyzerReference(
|
|
||||||
assembly: assemblyPath,
|
|
||||||
framework: NuGetFramework.Parse(specifiers[1]),
|
|
||||||
language: specifiers[3],
|
|
||||||
runtimeIdentifier: specifiers[2]
|
|
||||||
));
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Anything less than 2 specifiers or more than 4 is
|
|
||||||
// illegal according to the specification and will be
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return analyzerRefs;
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<LibraryResourceAssembly> PopulateResources(TargetLibraryWithAssets library, IEnumerable<LockFileItem> section)
|
|
||||||
{
|
|
||||||
foreach (var assemblyPath in section.Where(a => !PackageDependencyProvider.IsPlaceholderFile(a.Path)))
|
|
||||||
{
|
|
||||||
string locale;
|
|
||||||
if(!assemblyPath.Properties.TryGetValue(Constants.LocaleLockFilePropertyName, out locale))
|
|
||||||
{
|
|
||||||
locale = null;
|
|
||||||
}
|
|
||||||
yield return new LibraryResourceAssembly(
|
|
||||||
LibraryAsset.CreateFromRelativePath(library.Path, assemblyPath.Path),
|
|
||||||
locale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<LibraryAsset> PopulateAssets(TargetLibraryWithAssets library, IEnumerable<LockFileItem> section)
|
|
||||||
{
|
|
||||||
foreach (var assemblyPath in section.Where(a => !PackageDependencyProvider.IsPlaceholderFile(a.Path)))
|
|
||||||
{
|
|
||||||
yield return LibraryAsset.CreateFromRelativePath(library.Path, assemblyPath.Path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool LibraryIsOfType(LibraryType? type, LibraryDescription library)
|
|
||||||
{
|
|
||||||
return type == null || // No type filter was requested
|
|
||||||
library.Identity.Type.Equals(type); // OR, library type matches requested type
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.Compilation
|
|
||||||
{
|
|
||||||
internal class LibraryResourceAssembly
|
|
||||||
{
|
|
||||||
public LibraryResourceAssembly(LibraryAsset asset, string locale)
|
|
||||||
{
|
|
||||||
Asset = asset;
|
|
||||||
Locale = locale;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LibraryAsset Asset { get; }
|
|
||||||
|
|
||||||
public string Locale { get; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.Compilation.Preprocessor
|
|
||||||
{
|
|
||||||
internal class PPFileParameters
|
|
||||||
{
|
|
||||||
public static IDictionary<string, string> CreateForProject(Project project)
|
|
||||||
{
|
|
||||||
return new Dictionary<string, string>()
|
|
||||||
{
|
|
||||||
{"rootnamespace", project.Name },
|
|
||||||
{"assemblyname", project.Name }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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.IO;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Tools.Compiler
|
|
||||||
{
|
|
||||||
internal class PPFilePreprocessor
|
|
||||||
{
|
|
||||||
public static void Preprocess(Stream input, Stream output, IDictionary<string, string> parameters)
|
|
||||||
{
|
|
||||||
string text;
|
|
||||||
using (var streamReader = new StreamReader(input))
|
|
||||||
{
|
|
||||||
text = streamReader.ReadToEnd();
|
|
||||||
}
|
|
||||||
var tokenizer = new PPFileTokenizer(text);
|
|
||||||
using (var streamWriter = new StreamWriter(output))
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
var token = tokenizer.Read();
|
|
||||||
if (token == null)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (token.Category == PPFileTokenizer.TokenCategory.Variable)
|
|
||||||
{
|
|
||||||
var replaced = ReplaceToken(token.Value, parameters);
|
|
||||||
streamWriter.Write(replaced);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
streamWriter.Write(token.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ReplaceToken(string name, IDictionary<string, string> parameters)
|
|
||||||
{
|
|
||||||
string value;
|
|
||||||
if (!parameters.TryGetValue(name, out value))
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"The replacement token '{name}' has no value.");
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,124 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Tools.Compiler
|
|
||||||
{
|
|
||||||
internal class PPFileTokenizer
|
|
||||||
{
|
|
||||||
private readonly string _text;
|
|
||||||
private int _index;
|
|
||||||
|
|
||||||
public PPFileTokenizer(string text)
|
|
||||||
{
|
|
||||||
_text = text;
|
|
||||||
_index = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the next token.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The parsed token. Or null if no more tokens are available.</returns>
|
|
||||||
public Token Read()
|
|
||||||
{
|
|
||||||
if (_index >= _text.Length)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_text[_index] == '$')
|
|
||||||
{
|
|
||||||
_index++;
|
|
||||||
return ParseTokenAfterDollarSign();
|
|
||||||
}
|
|
||||||
return ParseText();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsWordChar(char ch)
|
|
||||||
{
|
|
||||||
// See http://msdn.microsoft.com/en-us/library/20bw873z.aspx#WordCharacter
|
|
||||||
var c = CharUnicodeInfo.GetUnicodeCategory(ch);
|
|
||||||
return c == UnicodeCategory.LowercaseLetter ||
|
|
||||||
c == UnicodeCategory.UppercaseLetter ||
|
|
||||||
c == UnicodeCategory.TitlecaseLetter ||
|
|
||||||
c == UnicodeCategory.OtherLetter ||
|
|
||||||
c == UnicodeCategory.ModifierLetter ||
|
|
||||||
c == UnicodeCategory.DecimalDigitNumber ||
|
|
||||||
c == UnicodeCategory.ConnectorPunctuation;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parses and returns the next token after a $ is just read.
|
|
||||||
// _index is one char after the $.
|
|
||||||
private Token ParseTokenAfterDollarSign()
|
|
||||||
{
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
while (_index < _text.Length)
|
|
||||||
{
|
|
||||||
var ch = _text[_index];
|
|
||||||
if (ch == '$')
|
|
||||||
{
|
|
||||||
++_index;
|
|
||||||
if (sb.Length == 0)
|
|
||||||
{
|
|
||||||
// escape sequence "$$" is encountered
|
|
||||||
return new Token(TokenCategory.Text, "$");
|
|
||||||
}
|
|
||||||
// matching $ is read. So the token is a variable.
|
|
||||||
return new Token(TokenCategory.Variable, sb.ToString());
|
|
||||||
}
|
|
||||||
if (IsWordChar(ch))
|
|
||||||
{
|
|
||||||
sb.Append(ch);
|
|
||||||
++_index;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// non word char encountered. So the current token
|
|
||||||
// is not a variable after all.
|
|
||||||
sb.Insert(0, '$');
|
|
||||||
sb.Append(ch);
|
|
||||||
++_index;
|
|
||||||
return new Token(TokenCategory.Text, sb.ToString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// no matching $ is found and the end of text is reached.
|
|
||||||
// So the current token is a text.
|
|
||||||
sb.Insert(0, '$');
|
|
||||||
return new Token(TokenCategory.Text, sb.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Token ParseText()
|
|
||||||
{
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
while (_index < _text.Length
|
|
||||||
&& _text[_index] != '$')
|
|
||||||
{
|
|
||||||
sb.Append(_text[_index]);
|
|
||||||
_index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Token(TokenCategory.Text, sb.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class Token
|
|
||||||
{
|
|
||||||
public string Value { get; private set; }
|
|
||||||
public TokenCategory Category { get; private set; }
|
|
||||||
|
|
||||||
public Token(TokenCategory category, string value)
|
|
||||||
{
|
|
||||||
Category = category;
|
|
||||||
Value = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum TokenCategory
|
|
||||||
{
|
|
||||||
Text,
|
|
||||||
Variable
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,104 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.Files;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.Resources;
|
|
||||||
using NuGet.Frameworks;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
internal class CompilationOutputFiles
|
|
||||||
{
|
|
||||||
protected readonly Project Project;
|
|
||||||
protected readonly string Configuration;
|
|
||||||
protected readonly NuGetFramework Framework;
|
|
||||||
|
|
||||||
public CompilationOutputFiles(
|
|
||||||
string basePath,
|
|
||||||
Project project,
|
|
||||||
string configuration,
|
|
||||||
NuGetFramework framework)
|
|
||||||
{
|
|
||||||
BasePath = basePath;
|
|
||||||
Project = project;
|
|
||||||
Configuration = configuration;
|
|
||||||
Framework = framework;
|
|
||||||
OutputExtension = FileNameSuffixes.DotNet.DynamicLib;
|
|
||||||
|
|
||||||
var compilerOptions = Project.GetCompilerOptions(framework, configuration);
|
|
||||||
if (framework.IsDesktop() && compilerOptions.EmitEntryPoint.GetValueOrDefault())
|
|
||||||
{
|
|
||||||
OutputExtension = FileNameSuffixes.DotNet.Exe;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string BasePath { get; }
|
|
||||||
|
|
||||||
public string Assembly
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var compilerOptions = Project.GetCompilerOptions(Framework, Configuration);
|
|
||||||
|
|
||||||
return Path.Combine(BasePath, compilerOptions.OutputName + OutputExtension);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string PdbPath
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return Path.ChangeExtension(Assembly, FileNameSuffixes.CurrentPlatform.ProgramDatabase);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string OutputExtension { get; }
|
|
||||||
|
|
||||||
public virtual IEnumerable<ResourceFile> Resources()
|
|
||||||
{
|
|
||||||
var resourceCultureNames = GetResourceFiles()
|
|
||||||
.Select(f => ResourceUtility.GetResourceCultureName(f))
|
|
||||||
.Where(f => !string.IsNullOrEmpty(f))
|
|
||||||
.Distinct();
|
|
||||||
|
|
||||||
foreach (var resourceCultureName in resourceCultureNames)
|
|
||||||
{
|
|
||||||
yield return new ResourceFile(
|
|
||||||
Path.Combine(
|
|
||||||
BasePath, resourceCultureName, Project.Name + ".resources" + FileNameSuffixes.DotNet.DynamicLib),
|
|
||||||
resourceCultureName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual IEnumerable<string> All()
|
|
||||||
{
|
|
||||||
yield return Assembly;
|
|
||||||
yield return PdbPath;
|
|
||||||
var compilerOptions = Project.GetCompilerOptions(Framework, Configuration);
|
|
||||||
if (compilerOptions.GenerateXmlDocumentation == true)
|
|
||||||
{
|
|
||||||
yield return Path.ChangeExtension(Assembly, "xml");
|
|
||||||
}
|
|
||||||
foreach (var resource in Resources())
|
|
||||||
{
|
|
||||||
yield return resource.Path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<string> GetResourceFiles()
|
|
||||||
{
|
|
||||||
var compilerOptions = Project.GetCompilerOptions(Framework, Configuration);
|
|
||||||
if (compilerOptions.EmbedInclude == null)
|
|
||||||
{
|
|
||||||
return Project.Files.ResourceFiles.Keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
var includeFiles = IncludeFilesResolver.GetIncludeFiles(compilerOptions.EmbedInclude, "/", diagnostics: null);
|
|
||||||
|
|
||||||
return includeFiles.Select(f => f.SourcePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
internal static class Constants
|
|
||||||
{
|
|
||||||
public static readonly string DefaultOutputDirectory = "bin";
|
|
||||||
public static readonly string DefaultConfiguration = "Debug";
|
|
||||||
|
|
||||||
public static readonly string LocaleLockFilePropertyName = "locale";
|
|
||||||
|
|
||||||
public static readonly Version Version50 = new Version(5, 0);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,240 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.Compilation;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.Resolution;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.Utilities;
|
|
||||||
using NuGet.Frameworks;
|
|
||||||
using NuGet.LibraryModel;
|
|
||||||
|
|
||||||
namespace Microsoft.Extensions.DependencyModel
|
|
||||||
{
|
|
||||||
internal class DependencyContextBuilder
|
|
||||||
{
|
|
||||||
private readonly string _referenceAssembliesPath;
|
|
||||||
|
|
||||||
public DependencyContextBuilder() : this(FrameworkReferenceResolver.Default.ReferenceAssembliesPath)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public DependencyContextBuilder(string referenceAssembliesPath)
|
|
||||||
{
|
|
||||||
_referenceAssembliesPath = referenceAssembliesPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DependencyContext Build(CommonCompilerOptions compilerOptions,
|
|
||||||
IEnumerable<LibraryExport> compilationExports,
|
|
||||||
IEnumerable<LibraryExport> runtimeExports,
|
|
||||||
bool portable,
|
|
||||||
NuGetFramework target,
|
|
||||||
string runtime)
|
|
||||||
{
|
|
||||||
if (compilationExports == null)
|
|
||||||
{
|
|
||||||
compilationExports = Enumerable.Empty<LibraryExport>();
|
|
||||||
}
|
|
||||||
|
|
||||||
var dependencyLookup = compilationExports
|
|
||||||
.Concat(runtimeExports)
|
|
||||||
.Select(export => export.Library.Identity)
|
|
||||||
.Distinct()
|
|
||||||
.Select(identity => new Dependency(identity.Name, identity.Version.ToString()))
|
|
||||||
.ToDictionary(dependency => dependency.Name, StringComparer.OrdinalIgnoreCase);
|
|
||||||
|
|
||||||
var compilationOptions = compilerOptions != null
|
|
||||||
? GetCompilationOptions(compilerOptions)
|
|
||||||
: CompilationOptions.Default;
|
|
||||||
|
|
||||||
var runtimeSignature = GenerateRuntimeSignature(runtimeExports);
|
|
||||||
|
|
||||||
return new DependencyContext(
|
|
||||||
new TargetInfo(target.DotNetFrameworkName, runtime, runtimeSignature, portable),
|
|
||||||
compilationOptions,
|
|
||||||
GetLibraries(compilationExports, dependencyLookup, runtime: false).Cast<CompilationLibrary>(),
|
|
||||||
GetLibraries(runtimeExports, dependencyLookup, runtime: true).Cast<RuntimeLibrary>(),
|
|
||||||
new RuntimeFallbacks[] {});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GenerateRuntimeSignature(IEnumerable<LibraryExport> runtimeExports)
|
|
||||||
{
|
|
||||||
var sha1 = SHA1.Create();
|
|
||||||
var builder = new StringBuilder();
|
|
||||||
var packages = runtimeExports
|
|
||||||
.Where(libraryExport => libraryExport.Library.Identity.Type == LibraryType.Package);
|
|
||||||
var seperator = "|";
|
|
||||||
foreach (var libraryExport in packages)
|
|
||||||
{
|
|
||||||
builder.Append(libraryExport.Library.Identity.Name);
|
|
||||||
builder.Append(seperator);
|
|
||||||
builder.Append(libraryExport.Library.Identity.Version.ToString());
|
|
||||||
builder.Append(seperator);
|
|
||||||
}
|
|
||||||
var hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(builder.ToString()));
|
|
||||||
|
|
||||||
builder.Clear();
|
|
||||||
foreach (var b in hash)
|
|
||||||
{
|
|
||||||
builder.AppendFormat("{0:x2}", b);
|
|
||||||
}
|
|
||||||
return builder.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static CompilationOptions GetCompilationOptions(CommonCompilerOptions compilerOptions)
|
|
||||||
{
|
|
||||||
return new CompilationOptions(compilerOptions.Defines,
|
|
||||||
compilerOptions.LanguageVersion,
|
|
||||||
compilerOptions.Platform,
|
|
||||||
compilerOptions.AllowUnsafe,
|
|
||||||
compilerOptions.WarningsAsErrors,
|
|
||||||
compilerOptions.Optimize,
|
|
||||||
compilerOptions.KeyFile,
|
|
||||||
compilerOptions.DelaySign,
|
|
||||||
compilerOptions.PublicSign,
|
|
||||||
compilerOptions.DebugType,
|
|
||||||
compilerOptions.EmitEntryPoint,
|
|
||||||
compilerOptions.GenerateXmlDocumentation);
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<Library> GetLibraries(IEnumerable<LibraryExport> exports,
|
|
||||||
IDictionary<string, Dependency> dependencyLookup,
|
|
||||||
bool runtime)
|
|
||||||
{
|
|
||||||
return exports.Select(export => GetLibrary(export, runtime, dependencyLookup));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Library GetLibrary(LibraryExport export,
|
|
||||||
bool runtime,
|
|
||||||
IDictionary<string, Dependency> dependencyLookup)
|
|
||||||
{
|
|
||||||
var type = export.Library.Identity.Type;
|
|
||||||
|
|
||||||
// TEMPORARY: All packages are serviceable in RC2
|
|
||||||
// See https://github.com/dotnet/cli/issues/2569
|
|
||||||
var serviceable = (export.Library as PackageDescription) != null;
|
|
||||||
var libraryDependencies = new HashSet<Dependency>();
|
|
||||||
|
|
||||||
foreach (var libraryDependency in export.Library.Dependencies)
|
|
||||||
{
|
|
||||||
// skip build time dependencies
|
|
||||||
if (libraryDependency.Type.Equals(LibraryDependencyType.Build))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Dependency dependency;
|
|
||||||
if (dependencyLookup.TryGetValue(libraryDependency.Name, out dependency))
|
|
||||||
{
|
|
||||||
libraryDependencies.Add(dependency);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (runtime)
|
|
||||||
{
|
|
||||||
return new RuntimeLibrary(
|
|
||||||
type.ToString().ToLowerInvariant(),
|
|
||||||
export.Library.Identity.Name,
|
|
||||||
export.Library.Identity.Version.ToString(),
|
|
||||||
export.Library.Hash,
|
|
||||||
export.RuntimeAssemblyGroups.Select(CreateRuntimeAssetGroup).ToArray(),
|
|
||||||
export.NativeLibraryGroups.Select(CreateRuntimeAssetGroup).ToArray(),
|
|
||||||
export.ResourceAssemblies.Select(CreateResourceAssembly),
|
|
||||||
libraryDependencies,
|
|
||||||
serviceable,
|
|
||||||
GetLibraryPath(export.Library),
|
|
||||||
GetLibraryHashPath(export.Library));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
IEnumerable<string> assemblies;
|
|
||||||
if (type == LibraryType.Reference)
|
|
||||||
{
|
|
||||||
assemblies = ResolveReferenceAssembliesPath(export.CompilationAssemblies);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
assemblies = export.CompilationAssemblies.Select(libraryAsset => libraryAsset.RelativePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new CompilationLibrary(
|
|
||||||
type.ToString().ToLowerInvariant(),
|
|
||||||
export.Library.Identity.Name,
|
|
||||||
export.Library.Identity.Version.ToString(),
|
|
||||||
export.Library.Hash,
|
|
||||||
assemblies,
|
|
||||||
libraryDependencies,
|
|
||||||
serviceable,
|
|
||||||
GetLibraryPath(export.Library),
|
|
||||||
GetLibraryHashPath(export.Library));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetLibraryPath(LibraryDescription description)
|
|
||||||
{
|
|
||||||
var packageDescription = description as PackageDescription;
|
|
||||||
|
|
||||||
if (packageDescription != null)
|
|
||||||
{
|
|
||||||
// This is the relative path appended to a NuGet packages directory to find the directory containing
|
|
||||||
// the package assets. This string should only be mastered by NuGet.
|
|
||||||
return packageDescription.PackageLibrary?.Path;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetLibraryHashPath(LibraryDescription description)
|
|
||||||
{
|
|
||||||
var packageDescription = description as PackageDescription;
|
|
||||||
|
|
||||||
if (packageDescription != null)
|
|
||||||
{
|
|
||||||
// This hash path appended to the package path (much like package assets). This string should only be
|
|
||||||
// mastered by NuGet.
|
|
||||||
return packageDescription.HashPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private RuntimeAssetGroup CreateRuntimeAssetGroup(LibraryAssetGroup libraryAssetGroup)
|
|
||||||
{
|
|
||||||
return new RuntimeAssetGroup(
|
|
||||||
libraryAssetGroup.Runtime,
|
|
||||||
libraryAssetGroup.Assets.Select(a => a.RelativePath));
|
|
||||||
}
|
|
||||||
|
|
||||||
private ResourceAssembly CreateResourceAssembly(LibraryResourceAssembly resourceAssembly)
|
|
||||||
{
|
|
||||||
return new ResourceAssembly(
|
|
||||||
path: resourceAssembly.Asset.RelativePath,
|
|
||||||
locale: resourceAssembly.Locale
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<string> ResolveReferenceAssembliesPath(IEnumerable<LibraryAsset> libraryAssets)
|
|
||||||
{
|
|
||||||
var referenceAssembliesPath =
|
|
||||||
PathUtility.EnsureTrailingSlash(_referenceAssembliesPath);
|
|
||||||
foreach (var libraryAsset in libraryAssets)
|
|
||||||
{
|
|
||||||
// If resolved path is under ReferenceAssembliesPath store it as a relative to it
|
|
||||||
// if not, save only assembly name and try to find it somehow later
|
|
||||||
if (libraryAsset.ResolvedPath.StartsWith(referenceAssembliesPath))
|
|
||||||
{
|
|
||||||
yield return libraryAsset.ResolvedPath.Substring(referenceAssembliesPath.Length);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
yield return Path.GetFileName(libraryAsset.ResolvedPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,148 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using NuGet.LibraryModel;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
internal class DesignTimeWorkspace : Workspace
|
|
||||||
{
|
|
||||||
private readonly HashSet<string> _projects = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
|
||||||
|
|
||||||
private bool _needRefresh;
|
|
||||||
|
|
||||||
public DesignTimeWorkspace(ProjectReaderSettings settings) : base(settings, true) { }
|
|
||||||
|
|
||||||
public void AddProject(string path)
|
|
||||||
{
|
|
||||||
var projectPath = ProjectPathHelper.NormalizeProjectDirectoryPath(path);
|
|
||||||
|
|
||||||
if (projectPath != null)
|
|
||||||
{
|
|
||||||
_needRefresh = _projects.Add(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveProject(string path)
|
|
||||||
{
|
|
||||||
_needRefresh = _projects.Remove(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Refresh all cached projects in the Workspace
|
|
||||||
/// </summary>
|
|
||||||
public void Refresh()
|
|
||||||
{
|
|
||||||
if (!_needRefresh)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var basePaths = new List<string>(_projects);
|
|
||||||
_projects.Clear();
|
|
||||||
|
|
||||||
foreach (var projectDirectory in basePaths)
|
|
||||||
{
|
|
||||||
var project = GetProject(projectDirectory);
|
|
||||||
if (project == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
_projects.Add(project.ProjectDirectory);
|
|
||||||
|
|
||||||
foreach (var projectContext in GetProjectContextCollection(project.ProjectDirectory).ProjectContexts)
|
|
||||||
{
|
|
||||||
foreach (var reference in GetProjectReferences(projectContext))
|
|
||||||
{
|
|
||||||
var referencedProject = GetProject(reference.Path);
|
|
||||||
if (referencedProject != null)
|
|
||||||
{
|
|
||||||
_projects.Add(referencedProject.ProjectDirectory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_needRefresh = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override IEnumerable<ProjectContext> BuildProjectContexts(Project project)
|
|
||||||
{
|
|
||||||
foreach (var framework in project.GetTargetFrameworks())
|
|
||||||
{
|
|
||||||
yield return CreateBaseProjectBuilder(project)
|
|
||||||
.AsDesignTime()
|
|
||||||
.WithTargetFramework(framework.FrameworkName)
|
|
||||||
.Build();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<string> ResolveProjectPath(string projectPath)
|
|
||||||
{
|
|
||||||
if (File.Exists(projectPath))
|
|
||||||
{
|
|
||||||
var filename = Path.GetFileName(projectPath);
|
|
||||||
if (!Project.FileName.Equals(filename, StringComparison.OrdinalIgnoreCase) &&
|
|
||||||
!GlobalSettings.FileName.Equals(filename, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
projectPath = Path.GetDirectoryName(projectPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (File.Exists(Path.Combine(projectPath, Project.FileName)))
|
|
||||||
{
|
|
||||||
return new List<string> { projectPath };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (File.Exists(Path.Combine(projectPath, GlobalSettings.FileName)))
|
|
||||||
{
|
|
||||||
var root = ProjectRootResolver.ResolveRootDirectory(projectPath);
|
|
||||||
GlobalSettings globalSettings;
|
|
||||||
if (GlobalSettings.TryGetGlobalSettings(projectPath, out globalSettings))
|
|
||||||
{
|
|
||||||
return globalSettings.ProjectSearchPaths
|
|
||||||
.Select(searchPath => Path.Combine(globalSettings.DirectoryPath, searchPath))
|
|
||||||
.Where(actualPath => Directory.Exists(actualPath))
|
|
||||||
.SelectMany(actualPath => Directory.GetDirectories(actualPath))
|
|
||||||
.Where(actualPath => File.Exists(Path.Combine(actualPath, Project.FileName)))
|
|
||||||
.Select(path => Path.GetFullPath(path))
|
|
||||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
|
||||||
.ToList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<ProjectDescription> GetProjectReferences(ProjectContext context)
|
|
||||||
{
|
|
||||||
var projectDescriptions = context.LibraryManager
|
|
||||||
.GetLibraries()
|
|
||||||
.Where(lib => lib.Identity.Type == LibraryType.Project)
|
|
||||||
.OfType<ProjectDescription>();
|
|
||||||
|
|
||||||
foreach (var description in projectDescriptions)
|
|
||||||
{
|
|
||||||
if (description.Identity.Name == context.ProjectFile.Name)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if this is an assembly reference then don't threat it as project reference
|
|
||||||
if (!string.IsNullOrEmpty(description.TargetFrameworkInfo?.AssemblyPath))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
yield return description;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,132 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a single diagnostic message, such as a compilation error or a project.json parsing error.
|
|
||||||
/// </summary>
|
|
||||||
internal class DiagnosticMessage
|
|
||||||
{
|
|
||||||
public DiagnosticMessage(string errorCode, string message, string filePath, DiagnosticMessageSeverity severity)
|
|
||||||
: this(errorCode, message, filePath, severity, startLine: 1, startColumn: 0)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
public DiagnosticMessage(string errorCode, string message, string filePath, DiagnosticMessageSeverity severity, int startLine, int startColumn)
|
|
||||||
: this(
|
|
||||||
errorCode,
|
|
||||||
message,
|
|
||||||
$"{filePath}({startLine},{startColumn}): {severity.ToString().ToLowerInvariant()} {errorCode}: {message}",
|
|
||||||
filePath,
|
|
||||||
severity,
|
|
||||||
startLine,
|
|
||||||
startColumn,
|
|
||||||
endLine: startLine,
|
|
||||||
endColumn: startColumn,
|
|
||||||
source: null)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
public DiagnosticMessage(string errorCode, string message, string filePath, DiagnosticMessageSeverity severity, int startLine, int startColumn, LibraryDescription source)
|
|
||||||
: this(
|
|
||||||
errorCode,
|
|
||||||
message,
|
|
||||||
$"{filePath}({startLine},{startColumn}): {severity.ToString().ToLowerInvariant()} {errorCode}: {message}",
|
|
||||||
filePath,
|
|
||||||
severity,
|
|
||||||
startLine,
|
|
||||||
startColumn,
|
|
||||||
endLine: startLine,
|
|
||||||
endColumn: startColumn,
|
|
||||||
source: source)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
public DiagnosticMessage(string errorCode, string message, string formattedMessage, string filePath,
|
|
||||||
DiagnosticMessageSeverity severity, int startLine, int startColumn, int endLine, int endColumn)
|
|
||||||
: this(errorCode,
|
|
||||||
message,
|
|
||||||
formattedMessage,
|
|
||||||
filePath,
|
|
||||||
severity,
|
|
||||||
startLine,
|
|
||||||
startColumn,
|
|
||||||
endLine,
|
|
||||||
endColumn,
|
|
||||||
source: null)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public DiagnosticMessage(
|
|
||||||
string errorCode,
|
|
||||||
string message,
|
|
||||||
string formattedMessage,
|
|
||||||
string filePath,
|
|
||||||
DiagnosticMessageSeverity severity,
|
|
||||||
int startLine,
|
|
||||||
int startColumn,
|
|
||||||
int endLine,
|
|
||||||
int endColumn,
|
|
||||||
LibraryDescription source)
|
|
||||||
{
|
|
||||||
ErrorCode = errorCode;
|
|
||||||
Message = message;
|
|
||||||
SourceFilePath = filePath;
|
|
||||||
Severity = severity;
|
|
||||||
StartLine = startLine;
|
|
||||||
EndLine = endLine;
|
|
||||||
StartColumn = startColumn;
|
|
||||||
EndColumn = endColumn;
|
|
||||||
FormattedMessage = formattedMessage;
|
|
||||||
Source = source;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The moniker associated with the error message
|
|
||||||
/// </summary>
|
|
||||||
public string ErrorCode { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Path of the file that produced the message.
|
|
||||||
/// </summary>
|
|
||||||
public string SourceFilePath { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the error message.
|
|
||||||
/// </summary>
|
|
||||||
public string Message { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <see cref="DiagnosticMessageSeverity"/>.
|
|
||||||
/// </summary>
|
|
||||||
public DiagnosticMessageSeverity Severity { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the one-based line index for the start of the compilation error.
|
|
||||||
/// </summary>
|
|
||||||
public int StartLine { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the zero-based column index for the start of the compilation error.
|
|
||||||
/// </summary>
|
|
||||||
public int StartColumn { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the one-based line index for the end of the compilation error.
|
|
||||||
/// </summary>
|
|
||||||
public int EndLine { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the zero-based column index for the end of the compilation error.
|
|
||||||
/// </summary>
|
|
||||||
public int EndColumn { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the formatted error message.
|
|
||||||
/// </summary>
|
|
||||||
public string FormattedMessage { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the source of this message
|
|
||||||
/// </summary>
|
|
||||||
public LibraryDescription Source { get; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Specifies the severity of a <see cref="DiagnosticMessage"/>.
|
|
||||||
/// </summary>
|
|
||||||
public enum DiagnosticMessageSeverity
|
|
||||||
{
|
|
||||||
Info,
|
|
||||||
Warning,
|
|
||||||
Error,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
internal static class DirectoryNames
|
|
||||||
{
|
|
||||||
public const string Bin = "bin";
|
|
||||||
|
|
||||||
public const string Obj = "obj";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
internal class EnvironmentNames
|
|
||||||
{
|
|
||||||
public static readonly string PackagesStore = "NUGET_PACKAGES";
|
|
||||||
public static readonly string StrongNameKeyFile = "DOTNET_BUILD_STRONG_NAME_KEYFILE";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
internal static partial class ErrorCodes
|
|
||||||
{
|
|
||||||
// Target framework not installed
|
|
||||||
public static readonly string DOTNET1011 = nameof(DOTNET1011);
|
|
||||||
|
|
||||||
// Reference assemblies location not specified
|
|
||||||
public static readonly string DOTNET1012 = nameof(DOTNET1012);
|
|
||||||
|
|
||||||
// Multiple libraries marked as "platform"
|
|
||||||
public static readonly string DOTNET1013 = nameof(DOTNET1013);
|
|
||||||
|
|
||||||
// Failed to read lock file
|
|
||||||
public static readonly string DOTNET1014 = nameof(DOTNET1014);
|
|
||||||
|
|
||||||
// The '{0}' option is deprecated. Use '{1}' instead.
|
|
||||||
public static readonly string DOTNET1015 = nameof(DOTNET1015);
|
|
||||||
|
|
||||||
// The '{0}' option in the root is deprecated. Use it in '{1}' instead.
|
|
||||||
public static readonly string DOTNET1016 = nameof(DOTNET1016);
|
|
||||||
|
|
||||||
// Project file does not exist '{0}'.
|
|
||||||
public static readonly string DOTNET1017 = nameof(DOTNET1017);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
internal static partial class ErrorCodes
|
|
||||||
{
|
|
||||||
// The dependency A could not be resolved.
|
|
||||||
public static readonly string NU1001 = nameof(NU1001);
|
|
||||||
|
|
||||||
// The dependency A in project B does not support framework C."
|
|
||||||
public static readonly string NU1002 = nameof(NU1002);
|
|
||||||
|
|
||||||
// Invalid A section. The target B is invalid, targets must either be a file name or a directory suffixed with '/'. The root directory of the package can be specified by using a single '/' character.
|
|
||||||
public static readonly string NU1003 = nameof(NU1003);
|
|
||||||
|
|
||||||
// Invalid A section. The target B contains path-traversal characters ('.' or '..'). These characters are not permitted in target paths.
|
|
||||||
public static readonly string NU1004 = nameof(NU1004);
|
|
||||||
|
|
||||||
// Invalid A section. The target B refers to a single file, but the pattern C produces multiple files. To mark the target as a directory, suffix it with '/'.
|
|
||||||
public static readonly string NU1005 = nameof(NU1005);
|
|
||||||
|
|
||||||
// A. Please run \"dotnet restore\" to generate a new lock file.
|
|
||||||
public static readonly string NU1006 = nameof(NU1006);
|
|
||||||
|
|
||||||
// Dependency specified was A but ended up with B.
|
|
||||||
public static readonly string NU1007 = nameof(NU1007);
|
|
||||||
|
|
||||||
// A is an unsupported framework.
|
|
||||||
public static readonly string NU1008 = nameof(NU1008);
|
|
||||||
|
|
||||||
// The expected lock file doesn't exist. Please run \"dotnet restore\" to generate a new lock file.
|
|
||||||
public static readonly string NU1009 = nameof(NU1009);
|
|
||||||
|
|
||||||
// The dependency type was changed
|
|
||||||
public static readonly string NU1010 = nameof(NU1010);
|
|
||||||
|
|
||||||
// The dependency target '{0}' is unsupported.
|
|
||||||
public static readonly string NU1011 = nameof(NU1011);
|
|
||||||
|
|
||||||
// Dependency conflict.
|
|
||||||
public static readonly string NU1012 = nameof(NU1012);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,127 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
public sealed class FileFormatException : Exception
|
|
||||||
{
|
|
||||||
private FileFormatException(string message) :
|
|
||||||
base(message)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
private FileFormatException(string message, Exception innerException) :
|
|
||||||
base(message, innerException)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Path { get; private set; }
|
|
||||||
public int Line { get; private set; }
|
|
||||||
public int Column { get; private set; }
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return $"{Path}({Line},{Column}): Error: {base.ToString()}";
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static FileFormatException Create(Exception exception, string filePath)
|
|
||||||
{
|
|
||||||
return new FileFormatException(exception.Message, exception)
|
|
||||||
.WithFilePath(filePath)
|
|
||||||
.WithLineInfo(exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static FileFormatException Create(Exception exception, JToken jsonValue, string filePath)
|
|
||||||
{
|
|
||||||
var result = Create(exception, jsonValue)
|
|
||||||
.WithFilePath(filePath);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static FileFormatException Create(Exception exception, JToken jsonValue)
|
|
||||||
{
|
|
||||||
var result = new FileFormatException(exception.Message, exception)
|
|
||||||
.WithLineInfo(jsonValue);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static FileFormatException Create(string message, JToken jsonValue, string filePath)
|
|
||||||
{
|
|
||||||
var result = Create(message, jsonValue)
|
|
||||||
.WithFilePath(filePath);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static FileFormatException Create(string message, string filePath)
|
|
||||||
{
|
|
||||||
var result = new FileFormatException(message)
|
|
||||||
.WithFilePath(filePath);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static FileFormatException Create(string message, JToken jsonValue)
|
|
||||||
{
|
|
||||||
var result = new FileFormatException(message)
|
|
||||||
.WithLineInfo(jsonValue);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal FileFormatException WithFilePath(string path)
|
|
||||||
{
|
|
||||||
if (path == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(path));
|
|
||||||
}
|
|
||||||
|
|
||||||
Path = path;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private FileFormatException WithLineInfo(Exception exception)
|
|
||||||
{
|
|
||||||
if (exception is JsonReaderException)
|
|
||||||
{
|
|
||||||
WithLineInfo((JsonReaderException) exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private FileFormatException WithLineInfo(JsonReaderException exception)
|
|
||||||
{
|
|
||||||
if (exception == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(exception));
|
|
||||||
}
|
|
||||||
|
|
||||||
Line = exception.LineNumber;
|
|
||||||
Column = exception.LinePosition;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private FileFormatException WithLineInfo(JToken value)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
var lineInfo = (IJsonLineInfo)value;
|
|
||||||
Line = lineInfo.LineNumber;
|
|
||||||
Column = lineInfo.LinePosition;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,76 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.DotNet.PlatformAbstractions;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
internal static class FileNameSuffixes
|
|
||||||
{
|
|
||||||
public const string DepsJson = ".deps.json";
|
|
||||||
public const string RuntimeConfigJson = ".runtimeconfig.json";
|
|
||||||
public const string RuntimeConfigDevJson = ".runtimeconfig.dev.json";
|
|
||||||
|
|
||||||
public static PlatformFileNameSuffixes CurrentPlatform
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
switch (RuntimeEnvironment.OperatingSystemPlatform)
|
|
||||||
{
|
|
||||||
case Platform.Windows:
|
|
||||||
return Windows;
|
|
||||||
case Platform.Darwin:
|
|
||||||
return OSX;
|
|
||||||
case Platform.Linux:
|
|
||||||
return Linux;
|
|
||||||
default:
|
|
||||||
throw new InvalidOperationException("Unknown Platform");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PlatformFileNameSuffixes DotNet { get; } = new PlatformFileNameSuffixes
|
|
||||||
{
|
|
||||||
DynamicLib = ".dll",
|
|
||||||
Exe = ".exe",
|
|
||||||
ProgramDatabase = ".pdb",
|
|
||||||
StaticLib = ".lib"
|
|
||||||
};
|
|
||||||
|
|
||||||
public static PlatformFileNameSuffixes Windows { get; } = new PlatformFileNameSuffixes
|
|
||||||
{
|
|
||||||
DynamicLib = ".dll",
|
|
||||||
Exe = ".exe",
|
|
||||||
ProgramDatabase = ".pdb",
|
|
||||||
StaticLib = ".lib"
|
|
||||||
};
|
|
||||||
|
|
||||||
public static PlatformFileNameSuffixes OSX { get; } = new PlatformFileNameSuffixes
|
|
||||||
{
|
|
||||||
DynamicLib = ".dylib",
|
|
||||||
Exe = "",
|
|
||||||
ProgramDatabase = ".pdb",
|
|
||||||
StaticLib = ".a"
|
|
||||||
};
|
|
||||||
|
|
||||||
public static PlatformFileNameSuffixes Linux { get; } = new PlatformFileNameSuffixes
|
|
||||||
{
|
|
||||||
DynamicLib = ".so",
|
|
||||||
Exe = "",
|
|
||||||
ProgramDatabase = ".pdb",
|
|
||||||
StaticLib = ".a"
|
|
||||||
};
|
|
||||||
|
|
||||||
public struct PlatformFileNameSuffixes
|
|
||||||
{
|
|
||||||
public string DynamicLib { get; internal set; }
|
|
||||||
|
|
||||||
public string Exe { get; internal set; }
|
|
||||||
|
|
||||||
public string ProgramDatabase { get; internal set; }
|
|
||||||
|
|
||||||
public string StaticLib { get; internal set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Abstractions
|
|
||||||
{
|
|
||||||
internal abstract class DirectoryInfoBase : FileSystemInfoBase
|
|
||||||
{
|
|
||||||
public abstract IEnumerable<FileSystemInfoBase> EnumerateFileSystemInfos();
|
|
||||||
|
|
||||||
public abstract DirectoryInfoBase GetDirectory(string path);
|
|
||||||
|
|
||||||
public abstract FileInfoBase GetFile(string path);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,89 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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.IO;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Abstractions
|
|
||||||
{
|
|
||||||
internal class DirectoryInfoWrapper : DirectoryInfoBase
|
|
||||||
{
|
|
||||||
private readonly DirectoryInfo _directoryInfo;
|
|
||||||
private readonly bool _isParentPath;
|
|
||||||
|
|
||||||
public DirectoryInfoWrapper(DirectoryInfo directoryInfo, bool isParentPath = false)
|
|
||||||
{
|
|
||||||
_directoryInfo = directoryInfo;
|
|
||||||
_isParentPath = isParentPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IEnumerable<FileSystemInfoBase> EnumerateFileSystemInfos()
|
|
||||||
{
|
|
||||||
if (_directoryInfo.Exists)
|
|
||||||
{
|
|
||||||
foreach (var fileSystemInfo in _directoryInfo.EnumerateFileSystemInfos("*", SearchOption.TopDirectoryOnly))
|
|
||||||
{
|
|
||||||
var directoryInfo = fileSystemInfo as DirectoryInfo;
|
|
||||||
if (directoryInfo != null)
|
|
||||||
{
|
|
||||||
yield return new DirectoryInfoWrapper(directoryInfo);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
yield return new FileInfoWrapper((FileInfo)fileSystemInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override DirectoryInfoBase GetDirectory(string name)
|
|
||||||
{
|
|
||||||
var isParentPath = string.Equals(name, "..", StringComparison.Ordinal);
|
|
||||||
|
|
||||||
if (isParentPath)
|
|
||||||
{
|
|
||||||
return new DirectoryInfoWrapper(new DirectoryInfo(Path.Combine(_directoryInfo.FullName, name)), isParentPath);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var dirs = _directoryInfo.GetDirectories(name);
|
|
||||||
|
|
||||||
if (dirs.Length == 1)
|
|
||||||
{
|
|
||||||
return new DirectoryInfoWrapper(dirs[0], isParentPath);
|
|
||||||
}
|
|
||||||
else if (dirs.Length == 0)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// This shouldn't happen. The parameter name isn't supposed to contain wild card.
|
|
||||||
throw new InvalidOperationException(
|
|
||||||
string.Format("More than one sub directories are found under {0} with name {1}.", _directoryInfo.FullName, name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override FileInfoBase GetFile(string name)
|
|
||||||
{
|
|
||||||
return new FileInfoWrapper(new FileInfo(Path.Combine(_directoryInfo.FullName, name)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string Name
|
|
||||||
{
|
|
||||||
get { return _isParentPath ? ".." : _directoryInfo.Name; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string FullName
|
|
||||||
{
|
|
||||||
get { return _directoryInfo.FullName; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public override DirectoryInfoBase ParentDirectory
|
|
||||||
{
|
|
||||||
get { return new DirectoryInfoWrapper(_directoryInfo.Parent); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Abstractions
|
|
||||||
{
|
|
||||||
internal abstract class FileInfoBase : FileSystemInfoBase
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Abstractions
|
|
||||||
{
|
|
||||||
internal class FileInfoWrapper : FileInfoBase
|
|
||||||
{
|
|
||||||
private FileInfo _fileInfo;
|
|
||||||
|
|
||||||
public FileInfoWrapper(FileInfo fileInfo)
|
|
||||||
{
|
|
||||||
_fileInfo = fileInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string Name
|
|
||||||
{
|
|
||||||
get { return _fileInfo.Name; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string FullName
|
|
||||||
{
|
|
||||||
get { return _fileInfo.FullName; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public override DirectoryInfoBase ParentDirectory
|
|
||||||
{
|
|
||||||
get { return new DirectoryInfoWrapper(_fileInfo.Directory); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Abstractions
|
|
||||||
{
|
|
||||||
internal abstract class FileSystemInfoBase
|
|
||||||
{
|
|
||||||
public abstract string Name { get; }
|
|
||||||
|
|
||||||
public abstract string FullName { get; }
|
|
||||||
|
|
||||||
public abstract DirectoryInfoBase ParentDirectory { get; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.DotNet.PlatformAbstractions;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing
|
|
||||||
{
|
|
||||||
public struct FilePatternMatch : IEquatable<FilePatternMatch>
|
|
||||||
{
|
|
||||||
public string Path { get; }
|
|
||||||
public string Stem { get; }
|
|
||||||
|
|
||||||
public FilePatternMatch(string path, string stem)
|
|
||||||
{
|
|
||||||
Path = path;
|
|
||||||
Stem = stem;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Equals(FilePatternMatch other)
|
|
||||||
{
|
|
||||||
return string.Equals(other.Path, Path, StringComparison.OrdinalIgnoreCase) &&
|
|
||||||
string.Equals(other.Stem, Stem, StringComparison.OrdinalIgnoreCase);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
return Equals((FilePatternMatch)obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
var hashCodeCombiner = HashCodeCombiner.Start();
|
|
||||||
hashCodeCombiner.Add(Path, StringComparer.OrdinalIgnoreCase);
|
|
||||||
hashCodeCombiner.Add(Stem, StringComparer.OrdinalIgnoreCase);
|
|
||||||
|
|
||||||
return hashCodeCombiner.CombinedHash;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Internal
|
|
||||||
{
|
|
||||||
internal interface ILinearPattern : IPattern
|
|
||||||
{
|
|
||||||
IList<IPathSegment> Segments { get; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Internal
|
|
||||||
{
|
|
||||||
internal interface IPathSegment
|
|
||||||
{
|
|
||||||
bool CanProduceStem { get; }
|
|
||||||
|
|
||||||
bool Match(string value);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Internal
|
|
||||||
{
|
|
||||||
internal interface IPattern
|
|
||||||
{
|
|
||||||
IPatternContext CreatePatternContextForInclude();
|
|
||||||
|
|
||||||
IPatternContext CreatePatternContextForExclude();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Abstractions;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Internal
|
|
||||||
{
|
|
||||||
internal interface IPatternContext
|
|
||||||
{
|
|
||||||
void Declare(Action<IPathSegment, bool> onDeclare);
|
|
||||||
|
|
||||||
bool Test(DirectoryInfoBase directory);
|
|
||||||
|
|
||||||
PatternTestResult Test(FileInfoBase file);
|
|
||||||
|
|
||||||
void PushDirectory(DirectoryInfoBase directory);
|
|
||||||
|
|
||||||
void PopDirectory();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Internal
|
|
||||||
{
|
|
||||||
internal interface IRaggedPattern : IPattern
|
|
||||||
{
|
|
||||||
IList<IPathSegment> Segments { get; }
|
|
||||||
|
|
||||||
IList<IPathSegment> StartsWith { get; }
|
|
||||||
|
|
||||||
IList<IList<IPathSegment>> Contains { get; }
|
|
||||||
|
|
||||||
IList<IPathSegment> EndsWith { get; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,250 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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.Linq;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Abstractions;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Internal.PathSegments;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Util;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Internal
|
|
||||||
{
|
|
||||||
internal class MatcherContext
|
|
||||||
{
|
|
||||||
private readonly DirectoryInfoBase _root;
|
|
||||||
private readonly IList<IPatternContext> _includePatternContexts;
|
|
||||||
private readonly IList<IPatternContext> _excludePatternContexts;
|
|
||||||
private readonly IList<FilePatternMatch> _files;
|
|
||||||
|
|
||||||
private readonly HashSet<string> _declaredLiteralFolderSegmentInString;
|
|
||||||
private readonly HashSet<LiteralPathSegment> _declaredLiteralFolderSegments = new HashSet<LiteralPathSegment>();
|
|
||||||
private readonly HashSet<LiteralPathSegment> _declaredLiteralFileSegments = new HashSet<LiteralPathSegment>();
|
|
||||||
|
|
||||||
private bool _declaredParentPathSegment;
|
|
||||||
private bool _declaredWildcardPathSegment;
|
|
||||||
|
|
||||||
private readonly StringComparison _comparisonType;
|
|
||||||
|
|
||||||
public MatcherContext(IEnumerable<IPattern> includePatterns,
|
|
||||||
IEnumerable<IPattern> excludePatterns,
|
|
||||||
DirectoryInfoBase directoryInfo,
|
|
||||||
StringComparison comparison)
|
|
||||||
{
|
|
||||||
_root = directoryInfo;
|
|
||||||
_files = new List<FilePatternMatch>();
|
|
||||||
_comparisonType = comparison;
|
|
||||||
|
|
||||||
_includePatternContexts = includePatterns.Select(pattern => pattern.CreatePatternContextForInclude()).ToList();
|
|
||||||
_excludePatternContexts = excludePatterns.Select(pattern => pattern.CreatePatternContextForExclude()).ToList();
|
|
||||||
|
|
||||||
_declaredLiteralFolderSegmentInString = new HashSet<string>(StringComparisonHelper.GetStringComparer(comparison));
|
|
||||||
}
|
|
||||||
|
|
||||||
public PatternMatchingResult Execute()
|
|
||||||
{
|
|
||||||
_files.Clear();
|
|
||||||
|
|
||||||
Match(_root, parentRelativePath: null);
|
|
||||||
|
|
||||||
return new PatternMatchingResult(_files);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Match(DirectoryInfoBase directory, string parentRelativePath)
|
|
||||||
{
|
|
||||||
// Request all the including and excluding patterns to push current directory onto their status stack.
|
|
||||||
PushDirectory(directory);
|
|
||||||
Declare();
|
|
||||||
|
|
||||||
var entities = new List<FileSystemInfoBase>();
|
|
||||||
if (_declaredWildcardPathSegment || _declaredLiteralFileSegments.Any())
|
|
||||||
{
|
|
||||||
entities.AddRange(directory.EnumerateFileSystemInfos());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var candidates = directory.EnumerateFileSystemInfos().OfType<DirectoryInfoBase>();
|
|
||||||
foreach (var candidate in candidates)
|
|
||||||
{
|
|
||||||
if (_declaredLiteralFolderSegmentInString.Contains(candidate.Name))
|
|
||||||
{
|
|
||||||
entities.Add(candidate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_declaredParentPathSegment)
|
|
||||||
{
|
|
||||||
entities.Add(directory.GetDirectory(".."));
|
|
||||||
}
|
|
||||||
|
|
||||||
// collect files and sub directories
|
|
||||||
var subDirectories = new List<DirectoryInfoBase>();
|
|
||||||
foreach (var entity in entities)
|
|
||||||
{
|
|
||||||
var fileInfo = entity as FileInfoBase;
|
|
||||||
if (fileInfo != null)
|
|
||||||
{
|
|
||||||
var result = MatchPatternContexts(fileInfo, (pattern, file) => pattern.Test(file));
|
|
||||||
if (result.IsSuccessful)
|
|
||||||
{
|
|
||||||
_files.Add(new FilePatternMatch(
|
|
||||||
path: CombinePath(parentRelativePath, fileInfo.Name),
|
|
||||||
stem: result.Stem));
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var directoryInfo = entity as DirectoryInfoBase;
|
|
||||||
if (directoryInfo != null)
|
|
||||||
{
|
|
||||||
if (MatchPatternContexts(directoryInfo, (pattern, dir) => pattern.Test(dir)))
|
|
||||||
{
|
|
||||||
subDirectories.Add(directoryInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Matches the sub directories recursively
|
|
||||||
foreach (var subDir in subDirectories)
|
|
||||||
{
|
|
||||||
var relativePath = CombinePath(parentRelativePath, subDir.Name);
|
|
||||||
|
|
||||||
Match(subDir, relativePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Request all the including and excluding patterns to pop their status stack.
|
|
||||||
PopDirectory();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Declare()
|
|
||||||
{
|
|
||||||
_declaredLiteralFileSegments.Clear();
|
|
||||||
_declaredLiteralFolderSegments.Clear();
|
|
||||||
_declaredParentPathSegment = false;
|
|
||||||
_declaredWildcardPathSegment = false;
|
|
||||||
|
|
||||||
foreach (var include in _includePatternContexts)
|
|
||||||
{
|
|
||||||
include.Declare(DeclareInclude);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DeclareInclude(IPathSegment patternSegment, bool isLastSegment)
|
|
||||||
{
|
|
||||||
var literalSegment = patternSegment as LiteralPathSegment;
|
|
||||||
if (literalSegment != null)
|
|
||||||
{
|
|
||||||
if (isLastSegment)
|
|
||||||
{
|
|
||||||
_declaredLiteralFileSegments.Add(literalSegment);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_declaredLiteralFolderSegments.Add(literalSegment);
|
|
||||||
_declaredLiteralFolderSegmentInString.Add(literalSegment.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (patternSegment is ParentPathSegment)
|
|
||||||
{
|
|
||||||
_declaredParentPathSegment = true;
|
|
||||||
}
|
|
||||||
else if (patternSegment is WildcardPathSegment)
|
|
||||||
{
|
|
||||||
_declaredWildcardPathSegment = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static string CombinePath(string left, string right)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(left))
|
|
||||||
{
|
|
||||||
return right;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return string.Format("{0}/{1}", left, right);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used to adapt Test(DirectoryInfoBase) for the below overload
|
|
||||||
private bool MatchPatternContexts<TFileInfoBase>(TFileInfoBase fileinfo, Func<IPatternContext, TFileInfoBase, bool> test)
|
|
||||||
{
|
|
||||||
return MatchPatternContexts(
|
|
||||||
fileinfo,
|
|
||||||
(ctx, file) =>
|
|
||||||
{
|
|
||||||
if (test(ctx, file))
|
|
||||||
{
|
|
||||||
return PatternTestResult.Success(stem: string.Empty);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return PatternTestResult.Failed;
|
|
||||||
}
|
|
||||||
}).IsSuccessful;
|
|
||||||
}
|
|
||||||
|
|
||||||
private PatternTestResult MatchPatternContexts<TFileInfoBase>(TFileInfoBase fileinfo, Func<IPatternContext, TFileInfoBase, PatternTestResult> test)
|
|
||||||
{
|
|
||||||
var result = PatternTestResult.Failed;
|
|
||||||
|
|
||||||
// If the given file/directory matches any including pattern, continues to next step.
|
|
||||||
foreach (var context in _includePatternContexts)
|
|
||||||
{
|
|
||||||
var localResult = test(context, fileinfo);
|
|
||||||
if (localResult.IsSuccessful)
|
|
||||||
{
|
|
||||||
result = localResult;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the given file/directory doesn't match any of the including pattern, returns false.
|
|
||||||
if (!result.IsSuccessful)
|
|
||||||
{
|
|
||||||
return PatternTestResult.Failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the given file/directory matches any excluding pattern, returns false.
|
|
||||||
foreach (var context in _excludePatternContexts)
|
|
||||||
{
|
|
||||||
if (test(context, fileinfo).IsSuccessful)
|
|
||||||
{
|
|
||||||
return PatternTestResult.Failed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PopDirectory()
|
|
||||||
{
|
|
||||||
foreach (var context in _excludePatternContexts)
|
|
||||||
{
|
|
||||||
context.PopDirectory();
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var context in _includePatternContexts)
|
|
||||||
{
|
|
||||||
context.PopDirectory();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PushDirectory(DirectoryInfoBase directory)
|
|
||||||
{
|
|
||||||
foreach (var context in _includePatternContexts)
|
|
||||||
{
|
|
||||||
context.PushDirectory(directory);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var context in _excludePatternContexts)
|
|
||||||
{
|
|
||||||
context.PushDirectory(directory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Internal.PathSegments
|
|
||||||
{
|
|
||||||
internal class CurrentPathSegment : IPathSegment
|
|
||||||
{
|
|
||||||
public bool CanProduceStem { get { return false; } }
|
|
||||||
|
|
||||||
public bool Match(string value)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Util;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Internal.PathSegments
|
|
||||||
{
|
|
||||||
internal class LiteralPathSegment : IPathSegment
|
|
||||||
{
|
|
||||||
private readonly StringComparison _comparisonType;
|
|
||||||
|
|
||||||
public bool CanProduceStem { get { return false; } }
|
|
||||||
|
|
||||||
public LiteralPathSegment(string value, StringComparison comparisonType)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
Value = value;
|
|
||||||
|
|
||||||
_comparisonType = comparisonType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Value { get; }
|
|
||||||
|
|
||||||
public bool Match(string value)
|
|
||||||
{
|
|
||||||
return string.Equals(Value, value, _comparisonType);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
var other = obj as LiteralPathSegment;
|
|
||||||
|
|
||||||
return other != null &&
|
|
||||||
_comparisonType == other._comparisonType &&
|
|
||||||
string.Equals(other.Value, Value, _comparisonType);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
return StringComparisonHelper.GetStringComparer(_comparisonType).GetHashCode(Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Internal.PathSegments
|
|
||||||
{
|
|
||||||
internal class ParentPathSegment : IPathSegment
|
|
||||||
{
|
|
||||||
private static readonly string LiteralParent = "..";
|
|
||||||
|
|
||||||
public bool CanProduceStem { get { return false; } }
|
|
||||||
|
|
||||||
public bool Match(string value)
|
|
||||||
{
|
|
||||||
return string.Equals(LiteralParent, value, StringComparison.Ordinal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Internal.PathSegments
|
|
||||||
{
|
|
||||||
internal class RecursiveWildcardSegment : IPathSegment
|
|
||||||
{
|
|
||||||
public bool CanProduceStem { get { return true; } }
|
|
||||||
|
|
||||||
public bool Match(string value)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Internal.PathSegments
|
|
||||||
{
|
|
||||||
internal class WildcardPathSegment : IPathSegment
|
|
||||||
{
|
|
||||||
// It doesn't matter which StringComparison type is used in this MatchAll segment because
|
|
||||||
// all comparing are skipped since there is no content in the segment.
|
|
||||||
public static readonly WildcardPathSegment MatchAll = new WildcardPathSegment(
|
|
||||||
string.Empty, new List<string>(), string.Empty, StringComparison.OrdinalIgnoreCase);
|
|
||||||
|
|
||||||
private readonly StringComparison _comparisonType;
|
|
||||||
|
|
||||||
public WildcardPathSegment(string beginsWith, List<string> contains, string endsWith, StringComparison comparisonType)
|
|
||||||
{
|
|
||||||
BeginsWith = beginsWith;
|
|
||||||
Contains = contains;
|
|
||||||
EndsWith = endsWith;
|
|
||||||
_comparisonType = comparisonType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CanProduceStem { get { return true; } }
|
|
||||||
|
|
||||||
public string BeginsWith { get; }
|
|
||||||
|
|
||||||
public List<string> Contains { get; }
|
|
||||||
|
|
||||||
public string EndsWith { get; }
|
|
||||||
|
|
||||||
public bool Match(string value)
|
|
||||||
{
|
|
||||||
var wildcard = this;
|
|
||||||
|
|
||||||
if (value.Length < wildcard.BeginsWith.Length + wildcard.EndsWith.Length)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!value.StartsWith(wildcard.BeginsWith, _comparisonType))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!value.EndsWith(wildcard.EndsWith, _comparisonType))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var beginRemaining = wildcard.BeginsWith.Length;
|
|
||||||
var endRemaining = value.Length - wildcard.EndsWith.Length;
|
|
||||||
for (var containsIndex = 0; containsIndex != wildcard.Contains.Count; ++containsIndex)
|
|
||||||
{
|
|
||||||
var containsValue = wildcard.Contains[containsIndex];
|
|
||||||
var indexOf = value.IndexOf(
|
|
||||||
value: containsValue,
|
|
||||||
startIndex: beginRemaining,
|
|
||||||
count: endRemaining - beginRemaining,
|
|
||||||
comparisonType: _comparisonType);
|
|
||||||
if (indexOf == -1)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
beginRemaining = indexOf + containsValue.Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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 Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Abstractions;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Internal.PatternContexts
|
|
||||||
{
|
|
||||||
internal abstract class PatternContext<TFrame> : IPatternContext
|
|
||||||
{
|
|
||||||
private Stack<TFrame> _stack = new Stack<TFrame>();
|
|
||||||
protected TFrame Frame;
|
|
||||||
|
|
||||||
public virtual void Declare(Action<IPathSegment, bool> declare) { }
|
|
||||||
|
|
||||||
public abstract PatternTestResult Test(FileInfoBase file);
|
|
||||||
|
|
||||||
public abstract bool Test(DirectoryInfoBase directory);
|
|
||||||
|
|
||||||
public abstract void PushDirectory(DirectoryInfoBase directory);
|
|
||||||
|
|
||||||
public virtual void PopDirectory()
|
|
||||||
{
|
|
||||||
Frame = _stack.Pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void PushDataFrame(TFrame frame)
|
|
||||||
{
|
|
||||||
_stack.Push(Frame);
|
|
||||||
Frame = frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected bool IsStackEmpty()
|
|
||||||
{
|
|
||||||
return _stack.Count == 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,105 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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 Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Abstractions;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Internal.PatternContexts
|
|
||||||
{
|
|
||||||
internal abstract class PatternContextLinear
|
|
||||||
: PatternContext<PatternContextLinear.FrameData>
|
|
||||||
{
|
|
||||||
public PatternContextLinear(ILinearPattern pattern)
|
|
||||||
{
|
|
||||||
Pattern = pattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override PatternTestResult Test(FileInfoBase file)
|
|
||||||
{
|
|
||||||
if (IsStackEmpty())
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Can't test file before entering a directory.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!Frame.IsNotApplicable && IsLastSegment() && TestMatchingSegment(file.Name))
|
|
||||||
{
|
|
||||||
return PatternTestResult.Success(CalculateStem(file));
|
|
||||||
}
|
|
||||||
|
|
||||||
return PatternTestResult.Failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void PushDirectory(DirectoryInfoBase directory)
|
|
||||||
{
|
|
||||||
// copy the current frame
|
|
||||||
var frame = Frame;
|
|
||||||
|
|
||||||
if (IsStackEmpty() || Frame.IsNotApplicable)
|
|
||||||
{
|
|
||||||
// when the stack is being initialized
|
|
||||||
// or no change is required.
|
|
||||||
}
|
|
||||||
else if (!TestMatchingSegment(directory.Name))
|
|
||||||
{
|
|
||||||
// nothing down this path is affected by this pattern
|
|
||||||
frame.IsNotApplicable = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Determine this frame's contribution to the stem (if any)
|
|
||||||
var segment = Pattern.Segments[Frame.SegmentIndex];
|
|
||||||
if (frame.InStem || segment.CanProduceStem)
|
|
||||||
{
|
|
||||||
frame.InStem = true;
|
|
||||||
frame.StemItems.Add(directory.Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
// directory matches segment, advance position in pattern
|
|
||||||
frame.SegmentIndex = frame.SegmentIndex + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
PushDataFrame(frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct FrameData
|
|
||||||
{
|
|
||||||
public bool IsNotApplicable;
|
|
||||||
public int SegmentIndex;
|
|
||||||
public bool InStem;
|
|
||||||
private IList<string> _stemItems;
|
|
||||||
|
|
||||||
public IList<string> StemItems
|
|
||||||
{
|
|
||||||
get { return _stemItems ?? (_stemItems = new List<string>()); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Stem
|
|
||||||
{
|
|
||||||
get { return _stemItems == null ? null : string.Join("/", _stemItems); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ILinearPattern Pattern { get; }
|
|
||||||
|
|
||||||
protected bool IsLastSegment()
|
|
||||||
{
|
|
||||||
return Frame.SegmentIndex == Pattern.Segments.Count - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected bool TestMatchingSegment(string value)
|
|
||||||
{
|
|
||||||
if (Frame.SegmentIndex >= Pattern.Segments.Count)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Pattern.Segments[Frame.SegmentIndex].Match(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected string CalculateStem(FileInfoBase matchedFile)
|
|
||||||
{
|
|
||||||
return MatcherContext.CombinePath(Frame.Stem, matchedFile.Name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Abstractions;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Internal.PatternContexts
|
|
||||||
{
|
|
||||||
internal class PatternContextLinearExclude : PatternContextLinear
|
|
||||||
{
|
|
||||||
public PatternContextLinearExclude(ILinearPattern pattern)
|
|
||||||
: base(pattern)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Test(DirectoryInfoBase directory)
|
|
||||||
{
|
|
||||||
if (IsStackEmpty())
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Can't test directory before entering a directory.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Frame.IsNotApplicable)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return IsLastSegment() && TestMatchingSegment(directory.Name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Abstractions;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Internal.PatternContexts
|
|
||||||
{
|
|
||||||
internal class PatternContextLinearInclude : PatternContextLinear
|
|
||||||
{
|
|
||||||
public PatternContextLinearInclude(ILinearPattern pattern)
|
|
||||||
: base(pattern)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Declare(Action<IPathSegment, bool> onDeclare)
|
|
||||||
{
|
|
||||||
if (IsStackEmpty())
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Can't declare path segment before entering a directory.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Frame.IsNotApplicable)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Frame.SegmentIndex < Pattern.Segments.Count)
|
|
||||||
{
|
|
||||||
onDeclare(Pattern.Segments[Frame.SegmentIndex], IsLastSegment());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Test(DirectoryInfoBase directory)
|
|
||||||
{
|
|
||||||
if (IsStackEmpty())
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Can't test directory before entering a directory.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Frame.IsNotApplicable)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return !IsLastSegment() && TestMatchingSegment(directory.Name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,186 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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 Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Abstractions;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Internal.PatternContexts
|
|
||||||
{
|
|
||||||
internal abstract class PatternContextRagged : PatternContext<PatternContextRagged.FrameData>
|
|
||||||
{
|
|
||||||
public PatternContextRagged(IRaggedPattern pattern)
|
|
||||||
{
|
|
||||||
Pattern = pattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override PatternTestResult Test(FileInfoBase file)
|
|
||||||
{
|
|
||||||
if (IsStackEmpty())
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Can't test file before entering a directory.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!Frame.IsNotApplicable && IsEndingGroup() && TestMatchingGroup(file))
|
|
||||||
{
|
|
||||||
return PatternTestResult.Success(CalculateStem(file));
|
|
||||||
}
|
|
||||||
return PatternTestResult.Failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed override void PushDirectory(DirectoryInfoBase directory)
|
|
||||||
{
|
|
||||||
// copy the current frame
|
|
||||||
var frame = Frame;
|
|
||||||
|
|
||||||
if (IsStackEmpty())
|
|
||||||
{
|
|
||||||
// initializing
|
|
||||||
frame.SegmentGroupIndex = -1;
|
|
||||||
frame.SegmentGroup = Pattern.StartsWith;
|
|
||||||
}
|
|
||||||
else if (Frame.IsNotApplicable)
|
|
||||||
{
|
|
||||||
// no change
|
|
||||||
}
|
|
||||||
else if (IsStartingGroup())
|
|
||||||
{
|
|
||||||
if (!TestMatchingSegment(directory.Name))
|
|
||||||
{
|
|
||||||
// nothing down this path is affected by this pattern
|
|
||||||
frame.IsNotApplicable = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// starting path incrementally satisfied
|
|
||||||
frame.SegmentIndex += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!IsStartingGroup() && directory.Name == "..")
|
|
||||||
{
|
|
||||||
// any parent path segment is not applicable in **
|
|
||||||
frame.IsNotApplicable = true;
|
|
||||||
}
|
|
||||||
else if (!IsStartingGroup() && !IsEndingGroup() && TestMatchingGroup(directory))
|
|
||||||
{
|
|
||||||
frame.SegmentIndex = Frame.SegmentGroup.Count;
|
|
||||||
frame.BacktrackAvailable = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// increase directory backtrack length
|
|
||||||
frame.BacktrackAvailable += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (frame.InStem)
|
|
||||||
{
|
|
||||||
frame.StemItems.Add(directory.Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (
|
|
||||||
frame.SegmentIndex == frame.SegmentGroup.Count &&
|
|
||||||
frame.SegmentGroupIndex != Pattern.Contains.Count)
|
|
||||||
{
|
|
||||||
frame.SegmentGroupIndex += 1;
|
|
||||||
frame.SegmentIndex = 0;
|
|
||||||
if (frame.SegmentGroupIndex < Pattern.Contains.Count)
|
|
||||||
{
|
|
||||||
frame.SegmentGroup = Pattern.Contains[frame.SegmentGroupIndex];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
frame.SegmentGroup = Pattern.EndsWith;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We now care about the stem
|
|
||||||
frame.InStem = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
PushDataFrame(frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void PopDirectory()
|
|
||||||
{
|
|
||||||
base.PopDirectory();
|
|
||||||
if (Frame.StemItems.Count > 0)
|
|
||||||
{
|
|
||||||
Frame.StemItems.RemoveAt(Frame.StemItems.Count - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct FrameData
|
|
||||||
{
|
|
||||||
public bool IsNotApplicable;
|
|
||||||
|
|
||||||
public int SegmentGroupIndex;
|
|
||||||
|
|
||||||
public IList<IPathSegment> SegmentGroup;
|
|
||||||
|
|
||||||
public int BacktrackAvailable;
|
|
||||||
|
|
||||||
public int SegmentIndex;
|
|
||||||
|
|
||||||
public bool InStem;
|
|
||||||
|
|
||||||
private IList<string> _stemItems;
|
|
||||||
|
|
||||||
public IList<string> StemItems
|
|
||||||
{
|
|
||||||
get { return _stemItems ?? (_stemItems = new List<string>()); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Stem
|
|
||||||
{
|
|
||||||
get { return _stemItems == null ? null : string.Join("/", _stemItems); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected IRaggedPattern Pattern { get; }
|
|
||||||
|
|
||||||
protected bool IsStartingGroup()
|
|
||||||
{
|
|
||||||
return Frame.SegmentGroupIndex == -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected bool IsEndingGroup()
|
|
||||||
{
|
|
||||||
return Frame.SegmentGroupIndex == Pattern.Contains.Count;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected bool TestMatchingSegment(string value)
|
|
||||||
{
|
|
||||||
if (Frame.SegmentIndex >= Frame.SegmentGroup.Count)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return Frame.SegmentGroup[Frame.SegmentIndex].Match(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected bool TestMatchingGroup(FileSystemInfoBase value)
|
|
||||||
{
|
|
||||||
var groupLength = Frame.SegmentGroup.Count;
|
|
||||||
var backtrackLength = Frame.BacktrackAvailable + 1;
|
|
||||||
if (backtrackLength < groupLength)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var scan = value;
|
|
||||||
for (int index = 0; index != groupLength; ++index)
|
|
||||||
{
|
|
||||||
var segment = Frame.SegmentGroup[groupLength - index - 1];
|
|
||||||
if (!segment.Match(scan.Name))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
scan = scan.ParentDirectory;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected string CalculateStem(FileInfoBase matchedFile)
|
|
||||||
{
|
|
||||||
return MatcherContext.CombinePath(Frame.Stem, matchedFile.Name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Abstractions;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Internal.PatternContexts
|
|
||||||
{
|
|
||||||
internal class PatternContextRaggedExclude : PatternContextRagged
|
|
||||||
{
|
|
||||||
public PatternContextRaggedExclude(IRaggedPattern pattern)
|
|
||||||
: base(pattern)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Test(DirectoryInfoBase directory)
|
|
||||||
{
|
|
||||||
if (IsStackEmpty())
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Can't test directory before entering a directory.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Frame.IsNotApplicable)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsEndingGroup() && TestMatchingGroup(directory))
|
|
||||||
{
|
|
||||||
// directory excluded with file-like pattern
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Pattern.EndsWith.Count == 0 &&
|
|
||||||
Frame.SegmentGroupIndex == Pattern.Contains.Count - 1 &&
|
|
||||||
TestMatchingGroup(directory))
|
|
||||||
{
|
|
||||||
// directory excluded by matching up to final '/**'
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,60 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Abstractions;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Internal.PathSegments;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Internal.PatternContexts
|
|
||||||
{
|
|
||||||
internal class PatternContextRaggedInclude : PatternContextRagged
|
|
||||||
{
|
|
||||||
public PatternContextRaggedInclude(IRaggedPattern pattern)
|
|
||||||
: base(pattern)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Declare(Action<IPathSegment, bool> onDeclare)
|
|
||||||
{
|
|
||||||
if (IsStackEmpty())
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Can't declare path segment before entering a directory.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Frame.IsNotApplicable)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsStartingGroup() && Frame.SegmentIndex < Frame.SegmentGroup.Count)
|
|
||||||
{
|
|
||||||
onDeclare(Frame.SegmentGroup[Frame.SegmentIndex], false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
onDeclare(WildcardPathSegment.MatchAll, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Test(DirectoryInfoBase directory)
|
|
||||||
{
|
|
||||||
if (IsStackEmpty())
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Can't test directory before entering a directory.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Frame.IsNotApplicable)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsStartingGroup() && !TestMatchingSegment(directory.Name))
|
|
||||||
{
|
|
||||||
// deterministic not-included
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Internal
|
|
||||||
{
|
|
||||||
public struct PatternTestResult
|
|
||||||
{
|
|
||||||
public static readonly PatternTestResult Failed = new PatternTestResult(isSuccessful: false, stem: null);
|
|
||||||
|
|
||||||
public bool IsSuccessful { get; }
|
|
||||||
public string Stem { get; }
|
|
||||||
|
|
||||||
private PatternTestResult(bool isSuccessful, string stem)
|
|
||||||
{
|
|
||||||
IsSuccessful = isSuccessful;
|
|
||||||
Stem = stem;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PatternTestResult Success(string stem)
|
|
||||||
{
|
|
||||||
return new PatternTestResult(isSuccessful: true, stem: stem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,272 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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 Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Internal.PathSegments;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Internal.PatternContexts;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Internal.Patterns
|
|
||||||
{
|
|
||||||
internal class PatternBuilder
|
|
||||||
{
|
|
||||||
private static readonly char[] _slashes = new[] { '/', '\\' };
|
|
||||||
private static readonly char[] _star = new[] { '*' };
|
|
||||||
|
|
||||||
public PatternBuilder()
|
|
||||||
{
|
|
||||||
ComparisonType = StringComparison.OrdinalIgnoreCase;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PatternBuilder(StringComparison comparisonType)
|
|
||||||
{
|
|
||||||
ComparisonType = comparisonType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public StringComparison ComparisonType { get; }
|
|
||||||
|
|
||||||
public IPattern Build(string pattern)
|
|
||||||
{
|
|
||||||
if (pattern == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("pattern");
|
|
||||||
}
|
|
||||||
|
|
||||||
pattern = pattern.TrimStart(_slashes);
|
|
||||||
|
|
||||||
if (pattern.TrimEnd(_slashes).Length < pattern.Length)
|
|
||||||
{
|
|
||||||
// If the pattern end with a slash, it is considered as
|
|
||||||
// a directory.
|
|
||||||
pattern = pattern.TrimEnd(_slashes) + "/**";
|
|
||||||
}
|
|
||||||
|
|
||||||
var allSegments = new List<IPathSegment>();
|
|
||||||
var isParentSegmentLegal = true;
|
|
||||||
|
|
||||||
IList<IPathSegment> segmentsPatternStartsWith = null;
|
|
||||||
IList<IList<IPathSegment>> segmentsPatternContains = null;
|
|
||||||
IList<IPathSegment> segmentsPatternEndsWith = null;
|
|
||||||
|
|
||||||
var endPattern = pattern.Length;
|
|
||||||
for (int scanPattern = 0; scanPattern < endPattern;)
|
|
||||||
{
|
|
||||||
var beginSegment = scanPattern;
|
|
||||||
var endSegment = NextIndex(pattern, _slashes, scanPattern, endPattern);
|
|
||||||
|
|
||||||
IPathSegment segment = null;
|
|
||||||
|
|
||||||
if (segment == null && endSegment - beginSegment == 3)
|
|
||||||
{
|
|
||||||
if (pattern[beginSegment] == '*' &&
|
|
||||||
pattern[beginSegment + 1] == '.' &&
|
|
||||||
pattern[beginSegment + 2] == '*')
|
|
||||||
{
|
|
||||||
// turn *.* into *
|
|
||||||
beginSegment += 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (segment == null && endSegment - beginSegment == 2)
|
|
||||||
{
|
|
||||||
if (pattern[beginSegment] == '*' &&
|
|
||||||
pattern[beginSegment + 1] == '*')
|
|
||||||
{
|
|
||||||
// recognized **
|
|
||||||
segment = new RecursiveWildcardSegment();
|
|
||||||
}
|
|
||||||
else if (pattern[beginSegment] == '.' &&
|
|
||||||
pattern[beginSegment + 1] == '.')
|
|
||||||
{
|
|
||||||
// recognized ..
|
|
||||||
|
|
||||||
if (!isParentSegmentLegal)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("\"..\" can be only added at the beginning of the pattern.");
|
|
||||||
}
|
|
||||||
segment = new ParentPathSegment();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (segment == null && endSegment - beginSegment == 1)
|
|
||||||
{
|
|
||||||
if (pattern[beginSegment] == '.')
|
|
||||||
{
|
|
||||||
// recognized .
|
|
||||||
segment = new CurrentPathSegment();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (segment == null && endSegment - beginSegment > 2)
|
|
||||||
{
|
|
||||||
if (pattern[beginSegment] == '*' &&
|
|
||||||
pattern[beginSegment + 1] == '*' &&
|
|
||||||
pattern[beginSegment + 2] == '.')
|
|
||||||
{
|
|
||||||
// recognize **.
|
|
||||||
// swallow the first *, add the recursive path segment and
|
|
||||||
// the remaining part will be treat as wild card in next loop.
|
|
||||||
segment = new RecursiveWildcardSegment();
|
|
||||||
endSegment = beginSegment;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (segment == null)
|
|
||||||
{
|
|
||||||
var beginsWith = string.Empty;
|
|
||||||
var contains = new List<string>();
|
|
||||||
var endsWith = string.Empty;
|
|
||||||
|
|
||||||
for (int scanSegment = beginSegment; scanSegment < endSegment;)
|
|
||||||
{
|
|
||||||
var beginLiteral = scanSegment;
|
|
||||||
var endLiteral = NextIndex(pattern, _star, scanSegment, endSegment);
|
|
||||||
|
|
||||||
if (beginLiteral == beginSegment)
|
|
||||||
{
|
|
||||||
if (endLiteral == endSegment)
|
|
||||||
{
|
|
||||||
// and the only bit
|
|
||||||
segment = new LiteralPathSegment(Portion(pattern, beginLiteral, endLiteral), ComparisonType);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// this is the first bit
|
|
||||||
beginsWith = Portion(pattern, beginLiteral, endLiteral);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (endLiteral == endSegment)
|
|
||||||
{
|
|
||||||
// this is the last bit
|
|
||||||
endsWith = Portion(pattern, beginLiteral, endLiteral);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (beginLiteral != endLiteral)
|
|
||||||
{
|
|
||||||
// this is a middle bit
|
|
||||||
contains.Add(Portion(pattern, beginLiteral, endLiteral));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// note: NOOP here, adjacent *'s are collapsed when they
|
|
||||||
// are mixed with literal text in a path segment
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
scanSegment = endLiteral + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (segment == null)
|
|
||||||
{
|
|
||||||
segment = new WildcardPathSegment(beginsWith, contains, endsWith, ComparisonType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(segment is ParentPathSegment))
|
|
||||||
{
|
|
||||||
isParentSegmentLegal = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (segment is CurrentPathSegment)
|
|
||||||
{
|
|
||||||
// ignore ".\"
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (segment is RecursiveWildcardSegment)
|
|
||||||
{
|
|
||||||
if (segmentsPatternStartsWith == null)
|
|
||||||
{
|
|
||||||
segmentsPatternStartsWith = new List<IPathSegment>(allSegments);
|
|
||||||
segmentsPatternEndsWith = new List<IPathSegment>();
|
|
||||||
segmentsPatternContains = new List<IList<IPathSegment>>();
|
|
||||||
}
|
|
||||||
else if (segmentsPatternEndsWith.Count != 0)
|
|
||||||
{
|
|
||||||
segmentsPatternContains.Add(segmentsPatternEndsWith);
|
|
||||||
segmentsPatternEndsWith = new List<IPathSegment>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (segmentsPatternEndsWith != null)
|
|
||||||
{
|
|
||||||
segmentsPatternEndsWith.Add(segment);
|
|
||||||
}
|
|
||||||
|
|
||||||
allSegments.Add(segment);
|
|
||||||
}
|
|
||||||
|
|
||||||
scanPattern = endSegment + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (segmentsPatternStartsWith == null)
|
|
||||||
{
|
|
||||||
return new LinearPattern(allSegments);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new RaggedPattern(allSegments, segmentsPatternStartsWith, segmentsPatternEndsWith, segmentsPatternContains);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int NextIndex(string pattern, char[] anyOf, int beginIndex, int endIndex)
|
|
||||||
{
|
|
||||||
var index = pattern.IndexOfAny(anyOf, beginIndex, endIndex - beginIndex);
|
|
||||||
return index == -1 ? endIndex : index;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string Portion(string pattern, int beginIndex, int endIndex)
|
|
||||||
{
|
|
||||||
return pattern.Substring(beginIndex, endIndex - beginIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class LinearPattern : ILinearPattern
|
|
||||||
{
|
|
||||||
public LinearPattern(List<IPathSegment> allSegments)
|
|
||||||
{
|
|
||||||
Segments = allSegments;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IList<IPathSegment> Segments { get; }
|
|
||||||
|
|
||||||
public IPatternContext CreatePatternContextForInclude()
|
|
||||||
{
|
|
||||||
return new PatternContextLinearInclude(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IPatternContext CreatePatternContextForExclude()
|
|
||||||
{
|
|
||||||
return new PatternContextLinearExclude(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class RaggedPattern : IRaggedPattern
|
|
||||||
{
|
|
||||||
public RaggedPattern(List<IPathSegment> allSegments, IList<IPathSegment> segmentsPatternStartsWith, IList<IPathSegment> segmentsPatternEndsWith, IList<IList<IPathSegment>> segmentsPatternContains)
|
|
||||||
{
|
|
||||||
Segments = allSegments;
|
|
||||||
StartsWith = segmentsPatternStartsWith;
|
|
||||||
Contains = segmentsPatternContains;
|
|
||||||
EndsWith = segmentsPatternEndsWith;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IList<IList<IPathSegment>> Contains { get; }
|
|
||||||
|
|
||||||
public IList<IPathSegment> EndsWith { get; }
|
|
||||||
|
|
||||||
public IList<IPathSegment> Segments { get; }
|
|
||||||
|
|
||||||
public IList<IPathSegment> StartsWith { get; }
|
|
||||||
|
|
||||||
public IPatternContext CreatePatternContextForInclude()
|
|
||||||
{
|
|
||||||
return new PatternContextRaggedInclude(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IPatternContext CreatePatternContextForExclude()
|
|
||||||
{
|
|
||||||
return new PatternContextRaggedExclude(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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 Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Abstractions;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Internal;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Internal.Patterns;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing
|
|
||||||
{
|
|
||||||
internal class Matcher
|
|
||||||
{
|
|
||||||
private IList<IPattern> _includePatterns = new List<IPattern>();
|
|
||||||
private IList<IPattern> _excludePatterns = new List<IPattern>();
|
|
||||||
private readonly PatternBuilder _builder;
|
|
||||||
private readonly StringComparison _comparison;
|
|
||||||
|
|
||||||
public Matcher()
|
|
||||||
: this(StringComparison.OrdinalIgnoreCase)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public Matcher(StringComparison comparisonType)
|
|
||||||
{
|
|
||||||
_comparison = comparisonType;
|
|
||||||
_builder = new PatternBuilder(comparisonType);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual Matcher AddInclude(string pattern)
|
|
||||||
{
|
|
||||||
_includePatterns.Add(_builder.Build(pattern));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual Matcher AddExclude(string pattern)
|
|
||||||
{
|
|
||||||
_excludePatterns.Add(_builder.Build(pattern));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual PatternMatchingResult Execute(DirectoryInfoBase directoryInfo)
|
|
||||||
{
|
|
||||||
var context = new MatcherContext(_includePatterns, _excludePatterns, directoryInfo, _comparison);
|
|
||||||
return context.Execute();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Abstractions;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing
|
|
||||||
{
|
|
||||||
internal static class MatcherExtensions
|
|
||||||
{
|
|
||||||
public static void AddExcludePatterns(this Matcher matcher, params IEnumerable<string>[] excludePatternsGroups)
|
|
||||||
{
|
|
||||||
foreach (var group in excludePatternsGroups)
|
|
||||||
{
|
|
||||||
foreach (var pattern in group)
|
|
||||||
{
|
|
||||||
matcher.AddExclude(pattern);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void AddIncludePatterns(this Matcher matcher, params IEnumerable<string>[] includePatternsGroups)
|
|
||||||
{
|
|
||||||
foreach (var group in includePatternsGroups)
|
|
||||||
{
|
|
||||||
foreach (var pattern in group)
|
|
||||||
{
|
|
||||||
matcher.AddInclude(pattern);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<string> GetResultsInFullPath(this Matcher matcher, string directoryPath)
|
|
||||||
{
|
|
||||||
var matches = matcher.Execute(new DirectoryInfoWrapper(new DirectoryInfo(directoryPath))).Files;
|
|
||||||
var result = matches.Select(match => Path.GetFullPath(Path.Combine(directoryPath, match.Path))).ToArray();
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing
|
|
||||||
{
|
|
||||||
internal class PatternMatchingResult
|
|
||||||
{
|
|
||||||
public PatternMatchingResult(IEnumerable<FilePatternMatch> files)
|
|
||||||
{
|
|
||||||
Files = files;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<FilePatternMatch> Files { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Util
|
|
||||||
{
|
|
||||||
internal static class StringComparisonHelper
|
|
||||||
{
|
|
||||||
public static StringComparer GetStringComparer(StringComparison comparisonType)
|
|
||||||
{
|
|
||||||
switch (comparisonType)
|
|
||||||
{
|
|
||||||
case StringComparison.CurrentCulture:
|
|
||||||
return StringComparer.CurrentCulture;
|
|
||||||
case StringComparison.CurrentCultureIgnoreCase:
|
|
||||||
return StringComparer.CurrentCultureIgnoreCase;
|
|
||||||
case StringComparison.Ordinal:
|
|
||||||
return StringComparer.Ordinal;
|
|
||||||
case StringComparison.OrdinalIgnoreCase:
|
|
||||||
return StringComparer.OrdinalIgnoreCase;
|
|
||||||
#if NET451
|
|
||||||
case StringComparison.InvariantCulture:
|
|
||||||
return StringComparer.InvariantCulture;
|
|
||||||
case StringComparison.InvariantCultureIgnoreCase:
|
|
||||||
return StringComparer.InvariantCultureIgnoreCase;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
throw new InvalidOperationException($"Unexpected StringComparison type: {comparisonType}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.Files
|
|
||||||
{
|
|
||||||
// Similar to IncludeContext, except that it replaces the include information with the exclude information and clears
|
|
||||||
// out the exclude information. This is to be used by migration to do CopyToOutput with Never set as its metadata.
|
|
||||||
internal class ExcludeContext : IncludeContext
|
|
||||||
{
|
|
||||||
public ExcludeContext(
|
|
||||||
string sourceBasePath,
|
|
||||||
string option,
|
|
||||||
JObject rawObject,
|
|
||||||
string[] defaultBuiltInInclude,
|
|
||||||
string[] defaultBuiltInExclude) : base(
|
|
||||||
sourceBasePath,
|
|
||||||
option,
|
|
||||||
rawObject,
|
|
||||||
defaultBuiltInInclude,
|
|
||||||
defaultBuiltInExclude)
|
|
||||||
{
|
|
||||||
IncludePatterns = ExcludePatterns;
|
|
||||||
ExcludePatterns = new List<string>();
|
|
||||||
|
|
||||||
IncludeFiles = ExcludeFiles;
|
|
||||||
ExcludeFiles = new List<string>();
|
|
||||||
|
|
||||||
BuiltInsInclude = BuiltInsExclude;
|
|
||||||
BuiltInsExclude = new List<string>();
|
|
||||||
|
|
||||||
if (Mappings != null)
|
|
||||||
{
|
|
||||||
var newMappings = new Dictionary<string, IncludeContext>();
|
|
||||||
foreach (var mapping in Mappings)
|
|
||||||
{
|
|
||||||
newMappings.Add(mapping.Key, new ExcludeContext(
|
|
||||||
mapping.Value.SourceBasePath,
|
|
||||||
mapping.Value.Option,
|
|
||||||
mapping.Value.RawObject,
|
|
||||||
mapping.Value.BuiltInsInclude?.ToArray(),
|
|
||||||
mapping.Value.BuiltInsExclude?.ToArray()));
|
|
||||||
}
|
|
||||||
|
|
||||||
Mappings = newMappings;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,236 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.Files
|
|
||||||
{
|
|
||||||
internal class IncludeContext
|
|
||||||
{
|
|
||||||
private static readonly char[] PatternSeparator = new[] { ';' };
|
|
||||||
|
|
||||||
public IncludeContext(
|
|
||||||
string sourceBasePath,
|
|
||||||
string option,
|
|
||||||
JObject rawObject,
|
|
||||||
string[] defaultBuiltInInclude,
|
|
||||||
string[] defaultBuiltInExclude)
|
|
||||||
{
|
|
||||||
if (sourceBasePath == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(sourceBasePath));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (option == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(option));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rawObject == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(rawObject));
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomIncludePatterns = new List<string>();
|
|
||||||
CustomRemovePatterns = new List<string>();
|
|
||||||
SourceBasePath = sourceBasePath;
|
|
||||||
Option = option;
|
|
||||||
RawObject = rawObject;
|
|
||||||
var token = rawObject.Value<JToken>(option);
|
|
||||||
|
|
||||||
if (token == null)
|
|
||||||
{
|
|
||||||
IncludePatterns = new List<string>();
|
|
||||||
ExcludePatterns = new List<string>();
|
|
||||||
IncludeFiles = new List<string>();
|
|
||||||
ExcludeFiles = new List<string>();
|
|
||||||
}
|
|
||||||
else if (token.Type != JTokenType.Object)
|
|
||||||
{
|
|
||||||
IncludePatterns = CreateCollection(
|
|
||||||
sourceBasePath, option, ExtractValues(token), literalPath: false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
IncludePatterns = CreateCollection(
|
|
||||||
sourceBasePath, "include", ExtractValues(token.Value<JToken>("include")), literalPath: false);
|
|
||||||
|
|
||||||
ExcludePatterns = CreateCollection(
|
|
||||||
sourceBasePath, "exclude", ExtractValues(token.Value<JToken>("exclude")), literalPath: false);
|
|
||||||
|
|
||||||
IncludeFiles = CreateCollection(
|
|
||||||
sourceBasePath, "includeFiles", ExtractValues(token.Value<JToken>("includeFiles")), literalPath: true);
|
|
||||||
|
|
||||||
ExcludeFiles = CreateCollection(
|
|
||||||
sourceBasePath, "excludeFiles", ExtractValues(token.Value<JToken>("excludeFiles")), literalPath: true);
|
|
||||||
|
|
||||||
var builtIns = token.Value<JToken>("builtIns") as JObject;
|
|
||||||
if (builtIns != null)
|
|
||||||
{
|
|
||||||
BuiltInsInclude = CreateCollection(
|
|
||||||
sourceBasePath, "include", ExtractValues(builtIns.Value<JToken>("include")), literalPath: false);
|
|
||||||
|
|
||||||
BuiltInsExclude = CreateCollection(
|
|
||||||
sourceBasePath, "exclude", ExtractValues(builtIns.Value<JToken>("exclude")), literalPath: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
var mappings = token.Value<JToken>("mappings") as JObject;
|
|
||||||
if (mappings != null)
|
|
||||||
{
|
|
||||||
Mappings = new Dictionary<string, IncludeContext>();
|
|
||||||
|
|
||||||
foreach (var map in mappings)
|
|
||||||
{
|
|
||||||
Mappings.Add(
|
|
||||||
map.Key,
|
|
||||||
new IncludeContext(
|
|
||||||
sourceBasePath,
|
|
||||||
map.Key,
|
|
||||||
mappings,
|
|
||||||
defaultBuiltInInclude: null,
|
|
||||||
defaultBuiltInExclude: null));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (defaultBuiltInInclude != null &&
|
|
||||||
(BuiltInsInclude == null || !BuiltInsInclude.Any()))
|
|
||||||
{
|
|
||||||
BuiltInsInclude = defaultBuiltInInclude.ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (defaultBuiltInExclude != null &&
|
|
||||||
(BuiltInsExclude == null || !BuiltInsExclude.Any()))
|
|
||||||
{
|
|
||||||
BuiltInsExclude = defaultBuiltInExclude.ToList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string SourceBasePath { get; }
|
|
||||||
|
|
||||||
public string Option { get; }
|
|
||||||
|
|
||||||
public List<string> CustomIncludePatterns { get; }
|
|
||||||
|
|
||||||
public List<string> CustomRemovePatterns { get; }
|
|
||||||
|
|
||||||
public List<string> IncludePatterns { get; protected set; }
|
|
||||||
|
|
||||||
public List<string> ExcludePatterns { get; protected set; }
|
|
||||||
|
|
||||||
public List<string> IncludeFiles { get; protected set; }
|
|
||||||
|
|
||||||
public List<string> ExcludeFiles { get; protected set; }
|
|
||||||
|
|
||||||
public List<string> BuiltInsInclude { get; protected set; }
|
|
||||||
|
|
||||||
public List<string> BuiltInsExclude { get; protected set; }
|
|
||||||
|
|
||||||
public IDictionary<string, IncludeContext> Mappings { get; protected set; }
|
|
||||||
|
|
||||||
public JObject RawObject { get; }
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
var other = obj as IncludeContext;
|
|
||||||
return other != null &&
|
|
||||||
SourceBasePath == other.SourceBasePath &&
|
|
||||||
Option == other.Option &&
|
|
||||||
EnumerableEquals(CustomIncludePatterns, other.CustomIncludePatterns) &&
|
|
||||||
EnumerableEquals(IncludePatterns, other.IncludePatterns) &&
|
|
||||||
EnumerableEquals(ExcludePatterns, other.ExcludePatterns) &&
|
|
||||||
EnumerableEquals(IncludeFiles, other.IncludeFiles) &&
|
|
||||||
EnumerableEquals(ExcludeFiles, other.ExcludeFiles) &&
|
|
||||||
EnumerableEquals(BuiltInsInclude, other.BuiltInsInclude) &&
|
|
||||||
EnumerableEquals(BuiltInsExclude, other.BuiltInsExclude) &&
|
|
||||||
EnumerableEquals(Mappings, other.Mappings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
return base.GetHashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool EnumerableEquals<T>(IEnumerable<T> left, IEnumerable<T> right)
|
|
||||||
=> Enumerable.SequenceEqual(left ?? EmptyArray<T>.Value, right ?? EmptyArray<T>.Value);
|
|
||||||
|
|
||||||
private static string[] ExtractValues(JToken token)
|
|
||||||
{
|
|
||||||
if (token != null)
|
|
||||||
{
|
|
||||||
if (token.Type == JTokenType.String)
|
|
||||||
{
|
|
||||||
return new string[] { token.Value<string>() };
|
|
||||||
}
|
|
||||||
else if (token.Type == JTokenType.Array)
|
|
||||||
{
|
|
||||||
return token.Values<string>().ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new string[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static List<string> CreateCollection(
|
|
||||||
string projectDirectory,
|
|
||||||
string propertyName,
|
|
||||||
IEnumerable<string> patternsStrings,
|
|
||||||
bool literalPath)
|
|
||||||
{
|
|
||||||
var patterns = patternsStrings
|
|
||||||
.SelectMany(patternsString => GetSourcesSplit(patternsString))
|
|
||||||
.Select(patternString =>
|
|
||||||
patternString.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar));
|
|
||||||
|
|
||||||
foreach (var pattern in patterns)
|
|
||||||
{
|
|
||||||
if (Path.IsPathRooted(pattern))
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"The '{propertyName}' property cannot be a rooted path.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (literalPath && pattern.Contains('*'))
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"The '{propertyName}' property cannot contain wildcard characters.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new List<string>(patterns.Select(pattern => FolderToPattern(pattern, projectDirectory)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<string> GetSourcesSplit(string sourceDescription)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(sourceDescription))
|
|
||||||
{
|
|
||||||
return Enumerable.Empty<string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
return sourceDescription.Split(PatternSeparator, StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string FolderToPattern(string candidate, string projectDir)
|
|
||||||
{
|
|
||||||
// If it's already a pattern, no change is needed
|
|
||||||
if (candidate.Contains('*'))
|
|
||||||
{
|
|
||||||
return candidate;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the given string ends with a path separator, or it is an existing directory
|
|
||||||
// we convert this folder name to a pattern matching all files in the folder
|
|
||||||
if (candidate.EndsWith(@"\") ||
|
|
||||||
candidate.EndsWith("/") ||
|
|
||||||
Directory.Exists(Path.Combine(projectDir, candidate)))
|
|
||||||
{
|
|
||||||
return Path.Combine(candidate, "**", "*");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, it represents a single file
|
|
||||||
return candidate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.DotNet.PlatformAbstractions;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.Files
|
|
||||||
{
|
|
||||||
internal class IncludeEntry : IEquatable<IncludeEntry>
|
|
||||||
{
|
|
||||||
public string TargetPath { get; }
|
|
||||||
|
|
||||||
public string SourcePath { get; }
|
|
||||||
|
|
||||||
public bool IsCustomTarget { get; set; }
|
|
||||||
|
|
||||||
public IncludeEntry(string target, string source)
|
|
||||||
{
|
|
||||||
TargetPath = target;
|
|
||||||
SourcePath = source;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
return Equals((IncludeEntry)obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
var combiner = HashCodeCombiner.Start();
|
|
||||||
combiner.Add(TargetPath);
|
|
||||||
combiner.Add(SourcePath);
|
|
||||||
|
|
||||||
return combiner.CombinedHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Equals(IncludeEntry other)
|
|
||||||
{
|
|
||||||
return other != null &&
|
|
||||||
string.Equals(TargetPath, other.TargetPath, StringComparison.Ordinal) &&
|
|
||||||
string.Equals(SourcePath, other.SourcePath, StringComparison.Ordinal) &&
|
|
||||||
IsCustomTarget == other.IsCustomTarget;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,212 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.Utilities;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing.Abstractions;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.Files
|
|
||||||
{
|
|
||||||
internal class IncludeFilesResolver
|
|
||||||
{
|
|
||||||
public static IEnumerable<IncludeEntry> GetIncludeFiles(IncludeContext context, string targetBasePath, IList<DiagnosticMessage> diagnostics)
|
|
||||||
{
|
|
||||||
return GetIncludeFiles(context, targetBasePath, diagnostics, flatten: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<IncludeEntry> GetIncludeFiles(
|
|
||||||
IncludeContext context,
|
|
||||||
string targetBasePath,
|
|
||||||
IList<DiagnosticMessage> diagnostics,
|
|
||||||
bool flatten)
|
|
||||||
{
|
|
||||||
var sourceBasePath = PathUtility.EnsureTrailingSlash(context.SourceBasePath);
|
|
||||||
targetBasePath = PathUtility.GetPathWithDirectorySeparator(targetBasePath);
|
|
||||||
|
|
||||||
var includeEntries = new HashSet<IncludeEntry>();
|
|
||||||
|
|
||||||
// Check for illegal characters in target path
|
|
||||||
if (string.IsNullOrEmpty(targetBasePath))
|
|
||||||
{
|
|
||||||
diagnostics?.Add(new DiagnosticMessage(
|
|
||||||
ErrorCodes.NU1003,
|
|
||||||
$"Invalid '{context.Option}' section. The target '{targetBasePath}' is invalid, " +
|
|
||||||
"targets must either be a file name or a directory suffixed with '/'. " +
|
|
||||||
"The root directory of the package can be specified by using a single '/' character.",
|
|
||||||
sourceBasePath,
|
|
||||||
DiagnosticMessageSeverity.Error));
|
|
||||||
}
|
|
||||||
else if (targetBasePath.Split(Path.DirectorySeparatorChar).Any(s => s.Equals(".") || s.Equals("..")))
|
|
||||||
{
|
|
||||||
diagnostics?.Add(new DiagnosticMessage(
|
|
||||||
ErrorCodes.NU1004,
|
|
||||||
$"Invalid '{context.Option}' section. " +
|
|
||||||
$"The target '{targetBasePath}' contains path-traversal characters ('.' or '..'). " +
|
|
||||||
"These characters are not permitted in target paths.",
|
|
||||||
sourceBasePath,
|
|
||||||
DiagnosticMessageSeverity.Error));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var files = GetIncludeFilesCore(
|
|
||||||
sourceBasePath,
|
|
||||||
context.IncludePatterns,
|
|
||||||
context.ExcludePatterns,
|
|
||||||
context.IncludeFiles,
|
|
||||||
context.BuiltInsInclude,
|
|
||||||
context.BuiltInsExclude).ToList();
|
|
||||||
|
|
||||||
var isFile = targetBasePath[targetBasePath.Length - 1] != Path.DirectorySeparatorChar;
|
|
||||||
if (isFile && files.Count > 1)
|
|
||||||
{
|
|
||||||
// It's a file. But the glob matched multiple things
|
|
||||||
diagnostics?.Add(new DiagnosticMessage(
|
|
||||||
ErrorCodes.NU1005,
|
|
||||||
$"Invalid '{ProjectFilesCollection.PackIncludePropertyName}' section. " +
|
|
||||||
$"The target '{targetBasePath}' refers to a single file, but the corresponding pattern " +
|
|
||||||
"produces multiple files. To mark the target as a directory, suffix it with '/'.",
|
|
||||||
sourceBasePath,
|
|
||||||
DiagnosticMessageSeverity.Error));
|
|
||||||
}
|
|
||||||
else if (isFile && files.Count > 0)
|
|
||||||
{
|
|
||||||
var filePath = Path.GetFullPath(
|
|
||||||
Path.Combine(sourceBasePath, PathUtility.GetPathWithDirectorySeparator(files[0].Path)));
|
|
||||||
|
|
||||||
includeEntries.Add(new IncludeEntry(targetBasePath, filePath));
|
|
||||||
}
|
|
||||||
else if (!isFile)
|
|
||||||
{
|
|
||||||
targetBasePath = targetBasePath.Substring(0, targetBasePath.Length - 1);
|
|
||||||
|
|
||||||
foreach (var file in files)
|
|
||||||
{
|
|
||||||
var fullPath = Path.GetFullPath(
|
|
||||||
Path.Combine(sourceBasePath, PathUtility.GetPathWithDirectorySeparator(file.Path)));
|
|
||||||
string targetPath;
|
|
||||||
|
|
||||||
if (flatten)
|
|
||||||
{
|
|
||||||
targetPath = Path.Combine(targetBasePath, PathUtility.GetPathWithDirectorySeparator(file.Stem));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
targetPath = Path.Combine(
|
|
||||||
targetBasePath,
|
|
||||||
PathUtility.GetRelativePathIgnoringDirectoryTraversals(sourceBasePath, fullPath));
|
|
||||||
}
|
|
||||||
|
|
||||||
includeEntries.Add(new IncludeEntry(targetPath, fullPath));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context.IncludeFiles != null)
|
|
||||||
{
|
|
||||||
foreach (var literalRelativePath in context.IncludeFiles)
|
|
||||||
{
|
|
||||||
var fullPath = Path.GetFullPath(Path.Combine(sourceBasePath, literalRelativePath));
|
|
||||||
string targetPath;
|
|
||||||
|
|
||||||
if (isFile)
|
|
||||||
{
|
|
||||||
targetPath = targetBasePath;
|
|
||||||
}
|
|
||||||
else if (flatten)
|
|
||||||
{
|
|
||||||
targetPath = Path.Combine(targetBasePath, Path.GetFileName(fullPath));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
targetPath = Path.Combine(targetBasePath, PathUtility.GetRelativePath(sourceBasePath, fullPath));
|
|
||||||
}
|
|
||||||
|
|
||||||
includeEntries.Add(new IncludeEntry(targetPath, fullPath));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context.ExcludeFiles != null)
|
|
||||||
{
|
|
||||||
var literalExcludedFiles = new HashSet<string>(
|
|
||||||
context.ExcludeFiles.Select(file => Path.GetFullPath(Path.Combine(sourceBasePath, file))),
|
|
||||||
StringComparer.Ordinal);
|
|
||||||
|
|
||||||
includeEntries.RemoveWhere(entry => literalExcludedFiles.Contains(entry.SourcePath));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context.Mappings != null)
|
|
||||||
{
|
|
||||||
// Finally add all the mappings
|
|
||||||
foreach (var map in context.Mappings)
|
|
||||||
{
|
|
||||||
var targetPath = Path.Combine(targetBasePath, PathUtility.GetPathWithDirectorySeparator(map.Key));
|
|
||||||
|
|
||||||
foreach (var file in GetIncludeFiles(map.Value, targetPath, diagnostics, flatten: true))
|
|
||||||
{
|
|
||||||
file.IsCustomTarget = true;
|
|
||||||
|
|
||||||
// Prefer named targets over default ones
|
|
||||||
includeEntries.RemoveWhere(f => string.Equals(f.SourcePath, file.SourcePath) && !f.IsCustomTarget);
|
|
||||||
includeEntries.Add(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return includeEntries;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<FilePatternMatch> GetIncludeFilesCore(
|
|
||||||
string sourceBasePath,
|
|
||||||
List<string> includePatterns,
|
|
||||||
List<string> excludePatterns,
|
|
||||||
List<string> includeFiles,
|
|
||||||
List<string> builtInsInclude,
|
|
||||||
List<string> builtInsExclude)
|
|
||||||
{
|
|
||||||
var literalIncludedFiles = new List<string>();
|
|
||||||
|
|
||||||
if (includeFiles != null)
|
|
||||||
{
|
|
||||||
// literal included files are added at the last, but the search happens early
|
|
||||||
// so as to make the process fail early in case there is missing file. fail early
|
|
||||||
// helps to avoid unnecessary globing for performance optimization
|
|
||||||
foreach (var literalRelativePath in includeFiles)
|
|
||||||
{
|
|
||||||
var fullPath = Path.GetFullPath(Path.Combine(sourceBasePath, literalRelativePath));
|
|
||||||
|
|
||||||
if (!File.Exists(fullPath))
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException(string.Format("Can't find file {0}", literalRelativePath));
|
|
||||||
}
|
|
||||||
|
|
||||||
literalIncludedFiles.Add(fullPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Globbing
|
|
||||||
var matcher = new Matcher();
|
|
||||||
if (builtInsInclude != null)
|
|
||||||
{
|
|
||||||
matcher.AddIncludePatterns(builtInsInclude);
|
|
||||||
}
|
|
||||||
if (includePatterns != null)
|
|
||||||
{
|
|
||||||
matcher.AddIncludePatterns(includePatterns);
|
|
||||||
}
|
|
||||||
if (builtInsExclude != null)
|
|
||||||
{
|
|
||||||
matcher.AddExcludePatterns(builtInsExclude);
|
|
||||||
}
|
|
||||||
if (excludePatterns != null)
|
|
||||||
{
|
|
||||||
matcher.AddExcludePatterns(excludePatterns);
|
|
||||||
}
|
|
||||||
|
|
||||||
return matcher.Execute(new DirectoryInfoWrapper(new DirectoryInfo(sourceBasePath))).Files;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,75 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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.IO;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.Files
|
|
||||||
{
|
|
||||||
internal static class NamedResourceReader
|
|
||||||
{
|
|
||||||
public static IDictionary<string, string> ReadNamedResources(JObject rawProject, string projectFilePath)
|
|
||||||
{
|
|
||||||
JToken namedResourceToken;
|
|
||||||
if (!rawProject.TryGetValue("namedResource", out namedResourceToken))
|
|
||||||
{
|
|
||||||
return new Dictionary<string, string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (namedResourceToken.Type != JTokenType.Object)
|
|
||||||
{
|
|
||||||
throw FileFormatException.Create(
|
|
||||||
"Value must be object.",
|
|
||||||
rawProject.Value<JToken>("namedResource"), projectFilePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
var namedResources = new Dictionary<string, string>();
|
|
||||||
foreach (var namedResource in (JObject)namedResourceToken)
|
|
||||||
{
|
|
||||||
if (namedResource.Value.Type != JTokenType.String)
|
|
||||||
{
|
|
||||||
throw FileFormatException.Create("Value must be string.", namedResource.Key, projectFilePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
var resourcePath = namedResource.Value.ToString();
|
|
||||||
if (resourcePath.Contains("*"))
|
|
||||||
{
|
|
||||||
throw FileFormatException.Create("Value cannot contain wildcards.", resourcePath, projectFilePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
var resourceFileFullPath =
|
|
||||||
Path.GetFullPath(Path.Combine(Path.GetDirectoryName(projectFilePath), resourcePath));
|
|
||||||
|
|
||||||
if (namedResources.ContainsKey(namedResource.Key))
|
|
||||||
{
|
|
||||||
throw FileFormatException.Create(
|
|
||||||
string.Format("The named resource {0} already exists.", namedResource.Key),
|
|
||||||
resourcePath,
|
|
||||||
projectFilePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
namedResources.Add(namedResource.Key, resourceFileFullPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
return namedResources;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void ApplyNamedResources(IDictionary<string, string> namedResources, IDictionary<string, string> resources)
|
|
||||||
{
|
|
||||||
foreach (var namedResource in namedResources)
|
|
||||||
{
|
|
||||||
// The named resources dictionary is like the project file
|
|
||||||
// key = name, value = path to resource
|
|
||||||
if (resources.ContainsKey(namedResource.Value))
|
|
||||||
{
|
|
||||||
resources[namedResource.Value] = namedResource.Key;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
resources.Add(namedResource.Value, namedResource.Key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System.Linq;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.Files
|
|
||||||
{
|
|
||||||
internal class PackIncludeEntry
|
|
||||||
{
|
|
||||||
public string Target { get; }
|
|
||||||
public string[] SourceGlobs { get; }
|
|
||||||
public int Line { get; }
|
|
||||||
public int Column { get; }
|
|
||||||
|
|
||||||
internal PackIncludeEntry(string target, JToken json)
|
|
||||||
{
|
|
||||||
Target = target;
|
|
||||||
SourceGlobs = ExtractValues(json);
|
|
||||||
|
|
||||||
var lineInfo = (IJsonLineInfo)json;
|
|
||||||
Line = lineInfo.LineNumber;
|
|
||||||
Column = lineInfo.LinePosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PackIncludeEntry(string target, string[] sourceGlobs, int line, int column)
|
|
||||||
{
|
|
||||||
Target = target;
|
|
||||||
SourceGlobs = sourceGlobs;
|
|
||||||
Line = line;
|
|
||||||
Column = column;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string[] ExtractValues(JToken json)
|
|
||||||
{
|
|
||||||
if (json.Type == JTokenType.String)
|
|
||||||
{
|
|
||||||
return new string[] { json.Value<string>() };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (json.Type == JTokenType.Array)
|
|
||||||
{
|
|
||||||
return json.Select(v => v.ToString()).ToArray();
|
|
||||||
}
|
|
||||||
return new string[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,123 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.FileSystemGlobbing;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.Files
|
|
||||||
{
|
|
||||||
internal class PatternGroup
|
|
||||||
{
|
|
||||||
private readonly List<PatternGroup> _excludeGroups = new List<PatternGroup>();
|
|
||||||
private readonly Matcher _matcher = new Matcher();
|
|
||||||
|
|
||||||
internal PatternGroup(IEnumerable<string> includePatterns)
|
|
||||||
{
|
|
||||||
IncludeLiterals = Enumerable.Empty<string>();
|
|
||||||
IncludePatterns = includePatterns;
|
|
||||||
ExcludePatterns = Enumerable.Empty<string>();
|
|
||||||
_matcher.AddIncludePatterns(IncludePatterns);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal PatternGroup(IEnumerable<string> includePatterns, IEnumerable<string> excludePatterns, IEnumerable<string> includeLiterals)
|
|
||||||
{
|
|
||||||
IncludeLiterals = includeLiterals;
|
|
||||||
IncludePatterns = includePatterns;
|
|
||||||
ExcludePatterns = excludePatterns;
|
|
||||||
|
|
||||||
_matcher.AddIncludePatterns(IncludePatterns);
|
|
||||||
_matcher.AddExcludePatterns(ExcludePatterns);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static PatternGroup Build(JObject rawProject,
|
|
||||||
string projectDirectory,
|
|
||||||
string projectFilePath,
|
|
||||||
string name,
|
|
||||||
IEnumerable<string> fallbackIncluding = null,
|
|
||||||
IEnumerable<string> additionalIncluding = null,
|
|
||||||
IEnumerable<string> additionalExcluding = null,
|
|
||||||
bool includePatternsOnly = false,
|
|
||||||
ICollection<DiagnosticMessage> warnings = null)
|
|
||||||
{
|
|
||||||
string includePropertyName = name;
|
|
||||||
additionalIncluding = additionalIncluding ?? Enumerable.Empty<string>();
|
|
||||||
var includePatterns = PatternsCollectionHelper.GetPatternsCollection(rawProject, projectDirectory, projectFilePath, includePropertyName, defaultPatterns: fallbackIncluding)
|
|
||||||
.Concat(additionalIncluding)
|
|
||||||
.Distinct();
|
|
||||||
|
|
||||||
if (includePatternsOnly)
|
|
||||||
{
|
|
||||||
return new PatternGroup(includePatterns);
|
|
||||||
}
|
|
||||||
|
|
||||||
additionalExcluding = additionalExcluding ?? Enumerable.Empty<string>();
|
|
||||||
var excludePatterns = PatternsCollectionHelper.GetPatternsCollection(rawProject, projectDirectory, projectFilePath, propertyName: name + "Exclude")
|
|
||||||
.Concat(additionalExcluding)
|
|
||||||
.Distinct();
|
|
||||||
|
|
||||||
var includeLiterals = PatternsCollectionHelper.GetPatternsCollection(rawProject, projectDirectory, projectFilePath, propertyName: name + "Files", literalPath: true)
|
|
||||||
.Distinct();
|
|
||||||
|
|
||||||
return new PatternGroup(includePatterns, excludePatterns, includeLiterals);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<string> IncludeLiterals { get; }
|
|
||||||
|
|
||||||
public IEnumerable<string> IncludePatterns { get; }
|
|
||||||
|
|
||||||
public IEnumerable<string> ExcludePatterns { get; }
|
|
||||||
|
|
||||||
public IEnumerable<PatternGroup> ExcludePatternsGroup { get { return _excludeGroups; } }
|
|
||||||
|
|
||||||
public PatternGroup ExcludeGroup(PatternGroup group)
|
|
||||||
{
|
|
||||||
_excludeGroups.Add(group);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<string> SearchFiles(string rootPath)
|
|
||||||
{
|
|
||||||
// literal included files are added at the last, but the search happens early
|
|
||||||
// so as to make the process fail early in case there is missing file. fail early
|
|
||||||
// helps to avoid unnecessary globing for performance optimization
|
|
||||||
var literalIncludedFiles = new List<string>();
|
|
||||||
foreach (var literalRelativePath in IncludeLiterals)
|
|
||||||
{
|
|
||||||
var fullPath = Path.GetFullPath(Path.Combine(rootPath, literalRelativePath));
|
|
||||||
|
|
||||||
if (!File.Exists(fullPath))
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException(string.Format("Can't find file {0}", literalRelativePath));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: extract utility like NuGet.PathUtility.GetPathWithForwardSlashes()
|
|
||||||
literalIncludedFiles.Add(fullPath.Replace('\\', '/'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// globing files
|
|
||||||
var globbingResults = _matcher.GetResultsInFullPath(rootPath);
|
|
||||||
|
|
||||||
// if there is no results generated in globing, skip excluding other groups
|
|
||||||
// for performance optimization.
|
|
||||||
if (globbingResults.Any())
|
|
||||||
{
|
|
||||||
foreach (var group in _excludeGroups)
|
|
||||||
{
|
|
||||||
globbingResults = globbingResults.Except(group.SearchFiles(rootPath));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return globbingResults.Concat(literalIncludedFiles).Distinct();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return string.Format("Pattern group: Literals [{0}] Includes [{1}] Excludes [{2}]", string.Join(", ", IncludeLiterals), string.Join(", ", IncludePatterns), string.Join(", ", ExcludePatterns));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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.Linq;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.Files
|
|
||||||
{
|
|
||||||
internal static class PatternsCollectionHelper
|
|
||||||
{
|
|
||||||
private static readonly char[] PatternSeparator = new[] { ';' };
|
|
||||||
|
|
||||||
public static IEnumerable<string> GetPatternsCollection(JObject rawProject,
|
|
||||||
string projectDirectory,
|
|
||||||
string projectFilePath,
|
|
||||||
string propertyName,
|
|
||||||
IEnumerable<string> defaultPatterns = null,
|
|
||||||
bool literalPath = false)
|
|
||||||
{
|
|
||||||
defaultPatterns = defaultPatterns ?? Enumerable.Empty<string>();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
JToken propertyNameToken;
|
|
||||||
if (!rawProject.TryGetValue(propertyName, out propertyNameToken))
|
|
||||||
{
|
|
||||||
return IncludeContext.CreateCollection(
|
|
||||||
projectDirectory, propertyName, defaultPatterns, literalPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (propertyNameToken.Type == JTokenType.String)
|
|
||||||
{
|
|
||||||
return IncludeContext.CreateCollection(
|
|
||||||
projectDirectory, propertyName, new string[] { propertyNameToken.Value<string>() }, literalPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (propertyNameToken.Type == JTokenType.Array)
|
|
||||||
{
|
|
||||||
var valuesInArray = propertyNameToken.Values<string>();
|
|
||||||
return IncludeContext.CreateCollection(
|
|
||||||
projectDirectory, propertyName, valuesInArray.Select(s => s.ToString()), literalPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
throw FileFormatException.Create(ex, rawProject.Value<JToken>(propertyName), projectFilePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw FileFormatException.Create("Value must be either string or array.", rawProject.Value<JToken>(propertyName), projectFilePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,193 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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 Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.Files
|
|
||||||
{
|
|
||||||
internal class ProjectFilesCollection
|
|
||||||
{
|
|
||||||
public static readonly string[] SdkInjectedDefaultCompileBuiltInPatterns = new[] { @"**/*.cs" };
|
|
||||||
public static readonly string[] DefaultPreprocessPatterns = new[] { @"compiler/preprocess/**/*.cs" };
|
|
||||||
public static readonly string[] DefaultSharedPatterns = new[] { @"compiler/shared/**/*.cs" };
|
|
||||||
public static readonly string[] DefaultBuiltInExcludePatterns = new[] { "bin/**", "obj/**", "**/*.xproj", "packages/**" };
|
|
||||||
|
|
||||||
public static readonly string PackIncludePropertyName = "packInclude";
|
|
||||||
|
|
||||||
private PatternGroup _sharedPatternsGroup;
|
|
||||||
private PatternGroup _resourcePatternsGroup;
|
|
||||||
private PatternGroup _preprocessPatternsGroup;
|
|
||||||
private PatternGroup _compilePatternsGroup;
|
|
||||||
private PatternGroup _contentPatternsGroup;
|
|
||||||
private IDictionary<string, string> _namedResources;
|
|
||||||
private IEnumerable<string> _publishExcludePatterns;
|
|
||||||
private IEnumerable<PackIncludeEntry> _packInclude;
|
|
||||||
|
|
||||||
private readonly string _projectDirectory;
|
|
||||||
private readonly string _projectFilePath;
|
|
||||||
|
|
||||||
private JObject _rawProject;
|
|
||||||
private bool _initialized;
|
|
||||||
|
|
||||||
internal ProjectFilesCollection(JObject rawProject, string projectDirectory, string projectFilePath)
|
|
||||||
{
|
|
||||||
_projectDirectory = projectDirectory;
|
|
||||||
_projectFilePath = projectFilePath;
|
|
||||||
_rawProject = rawProject;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void EnsureInitialized()
|
|
||||||
{
|
|
||||||
if (_initialized)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var excludeBuiltIns = PatternsCollectionHelper.GetPatternsCollection(_rawProject, _projectDirectory, _projectFilePath, "excludeBuiltIn", DefaultBuiltInExcludePatterns);
|
|
||||||
var excludePatterns = PatternsCollectionHelper.GetPatternsCollection(_rawProject, _projectDirectory, _projectFilePath, "exclude")
|
|
||||||
.Concat(excludeBuiltIns);
|
|
||||||
var contentBuiltIns = PatternsCollectionHelper.GetPatternsCollection(_rawProject, _projectDirectory, _projectFilePath, "contentBuiltIn");
|
|
||||||
var compileBuiltIns = PatternsCollectionHelper.GetPatternsCollection(_rawProject, _projectDirectory, _projectFilePath, "compileBuiltIn", SdkInjectedDefaultCompileBuiltInPatterns);
|
|
||||||
var resourceBuiltIns = PatternsCollectionHelper.GetPatternsCollection(_rawProject, _projectDirectory, _projectFilePath, "resourceBuiltIn");
|
|
||||||
|
|
||||||
_publishExcludePatterns = PatternsCollectionHelper.GetPatternsCollection(_rawProject, _projectDirectory, _projectFilePath, "publishExclude");
|
|
||||||
|
|
||||||
_sharedPatternsGroup = PatternGroup.Build(_rawProject, _projectDirectory, _projectFilePath, "shared", fallbackIncluding: DefaultSharedPatterns, additionalExcluding: excludePatterns);
|
|
||||||
|
|
||||||
_resourcePatternsGroup = PatternGroup.Build(_rawProject, _projectDirectory, _projectFilePath, "resource", additionalIncluding: resourceBuiltIns, additionalExcluding: excludePatterns);
|
|
||||||
|
|
||||||
_preprocessPatternsGroup = PatternGroup.Build(_rawProject, _projectDirectory, _projectFilePath, "preprocess", fallbackIncluding: DefaultPreprocessPatterns, additionalExcluding: excludePatterns)
|
|
||||||
.ExcludeGroup(_sharedPatternsGroup)
|
|
||||||
.ExcludeGroup(_resourcePatternsGroup);
|
|
||||||
|
|
||||||
_compilePatternsGroup = PatternGroup.Build(_rawProject, _projectDirectory, _projectFilePath, "compile", additionalIncluding: compileBuiltIns, additionalExcluding: excludePatterns)
|
|
||||||
.ExcludeGroup(_sharedPatternsGroup)
|
|
||||||
.ExcludeGroup(_preprocessPatternsGroup)
|
|
||||||
.ExcludeGroup(_resourcePatternsGroup);
|
|
||||||
|
|
||||||
_contentPatternsGroup = PatternGroup.Build(_rawProject, _projectDirectory, _projectFilePath, "content", additionalIncluding: contentBuiltIns, additionalExcluding: _publishExcludePatterns);
|
|
||||||
|
|
||||||
_namedResources = NamedResourceReader.ReadNamedResources(_rawProject, _projectFilePath);
|
|
||||||
|
|
||||||
// Files to be packed along with the project
|
|
||||||
var packIncludeJson = _rawProject.Value<JToken>(PackIncludePropertyName) as JObject;
|
|
||||||
if (packIncludeJson != null)
|
|
||||||
{
|
|
||||||
var packIncludeEntries = new List<PackIncludeEntry>();
|
|
||||||
foreach (var token in packIncludeJson)
|
|
||||||
{
|
|
||||||
packIncludeEntries.Add(new PackIncludeEntry(token.Key, token.Value));
|
|
||||||
}
|
|
||||||
|
|
||||||
_packInclude = packIncludeEntries;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_packInclude = new List<PackIncludeEntry>();
|
|
||||||
}
|
|
||||||
|
|
||||||
_initialized = true;
|
|
||||||
_rawProject = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<PackIncludeEntry> PackInclude
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
EnsureInitialized();
|
|
||||||
return _packInclude;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<string> SourceFiles
|
|
||||||
{
|
|
||||||
get { return CompilePatternsGroup.SearchFiles(_projectDirectory).Distinct(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<string> PreprocessSourceFiles
|
|
||||||
{
|
|
||||||
get { return PreprocessPatternsGroup.SearchFiles(_projectDirectory).Distinct(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public IDictionary<string, string> ResourceFiles
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var resources = ResourcePatternsGroup
|
|
||||||
.SearchFiles(_projectDirectory)
|
|
||||||
.Distinct()
|
|
||||||
.ToDictionary(res => res, res => (string)null);
|
|
||||||
|
|
||||||
NamedResourceReader.ApplyNamedResources(_namedResources, resources);
|
|
||||||
|
|
||||||
return resources;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<string> SharedFiles
|
|
||||||
{
|
|
||||||
get { return SharedPatternsGroup.SearchFiles(_projectDirectory).Distinct(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<string> GetContentFiles(IEnumerable<string> additionalExcludePatterns = null)
|
|
||||||
{
|
|
||||||
var patternGroup = new PatternGroup(ContentPatternsGroup.IncludePatterns,
|
|
||||||
ContentPatternsGroup.ExcludePatterns.Concat(additionalExcludePatterns ?? new List<string>()),
|
|
||||||
ContentPatternsGroup.IncludeLiterals);
|
|
||||||
|
|
||||||
foreach (var excludedGroup in ContentPatternsGroup.ExcludePatternsGroup)
|
|
||||||
{
|
|
||||||
patternGroup.ExcludeGroup(excludedGroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
return patternGroup.SearchFiles(_projectDirectory);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal PatternGroup CompilePatternsGroup
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
EnsureInitialized();
|
|
||||||
return _compilePatternsGroup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal PatternGroup SharedPatternsGroup
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
EnsureInitialized();
|
|
||||||
return _sharedPatternsGroup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal PatternGroup ResourcePatternsGroup
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
EnsureInitialized();
|
|
||||||
return _resourcePatternsGroup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal PatternGroup PreprocessPatternsGroup
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
EnsureInitialized();
|
|
||||||
return _preprocessPatternsGroup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal PatternGroup ContentPatternsGroup
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
EnsureInitialized();
|
|
||||||
return _contentPatternsGroup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,105 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
internal class GlobalSettings
|
|
||||||
{
|
|
||||||
public const string FileName = "global.json";
|
|
||||||
|
|
||||||
public IList<string> ProjectSearchPaths { get; private set; }
|
|
||||||
public string PackagesPath { get; private set; }
|
|
||||||
public string FilePath { get; private set; }
|
|
||||||
public string DirectoryPath
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return Path.GetFullPath(Path.GetDirectoryName(FilePath));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool TryGetGlobalSettings(string path, out GlobalSettings globalSettings)
|
|
||||||
{
|
|
||||||
globalSettings = null;
|
|
||||||
string globalJsonPath = null;
|
|
||||||
|
|
||||||
if (Path.GetFileName(path) == FileName)
|
|
||||||
{
|
|
||||||
globalJsonPath = path;
|
|
||||||
path = Path.GetDirectoryName(path);
|
|
||||||
}
|
|
||||||
else if (!HasGlobalFile(path))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
globalJsonPath = Path.Combine(path, FileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var fs = File.OpenRead(globalJsonPath))
|
|
||||||
{
|
|
||||||
globalSettings = GetGlobalSettings(fs, globalJsonPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
throw FileFormatException.Create(ex, globalJsonPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GlobalSettings GetGlobalSettings(Stream fs, string globalJsonPath)
|
|
||||||
{
|
|
||||||
var globalSettings = new GlobalSettings();
|
|
||||||
|
|
||||||
var reader = new StreamReader(fs);
|
|
||||||
JObject jobject;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
jobject = JObject.Parse(reader.ReadToEnd());
|
|
||||||
}
|
|
||||||
catch (JsonReaderException)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("The JSON file can't be deserialized to a JSON object.");
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerable<string> projectSearchPaths = Enumerable.Empty<string>();
|
|
||||||
JToken projectSearchPathsToken;
|
|
||||||
if (jobject.TryGetValue("projects", out projectSearchPathsToken) &&
|
|
||||||
projectSearchPathsToken.Type == JTokenType.Array)
|
|
||||||
{
|
|
||||||
projectSearchPaths = projectSearchPathsToken.Values<string>();
|
|
||||||
}
|
|
||||||
else if (jobject.TryGetValue("sources", out projectSearchPathsToken) &&
|
|
||||||
projectSearchPathsToken.Type == JTokenType.Array)
|
|
||||||
{
|
|
||||||
projectSearchPaths = projectSearchPathsToken.Values<string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
globalSettings.ProjectSearchPaths = new List<string>(projectSearchPaths);
|
|
||||||
globalSettings.PackagesPath = jobject.Value<string>("packages");
|
|
||||||
globalSettings.FilePath = globalJsonPath;
|
|
||||||
|
|
||||||
return globalSettings;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool HasGlobalFile(string path)
|
|
||||||
{
|
|
||||||
string projectPath = Path.Combine(path, FileName);
|
|
||||||
|
|
||||||
return File.Exists(projectPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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 NuGet.ProjectModel;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.Graph
|
|
||||||
{
|
|
||||||
internal class ExportFile
|
|
||||||
{
|
|
||||||
public static readonly string ExportFileName = "project.fragment.lock.json";
|
|
||||||
|
|
||||||
public int Version { get; }
|
|
||||||
public string ExportFilePath { get; }
|
|
||||||
|
|
||||||
public IList<LockFileTargetLibrary> Exports { get; }
|
|
||||||
|
|
||||||
public ExportFile(string exportFilePath, int version, IList<LockFileTargetLibrary> exports)
|
|
||||||
{
|
|
||||||
ExportFilePath = exportFilePath;
|
|
||||||
Version = version;
|
|
||||||
Exports = exports.Any() ? exports : new List<LockFileTargetLibrary>(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,76 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using NuGet.ProjectModel;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.Graph
|
|
||||||
{
|
|
||||||
internal static class LockFileExtensions
|
|
||||||
{
|
|
||||||
public static readonly int CurrentVersion = 2;
|
|
||||||
|
|
||||||
public static bool IsValidForProject(this LockFile lockFile, Project project)
|
|
||||||
{
|
|
||||||
string message;
|
|
||||||
return lockFile.IsValidForProject(project, out message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool IsValidForProject(this LockFile lockFile, Project project, out string message)
|
|
||||||
{
|
|
||||||
if (lockFile.Version != CurrentVersion)
|
|
||||||
{
|
|
||||||
message = $"The expected lock file version does not match the actual version";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
message = $"Dependencies in {Project.FileName} were modified";
|
|
||||||
|
|
||||||
var actualTargetFrameworks = project.GetTargetFrameworks();
|
|
||||||
|
|
||||||
// The lock file should contain dependencies for each framework plus dependencies shared by all frameworks
|
|
||||||
if (lockFile.ProjectFileDependencyGroups.Count != actualTargetFrameworks.Count() + 1)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Different count; {lockFile.ProjectFileDependencyGroups.Count} != {actualTargetFrameworks.Count() + 1}");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var group in lockFile.ProjectFileDependencyGroups)
|
|
||||||
{
|
|
||||||
IOrderedEnumerable<string> actualDependencies;
|
|
||||||
var expectedDependencies = group.Dependencies.OrderBy(x => x);
|
|
||||||
|
|
||||||
// If the framework name is empty, the associated dependencies are shared by all frameworks
|
|
||||||
if (string.IsNullOrEmpty(group.FrameworkName))
|
|
||||||
{
|
|
||||||
actualDependencies = project.Dependencies
|
|
||||||
.Select(d => d.LibraryRange.ToLockFileDependencyGroupString())
|
|
||||||
.OrderBy(x => x, StringComparer.OrdinalIgnoreCase);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var framework = actualTargetFrameworks
|
|
||||||
.FirstOrDefault(f => Equals(f.FrameworkName.DotNetFrameworkName, group.FrameworkName));
|
|
||||||
if (framework == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
actualDependencies = framework.Dependencies
|
|
||||||
.Select(d => d.LibraryRange.ToLockFileDependencyGroupString())
|
|
||||||
.OrderBy(x => x, StringComparer.OrdinalIgnoreCase);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!actualDependencies.SequenceEqual(expectedDependencies))
|
|
||||||
{
|
|
||||||
Console.WriteLine($"ActualDependencies don't match");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
message = null;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,66 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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 NuGet.LibraryModel;
|
|
||||||
using NuGet.ProjectModel;
|
|
||||||
using NuGet.Versioning;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.Graph
|
|
||||||
{
|
|
||||||
internal class LockFileLookup
|
|
||||||
{
|
|
||||||
// REVIEW: Case sensitivity?
|
|
||||||
private readonly Dictionary<Tuple<string, NuGetVersion>, LockFileLibrary> _packages;
|
|
||||||
private readonly Dictionary<string, LockFileLibrary> _projects;
|
|
||||||
|
|
||||||
public LockFileLookup(LockFile lockFile)
|
|
||||||
{
|
|
||||||
_packages = new Dictionary<Tuple<string, NuGetVersion>, LockFileLibrary>();
|
|
||||||
_projects = new Dictionary<string, LockFileLibrary>();
|
|
||||||
|
|
||||||
foreach (var library in lockFile.Libraries)
|
|
||||||
{
|
|
||||||
var libraryType = LibraryType.Parse(library.Type);
|
|
||||||
|
|
||||||
if (libraryType == LibraryType.Package)
|
|
||||||
{
|
|
||||||
_packages[Tuple.Create(library.Name, library.Version)] = library;
|
|
||||||
}
|
|
||||||
if (libraryType == LibraryType.Project)
|
|
||||||
{
|
|
||||||
_projects[library.Name] = library;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public LockFileLibrary GetProject(string name)
|
|
||||||
{
|
|
||||||
LockFileLibrary project;
|
|
||||||
if (_projects.TryGetValue(name, out project))
|
|
||||||
{
|
|
||||||
return project;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LockFileLibrary GetPackage(string id, NuGetVersion version)
|
|
||||||
{
|
|
||||||
LockFileLibrary package;
|
|
||||||
if (_packages.TryGetValue(Tuple.Create(id, version), out package))
|
|
||||||
{
|
|
||||||
return package;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
_packages.Clear();
|
|
||||||
_projects.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using NuGet.LibraryModel;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
internal class ProjectLibraryDependency : LibraryDependency
|
|
||||||
{
|
|
||||||
public string SourceFilePath { get; set; }
|
|
||||||
public int SourceLine { get; set; }
|
|
||||||
public int SourceColumn { get; set; }
|
|
||||||
|
|
||||||
public ProjectLibraryDependency()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProjectLibraryDependency(LibraryRange libraryRange)
|
|
||||||
{
|
|
||||||
LibraryRange = libraryRange;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
internal interface IProjectReader
|
|
||||||
{
|
|
||||||
Project ReadProject(string projectPath, ProjectReaderSettings settings = null);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
internal static class EmptyArray<T>
|
|
||||||
{
|
|
||||||
#if NET451
|
|
||||||
public static readonly T[] Value = new T[0];
|
|
||||||
#else
|
|
||||||
public static readonly T[] Value = System.Array.Empty<T>();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,77 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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.Linq;
|
|
||||||
using Microsoft.DotNet.PlatformAbstractions;
|
|
||||||
using NuGet.Frameworks;
|
|
||||||
using NuGet.LibraryModel;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Represents the result of resolving the library
|
|
||||||
/// </summary>
|
|
||||||
internal class LibraryDescription
|
|
||||||
{
|
|
||||||
public LibraryDescription(
|
|
||||||
LibraryIdentity identity,
|
|
||||||
string hash,
|
|
||||||
string path,
|
|
||||||
IEnumerable<ProjectLibraryDependency> dependencies,
|
|
||||||
NuGetFramework framework,
|
|
||||||
bool resolved,
|
|
||||||
bool compatible)
|
|
||||||
{
|
|
||||||
Path = path;
|
|
||||||
Identity = identity;
|
|
||||||
Hash = hash;
|
|
||||||
Dependencies = dependencies ?? Enumerable.Empty<ProjectLibraryDependency>();
|
|
||||||
Framework = framework;
|
|
||||||
Resolved = resolved;
|
|
||||||
Compatible = compatible;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LibraryIdentity Identity { get; }
|
|
||||||
public string Hash { get; }
|
|
||||||
public HashSet<ProjectLibraryDependency> RequestedRanges { get; } =
|
|
||||||
new HashSet<ProjectLibraryDependency>(new LibraryRangeEqualityComparer());
|
|
||||||
public List<LibraryDescription> Parents { get; } = new List<LibraryDescription>();
|
|
||||||
public string Path { get; }
|
|
||||||
public IEnumerable<ProjectLibraryDependency> Dependencies { get; }
|
|
||||||
public bool Compatible { get; }
|
|
||||||
|
|
||||||
public NuGetFramework Framework { get; set; }
|
|
||||||
public bool Resolved { get; set; }
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return $"{Identity} ({Identity.Type}) = {Path}";
|
|
||||||
}
|
|
||||||
|
|
||||||
// For diagnostics, we don't want to duplicate requested dependencies so we
|
|
||||||
// dedupe dependencies defined in project.json
|
|
||||||
private class LibraryRangeEqualityComparer : IEqualityComparer<ProjectLibraryDependency>
|
|
||||||
{
|
|
||||||
public bool Equals(ProjectLibraryDependency x, ProjectLibraryDependency y)
|
|
||||||
{
|
|
||||||
return x.Equals(y) &&
|
|
||||||
x.SourceColumn == y.SourceColumn &&
|
|
||||||
x.SourceLine == y.SourceLine &&
|
|
||||||
string.Equals(x.SourceFilePath, y.SourceFilePath, StringComparison.Ordinal);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GetHashCode(ProjectLibraryDependency obj)
|
|
||||||
{
|
|
||||||
var combiner = HashCodeCombiner.Start();
|
|
||||||
combiner.Add(obj);
|
|
||||||
combiner.Add(obj.SourceFilePath);
|
|
||||||
combiner.Add(obj.SourceLine);
|
|
||||||
combiner.Add(obj.SourceColumn);
|
|
||||||
|
|
||||||
return combiner.CombinedHash;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using NuGet.LibraryModel;
|
|
||||||
using NuGet.ProjectModel;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Represents an MSBuild project.
|
|
||||||
/// It has been invisibly built by MSBuild, so it behaves like a package: can provide all assets up front
|
|
||||||
///
|
|
||||||
/// Path points to the project's directory
|
|
||||||
/// MSBuildPRojectPath points to the csproj file
|
|
||||||
/// </summary>
|
|
||||||
internal class MSBuildProjectDescription : TargetLibraryWithAssets
|
|
||||||
{
|
|
||||||
public MSBuildProjectDescription(
|
|
||||||
string path,
|
|
||||||
string msbuildProjectPath,
|
|
||||||
LockFileLibrary projectLibrary,
|
|
||||||
LockFileTargetLibrary lockFileLibrary,
|
|
||||||
Project projectFile,
|
|
||||||
IEnumerable<ProjectLibraryDependency> dependencies,
|
|
||||||
bool compatible,
|
|
||||||
bool resolved)
|
|
||||||
: base(
|
|
||||||
new LibraryIdentity(projectLibrary.Name, projectLibrary.Version, LibraryType.Project),
|
|
||||||
string.Empty, //msbuild projects don't have hashes
|
|
||||||
path,
|
|
||||||
lockFileLibrary,
|
|
||||||
dependencies,
|
|
||||||
resolved: resolved,
|
|
||||||
compatible: compatible,
|
|
||||||
framework: null)
|
|
||||||
{
|
|
||||||
MSBuildProjectPath = msbuildProjectPath;
|
|
||||||
ProjectFile = projectFile;
|
|
||||||
ProjectLibrary = projectLibrary;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LockFileLibrary ProjectLibrary { get; }
|
|
||||||
|
|
||||||
public string MSBuildProjectPath { get; set; }
|
|
||||||
|
|
||||||
public Project ProjectFile { get; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
internal class OutputPaths
|
|
||||||
{
|
|
||||||
private readonly string _runtimePath;
|
|
||||||
private readonly RuntimeOutputFiles _runtimeFiles;
|
|
||||||
|
|
||||||
public OutputPaths(string intermediateOutputDirectoryPath,
|
|
||||||
string compilationOutputPath,
|
|
||||||
string runtimePath,
|
|
||||||
CompilationOutputFiles compilationFiles,
|
|
||||||
RuntimeOutputFiles runtimeFiles)
|
|
||||||
{
|
|
||||||
_runtimePath = runtimePath;
|
|
||||||
_runtimeFiles = runtimeFiles;
|
|
||||||
CompilationOutputPath = compilationOutputPath;
|
|
||||||
IntermediateOutputDirectoryPath = intermediateOutputDirectoryPath;
|
|
||||||
CompilationFiles = compilationFiles;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string CompilationOutputPath { get; }
|
|
||||||
|
|
||||||
public string IntermediateOutputDirectoryPath { get; }
|
|
||||||
|
|
||||||
public string RuntimeOutputPath
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_runtimePath == null)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException(
|
|
||||||
$"Cannot get runtime output path for {nameof(OutputPaths)} with no runtime set");
|
|
||||||
}
|
|
||||||
return _runtimePath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public CompilationOutputFiles CompilationFiles { get; }
|
|
||||||
|
|
||||||
public RuntimeOutputFiles RuntimeFiles
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_runtimeFiles == null)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException(
|
|
||||||
$"Cannot get runtime output files for {nameof(OutputPaths)} with no runtime set");
|
|
||||||
}
|
|
||||||
return _runtimeFiles;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,77 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System.IO;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.Utilities;
|
|
||||||
using NuGet.Frameworks;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
internal class OutputPathsCalculator
|
|
||||||
{
|
|
||||||
private const string ObjDirectoryName = "obj";
|
|
||||||
private const string BinDirectoryName = "bin";
|
|
||||||
|
|
||||||
public static OutputPaths GetOutputPaths(
|
|
||||||
Project project,
|
|
||||||
NuGetFramework framework,
|
|
||||||
string runtimeIdentifier,
|
|
||||||
string configuration,
|
|
||||||
string solutionRootPath,
|
|
||||||
string buildBasePath,
|
|
||||||
string outputPath)
|
|
||||||
{
|
|
||||||
string resolvedBuildBasePath;
|
|
||||||
if (string.IsNullOrEmpty(buildBasePath))
|
|
||||||
{
|
|
||||||
resolvedBuildBasePath = project.ProjectDirectory;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(solutionRootPath))
|
|
||||||
{
|
|
||||||
resolvedBuildBasePath = Path.Combine(buildBasePath, project.Name);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
resolvedBuildBasePath = project.ProjectDirectory.Replace(solutionRootPath, buildBasePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var compilationOutputPath = PathUtility.EnsureTrailingSlash(Path.Combine(resolvedBuildBasePath,
|
|
||||||
BinDirectoryName,
|
|
||||||
configuration,
|
|
||||||
framework.GetShortFolderName()));
|
|
||||||
|
|
||||||
string runtimeOutputPath = null;
|
|
||||||
if (string.IsNullOrEmpty(outputPath))
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(runtimeIdentifier))
|
|
||||||
{
|
|
||||||
runtimeOutputPath = PathUtility.EnsureTrailingSlash(Path.Combine(compilationOutputPath, runtimeIdentifier));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// "Runtime" assets (i.e. the deps file) will be dropped to the compilation output path, because
|
|
||||||
// we are building a RID-less target.
|
|
||||||
runtimeOutputPath = compilationOutputPath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
runtimeOutputPath = PathUtility.EnsureTrailingSlash(Path.GetFullPath(outputPath));
|
|
||||||
}
|
|
||||||
|
|
||||||
var intermediateOutputPath = PathUtility.EnsureTrailingSlash(Path.Combine(
|
|
||||||
resolvedBuildBasePath,
|
|
||||||
ObjDirectoryName,
|
|
||||||
configuration,
|
|
||||||
framework.GetTwoDigitShortFolderName()));
|
|
||||||
|
|
||||||
var compilationFiles = new CompilationOutputFiles(compilationOutputPath, project, configuration, framework);
|
|
||||||
|
|
||||||
RuntimeOutputFiles runtimeFiles = new RuntimeOutputFiles(runtimeOutputPath, project, configuration, framework, runtimeIdentifier);
|
|
||||||
return new OutputPaths(intermediateOutputPath, compilationOutputPath, runtimeOutputPath, compilationFiles, runtimeFiles);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.Files;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
internal class PackOptions
|
|
||||||
{
|
|
||||||
public string[] Tags { get; set; }
|
|
||||||
|
|
||||||
public string[] Owners { get; set; }
|
|
||||||
|
|
||||||
public string ReleaseNotes { get; set; }
|
|
||||||
|
|
||||||
public string IconUrl { get; set; }
|
|
||||||
|
|
||||||
public string ProjectUrl { get; set; }
|
|
||||||
|
|
||||||
public string LicenseUrl { get; set; }
|
|
||||||
|
|
||||||
public bool RequireLicenseAcceptance { get; set; }
|
|
||||||
|
|
||||||
public string RepositoryType { get; set; }
|
|
||||||
|
|
||||||
public string RepositoryUrl { get; set; }
|
|
||||||
|
|
||||||
public string Summary { get; set; }
|
|
||||||
|
|
||||||
public IncludeContext PackInclude { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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 Microsoft.DotNet.Internal.ProjectModel.Resolution;
|
|
||||||
using NuGet.LibraryModel;
|
|
||||||
using NuGet.ProjectModel;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
internal class PackageDescription : TargetLibraryWithAssets
|
|
||||||
{
|
|
||||||
public PackageDescription(
|
|
||||||
string path,
|
|
||||||
string hashPath,
|
|
||||||
LockFileLibrary package,
|
|
||||||
LockFileTargetLibrary lockFileLibrary,
|
|
||||||
IEnumerable<ProjectLibraryDependency> dependencies,
|
|
||||||
bool compatible,
|
|
||||||
bool resolved)
|
|
||||||
: base(
|
|
||||||
new LibraryIdentity(package.Name, package.Version, LibraryType.Package),
|
|
||||||
"sha512-" + package.Sha512,
|
|
||||||
path,
|
|
||||||
lockFileLibrary,
|
|
||||||
dependencies,
|
|
||||||
resolved: resolved,
|
|
||||||
compatible: compatible,
|
|
||||||
framework: null)
|
|
||||||
{
|
|
||||||
HashPath = hashPath;
|
|
||||||
PackageLibrary = package;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string HashPath { get; }
|
|
||||||
|
|
||||||
public LockFileLibrary PackageLibrary { get; }
|
|
||||||
|
|
||||||
public override IEnumerable<LockFileItem> RuntimeAssemblies => FilterPlaceholders(base.RuntimeAssemblies);
|
|
||||||
|
|
||||||
public override IEnumerable<LockFileItem> CompileTimeAssemblies => FilterPlaceholders(base.CompileTimeAssemblies);
|
|
||||||
|
|
||||||
public bool HasCompileTimePlaceholder =>
|
|
||||||
base.CompileTimeAssemblies.Any() &&
|
|
||||||
base.CompileTimeAssemblies.All(a => PackageDependencyProvider.IsPlaceholderFile(a.Path));
|
|
||||||
|
|
||||||
private static IEnumerable<LockFileItem> FilterPlaceholders(IEnumerable<LockFileItem> items)
|
|
||||||
{
|
|
||||||
return items.Where(a => !PackageDependencyProvider.IsPlaceholderFile(a.Path));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,156 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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.IO;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.Files;
|
|
||||||
using NuGet.Frameworks;
|
|
||||||
using NuGet.Versioning;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
internal class Project
|
|
||||||
{
|
|
||||||
public static readonly string FileName = "project.json";
|
|
||||||
|
|
||||||
// REVIEW: It's kinda hacky making these internal but the reader needs to set them
|
|
||||||
internal Dictionary<NuGetFramework, TargetFrameworkInformation> _targetFrameworks = new Dictionary<NuGetFramework, TargetFrameworkInformation>();
|
|
||||||
internal Dictionary<string, CommonCompilerOptions> _compilerOptionsByConfiguration = new Dictionary<string, CommonCompilerOptions>(StringComparer.OrdinalIgnoreCase);
|
|
||||||
|
|
||||||
internal CommonCompilerOptions _defaultCompilerOptions;
|
|
||||||
internal TargetFrameworkInformation _defaultTargetFrameworkConfiguration;
|
|
||||||
|
|
||||||
public Project()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public string ProjectFilePath { get; set; }
|
|
||||||
|
|
||||||
public string ProjectDirectory
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return Path.GetDirectoryName(ProjectFilePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public AnalyzerOptions AnalyzerOptions { get; set; }
|
|
||||||
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
public string Title { get; set; }
|
|
||||||
|
|
||||||
public string Description { get; set; }
|
|
||||||
|
|
||||||
public string Copyright { get; set; }
|
|
||||||
|
|
||||||
public string Language { get; set; }
|
|
||||||
|
|
||||||
public string[] Authors { get; set; }
|
|
||||||
|
|
||||||
public bool EmbedInteropTypes { get; set; }
|
|
||||||
|
|
||||||
public NuGetVersion Version { get; set; }
|
|
||||||
|
|
||||||
public Version AssemblyFileVersion { get; set; }
|
|
||||||
|
|
||||||
public IList<ProjectLibraryDependency> Dependencies { get; set; }
|
|
||||||
|
|
||||||
public List<ProjectLibraryDependency> Tools { get; set; }
|
|
||||||
|
|
||||||
public string EntryPoint { get; set; }
|
|
||||||
|
|
||||||
public string TestRunner { get; set; }
|
|
||||||
|
|
||||||
public ProjectFilesCollection Files { get; set; }
|
|
||||||
|
|
||||||
public PackOptions PackOptions { get; set; }
|
|
||||||
|
|
||||||
public bool Serviceable { get; set; }
|
|
||||||
|
|
||||||
public RuntimeOptions RuntimeOptions { get; set; }
|
|
||||||
|
|
||||||
public IList<string> Runtimes { get; set; }
|
|
||||||
|
|
||||||
public IDictionary<string, string> Commands { get; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
|
||||||
|
|
||||||
public IDictionary<string, IEnumerable<string>> Scripts { get; } = new Dictionary<string, IEnumerable<string>>(StringComparer.OrdinalIgnoreCase);
|
|
||||||
|
|
||||||
public string RawRuntimeOptions { get; set; }
|
|
||||||
|
|
||||||
public IncludeContext PublishOptions { get; set; }
|
|
||||||
|
|
||||||
public List<DiagnosticMessage> Diagnostics { get; } = new List<DiagnosticMessage>();
|
|
||||||
|
|
||||||
public bool IsTestProject => !string.IsNullOrEmpty(TestRunner);
|
|
||||||
|
|
||||||
public IEnumerable<TargetFrameworkInformation> GetTargetFrameworks()
|
|
||||||
{
|
|
||||||
return _targetFrameworks.Values;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<string> GetConfigurations()
|
|
||||||
{
|
|
||||||
return _compilerOptionsByConfiguration.Keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CommonCompilerOptions GetCompilerOptions(NuGetFramework targetFramework, string configurationName)
|
|
||||||
{
|
|
||||||
// Get all project options and combine them
|
|
||||||
var rootOptions = GetCompilerOptions();
|
|
||||||
var configurationOptions = configurationName != null ? GetRawCompilerOptions(configurationName) : null;
|
|
||||||
var targetFrameworkOptions = targetFramework != null ? GetRawCompilerOptions(targetFramework) : null;
|
|
||||||
|
|
||||||
// Combine all of the options
|
|
||||||
var compilerOptions = CommonCompilerOptions.Combine(rootOptions, configurationOptions, targetFrameworkOptions);
|
|
||||||
|
|
||||||
if (compilerOptions.OutputName == null)
|
|
||||||
{
|
|
||||||
compilerOptions.OutputName = Name;
|
|
||||||
}
|
|
||||||
|
|
||||||
return compilerOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TargetFrameworkInformation GetTargetFramework(NuGetFramework targetFramework)
|
|
||||||
{
|
|
||||||
TargetFrameworkInformation targetFrameworkInfo = null;
|
|
||||||
if (targetFramework != null && _targetFrameworks.TryGetValue(targetFramework, out targetFrameworkInfo))
|
|
||||||
{
|
|
||||||
return targetFrameworkInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
return targetFrameworkInfo ?? _defaultTargetFrameworkConfiguration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasRuntimeOutput(string configuration)
|
|
||||||
{
|
|
||||||
var compilerOptions = GetCompilerOptions(targetFramework: null, configurationName: configuration);
|
|
||||||
|
|
||||||
// TODO: Make this opt in via another mechanism
|
|
||||||
return compilerOptions.EmitEntryPoint.GetValueOrDefault() || IsTestProject;
|
|
||||||
}
|
|
||||||
|
|
||||||
private CommonCompilerOptions GetCompilerOptions()
|
|
||||||
{
|
|
||||||
return _defaultCompilerOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal CommonCompilerOptions GetRawCompilerOptions(string configurationName)
|
|
||||||
{
|
|
||||||
CommonCompilerOptions options;
|
|
||||||
if (_compilerOptionsByConfiguration.TryGetValue(configurationName, out options))
|
|
||||||
{
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal CommonCompilerOptions GetRawCompilerOptions(NuGetFramework frameworkName)
|
|
||||||
{
|
|
||||||
return GetTargetFramework(frameworkName)?.CompilerOptions;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,171 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.Compilation;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.Resolution;
|
|
||||||
using NuGet.Frameworks;
|
|
||||||
using NuGet.ProjectModel;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
internal class ProjectContext
|
|
||||||
{
|
|
||||||
private string[] _runtimeFallbacks;
|
|
||||||
|
|
||||||
public ProjectContextIdentity Identity { get; }
|
|
||||||
|
|
||||||
public GlobalSettings GlobalSettings { get; }
|
|
||||||
|
|
||||||
public ProjectDescription RootProject { get; }
|
|
||||||
|
|
||||||
public NuGetFramework TargetFramework { get; }
|
|
||||||
|
|
||||||
public LibraryDescription PlatformLibrary { get; }
|
|
||||||
|
|
||||||
public bool IsPortable { get; }
|
|
||||||
|
|
||||||
public string RuntimeIdentifier { get; }
|
|
||||||
|
|
||||||
public Project ProjectFile => RootProject?.Project;
|
|
||||||
|
|
||||||
public LockFile LockFile { get; }
|
|
||||||
|
|
||||||
public string RootDirectory => GlobalSettings?.DirectoryPath;
|
|
||||||
|
|
||||||
public string ProjectDirectory => ProjectFile?.ProjectDirectory;
|
|
||||||
|
|
||||||
public string PackagesDirectory { get; }
|
|
||||||
|
|
||||||
public LibraryManager LibraryManager { get; }
|
|
||||||
|
|
||||||
public List<DiagnosticMessage> Diagnostics { get; }
|
|
||||||
|
|
||||||
internal ProjectContext(
|
|
||||||
GlobalSettings globalSettings,
|
|
||||||
ProjectDescription rootProject,
|
|
||||||
LibraryDescription platformLibrary,
|
|
||||||
NuGetFramework targetFramework,
|
|
||||||
bool isPortable,
|
|
||||||
string runtimeIdentifier,
|
|
||||||
string packagesDirectory,
|
|
||||||
LibraryManager libraryManager,
|
|
||||||
LockFile lockfile,
|
|
||||||
List<DiagnosticMessage> diagnostics)
|
|
||||||
{
|
|
||||||
Identity = new ProjectContextIdentity(rootProject?.Path, targetFramework);
|
|
||||||
GlobalSettings = globalSettings;
|
|
||||||
RootProject = rootProject;
|
|
||||||
PlatformLibrary = platformLibrary;
|
|
||||||
TargetFramework = targetFramework;
|
|
||||||
RuntimeIdentifier = runtimeIdentifier;
|
|
||||||
PackagesDirectory = packagesDirectory;
|
|
||||||
LibraryManager = libraryManager;
|
|
||||||
LockFile = lockfile;
|
|
||||||
IsPortable = isPortable;
|
|
||||||
Diagnostics = diagnostics;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LibraryExporter CreateExporter(string configuration, string buildBasePath = null)
|
|
||||||
{
|
|
||||||
if (IsPortable && RuntimeIdentifier != null && _runtimeFallbacks == null)
|
|
||||||
{
|
|
||||||
var graph = RuntimeGraphCollector.Collect(LibraryManager.GetLibraries());
|
|
||||||
_runtimeFallbacks = graph.ExpandRuntime(RuntimeIdentifier).ToArray();
|
|
||||||
}
|
|
||||||
return new LibraryExporter(RootProject,
|
|
||||||
LibraryManager,
|
|
||||||
configuration,
|
|
||||||
RuntimeIdentifier,
|
|
||||||
_runtimeFallbacks,
|
|
||||||
buildBasePath,
|
|
||||||
RootDirectory);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a project context for the project located at <paramref name="projectPath"/>,
|
|
||||||
/// specifically in the context of the framework specified in <paramref name="framework"/>
|
|
||||||
/// </summary>
|
|
||||||
public static ProjectContext Create(string projectPath, NuGetFramework framework)
|
|
||||||
{
|
|
||||||
return Create(projectPath, framework, Enumerable.Empty<string>());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a project context for the project located at <paramref name="projectPath"/>,
|
|
||||||
/// specifically in the context of the framework specified in <paramref name="framework"/>
|
|
||||||
/// and the candidate runtime identifiers specified in <param name="runtimeIdentifiers"/>
|
|
||||||
/// </summary>
|
|
||||||
public static ProjectContext Create(string projectPath, NuGetFramework framework, IEnumerable<string> runtimeIdentifiers)
|
|
||||||
{
|
|
||||||
if (projectPath.EndsWith(Project.FileName))
|
|
||||||
{
|
|
||||||
projectPath = Path.GetDirectoryName(projectPath);
|
|
||||||
}
|
|
||||||
return new ProjectContextBuilder()
|
|
||||||
.WithProjectDirectory(projectPath)
|
|
||||||
.WithTargetFramework(framework)
|
|
||||||
.WithRuntimeIdentifiers(runtimeIdentifiers)
|
|
||||||
.Build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ProjectContextBuilder CreateBuilder(string projectPath, NuGetFramework framework)
|
|
||||||
{
|
|
||||||
if (projectPath.EndsWith(Project.FileName))
|
|
||||||
{
|
|
||||||
projectPath = Path.GetDirectoryName(projectPath);
|
|
||||||
}
|
|
||||||
return new ProjectContextBuilder()
|
|
||||||
.WithProjectDirectory(projectPath)
|
|
||||||
.WithTargetFramework(framework);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a project context for each framework located in the project at <paramref name="projectPath"/>
|
|
||||||
/// </summary>
|
|
||||||
public static IEnumerable<ProjectContext> CreateContextForEachFramework(string projectPath, ProjectReaderSettings settings = null, IEnumerable<string> runtimeIdentifiers = null)
|
|
||||||
{
|
|
||||||
if (!projectPath.EndsWith(Project.FileName))
|
|
||||||
{
|
|
||||||
projectPath = Path.Combine(projectPath, Project.FileName);
|
|
||||||
}
|
|
||||||
var project = ProjectReader.GetProject(projectPath, settings);
|
|
||||||
|
|
||||||
foreach (var framework in project.GetTargetFrameworks())
|
|
||||||
{
|
|
||||||
yield return new ProjectContextBuilder()
|
|
||||||
.WithProject(project)
|
|
||||||
.WithTargetFramework(framework.FrameworkName)
|
|
||||||
.WithProjectReaderSettings(settings)
|
|
||||||
.WithRuntimeIdentifiers(runtimeIdentifiers ?? Enumerable.Empty<string>())
|
|
||||||
.Build();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a project context for each target located in the project at <paramref name="projectPath"/>
|
|
||||||
/// </summary>
|
|
||||||
public static IEnumerable<ProjectContext> CreateContextForEachTarget(string projectPath, ProjectReaderSettings settings = null)
|
|
||||||
{
|
|
||||||
var project = ProjectReader.GetProject(projectPath);
|
|
||||||
|
|
||||||
return new ProjectContextBuilder()
|
|
||||||
.WithProjectReaderSettings(settings)
|
|
||||||
.WithProject(project)
|
|
||||||
.BuildAllTargets();
|
|
||||||
}
|
|
||||||
|
|
||||||
public OutputPaths GetOutputPaths(string configuration, string buidBasePath = null, string outputPath = null)
|
|
||||||
{
|
|
||||||
return OutputPathsCalculator.GetOutputPaths(ProjectFile,
|
|
||||||
TargetFramework,
|
|
||||||
RuntimeIdentifier,
|
|
||||||
configuration,
|
|
||||||
RootDirectory,
|
|
||||||
buidBasePath,
|
|
||||||
outputPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,708 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Microsoft.DotNet.Cli.Utils;
|
|
||||||
using Microsoft.DotNet.PlatformAbstractions;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.Graph;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.Resolution;
|
|
||||||
using NuGet.Common;
|
|
||||||
using NuGet.Configuration;
|
|
||||||
using NuGet.Frameworks;
|
|
||||||
using NuGet.LibraryModel;
|
|
||||||
using NuGet.ProjectModel;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
internal class ProjectContextBuilder
|
|
||||||
{
|
|
||||||
// Note: When adding a property, make sure to add it to Clone below. You'll also need to update the CloneTest in
|
|
||||||
// Microsoft.DotNet.ProjectModel.Tests.ProjectContextBuilderTests
|
|
||||||
|
|
||||||
private Project Project { get; set; }
|
|
||||||
|
|
||||||
private LockFile LockFile { get; set; }
|
|
||||||
|
|
||||||
private NuGetFramework TargetFramework { get; set; }
|
|
||||||
|
|
||||||
private IEnumerable<string> RuntimeIdentifiers { get; set; } = Enumerable.Empty<string>();
|
|
||||||
|
|
||||||
private string RootDirectory { get; set; }
|
|
||||||
|
|
||||||
private string ProjectDirectory { get; set; }
|
|
||||||
|
|
||||||
private string PackagesDirectory { get; set; }
|
|
||||||
|
|
||||||
private string ReferenceAssembliesPath { get; set; }
|
|
||||||
|
|
||||||
private bool IsDesignTime { get; set; }
|
|
||||||
|
|
||||||
private Func<string, Project> ProjectResolver { get; set; }
|
|
||||||
|
|
||||||
private Func<string, LockFile> LockFileResolver { get; set; }
|
|
||||||
|
|
||||||
private ProjectReaderSettings ProjectReaderSettings { get; set; } = ProjectReaderSettings.ReadFromEnvironment();
|
|
||||||
|
|
||||||
public ProjectContextBuilder()
|
|
||||||
{
|
|
||||||
ProjectResolver = ResolveProject;
|
|
||||||
LockFileResolver = ResolveLockFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProjectContextBuilder Clone()
|
|
||||||
{
|
|
||||||
var builder = new ProjectContextBuilder()
|
|
||||||
.WithLockFile(LockFile)
|
|
||||||
.WithProject(Project)
|
|
||||||
.WithProjectDirectory(ProjectDirectory)
|
|
||||||
.WithTargetFramework(TargetFramework)
|
|
||||||
.WithRuntimeIdentifiers(RuntimeIdentifiers)
|
|
||||||
.WithReferenceAssembliesPath(ReferenceAssembliesPath)
|
|
||||||
.WithPackagesDirectory(PackagesDirectory)
|
|
||||||
.WithRootDirectory(RootDirectory)
|
|
||||||
.WithProjectResolver(ProjectResolver)
|
|
||||||
.WithLockFileResolver(LockFileResolver)
|
|
||||||
.WithProjectReaderSettings(ProjectReaderSettings);
|
|
||||||
if (IsDesignTime)
|
|
||||||
{
|
|
||||||
builder.AsDesignTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProjectContextBuilder WithLockFile(LockFile lockFile)
|
|
||||||
{
|
|
||||||
LockFile = lockFile;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProjectContextBuilder WithProject(Project project)
|
|
||||||
{
|
|
||||||
Project = project;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProjectContextBuilder WithProjectDirectory(string projectDirectory)
|
|
||||||
{
|
|
||||||
ProjectDirectory = projectDirectory;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProjectContextBuilder WithTargetFramework(NuGetFramework targetFramework)
|
|
||||||
{
|
|
||||||
TargetFramework = targetFramework;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProjectContextBuilder WithTargetFramework(string targetFramework)
|
|
||||||
{
|
|
||||||
TargetFramework = NuGetFramework.Parse(targetFramework);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProjectContextBuilder WithRuntimeIdentifiers(IEnumerable<string> runtimeIdentifiers)
|
|
||||||
{
|
|
||||||
RuntimeIdentifiers = runtimeIdentifiers;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProjectContextBuilder WithReferenceAssembliesPath(string referenceAssembliesPath)
|
|
||||||
{
|
|
||||||
ReferenceAssembliesPath = referenceAssembliesPath;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProjectContextBuilder WithPackagesDirectory(string packagesDirectory)
|
|
||||||
{
|
|
||||||
PackagesDirectory = packagesDirectory;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProjectContextBuilder WithRootDirectory(string rootDirectory)
|
|
||||||
{
|
|
||||||
RootDirectory = rootDirectory;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProjectContextBuilder WithProjectResolver(Func<string, Project> projectResolver)
|
|
||||||
{
|
|
||||||
ProjectResolver = projectResolver;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProjectContextBuilder WithLockFileResolver(Func<string, LockFile> lockFileResolver)
|
|
||||||
{
|
|
||||||
LockFileResolver = lockFileResolver;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProjectContextBuilder WithProjectReaderSettings(ProjectReaderSettings projectReaderSettings)
|
|
||||||
{
|
|
||||||
ProjectReaderSettings = projectReaderSettings;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProjectContextBuilder AsDesignTime()
|
|
||||||
{
|
|
||||||
IsDesignTime = true;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Produce all targets found in the lock file associated with this builder.
|
|
||||||
/// Returns an empty enumerable if there is no lock file
|
|
||||||
/// (making this unsuitable for scenarios where the lock file may not be present,
|
|
||||||
/// such as at design-time)
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public IEnumerable<ProjectContext> BuildAllTargets()
|
|
||||||
{
|
|
||||||
ProjectDirectory = Project?.ProjectDirectory ?? ProjectDirectory;
|
|
||||||
EnsureProjectLoaded();
|
|
||||||
LockFile = LockFile ?? LockFileResolver(ProjectDirectory);
|
|
||||||
|
|
||||||
if (LockFile != null)
|
|
||||||
{
|
|
||||||
var deduper = new HashSet<string>();
|
|
||||||
foreach (var target in LockFile.Targets)
|
|
||||||
{
|
|
||||||
var context = Clone()
|
|
||||||
.WithTargetFramework(target.TargetFramework)
|
|
||||||
.WithRuntimeIdentifiers(new[] { target.RuntimeIdentifier }).Build();
|
|
||||||
|
|
||||||
var id = $"{context.TargetFramework}/{context.RuntimeIdentifier}";
|
|
||||||
if (deduper.Add(id))
|
|
||||||
{
|
|
||||||
yield return context;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Build a context for each framework. It won't be fully valid, since it won't have resolved data or runtime data, but the diagnostics will show that.
|
|
||||||
foreach (var framework in Project.GetTargetFrameworks())
|
|
||||||
{
|
|
||||||
var builder = new ProjectContextBuilder()
|
|
||||||
.WithProject(Project)
|
|
||||||
.WithTargetFramework(framework.FrameworkName);
|
|
||||||
if (IsDesignTime)
|
|
||||||
{
|
|
||||||
builder.AsDesignTime();
|
|
||||||
}
|
|
||||||
yield return builder.Build();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProjectContext Build()
|
|
||||||
{
|
|
||||||
var diagnostics = new List<DiagnosticMessage>();
|
|
||||||
|
|
||||||
ProjectDirectory = Project?.ProjectDirectory ?? ProjectDirectory;
|
|
||||||
|
|
||||||
GlobalSettings globalSettings = null;
|
|
||||||
if (ProjectDirectory != null)
|
|
||||||
{
|
|
||||||
RootDirectory = ProjectRootResolver.ResolveRootDirectory(ProjectDirectory);
|
|
||||||
GlobalSettings.TryGetGlobalSettings(RootDirectory, out globalSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
RootDirectory = globalSettings?.DirectoryPath ?? RootDirectory;
|
|
||||||
|
|
||||||
FrameworkReferenceResolver frameworkReferenceResolver;
|
|
||||||
if (string.IsNullOrEmpty(ReferenceAssembliesPath))
|
|
||||||
{
|
|
||||||
// Use the default static resolver
|
|
||||||
frameworkReferenceResolver = FrameworkReferenceResolver.Default;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
frameworkReferenceResolver = new FrameworkReferenceResolver(ReferenceAssembliesPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
LockFileLookup lockFileLookup = null;
|
|
||||||
EnsureProjectLoaded();
|
|
||||||
|
|
||||||
ReadLockFile(diagnostics);
|
|
||||||
|
|
||||||
// some callers only give ProjectContextBuilder a LockFile
|
|
||||||
ProjectDirectory = ProjectDirectory ?? TryGetProjectDirectoryFromLockFile();
|
|
||||||
|
|
||||||
INuGetPathContext nugetPathContext = null;
|
|
||||||
if (ProjectDirectory != null)
|
|
||||||
{
|
|
||||||
nugetPathContext = NuGetPathContext.Create(ProjectDirectory);
|
|
||||||
}
|
|
||||||
|
|
||||||
PackagesDirectory = PackagesDirectory ?? nugetPathContext?.UserPackageFolder;
|
|
||||||
|
|
||||||
var validLockFile = true;
|
|
||||||
string lockFileValidationMessage = null;
|
|
||||||
|
|
||||||
if (LockFile != null)
|
|
||||||
{
|
|
||||||
if (Project != null)
|
|
||||||
{
|
|
||||||
validLockFile = LockFile.IsValidForProject(Project, out lockFileValidationMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
lockFileLookup = new LockFileLookup(LockFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
var libraries = new Dictionary<LibraryKey, LibraryDescription>();
|
|
||||||
var projectResolver = new ProjectDependencyProvider(ProjectResolver);
|
|
||||||
|
|
||||||
ProjectDescription mainProject = null;
|
|
||||||
if (Project != null)
|
|
||||||
{
|
|
||||||
mainProject = projectResolver.GetDescription(TargetFramework, Project, targetLibrary: null);
|
|
||||||
|
|
||||||
// Add the main project
|
|
||||||
libraries.Add(new LibraryKey(mainProject.Identity.Name), mainProject);
|
|
||||||
}
|
|
||||||
|
|
||||||
ProjectLibraryDependency platformDependency = null;
|
|
||||||
if (mainProject != null)
|
|
||||||
{
|
|
||||||
platformDependency = mainProject.Dependencies
|
|
||||||
.Where(d => d.Type.Equals(LibraryDependencyType.Platform))
|
|
||||||
.Cast<ProjectLibraryDependency>()
|
|
||||||
.FirstOrDefault();
|
|
||||||
}
|
|
||||||
bool isPortable = platformDependency != null;
|
|
||||||
|
|
||||||
LockFileTarget target = null;
|
|
||||||
LibraryDescription platformLibrary = null;
|
|
||||||
|
|
||||||
if (lockFileLookup != null)
|
|
||||||
{
|
|
||||||
target = SelectTarget(LockFile, isPortable);
|
|
||||||
if (target != null)
|
|
||||||
{
|
|
||||||
var nugetPackageResolver = new PackageDependencyProvider(nugetPathContext, frameworkReferenceResolver);
|
|
||||||
var msbuildProjectResolver = new MSBuildDependencyProvider(Project, ProjectResolver);
|
|
||||||
ScanLibraries(target, lockFileLookup, libraries, msbuildProjectResolver, nugetPackageResolver, projectResolver);
|
|
||||||
|
|
||||||
if (platformDependency != null)
|
|
||||||
{
|
|
||||||
libraries.TryGetValue(new LibraryKey(platformDependency.Name), out platformLibrary);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
string runtime = target?.RuntimeIdentifier;
|
|
||||||
if (string.IsNullOrEmpty(runtime) && TargetFramework.IsDesktop())
|
|
||||||
{
|
|
||||||
// we got a ridless target for desktop so turning portable mode on
|
|
||||||
isPortable = true;
|
|
||||||
var legacyRuntime = RuntimeEnvironmentRidExtensions.GetLegacyRestoreRuntimeIdentifier();
|
|
||||||
if (RuntimeIdentifiers.Contains(legacyRuntime))
|
|
||||||
{
|
|
||||||
runtime = legacyRuntime;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
runtime = RuntimeIdentifiers.FirstOrDefault();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var referenceAssemblyDependencyResolver = new ReferenceAssemblyDependencyResolver(frameworkReferenceResolver);
|
|
||||||
bool requiresFrameworkAssemblies;
|
|
||||||
|
|
||||||
// Resolve the dependencies
|
|
||||||
ResolveDependencies(libraries, referenceAssemblyDependencyResolver, out requiresFrameworkAssemblies);
|
|
||||||
|
|
||||||
// REVIEW: Should this be in NuGet (possibly stored in the lock file?)
|
|
||||||
if (LockFile == null)
|
|
||||||
{
|
|
||||||
diagnostics.Add(new DiagnosticMessage(
|
|
||||||
ErrorCodes.NU1009,
|
|
||||||
$"The expected lock file doesn't exist. Please run \"dotnet restore\" to generate a new lock file.",
|
|
||||||
Path.Combine(Project.ProjectDirectory, LockFileFormat.LockFileName),
|
|
||||||
DiagnosticMessageSeverity.Error));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!validLockFile)
|
|
||||||
{
|
|
||||||
diagnostics.Add(new DiagnosticMessage(
|
|
||||||
ErrorCodes.NU1006,
|
|
||||||
$"{lockFileValidationMessage}. Please run \"dotnet restore\" to generate a new lock file.",
|
|
||||||
Path.Combine(Project.ProjectDirectory, LockFileFormat.LockFileName),
|
|
||||||
DiagnosticMessageSeverity.Warning));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (requiresFrameworkAssemblies)
|
|
||||||
{
|
|
||||||
var frameworkInfo = Project.GetTargetFramework(TargetFramework);
|
|
||||||
|
|
||||||
if (frameworkReferenceResolver == null || string.IsNullOrEmpty(frameworkReferenceResolver.ReferenceAssembliesPath))
|
|
||||||
{
|
|
||||||
// If there was an attempt to use reference assemblies but they were not installed
|
|
||||||
// report an error
|
|
||||||
diagnostics.Add(new DiagnosticMessage(
|
|
||||||
ErrorCodes.DOTNET1012,
|
|
||||||
$"The reference assemblies directory was not specified. You can set the location using the DOTNET_REFERENCE_ASSEMBLIES_PATH environment variable.",
|
|
||||||
filePath: Project.ProjectFilePath,
|
|
||||||
severity: DiagnosticMessageSeverity.Error,
|
|
||||||
startLine: frameworkInfo.Line,
|
|
||||||
startColumn: frameworkInfo.Column
|
|
||||||
));
|
|
||||||
}
|
|
||||||
else if (!frameworkReferenceResolver.IsInstalled(TargetFramework))
|
|
||||||
{
|
|
||||||
// If there was an attempt to use reference assemblies but they were not installed
|
|
||||||
// report an error
|
|
||||||
diagnostics.Add(new DiagnosticMessage(
|
|
||||||
ErrorCodes.DOTNET1011,
|
|
||||||
$"Framework not installed: {TargetFramework.DotNetFrameworkName} in {ReferenceAssembliesPath}",
|
|
||||||
filePath: Project.ProjectFilePath,
|
|
||||||
severity: DiagnosticMessageSeverity.Error,
|
|
||||||
startLine: frameworkInfo.Line,
|
|
||||||
startColumn: frameworkInfo.Column
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<DiagnosticMessage> allDiagnostics = new List<DiagnosticMessage>(diagnostics);
|
|
||||||
if (Project != null)
|
|
||||||
{
|
|
||||||
allDiagnostics.AddRange(Project.Diagnostics);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a library manager
|
|
||||||
var libraryManager = new LibraryManager(libraries.Values.ToList(), allDiagnostics, Project?.ProjectFilePath);
|
|
||||||
|
|
||||||
return new ProjectContext(
|
|
||||||
globalSettings,
|
|
||||||
mainProject,
|
|
||||||
platformLibrary,
|
|
||||||
TargetFramework,
|
|
||||||
isPortable,
|
|
||||||
runtime,
|
|
||||||
PackagesDirectory,
|
|
||||||
libraryManager,
|
|
||||||
LockFile,
|
|
||||||
diagnostics);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string TryGetProjectDirectoryFromLockFile()
|
|
||||||
{
|
|
||||||
string result = null;
|
|
||||||
|
|
||||||
if (LockFile != null && !string.IsNullOrEmpty(LockFile.Path))
|
|
||||||
{
|
|
||||||
result = Path.GetDirectoryName(LockFile.Path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ReadLockFile(ICollection<DiagnosticMessage> diagnostics)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
LockFile = LockFile ?? LockFileResolver(ProjectDirectory);
|
|
||||||
}
|
|
||||||
catch (FileFormatException e)
|
|
||||||
{
|
|
||||||
var lockFilePath = "";
|
|
||||||
if (LockFile != null)
|
|
||||||
{
|
|
||||||
lockFilePath = LockFile.Path;
|
|
||||||
}
|
|
||||||
else if (Project != null)
|
|
||||||
{
|
|
||||||
lockFilePath = Path.Combine(Project.ProjectDirectory, LockFileFormat.LockFileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
diagnostics.Add(new DiagnosticMessage(
|
|
||||||
ErrorCodes.DOTNET1014,
|
|
||||||
ComposeMessageFromInnerExceptions(e),
|
|
||||||
lockFilePath,
|
|
||||||
DiagnosticMessageSeverity.Error));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ComposeMessageFromInnerExceptions(Exception exception)
|
|
||||||
{
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
var messages = new HashSet<string>();
|
|
||||||
|
|
||||||
while (exception != null)
|
|
||||||
{
|
|
||||||
messages.Add(exception.Message);
|
|
||||||
exception = exception.InnerException;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var message in messages)
|
|
||||||
{
|
|
||||||
sb.AppendLine(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ResolveDependencies(Dictionary<LibraryKey, LibraryDescription> libraries,
|
|
||||||
ReferenceAssemblyDependencyResolver referenceAssemblyDependencyResolver,
|
|
||||||
out bool requiresFrameworkAssemblies)
|
|
||||||
{
|
|
||||||
// Remark: the LibraryType in the key of the given dictionary are all "Unspecified" at the beginning.
|
|
||||||
requiresFrameworkAssemblies = false;
|
|
||||||
|
|
||||||
foreach (var pair in libraries.ToList())
|
|
||||||
{
|
|
||||||
var library = pair.Value;
|
|
||||||
|
|
||||||
// The System.* packages provide placeholders on any non netstandard platform
|
|
||||||
// To make them work seamlessly on those platforms, we fill the gap with a reference
|
|
||||||
// assembly (if available)
|
|
||||||
var package = library as PackageDescription;
|
|
||||||
if (package != null &&
|
|
||||||
package.Resolved &&
|
|
||||||
package.HasCompileTimePlaceholder &&
|
|
||||||
!TargetFramework.IsPackageBased)
|
|
||||||
{
|
|
||||||
// requiresFrameworkAssemblies is true whenever we find a CompileTimePlaceholder in a non-package based framework, even if
|
|
||||||
// the reference is unresolved. This ensures the best error experience when someone is building on a machine without
|
|
||||||
// the target framework installed.
|
|
||||||
requiresFrameworkAssemblies = true;
|
|
||||||
|
|
||||||
var newKey = new LibraryKey(library.Identity.Name, LibraryType.Reference);
|
|
||||||
var dependency = new ProjectLibraryDependency
|
|
||||||
{
|
|
||||||
LibraryRange = new LibraryRange(library.Identity.Name, LibraryDependencyTarget.Reference)
|
|
||||||
};
|
|
||||||
|
|
||||||
var replacement = referenceAssemblyDependencyResolver.GetDescription(dependency, TargetFramework);
|
|
||||||
|
|
||||||
// If the reference is unresolved, just skip it. Don't replace the package dependency
|
|
||||||
if (replacement == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the original package reference
|
|
||||||
libraries.Remove(pair.Key);
|
|
||||||
|
|
||||||
// Insert a reference assembly key if there isn't one
|
|
||||||
if (!libraries.ContainsKey(newKey))
|
|
||||||
{
|
|
||||||
libraries[newKey] = replacement;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var pair in libraries.ToList())
|
|
||||||
{
|
|
||||||
var library = pair.Value;
|
|
||||||
library.Framework = library.Framework ?? TargetFramework;
|
|
||||||
foreach (var dependency in library.Dependencies)
|
|
||||||
{
|
|
||||||
var keyType = dependency.LibraryRange.TypeConstraint == LibraryDependencyTarget.Reference ?
|
|
||||||
LibraryType.Reference :
|
|
||||||
(LibraryType?) null;
|
|
||||||
|
|
||||||
var key = new LibraryKey(dependency.Name, keyType);
|
|
||||||
|
|
||||||
LibraryDescription dependencyDescription;
|
|
||||||
if (!libraries.TryGetValue(key, out dependencyDescription))
|
|
||||||
{
|
|
||||||
if (keyType == LibraryType.Reference)
|
|
||||||
{
|
|
||||||
// a dependency is specified to be reference assembly but fail to match
|
|
||||||
// then add a unresolved dependency
|
|
||||||
dependencyDescription = referenceAssemblyDependencyResolver.GetDescription(dependency, TargetFramework) ??
|
|
||||||
UnresolvedDependencyProvider.GetDescription(dependency, TargetFramework);
|
|
||||||
libraries[key] = dependencyDescription;
|
|
||||||
}
|
|
||||||
else if (!libraries.TryGetValue(new LibraryKey(dependency.Name, LibraryType.Reference), out dependencyDescription))
|
|
||||||
{
|
|
||||||
// a dependency which type is unspecified fails to match, then try to find a
|
|
||||||
// reference assembly type dependency
|
|
||||||
dependencyDescription = UnresolvedDependencyProvider.GetDescription(dependency, TargetFramework);
|
|
||||||
libraries[key] = dependencyDescription;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencyDescription.RequestedRanges.Add(dependency);
|
|
||||||
dependencyDescription.Parents.Add(library);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deduplicate libraries with the same name
|
|
||||||
// Priority list is backwards so not found -1 would be last when sorting by descending
|
|
||||||
var priorities = new[] { LibraryType.Package, LibraryType.Project, LibraryType.Reference };
|
|
||||||
var nameGroups = libraries.Keys.ToLookup(libraryKey => libraryKey.Name);
|
|
||||||
foreach (var nameGroup in nameGroups)
|
|
||||||
{
|
|
||||||
var librariesToRemove = nameGroup
|
|
||||||
.OrderByDescending(libraryKey => Array.IndexOf(priorities, libraryKey.LibraryType))
|
|
||||||
.Skip(1);
|
|
||||||
|
|
||||||
foreach (var library in librariesToRemove)
|
|
||||||
{
|
|
||||||
libraries.Remove(library);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ScanLibraries(LockFileTarget target,
|
|
||||||
LockFileLookup lockFileLookup,
|
|
||||||
Dictionary<LibraryKey, LibraryDescription> libraries,
|
|
||||||
MSBuildDependencyProvider msbuildResolver,
|
|
||||||
PackageDependencyProvider packageResolver,
|
|
||||||
ProjectDependencyProvider projectResolver)
|
|
||||||
{
|
|
||||||
foreach (var library in target.Libraries)
|
|
||||||
{
|
|
||||||
LibraryDescription description = null;
|
|
||||||
LibraryDependencyTarget type = LibraryDependencyTarget.All;
|
|
||||||
|
|
||||||
if (string.Equals(library.Type, "project"))
|
|
||||||
{
|
|
||||||
var projectLibrary = lockFileLookup.GetProject(library.Name);
|
|
||||||
|
|
||||||
if (projectLibrary != null)
|
|
||||||
{
|
|
||||||
if (MSBuildDependencyProvider.IsMSBuildProjectLibrary(projectLibrary))
|
|
||||||
{
|
|
||||||
description = msbuildResolver.GetDescription(TargetFramework, projectLibrary, library, IsDesignTime);
|
|
||||||
type = LibraryDependencyTarget.Project;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var path = Path.GetFullPath(Path.Combine(ProjectDirectory, projectLibrary.Path));
|
|
||||||
description = projectResolver.GetDescription(library.Name, path, library, ProjectResolver);
|
|
||||||
type = LibraryDependencyTarget.Project;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var packageEntry = lockFileLookup.GetPackage(library.Name, library.Version);
|
|
||||||
|
|
||||||
if (packageEntry != null)
|
|
||||||
{
|
|
||||||
description = packageResolver.GetDescription(TargetFramework, packageEntry, library);
|
|
||||||
}
|
|
||||||
|
|
||||||
type = LibraryDependencyTarget.Package;
|
|
||||||
}
|
|
||||||
|
|
||||||
description = description ??
|
|
||||||
UnresolvedDependencyProvider.GetDescription(
|
|
||||||
new ProjectLibraryDependency
|
|
||||||
{
|
|
||||||
LibraryRange = new LibraryRange(library.Name, type)
|
|
||||||
},
|
|
||||||
target.TargetFramework);
|
|
||||||
|
|
||||||
libraries.Add(new LibraryKey(library.Name), description);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EnsureProjectLoaded()
|
|
||||||
{
|
|
||||||
if (Project == null && ProjectDirectory != null)
|
|
||||||
{
|
|
||||||
Project = ProjectResolver(ProjectDirectory);
|
|
||||||
if (Project == null)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"Could not resolve project at: {ProjectDirectory}. " +
|
|
||||||
$"This could happen when project.lock.json was moved after restore.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private LockFileTarget SelectTarget(LockFile lockFile, bool isPortable)
|
|
||||||
{
|
|
||||||
if (!isPortable)
|
|
||||||
{
|
|
||||||
foreach (var runtimeIdentifier in RuntimeIdentifiers)
|
|
||||||
{
|
|
||||||
foreach (var scanTarget in lockFile.Targets)
|
|
||||||
{
|
|
||||||
if (Equals(scanTarget.TargetFramework, TargetFramework) && string.Equals(scanTarget.RuntimeIdentifier, runtimeIdentifier, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
return scanTarget;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var scanTarget in lockFile.Targets)
|
|
||||||
{
|
|
||||||
if (Equals(scanTarget.TargetFramework, TargetFramework) && string.IsNullOrEmpty(scanTarget.RuntimeIdentifier))
|
|
||||||
{
|
|
||||||
return scanTarget;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Project ResolveProject(string projectDirectory)
|
|
||||||
{
|
|
||||||
Project project;
|
|
||||||
if (ProjectReader.TryGetProject(projectDirectory, out project, settings: ProjectReaderSettings))
|
|
||||||
{
|
|
||||||
return project;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static LockFile ResolveLockFile(string projectDir)
|
|
||||||
{
|
|
||||||
var projectLockJsonPath = Path.Combine(projectDir, LockFileFormat.LockFileName);
|
|
||||||
return File.Exists(projectLockJsonPath) ?
|
|
||||||
new LockFileFormat().Read(Path.Combine(projectDir, LockFileFormat.LockFileName)) :
|
|
||||||
null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private struct LibraryKey
|
|
||||||
{
|
|
||||||
public LibraryKey(string name) : this(name, null)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public LibraryKey(string name, LibraryType? libraryType)
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
LibraryType = libraryType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Name { get; }
|
|
||||||
public LibraryType? LibraryType { get; }
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
var otherKey = (LibraryKey)obj;
|
|
||||||
|
|
||||||
return string.Equals(otherKey.Name, Name, StringComparison.OrdinalIgnoreCase) &&
|
|
||||||
otherKey.LibraryType.Equals(LibraryType);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
var combiner = new HashCodeCombiner();
|
|
||||||
combiner.Add(Name.ToLowerInvariant());
|
|
||||||
combiner.Add(LibraryType);
|
|
||||||
|
|
||||||
return combiner.CombinedHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return Name + " " + LibraryType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,85 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using NuGet.Frameworks;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
internal class ProjectContextCollection
|
|
||||||
{
|
|
||||||
public Project Project { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets all the ProjectContexts in this collection
|
|
||||||
/// </summary>
|
|
||||||
public List<ProjectContext> ProjectContexts { get; } = new List<ProjectContext>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the ProjectContexts in this collection which are not runtime-specific (i.e. the ones used for compilation)
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<ProjectContext> FrameworkOnlyContexts => ProjectContexts.Where(c => string.IsNullOrEmpty(c.RuntimeIdentifier));
|
|
||||||
|
|
||||||
public List<DiagnosticMessage> ProjectDiagnostics { get; } = new List<DiagnosticMessage>();
|
|
||||||
|
|
||||||
public string LockFilePath { get; set; }
|
|
||||||
|
|
||||||
public string ProjectFilePath { get; set; }
|
|
||||||
|
|
||||||
public DateTime LastProjectFileWriteTimeUtc { get; set; }
|
|
||||||
|
|
||||||
public DateTime LastLockFileWriteTimeUtc { get; set; }
|
|
||||||
|
|
||||||
public bool HasChanged
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (ProjectFilePath == null || !File.Exists(ProjectFilePath))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (LastProjectFileWriteTimeUtc < File.GetLastWriteTimeUtc(ProjectFilePath))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (LockFilePath == null || !File.Exists(LockFilePath))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (LastLockFileWriteTimeUtc < File.GetLastWriteTimeUtc(LockFilePath))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProjectContext GetTarget(NuGetFramework targetFramework) => GetTarget(targetFramework, string.Empty);
|
|
||||||
|
|
||||||
public ProjectContext GetTarget(NuGetFramework targetFramework, string runtimeIdentifier)
|
|
||||||
{
|
|
||||||
return ProjectContexts
|
|
||||||
.FirstOrDefault(c =>
|
|
||||||
Equals(c.TargetFramework, targetFramework) &&
|
|
||||||
string.Equals(c.RuntimeIdentifier ?? string.Empty, runtimeIdentifier ?? string.Empty));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Reset()
|
|
||||||
{
|
|
||||||
Project = null;
|
|
||||||
ProjectContexts.Clear();
|
|
||||||
ProjectFilePath = null;
|
|
||||||
LockFilePath = null;
|
|
||||||
LastLockFileWriteTimeUtc = DateTime.MinValue;
|
|
||||||
LastProjectFileWriteTimeUtc = DateTime.MinValue;
|
|
||||||
ProjectDiagnostics.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using Microsoft.DotNet.PlatformAbstractions;
|
|
||||||
using NuGet.Frameworks;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
public struct ProjectContextIdentity
|
|
||||||
{
|
|
||||||
public ProjectContextIdentity(string path, NuGetFramework targetFramework)
|
|
||||||
{
|
|
||||||
Path = path;
|
|
||||||
TargetFramework = targetFramework;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Path { get; }
|
|
||||||
public NuGetFramework TargetFramework { get; }
|
|
||||||
|
|
||||||
public bool Equals(ProjectContextIdentity other)
|
|
||||||
{
|
|
||||||
return string.Equals(Path, other.Path) && Equals(TargetFramework, other.TargetFramework);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
if (ReferenceEquals(null, obj)) return false;
|
|
||||||
return obj is ProjectContextIdentity && Equals((ProjectContextIdentity) obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
var combiner = HashCodeCombiner.Start();
|
|
||||||
combiner.Add(Path);
|
|
||||||
combiner.Add(TargetFramework);
|
|
||||||
return combiner.CombinedHash;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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 NuGet.LibraryModel;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
internal class ProjectDescription : LibraryDescription
|
|
||||||
{
|
|
||||||
// Create an unresolved project description
|
|
||||||
public ProjectDescription(string name, string path)
|
|
||||||
: base(
|
|
||||||
new LibraryIdentity(name, null, LibraryType.Project),
|
|
||||||
string.Empty, // Projects don't have hashes
|
|
||||||
path,
|
|
||||||
Enumerable.Empty<ProjectLibraryDependency>(),
|
|
||||||
framework: null,
|
|
||||||
resolved: false,
|
|
||||||
compatible: false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProjectDescription(
|
|
||||||
LibraryRange libraryRange,
|
|
||||||
Project project,
|
|
||||||
IEnumerable<ProjectLibraryDependency> dependencies,
|
|
||||||
TargetFrameworkInformation targetFrameworkInfo,
|
|
||||||
bool resolved) :
|
|
||||||
base(
|
|
||||||
new LibraryIdentity(project.Name, project.Version, LibraryType.Project),
|
|
||||||
string.Empty, // Projects don't have hashes
|
|
||||||
project.ProjectFilePath,
|
|
||||||
dependencies,
|
|
||||||
targetFrameworkInfo.FrameworkName,
|
|
||||||
resolved,
|
|
||||||
compatible: true)
|
|
||||||
{
|
|
||||||
Project = project;
|
|
||||||
TargetFrameworkInfo = targetFrameworkInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Project Project { get; }
|
|
||||||
|
|
||||||
public TargetFrameworkInformation TargetFrameworkInfo { get; }
|
|
||||||
|
|
||||||
public OutputPaths GetOutputPaths(string buildBasePath, string solutionRootPath, string configuration, string runtime)
|
|
||||||
{
|
|
||||||
return OutputPathsCalculator.GetOutputPaths(Project,
|
|
||||||
Framework,
|
|
||||||
runtimeIdentifier: runtime,
|
|
||||||
configuration: configuration,
|
|
||||||
solutionRootPath: solutionRootPath,
|
|
||||||
buildBasePath: buildBasePath,
|
|
||||||
outputPath: null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
internal static class ProjectExtensions
|
|
||||||
{
|
|
||||||
private static readonly KeyValuePair<string, string>[] _compilerNameToLanguageId =
|
|
||||||
{
|
|
||||||
new KeyValuePair<string, string>("csc", "cs"),
|
|
||||||
new KeyValuePair<string, string>("vbc", "vb"),
|
|
||||||
new KeyValuePair<string, string>("fsc", "fs")
|
|
||||||
};
|
|
||||||
|
|
||||||
public static string GetSourceCodeLanguage(this Project project)
|
|
||||||
{
|
|
||||||
foreach (var kvp in _compilerNameToLanguageId)
|
|
||||||
{
|
|
||||||
if (kvp.Key == (project._defaultCompilerOptions.CompilerName))
|
|
||||||
{
|
|
||||||
return kvp.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using NuGet.Frameworks;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
internal class ProjectFileDependencyGroup
|
|
||||||
{
|
|
||||||
public ProjectFileDependencyGroup(NuGetFramework frameworkName, IEnumerable<string> dependencies)
|
|
||||||
{
|
|
||||||
FrameworkName = frameworkName;
|
|
||||||
Dependencies = dependencies;
|
|
||||||
}
|
|
||||||
|
|
||||||
public NuGetFramework FrameworkName { get; }
|
|
||||||
|
|
||||||
public IEnumerable<string> Dependencies { get; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,82 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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 Microsoft.DotNet.Internal.ProjectModel.Compilation;
|
|
||||||
using NuGet.LibraryModel;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
internal static class ProjectModelPlatformExtensions
|
|
||||||
{
|
|
||||||
public static HashSet<string> GetPlatformExclusionList(this ProjectContext context, IDictionary<string, LibraryExport> exports)
|
|
||||||
{
|
|
||||||
var exclusionList = new HashSet<string>();
|
|
||||||
var redistPackage = context.PlatformLibrary;
|
|
||||||
if (redistPackage == null)
|
|
||||||
{
|
|
||||||
return exclusionList;
|
|
||||||
}
|
|
||||||
|
|
||||||
var redistExport = exports[redistPackage.Identity.Name];
|
|
||||||
|
|
||||||
exclusionList.Add(redistExport.Library.Identity.Name);
|
|
||||||
CollectDependencies(exports, redistExport.Library.Dependencies, exclusionList);
|
|
||||||
return exclusionList;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void CollectDependencies(
|
|
||||||
IDictionary<string, LibraryExport> exports,
|
|
||||||
IEnumerable<LibraryDependency> dependencies,
|
|
||||||
HashSet<string> exclusionList)
|
|
||||||
{
|
|
||||||
foreach (var dependency in dependencies)
|
|
||||||
{
|
|
||||||
var export = exports[dependency.Name];
|
|
||||||
if (export.Library.Identity.Version.Equals(dependency.LibraryRange.VersionRange.MinVersion))
|
|
||||||
{
|
|
||||||
exclusionList.Add(export.Library.Identity.Name);
|
|
||||||
CollectDependencies(exports, export.Library.Dependencies, exclusionList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static HashSet<string> GetTypeBuildExclusionList(this ProjectContext context, IDictionary<string, LibraryExport> exports)
|
|
||||||
{
|
|
||||||
var acceptedExports = new HashSet<string>();
|
|
||||||
|
|
||||||
// Accept the root project, obviously :)
|
|
||||||
acceptedExports.Add(context.RootProject.Identity.Name);
|
|
||||||
|
|
||||||
// Walk all dependencies, tagging exports. But don't walk through Build dependencies.
|
|
||||||
CollectNonBuildDependencies(exports, context.RootProject.Dependencies, acceptedExports);
|
|
||||||
|
|
||||||
// Whatever is left in exports was brought in ONLY by a build dependency
|
|
||||||
var exclusionList = new HashSet<string>(exports.Keys);
|
|
||||||
exclusionList.ExceptWith(acceptedExports);
|
|
||||||
return exclusionList;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void CollectNonBuildDependencies(
|
|
||||||
IDictionary<string, LibraryExport> exports,
|
|
||||||
IEnumerable<LibraryDependency> dependencies,
|
|
||||||
HashSet<string> acceptedExports)
|
|
||||||
{
|
|
||||||
foreach (var dependency in dependencies)
|
|
||||||
{
|
|
||||||
var export = exports[dependency.Name];
|
|
||||||
if (!dependency.Type.Equals(LibraryDependencyType.Build))
|
|
||||||
{
|
|
||||||
acceptedExports.Add(export.Library.Identity.Name);
|
|
||||||
CollectNonBuildDependencies(exports, export.Library.Dependencies, acceptedExports);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<LibraryExport> FilterExports(this IEnumerable<LibraryExport> exports, HashSet<string> exclusionList)
|
|
||||||
{
|
|
||||||
return exports.Where(e => !exclusionList.Contains(e.Library.Identity.Name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
internal static class ProjectPathHelper
|
|
||||||
{
|
|
||||||
public static string NormalizeProjectDirectoryPath(string path)
|
|
||||||
{
|
|
||||||
string fullPath = Path.GetFullPath(path);
|
|
||||||
|
|
||||||
if (IsProjectFilePath(fullPath))
|
|
||||||
{
|
|
||||||
return Path.GetDirectoryName(fullPath);
|
|
||||||
}
|
|
||||||
else if (IsDirectoryContainingProjectFile(fullPath))
|
|
||||||
{
|
|
||||||
return fullPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string NormalizeProjectFilePath(string path)
|
|
||||||
{
|
|
||||||
if (!path.EndsWith(Project.FileName))
|
|
||||||
{
|
|
||||||
path = Path.Combine(path, Project.FileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Path.GetFullPath(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsProjectFilePath(string path)
|
|
||||||
{
|
|
||||||
return File.Exists(path) &&
|
|
||||||
string.Equals(Path.GetFileName(path), Project.FileName, StringComparison.OrdinalIgnoreCase);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsDirectoryContainingProjectFile(string path)
|
|
||||||
{
|
|
||||||
return Directory.Exists(path) && File.Exists(Path.Combine(path, Project.FileName));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,24 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
internal class ProjectReaderSettings
|
|
||||||
{
|
|
||||||
public string VersionSuffix { get; set; }
|
|
||||||
public string AssemblyFileVersion { get; set; }
|
|
||||||
|
|
||||||
public static ProjectReaderSettings ReadFromEnvironment()
|
|
||||||
{
|
|
||||||
var settings = new ProjectReaderSettings
|
|
||||||
{
|
|
||||||
VersionSuffix = Environment.GetEnvironmentVariable("DOTNET_BUILD_VERSION"),
|
|
||||||
AssemblyFileVersion = Environment.GetEnvironmentVariable("DOTNET_ASSEMBLY_FILE_VERSION")
|
|
||||||
};
|
|
||||||
|
|
||||||
return settings;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel
|
|
||||||
{
|
|
||||||
internal static class ProjectRootResolver
|
|
||||||
{
|
|
||||||
public static readonly string GlobalFileName = "global.json";
|
|
||||||
public static string ResolveRootDirectory(string projectPath)
|
|
||||||
{
|
|
||||||
var di = new DirectoryInfo(projectPath);
|
|
||||||
|
|
||||||
while (di.Parent != null)
|
|
||||||
{
|
|
||||||
var globalJsonPath = Path.Combine(di.FullName, GlobalFileName);
|
|
||||||
|
|
||||||
if (File.Exists(globalJsonPath))
|
|
||||||
{
|
|
||||||
return di.FullName;
|
|
||||||
}
|
|
||||||
|
|
||||||
di = di.Parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we don't find any files then make the project folder the root
|
|
||||||
return projectPath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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.IO;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.Resolution
|
|
||||||
{
|
|
||||||
internal class FrameworkInformation
|
|
||||||
{
|
|
||||||
private bool? _exists;
|
|
||||||
|
|
||||||
public FrameworkInformation()
|
|
||||||
{
|
|
||||||
Assemblies = new Dictionary<string, AssemblyEntry>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Exists
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_exists == null)
|
|
||||||
{
|
|
||||||
_exists = Directory.Exists(Path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _exists.Value;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_exists = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Path { get; set; }
|
|
||||||
|
|
||||||
public IEnumerable<string> SearchPaths { get; set; }
|
|
||||||
|
|
||||||
public string RedistListPath { get; set; }
|
|
||||||
|
|
||||||
public IDictionary<string, AssemblyEntry> Assemblies { get; private set; }
|
|
||||||
|
|
||||||
public string Name { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class AssemblyEntry
|
|
||||||
{
|
|
||||||
public string Path { get; set; }
|
|
||||||
public Version Version { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,487 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.Versioning;
|
|
||||||
using System.Xml.Linq;
|
|
||||||
using Microsoft.DotNet.PlatformAbstractions;
|
|
||||||
using Microsoft.DotNet.Internal.ProjectModel.Utilities;
|
|
||||||
using Microsoft.Extensions.DependencyModel.Resolution;
|
|
||||||
using NuGet.Frameworks;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.Resolution
|
|
||||||
{
|
|
||||||
internal class FrameworkReferenceResolver
|
|
||||||
{
|
|
||||||
// FrameworkConstants doesn't have dnx46 yet
|
|
||||||
private static readonly NuGetFramework Dnx46 = new NuGetFramework(
|
|
||||||
FrameworkConstants.FrameworkIdentifiers.Dnx,
|
|
||||||
new Version(4, 6));
|
|
||||||
|
|
||||||
private static FrameworkReferenceResolver _default;
|
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<NuGetFramework, FrameworkInformation> _cache = new ConcurrentDictionary<NuGetFramework, FrameworkInformation>();
|
|
||||||
|
|
||||||
private static readonly IDictionary<NuGetFramework, NuGetFramework[]> _aliases = new Dictionary<NuGetFramework, NuGetFramework[]>
|
|
||||||
{
|
|
||||||
{ FrameworkConstants.CommonFrameworks.Dnx451, new [] { FrameworkConstants.CommonFrameworks.Net451 } },
|
|
||||||
{ Dnx46, new [] { FrameworkConstants.CommonFrameworks.Net46 } }
|
|
||||||
};
|
|
||||||
|
|
||||||
public FrameworkReferenceResolver(string referenceAssembliesPath)
|
|
||||||
{
|
|
||||||
ReferenceAssembliesPath = referenceAssembliesPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string ReferenceAssembliesPath { get; }
|
|
||||||
|
|
||||||
public static FrameworkReferenceResolver Default
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_default == null)
|
|
||||||
{
|
|
||||||
_default = new FrameworkReferenceResolver(GetDefaultReferenceAssembliesPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
return _default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetDefaultReferenceAssembliesPath()
|
|
||||||
{
|
|
||||||
// Allow setting the reference assemblies path via an environment variable
|
|
||||||
var referenceAssembliesPath = DotNetReferenceAssembliesPathResolver.Resolve();
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(referenceAssembliesPath))
|
|
||||||
{
|
|
||||||
return referenceAssembliesPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (RuntimeEnvironment.OperatingSystemPlatform != Platform.Windows)
|
|
||||||
{
|
|
||||||
// There is no reference assemblies path outside of windows
|
|
||||||
// The environment variable can be used to specify one
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// References assemblies are in %ProgramFiles(x86)% on
|
|
||||||
// 64 bit machines
|
|
||||||
var programFiles = Environment.GetEnvironmentVariable("ProgramFiles(x86)");
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(programFiles))
|
|
||||||
{
|
|
||||||
// On 32 bit machines they are in %ProgramFiles%
|
|
||||||
programFiles = Environment.GetEnvironmentVariable("ProgramFiles");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(programFiles))
|
|
||||||
{
|
|
||||||
// Reference assemblies aren't installed
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Path.Combine(
|
|
||||||
programFiles,
|
|
||||||
"Reference Assemblies", "Microsoft", "Framework");
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryGetAssembly(string name, NuGetFramework targetFramework, out string path, out Version version)
|
|
||||||
{
|
|
||||||
path = null;
|
|
||||||
version = null;
|
|
||||||
|
|
||||||
var information = _cache.GetOrAdd(targetFramework, GetFrameworkInformation);
|
|
||||||
|
|
||||||
if (information == null || !information.Exists)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
lock (information.Assemblies)
|
|
||||||
{
|
|
||||||
AssemblyEntry entry;
|
|
||||||
if (information.Assemblies.TryGetValue(name, out entry))
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(entry.Path))
|
|
||||||
{
|
|
||||||
entry.Path = GetAssemblyPath(information.SearchPaths, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(entry.Path) && entry.Version == null)
|
|
||||||
{
|
|
||||||
// This code path should only run on mono
|
|
||||||
entry.Version = VersionUtility.GetAssemblyVersion(entry.Path).Version;
|
|
||||||
}
|
|
||||||
|
|
||||||
path = entry.Path;
|
|
||||||
version = entry.Version;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return !string.IsNullOrEmpty(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsInstalled(NuGetFramework targetFramework)
|
|
||||||
{
|
|
||||||
var information = _cache.GetOrAdd(targetFramework, GetFrameworkInformation);
|
|
||||||
|
|
||||||
return information?.Exists == true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetFrameworkRedistListPath(NuGetFramework targetFramework)
|
|
||||||
{
|
|
||||||
var information = _cache.GetOrAdd(targetFramework, GetFrameworkInformation);
|
|
||||||
|
|
||||||
if (information == null || !information.Exists)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return information.RedistListPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetFriendlyFrameworkName(NuGetFramework targetFramework)
|
|
||||||
{
|
|
||||||
var frameworkName = new FrameworkName(targetFramework.DotNetFrameworkName);
|
|
||||||
|
|
||||||
// We don't have a friendly name for this anywhere on the machine so hard code it
|
|
||||||
if (string.Equals(frameworkName.Identifier, VersionUtility.DnxCoreFrameworkIdentifier, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
return "DNX Core 5.0";
|
|
||||||
}
|
|
||||||
else if (string.Equals(frameworkName.Identifier, VersionUtility.DnxFrameworkIdentifier, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
return "DNX " + targetFramework.Version.ToString();
|
|
||||||
}
|
|
||||||
else if (string.Equals(frameworkName.Identifier, VersionUtility.NetPlatformFrameworkIdentifier, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
var version = targetFramework.Version > Constants.Version50 ?
|
|
||||||
(" " + targetFramework.Version.ToString()) :
|
|
||||||
string.Empty;
|
|
||||||
return ".NET Platform" + version;
|
|
||||||
}
|
|
||||||
|
|
||||||
var information = _cache.GetOrAdd(targetFramework, GetFrameworkInformation);
|
|
||||||
|
|
||||||
if (information == null)
|
|
||||||
{
|
|
||||||
return SynthesizeFrameworkFriendlyName(targetFramework);
|
|
||||||
}
|
|
||||||
|
|
||||||
return information.Name;
|
|
||||||
}
|
|
||||||
|
|
||||||
private FrameworkInformation GetFrameworkInformation(NuGetFramework targetFramework)
|
|
||||||
{
|
|
||||||
string referenceAssembliesPath = ReferenceAssembliesPath;
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(referenceAssembliesPath))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
NuGetFramework[] candidates;
|
|
||||||
if (_aliases.TryGetValue(targetFramework, out candidates))
|
|
||||||
{
|
|
||||||
foreach (var framework in candidates)
|
|
||||||
{
|
|
||||||
var information = GetFrameworkInformation(framework);
|
|
||||||
|
|
||||||
if (information != null)
|
|
||||||
{
|
|
||||||
return information;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return GetFrameworkInformation(targetFramework, referenceAssembliesPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static FrameworkInformation GetFrameworkInformation(NuGetFramework targetFramework, string referenceAssembliesPath)
|
|
||||||
{
|
|
||||||
// Check for legacy frameworks
|
|
||||||
if (RuntimeEnvironment.OperatingSystemPlatform == Platform.Windows &&
|
|
||||||
targetFramework.IsDesktop() &&
|
|
||||||
targetFramework.Version <= new Version(3, 5, 0, 0))
|
|
||||||
{
|
|
||||||
return GetLegacyFrameworkInformation(targetFramework, referenceAssembliesPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
var basePath = Path.Combine(referenceAssembliesPath,
|
|
||||||
targetFramework.Framework,
|
|
||||||
"v" + GetDisplayVersion(targetFramework));
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(targetFramework.Profile))
|
|
||||||
{
|
|
||||||
basePath = Path.Combine(basePath, "Profile", targetFramework.Profile);
|
|
||||||
}
|
|
||||||
|
|
||||||
var version = new DirectoryInfo(basePath);
|
|
||||||
if (!version.Exists)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return GetFrameworkInformation(version, targetFramework, referenceAssembliesPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static FrameworkInformation GetLegacyFrameworkInformation(NuGetFramework targetFramework, string referenceAssembliesPath)
|
|
||||||
{
|
|
||||||
var frameworkInfo = new FrameworkInformation();
|
|
||||||
|
|
||||||
// Always grab .NET 2.0 data
|
|
||||||
var searchPaths = new List<string>();
|
|
||||||
var net20Dir = Path.Combine(Environment.GetEnvironmentVariable("WINDIR"), "Microsoft.NET", "Framework", "v2.0.50727");
|
|
||||||
|
|
||||||
if (!Directory.Exists(net20Dir))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Grab reference assemblies first, if present for this framework
|
|
||||||
if (targetFramework.Version.Major == 3)
|
|
||||||
{
|
|
||||||
// Most specific first (i.e. 3.5)
|
|
||||||
if (targetFramework.Version.Minor == 5)
|
|
||||||
{
|
|
||||||
var refAsms35Dir = Path.Combine(referenceAssembliesPath, "v3.5");
|
|
||||||
if (!string.IsNullOrEmpty(targetFramework.Profile))
|
|
||||||
{
|
|
||||||
// The 3.5 Client Profile assemblies ARE in .NETFramework... it's weird.
|
|
||||||
refAsms35Dir = Path.Combine(referenceAssembliesPath, ".NETFramework", "v3.5", "Profile", targetFramework.Profile);
|
|
||||||
}
|
|
||||||
if (Directory.Exists(refAsms35Dir))
|
|
||||||
{
|
|
||||||
searchPaths.Add(refAsms35Dir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Always search the 3.0 reference assemblies
|
|
||||||
if (string.IsNullOrEmpty(targetFramework.Profile))
|
|
||||||
{
|
|
||||||
// a) 3.0 didn't have profiles
|
|
||||||
// b) When using a profile, we don't want to fall back to 3.0 or 2.0
|
|
||||||
var refAsms30Dir = Path.Combine(referenceAssembliesPath, "v3.0");
|
|
||||||
if (Directory.Exists(refAsms30Dir))
|
|
||||||
{
|
|
||||||
searchPaths.Add(refAsms30Dir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// .NET 2.0 reference assemblies go last (but only if there's no profile in the TFM)
|
|
||||||
if (string.IsNullOrEmpty(targetFramework.Profile))
|
|
||||||
{
|
|
||||||
searchPaths.Add(net20Dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
frameworkInfo.Exists = true;
|
|
||||||
frameworkInfo.Path = searchPaths.First();
|
|
||||||
frameworkInfo.SearchPaths = searchPaths;
|
|
||||||
|
|
||||||
// Load the redist list in reverse order (most general -> most specific)
|
|
||||||
for (int i = searchPaths.Count - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
var dir = new DirectoryInfo(searchPaths[i]);
|
|
||||||
if (dir.Exists)
|
|
||||||
{
|
|
||||||
PopulateFromRedistList(dir, targetFramework, referenceAssembliesPath, frameworkInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(frameworkInfo.Name))
|
|
||||||
{
|
|
||||||
frameworkInfo.Name = SynthesizeFrameworkFriendlyName(targetFramework);
|
|
||||||
}
|
|
||||||
return frameworkInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string SynthesizeFrameworkFriendlyName(NuGetFramework targetFramework)
|
|
||||||
{
|
|
||||||
// Names are not present in the RedistList.xml file for older frameworks or on Mono
|
|
||||||
// We do some custom version string rendering to match how net40 is rendered (.NET Framework 4)
|
|
||||||
if (targetFramework.Framework.Equals(FrameworkConstants.FrameworkIdentifiers.Net))
|
|
||||||
{
|
|
||||||
string versionString = targetFramework.Version.Minor == 0 ?
|
|
||||||
targetFramework.Version.Major.ToString() :
|
|
||||||
GetDisplayVersion(targetFramework).ToString();
|
|
||||||
|
|
||||||
string profileString = string.IsNullOrEmpty(targetFramework.Profile) ?
|
|
||||||
string.Empty :
|
|
||||||
$" {targetFramework.Profile} Profile";
|
|
||||||
return ".NET Framework " + versionString + profileString;
|
|
||||||
}
|
|
||||||
return targetFramework.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static FrameworkInformation GetFrameworkInformation(DirectoryInfo directory, NuGetFramework targetFramework, string referenceAssembliesPath)
|
|
||||||
{
|
|
||||||
var frameworkInfo = new FrameworkInformation();
|
|
||||||
frameworkInfo.Exists = true;
|
|
||||||
frameworkInfo.Path = directory.FullName;
|
|
||||||
frameworkInfo.SearchPaths = new[] {
|
|
||||||
frameworkInfo.Path,
|
|
||||||
Path.Combine(frameworkInfo.Path, "Facades")
|
|
||||||
};
|
|
||||||
|
|
||||||
PopulateFromRedistList(directory, targetFramework, referenceAssembliesPath, frameworkInfo);
|
|
||||||
if (string.IsNullOrEmpty(frameworkInfo.Name))
|
|
||||||
{
|
|
||||||
frameworkInfo.Name = SynthesizeFrameworkFriendlyName(targetFramework);
|
|
||||||
}
|
|
||||||
return frameworkInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void PopulateFromRedistList(DirectoryInfo directory, NuGetFramework targetFramework, string referenceAssembliesPath, FrameworkInformation frameworkInfo)
|
|
||||||
{
|
|
||||||
// The redist list contains the list of assemblies for this target framework
|
|
||||||
string redistList = Path.Combine(directory.FullName, "RedistList", "FrameworkList.xml");
|
|
||||||
|
|
||||||
if (File.Exists(redistList))
|
|
||||||
{
|
|
||||||
frameworkInfo.RedistListPath = redistList;
|
|
||||||
|
|
||||||
using (var stream = File.OpenRead(redistList))
|
|
||||||
{
|
|
||||||
var frameworkList = XDocument.Load(stream);
|
|
||||||
|
|
||||||
// Remember the original search paths, because we might need them later
|
|
||||||
var originalSearchPaths = frameworkInfo.SearchPaths;
|
|
||||||
|
|
||||||
// There are some frameworks, that "inherit" from a base framework, like
|
|
||||||
// e.g. .NET 4.0.3, and MonoAndroid.
|
|
||||||
var includeFrameworkVersion = frameworkList.Root.Attribute("IncludeFramework")?.Value;
|
|
||||||
if (includeFrameworkVersion != null)
|
|
||||||
{
|
|
||||||
// Get the NuGetFramework identifier for the framework to include
|
|
||||||
var includeFramework = NuGetFramework.Parse($"{targetFramework.Framework}, Version={includeFrameworkVersion}");
|
|
||||||
|
|
||||||
// Recursively call the code to get the framework information
|
|
||||||
var includeFrameworkInfo = GetFrameworkInformation(includeFramework, referenceAssembliesPath);
|
|
||||||
|
|
||||||
// Append the search paths of the included framework
|
|
||||||
frameworkInfo.SearchPaths = frameworkInfo.SearchPaths.Concat(includeFrameworkInfo.SearchPaths).ToArray();
|
|
||||||
|
|
||||||
// Add the assemblies of the included framework
|
|
||||||
foreach (var assemblyEntry in includeFrameworkInfo.Assemblies)
|
|
||||||
{
|
|
||||||
frameworkInfo.Assemblies[assemblyEntry.Key] = assemblyEntry.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// On mono, the RedistList.xml has an entry pointing to the TargetFrameworkDirectory
|
|
||||||
// It basically uses the GAC as the reference assemblies for all .NET framework
|
|
||||||
// profiles
|
|
||||||
var targetFrameworkDirectory = frameworkList.Root.Attribute("TargetFrameworkDirectory")?.Value;
|
|
||||||
|
|
||||||
IEnumerable<string> populateFromPaths;
|
|
||||||
if (!string.IsNullOrEmpty(targetFrameworkDirectory))
|
|
||||||
{
|
|
||||||
// For some odd reason, the paths are actually listed as \ so normalize them here
|
|
||||||
targetFrameworkDirectory = targetFrameworkDirectory.Replace('\\', Path.DirectorySeparatorChar);
|
|
||||||
|
|
||||||
// The specified path is the relative path from the RedistList.xml itself
|
|
||||||
var resovledPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(redistList), targetFrameworkDirectory));
|
|
||||||
|
|
||||||
// Update the path to the framework
|
|
||||||
frameworkInfo.Path = resovledPath;
|
|
||||||
|
|
||||||
populateFromPaths = new List<string>
|
|
||||||
{
|
|
||||||
resovledPath,
|
|
||||||
Path.Combine(resovledPath, "Facades")
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var emptyFileElements = true;
|
|
||||||
foreach (var e in frameworkList.Root.Elements())
|
|
||||||
{
|
|
||||||
// Remember that we had at least one framework assembly
|
|
||||||
emptyFileElements = false;
|
|
||||||
|
|
||||||
var assemblyName = e.Attribute("AssemblyName").Value;
|
|
||||||
var version = e.Attribute("Version")?.Value;
|
|
||||||
|
|
||||||
var entry = new AssemblyEntry();
|
|
||||||
entry.Version = version != null ? Version.Parse(version) : null;
|
|
||||||
frameworkInfo.Assemblies[assemblyName] = entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (emptyFileElements)
|
|
||||||
{
|
|
||||||
// When we haven't found any file elements, we probably processed a
|
|
||||||
// Mono/Xamarin FrameworkList.xml. That means, that we have to
|
|
||||||
// populate the assembly list from the files.
|
|
||||||
populateFromPaths = originalSearchPaths;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
populateFromPaths = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do we need to populate from search paths?
|
|
||||||
if (populateFromPaths != null)
|
|
||||||
{
|
|
||||||
foreach (var populateFromPath in populateFromPaths)
|
|
||||||
{
|
|
||||||
PopulateAssemblies(frameworkInfo.Assemblies, populateFromPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var nameAttribute = frameworkList.Root.Attribute("Name");
|
|
||||||
|
|
||||||
frameworkInfo.Name = nameAttribute == null ? null : nameAttribute.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void PopulateAssemblies(IDictionary<string, AssemblyEntry> assemblies, string path)
|
|
||||||
{
|
|
||||||
if (!Directory.Exists(path))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var assemblyPath in Directory.GetFiles(path, "*.dll"))
|
|
||||||
{
|
|
||||||
var name = Path.GetFileNameWithoutExtension(assemblyPath);
|
|
||||||
var entry = new AssemblyEntry();
|
|
||||||
entry.Path = assemblyPath;
|
|
||||||
assemblies[name] = entry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetAssemblyPath(IEnumerable<string> basePaths, string assemblyName)
|
|
||||||
{
|
|
||||||
foreach (var basePath in basePaths)
|
|
||||||
{
|
|
||||||
var assemblyPath = Path.Combine(basePath, assemblyName + ".dll");
|
|
||||||
|
|
||||||
if (File.Exists(assemblyPath))
|
|
||||||
{
|
|
||||||
return assemblyPath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Version GetDisplayVersion(NuGetFramework framework)
|
|
||||||
{
|
|
||||||
// Fix the target framework version due to https://github.com/NuGet/Home/issues/1600, this is relevant
|
|
||||||
// when looking up in the reference assembly folder
|
|
||||||
return new FrameworkName(framework.DotNetFrameworkName).Version;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,269 +0,0 @@
|
||||||
// Copyright (c) .NET Foundation and contributors. 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 Microsoft.DotNet.Internal.ProjectModel.Utilities;
|
|
||||||
using NuGet.LibraryModel;
|
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Internal.ProjectModel.Resolution
|
|
||||||
{
|
|
||||||
internal class LibraryManager
|
|
||||||
{
|
|
||||||
private readonly IList<LibraryDescription> _libraries;
|
|
||||||
private readonly IList<DiagnosticMessage> _diagnostics;
|
|
||||||
private readonly string _projectPath;
|
|
||||||
|
|
||||||
public LibraryManager(IList<LibraryDescription> libraries,
|
|
||||||
IList<DiagnosticMessage> diagnostics,
|
|
||||||
string projectPath)
|
|
||||||
{
|
|
||||||
_libraries = libraries;
|
|
||||||
_diagnostics = diagnostics;
|
|
||||||
_projectPath = projectPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IList<LibraryDescription> GetLibraries()
|
|
||||||
{
|
|
||||||
return _libraries;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IList<DiagnosticMessage> GetAllDiagnostics()
|
|
||||||
{
|
|
||||||
var messages = new List<DiagnosticMessage>();
|
|
||||||
|
|
||||||
if (_diagnostics != null)
|
|
||||||
{
|
|
||||||
messages.AddRange(_diagnostics);
|
|
||||||
}
|
|
||||||
|
|
||||||
var dependencies = new Dictionary<string, List<DependencyItem>>();
|
|
||||||
var topLevel = new List<LibraryItem>();
|
|
||||||
|
|
||||||
var platformLibraries = new List<LibraryDescription>();
|
|
||||||
foreach (var library in GetLibraries())
|
|
||||||
{
|
|
||||||
if (!library.Resolved)
|
|
||||||
{
|
|
||||||
string message;
|
|
||||||
string errorCode;
|
|
||||||
if (library.Compatible)
|
|
||||||
{
|
|
||||||
foreach (var range in library.RequestedRanges)
|
|
||||||
{
|
|
||||||
errorCode = ErrorCodes.NU1001;
|
|
||||||
message = $"The dependency {FormatLibraryRange(range)} could not be resolved.";
|
|
||||||
|
|
||||||
AddDiagnostics(messages, library, message, DiagnosticMessageSeverity.Error, errorCode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
errorCode = ErrorCodes.NU1002;
|
|
||||||
message = $"The dependency {library.Identity} does not support framework {library.Framework}.";
|
|
||||||
|
|
||||||
AddDiagnostics(messages, library, message, DiagnosticMessageSeverity.Error, errorCode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var isPlatform = library.RequestedRanges.Any(r => r.Type.Equals(LibraryDependencyType.Platform));
|
|
||||||
if (isPlatform)
|
|
||||||
{
|
|
||||||
platformLibraries.Add(library);
|
|
||||||
}
|
|
||||||
// Store dependency -> library for later
|
|
||||||
// J.N -> [(R1, P1), (R2, P2)]
|
|
||||||
foreach (var dependency in library.Dependencies)
|
|
||||||
{
|
|
||||||
List<DependencyItem> items;
|
|
||||||
if (!dependencies.TryGetValue(dependency.Name, out items))
|
|
||||||
{
|
|
||||||
items = new List<DependencyItem>();
|
|
||||||
dependencies[dependency.Name] = items;
|
|
||||||
}
|
|
||||||
items.Add(new DependencyItem(dependency, library));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var range in library.RequestedRanges)
|
|
||||||
{
|
|
||||||
// Skip libraries that aren't specified in a project.json
|
|
||||||
// Only report problems for this project
|
|
||||||
if (string.IsNullOrEmpty(range.SourceFilePath))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We only care about things requested in this project
|
|
||||||
if (!string.Equals(_projectPath, range.SourceFilePath))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (range.LibraryRange.VersionRange == null)
|
|
||||||
{
|
|
||||||
// TODO: Show errors/warnings for things without versions
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
topLevel.Add(new LibraryItem(range, library));
|
|
||||||
|
|
||||||
// If we ended up with a declared version that isn't what was asked for directly
|
|
||||||
// then report a warning
|
|
||||||
// Case 1: Non floating version and the minimum doesn't match what was specified
|
|
||||||
// Case 2: Floating version that fell outside of the range
|
|
||||||
if ((!range.LibraryRange.VersionRange.IsFloating &&
|
|
||||||
range.LibraryRange.VersionRange.MinVersion != library.Identity.Version) ||
|
|
||||||
(range.LibraryRange.VersionRange.IsFloating &&
|
|
||||||
!range.LibraryRange.VersionRange.Float.Satisfies(library.Identity.Version)))
|
|
||||||
{
|
|
||||||
var message = $"Dependency specified was {FormatLibraryRange(range)} but ended up with {library.Identity}.";
|
|
||||||
|
|
||||||
messages.Add(
|
|
||||||
new DiagnosticMessage(
|
|
||||||
ErrorCodes.NU1007,
|
|
||||||
message,
|
|
||||||
range.SourceFilePath,
|
|
||||||
DiagnosticMessageSeverity.Warning,
|
|
||||||
range.SourceLine,
|
|
||||||
range.SourceColumn,
|
|
||||||
library));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (platformLibraries.Count > 1)
|
|
||||||
{
|
|
||||||
foreach (var platformLibrary in platformLibraries)
|
|
||||||
{
|
|
||||||
AddDiagnostics(
|
|
||||||
messages,
|
|
||||||
platformLibrary,
|
|
||||||
"The following dependencies are marked with type 'platform', however only one dependency can have this type: " +
|
|
||||||
string.Join(", ", platformLibraries.Select(l => l.Identity.Name).ToArray()),
|
|
||||||
DiagnosticMessageSeverity.Error,
|
|
||||||
ErrorCodes.DOTNET1013);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Version conflicts
|
|
||||||
foreach (var libraryItem in topLevel)
|
|
||||||
{
|
|
||||||
var library = libraryItem.Library;
|
|
||||||
|
|
||||||
if (library.Identity.Type != LibraryType.Package)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<DependencyItem> items;
|
|
||||||
if (dependencies.TryGetValue(library.Identity.Name, out items))
|
|
||||||
{
|
|
||||||
foreach (var item in items)
|
|
||||||
{
|
|
||||||
var versionRange = item.Dependency.LibraryRange.VersionRange;
|
|
||||||
|
|
||||||
if (versionRange == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.Library != library && !versionRange.Satisfies(library.Identity.Version))
|
|
||||||
{
|
|
||||||
var message = $"Dependency conflict. {item.Library.Identity} expected {FormatLibraryRange(item.Dependency)} but received {library.Identity.Version}";
|
|
||||||
|
|
||||||
messages.Add(
|
|
||||||
new DiagnosticMessage(
|
|
||||||
ErrorCodes.NU1012,
|
|
||||||
message,
|
|
||||||
libraryItem.RequestedRange.SourceFilePath,
|
|
||||||
DiagnosticMessageSeverity.Warning,
|
|
||||||
libraryItem.RequestedRange.SourceLine,
|
|
||||||
libraryItem.RequestedRange.SourceColumn,
|
|
||||||
library));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return messages;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string FormatLibraryRange(ProjectLibraryDependency range)
|
|
||||||
{
|
|
||||||
return range.LibraryRange.ToLockFileDependencyGroupString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddDiagnostics(List<DiagnosticMessage> messages,
|
|
||||||
LibraryDescription library,
|
|
||||||
string message,
|
|
||||||
DiagnosticMessageSeverity severity,
|
|
||||||
string errorCode)
|
|
||||||
{
|
|
||||||
// A (in project.json) -> B (unresolved) (not in project.json)
|
|
||||||
foreach (var source in GetRangesWithSourceLocations(library).Distinct())
|
|
||||||
{
|
|
||||||
// We only care about things requested in this project
|
|
||||||
if (!string.Equals(_projectPath, source.SourceFilePath))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
messages.Add(
|
|
||||||
new DiagnosticMessage(
|
|
||||||
errorCode,
|
|
||||||
message,
|
|
||||||
source.SourceFilePath,
|
|
||||||
severity,
|
|
||||||
source.SourceLine,
|
|
||||||
source.SourceColumn,
|
|
||||||
library));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<ProjectLibraryDependency> GetRangesWithSourceLocations(LibraryDescription library)
|
|
||||||
{
|
|
||||||
foreach (var range in library.RequestedRanges)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(range.SourceFilePath))
|
|
||||||
{
|
|
||||||
yield return range;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var parent in library.Parents)
|
|
||||||
{
|
|
||||||
foreach (var relevantPath in GetRangesWithSourceLocations(parent))
|
|
||||||
{
|
|
||||||
yield return relevantPath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private struct DependencyItem
|
|
||||||
{
|
|
||||||
public ProjectLibraryDependency Dependency { get; private set; }
|
|
||||||
public LibraryDescription Library { get; private set; }
|
|
||||||
|
|
||||||
public DependencyItem(ProjectLibraryDependency dependency, LibraryDescription library)
|
|
||||||
{
|
|
||||||
Dependency = dependency;
|
|
||||||
Library = library;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private struct LibraryItem
|
|
||||||
{
|
|
||||||
public ProjectLibraryDependency RequestedRange { get; private set; }
|
|
||||||
public LibraryDescription Library { get; private set; }
|
|
||||||
|
|
||||||
public LibraryItem(ProjectLibraryDependency requestedRange, LibraryDescription library)
|
|
||||||
{
|
|
||||||
RequestedRange = requestedRange;
|
|
||||||
Library = library;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue