Exemple #1
0
 public PackInfo(string id, string version, WorkloadPackKind kind, string path)
 {
     Id      = id;
     Version = version;
     Kind    = kind;
     Path    = path;
 }
 public WorkloadPack(WorkloadPackId id, string version, WorkloadPackKind kind, Dictionary <string, WorkloadPackId>?aliasTo)
 {
     Id      = id;
     Version = version;
     Kind    = kind;
     AliasTo = aliasTo;
 }
Exemple #3
0
 public PackInfo(string id, string version, WorkloadPackKind kind, string path, string resolvedPackageId)
 {
     Id                = id;
     Version           = version;
     Kind              = kind;
     Path              = path;
     ResolvedPackageId = resolvedPackageId;
 }
Exemple #4
0
 /// <summary>
 /// Get the installation directory based on the kind of workload pack.
 /// </summary>
 /// <param name="kind">The workload pack kind.</param>
 /// <returns>The name of the root installation directory.</returns>
 internal static string GetInstallDir(WorkloadPackKind kind)
 {
     return(kind switch
     {
         WorkloadPackKind.Framework or WorkloadPackKind.Sdk => "packs",
         WorkloadPackKind.Library => "library-packs",
         WorkloadPackKind.Template => "template-packs",
         WorkloadPackKind.Tool => "tool-packs",
         _ => throw new ArgumentException($"Unknown package kind: {kind}"),
     });
Exemple #5
0
        /// <summary>
        /// Gets the installed workload packs of a particular kind
        /// </summary>
        /// <remarks>
        /// Used by MSBuild resolver to scan SDK packs for AutoImport.props files to be imported.
        /// Used by template engine to find templates to be added to hive.
        /// </remarks>
        public IEnumerable <PackInfo> GetInstalledWorkloadPacksOfKind(WorkloadPackKind kind)
        {
            foreach (var pack in _packs)
            {
                if (pack.Value.Kind != kind)
                {
                    continue;
                }

                var aliasedPath = GetAliasedPackPath(pack.Value);
                if (PackExists(aliasedPath, pack.Value.Kind))
                {
                    yield return(CreatePackInfo(pack.Value, aliasedPath));
                }
            }
        }
Exemple #6
0
        /// <summary>
        /// Gets the installed workload packs of a particular kind
        /// </summary>
        /// <remarks>
        /// Used by MSBuild resolver to scan SDK packs for AutoImport.props files to be imported.
        /// Used by template engine to find templates to be added to hive.
        /// </remarks>
        public IEnumerable <PackInfo> GetInstalledWorkloadPacksOfKind(WorkloadPackKind kind)
        {
            foreach (var pack in _packs)
            {
                if (pack.Value.Kind != kind)
                {
                    continue;
                }

                var aliasedPath       = ResolvePackPath(pack.Value);
                var resolvedPackageId = pack.Value.IsAlias ? pack.Value.TryGetAliasForRuntimeIdentifiers(_currentRuntimeIdentifiers)?.ToString() : pack.Value.Id.ToString();
                if (aliasedPath != null && resolvedPackageId != null && PackExists(aliasedPath, pack.Value.Kind))
                {
                    yield return(CreatePackInfo(pack.Value, aliasedPath, resolvedPackageId));
                }
            }
        }
Exemple #7
0
        private bool PackExists(string packPath, WorkloadPackKind packKind)
        {
            switch (packKind)
            {
            case WorkloadPackKind.Framework:
            case WorkloadPackKind.Sdk:
            case WorkloadPackKind.Tool:
                //can we do a more robust check than directory.exists?
                return(_directoryExistOverride?.Invoke(packPath) ?? Directory.Exists(packPath));

            case WorkloadPackKind.Library:
            case WorkloadPackKind.Template:
                return(_fileExistOverride?.Invoke(packPath) ?? File.Exists(packPath));

            default:
                throw new ArgumentException($"The package kind '{packKind}' is not known", nameof(packKind));
            }
        }
Exemple #8
0
 public IEnumerable <WorkloadResolver.PackInfo> GetInstalledWorkloadPacks(WorkloadPackKind kind)
 => workloadResolver.GetInstalledWorkloadPacksOfKind(kind);
Exemple #9
0
 static PackInfo CreatePackInfo(string id, string version, WorkloadPackKind kind, string path, string resolvedPackageId) => new(new WorkloadPackId(id), version, kind, path, resolvedPackageId);
Exemple #10
0
        private string GetPackPath(string [] dotnetRootPaths, WorkloadPackId packageId, string packageVersion, WorkloadPackKind kind)
        {
            string packPath = "";
            bool   isFile;

            foreach (var rootPath in dotnetRootPaths)
            {
                switch (kind)
                {
                case WorkloadPackKind.Framework:
                case WorkloadPackKind.Sdk:
                    packPath = Path.Combine(rootPath, "packs", packageId.ToString(), packageVersion);
                    isFile   = false;
                    break;

                case WorkloadPackKind.Template:
                    packPath = Path.Combine(rootPath, "template-packs", packageId.GetNuGetCanonicalId() + "." + packageVersion.ToLowerInvariant() + ".nupkg");
                    isFile   = true;
                    break;

                case WorkloadPackKind.Library:
                    packPath = Path.Combine(rootPath, "library-packs", packageId.GetNuGetCanonicalId() + "." + packageVersion.ToLowerInvariant() + ".nupkg");
                    isFile   = true;
                    break;

                case WorkloadPackKind.Tool:
                    packPath = Path.Combine(rootPath, "tool-packs", packageId.ToString(), packageVersion);
                    isFile   = false;
                    break;

                default:
                    throw new ArgumentException($"The package kind '{kind}' is not known", nameof(kind));
                }

                bool packFound = isFile ?
                                 _fileExistOverride?.Invoke(packPath) ?? File.Exists(packPath) :
                                 _directoryExistOverride?.Invoke(packPath) ?? Directory.Exists(packPath);;

                if (packFound)
                {
                    break;
                }
            }
            return(packPath);
        }
Exemple #11
0
 public IEnumerable <WorkloadResolver.PackInfo> GetInstalledWorkloadPacksOfKind(WorkloadPackKind kind) => throw new NotImplementedException();
Exemple #12
0
        private static string GetPackPath(string dotnetRootPath, WorkloadPackId packageId, string packageVersion, WorkloadPackKind kind)
        {
            switch (kind)
            {
            case WorkloadPackKind.Framework:
            case WorkloadPackKind.Sdk:
                return(Path.Combine(dotnetRootPath, "packs", packageId.ToString(), packageVersion));

            case WorkloadPackKind.Template:
                return(Path.Combine(dotnetRootPath, "template-packs", packageId.GetNuGetCanonicalId() + "." + packageVersion.ToLowerInvariant() + ".nupkg"));

            case WorkloadPackKind.Library:
                return(Path.Combine(dotnetRootPath, "library-packs", packageId.GetNuGetCanonicalId() + "." + packageVersion.ToLowerInvariant() + ".nupkg"));

            case WorkloadPackKind.Tool:
                return(Path.Combine(dotnetRootPath, "tool-packs", packageId.ToString(), packageVersion));

            default:
                throw new ArgumentException($"The package kind '{kind}' is not known", nameof(kind));
            }
        }
Exemple #13
0
        /// <summary>
        /// Generate a set of MSIs for the specified platforms using the specified NuGet package.
        /// </summary>
        /// <param name="sourcePackage">The NuGet package to convert into an MSI.</param>
        /// <param name="outputPath">The output path of the generated MSI.</param>
        /// <param name="platforms"></param>
        protected IEnumerable <ITaskItem> Generate(string sourcePackage, string swixPackageId, string outputPath, WorkloadPackKind kind, params string[] platforms)
        {
            NugetPackage    nupkg = new(sourcePackage, Log);
            List <TaskItem> msis  = new();

            // MSI ProductName defaults to the package title and fallback to the package ID with a warning.
            string productName = nupkg.Title;

            if (string.IsNullOrWhiteSpace(nupkg.Title))
            {
                Log?.LogMessage(MessageImportance.High, $"'{sourcePackage}' should have a non-empty title. The MSI ProductName will be set to the package ID instead.");
                productName = nupkg.Id;
            }

            // Extract once, but harvest multiple times because some generated attributes are platform dependent.
            string packageContentsDirectory = Path.Combine(PackageDirectory, $"{nupkg.Identity}");
            IEnumerable <string> exclusions = GetExlusionPatterns();
            string installDir = GetInstallDir(kind);
            string packKind   = kind.ToString().ToLowerInvariant();

            if ((kind != WorkloadPackKind.Library) && (kind != WorkloadPackKind.Template))
            {
                Log.LogMessage(MessageImportance.Low, $"Extracting '{sourcePackage}' to '{packageContentsDirectory}'");
                nupkg.Extract(packageContentsDirectory, exclusions);
            }
            else
            {
                // Library and template packs are not extracted. We want to harvest the nupkg itself,
                // instead of the contents. The package is still copied to a separate folder for harvesting
                // to avoid accidentally pulling in additional files and directories.
                Log.LogMessage(MessageImportance.Low, $"Copying '{sourcePackage}' to '{packageContentsDirectory}'");

                if (Directory.Exists(packageContentsDirectory))
                {
                    Directory.Delete(packageContentsDirectory, recursive: true);
                }
                Directory.CreateDirectory(packageContentsDirectory);

                File.Copy(sourcePackage, Path.Combine(packageContentsDirectory, Path.GetFileName(sourcePackage)));
            }

            System.Threading.Tasks.Parallel.ForEach(platforms, platform =>
            {
                // Extract the MSI template and add it to the list of source files.
                List <string> sourceFiles = new();
                string msiSourcePath      = Path.Combine(MsiDirectory, $"{nupkg.Id}", $"{nupkg.Version}", platform);
                sourceFiles.Add(EmbeddedTemplates.Extract("DependencyProvider.wxs", msiSourcePath));
                sourceFiles.Add(EmbeddedTemplates.Extract("Directories.wxs", msiSourcePath));
                sourceFiles.Add(EmbeddedTemplates.Extract("Product.wxs", msiSourcePath));
                sourceFiles.Add(EmbeddedTemplates.Extract("Registry.wxs", msiSourcePath));

                string EulaRtfPath = Path.Combine(msiSourcePath, "eula.rtf");
                File.WriteAllText(EulaRtfPath, Eula.Replace("__LICENSE_URL__", nupkg.LicenseUrl));
                EmbeddedTemplates.Extract("Variables.wxi", msiSourcePath);

                // Harvest the package contents and add it to the source files we need to compile.
                string packageContentWxs = Path.Combine(msiSourcePath, "PackageContent.wxs");
                sourceFiles.Add(packageContentWxs);

                string directoryReference = (kind == WorkloadPackKind.Library) || (kind == WorkloadPackKind.Template)
                    ? "InstallDir"
                    : PackageContentDirectoryReference;

                HarvestToolTask heat = new(BuildEngine, WixToolsetPath)
                {
                    ComponentGroupName = PackageContentComponentGroupName,
                    DirectoryReference = directoryReference,
                    OutputFile         = packageContentWxs,
                    Platform           = platform,
                    SourceDirectory    = packageContentsDirectory
                };

                if (!heat.Execute())
                {
                    throw new Exception($"Failed to harvest package contents.");
                }

                // Compile the MSI sources
                string candleIntermediateOutputPath = Path.Combine(IntermediateBaseOutputPath, "wixobj",
                                                                   $"{nupkg.Id}", $"{nupkg.Version}", platform);

                CompileToolTask candle = new(BuildEngine, WixToolsetPath)
                {
                    // Candle expects the output path to end with a single '\'
                    OutputPath  = candleIntermediateOutputPath.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar,
                    SourceFiles = sourceFiles,
                    Arch        = platform
                };

                // Configure preprocessor definitions.
                string manufacturer = "Microsoft Corporation";

                if (!string.IsNullOrWhiteSpace(nupkg.Authors) && (nupkg.Authors.IndexOf("Microsoft", StringComparison.OrdinalIgnoreCase) < 0))
                {
                    manufacturer = nupkg.Authors;
                }
                Log.LogMessage(MessageImportance.Low, $"Setting Manufacturer to '{manufacturer}'");

                candle.PreprocessorDefinitions.AddRange(GetPreprocessorDefinitions(nupkg, platform));
                candle.PreprocessorDefinitions.Add($@"InstallDir={installDir}");
                candle.PreprocessorDefinitions.Add($@"ProductName={productName}");
                candle.PreprocessorDefinitions.Add($@"Platform={platform}");
                candle.PreprocessorDefinitions.Add($@"SourceDir={packageContentsDirectory}");
                candle.PreprocessorDefinitions.Add($@"Manufacturer={manufacturer}");
                candle.PreprocessorDefinitions.Add($@"EulaRtf={EulaRtfPath}");
                candle.PreprocessorDefinitions.Add($@"PackKind={packKind}");

                // Compiler extension to process dependency provider authoring for package reference counting.
                candle.Extensions.Add("WixDependencyExtension");

                if (!candle.Execute())
                {
                    throw new Exception($"Failed to compile MSI.");
                }

                // Link the MSI. The generated filename contains a the semantic version (excluding build metadata) and platform.
                // If the source package already contains a platform, e.g. an aliased package that has a RID, then we don't add
                // the platform again.

                string shortPackageName = Path.GetFileNameWithoutExtension(sourcePackage).Replace(ShortNames);

                string outputFile = sourcePackage.Contains(platform) ?
                                    Path.Combine(OutputPath, shortPackageName + ".msi") :
                                    Path.Combine(OutputPath, shortPackageName + $"-{platform}.msi");

                LinkToolTask light = new(BuildEngine, WixToolsetPath)
                {
                    OutputFile   = Path.Combine(OutputPath, outputFile),
                    SourceFiles  = Directory.EnumerateFiles(candleIntermediateOutputPath, "*.wixobj"),
                    SuppressIces = this.SuppressIces
                };

                // Add WiX extensions
                light.Extensions.Add("WixDependencyExtension");
                light.Extensions.Add("WixUIExtension");

                if (!light.Execute())
                {
                    throw new Exception($"Failed to link MSI.");
                }

                // Generate metadata used for CLI based installations.
                string msiPath         = light.OutputFile;
                MsiProperties msiProps = new MsiProperties
                {
                    InstallSize     = MsiUtils.GetInstallSize(msiPath),
                    Language        = Convert.ToInt32(MsiUtils.GetProperty(msiPath, "ProductLanguage")),
                    Payload         = Path.GetFileName(msiPath),
                    ProductCode     = MsiUtils.GetProperty(msiPath, "ProductCode"),
                    ProductVersion  = MsiUtils.GetProperty(msiPath, "ProductVersion"),
                    ProviderKeyName = $"{nupkg.Id},{nupkg.Version},{platform}",
                    UpgradeCode     = MsiUtils.GetProperty(msiPath, "UpgradeCode"),
                    RelatedProducts = MsiUtils.GetRelatedProducts(msiPath)
                };

                string msiJsonPath = Path.Combine(Path.GetDirectoryName(msiPath), Path.GetFileNameWithoutExtension(msiPath) + ".json");
                File.WriteAllText(msiJsonPath, JsonSerializer.Serialize <MsiProperties>(msiProps));

                TaskItem msi = new(light.OutputFile);
                msi.SetMetadata(Metadata.Platform, platform);
                msi.SetMetadata(Metadata.Version, nupkg.ProductVersion);
                msi.SetMetadata(Metadata.JsonProperties, msiJsonPath);
                msi.SetMetadata(Metadata.WixObj, candleIntermediateOutputPath);

                if (GenerateSwixAuthoring && IsSupportedByVisualStudio(platform))
                {
                    string swixProject = GenerateSwixPackageAuthoring(light.OutputFile,
                                                                      !string.IsNullOrWhiteSpace(swixPackageId) ? swixPackageId :
                                                                      $"{nupkg.Id.Replace(ShortNames)}.{nupkg.Version}", platform);

                    if (!string.IsNullOrWhiteSpace(swixProject))
                    {
                        msi.SetMetadata(Metadata.SwixProject, swixProject);
                    }
                }

                // Generate a .csproj to build a NuGet payload package to carry the MSI and JSON manifest
                msi.SetMetadata(Metadata.PackageProject, GeneratePackageProject(msi.ItemSpec, msiJsonPath, platform, nupkg));

                msis.Add(msi);
            });

            return(msis);
        }