Exemple #1
0
    private static async Task <(LockFile, String, NuGetFramework)> RestoreAndFilterOutSDKPackages(
        this NuGetDeploymentConfiguration config,
        BoundRestoreCommandUser restorer,
        CancellationToken token,
        String restoreSDKPackageID,
        String restoreSDKPackageVersion
        )
    {
        var packageID = config.PackageID;
        var lockFile  = await restorer.RestoreIfNeeded(packageID, config.PackageVersion, token);

        // TODO better error messages
        var packagePath = restorer.ResolveFullPath(
            lockFile,
            lockFile.Libraries.FirstOrDefault(l => String.Equals(l.Name, packageID, StringComparison.OrdinalIgnoreCase))?.Path
            );
        var epAssemblyPath = NuGetUtility.GetAssemblyPathFromNuGetAssemblies(
            packageID,
            lockFile
            .Targets[0]
            .GetTargetLibrary(packageID)
            .RuntimeAssemblies
            .Select(ra => Path.GetFullPath(Path.Combine(packagePath, ra.Path)))
            .ToArray(),
            config.AssemblyPath
            );

        // We might be restoring .NETStandard package against .NETCoreApp framework, so find out the actual framework the package was built against.
        // So from path "/path/to/nuget/repo/package-id/package-version/lib/target-fw/package-id.dll" we want to extract the target-fw portion.
        // packagePath variable holds everything before the 'lib', so we just need to name of the folder 1 hierarchy level down from packagePath.
        var start            = GetNextSeparatorIndex(epAssemblyPath, packagePath.Length + 1) + 1;
        var end              = GetNextSeparatorIndex(epAssemblyPath, start);
        var packageFramework = NuGetFramework.ParseFolder(epAssemblyPath.Substring(start, end - start));

        //}
        //var targetFramework = restorer.ThisFramework;
        //sdkPackageID = NuGetUtility.GetSDKPackageID( targetFramework, config.ProcessSDKFrameworkPackageID ?? sdkPackageID );
        //sdkPackageVersion = NuGetUtility.GetSDKPackageVersion( targetFramework, sdkPackageID, config.ProcessSDKFrameworkPackageVersion ?? sdkPackageVersion );

        // Warning: The code below exploits the de facto behaviour that package named "System.XYZ" will contain assembly named "System.XYZ". Should sometime in the future this change, this code will then result in possibly wrong behaviour.
        // TODO I wonder if this assumption is needed anymore with .NET Standard and .NET Core 2+?

        var packageSDKPackageID = packageFramework.GetSDKPackageID(config.PackageSDKFrameworkPackageID);
        var sdkPackages         = new HashSet <String>(StringComparer.OrdinalIgnoreCase);

        if (!String.Equals(packageSDKPackageID, restoreSDKPackageID, StringComparison.OrdinalIgnoreCase))
        {
            // Typically when package is for .NET Standard and target framework is .NET Core
            var restoreLockFile = await restorer.RestoreIfNeeded(restoreSDKPackageID, restoreSDKPackageVersion, token);

            sdkPackages.UnionWith(restoreLockFile.Targets[0].GetAllDependencies(restoreSDKPackageID.Singleton())
                                  .SelectMany(lib => lib.Name.Singleton().Concat(lib.CompileTimeAssemblies.Select(cta => Path.GetFileNameWithoutExtension(cta.Path)).FilterUnderscores()))
                                  );
        }
        sdkPackages.UnionWith(lockFile.Targets[0].GetAllDependencies(packageSDKPackageID.Singleton()).Select(lib => lib.Name));


        var packageSDKPackageVersion = packageFramework.GetSDKPackageVersion(packageSDKPackageID, config.PackageSDKFrameworkPackageVersion);
        // In addition, check all compile assemblies from sdk package (e.g. Microsoft.NETCore.App )
        // Starting from 2.0.0, all assemblies from all dependent packages are marked as compile-assemblies stored in sdk package.
        var sdkPackageContainsAllPackagesAsAssemblies = config.PackageFrameworkIsPackageBased;

        Version.TryParse(packageSDKPackageVersion, out var sdkPkgVer);
        if (sdkPackageContainsAllPackagesAsAssemblies.IsTrue() ||
            (!sdkPackageContainsAllPackagesAsAssemblies.HasValue && packageFramework.IsPackageBased) // sdkPackageID == NuGetUtility.SDK_PACKAGE_NETCORE && sdkPkgVer != null && sdkPkgVer.Major >= 2 )
            )
        {
            var sdkPackageLibraries = lockFile.Targets[0].Libraries.Where(l => l.Name == packageSDKPackageID);

            if (sdkPkgVer != null)
            {
                sdkPackageLibraries = sdkPackageLibraries.Where(l => l.Version.Version >= sdkPkgVer);
            }

            var sdkPackageLibrary = sdkPackageLibraries.FirstOrDefault();

            if (sdkPackageLibrary == null && sdkPkgVer != null)
            {
                // We need to restore the correctly versioned SDK package
                sdkPackageLibrary = (await restorer.RestoreIfNeeded(packageSDKPackageID, packageSDKPackageVersion, token)).Targets[0].GetTargetLibrary(packageSDKPackageID);
            }

            if (sdkPackageLibrary != null)
            {
                sdkPackages.UnionWith(sdkPackageLibrary.CompileTimeAssemblies.Select(cta => Path.GetFileNameWithoutExtension(cta.Path)).FilterUnderscores());
            }
        }

        // Actually -> return LockFile, but modify it so that sdk packages are removed
        var targetLibs = lockFile.Targets[0].Libraries;

        for (var i = 0; i < targetLibs.Count;)
        {
            var curLib   = targetLibs[i];
            var contains = sdkPackages.Contains(curLib.Name);
            if (contains ||
                (
                    (curLib.RuntimeAssemblies.Count <= 0 || !curLib.RuntimeAssemblies.Select(ra => ra.Path).FilterUnderscores().Any()) &&
                    curLib.RuntimeTargets.Count <= 0 &&
                    curLib.ResourceAssemblies.Count <= 0 &&
                    curLib.NativeLibraries.Count <= 0
                )
                )
            {
                targetLibs.RemoveAt(i);
                if (!contains)
                {
                    sdkPackages.Add(curLib.Name);
                }
            }
            else
            {
                ++i;
            }
        }

        var libs = lockFile.Libraries;

        for (var i = 0; i < libs.Count;)
        {
            var curLib = libs[i];
            if (sdkPackages.Contains(curLib.Name))
            {
                libs.RemoveAt(i);
            }
            else
            {
                ++i;
            }
        }

        return(lockFile, epAssemblyPath, packageFramework);
    }
Exemple #2
0
    /// <summary>
    /// Using information from this <see cref="NuGetDeploymentConfiguration"/>, restores the NuGet package, and deploys it by copying non-framework dependencies to target directory or by creating a <c>.deps.json</c> and <c>.runtimeconfig.json</c> files.
    /// </summary>
    /// <param name="config">This <see cref="NuGetDeploymentConfiguration"/>.</param>
    /// <param name="restorer">The <see cref="BoundRestoreCommandUser"/> to restore the NuGet package.</param>
    /// <param name="token">The <see cref="CancellationToken"/> to use when performing <c>async</c> operations.</param>
    /// <param name="sdkPackageID">The SDK package ID.</param>
    /// <param name="sdkPackageVersion">The SDK package version.</param>
    /// <returns>Asynchronously returns the full path to the deployed assembly, and a <see cref="NuGetFramework"/> which the assembly was built against.</returns>
    /// <exception cref="NullReferenceException">If this <see cref="NuGetDeploymentConfiguration"/> is <c>null</c>.</exception>
    /// <exception cref="ArgumentNullException">If <paramref name="restorer"/> is <c>null</c>.</exception>
    public static async Task <(String EntryPointAssemblyPath, NuGetFramework DeployedPackageFramework)> DeployAsync(
        this NuGetDeploymentConfiguration config,
        BoundRestoreCommandUser restorer,
        CancellationToken token,
        String sdkPackageID,
        String sdkPackageVersion
        )
    {
        ArgumentValidator.ValidateNotNullReference(config);
        ArgumentValidator.ValidateNotNull(nameof(restorer), restorer);

        (var lockFile, var entryPointAssembly, var packageFramework) = await config.RestoreAndFilterOutSDKPackages(
            restorer,
            token,
            sdkPackageID,
            sdkPackageVersion
            );


        JToken runtimeConfig     = null;
        var    runtimeConfigPath = Path.ChangeExtension(entryPointAssembly, RUNTIME_CONFIG_EXTENSION);

        if (File.Exists(runtimeConfigPath))
        {
            try
            {
                using (var streamReader = new StreamReader(File.OpenRead(runtimeConfigPath)))
                    using (var jsonReader = new JsonTextReader(streamReader))
                    {
                        runtimeConfig = JToken.ReadFrom(jsonReader);
                    }
            }
            catch
            {
                // Ignore
            }
        }

        var targetDirectory = CreateTargetDirectory(config.TargetDirectory);

        String assemblyToBeExecuted;

        switch (config.DeploymentKind)
        {
        case DeploymentKind.GenerateConfigFiles:
            if (restorer.ThisFramework.IsDesktop())
            {
                // This is not supported for desktop framework
                // TODO log warning
                assemblyToBeExecuted = DeployByCopyingAssemblies(
                    restorer,
                    lockFile,
                    entryPointAssembly,
                    runtimeConfig,
                    sdkPackageID,
                    sdkPackageVersion,
                    targetDirectory
                    );
            }
            else
            {
                assemblyToBeExecuted = DeployByGeneratingConfigFiles(
                    lockFile,
                    entryPointAssembly,
                    runtimeConfig,
                    sdkPackageID,
                    sdkPackageVersion,
                    targetDirectory
                    );
            }
            break;

        case DeploymentKind.CopyNonSDKAssemblies:
            assemblyToBeExecuted = DeployByCopyingAssemblies(
                restorer,
                lockFile,
                entryPointAssembly,
                runtimeConfig,
                sdkPackageID,
                sdkPackageVersion,
                targetDirectory
                );
            break;

        default:
            throw new NotSupportedException($"Unrecognized deployment kind: {config.DeploymentKind}.");
        }

        return(assemblyToBeExecuted, packageFramework);
    }