aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core/Bind/ResolveDelayedFieldsCommand.cs
blob: 3ded9a87e2efdd625ace0e87ccc9206ee10e0550 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.

namespace WixToolset.Core.Bind
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using WixToolset.Data;
    using WixToolset.Extensibility;
    using WixToolset.Extensibility.Services;

    /// <summary>
    /// Resolves the fields which had variables that needed to be resolved after the file information
    /// was loaded.
    /// </summary>
    public class ResolveDelayedFieldsCommand
    {
        /// <summary>
        /// Resolve delayed fields.
        /// </summary>
        /// <param name="delayedFields">The fields which had resolution delayed.</param>
        /// <param name="variableCache">The file information to use when resolving variables.</param>
        public ResolveDelayedFieldsCommand(IMessaging messaging, IEnumerable<IDelayedField> delayedFields, Dictionary<string, string> variableCache)
        {
            this.Messaging = messaging;
            this.DelayedFields = delayedFields;
            this.VariableCache = variableCache;
        }

        private IMessaging Messaging { get; }

        private IEnumerable<IDelayedField> DelayedFields { get;}

        private IDictionary<string, string> VariableCache { get; }

        public void Execute()
        {
            var deferredFields = new List<IDelayedField>();

            foreach (var delayedField in this.DelayedFields)
            {
                try
                {
                    var propertyRow = delayedField.Row;

                    // process properties first in case they refer to other binder variables
                    if (delayedField.Row.Definition.Type == TupleDefinitionType.Property)
                    {
                        var value = WixVariableResolver.ResolveDelayedVariables(propertyRow.SourceLineNumbers, delayedField.Field.AsString(), this.VariableCache);

                        // update the variable cache with the new value
                        var key = String.Concat("property.", propertyRow.AsString(0));
                        this.VariableCache[key] = value;

                        // update the field data
                        delayedField.Field.Set(value);
                    }
                    else
                    {
                        deferredFields.Add(delayedField);
                    }
                }
                catch (WixException we)
                {
                    this.Messaging.Write(we.Error);
                    continue;
                }
            }

            // add specialization for ProductVersion fields
            string keyProductVersion = "property.ProductVersion";
            if (this.VariableCache.TryGetValue(keyProductVersion, out var versionValue) && Version.TryParse(versionValue, out Version productVersion))
            {
                // Don't add the variable if it already exists (developer defined a property with the same name).
                string fieldKey = String.Concat(keyProductVersion, ".Major");
                if (!this.VariableCache.ContainsKey(fieldKey))
                {
                    this.VariableCache[fieldKey] = productVersion.Major.ToString(CultureInfo.InvariantCulture);
                }

                fieldKey = String.Concat(keyProductVersion, ".Minor");
                if (!this.VariableCache.ContainsKey(fieldKey))
                {
                    this.VariableCache[fieldKey] = productVersion.Minor.ToString(CultureInfo.InvariantCulture);
                }

                fieldKey = String.Concat(keyProductVersion, ".Build");
                if (!this.VariableCache.ContainsKey(fieldKey))
                {
                    this.VariableCache[fieldKey] = productVersion.Build.ToString(CultureInfo.InvariantCulture);
                }

                fieldKey = String.Concat(keyProductVersion, ".Revision");
                if (!this.VariableCache.ContainsKey(fieldKey))
                {
                    this.VariableCache[fieldKey] = productVersion.Revision.ToString(CultureInfo.InvariantCulture);
                }
            }

            // process the remaining fields in case they refer to property binder variables
            foreach (var delayedField in deferredFields)
            {
                try
                {
                    var value = WixVariableResolver.ResolveDelayedVariables(delayedField.Row.SourceLineNumbers, delayedField.Field.AsString(), this.VariableCache);
                    delayedField.Field.Set(value);
                }
                catch (WixException we)
                {
                    this.Messaging.Write(we.Error);
                }
            }
        }
    }
}