コード例 #1
0
        /// <summary>
        /// Generate a set of preprocessor variable definitions using the metadata.
        /// </summary>
        /// <returns>An enumerable containing package metadata converted to WiX preprocessor definitions.</returns>
        private IEnumerable <string> GetPreprocessorDefinitions(NugetPackage package, string platform)
        {
            yield return($@"PackageId={package.Id}");

            yield return($@"PackageVersion={package.Version}");

            yield return($@"ProductVersion={package.ProductVersion}");

            yield return($@"ProductCode={Utils.CreateUuid(ProductCodeNamespaceUuid, package.Identity.ToString() + $"{platform}"):B}");

            yield return($@"UpgradeCode={Utils.CreateUuid(UpgradeCodeNamespaceUuid, package.Identity.ToString() + $"{platform}"):B}");
        }
コード例 #2
0
        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);

            string iconFileName    = "Icon.png";
            string licenseFileName = "LICENSE.TXT";

            EmbeddedTemplates.Extract(iconFileName, msiPackageProjectDir);
            EmbeddedTemplates.Extract(licenseFileName, msiPackageProjectDir);

            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);

            if (!string.IsNullOrWhiteSpace(nupkg.Authors))
            {
                writer.WriteElementString("Authors", nupkg.Authors);
            }

            if (!string.IsNullOrWhiteSpace(nupkg.Copyright))
            {
                writer.WriteElementString("Copyright", nupkg.Copyright);
            }

            if (!string.IsNullOrWhiteSpace(nupkg.ProjectUrl))
            {
                writer.WriteElementString("PackageProjectUrl", nupkg.ProjectUrl);
            }

            writer.WriteElementString("PackageLicenseExpression", "MIT");
            writer.WriteEndElement();

            writer.WriteStartElement("ItemGroup");
            WriteItem(writer, "None", msiPath, @"\data");
            WriteItem(writer, "None", msiJsonPath, @"\data\msi.json");
            WriteItem(writer, "None", licenseFileName, @"\");
            writer.WriteEndElement(); // ItemGroup

            writer.WriteRaw(@"
<Target Name=""AddPackageIcon""
        BeforeTargets=""$(GenerateNuspecDependsOn)""
        Condition=""'$(PackageIcon)' == ''"">
  <PropertyGroup>
    <PackageIcon>Icon.png</PackageIcon>
  </PropertyGroup>
  <ItemGroup Condition=""'$(IsPackable)' == 'true'"">
    <None Include=""$(PackageIcon)"" Pack=""true"" PackagePath=""$(PackageIcon)"" Visible=""false"" />
  </ItemGroup>
</Target>
");

            writer.WriteEndElement(); // Project
            writer.Flush();
            writer.Close();

            return(msiPackageProject);
        }
コード例 #3
0
ファイル: GenerateMsiBase.cs プロジェクト: ryalanms/arcade
        /// <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 = null;

            lock (extractNuGetLock)
            {
                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}'");
                lock (extractNuGetLock)
                {
                    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("dotnethome_x64.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
                };

                lock (extractNuGetLock)
                {
                    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);
        }