Example #1
0
        /// <summary>The minify.</summary>
        /// <param name="sourceContentItem">The content item.</param>
        /// <returns>The minified content item, or null if it failed.</returns>
        internal ContentItem Minify(ContentItem sourceContentItem)
        {
            ContentItem minifiedJsContentItem = null;

            this.context.SectionedAction(SectionIdParts.MinifyJsActivity)
            .MakeCachable(sourceContentItem, new { this.ShouldAnalyze, this.ShouldMinify, this.AnalyzeArgs, this.context.Configuration.Global.TreatWarningsAsErrors })
            .RestoreFromCacheAction(cacheSection =>
            {
                minifiedJsContentItem = cacheSection.GetCachedContentItem(CacheFileCategories.MinifiedJsResult, sourceContentItem.RelativeContentPath, null, sourceContentItem.ResourcePivotKeys);
                return(minifiedJsContentItem != null);
            }).Execute(cacheSection =>
            {
                var minifier = new Minifier {
                    FileName = this.SourceFile
                };
                var minifierSettings = this.GetMinifierSettings(minifier);

                var js = minifier.MinifyJavaScript(sourceContentItem.Content, minifierSettings.JSSettings);

                // TODO: RTUIT: Store warnings in cache so that they can be reported even when coming from cache.
                this.HandleMinifierErrors(sourceContentItem, minifier.ErrorList);

                if (js != null)
                {
                    minifiedJsContentItem = ContentItem.FromContent(js, sourceContentItem.RelativeContentPath, null, sourceContentItem.ResourcePivotKeys == null ? null : sourceContentItem.ResourcePivotKeys.ToArray());
                    cacheSection.AddResult(minifiedJsContentItem, CacheFileCategories.MinifiedJsResult);
                }

                return(minifiedJsContentItem != null && !minifier.ErrorList.Any());
            });

            return(minifiedJsContentItem);
        }
        /// <summary>The create sprited images.</summary>
        /// <param name="mapXmlFile">The map xml file.</param>
        /// <param name="imageAssemblyAnalysisLog">The image assembly analysis log.</param>
        /// <param name="imageReferencesToAssemble">The image references to assemble.</param>
        /// <param name="cacheSection">The cache section.</param>
        /// <param name="results">The results.</param>
        /// <param name="threadContext">The thread Context.</param>
        /// <returns>The <see cref="bool"/>.</returns>
        private ImageLog CreateSpritedImages(
            string mapXmlFile,
            ImageAssemblyAnalysisLog imageAssemblyAnalysisLog,
            IEnumerable <InputImage> imageReferencesToAssemble,
            ICacheSection cacheSection,
            BlockingCollection <ContentItem> results,
            IWebGreaseContext threadContext)
        {
            if (!Directory.Exists(this.ImagesOutputDirectory))
            {
                Directory.CreateDirectory(this.ImagesOutputDirectory);
            }

            var imageMap = ImageAssembleGenerator.AssembleImages(
                imageReferencesToAssemble.ToSafeReadOnlyCollection(),
                SpritePackingType.Vertical,
                this.ImagesOutputDirectory,
                string.Empty,
                true,
                threadContext,
                this.ImageAssemblyPadding,
                imageAssemblyAnalysisLog,
                this.ForcedSpritingImageType);

            if (imageMap == null || imageMap.Document == null)
            {
                return(null);
            }

            var destinationDirectory = threadContext.Configuration.DestinationDirectory;

            if (!string.IsNullOrWhiteSpace(this.ImageAssembleScanDestinationFile))
            {
                var scanXml = imageMap.Document.ToString();
                FileHelper.WriteFile(mapXmlFile, scanXml);
                cacheSection.AddResult(ContentItem.FromFile(mapXmlFile), CacheFileCategories.SpriteLogFileXml);
            }

            var imageLog = new ImageLog(imageMap.Document);

            cacheSection.AddResult(ContentItem.FromContent(imageLog.ToJson(true)), CacheFileCategories.SpriteLogFile);

            foreach (var spritedFile in imageLog.InputImages.Select(il => il.OutputFilePath).Distinct())
            {
                var spritedImageContentItem = ContentItem.FromFile(spritedFile, spritedFile.MakeRelativeToDirectory(destinationDirectory));
                results.Add(spritedImageContentItem);
                cacheSection.AddResult(spritedImageContentItem, CacheFileCategories.HashedSpriteImage);
            }

            return(imageLog);
        }
Example #3
0
        /// <summary>Applies the resojurce keys to the content item.</summary>
        /// <param name="inputItem">The input item.</param>
        /// <param name="mergedResoures">The merged resoures.</param>
        /// <returns>The list of merged/applied content items..</returns>
        internal static IEnumerable <ContentItem> ApplyResourceKeys(
            ContentItem inputItem,
            Dictionary <string, IDictionary <string, IDictionary <string, string> > > mergedResoures)
        {
            if (mergedResoures == null || !mergedResoures.Any())
            {
                return(new[] { inputItem });
            }

            var contentItems = new List <ContentItem>();

            try
            {
                var originalContent         = inputItem.Content;
                var usedAndGroupedResources = GetUsedGroupedResources(originalContent, mergedResoures);
                foreach (var usedAndGroupedResource in usedAndGroupedResources)
                {
                    var resourcedContent = originalContent;
                    foreach (var resources in usedAndGroupedResource.Value)
                    {
                        resourcedContent = ResourcesResolver.ExpandResourceKeys(resourcedContent, resources.Value);
                    }

                    contentItems.Add(ContentItem.FromContent(resourcedContent, inputItem, usedAndGroupedResource.Key));
                }
            }
            catch (ResourceOverrideException resourceOverrideException)
            {
                // There was a resource override in folder path that does not
                // allow resource overriding. For this case, we need to
                // show a build error.
                var errorMessage = string.Format(CultureInfo.CurrentUICulture, ResourceStrings.ResourcePivotActivityDuplicateKeysError, resourceOverrideException.TokenKey);
                throw new WorkflowException(errorMessage, resourceOverrideException);
            }
            catch (Exception exception)
            {
                throw new WorkflowException(ResourceStrings.ResourcePivotActivityError, exception);
            }

            return(contentItems);
        }
Example #4
0
        private ContentItem Bundle(ContentItemType targetContentItemType, string outputDirectory, string outputFile, string sourceDirectory)
        {
            var contentBuilder = new StringBuilder();

            using (
                var writer = targetContentItemType == ContentItemType.Path
                                 ? new StreamWriter(outputFile, false, Encoding.UTF8)
                                 : new StringWriter(contentBuilder, CultureInfo.InvariantCulture) as TextWriter)
            {
                this.context.Log.Information("Start bundling output file: {0}".InvariantFormat(outputFile));
                foreach (var file in this.Inputs.GetFiles(sourceDirectory, this.context.Log, true))
                {
                    this.Append(writer, file, sourceDirectory, this.PreprocessingConfig);
                }

                this.context.Log.Information("End bundling output file: {0}".InvariantFormat(outputFile));
            }

            return(targetContentItemType == ContentItemType.Path
                ? ContentItem.FromFile(outputFile, outputFile.MakeRelativeTo(outputDirectory))
                : ContentItem.FromContent(contentBuilder.ToString(), outputFile.MakeRelativeTo(outputDirectory)));
        }
Example #5
0
        /// <summary>Processed the contents of the file and returns the processed content.
        /// returns null if anything went wrong, and reports any errors through the lot delegates.</summary>
        /// <param name="context">The context.</param>
        /// <param name="contentItem">The content of the file.</param>
        /// <param name="preprocessingConfig">The pre processing configuration</param>
        /// <param name="minimalOutput">Is the goal to have the most minimal output (true skips lots of comments)</param>
        /// <returns>The processed contents or null of an error occurred.</returns>
        public ContentItem Process(IWebGreaseContext context, ContentItem contentItem, PreprocessingConfig preprocessingConfig, bool minimalOutput)
        {
            var settingsMinimalOutput = preprocessingConfig != null && preprocessingConfig.Element != null && (bool?)preprocessingConfig.Element.Attribute("minimalOutput") == true;

            context.SectionedAction(SectionIdParts.Preprocessing, SectionIdParts.Process, "WgInclude")
            .MakeCachable(contentItem, new { minimalOutput })
            .Execute(wgincludeCacheImportsSection =>
            {
                var workingFolder = context.GetWorkingSourceDirectory(contentItem.RelativeContentPath);
                var content       = contentItem.Content;
                if (string.IsNullOrWhiteSpace(content))
                {
                    return(true);
                }

                content     = IncludeRegex.Replace(content, match => ReplaceInputs(match, workingFolder, wgincludeCacheImportsSection, minimalOutput || settingsMinimalOutput));
                contentItem = ContentItem.FromContent(content, contentItem);
                return(true);
            });

            return(contentItem);
        }
        internal MinifyCssResult Process(ContentItem contentItem, FileHasherActivity imageHasher = null)
        {
            if (imageHasher != null)
            {
                this.availableSourceImages = this.context.GetAvailableFiles(this.context.Configuration.SourceDirectory, this.ImageDirectories, this.ImageExtensions, FileTypes.Image);
            }

            var cssContent = contentItem.Content;

            var minifiedContentItems     = new BlockingCollection <ContentItem>();
            var hashedImageContentItems  = new BlockingCollection <ContentItem>();
            var spritedImageContentItems = new BlockingCollection <ContentItem>();
            var mergedResources          = ResourcePivotActivity.GetUsedGroupedResources(cssContent, this.MergedResources);

            var dpiValues = this.Dpi;

            if (dpiValues == null || !dpiValues.Any())
            {
                dpiValues = new HashSet <float>(new[] { 1f });
            }

            var pivots = GetMinifyCssPivots(contentItem, dpiValues, mergedResources, this.DpiResources).ToArray();

            var nonIgnoredPivots = pivots.Where(p => !this.context.TemporaryIgnore(p.NewContentResourcePivotKeys)).ToArray();

            var parsedStylesheetNode = CssParser.Parse(this.context, cssContent, false);

            this.context.ParallelForEach(
                item => new[] { SectionIdParts.MinifyCssActivity },
                nonIgnoredPivots,
                (threadContext, pivot, parallelLoopState) =>
            {
                ContentItem minifiedContentItem = null;
                var resourceContentItem         = ContentItem.FromContent(contentItem.Content, pivot.NewContentResourcePivotKeys);
                var result = threadContext
                             .SectionedAction(SectionIdParts.MinifyCssActivity, SectionIdParts.Process)
                             .MakeCachable(resourceContentItem, this.GetVarBySettings(imageHasher, pivot.NewContentResourcePivotKeys, pivot.MergedResource))
                             .RestoreFromCacheAction(cacheSection =>
                {
                    minifiedContentItem = cacheSection.GetCachedContentItem(CacheFileCategories.MinifiedCssResult, contentItem.RelativeContentPath, contentItem.AbsoluteDiskPath, pivot.NewContentResourcePivotKeys);
                    hashedImageContentItems.AddRange(cacheSection.GetCachedContentItems(CacheFileCategories.HashedImage));
                    spritedImageContentItems.AddRange(cacheSection.GetCachedContentItems(CacheFileCategories.HashedSpriteImage));

                    if (minifiedContentItem == null)
                    {
                        context.Log.Error("Css minify cache result is null");
                        return(false);
                    }

                    if (spritedImageContentItems.Any(hi => hi == null))
                    {
                        context.Log.Error("Sprited image cache result is null");
                        return(false);
                    }

                    if (hashedImageContentItems.Any(hi => hi == null))
                    {
                        context.Log.Error("Hashed image cache result is null");
                        return(false);
                    }

                    return(true);
                })
                             .Execute(cacheSection =>
                {
                    try
                    {
                        // Apply all configured visitors, including, validating, optimizing, minifying and spriting.

                        // Applying of resources
                        var stylesheetNode = ApplyResources(parsedStylesheetNode, pivot.MergedResource, threadContext) as StyleSheetNode;

                        // Validation
                        stylesheetNode = this.ApplyValidation(stylesheetNode, threadContext) as StyleSheetNode;

                        // Optimization
                        stylesheetNode = this.ApplyOptimization(stylesheetNode, threadContext) as StyleSheetNode;

                        // Spriting
                        stylesheetNode = this.ApplySpriting(stylesheetNode, pivot.Dpi, spritedImageContentItems, threadContext) as StyleSheetNode;

                        // Output css as string
                        var processedCssContent = threadContext.SectionedAction(SectionIdParts.MinifyCssActivity, SectionIdParts.PrintCss).Execute(() =>
                                                                                                                                                   this.ShouldMinify ? stylesheetNode.MinifyPrint() : stylesheetNode.PrettyPrint());

                        // TODO: Hash the images on the styielsheetnode not on the css result.
                        // Hash images on the result css
                        if (imageHasher != null)
                        {
                            var hashResult      = HashImages(processedCssContent, imageHasher, cacheSection, threadContext, this.availableSourceImages, this.MissingImageUrl);
                            processedCssContent = hashResult.Item1;
                            hashedImageContentItems.AddRange(hashResult.Item2);
                        }

                        minifiedContentItem = ContentItem.FromContent(processedCssContent, this.DestinationFile, null, pivot.NewContentResourcePivotKeys);
                        cacheSection.AddResult(minifiedContentItem, CacheFileCategories.MinifiedCssResult);
                    }
                    catch (Exception ex)
                    {
                        context.Log.Error(ex, ex.ToString());
                        return(false);
                    }

                    return(true);
                });

                Safe.Lock(minifiedContentItems, () => minifiedContentItems.Add(minifiedContentItem));

                if (!result)
                {
                    context.Log.Error("An errror occurred while minifying '{0}' with resources '{1}'".InvariantFormat(contentItem.RelativeContentPath, pivot));
                }

                return(result);
            });

            return(new MinifyCssResult(
                       minifiedContentItems,
                       spritedImageContentItems.DistinctBy(hi => hi.RelativeContentPath).ToArray(),
                       hashedImageContentItems.DistinctBy(hi => hi.RelativeContentPath).ToArray()));
        }
        public ContentItem Process(IWebGreaseContext context, ContentItem contentItem, PreprocessingConfig preprocessingConfig, bool minimalOutput)
        {
            var settingsMinimalOutput = preprocessingConfig != null && preprocessingConfig.Element != null && (bool?)preprocessingConfig.Element.Attribute("minimalOutput") == true;
            var relativeContentPath   = contentItem.RelativeContentPath;

            context.Log.Information("Sass: Processing contents for file {0}".InvariantFormat(relativeContentPath));

            context.SectionedAction(SectionIdParts.Preprocessing, SectionIdParts.Process, "Sass")
            .Execute(
                () =>
            {
                var sassCacheImportsSection = context.Cache.CurrentCacheSection;

                string fileToProcess = null;
                var isTemp           = false;
                try
                {
                    var workingDirectory = Path.IsPathRooted(relativeContentPath)
                                                       ? Path.GetDirectoryName(relativeContentPath)
                                                       : context.GetWorkingSourceDirectory(relativeContentPath);

                    var content = ParseImports(contentItem.Content, workingDirectory, sassCacheImportsSection, minimalOutput || settingsMinimalOutput);

                    var currentContentHash = context.GetValueHash(content);

                    var contentIsUnchangedFromDisk = !string.IsNullOrWhiteSpace(contentItem.AbsoluteDiskPath) &&
                                                     File.Exists(contentItem.AbsoluteDiskPath) &&
                                                     context.GetFileHash(contentItem.AbsoluteDiskPath).Equals(currentContentHash);

                    if (contentIsUnchangedFromDisk)
                    {
                        fileToProcess = contentItem.AbsoluteDiskPath;
                    }
                    else if (!string.IsNullOrWhiteSpace(relativeContentPath))
                    {
                        fileToProcess = Path.Combine(context.Configuration.SourceDirectory ?? string.Empty, relativeContentPath);

                        fileToProcess       = PrependToExtension(fileToProcess, ".imports");
                        relativeContentPath = PrependToExtension(relativeContentPath, ".imports");

                        if (!File.Exists(fileToProcess) || !context.GetFileHash(fileToProcess).Equals(currentContentHash))
                        {
                            File.WriteAllText(fileToProcess, content);
                        }
                    }
                    else
                    {
                        isTemp        = true;
                        fileToProcess = Path.GetTempFileName() + Path.GetExtension(relativeContentPath);
                        File.WriteAllText(fileToProcess, content);
                    }

                    content = ProcessFile(fileToProcess, workingDirectory, relativeContentPath, context);

                    contentItem = content != null ? ContentItem.FromContent(content, contentItem) : null;

                    return(true);
                }
                finally
                {
                    if (isTemp && !string.IsNullOrWhiteSpace(fileToProcess))
                    {
                        try
                        {
                            File.Delete(fileToProcess);
                        }
                        catch (Exception)
                        {
                        }
                    }
                }
            });

            return(contentItem);
        }