4

我一直在 BeforeBuild 目标中的 WiX 安装程序项目中使用 HeatDirectory 任务来收集我们在客户端网络上部署的 Web 应用程序的文件。工作得很好。

我现在想部署第二组文件,它恰好是一些文档,它包含与先前 HeatDirectory 输出中存在的同名文件。

我收到以下错误:

LGHT0293: Multiple files with ID 'Web.Config' exist.

我明白为什么我会收到错误,我想知道如何最好地解决它。

选项 A

将所有文件复制到一个目录中,并一次性大量运行它们。

我喜欢这个,因为使用股票 MSBuild 任务实现起来相当容易。我不喜欢它,因为它会创建一个庞大的 ComponentGroup,如果我决定制作可选功能(比如不安装某些东西),我就做不到。

选项 B

遍历 HeatDirectory 任务的输出文件并在所有组件 ID 和文件 ID 上附加一个后缀。示例 - web.config 将变为 web.config_DocumenationFiles

我喜欢这个,因为它很干净;即我可以稍后将其删除或将其添加到有问题的项目中,而不是将其添加到没有问题的项目中。我不喜欢它,因为我不确定什么“进程”(或 MSBuild 任务)能够做到这一点。我认为我需要一个自定义任务。

其他选项:?

想法?

4

2 回答 2

4

HeatDirectory任务具有Transforms可用于转换结果文件的属性。您可以创建一个 xslt 来将您的后缀添加到组件 ID。

此外,Heat 是可扩展的。您可能需要考虑创建自己的收割机,它会为您在组件 ID 上附加一个后缀。

于 2011-02-15T03:21:33.270 回答
2

我看到有人在三年后出现并对此表示赞同。我以为我会回来并声明我仍在使用选项 B,这是一个自定义 MSBuild 任务来解决问题。

在另一篇关于该问题的帖子上发表了评论,并提供了更多详细信息,并认为我会在此处移动/复制我的实现以防万一。

我通过创建一个自定义构建任务来解决它,该任务在 HeatDirectory 任务之后运行,以将后缀附加到 Id 属性。

<AddSuffixToHeatDirectory File="ReportFiles.Generated.wxs" Suffix="_r" />

AddSuffixToHeatDirectory 任务就是这样

public class AddSuffixToHeatDirectory : Task
{
    public override bool Execute()
    {
        bool result = true;

        Log.LogMessage("Opening file '{0}'.", File);
        var document = XElement.Load(File);

        var defaultNamespace = GetDefaultNamespace(document);

        AddSuffixToAttribute(document, defaultNamespace, "Component", "Id");
        AddSuffixToAttribute(document, defaultNamespace, "File", "Id");
        AddSuffixToAttribute(document, defaultNamespace, "ComponentRef", "Id");
        AddSuffixToAttribute(document, defaultNamespace, "Directory", "Id");

        var files = (from x in document.Descendants(defaultNamespace.GetName("File")) select x).ToList();

        Log.LogMessage("Saving file '{0}'.", File);
        document.Save(File);

        return result;
    }

    private void AddSuffixToAttribute(XElement xml, XNamespace defaultNamespace, string elementName, string attributeName)
    {
        var items = (from x in xml.Descendants(defaultNamespace.GetName(elementName)) select x).ToList();
        foreach (var item in items)
        {
            var attribute = item.Attribute(attributeName);
            attribute.Value = string.Format("{0}{1}", attribute.Value, Suffix);
        }
    }

    private XNamespace GetDefaultNamespace(XElement root)
    {
        // I pieced together this query from hanselman's post.
        //  http://www.hanselman.com/blog/GetNamespacesFromAnXMLDocumentWithXPathDocumentAndLINQToXML.aspx
        // 
        // Basically I'm just getting the namespace that doesn't have a localname.
        var result = root.Attributes()
                        .Where(a => a.IsNamespaceDeclaration)
                        .GroupBy(a => a.Name.Namespace == XNamespace.None ? String.Empty : a.Name.LocalName, a => XNamespace.Get(a.Value))
                        .ToDictionary(g => g.Key, g => g.First());
        return result[string.Empty];
    }

    /// <summary>
    /// File to modify.
    /// </summary>
    [Required]
    public string File { get; set; }

    /// <summary>
    /// Suffix to append.
    /// </summary>
    [Required]
    public string Suffix { get; set; }
}

希望有帮助。我今天仍在使用这种方法,而且我还没有完成研究 Transform 或扩展 HeatDirectory 的工作。

于 2014-04-16T18:31:22.350 回答