/// <summary>
        /// Creates a work item to create a cabinet.
        /// </summary>
        /// <param name="output">Output for the current database.</param>
        /// <param name="cabinetDir">Directory to create cabinet in.</param>
        /// <param name="mediaRow">MediaRow containing information about the cabinet.</param>
        /// <param name="fileFacades">Collection of files in this cabinet.</param>
        /// <param name="fileTransfers">Array of files to be transfered.</param>
        /// <returns>created CabinetWorkItem object</returns>
        private CabinetWorkItem CreateCabinetWorkItem(Output output, string cabinetDir, MediaTuple mediaRow, CompressionLevel compressionLevel, IEnumerable <FileFacade> fileFacades, List <FileTransfer> fileTransfers)
        {
            CabinetWorkItem cabinetWorkItem  = null;
            string          tempCabinetFileX = Path.Combine(this.TempFilesLocation, mediaRow.Cabinet);

            // check for an empty cabinet
            if (!fileFacades.Any())
            {
                string cabinetName = mediaRow.Cabinet;

                // remove the leading '#' from the embedded cabinet name to make the warning easier to understand
                if (cabinetName.StartsWith("#", StringComparison.Ordinal))
                {
                    cabinetName = cabinetName.Substring(1);
                }

                // If building a patch, remind them to run -p for torch.
                if (OutputType.Patch == output.Type)
                {
                    this.Messaging.Write(WarningMessages.EmptyCabinet(mediaRow.SourceLineNumbers, cabinetName, true));
                }
                else
                {
                    this.Messaging.Write(WarningMessages.EmptyCabinet(mediaRow.SourceLineNumbers, cabinetName));
                }
            }

            var cabinetResolver = new CabinetResolver(this.CabCachePath, this.BackendExtensions);

            ResolvedCabinet resolvedCabinet = cabinetResolver.ResolveCabinet(tempCabinetFileX, fileFacades);

            // create a cabinet work item if it's not being skipped
            if (CabinetBuildOption.BuildAndCopy == resolvedCabinet.BuildOption || CabinetBuildOption.BuildAndMove == resolvedCabinet.BuildOption)
            {
                int maxThreshold = 0; // default to the threshold for best smartcabbing (makes smallest cabinet).

                cabinetWorkItem = new CabinetWorkItem(fileFacades, resolvedCabinet.Path, maxThreshold, compressionLevel /*, this.FileManager*/);
            }
            else // reuse the cabinet from the cabinet cache.
            {
                this.Messaging.Write(VerboseMessages.ReusingCabCache(mediaRow.SourceLineNumbers, mediaRow.Cabinet, resolvedCabinet.Path));

                try
                {
                    // Ensure the cached cabinet timestamp is current to prevent perpetual incremental builds. The
                    // problematic scenario goes like this. Imagine two cabinets in the cache. Update a file that
                    // goes into one of the cabinets. One cabinet will get rebuilt, the other will be copied from
                    // the cache. Now the file (an input) has a newer timestamp than the reused cabient (an output)
                    // causing the project to look like it perpetually needs a rebuild until all of the reused
                    // cabinets get newer timestamps.
                    File.SetLastWriteTime(resolvedCabinet.Path, DateTime.Now);
                }
                catch (Exception e)
                {
                    this.Messaging.Write(WarningMessages.CannotUpdateCabCache(mediaRow.SourceLineNumbers, resolvedCabinet.Path, e.Message));
                }
            }

            if (mediaRow.Cabinet.StartsWith("#", StringComparison.Ordinal))
            {
                Table streamsTable = output.EnsureTable(this.TableDefinitions["_Streams"]);

                Row streamRow = streamsTable.CreateRow(mediaRow.SourceLineNumbers);
                streamRow[0] = mediaRow.Cabinet.Substring(1);
                streamRow[1] = resolvedCabinet.Path;
            }
            else
            {
                string destinationPath = Path.Combine(cabinetDir, mediaRow.Cabinet);
                if (FileTransfer.TryCreate(resolvedCabinet.Path, destinationPath, CabinetBuildOption.BuildAndMove == resolvedCabinet.BuildOption, "Cabinet", mediaRow.SourceLineNumbers, out var transfer))
                {
                    transfer.Built = true;
                    fileTransfers.Add(transfer);
                }
            }

            return(cabinetWorkItem);
        }
Exemple #2
0
        /// <summary>
        /// Creates a work item to create a cabinet.
        /// </summary>
        /// <param name="output">Output for the current database.</param>
        /// <param name="cabinetDir">Directory to create cabinet in.</param>
        /// <param name="mediaSymbol">Media symbol containing information about the cabinet.</param>
        /// <param name="fileFacades">Collection of files in this cabinet.</param>
        /// <returns>created CabinetWorkItem object</returns>
        private CabinetWorkItem CreateCabinetWorkItem(WindowsInstallerData output, string cabinetDir, MediaSymbol mediaSymbol, CompressionLevel compressionLevel, IEnumerable <FileFacade> fileFacades)
        {
            CabinetWorkItem cabinetWorkItem  = null;
            var             tempCabinetFileX = Path.Combine(this.IntermediateFolder, mediaSymbol.Cabinet);

            // check for an empty cabinet
            if (!fileFacades.Any())
            {
                // Remove the leading '#' from the embedded cabinet name to make the warning easier to understand
                var cabinetName = mediaSymbol.Cabinet.TrimStart('#');

                // If building a patch, remind them to run -p for torch.
                if (OutputType.Patch == output.Type)
                {
                    this.Messaging.Write(WarningMessages.EmptyCabinet(mediaSymbol.SourceLineNumbers, cabinetName, true));
                }
                else
                {
                    this.Messaging.Write(WarningMessages.EmptyCabinet(mediaSymbol.SourceLineNumbers, cabinetName));
                }
            }

            var cabinetResolver = new CabinetResolver(this.ServiceProvider, this.CabCachePath, this.BackendExtensions);

            var resolvedCabinet = cabinetResolver.ResolveCabinet(tempCabinetFileX, fileFacades);

            // create a cabinet work item if it's not being skipped
            if (CabinetBuildOption.BuildAndCopy == resolvedCabinet.BuildOption || CabinetBuildOption.BuildAndMove == resolvedCabinet.BuildOption)
            {
                // Default to the threshold for best smartcabbing (makes smallest cabinet).
                cabinetWorkItem = new CabinetWorkItem(fileFacades, resolvedCabinet.Path, maxThreshold: 0, compressionLevel, this.ModularizationSuffix /*, this.FileManager*/);
            }
            else // reuse the cabinet from the cabinet cache.
            {
                this.Messaging.Write(VerboseMessages.ReusingCabCache(mediaSymbol.SourceLineNumbers, mediaSymbol.Cabinet, resolvedCabinet.Path));

                try
                {
                    // Ensure the cached cabinet timestamp is current to prevent perpetual incremental builds. The
                    // problematic scenario goes like this. Imagine two cabinets in the cache. Update a file that
                    // goes into one of the cabinets. One cabinet will get rebuilt, the other will be copied from
                    // the cache. Now the file (an input) has a newer timestamp than the reused cabient (an output)
                    // causing the project to look like it perpetually needs a rebuild until all of the reused
                    // cabinets get newer timestamps.
                    File.SetLastWriteTime(resolvedCabinet.Path, DateTime.Now);
                }
                catch (Exception e)
                {
                    this.Messaging.Write(WarningMessages.CannotUpdateCabCache(mediaSymbol.SourceLineNumbers, resolvedCabinet.Path, e.Message));
                }
            }

            var trackResolvedCabinet = this.BackendHelper.TrackFile(resolvedCabinet.Path, TrackedFileType.Intermediate, mediaSymbol.SourceLineNumbers);

            this.trackedFiles.Add(trackResolvedCabinet);

            if (mediaSymbol.Cabinet.StartsWith("#", StringComparison.Ordinal))
            {
                var streamsTable = output.EnsureTable(this.TableDefinitions["_Streams"]);

                var streamRow = streamsTable.CreateRow(mediaSymbol.SourceLineNumbers);
                streamRow[0] = mediaSymbol.Cabinet.Substring(1);
                streamRow[1] = resolvedCabinet.Path;
            }
            else
            {
                var trackDestination = this.BackendHelper.TrackFile(Path.Combine(cabinetDir, mediaSymbol.Cabinet), TrackedFileType.Final, mediaSymbol.SourceLineNumbers);
                this.trackedFiles.Add(trackDestination);

                var transfer = this.BackendHelper.CreateFileTransfer(resolvedCabinet.Path, trackDestination.Path, resolvedCabinet.BuildOption == CabinetBuildOption.BuildAndMove, mediaSymbol.SourceLineNumbers);
                this.fileTransfers.Add(transfer);
            }

            return(cabinetWorkItem);
        }