public override bool Execute() { try { Log.LogMessage($"Generating SWIX package authoring for '{MsiPath}'"); if (Version == null) { // Use the version of the MSI if none was specified Version = new Version(MsiUtils.GetProperty(MsiPath, "ProductVersion")); Log.LogMessage($"Using MSI version for package version: {Version}"); } // Try to catch VS manifest validation errors before we get to VS. string vsPayloadRelativePath = $"{PackageName},version={Version.ToString(3)},chip={Chip},productarch={ProductArch}\\{Path.GetFileName(MsiPath)}"; CheckRelativePayloadPath(vsPayloadRelativePath); string swixSourceDirectory = Path.Combine(SwixDirectory, PackageName, Chip); string msiSwr = EmbeddedTemplates.Extract("msi.swr", swixSourceDirectory); string fullProjectName = $"{PackageName}.{Version.ToString(3)}.{Chip}"; string msiSwixProj = EmbeddedTemplates.Extract("msi.swixproj", swixSourceDirectory, $"{Utils.GetHash(fullProjectName, "MD5")}.swixproj"); FileInfo msiInfo = new(MsiPath); PayloadSize = msiInfo.Length; InstallSize = MsiUtils.GetInstallSize(MsiPath); Log.LogMessage($"MSI payload size: {PayloadSize}, install size (estimated): {InstallSize} "); Utils.StringReplace(msiSwr, GetReplacementTokens(), Encoding.UTF8); Utils.StringReplace(msiSwixProj, GetReplacementTokens(), Encoding.UTF8); SwixProject = msiSwixProj; } catch (Exception e) { Log.LogMessage(e.StackTrace); Log.LogErrorFromException(e); } return(!Log.HasLoggedErrors); }
public override bool Execute() { try { NugetPackage nupkg = new(WorkloadManifestPackage, Log); List <TaskItem> msis = new(); var manifestSeparator = ".Manifest-"; if (string.IsNullOrWhiteSpace(ManifestId)) { if ($"{nupkg.Id}".IndexOf(manifestSeparator, StringComparison.OrdinalIgnoreCase) == -1) { Log.LogError($"Unable to parse a manifest ID from package ID: '{nupkg.Id}'. Please provide the 'ManifestId' parameter."); } else { ManifestId = $"{nupkg.Id}".Substring(0, $"{nupkg.Id}".IndexOf(manifestSeparator)); } } if (string.IsNullOrWhiteSpace(SdkVersion)) { if ($"{nupkg.Id}".IndexOf(manifestSeparator, StringComparison.OrdinalIgnoreCase) == -1) { Log.LogError($"Unable to parse the SDK version from package ID: '{nupkg.Id}'. Please provide the 'SdkVersion' parameter."); } else { SdkVersion = $"{nupkg.Id}".Substring($"{nupkg.Id}".IndexOf(manifestSeparator) + manifestSeparator.Length); } } Log.LogMessage(MessageImportance.High, $"Generating workload manifest installer for {SdkFeatureBandVersion}"); // 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, $"'{WorkloadManifestPackage}' 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}"); nupkg.Extract(packageContentsDirectory, Enumerable.Empty <string>()); string packageContentsDataDirectory = Path.Combine(packageContentsDirectory, "data"); foreach (string platform in GenerateMsiBase.SupportedPlatforms) { // 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("dotnethome_x64.wxs", msiSourcePath)); sourceFiles.Add(EmbeddedTemplates.Extract("ManifestProduct.wxs", msiSourcePath)); string EulaRtfPath = Path.Combine(msiSourcePath, "eula.rtf"); File.WriteAllText(EulaRtfPath, GenerateMsiBase.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); HarvestToolTask heat = new(BuildEngine, WixToolsetPath) { ComponentGroupName = GenerateMsiBase.PackageContentComponentGroupName, DirectoryReference = "ManifestIdDir", OutputFile = packageContentWxs, Platform = platform, SourceDirectory = packageContentsDataDirectory }; if (!heat.Execute()) { throw new Exception($"Failed to harvest package contents."); } // To support upgrades, the UpgradeCode must be stable withing a feature band. // For example, 6.0.101 and 6.0.108 will generate the same GUID for the same platform. var upgradeCode = Utils.CreateUuid(GenerateMsiBase.UpgradeCodeNamespaceUuid, $"{ManifestId};{SdkFeatureBandVersion};{platform}"); var productCode = Guid.NewGuid(); Log.LogMessage($"UC: {upgradeCode}, PC: {productCode}, {SdkFeatureBandVersion}, {SdkVersion}, {platform}"); string providerKeyName = $"{ManifestId},{SdkFeatureBandVersion},{platform}"; // 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.Add($@"PackageId={nupkg.Id}"); candle.PreprocessorDefinitions.Add($@"PackageVersion={nupkg.Version}"); candle.PreprocessorDefinitions.Add($@"ProductVersion={MsiVersion}"); candle.PreprocessorDefinitions.Add($@"ProductCode={productCode}"); candle.PreprocessorDefinitions.Add($@"UpgradeCode={upgradeCode}"); // Override the default provider key candle.PreprocessorDefinitions.Add($@"DependencyProviderKeyName={providerKeyName}"); candle.PreprocessorDefinitions.Add($@"ProductName={productName}"); candle.PreprocessorDefinitions.Add($@"Platform={platform}"); candle.PreprocessorDefinitions.Add($@"SourceDir={packageContentsDataDirectory}"); candle.PreprocessorDefinitions.Add($@"Manufacturer={manufacturer}"); candle.PreprocessorDefinitions.Add($@"EulaRtf={EulaRtfPath}"); candle.PreprocessorDefinitions.Add($@"SdkFeatureBandVersion={SdkFeatureBandVersion}"); // The temporary installer in the SDK used lower invariants of the manifest ID. // We have to do the same to ensure the keypath generation produces stable GUIDs so that // the manifests/targets get the same component GUIDs. candle.PreprocessorDefinitions.Add($@"ManifestId={ManifestId.ToLowerInvariant()}"); // 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(WorkloadManifestPackage); string outputFile = 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 = $"{providerKeyName}", 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 swixPackageId = $"{nupkg.Id.ToString().Replace(ShortNames)}"; string swixProject = GenerateSwixPackageAuthoring(light.OutputFile, swixPackageId, 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); } Msis = msis.ToArray(); } catch (Exception e) { Log.LogErrorFromException(e); } return(!Log.HasLoggedErrors); }
/// <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); }
/// <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, string installDir, 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(); Log.LogMessage(MessageImportance.Low, $"Extracting '{sourcePackage}' to '{packageContentsDirectory}'"); nupkg.Extract(packageContentsDirectory, exclusions); foreach (string platform in platforms) { // 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); HarvestToolTask heat = new(BuildEngine, WixToolsetPath) { ComponentGroupName = PackageContentComponentGroupName, DirectoryReference = PackageContentDirectoryReference, 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}"); // 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), ProductCode = MsiUtils.GetProperty(msiPath, "ProductCode"), ProductVersion = MsiUtils.GetProperty(msiPath, "ProductVersion"), ProviderKeyName = $"{nupkg.Id},{nupkg.Version},{platform}", UpgradeCode = MsiUtils.GetProperty(msiPath, "UpgradeCode") }; 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); } private string GeneratePackageProject(string msiPath, string msiJsonPath, string platform, NugetPackage nupkg) { string msiPackageProject = Path.Combine(MsiPackageDirectory, platform, nupkg.Id, "msi.csproj"); string msiPackageProjectDir = Path.GetDirectoryName(msiPackageProject); Log?.LogMessage($"Generating package project: '{msiPackageProject}'"); if (Directory.Exists(msiPackageProjectDir)) { Directory.Delete(msiPackageProjectDir, recursive: true); } Directory.CreateDirectory(msiPackageProjectDir); EmbeddedTemplates.Extract("Icon.png", msiPackageProjectDir); EmbeddedTemplates.Extract("LICENSE.TXT", msiPackageProjectDir); string licenseTextPath = Path.Combine(msiPackageProjectDir, "LICENSE.TXT"); XmlWriterSettings settings = new XmlWriterSettings { Indent = true, IndentChars = " ", }; XmlWriter writer = XmlWriter.Create(msiPackageProject, settings); writer.WriteStartElement("Project"); writer.WriteAttributeString("Sdk", "Microsoft.NET.Sdk"); writer.WriteStartElement("PropertyGroup"); writer.WriteElementString("TargetFramework", "net5.0"); writer.WriteElementString("GeneratePackageOnBuild", "true"); writer.WriteElementString("IncludeBuildOutput", "false"); writer.WriteElementString("IsPackable", "true"); writer.WriteElementString("PackageType", "DotnetPlatform"); writer.WriteElementString("SuppressDependenciesWhenPacking", "true"); writer.WriteElementString("NoWarn", "$(NoWarn);NU5128"); writer.WriteElementString("PackageId", $"{nupkg.Id}.Msi.{platform}"); writer.WriteElementString("PackageVersion", $"{nupkg.Version}"); writer.WriteElementString("Description", nupkg.Description); writer.WriteElementString("PackageIcon", "Icon.png"); if (!string.IsNullOrWhiteSpace(nupkg.Authors)) { writer.WriteElementString("Authors", nupkg.Authors); } if (!string.IsNullOrWhiteSpace(nupkg.Copyright)) { writer.WriteElementString("Copyright", nupkg.Copyright); } writer.WriteElementString("PackageLicenseExpression", "MIT"); writer.WriteEndElement(); writer.WriteStartElement("ItemGroup"); WriteItem(writer, "None", msiPath, @"\data"); WriteItem(writer, "None", msiJsonPath, @"\data"); WriteItem(writer, "None", licenseTextPath, @"\"); writer.WriteEndElement(); writer.WriteEndElement(); writer.Flush(); writer.Close(); return(msiPackageProject); }