private bool IsSupported(NuGetFramework inboxFx, NuGetAssetResolver resolver)
        {
            var compileAssets = resolver.ResolveCompileAssets(inboxFx);

            // We assume that packages will only support inbox frameworks with lib/tfm assets and not runtime specific assets.
            // This effectively means we'll never reduce dependencies if a package happens to support an inbox framework with
            // a RID asset, but that is OK because RID assets can only be used by nuget3 + project.json
            // and we don't care about reducing dependencies for project.json because indirect dependencies are hidden.
            var runtimeAssets = resolver.ResolveRuntimeAssets(inboxFx, null);

            foreach (var compileAsset in compileAssets.Where(c => !NuGetAssetResolver.IsPlaceholder(c)))
            {
                string fileName = Path.GetFileName(compileAsset);

                if (!runtimeAssets.Any(r => Path.GetFileName(r).Equals(fileName, StringComparison.OrdinalIgnoreCase)))
                {
                    // ref with no matching lib
                    return(false);
                }
            }

            // Either all compile assets had matching runtime assets, or all were placeholders, make sure we have at
            // least one runtime asset to cover the placeholder case
            return(runtimeAssets.Any());
        }
Пример #2
0
        private void ExamineAssets(string assetType, string package, string target, IEnumerable <string> runtimeItems, out bool hasRealAsset, out bool hasPlaceHolder)
        {
            hasPlaceHolder = false;
            hasRealAsset   = false;
            StringBuilder assetLog = new StringBuilder($"{assetType} assets for {ContractName} on {target}: ");

            if (runtimeItems != null && runtimeItems.Any())
            {
                foreach (var runtimeItem in runtimeItems)
                {
                    assetLog.AppendLine();
                    assetLog.Append($"  {runtimeItem}");

                    if (!hasRealAsset && NuGetAssetResolver.IsPlaceholder(runtimeItem))
                    {
                        hasPlaceHolder = true;
                    }
                    else
                    {
                        hasRealAsset   = true;
                        hasPlaceHolder = false;
                    }
                }
            }
            else
            {
                assetLog.AppendLine();
                assetLog.Append("  <none>");
            }
            Log.LogMessage(LogImportance.Low, assetLog.ToString());
        }
Пример #3
0
        private IEnumerable <string> GetRuntimeAssetFoldersForPromotion(ContentItemGroup runtimeAssets, NuGetFramework targetFramework, string targetFrameworkName)
        {
            if (runtimeAssets == null || runtimeAssets.Items.Count == 0)
            {
                return(Enumerable.Empty <string>());
            }

            if (runtimeAssets.Items.All(ci => NuGetAssetResolver.IsPlaceholder(ci.Path)))
            {
                return(Enumerable.Empty <string>());
            }

            if (targetFrameworkName == null)
            {
                targetFrameworkName = targetFramework.GetShortFolderName();
            }

            var resolvedFramework = runtimeAssets.Properties["tfm"] as NuGetFramework;

            if (targetFramework.Equals(resolvedFramework))
            {
                Log.LogMessage(LogImportance.Low, $"Not promoting explicit implementation for {targetFrameworkName}");
                return(Enumerable.Empty <string>());
            }

            return(NuGetAssetResolver.GetPackageTargetDirectories(runtimeAssets));
        }
Пример #4
0
        public override bool Execute()
        {
            _packageItems = Files.Select(f => new PackageItem(f));
            var packageDlls  = _packageItems.Where(pi => Path.GetExtension(pi.SourcePath).Equals(".dll", StringComparison.OrdinalIgnoreCase));
            var packagePaths = _packageItems.Select(pi => pi.TargetPath);
            var packagePathsWithoutPlaceHolders = packagePaths.Where(pi => !NuGetAssetResolver.IsPlaceholder(pi));

            if (!String.IsNullOrEmpty(RuntimeJson) && !File.Exists(RuntimeJson))
            {
                Log.LogError("Could not load runtime file: {0}", RuntimeJson);
                RuntimeJson = null;
            }

            NuGetAssetResolver resolver         = new NuGetAssetResolver(RuntimeJson, packagePaths);
            NuGetAssetResolver obscuredResolver = new NuGetAssetResolver(RuntimeJson, packagePathsWithoutPlaceHolders);

            List <ITaskItem> newItems = new List <ITaskItem>();

            // determine if an inbox placeholder obscures an OOB implementation.
            foreach (var oobFx in OOBFrameworks)
            {
                NuGetFramework targetFramework = NuGetFramework.Parse(oobFx);

                // first see if any dlls are explicitly marked for this framework.
                IEnumerable <string> obscuredCompileFolders = packageDlls.Where(pi => pi.OriginalItem.GetMetadata("EnsureOOBFrameworkRef") == oobFx).Select(pi => pi.TargetDirectory);

                if (!obscuredCompileFolders.Any())
                {
                    // no dlls were marked, resolve without placeholders to determine what to promote.
                    var compileItems         = resolver.GetCompileItems(targetFramework);
                    var obscuredCompileItems = obscuredResolver.GetCompileItems(targetFramework);
                    obscuredCompileFolders = GetObscuredAssetFolders(compileItems, obscuredCompileItems, targetFramework, targetFrameworkName: oobFx, expectedAssetFolder: "ref", ignoredAssetFolder: "lib");
                }

                var promotedCompileItems = ExpandAssetFoldersToItems(obscuredCompileFolders, targetAssetFolder: "ref", targetFrameworkName: oobFx);
                newItems.AddRange(promotedCompileItems);

                // don't use 'any' in paths due to https://github.com/NuGet/Home/issues/1676
                string targetLibFolder = !String.IsNullOrEmpty(RuntimeId) && RuntimeId != "any" ? $"runtimes/{RuntimeId}/lib" : "lib";
                IEnumerable <string> obscuredRuntimeFolders = packageDlls.Where(pi => pi.OriginalItem.GetMetadata("EnsureOOBFrameworkLib") == oobFx).Select(pi => pi.TargetDirectory);

                if (!obscuredRuntimeFolders.Any())
                {
                    var runtimeItems         = resolver.GetRuntimeItems(targetFramework, RuntimeId);
                    var obscuredRuntimeItems = obscuredResolver.GetRuntimeItems(targetFramework, RuntimeId);
                    obscuredRuntimeFolders = GetObscuredAssetFolders(runtimeItems, obscuredRuntimeItems, targetFramework, targetFrameworkName: oobFx, expectedAssetFolder: targetLibFolder);
                }

                var promotedRuntimeItems = ExpandAssetFoldersToItems(obscuredRuntimeFolders, targetLibFolder, targetFrameworkName: oobFx);
                newItems.AddRange(promotedRuntimeItems);
            }

            AdditionalFiles = newItems.ToArray();

            return(!Log.HasLoggedErrors);
        }
Пример #5
0
        private IEnumerable <string> GetObscuredAssetFolders(ContentItemGroup assets, ContentItemGroup obscuredAssets, NuGetFramework targetFramework, string targetFrameworkName, string expectedAssetFolder, string ignoredAssetFolder = null)
        {
            if (assets == null || assets.Items.Count == 0)
            {
                return(Enumerable.Empty <string>());
            }

            if (assets.Items.Any(ci => !NuGetAssetResolver.IsPlaceholder(ci.Path)))
            {
                return(Enumerable.Empty <string>());
            }

            if (targetFrameworkName == null)
            {
                targetFrameworkName = targetFramework.GetShortFolderName();
            }

            var resolvedFramework = assets.Properties["tfm"] as NuGetFramework;

            if (targetFramework.Equals(resolvedFramework))
            {
                Log.LogMessage(LogImportance.Low, $"Not overriding explicit placeholder for {targetFrameworkName}");
                return(Enumerable.Empty <string>());
            }

            var obscuredAssetPaths = NuGetAssetResolver.GetPackageTargetDirectories(obscuredAssets);

            if (ignoredAssetFolder != null)
            {
                string ignoredFolder = ignoredAssetFolder + '/';
                obscuredAssetPaths = obscuredAssetPaths.Where(i => - 1 == i.IndexOf(ignoredFolder, StringComparison.OrdinalIgnoreCase));
            }

            if (expectedAssetFolder != null)
            {
                var unexpectedAssetPaths = obscuredAssetPaths.Where(ri => !ri.StartsWith(expectedAssetFolder, StringComparison.OrdinalIgnoreCase));
                foreach (var unexpectedAssetPath in unexpectedAssetPaths)
                {
                    Log.LogWarning($"Unexpected targetPath {unexpectedAssetPath}.  Expected only {expectedAssetFolder}.");
                }

                // filter after we've warned
                obscuredAssetPaths = obscuredAssetPaths.Except(unexpectedAssetPaths);
            }

            if (!obscuredAssetPaths.Any())
            {
                // it's acceptable to have no override, this is the case for packages which
                // carry implementation in a runtime-specific package
                Log.LogMessage(LogImportance.Low, $"No {expectedAssetFolder} assets could be found to override inbox placeholder for {targetFrameworkName}.");
            }

            return(obscuredAssetPaths);
        }
        public PackageItem(ITaskItem item)
        {
            OriginalItem  = item;
            SourcePath    = item.GetMetadata("FullPath");
            SourceProject = GetMetadata("MSBuildSourceProjectFile");
            string value = GetMetadata("TargetFramework");

            if (!String.IsNullOrWhiteSpace(value))
            {
                TargetFramework = NuGetFramework.Parse(value);
            }
            TargetPath           = item.GetMetadata(nameof(TargetPath));
            AdditionalProperties = GetMetadata(nameof(AdditionalProperties));
            UndefineProperties   = GetMetadata(nameof(UndefineProperties));
            HarvestedFrom        = GetMetadata(nameof(HarvestedFrom));
            Package        = GetMetadata("PackageId");
            PackageVersion = GetMetadata("PackageVersion");
            IsDll          = Path.GetExtension(SourcePath).Equals(".dll", StringComparison.OrdinalIgnoreCase);
            IsPlaceholder  = NuGetAssetResolver.IsPlaceholder(SourcePath);
            IsRef          = TargetPath.StartsWith("ref/", StringComparison.OrdinalIgnoreCase);

            // determine if we need to append filename to TargetPath
            // see https://docs.nuget.org/create/nuspec-reference#specifying-files-to-include-in-the-package
            // SourcePath specifies file and target specifies file - do nothing
            // SourcePath specifies file and Target specifies directory - copy filename
            // SourcePath specifies wildcard files - copy wildcard
            // SourcePath specifies recursive wildcard - do not allow, recursive directory may impact asset selection
            //   we don't want to attempt to expand the wildcard since the build may not yet be complete.

            if (SourcePath.Contains("**"))
            {
                throw new ArgumentException($"Recursive wildcards \"**\" are not permitted in source paths for packages: {SourcePath}.  Recursive directory may impact asset selection and we don't want to attempt to expand the wildcard since the build may not yet be complete.");
            }

            string sourceFile = Path.GetFileName(SourcePath);

            if (!Path.GetExtension(TargetPath).Equals(Path.GetExtension(sourceFile), StringComparison.OrdinalIgnoreCase) ||
                sourceFile.Contains("*"))
            {
                TargetPath = Path.Combine(TargetPath, sourceFile);
            }

            // standardize to /
            TargetPath = TargetPath.Replace('\\', '/');

            int dirLength = TargetPath.LastIndexOf('/');

            TargetDirectory = (dirLength > 0) ? TargetPath.Substring(0, dirLength) : String.Empty;
        }
Пример #7
0
        private void UpdateFromPackage(PackageIndex index, string packagePath, bool filter = false)
        {
            string                id;
            NuGetVersion          version;
            IEnumerable <Version> assemblyVersions;

            using (var reader = new PackageArchiveReader(packagePath))
            {
                var identity = reader.GetIdentity();
                id      = identity.Id;
                version = identity.Version;

                if (filter && !ShouldInclude(id))
                {
                    return;
                }

                var refFiles = reader.GetFiles("ref").Where(r => !NuGetAssetResolver.IsPlaceholder(r));

                if (!refFiles.Any())
                {
                    refFiles = reader.GetFiles("lib");
                }

                assemblyVersions = refFiles.Select(refFile =>
                {
                    using (var refStream = reader.GetStream(refFile))
                        using (var memStream = new MemoryStream())
                        {
                            refStream.CopyTo(memStream);
                            memStream.Seek(0, SeekOrigin.Begin);
                            return(VersionUtility.GetAssemblyVersion(memStream));
                        }
                }).ToArray();
            }

            UpdateFromValues(index, id, version, assemblyVersions);
        }
Пример #8
0
        private void ValidateSupport()
        {
            var runtimeFxSuppression = GetSuppressionValues(Suppression.PermitRuntimeTargetMonikerMismatch) ?? new HashSet <string>();
            ValidationReport report  = null;

            if (ValidationReport != null)
            {
                report = CreateValidationReport();
            }

            // validate support for each TxM:RID
            foreach (var validateFramework in _frameworks.Values)
            {
                NuGetFramework fx = validateFramework.Framework;
                Version        supportedVersion = validateFramework.SupportedVersion;

                var  compileAssetPaths = _resolver.ResolveCompileAssets(fx, PackageId);
                bool hasCompileAsset, hasCompilePlaceHolder;
                NuGetAssetResolver.ExamineAssets(Log, "Compile", ContractName, fx.ToString(), compileAssetPaths, out hasCompileAsset, out hasCompilePlaceHolder);

                if (report != null && validateFramework.RuntimeIds.All(rid => !String.IsNullOrEmpty(rid)))
                {
                    // Add Framework only (compile) target if all RIDs are non-empty.
                    // This acts as a compile target for a framework that requires a RID for runtime.
                    var reportTarget = new Target()
                    {
                        Framework     = fx.ToString(),
                        RuntimeID     = null,
                        CompileAssets = compileAssetPaths.Where(c => !NuGetAssetResolver.IsPlaceholder(c)).Select(c => GetPackageAssetFromTargetPath(c)).ToArray()
                    };
                    report.Targets.Add(fx.ToString(), reportTarget);
                }

                // resolve/test for each RID associated with this framework.
                foreach (string runtimeId in validateFramework.RuntimeIds)
                {
                    string target            = String.IsNullOrEmpty(runtimeId) ? fx.ToString() : $"{fx}/{runtimeId}";
                    var    runtimeAssetPaths = _resolver.ResolveRuntimeAssets(fx, runtimeId);

                    bool hasRuntimeAsset, hasRuntimePlaceHolder;
                    NuGetAssetResolver.ExamineAssets(Log, "Runtime", ContractName, target, runtimeAssetPaths, out hasRuntimeAsset, out hasRuntimePlaceHolder);

                    if (null == supportedVersion)
                    {
                        // Contract should not be supported on this platform.
                        bool permitImplementation = HasSuppression(Suppression.PermitImplementation, target);

                        if (hasCompileAsset && (hasRuntimeAsset & !permitImplementation))
                        {
                            Log.LogError($"{ContractName} should not be supported on {target} but has both compile and runtime assets.");
                        }
                        else if (hasRuntimeAsset & !permitImplementation)
                        {
                            Log.LogError($"{ContractName} should not be supported on {target} but has runtime assets.");
                        }

                        if (hasRuntimePlaceHolder && hasCompilePlaceHolder)
                        {
                            Log.LogError($"{ContractName} should not be supported on {target} but has placeholders for both compile and runtime which will permit the package to install.");
                        }
                    }
                    else
                    {
                        if (report != null)
                        {
                            var reportTarget = new Target()
                            {
                                Framework     = fx.ToString(),
                                RuntimeID     = runtimeId,
                                CompileAssets = compileAssetPaths.Where(c => !NuGetAssetResolver.IsPlaceholder(c)).Select(c => GetPackageAssetFromTargetPath(c)).ToArray(),
                                RuntimeAssets = runtimeAssetPaths.Where(r => !NuGetAssetResolver.IsPlaceholder(r)).Select(r => GetPackageAssetFromTargetPath(r)).ToArray()
                            };
                            report.Targets.Add(target, reportTarget);
                        }

                        if (validateFramework.IsInbox)
                        {
                            if (!hasCompileAsset && !hasCompilePlaceHolder)
                            {
                                Log.LogError($"Framework {fx} should support {ContractName} inbox but was missing a placeholder for compile-time.  You may need to add <InboxOnTargetFramework Include=\"{fx.GetShortFolderName()}\" /> to your project.");
                            }
                            else if (hasCompileAsset)
                            {
                                Log.LogError($"Framework {fx} should support {ContractName} inbox but contained a reference assemblies: {String.Join(", ", compileAssetPaths)}.  You may need to add <InboxOnTargetFramework Include=\"{fx.GetShortFolderName()}\" /> to your project.");
                            }

                            if (!hasRuntimeAsset && !hasRuntimePlaceHolder)
                            {
                                Log.LogError($"Framework {fx} should support {ContractName} inbox but was missing a placeholder for run-time.  You may need to add <InboxOnTargetFramework Include=\"{fx.GetShortFolderName()}\" /> to your project.");
                            }
                            else if (hasRuntimeAsset)
                            {
                                Log.LogError($"Framework {fx} should support {ContractName} inbox but contained a implementation assemblies: {String.Join(", ", runtimeAssetPaths)}.  You may need to add <InboxOnTargetFramework Include=\"{fx.GetShortFolderName()}\" /> to your project.");
                            }
                        }
                        else
                        {
                            Version referenceAssemblyVersion = null;
                            if (!hasCompileAsset)
                            {
                                Log.LogError($"{ContractName} should be supported on {target} but has no compile assets.");
                            }
                            else
                            {
                                var referenceAssemblies = compileAssetPaths.Where(IsDll);

                                if (referenceAssemblies.Count() > 1)
                                {
                                    Log.LogError($"{ContractName} should only contain a single compile asset for {target}.");
                                }

                                foreach (var referenceAssembly in referenceAssemblies)
                                {
                                    referenceAssemblyVersion = _targetPathToPackageItem[referenceAssembly].Version;

                                    if (!VersionUtility.IsCompatibleApiVersion(supportedVersion, referenceAssemblyVersion))
                                    {
                                        Log.LogError($"{ContractName} should support API version {supportedVersion} on {target} but {referenceAssembly} was found to support {referenceAssemblyVersion?.ToString() ?? "<unknown version>"}.");
                                    }
                                }
                            }

                            if (!hasRuntimeAsset && !FrameworkUtilities.IsGenerationMoniker(validateFramework.Framework))
                            {
                                Log.LogError($"{ContractName} should be supported on {target} but has no runtime assets.");
                            }
                            else
                            {
                                var implementationAssemblies = runtimeAssetPaths.Where(IsDll);

                                Dictionary <string, string> implementationFiles = new Dictionary <string, string>();
                                foreach (var implementationAssembly in implementationAssemblies)
                                {
                                    var     packageItem           = _targetPathToPackageItem[implementationAssembly];
                                    Version implementationVersion = packageItem.Version;

                                    if (!VersionUtility.IsCompatibleApiVersion(supportedVersion, implementationVersion))
                                    {
                                        Log.LogError($"{ContractName} should support API version {supportedVersion} on {target} but {implementationAssembly} was found to support {implementationVersion?.ToString() ?? "<unknown version>"}.");
                                    }

                                    // Previously we only permitted compatible mismatch if Suppression.PermitHigherCompatibleImplementationVersion was specified
                                    // this is a permitted thing on every framework but desktop (which requires exact match to ensure bindingRedirects exist)
                                    // Now make this the default, we'll check desktop, where it matters, more strictly
                                    if (referenceAssemblyVersion != null &&
                                        !VersionUtility.IsCompatibleApiVersion(referenceAssemblyVersion, implementationVersion))
                                    {
                                        Log.LogError($"{ContractName} has mismatched compile ({referenceAssemblyVersion}) and runtime ({implementationVersion}) versions on {target}.");
                                    }

                                    if (fx.Framework == FrameworkConstants.FrameworkIdentifiers.Net &&
                                        !referenceAssemblyVersion.Equals(implementationVersion))
                                    {
                                        Log.LogError($"{ContractName} has a higher runtime version ({implementationVersion}) than compile version ({referenceAssemblyVersion}) on .NET Desktop framework {target}.  This will break bindingRedirects.");
                                    }

                                    string fileName = Path.GetFileName(implementationAssembly);

                                    if (implementationFiles.ContainsKey(fileName))
                                    {
                                        Log.LogError($"{ContractName} includes both {implementationAssembly} and {implementationFiles[fileName]} an on {target} which have the same name and will clash when both packages are used.");
                                    }
                                    else
                                    {
                                        implementationFiles[fileName] = implementationAssembly;
                                    }

                                    if (packageItem.TargetFramework != fx && !runtimeFxSuppression.Contains(fx.ToString()))
                                    {
                                        // the selected asset wasn't an exact framework match, let's see if we have an exact match in any other runtime asset.
                                        var matchingFxAssets = _targetPathToPackageItem.Values.Where(i => i.TargetFramework == fx && // exact framework
                                                                                                                                     // Same file
                                                                                                     Path.GetFileName(i.TargetPath).Equals(fileName, StringComparison.OrdinalIgnoreCase) &&
                                                                                                                                     // Is implementation
                                                                                                     (i.TargetPath.StartsWith("lib") || i.TargetPath.StartsWith("runtimes")) &&
                                                                                                                                     // is not the same source file as was already selected
                                                                                                     i.SourcePath != packageItem.SourcePath);

                                        if (matchingFxAssets.Any())
                                        {
                                            Log.LogError($"When targeting {target} {ContractName} will use {implementationAssembly} which targets {packageItem.TargetFramework.GetShortFolderName()}  but {String.Join(";", matchingFxAssets.Select(i => i.TargetPath))} targets {fx.GetShortFolderName()} specifically.");
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            // Set output items
            AllSupportedFrameworks = _frameworks.Values.Where(fx => fx.SupportedVersion != null).Select(fx => fx.ToItem()).OrderBy(i => i.ItemSpec).ToArray();

            if (!String.IsNullOrEmpty(ValidationReport))
            {
                report.Save(ValidationReport);
            }
        }
Пример #9
0
        private void HarvestSupportedFrameworks()
        {
            List <ITaskItem> supportedFrameworks = new List <ITaskItem>();

            AggregateNuGetAssetResolver resolver = new AggregateNuGetAssetResolver(RuntimeFile);
            string packagePath = Path.Combine(PackagesFolder, PackageId, PackageVersion);

            // add the primary package
            resolver.AddPackageItems(PackageId, GetPackageItems(packagePath));

            if (RuntimePackages != null)
            {
                // add any split runtime packages
                foreach (var runtimePackage in RuntimePackages)
                {
                    var runtimePackageId      = runtimePackage.ItemSpec;
                    var runtimePackageVersion = runtimePackage.GetMetadata("Version");

                    resolver.AddPackageItems(runtimePackageId, GetPackageItems(PackagesFolder, runtimePackageId, runtimePackageVersion));
                }
            }

            // create a resolver that can be used to determine the API version for inbox assemblies
            // since inbox assemblies are represented with placeholders we can remove the placeholders
            // and use the netstandard reference assembly to determine the API version
            var filesWithoutPlaceholders = GetPackageItems(packagePath)
                                           .Where(f => !NuGetAssetResolver.IsPlaceholder(f));
            NuGetAssetResolver resolverWithoutPlaceholders = new NuGetAssetResolver(RuntimeFile, filesWithoutPlaceholders);

            string package = $"{PackageId}/{PackageVersion}";

            foreach (var framework in Frameworks)
            {
                var runtimeIds = framework.GetMetadata("RuntimeIDs")?.Split(';');

                NuGetFramework fx;
                try
                {
                    fx = FrameworkUtilities.ParseNormalized(framework.ItemSpec);
                }
                catch (Exception ex)
                {
                    Log.LogError($"Could not parse Framework {framework.ItemSpec}. {ex}");
                    continue;
                }

                if (fx.Equals(NuGetFramework.UnsupportedFramework))
                {
                    Log.LogError($"Did not recognize {framework.ItemSpec} as valid Framework.");
                    continue;
                }

                var compileAssets = resolver.ResolveCompileAssets(fx, PackageId);

                bool hasCompileAsset, hasCompilePlaceHolder;
                NuGetAssetResolver.ExamineAssets(Log, "Compile", package, fx.ToString(), compileAssets, out hasCompileAsset, out hasCompilePlaceHolder);

                // start by making sure it has some asset available for compile
                var isSupported = hasCompileAsset || hasCompilePlaceHolder;

                if (!isSupported)
                {
                    Log.LogMessage(LogImportance.Low, $"Skipping {fx} because it is not supported.");
                    continue;
                }

                foreach (var runtimeId in runtimeIds)
                {
                    string target = String.IsNullOrEmpty(runtimeId) ? fx.ToString() : $"{fx}/{runtimeId}";

                    var runtimeAssets = resolver.ResolveRuntimeAssets(fx, runtimeId);

                    bool hasRuntimeAsset, hasRuntimePlaceHolder;
                    NuGetAssetResolver.ExamineAssets(Log, "Runtime", package, target, runtimeAssets, out hasRuntimeAsset, out hasRuntimePlaceHolder);

                    isSupported &= hasCompileAsset == hasRuntimeAsset;
                    isSupported &= hasCompilePlaceHolder == hasRuntimePlaceHolder;

                    if (!isSupported)
                    {
                        Log.LogMessage(LogImportance.Low, $"Skipping {fx} because it is not supported on {target}.");
                        break;
                    }
                }

                if (isSupported)
                {
                    var supportedFramework = new TaskItem(framework.ItemSpec);
                    supportedFramework.SetMetadata("HarvestedFromPackage", package);

                    // set version

                    // first try the resolved compile asset for this package
                    var refAssm = compileAssets.FirstOrDefault(r => !NuGetAssetResolver.IsPlaceholder(r))?.Substring(PackageId.Length + 1);

                    if (refAssm == null)
                    {
                        // if we didn't have a compile asset it means this framework is supported inbox with a placeholder
                        // resolve the assets without placeholders to pick up the netstandard reference assembly.
                        compileAssets = resolverWithoutPlaceholders.ResolveCompileAssets(fx);
                        refAssm       = compileAssets.FirstOrDefault(r => !NuGetAssetResolver.IsPlaceholder(r));
                    }

                    string version = "unknown";
                    if (refAssm != null)
                    {
                        version = VersionUtility.GetAssemblyVersion(Path.Combine(packagePath, refAssm))?.ToString() ?? version;
                    }

                    supportedFramework.SetMetadata("Version", version);

                    Log.LogMessage($"Validating version {version} for {supportedFramework.ItemSpec} because it was supported by {PackageId}/{PackageVersion}.");

                    supportedFrameworks.Add(supportedFramework);
                }
            }

            SupportedFrameworks = supportedFrameworks.ToArray();
        }
        /* Given a set of available frameworks ("InboxOnTargetFrameworks"), and a list of desired frameworks,
         * reduce the set of frameworks to the minimum set of frameworks which is compatible (preferring inbox frameworks. */
        public override bool Execute()
        {
            if (null == Dependencies)
            {
                Log.LogError("Dependencies argument must be specified");
                return(false);
            }
            if (null == FrameworkListsPath)
            {
                Log.LogError("FrameworkListsPath argument must be specified");
                return(false);
            }

            // Retrieve the list of generation dependency group TFM's
            var dependencyGroups = Dependencies.GroupBy(d => d.GetMetadata("TargetFramework")).Select(dg => new
            {
                Framework    = NuGetFramework.Parse(dg.Key),
                Dependencies = dg.ToArray()
            });

            List <ITaskItem> addedDependencies = new List <ITaskItem>();

            // Exclude any non-portable frameworks that already have specific dependency groups.
            var frameworksToExclude = dependencyGroups.Select(dg => dg.Framework).Where(fx => !FrameworkUtilities.IsGenerationMoniker(fx));

            // Prepare a resolver for evaluating if candidate frameworks are actually supported by the package
            PackageItem[] packageItems = Files.Select(f => new PackageItem(f)).ToArray();
            var           packagePaths = packageItems.Select(pi => pi.TargetPath);
            var           targetFrameworksWithPlaceHolders = packageItems.Where(pi => NuGetAssetResolver.IsPlaceholder(pi.TargetPath)).Select(pi => pi.TargetFramework);

            NuGetAssetResolver resolver = new NuGetAssetResolver(null, packagePaths);

            foreach (var portableDependencyGroup in dependencyGroups.Where(dg => FrameworkUtilities.IsGenerationMoniker(dg.Framework)))
            {
                // Determine inbox frameworks for this generation that don't already have explicit groups
                HashSet <NuGetFramework> inboxFrameworksList = new HashSet <NuGetFramework>(
                    Frameworks.GetAlllInboxFrameworks(FrameworkListsPath)
                    .Where(fx => !fx.IsPCL)
                    .Where(fx => Generations.DetermineGenerationForFramework(fx, UseNetPlatform) >= portableDependencyGroup.Framework.Version &&
                           !frameworksToExclude.Any(exFx => exFx.Framework == fx.Framework && exFx.Version <= fx.Version)));

                // Check for assets which have a ref, but not a lib asset. If we have any of these, then they are actually not supported frameworks
                // and we should not include them.
                inboxFrameworksList.RemoveWhere(inboxFx => !IsSupported(inboxFx, resolver));

                // Only add the lowest version for a particular inbox framework.  EG if both net45 and net46 are supported by this generation,
                //        only add net45
                inboxFrameworksList.RemoveWhere(fx => inboxFrameworksList.Any(otherFx => (otherFx.Framework.Equals(fx.Framework)) && (otherFx.Version < fx.Version)));

                // Create dependency items for each inbox framework.
                foreach (var framework in inboxFrameworksList)
                {
                    bool addedDependencyToFramework = false;
                    foreach (ITaskItem dependency in portableDependencyGroup.Dependencies)
                    {
                        string version = GetVersion(dependency);

                        if (!Frameworks.IsInbox(FrameworkListsPath, framework, dependency.ItemSpec, version))
                        {
                            addedDependencyToFramework = true;
                            AddDependency(addedDependencies, new TaskItem(dependency), framework, portableDependencyGroup.Framework);
                        }
                    }
                    if (!addedDependencyToFramework)
                    {
                        AddDependency(addedDependencies, new TaskItem("_._"), framework, portableDependencyGroup.Framework);
                    }
                }
            }

            // Collapse frameworks
            // For any dependency with a targetframework, if there is another target framework which is compatible and older, remove this dependency.

            // Get all Dependencies which are not in a portable dependency group so that we can collapse the frameworks.  If we include
            // the portable frameworks, then we'll end up collapsing to those.
            List <NuGetFramework> allDependencyGroups = new List <NuGetFramework>();

            allDependencyGroups.AddRange(Dependencies.Select(d => NuGetFramework.Parse(d.GetMetadata("TargetFramework"))).Where(a => !allDependencyGroups.Contains(a) &&
                                                                                                                                !FrameworkUtilities.IsGenerationMoniker(a) &&
                                                                                                                                !FrameworkUtilities.IsPortableMoniker(a)));
            allDependencyGroups.AddRange(addedDependencies.Select(d => NuGetFramework.Parse(d.GetMetadata("TargetFramework"))).Where(a => !allDependencyGroups.Contains(a) &&
                                                                                                                                     !FrameworkUtilities.IsGenerationMoniker(a) &&
                                                                                                                                     !FrameworkUtilities.IsPortableMoniker(a)));

            List <NuGetFramework> collapsedDependencyGroups = FrameworkUtilities.ReduceDownwards(allDependencyGroups).ToList <NuGetFramework>();

            // Get the list of dependency groups that we collapsed down so that we can add them back if they contained different dependencies than what is present in the collapsed group.

            /* TODO: Look into NuGet's sorting algorithm, they may have a bug (fixed in this line). They were not including version in the sort.
             *       See ReduceCore in https://github.com/NuGet/NuGet.Client/blob/23ea68b91a439fcfd7f94bcd01bcdee2e8adae92/src/NuGet.Core/NuGet.Frameworks/FrameworkReducer.cs */
            IEnumerable <NuGetFramework> removedDependencyGroups = allDependencyGroups.Where(d => !collapsedDependencyGroups.Contains(d))?.OrderBy(f => f.Framework, StringComparer.OrdinalIgnoreCase).ThenBy(f => f.Version);

            foreach (NuGetFramework removedDependencyGroup in removedDependencyGroups)
            {
                // always recalculate collapsedDependencyGroups in case we added an item in a previous iteration.  Dependency groups are sorted, so this should be additive and we shouldn't need to restart the collapse / add back cycle
                var nearest = FrameworkUtilities.GetNearest(removedDependencyGroup, collapsedDependencyGroups.ToArray());

                // gather the dependencies for this dependency group and the calculated "nearest" dependency group
                var nearestDependencies = addedDependencies.Where(d => nearest.Equals(NuGetFramework.Parse(d.GetMetadata("TargetFramework")))).OrderBy(f => f.ToString());
                var currentDependencies = addedDependencies.Where(d => removedDependencyGroup.Equals(NuGetFramework.Parse(d.GetMetadata("TargetFramework")))).OrderBy(f => f.ToString());

                // The nearest dependency group's dependencies are different than this dependency group's dependencies
                if (nearestDependencies.Count() != currentDependencies.Count())
                {
                    // ignore if dependency is a placeholder
                    if (currentDependencies.Count() > 0)
                    {
                        if (!NuGetAssetResolver.IsPlaceholder(currentDependencies.First().ToString()))
                        {
                            collapsedDependencyGroups.Add(removedDependencyGroup);
                        }
                    }
                    else
                    {
                        collapsedDependencyGroups.Add(removedDependencyGroup);
                    }
                }
                // identical dependency count between current and nearest, and the count is > 0
                else if (nearestDependencies.Count() > 0)
                {
                    if (!currentDependencies.SequenceEqual(nearestDependencies, new DependencyITaskItemComparer()))
                    {
                        collapsedDependencyGroups.Add(removedDependencyGroup);
                    }
                }
            }


            List <ITaskItem> collapsedDependencies = new List <ITaskItem>();

            foreach (ITaskItem dependency in addedDependencies)
            {
                if (collapsedDependencyGroups.Contains(NuGetFramework.Parse(dependency.GetMetadata("TargetFramework"))))
                {
                    collapsedDependencies.Add(dependency);
                }
            }
            TrimmedDependencies = collapsedDependencies.ToArray();

            return(!Log.HasLoggedErrors);
        }
Пример #11
0
 private IEnumerable <ITaskItem> CreateLayoutFiles(IEnumerable <PackageAsset> assets, string subFolder, string assetType)
 {
     return(assets.Where(a => !NuGetAssetResolver.IsPlaceholder(a.LocalPath))
            .SelectMany(a => CreateLayoutFile(a.LocalPath, subFolder, assetType)));
 }
Пример #12
0
        /* Given a set of available frameworks ("InboxOnTargetFrameworks"), and a list of desired frameworks,
         * reduce the set of frameworks to the minimum set of frameworks which is compatible (preferring inbox frameworks. */
        public override bool Execute()
        {
            if (null == Dependencies)
            {
                Log.LogError("Dependencies argument must be specified");
                return(false);
            }
            if (null == FrameworkListsPath)
            {
                Log.LogError("FrameworkListsPath argument must be specified");
                return(false);
            }

            // Retrieve the list of generation dependency group TFM's
            Dictionary <string, IEnumerable <ITaskItem> > portableDependencyGroups = new Dictionary <string, IEnumerable <ITaskItem> >();

            foreach (ITaskItem dependency in Dependencies)
            {
                string framework = dependency.GetMetadata("TargetFramework");
                if (framework != null && FrameworkUtilities.IsGenerationMoniker(framework) && !portableDependencyGroups.ContainsKey(framework))
                {
                    portableDependencyGroups.Add(framework, Dependencies.Where(d => d.GetMetadata("TargetFramework") == framework));
                }
            }

            List <ITaskItem> addedDependencies     = new List <ITaskItem>();
            List <string>    placeHolderFrameworks = new List <string>();

            var frameworksToExclude = TrimFrameworks?.Select(fx => NuGetFramework.Parse(fx))?.ToArray() ?? new NuGetFramework[0];

            // Prepare a resolver for evaluating if candidate frameworks are actually supported by the package
            PackageItem[] packageItems = Files.Select(f => new PackageItem(f)).ToArray();
            var           packagePaths = packageItems.Select(pi => pi.TargetPath);
            var           targetFrameworksWithPlaceHolders = packageItems.Where(pi => NuGetAssetResolver.IsPlaceholder(pi.TargetPath)).Select(pi => pi.TargetFramework);

            NuGetAssetResolver resolver = new NuGetAssetResolver(null, packagePaths);

            foreach (string portableDependency in portableDependencyGroups.Keys)
            {
                NuGetFramework portableDependencyFramework = NuGetFramework.Parse(portableDependency);

                // Determine inbox frameworks for this generations dependencies as a whole
                HashSet <NuGetFramework> inboxFrameworksList = new HashSet <NuGetFramework>();

                foreach (NuGetFramework inboxFramework in Frameworks.GetAlllInboxFrameworks(FrameworkListsPath))
                {
                    if (Generations.DetermineGenerationForFramework(inboxFramework, UseNetPlatform) >= portableDependencyFramework.Version &&
                        !frameworksToExclude.Contains(inboxFramework))
                    {
                        inboxFrameworksList.Add(inboxFramework);
                    }
                }

                // Only add the lowest version for a particular inbox framework.  EG if both net45 and net46 are supported by this generation,
                //        only add net45
                inboxFrameworksList.RemoveWhere(fx => inboxFrameworksList.Any(otherFx => (otherFx.Framework.Equals(fx.Framework)) && (otherFx.Version < fx.Version)));

                // Check for assets which have a ref, but not a lib asset. If we have any of these, then they are actually not supported frameworks
                // and we should not include them.
                inboxFrameworksList.RemoveWhere(inboxFx => !IsSupported(inboxFx, resolver));

                // Remove the frameworks which have placeholders.
                inboxFrameworksList.RemoveWhere(fx => targetFrameworksWithPlaceHolders.Any(tfx => tfx != null && fx.DotNetFrameworkName == tfx.DotNetFrameworkName));

                // Create dependency items for each inbox framework.
                foreach (string framework in inboxFrameworksList.Select(fx => fx.GetShortFolderName()))
                {
                    bool addedDependencyToFramework = false;
                    foreach (ITaskItem dependency in portableDependencyGroups[portableDependency])
                    {
                        // If we don't have the AssemblyVersion metadata (4 part version string), fall back and use Version (3 part version string)
                        string version = dependency.GetMetadata("AssemblyVersion");
                        if (string.IsNullOrEmpty(version))
                        {
                            version = dependency.GetMetadata("Version");

                            int prereleaseIndex = version.IndexOf('-');
                            if (prereleaseIndex != -1)
                            {
                                version = version.Substring(0, prereleaseIndex);
                            }
                        }
                        if (!Frameworks.IsInbox(FrameworkListsPath, framework, dependency.ItemSpec, version))
                        {
                            addedDependencyToFramework = true;
                            TaskItem dependencyItem = new TaskItem(dependency);
                            dependencyItem.SetMetadata("TargetFramework", framework);
                            // "Generation" is not required metadata, we just include it because it can be useful for debugging.
                            dependencyItem.SetMetadata("Generation", portableDependency);
                            addedDependencies.Add(dependencyItem);
                        }
                    }
                    if (!addedDependencyToFramework)
                    {
                        TaskItem dependencyItem = new TaskItem("_._");
                        dependencyItem.SetMetadata("TargetFramework", framework);
                        // "Generation" is not required metadata, we just include it because it can be useful for debugging.
                        dependencyItem.SetMetadata("Generation", portableDependency);
                        addedDependencies.Add(dependencyItem);
                        placeHolderFrameworks.Add(framework);
                    }
                }
            }

            // Collapse frameworks
            // For any dependency with a targetframework, if there is another target framework which is compatible and older, remove this dependency.

            // Get all Dependencies which are not in a portable dependency group so that we can collapse the frameworks.  If we include
            // the portable frameworks, then we'll end up collapsing to those.
            List <NuGetFramework> allDependencyGroups = new List <NuGetFramework>();

            allDependencyGroups.AddRange(Dependencies.Select(d => NuGetFramework.Parse(d.GetMetadata("TargetFramework"))).Where(a => !allDependencyGroups.Contains(a) &&
                                                                                                                                !FrameworkUtilities.IsGenerationMoniker(a) &&
                                                                                                                                !FrameworkUtilities.IsPortableMoniker(a)));
            allDependencyGroups.AddRange(addedDependencies.Select(d => NuGetFramework.Parse(d.GetMetadata("TargetFramework"))).Where(a => !allDependencyGroups.Contains(a) &&
                                                                                                                                     !FrameworkUtilities.IsGenerationMoniker(a) &&
                                                                                                                                     !FrameworkUtilities.IsPortableMoniker(a)));

            List <NuGetFramework> collapsedDependencyGroups = FrameworkUtilities.ReduceDownwards(allDependencyGroups).ToList <NuGetFramework>();

            // Get the list of dependency groups that we collapsed down so that we can add them back if they contained different dependencies than what is present in the collapsed group.

            /* TODO: Look into NuGet's sorting algorithm, they may have a bug (fixed in this line). They were not including version in the sort.
             *       See ReduceCore in https://github.com/NuGet/NuGet.Client/blob/23ea68b91a439fcfd7f94bcd01bcdee2e8adae92/src/NuGet.Core/NuGet.Frameworks/FrameworkReducer.cs */
            IEnumerable <NuGetFramework> removedDependencyGroups = allDependencyGroups.Where(d => !collapsedDependencyGroups.Contains(d))?.OrderBy(f => f.Framework, StringComparer.OrdinalIgnoreCase).ThenBy(f => f.Version);

            foreach (NuGetFramework removedDependencyGroup in removedDependencyGroups)
            {
                // always recalculate collapsedDependencyGroups in case we added an item in a previous iteration.  Dependency groups are sorted, so this should be additive and we shouldn't need to restart the collapse / add back cycle
                var nearest = FrameworkUtilities.GetNearest(removedDependencyGroup, collapsedDependencyGroups.ToArray());

                // gather the dependencies for this dependency group and the calculated "nearest" dependency group
                var nearestDependencies = addedDependencies.Where(d => nearest.Equals(NuGetFramework.Parse(d.GetMetadata("TargetFramework")))).OrderBy(f => f.ToString());
                var currentDependencies = addedDependencies.Where(d => removedDependencyGroup.Equals(NuGetFramework.Parse(d.GetMetadata("TargetFramework")))).OrderBy(f => f.ToString());

                // The nearest dependency group's dependencies are different than this dependency group's dependencies
                if (nearestDependencies.Count() != currentDependencies.Count())
                {
                    // ignore if dependency is a placeholder
                    if (currentDependencies.Count() > 0)
                    {
                        if (!NuGetAssetResolver.IsPlaceholder(currentDependencies.First().ToString()))
                        {
                            collapsedDependencyGroups.Add(removedDependencyGroup);
                        }
                    }
                    else
                    {
                        collapsedDependencyGroups.Add(removedDependencyGroup);
                    }
                }
                // identical dependency count between current and nearest, and the count is > 0
                else if (nearestDependencies.Count() > 0)
                {
                    if (!currentDependencies.SequenceEqual(nearestDependencies, new DependencyITaskItemComparer()))
                    {
                        collapsedDependencyGroups.Add(removedDependencyGroup);
                    }
                }
            }


            List <ITaskItem> collapsedDependencies = new List <ITaskItem>();

            foreach (ITaskItem dependency in addedDependencies)
            {
                if (collapsedDependencyGroups.Contains(NuGetFramework.Parse(dependency.GetMetadata("TargetFramework"))))
                {
                    collapsedDependencies.Add(dependency);
                }
            }
            TrimmedDependencies = collapsedDependencies.ToArray();

            return(!Log.HasLoggedErrors);
        }
Пример #13
0
        public override bool Execute()
        {
            LoadFiles();
            LoadFrameworks();

            var report = new PackageReport()
            {
                Id                  = PackageId,
                Version             = PackageVersion,
                SupportedFrameworks = new Dictionary <string, string>()
            };

            string package = $"{PackageId}/{PackageVersion}";

            foreach (var framework in _frameworks.OrderBy(f => f.Key.ToString()))
            {
                var fx         = framework.Key;
                var runtimeIds = framework.Value;

                var compileAssets = _resolver.ResolveCompileAssets(fx, PackageId);

                bool hasCompileAsset, hasCompilePlaceHolder;
                NuGetAssetResolver.ExamineAssets(Log, "Compile", package, fx.ToString(), compileAssets, out hasCompileAsset, out hasCompilePlaceHolder);
                MarkUsed(compileAssets);

                // start by making sure it has some asset available for compile
                var isSupported = hasCompileAsset || hasCompilePlaceHolder;

                if (runtimeIds.All(rid => !String.IsNullOrEmpty(rid)))
                {
                    // Add Framework only (compile) target if all RIDs are non-empty.
                    // This acts as a compile target for a framework that requires a RID for runtime.
                    var reportTarget = new Target()
                    {
                        Framework     = fx.ToString(),
                        RuntimeID     = null,
                        CompileAssets = compileAssets.Select(c => GetPackageAssetFromTargetPath(c)).ToArray()
                    };
                    report.Targets.Add(fx.ToString(), reportTarget);
                }

                foreach (var runtimeId in runtimeIds)
                {
                    string target = String.IsNullOrEmpty(runtimeId) ? fx.ToString() : $"{fx}/{runtimeId}";

                    var runtimeAssets = _resolver.ResolveRuntimeAssets(fx, runtimeId);

                    bool hasRuntimeAsset, hasRuntimePlaceHolder;
                    NuGetAssetResolver.ExamineAssets(Log, "Runtime", package, target, runtimeAssets, out hasRuntimeAsset, out hasRuntimePlaceHolder);
                    MarkUsed(runtimeAssets);

                    if (!FrameworkUtilities.IsGenerationMoniker(fx) && !fx.IsPCL)
                    {
                        // only look at runtime assets for runnable frameworks.
                        isSupported &= (hasCompileAsset && hasRuntimeAsset) ||           // matching assets
                                       (hasCompilePlaceHolder && hasRuntimeAsset) ||     // private runtime
                                       (hasCompilePlaceHolder && hasRuntimePlaceHolder); // placeholders
                    }

                    var nativeAssets = _resolver.ResolveNativeAssets(fx, runtimeId);
                    MarkUsed(nativeAssets);

                    var reportTarget = new Target()
                    {
                        Framework     = fx.ToString(),
                        RuntimeID     = runtimeId,
                        CompileAssets = compileAssets.Select(c => GetPackageAssetFromTargetPath(c)).ToArray(),
                        RuntimeAssets = runtimeAssets.Select(r => GetPackageAssetFromTargetPath(r)).ToArray(),
                        NativeAssets  = nativeAssets.Select(n => GetPackageAssetFromTargetPath(n)).ToArray()
                    };
                    report.Targets[target] = reportTarget;
                }

                if (isSupported)
                {
                    // Find version
                    // first try the resolved compile asset for this package
                    var refAssm = compileAssets.FirstOrDefault(r => !NuGetAssetResolver.IsPlaceholder(r))?.Substring(PackageId.Length + 1);

                    if (refAssm == null)
                    {
                        // if we didn't have a compile asset it means this framework is supported inbox with a placeholder
                        // resolve the assets without placeholders to pick up the netstandard reference assembly.
                        compileAssets = _resolverWithoutPlaceholders.ResolveCompileAssets(fx);
                        refAssm       = compileAssets.FirstOrDefault(r => !NuGetAssetResolver.IsPlaceholder(r));
                    }

                    var version = "unknown";
                    if (refAssm != null)
                    {
                        version = _targetPathToPackageItem[AggregateNuGetAssetResolver.AsPackageSpecificTargetPath(PackageId, refAssm)].Version?.ToString() ?? version;
                    }

                    report.SupportedFrameworks.Add(fx.ToString(), version);
                }
            }

            report.UnusedAssets = _unusedTargetPaths.Select(tp => GetPackageAssetFromTargetPath(tp)).ToArray();

            report.Save(ReportFile);

            return(!Log.HasLoggedErrors);
        }
Пример #14
0
        private void LoadFiles()
        {
            var packageItems = new Dictionary <string, List <PackageItem> >();

            foreach (var file in Files)
            {
                try
                {
                    var packageItem = new PackageItem(file);

                    if (!packageItem.TargetPath.StartsWith("runtimes") && !packageItem.IsDll && !packageItem.IsPlaceholder)
                    {
                        continue;
                    }

                    if (String.IsNullOrWhiteSpace(packageItem.TargetPath))
                    {
                        Log.LogError($"{packageItem.TargetPath} is missing TargetPath metadata");
                    }

                    string packageId = packageItem.Package ?? PackageId;

                    if (!packageItems.ContainsKey(packageId))
                    {
                        packageItems[packageId] = new List <PackageItem>();
                    }
                    packageItems[packageId].Add(packageItem);
                }
                catch (Exception ex)
                {
                    Log.LogError($"Could not parse File {file.ItemSpec}. {ex}");
                    // skip it.
                }
            }

            // build a map to translate back to source file from resolved asset
            // we use package-specific paths since we're resolving a set of packages.
            _targetPathToPackageItem = new Dictionary <string, PackageItem>();
            _unusedTargetPaths       = new HashSet <string>();
            foreach (var packageSpecificItems in packageItems)
            {
                foreach (PackageItem packageItem in packageSpecificItems.Value)
                {
                    string packageSpecificTargetPath = AggregateNuGetAssetResolver.AsPackageSpecificTargetPath(packageSpecificItems.Key, packageItem.TargetPath);

                    if (_targetPathToPackageItem.ContainsKey(packageSpecificTargetPath))
                    {
                        Log.LogError($"Files {_targetPathToPackageItem[packageSpecificTargetPath].SourcePath} and {packageItem.SourcePath} have the same TargetPath {packageSpecificTargetPath}.");
                    }
                    _targetPathToPackageItem[packageSpecificTargetPath] = packageItem;
                    _unusedTargetPaths.Add(packageSpecificTargetPath);
                }
            }

            _resolver = new AggregateNuGetAssetResolver(RuntimeFile);
            foreach (string packageId in packageItems.Keys)
            {
                _resolver.AddPackageItems(packageId, packageItems[packageId].Select(f => f.TargetPath));
            }

            // create a resolver that can be used to determine the API version for inbox assemblies
            // since inbox assemblies are represented with placeholders we can remove the placeholders
            // and use the netstandard reference assembly to determine the API version
            if (packageItems.Any() && packageItems.ContainsKey(PackageId))
            {
                var filesWithoutPlaceholders = packageItems[PackageId]
                                               .Select(pf => pf.TargetPath)
                                               .Where(f => !NuGetAssetResolver.IsPlaceholder(f));

                _resolverWithoutPlaceholders = new NuGetAssetResolver(RuntimeFile, filesWithoutPlaceholders);
            }
        }
Пример #15
0
        private void ValidateIndex()
        {
            if (SkipIndexCheck)
            {
                return;
            }

            if (PackageIndexes == null || PackageIndexes.Length == 0)
            {
                return;
            }

            PackageIndex.Current.Merge(PackageIndexes.Select(pi => pi.GetMetadata("FullPath")));

            PackageInfo info;

            if (!PackageIndex.Current.Packages.TryGetValue(PackageId, out info))
            {
                Log.LogError($"PackageIndex from {String.Join(", ", PackageIndexes.Select(i => i.ItemSpec))} is missing an entry for package {PackageId}.  Please run /t:UpdatePackageIndex on this project to commit an update.");
                return;
            }

            var thisPackageFiles = _validateFiles[PackageId];
            var refFiles         = thisPackageFiles.Where(f => f.TargetPath.StartsWith("ref/", StringComparison.OrdinalIgnoreCase)).Where(r => !NuGetAssetResolver.IsPlaceholder(r.TargetPath));

            if (!refFiles.Any())
            {
                refFiles = thisPackageFiles.Where(f => f.TargetPath.StartsWith("lib/", StringComparison.OrdinalIgnoreCase));
            }

            var thisPackageVersion = VersionUtility.As3PartVersion(NuGetVersion.Parse(PackageVersion).Version);
            var refFileVersions    = new HashSet <Version>(refFiles.Where(r => r.Version != null).Select(r => VersionUtility.As4PartVersion(r.Version)));

            foreach (var refFileVersion in refFileVersions)
            {
                Version refPackageVersion;

                // determine if we're missing a mapping for this package
                if (!info.AssemblyVersionInPackageVersion.TryGetValue(refFileVersion, out refPackageVersion))
                {
                    Log.LogError($"PackageIndex from {String.Join(", ", PackageIndexes.Select(i => i.ItemSpec))} is missing an assembly version entry for {refFileVersion} for package {PackageId}.  Please run /t:UpdatePackageIndex on this project to commit an update.");
                }
                else
                {
                    // determine if we have a mapping for an unstable package and that unstable package is not this one
                    if (!info.StableVersions.Contains(refPackageVersion) && refPackageVersion != thisPackageVersion)
                    {
                        Log.LogError($"PackageIndex from {String.Join(", ", PackageIndexes.Select(i => i.ItemSpec))} indicates that assembly version {refFileVersion} is contained in non-stable package version {refPackageVersion} which differs from this package version {thisPackageVersion}.");
                    }
                }
            }

            var orphanedAssemblyVersions = info.AssemblyVersionInPackageVersion
                                           .Where(pair => pair.Value == thisPackageVersion && !refFileVersions.Contains(pair.Key))
                                           .Select(pair => pair.Key);

            if (orphanedAssemblyVersions.Any())
            {
                Log.LogError($"PackageIndex from {String.Join(", ", PackageIndexes.Select(i => i.ItemSpec))} is has an assembly version entry(s) for {String.Join(", ", orphanedAssemblyVersions)} which are no longer in package {PackageId}.  Please run /t:UpdatePackageIndex on this project to commit an update.");
            }
        }
Пример #16
0
        public override bool Execute()
        {
            _packageItems = Files.Select(f => new PackageItem(f));
            var packageDlls  = _packageItems.Where(pi => Path.GetExtension(pi.SourcePath).Equals(".dll", StringComparison.OrdinalIgnoreCase));
            var packagePaths = _packageItems.Select(pi => pi.TargetPath);
            var packagePathsWithoutPlaceHolders = packagePaths.Where(pi => !NuGetAssetResolver.IsPlaceholder(pi));

            if (!String.IsNullOrEmpty(RuntimeJson) && !File.Exists(RuntimeJson))
            {
                Log.LogError("Could not load runtime file: {0}", RuntimeJson);
                RuntimeJson = null;
            }

            NuGetAssetResolver resolver         = new NuGetAssetResolver(RuntimeJson, packagePaths);
            NuGetAssetResolver obscuredResolver = new NuGetAssetResolver(RuntimeJson, packagePathsWithoutPlaceHolders);

            List <ITaskItem> newItems = new List <ITaskItem>();

            // determine if an inbox placeholder obscures an OOB implementation.
            foreach (var oobFramework in OOBFrameworks)
            {
                var            oobFx           = oobFramework.ItemSpec;
                NuGetFramework targetFramework = NuGetFramework.Parse(oobFx);

                // first see if any dlls are explicitly marked for this framework.
                IEnumerable <string> obscuredCompileFolders = packageDlls.Where(pi => pi.OriginalItem.GetMetadata("EnsureOOBFrameworkRef") == oobFx).Select(pi => pi.TargetDirectory);

                if (!obscuredCompileFolders.Any())
                {
                    // no dlls were marked, resolve without placeholders to determine what to promote.
                    var compileItems         = resolver.GetCompileItems(targetFramework);
                    var obscuredCompileItems = obscuredResolver.GetCompileItems(targetFramework);
                    obscuredCompileFolders = GetObscuredAssetFolders(compileItems, obscuredCompileItems, targetFramework, targetFrameworkName: oobFx, expectedAssetFolder: "ref", ignoredAssetFolder: "lib");
                }

                var promotedCompileItems = ExpandAssetFoldersToItems(obscuredCompileFolders, targetAssetFolder: "ref", targetFrameworkName: oobFx);
                newItems.AddRange(promotedCompileItems);

                // don't use 'any' in paths due to https://github.com/NuGet/Home/issues/1676
                string targetLibFolder = !String.IsNullOrEmpty(RuntimeId) && RuntimeId != "any" ? $"runtimes/{RuntimeId}/lib" : "lib";
                IEnumerable <string> obscuredRuntimeFolders = packageDlls.Where(pi => pi.OriginalItem.GetMetadata("EnsureOOBFrameworkLib") == oobFx).Select(pi => pi.TargetDirectory);

                if (!obscuredRuntimeFolders.Any())
                {
                    var runtimeItems         = resolver.GetRuntimeItems(targetFramework, RuntimeId);
                    var obscuredRuntimeItems = obscuredResolver.GetRuntimeItems(targetFramework, RuntimeId);
                    obscuredRuntimeFolders = GetObscuredAssetFolders(runtimeItems, obscuredRuntimeItems, targetFramework, targetFrameworkName: oobFx, expectedAssetFolder: targetLibFolder);
                }

                var promotedRuntimeItems = ExpandAssetFoldersToItems(obscuredRuntimeFolders, targetLibFolder, targetFrameworkName: oobFx);

                // If we promoted compile assets but couldn't find any runtime assets to promote we could
                // be missing dependencies since a dependency group will be created for the compile assets
                // that may differ from the runtime assets.
                if (promotedCompileItems.Any() && !promotedRuntimeItems.Any())
                {
                    string oobFxRid = oobFramework.GetMetadata("RuntimeId") ?? RuntimeId;

                    // find the actual implementation that will be used.
                    var runtimeItems           = resolver.GetRuntimeItems(targetFramework, oobFxRid);
                    var promotedRuntimeFolders = GetRuntimeAssetFoldersForPromotion(runtimeItems, targetFramework, oobFx);

                    // use null here to indicate that this should not actually go into the package but only be used for
                    // dependency harvesting
                    promotedRuntimeItems = ExpandAssetFoldersToItems(promotedRuntimeFolders, "$none$", targetFrameworkName: oobFx);
                }

                newItems.AddRange(promotedRuntimeItems);
            }

            AdditionalFiles = newItems.ToArray();

            return(!Log.HasLoggedErrors);
        }
Пример #17
0
        /// <summary>
        /// Generates a table in markdown that lists the API version supported by
        /// various packages at all levels of NETStandard.
        /// </summary>
        /// <returns></returns>
        public override bool Execute()
        {
            if (PackageAssets == null || PackageAssets.Length == 0)
            {
                Log.LogError("PackageAssets argument must be specified");
                return(false);
            }

            if (TargetMonikers == null || TargetMonikers.Length == 0)
            {
                Log.LogError("TargetMoniker argument must be specified");
                return(false);
            }

            NuGetFramework[] compileFxs = TargetMonikers.Select(fx => NuGetFramework.Parse(fx)).ToArray();
            NuGetFramework[] runtimeFxs = compileFxs;

            if (RuntimeTargetMonikers != null && RuntimeTargetMonikers.Length > 0)
            {
                runtimeFxs = RuntimeTargetMonikers.Select(fx => NuGetFramework.Parse(fx)).ToArray();
            }

            LoadFiles();

            var buildProjects = new List <BuildProject>();

            CompileAssets = null;
            // find the best framework
            foreach (var compileFx in compileFxs)
            {
                var compileAssets = _resolver.ResolveCompileAssets(compileFx);

                if (compileAssets.Any())
                {
                    var compileItems = compileAssets.Where(ca => !NuGetAssetResolver.IsPlaceholder(ca))
                                       .Select(ca => _targetPathToPackageItem[ca]);

                    buildProjects.AddRange(compileItems.Select(ci => BuildProjectFromPackageItem(ci)).Where(bp => bp != null));

                    CompileAssets = compileItems.Select(ci => PackageItemAsResolvedAsset(ci)).ToArray();

                    Log.LogMessage($"Resolved compile assets from {compileFx.ToString()}: {String.Join(";", CompileAssets.Select(c => c.ItemSpec))}");
                    break;
                }
            }

            if (CompileAssets == null)
            {
                Log.LogError($"Could not locate compile assets for any of the frameworks {String.Join(";", compileFxs.Select(fx => fx.ToString()))}");
            }

            RuntimeAssets = null;
            foreach (var runtimeFx in runtimeFxs)
            {
                var runtimeAssets = _resolver.ResolveRuntimeAssets(runtimeFx, TargetRuntime);

                if (runtimeAssets.Any())
                {
                    var runtimeItems = runtimeAssets.Where(ra => !NuGetAssetResolver.IsPlaceholder(ra))
                                       .Select(ra => _targetPathToPackageItem[ra]);

                    buildProjects.AddRange(runtimeItems.Select(ri => BuildProjectFromPackageItem(ri)).Where(bp => bp != null));

                    RuntimeAssets = runtimeItems.SelectMany(ri => PackageItemAndSymbolsAsResolvedAsset(ri)).ToArray();

                    Log.LogMessage($"Resolved runtime assets from {runtimeFx.ToString()}: {String.Join(";", RuntimeAssets.Select(r => r.ItemSpec))}");
                    break;
                }
            }

            if (RuntimeAssets == null)
            {
                Log.LogError($"Could not locate runtime assets for any of the frameworks {String.Join(";", runtimeFxs.Select(fx => fx.ToString()))}");
            }

            BuildProjects = buildProjects.Distinct().Select(bp => bp.ToItem()).ToArray();

            return(!Log.HasLoggedErrors);
        }
        /// <summary>
        /// Generates a table in markdown that lists the API version supported by
        /// various packages at all levels of NETStandard.
        /// </summary>
        /// <returns></returns>
        public override bool Execute()
        {
            if (PackageAssets == null || PackageAssets.Length == 0)
            {
                Log.LogError("PackageAssets argument must be specified");
                return(false);
            }

            if (TargetMonikers == null || TargetMonikers.Length == 0)
            {
                Log.LogError("TargetMoniker argument must be specified");
                return(false);
            }

            NuGetFramework[] compileFxs = TargetMonikers.Select(fx => NuGetFramework.Parse(fx)).ToArray();
            NuGetFramework[] runtimeFxs = compileFxs;

            if (RuntimeTargetMonikers != null && RuntimeTargetMonikers.Length > 0)
            {
                runtimeFxs = RuntimeTargetMonikers.Select(fx => NuGetFramework.Parse(fx)).ToArray();
            }

            LoadFiles();

            // find the best framework
            foreach (var compileFx in compileFxs)
            {
                CompileAssets = _resolver.ResolveCompileAssets(compileFx)
                                .Where(ca => !NuGetAssetResolver.IsPlaceholder(ca))
                                .Select(ca => PackageItemAsResolvedAsset(_targetPathToPackageItem[ca]))
                                .ToArray();

                if (CompileAssets.Any())
                {
                    Log.LogMessage($"Resolved compile assets from {compileFx.ToString()}: {String.Join(";", CompileAssets.Select(c => c.ItemSpec))}");
                    break;
                }
            }

            if (!CompileAssets.Any())
            {
                Log.LogError($"Could not locate compile assets for any of the frameworks {String.Join(";", compileFxs.Select(fx => fx.ToString()))}");
            }

            foreach (var runtimeFx in runtimeFxs)
            {
                RuntimeAssets = _resolver.ResolveRuntimeAssets(runtimeFx, TargetRuntime)
                                .Where(ra => !NuGetAssetResolver.IsPlaceholder(ra))
                                .Select(ra => PackageItemAsResolvedAsset(_targetPathToPackageItem[ra]))
                                .ToArray();

                if (RuntimeAssets.Any())
                {
                    Log.LogMessage($"Resolved runtime assets from {runtimeFx.ToString()}: {String.Join(";", RuntimeAssets.Select(r => r.ItemSpec))}");
                    break;
                }
            }

            if (!RuntimeAssets.Any())
            {
                Log.LogError($"Could not locate runtime assets for any of the frameworks {String.Join(";", runtimeFxs.Select(fx => fx.ToString()))}");
            }

            return(!Log.HasLoggedErrors);
        }