aboutsummaryrefslogtreecommitdiff
path: root/src/wix/WixToolset.Core.WindowsInstaller/Bind/ProcessUncompressedFilesCommand.cs
blob: 6662f8f769900f3abe7ece3f75371b1375ac5322 (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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// 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.WindowsInstaller.Bind
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using WixToolset.Core.Native.Msi;
    using WixToolset.Data;
    using WixToolset.Data.Symbols;
    using WixToolset.Extensibility.Data;
    using WixToolset.Extensibility.Services;

    /// <summary>
    /// Defines the file transfers necessary to layout the uncompressed files.
    /// </summary>
    internal class ProcessUncompressedFilesCommand
    {
        public ProcessUncompressedFilesCommand(IntermediateSection section, IBackendHelper backendHelper, IPathResolver pathResolver, IEnumerable<IFileFacade> fileFacades, string outputPath, bool compressed, bool longNamesInImage, Func<MediaSymbol, string, string, string> resolveMedia)
        {
            this.Section = section;
            this.BackendHelper = backendHelper;
            this.PathResolver = pathResolver;

            this.DatabasePath = outputPath;
            this.LayoutDirectory = Path.GetDirectoryName(outputPath);
            this.Compressed = compressed;
            this.LongNamesInImage = longNamesInImage;

            this.FileFacades = fileFacades;
            this.ResolveMedia = resolveMedia;
        }

        private IntermediateSection Section { get; }

        private IBackendHelper BackendHelper { get; }

        private IPathResolver PathResolver { get; }

        private string DatabasePath { get; }

        private string LayoutDirectory { get; }

        private bool Compressed { get; }

        private bool LongNamesInImage { get; }

        private IEnumerable<IFileFacade> FileFacades { get; }

        private Func<MediaSymbol, string, string, string> ResolveMedia { get; }

        public IEnumerable<IFileTransfer> FileTransfers { get; private set; }

        public IEnumerable<ITrackedFile> TrackedFiles { get; private set; }

        public void Execute()
        {
            var fileTransfers = new List<IFileTransfer>();

            var trackedFiles = new List<ITrackedFile>();

            var directories = new Dictionary<string, IResolvedDirectory>();

            var mediaRows = this.Section.Symbols.OfType<MediaSymbol>().ToDictionary(t => t.DiskId);

            using (var db = new Database(this.DatabasePath, OpenDatabase.ReadOnly))
            {
                using (var directoryView = db.OpenExecuteView("SELECT `Directory`, `Directory_Parent`, `DefaultDir` FROM `Directory`"))
                {
                    foreach (var directoryRecord in directoryView.Records)
                    {
                        var sourceName = this.BackendHelper.GetMsiFileName(directoryRecord.GetString(3), true, this.LongNamesInImage);

                        var resolvedDirectory = this.BackendHelper.CreateResolvedDirectory(directoryRecord.GetString(2), sourceName);

                        directories.Add(directoryRecord.GetString(1), resolvedDirectory);
                    }
                }

                using (var fileView = db.OpenView("SELECT `Directory_`, `FileName` FROM `Component`, `File` WHERE `Component`.`Component`=`File`.`Component_` AND `File`.`File`=?"))
                {
                    using (var fileQueryRecord = new Record(1))
                    {
                        // for each file in the array of uncompressed files
                        foreach (var facade in this.FileFacades)
                        {
                            var mediaSymbol = mediaRows[facade.DiskId];
                            string relativeFileLayoutPath = null;
                            var mediaLayoutFolder = mediaSymbol.Layout;

                            var mediaLayoutDirectory = this.ResolveMedia(mediaSymbol, mediaLayoutFolder, this.LayoutDirectory);

                            // setup up the query record and find the appropriate file in the
                            // previously executed file view
                            fileQueryRecord[1] = facade.Id;
                            fileView.Execute(fileQueryRecord);

                            using (var fileRecord = fileView.Fetch())
                            {
                                if (null == fileRecord)
                                {
                                    throw new WixException(ErrorMessages.FileIdentifierNotFound(facade.SourceLineNumber, facade.Id));
                                }

                                relativeFileLayoutPath = this.PathResolver.GetFileSourcePath(directories, fileRecord[1], fileRecord[2], this.Compressed, this.LongNamesInImage);
                            }

                            // finally put together the base media layout path and the relative file layout path
                            var fileLayoutPath = Path.Combine(mediaLayoutDirectory, relativeFileLayoutPath);

                            var transfer = this.BackendHelper.CreateFileTransfer(facade.SourcePath, fileLayoutPath, false, facade.SourceLineNumber);
                            fileTransfers.Add(transfer);

                            // Track the location where the cabinet will be placed. If the transfer is
                            // redundant then then the file should not be cleaned. This is important
                            // because if the source and destination of the transfer is the same, we
                            // don't want to clean the file because we'd be deleting the original
                            // (and that would be bad).
                            var tracked = this.BackendHelper.TrackFile(transfer.Destination, TrackedFileType.BuiltOutput, facade.SourceLineNumber);
                            tracked.Clean = !transfer.Redundant;

                            trackedFiles.Add(tracked);
                        }
                    }
                }
            }

            this.FileTransfers = fileTransfers;
            this.TrackedFiles = trackedFiles;
        }
    }
}