/// <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); }
/// <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); }
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))); }
/// <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); }