Example #1
0
        /// <summary>When overridden in a derived class, executes the task.</summary>
        /// <param name="contentItem">The result File.</param>
        internal void Execute(ContentItem contentItem = null)
        {
            var destinationDirectory = this.context.Configuration.DestinationDirectory;

            if ((contentItem == null) && string.IsNullOrWhiteSpace(this.SourceFile))
            {
                throw new ArgumentException("MinifyJSActivity - The source file cannot be null or whitespace.");
            }

            if (string.IsNullOrWhiteSpace(this.DestinationFile))
            {
                throw new ArgumentException("MinifyJSActivity - The destination file cannot be null or whitespace.");
            }

            if (contentItem == null)
            {
                contentItem = ContentItem.FromFile(
                    this.SourceFile, Path.IsPathRooted(this.SourceFile) ? this.SourceFile.MakeRelativeToDirectory(destinationDirectory) : this.SourceFile);
            }

            var minifiedContentItem = this.Minify(contentItem);

            if (minifiedContentItem != null)
            {
                minifiedContentItem.WriteTo(this.DestinationFile);
            }
        }
Example #2
0
        /// <summary>The execute.</summary>
        /// <returns>The list of processed files.</returns>
        internal IEnumerable <ContentItem> Execute()
        {
            var preprocessedFiles = new List <ContentItem>();
            var sourceDirectory   = this.context.Configuration.SourceDirectory;

            foreach (var file in this.Inputs.GetFiles(sourceDirectory))
            {
                var fi = new FileInfo(file);
                if (!fi.Exists)
                {
                    throw new FileNotFoundException("Could not find the file {0} to preprocess on.");
                }

                if (!Directory.Exists(this.OutputFolder))
                {
                    Directory.CreateDirectory(this.OutputFolder);
                }

                var contentItem = ContentItem.FromFile(file, file.MakeRelativeToDirectory(sourceDirectory));

                contentItem = this.context.Preprocessing.Process(contentItem, this.PreprocessingConfig, this.MinimalOutput);
                if (contentItem == null)
                {
                    throw new WorkflowException("An error occurred while processing the file: " + file);
                }

                preprocessedFiles.Add(contentItem);
            }

            return(preprocessedFiles);
        }
        /// <summary>Copies and hashes the Directory.</summary>
        /// <param name="sourceDirectory">Path to source directory.</param>
        /// <param name="destinationDirectory">Path to destination directory.</param>
        /// <param name="filters">Array of file filters to apply.</param>
        /// <param name="rootSourceDirectory">The root source directory</param>
        /// <returns>The result files after the hash.</returns>
        private IEnumerable <ContentItem> Hash(string sourceDirectory, string destinationDirectory, IEnumerable <string> filters, string rootSourceDirectory = null)
        {
            var results = new List <ContentItem>();

            // Create the directory if does not exist.
            Directory.CreateDirectory(destinationDirectory);

            var sourceDirectoryInfo = new DirectoryInfo(sourceDirectory);

            rootSourceDirectory = rootSourceDirectory ?? sourceDirectoryInfo.FullName;

            // Need to do this for only the file type(s) desired
            results.AddRange(
                filters.SelectMany(filter =>
                                   sourceDirectoryInfo
                                   .EnumerateFiles(filter, SearchOption.TopDirectoryOnly)
                                   .Select(sourceFileInfo =>
                                           this.Hash(ContentItem.FromFile(sourceFileInfo.FullName, sourceFileInfo.FullName.MakeRelativeToDirectory(rootSourceDirectory))))));

            // recurse through subdirs, either keeping the source dir structure in the destination or flattening it
            foreach (var subDirectoryInfo in sourceDirectoryInfo.GetDirectories())
            {
                var subDestinationDirectory =
                    this.ShouldPreserveSourceDirectoryStructure
                    ? Path.Combine(destinationDirectory, subDirectoryInfo.Name)
                    : destinationDirectory;

                results.AddRange(
                    this.Hash(subDirectoryInfo.FullName, subDestinationDirectory, filters, rootSourceDirectory));
            }

            return(results);
        }
        /// <summary>Hash the images.</summary>
        /// <param name="cssContent">The css content.</param>
        /// <param name="imageHasher">The image Hasher.</param>
        /// <param name="cacheSection">The cache section.</param>
        /// <param name="threadContext">The context.</param>
        /// <param name="sourceImages">The source Images.</param>
        /// <param name="missingImage">The missing Image.</param>
        /// <returns>The css with hashed images.</returns>
        private static Tuple <string, IEnumerable <ContentItem> > HashImages(string cssContent, FileHasherActivity imageHasher, ICacheSection cacheSection, IWebGreaseContext threadContext, IDictionary <string, string> sourceImages, string missingImage)
        {
            return(threadContext.SectionedAction(SectionIdParts.MinifyCssActivity, SectionIdParts.ImageHash).Execute(() =>
            {
                var contentImagesToHash = new HashSet <string>();
                var hashedContentItems = new List <ContentItem>();
                var hashedImages = new Dictionary <string, string>();
                cssContent = UrlHashRegexPattern.Replace(
                    cssContent,
                    match =>
                {
                    var urlToHash = match.Groups["url"].Value;
                    var extraInfo = match.Groups["extra"].Value;

                    if (ResourcesResolver.LocalizationResourceKeyRegex.IsMatch(urlToHash))
                    {
                        return match.Value;
                    }

                    var normalizedHashUrl = urlToHash.NormalizeUrl();

                    var imageContentFile = sourceImages.TryGetValue(normalizedHashUrl);
                    if (imageContentFile == null && !string.IsNullOrWhiteSpace(missingImage))
                    {
                        imageContentFile = sourceImages.TryGetValue(missingImage);
                    }

                    if (imageContentFile == null)
                    {
                        throw new BuildWorkflowException("Could not find a matching source image for url: {0}".InvariantFormat(urlToHash));
                    }

                    if (contentImagesToHash.Add(normalizedHashUrl))
                    {
                        // Add the image as end result
                        var imageContentItem = ContentItem.FromFile(imageContentFile, normalizedHashUrl);
                        imageContentItem = imageHasher.Hash(imageContentItem);
                        cacheSection.AddSourceDependency(imageContentFile);
                        hashedContentItems.Add(imageContentItem);

                        imageContentFile =
                            Path.Combine(
                                imageHasher.BasePrefixToAddToOutputPath ?? Path.AltDirectorySeparatorChar.ToString(CultureInfo.InvariantCulture),
                                imageContentItem.RelativeHashedContentPath.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar));

                        hashedImages.Add(normalizedHashUrl, imageContentFile);
                    }
                    else
                    {
                        imageContentFile = hashedImages[normalizedHashUrl];
                    }

                    return "url(" + imageContentFile + extraInfo + ")";
                });

                return Tuple.Create(cssContent, (IEnumerable <ContentItem>)hashedContentItems);
            }));
        }
Example #5
0
        /// <summary>Execute a single config file.</summary>
        /// <param name="sessionContext">The session context.</param>
        /// <param name="configFile">The config file.</param>
        /// <param name="activity">The activity</param>
        /// <param name="fileType">The file types</param>
        /// <param name="measure">If it should measure.</param>
        /// <param name="fullPathToConfigFiles">The full Path To Config Files.</param>
        /// <returns>The success.</returns>
        private static Tuple <bool, int> ExecuteConfigFile(IWebGreaseContext sessionContext, string configFile, ActivityName activity, FileTypes fileType, bool measure, string fullPathToConfigFiles)
        {
            var configFileStart = DateTimeOffset.Now;

            var configFileInfo = new FileInfo(configFile);

            // Creates the context specific to the configuration file
            var fileContext = new WebGreaseContext(sessionContext, configFileInfo);

            var configFileSuccess = true;
            var fileSets          = GetFileSets(fileContext.Configuration, fileType).ToArray();

            if (fileSets.Length > 0 || (fileType.HasFlag(FileTypes.Image) && fileContext.Configuration.ImageDirectoriesToHash.Any()))
            {
                var configFileContentItem = ContentItem.FromFile(configFileInfo.FullName);
                configFileSuccess = sessionContext
                                    .SectionedActionGroup(fileType.ToString(), SectionIdParts.WebGreaseBuildTask, SectionIdParts.ConfigurationFile)
                                    .MakeCachable(configFileContentItem, new { activity, fileContext.Configuration }, activity == ActivityName.Bundle) // Cached action can only be skipped when it is the bundle activity, otherwise don't.
                                    .Execute(configFileCacheSection =>
                {
                    fileContext.Configuration.AllLoadedConfigurationFiles.ForEach(configFileCacheSection.AddSourceDependency);

                    var success = true;
                    fileContext.Log.Information("Activity Start: [{0}] for [{1}] on configuration file \"{2}\"".InvariantFormat(activity, fileType, configFile), MessageImportance.High);
                    switch (activity)
                    {
                    case ActivityName.Bundle:
                        // execute the bundle pipeline
                        var bundleActivity = new BundleActivity(fileContext);
                        success           &= bundleActivity.Execute(fileSets);
                        break;

                    case ActivityName.Everything:
                        // execute the full pipeline
                        var everythingActivity = new EverythingActivity(fileContext);
                        success &= everythingActivity.Execute(fileSets, fileType);
                        break;
                    }

                    if (success && measure)
                    {
                        var configReportFile = Path.Combine(sessionContext.Configuration.ReportPath, (configFileInfo.Directory != null ? configFileInfo.Directory.Name + "." : string.Empty) + activity.ToString() + "." + fileType + "." + configFileInfo.Name);
                        fileContext.Measure.WriteResults(configReportFile, configFileInfo.FullName, configFileStart);
                    }

                    fileContext.Log.Information("Activity End: [{0}] for [{1}] on configuration file \"{2}\"".InvariantFormat(activity, fileType, configFile), MessageImportance.High);
                    return(success);
                });
            }

            return(Tuple.Create(configFileSuccess, fileSets.Length));
        }
        /// <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);
        }
        internal void Execute(ContentItem contentItem = null, FileHasherActivity imageHasher = null)
        {
            if (contentItem == null)
            {
                if (string.IsNullOrWhiteSpace(this.SourceFile))
                {
                    throw new ArgumentException("MinifyCssActivity - The source file cannot be null or whitespace.");
                }

                if (!File.Exists(this.SourceFile))
                {
                    throw new FileNotFoundException("MinifyCssActivity - The source file cannot be found.", this.SourceFile);
                }
            }

            if (string.IsNullOrWhiteSpace(this.DestinationFile))
            {
                throw new ArgumentException("MinifyCssActivity - The destination file cannot be null or whitespace.");
            }

            if (contentItem == null)
            {
                contentItem = ContentItem.FromFile(this.SourceFile, Path.IsPathRooted(this.SourceFile) ? this.SourceFile.MakeRelativeToDirectory(this.context.Configuration.SourceDirectory) : this.SourceFile);
            }

            var minifyresult = this.Process(contentItem, imageHasher);

            var css = minifyresult.Css.FirstOrDefault();

            if (css != null)
            {
                css.WriteTo(this.DestinationFile);
            }

            if (minifyresult.SpritedImages != null && minifyresult.SpritedImages.Any())
            {
                foreach (var spritedImage in minifyresult.SpritedImages)
                {
                    spritedImage.WriteToContentPath(this.context.Configuration.DestinationDirectory);
                }
            }

            if (minifyresult.HashedImages != null && minifyresult.HashedImages.Any())
            {
                foreach (var hashedImage in minifyresult.HashedImages)
                {
                    hashedImage.WriteToRelativeHashedPath(this.context.Configuration.DestinationDirectory);
                }
            }
        }
Example #8
0
        /// <summary>The append file.</summary>
        /// <param name="writer">The writer.</param>
        /// <param name="filePath">The file path</param>
        /// <param name="sourceDirectory">The source directory</param>
        /// <param name="preprocessingConfig">The configuration for the preprocessing.</param>
        private void Append(TextWriter writer, string filePath, string sourceDirectory, PreprocessingConfig preprocessingConfig = null)
        {
            // Add a newline to make sure what comes next doesn't get mistakenly attached to the end of
            // a single-line comment or anything. add two so we get an easy-to-read separation between files
            // for debugging purposes.
            writer.WriteLine();
            writer.WriteLine();

            // if we want to separate files with semicolons and the previous file didn't have one, add one now
            if (this.AddSemicolons && !this.endedInSemicolon)
            {
                writer.Write(';');
            }

            string relativeFilePath =
                Path.IsPathRooted(filePath) && !sourceDirectory.IsNullOrWhitespace()
                ? filePath.MakeRelativeTo(sourceDirectory)
                : filePath;

            if (!this.MinimalOutput)
            {
                writer.WriteLine("/* {0} {1} */".InvariantFormat(relativeFilePath, filePath != relativeFilePath ? "(" + filePath + ")" : string.Empty));
                writer.WriteLine();
            }

            var contentItem = ContentItem.FromFile(filePath, relativeFilePath);

            // Executing any applicable preprocessors from the list of configured preprocessors on the file content
            if (preprocessingConfig != null && preprocessingConfig.Enabled)
            {
                contentItem = this.context.Preprocessing.Process(contentItem, preprocessingConfig, this.MinimalOutput);
                if (contentItem == null)
                {
                    throw new WorkflowException("Could not assembly the file {0} because one of the preprocessors threw an error.".InvariantFormat(filePath));
                }
            }

            // TODO:RTUIT: Use a writer/reader instead of getting the content and check differently for the endoign semicolon. Also fix not passing encoding. ONly when not using any preprocessors.
            var content = contentItem.Content;

            writer.Write(content);
            writer.WriteLine();

            // don't even bother checking for a semicolon if we aren't interested in adding one
            if (this.AddSemicolons)
            {
                this.endedInSemicolon = EndsWithSemicolon.IsMatch(content);
            }
        }
Example #9
0
        public void TestWgInclude1()
        {
            var includeFile      = Path.Combine(TestDeploymentPaths.TestDirectory, @"WebGrease.Tests\IncludeTest\Test1\test1.js");
            var ie               = new IncludePreprocessingEngine();
            var webGreaseContext = new WebGreaseContext(new WebGreaseConfiguration()
            {
                DestinationDirectory = TestDeploymentPaths.TestDirectory
            });
            var result = ie.Process(webGreaseContext, ContentItem.FromFile(includeFile, includeFile.MakeRelativeToDirectory(TestDeploymentPaths.TestDirectory)), new PreprocessingConfig(), false).Content;

            Assert.IsTrue(result.Contains("included1();"));
            Assert.IsTrue(result.Contains("included2();"));
            Assert.IsTrue(result.Contains("included3();"));
            Assert.IsTrue(result.Contains("included4();"));
            Assert.IsFalse(result.Contains("included5();"));
        }
Example #10
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 #11
0
        private static string ProcessSass(string content, string filename, LogExtendedError logExtendedError = null)
        {
            var sassPreprocessingEngine = new SassPreprocessingEngine();
            var webGreaseContext        = new WebGreaseContext(new WebGreaseConfiguration(), logInformation: null, logExtendedWarning: null, logError: null, logExtendedError: logExtendedError);

            File.WriteAllText(filename, content);
            var processSassResult = sassPreprocessingEngine.Process(webGreaseContext, ContentItem.FromFile(filename), null, false);

            return(processSassResult != null
                ? processSassResult.Content
                : null);
        }