File: GenerateBootstrapper.cs
Web Access
Project: ..\..\..\src\Tasks\Microsoft.Build.Tasks.csproj (Microsoft.Build.Tasks.Core)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
#if NETFRAMEWORK
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Build.Tasks.Deployment.Bootstrapper;
#endif
 
using Microsoft.Build.Framework;
 
#nullable disable
 
namespace Microsoft.Build.Tasks
{
#if NETFRAMEWORK
 
    /// <summary>
    /// Generates a bootstrapper for ClickOnce deployment projects.
    /// </summary>
    public sealed class GenerateBootstrapper : TaskExtension, IGenerateBootstrapperTaskContract
    {
        public string ApplicationName { get; set; }
 
        public string ApplicationFile { get; set; }
 
        public bool ApplicationRequiresElevation { get; set; }
 
        public string ApplicationUrl { get; set; }
 
        public ITaskItem[] BootstrapperItems { get; set; }
 
        public string ComponentsLocation { get; set; }
 
        public string ComponentsUrl { get; set; }
 
        public bool CopyComponents { get; set; } = true;
 
        public string Culture { get; set; } = Util.DefaultCultureInfo.Name;
 
        public string FallbackCulture { get; set; } = Util.DefaultCultureInfo.Name;
 
        public string OutputPath { get; set; } = Directory.GetCurrentDirectory();
 
        public string Path { get; set; }
 
        public string SupportUrl { get; set; }
 
        public string VisualStudioVersion { get; set; }
 
        public bool Validate { get; set; } = true;
 
        [Output]
        public string BootstrapperKeyFile { get; set; }
 
        [Output]
        public string[] BootstrapperComponentFiles { get; set; }
 
        /// <summary>
        /// Generate the bootstrapper.
        /// </summary>
        /// <returns> Return true on success, false on failure.</returns>
        public override bool Execute()
        {
            if (Path == null)
            {
                Path = Util.GetDefaultPath(VisualStudioVersion);
            }
 
            var bootstrapperBuilder = new BootstrapperBuilder
            {
                Validate = Validate,
                Path = Path
            };
 
            ProductCollection products = bootstrapperBuilder.Products;
 
            var settings = new BuildSettings
            {
                ApplicationFile = ApplicationFile,
                ApplicationName = ApplicationName,
                ApplicationRequiresElevation = ApplicationRequiresElevation,
                ApplicationUrl = ApplicationUrl,
                ComponentsLocation = ConvertStringToComponentsLocation(ComponentsLocation),
                ComponentsUrl = ComponentsUrl,
                CopyComponents = CopyComponents,
                Culture = Culture,
                FallbackCulture = FallbackCulture,
                OutputPath = OutputPath,
                SupportUrl = SupportUrl
            };
 
            if (String.IsNullOrEmpty(settings.Culture) || settings.Culture == "*")
            {
                settings.Culture = settings.FallbackCulture;
            }
 
            if (BootstrapperItems != null)
            {
                // The bootstrapper items may not be in the correct order, because XMake saves
                // items in alphabetical order.  So we will attempt to put items into the correct
                // order, according to the Products order in the search.  To do this, we add all
                // the items we are told to build into a hashtable, then go through our products
                // in order, looking to see if the item is built.  If it is, remove the item from
                // the hashtable.  All remaining items in the table can not be built, so errors
                // will be issued.
                var items = new Dictionary<string, ITaskItem>(StringComparer.OrdinalIgnoreCase);
 
                foreach (ITaskItem bootstrapperItem in BootstrapperItems)
                {
                    string installAttribute = bootstrapperItem.GetMetadata("Install");
                    if (String.IsNullOrEmpty(installAttribute) || Shared.ConversionUtilities.ConvertStringToBool(installAttribute))
                    {
                        if (!items.ContainsKey(bootstrapperItem.ItemSpec))
                        {
                            items.Add(bootstrapperItem.ItemSpec, bootstrapperItem);
                        }
                        else
                        {
                            Log.LogWarningWithCodeFromResources("GenerateBootstrapper.DuplicateItems", bootstrapperItem.ItemSpec);
                        }
                    }
                }
 
                foreach (Product product in products)
                {
                    if (items.Remove(product.ProductCode))
                    {
                        settings.ProductBuilders.Add(product.ProductBuilder);
                    }
                }
 
                foreach (ITaskItem bootstrapperItem in items.Values)
                {
                    Log.LogWarningWithCodeFromResources("GenerateBootstrapper.ProductNotFound", bootstrapperItem.ItemSpec, bootstrapperBuilder.Path);
                }
            }
 
            BuildResults results = bootstrapperBuilder.Build(settings);
            BuildMessage[] messages = results.Messages;
 
            if (messages != null)
            {
                foreach (BuildMessage message in messages)
                {
                    if (message.Severity == BuildMessageSeverity.Error)
                    {
                        Log.LogError(null, message.HelpCode, message.HelpKeyword, null, 0, 0, 0, 0, message.Message);
                    }
                    else if (message.Severity == BuildMessageSeverity.Warning)
                    {
                        Log.LogWarning(null, message.HelpCode, message.HelpKeyword, null, 0, 0, 0, 0, message.Message);
                    }
                }
            }
 
            BootstrapperKeyFile = results.KeyFile;
            BootstrapperComponentFiles = results.ComponentFiles;
 
            return results.Succeeded;
        }
 
        private ComponentsLocation ConvertStringToComponentsLocation(string parameterValue)
        {
            if (string.IsNullOrEmpty(parameterValue))
            {
                return Deployment.Bootstrapper.ComponentsLocation.HomeSite;
            }
 
            try
            {
                return (ComponentsLocation)Enum.Parse(typeof(ComponentsLocation), parameterValue, false);
            }
            catch (FormatException)
            {
                Log.LogWarningWithCodeFromResources("GenerateBootstrapper.InvalidComponentsLocation", parameterValue);
                return Deployment.Bootstrapper.ComponentsLocation.HomeSite;
            }
        }
    }
 
#else

    public sealed class GenerateBootstrapper : TaskRequiresFramework, IGenerateBootstrapperTaskContract
    {
        public GenerateBootstrapper()
            : base(nameof(GenerateBootstrapper))
        {
        }
 
        #region Properties

        public string ApplicationName { get; set; }
 
        public string ApplicationFile { get; set; }
 
        public bool ApplicationRequiresElevation { get; set; }
 
        public string ApplicationUrl { get; set; }
 
        public ITaskItem[] BootstrapperItems { get; set; }
 
        public string ComponentsLocation { get; set; }
 
        public string ComponentsUrl { get; set; }
 
        public bool CopyComponents { get; set; }
 
        public string Culture { get; set; }
 
        public string FallbackCulture { get; set; }
 
        public string OutputPath { get; set; }
 
        public string Path { get; set; }
 
        public string SupportUrl { get; set; }
 
        public string VisualStudioVersion { get; set; }
 
        public bool Validate { get; set; }
 
        [Output]
        public string BootstrapperKeyFile { get; set; }
 
        [Output]
        public string[] BootstrapperComponentFiles { get; set; }
 
        #endregion
    }
 
#endif
 
    internal interface IGenerateBootstrapperTaskContract
    {
        #region Properties
 
        string ApplicationName { get; set; }
        string ApplicationFile { get; set; }
        bool ApplicationRequiresElevation { get; set; }
        string ApplicationUrl { get; set; }
        ITaskItem[] BootstrapperItems { get; set; }
        string ComponentsLocation { get; set; }
        string ComponentsUrl { get; set; }
        bool CopyComponents { get; set; }
        string Culture { get; set; }
        string FallbackCulture { get; set; }
        string OutputPath { get; set; }
        string Path { get; set; }
        string SupportUrl { get; set; }
        string VisualStudioVersion { get; set; }
        bool Validate { get; set; }
        string BootstrapperKeyFile { get; set; }
        string[] BootstrapperComponentFiles { get; set; }
 
        #endregion
    }
}