public bool Exists(string fingerprint, ICombinatorSettings settings) { var exists = false; if (settings.EnableResourceSharing && CallOnDefaultShell(cacheFileService => exists = cacheFileService.Exists(fingerprint, new CombinatorSettings(settings) { EnableResourceSharing = false }))) { // Because resources were excluded from resource sharing in this set this set could be stored locally, not shared. // Thus we fall back to local storage. if (exists) { return(true); } } var cacheKey = MakeCacheKey("Exists." + fingerprint); return(_cacheService.Get(cacheKey, () => { _combinatorEventMonitor.MonitorCacheEmptied(cacheKey); _combinatorEventMonitor.MonitorBundleChanged(cacheKey, fingerprint); // Maybe also check if the file exists? return _fileRepository.Count(file => file.Fingerprint == ConvertFingerprintToStorageFormat(fingerprint)) != 0; })); }
public IList <ResourceRequiredContext> CombineScripts( IList <ResourceRequiredContext> resources, ICombinatorSettings settings) { var hashCode = resources.GetResourceListHashCode(); var combinedScripts = new List <ResourceRequiredContext>(2); Func <ResourceLocation, List <ResourceRequiredContext> > filterScripts = (location) => { return((from r in resources where r.Settings.Location == location select r).ToList()); }; Action <ResourceLocation> combineScriptsAtLocation = (location) => { var locationHashCode = hashCode + (int)location; var lockName = MakeLockName(locationHashCode); var combinedResourcesAtLocation = _lockingCacheManager.Get(lockName, ctx => { if (!_cacheFileService.Exists(locationHashCode)) { var scripts = filterScripts(location); if (scripts.Count == 0) { return(new List <ResourceRequiredContext>()); } Combine(scripts, locationHashCode, ResourceType.JavaScript, settings); } _combinatorEventMonitor.MonitorCacheEmptied(ctx); var combinedResources = ProcessCombinedResources(_cacheFileService.GetCombinedResources(locationHashCode)); combinedResources.SetLocation(location); return(combinedResources); }, () => filterScripts(location)); combinedScripts = combinedScripts.Union(combinedResourcesAtLocation).ToList(); }; // Scripts at different locations are processed separately // Currently this will add two files at the foot if scripts with unspecified location are also included combineScriptsAtLocation(ResourceLocation.Head); combineScriptsAtLocation(ResourceLocation.Foot); combineScriptsAtLocation(ResourceLocation.Unspecified); return(combinedScripts); }
public IList <ResourceRequiredContext> CombineScripts( IList <ResourceRequiredContext> resources, ICombinatorSettings settings) { var combinedScripts = new List <ResourceRequiredContext>(2); Action <ResourceLocation> combineScriptsAtLocation = (location) => { Predicate <RequireSettings> locationFilter; // Making sure that scripts with unspecified location are treated equally to foot scripts. Theoretically // this isn't right (it can change what "unspecified" results in) but it deals with the lazyness of developers. if (location == ResourceLocation.Head) { locationFilter = s => s.Location == ResourceLocation.Head; } else { locationFilter = s => s.Location == ResourceLocation.Foot || s.Location == ResourceLocation.Unspecified; } var scripts = (from r in resources where locationFilter(r.Settings) select r).ToList(); var fingerprint = scripts.GetResourceListFingerprint(settings); IList <ResourceRequiredContext> combinedResourcesAtLocation; if (!scripts.Any()) { combinedResourcesAtLocation = new List <ResourceRequiredContext>(); } else { if (!_cacheFileService.Exists(fingerprint, settings)) { Combine(scripts, fingerprint, ResourceType.JavaScript, settings); } combinedResourcesAtLocation = ProcessCombinedResources(_cacheFileService.GetCombinedResources(fingerprint, settings), settings.ResourceBaseUri); combinedResourcesAtLocation.SetLocation(location); } combinedScripts = combinedScripts.Union(combinedResourcesAtLocation).ToList(); }; combineScriptsAtLocation(ResourceLocation.Head); combineScriptsAtLocation(ResourceLocation.Foot); return(combinedScripts); }
public IList <ResourceRequiredContext> CombineStylesheets( IList <ResourceRequiredContext> resources, ICombinatorSettings settings) { var fingerprint = resources.GetResourceListFingerprint(settings); if (!_cacheFileService.Exists(fingerprint, settings)) { Combine(resources, fingerprint, ResourceType.Style, settings); } return(ProcessCombinedResources(_cacheFileService.GetCombinedResources(fingerprint, settings), settings.ResourceBaseUri)); }
public IList<ResourceRequiredContext> CombineScripts( IList<ResourceRequiredContext> resources, ICombinatorSettings settings) { var hashCode = resources.GetResourceListHashCode(); var combinedScripts = new List<ResourceRequiredContext>(2); Func<ResourceLocation, List<ResourceRequiredContext>> filterScripts = (location) => { return (from r in resources where r.Settings.Location == location select r).ToList(); }; Action<ResourceLocation> combineScriptsAtLocation = (location) => { var locationHashCode = hashCode + (int)location; var lockName = MakeLockName(locationHashCode); var combinedResourcesAtLocation = _lockingCacheManager.Get(lockName, ctx => { if (!_cacheFileService.Exists(locationHashCode)) { var scripts = filterScripts(location); if (scripts.Count == 0) return new List<ResourceRequiredContext>(); Combine(scripts, locationHashCode, ResourceType.JavaScript, settings); } _combinatorEventMonitor.MonitorCacheEmptied(ctx); var combinedResources = ProcessCombinedResources(_cacheFileService.GetCombinedResources(locationHashCode)); combinedResources.SetLocation(location); return combinedResources; }, () => filterScripts(location)); combinedScripts = combinedScripts.Union(combinedResourcesAtLocation).ToList(); }; // Scripts at different locations are processed separately // Currently this will add two files at the foot if scripts with unspecified location are also included combineScriptsAtLocation(ResourceLocation.Head); combineScriptsAtLocation(ResourceLocation.Foot); combineScriptsAtLocation(ResourceLocation.Unspecified); return combinedScripts; }
public IList<ResourceRequiredContext> CombineScripts( IList<ResourceRequiredContext> resources, ICombinatorSettings settings) { var combinedScripts = new List<ResourceRequiredContext>(2); Action<ResourceLocation> combineScriptsAtLocation = (location) => { Predicate<RequireSettings> locationFilter; // Making sure that scripts with unspecified location are treated equally to foot scripts. Theoretically // this isn't right (it can change what "unspecified" results in) but it deals with the lazyness of developers. if (location == ResourceLocation.Head) { locationFilter = s => s.Location == ResourceLocation.Head; } else { locationFilter = s => s.Location == ResourceLocation.Foot || s.Location == ResourceLocation.Unspecified; } var scripts = (from r in resources where locationFilter(r.Settings) select r).ToList(); var fingerprint = scripts.GetResourceListFingerprint(settings); IList<ResourceRequiredContext> combinedResourcesAtLocation; if (!scripts.Any()) combinedResourcesAtLocation = new List<ResourceRequiredContext>(); else { if (!_cacheFileService.Exists(fingerprint, settings)) { Combine(scripts, fingerprint, ResourceType.JavaScript, settings); } combinedResourcesAtLocation = ProcessCombinedResources(_cacheFileService.GetCombinedResources(fingerprint, settings), settings.ResourceBaseUri); combinedResourcesAtLocation.SetLocation(location); } combinedScripts = combinedScripts.Union(combinedResourcesAtLocation).ToList(); }; combineScriptsAtLocation(ResourceLocation.Head); combineScriptsAtLocation(ResourceLocation.Foot); return combinedScripts; }
public CombinatorSettings(ICombinatorSettings previous) { CombinationExcludeFilter = previous.CombinationExcludeFilter; CombineCdnResources = previous.CombineCdnResources; RemoteStorageUrlPattern = previous.RemoteStorageUrlPattern; ResourceBaseUri = previous.ResourceBaseUri; MinifyResources = previous.MinifyResources; MinificationExcludeFilter = previous.MinificationExcludeFilter; EmbedCssImages = previous.EmbedCssImages; EmbeddedImagesMaxSizeKB = previous.EmbeddedImagesMaxSizeKB; EmbedCssImagesStylesheetExcludeFilter = previous.EmbedCssImagesStylesheetExcludeFilter; GenerateImageSprites = previous.GenerateImageSprites; EnableResourceSharing = previous.EnableResourceSharing; ResourceSharingExcludeFilter = previous.ResourceSharingExcludeFilter; ResourceSetFilters = previous.ResourceSetFilters; }
public IList <CombinatorResource> GetCombinedResources(string fingerprint, ICombinatorSettings settings) { IList <CombinatorResource> sharedResources = new List <CombinatorResource>(); if (settings.EnableResourceSharing) { CallOnDefaultShell(cacheFileService => sharedResources = cacheFileService.GetCombinedResources(fingerprint, new CombinatorSettings(settings) { EnableResourceSharing = false })); } var cacheKey = MakeCacheKey("GetCombinedResources." + fingerprint); return(_cacheService.Get(cacheKey, () => { _combinatorEventMonitor.MonitorCacheEmptied(cacheKey); _combinatorEventMonitor.MonitorBundleChanged(cacheKey, fingerprint); var files = _fileRepository.Fetch(file => file.Fingerprint == ConvertFingerprintToStorageFormat(fingerprint)).ToList(); var fileCount = files.Count; var resources = new List <CombinatorResource>(fileCount); foreach (var file in files) { var resource = _combinatorResourceManager.ResourceFactory(file.Type); resource.FillRequiredContext("CombinedResource" + file.Id.ToString(), string.Empty); _combinatorResourceManager.DeserializeSettings(file.Settings, resource); if (!resource.IsOriginal) // If the resource is original its url was filled from the settings { resource.RequiredContext.Resource.SetUrl(_storageProvider.GetPublicUrl(MakePath(file))); } resource.LastUpdatedUtc = file.LastUpdatedUtc.HasValue ? file.LastUpdatedUtc.Value : _clock.UtcNow; resources.Add(resource); } // This way if a set of resources contains shared and local resources in two resource sets then both will be returned. // Issue: the order is not necessarily correctly kept... But this should be a rare case. Should be solved eventually. return sharedResources.Union(resources).ToList(); })); }
public IList <ResourceRequiredContext> CombineStylesheets( IList <ResourceRequiredContext> resources, ICombinatorSettings settings) { var hashCode = resources.GetResourceListHashCode(); var lockName = MakeLockName(hashCode); return(_lockingCacheManager.Get(lockName, ctx => { if (!_cacheFileService.Exists(hashCode)) { Combine(resources, hashCode, ResourceType.Style, settings); } _combinatorEventMonitor.MonitorCacheEmptied(ctx); return ProcessCombinedResources(_cacheFileService.GetCombinedResources(hashCode)); }, () => resources)); }
public IList<ResourceRequiredContext> CombineStylesheets( IList<ResourceRequiredContext> resources, ICombinatorSettings settings) { var hashCode = resources.GetResourceListHashCode(); var lockName = MakeLockName(hashCode); return _lockingCacheManager.Get(lockName, ctx => { if (!_cacheFileService.Exists(hashCode)) { Combine(resources, hashCode, ResourceType.Style, settings); } _combinatorEventMonitor.MonitorCacheEmptied(ctx); return ProcessCombinedResources(_cacheFileService.GetCombinedResources(hashCode)); }, () => resources); }
public void Save(string fingerprint, CombinatorResource resource, ICombinatorSettings settings) { int count; sliceCounts.TryGetValue(fingerprint, out count); sliceCounts[fingerprint] = ++count; var sliceName = fingerprint + "-" + count; var savedResource = _resourceRepository.NewResource(resource.Type); var requiredContext = resource.RequiredContext; savedResource.IsOriginal = resource.IsOriginal; savedResource.LastUpdatedUtc = DateTime.UtcNow; savedResource.FillRequiredContext( requiredContext.Resource.Name, requiredContext.Resource.Url, requiredContext.Settings.Culture, requiredContext.Settings.Condition, requiredContext.Settings.Attributes); savedResource.Content = resource.Content; if (!resource.IsOriginal) { var url = "/Media/Default/_PiedoneModules/Combinator/"; if (resource.Type == ResourceType.Style) { url += "Styles/" + sliceName + ".css"; } else if (resource.Type == ResourceType.JavaScript) { url += "Scripts/" + sliceName + ".js"; } savedResource.RequiredContext.Resource.SetUrl(url); } _resourceRepository.SaveResource(sliceName, savedResource); }
public void ProcessResource(CombinatorResource resource, StringBuilder combinedContent, ICombinatorSettings settings) { if (!resource.IsCdnResource || settings.CombineCDNResources) { var absoluteUrlString = resource.AbsoluteUrl.ToString(); if (!resource.IsCdnResource) { resource.Content = _resourceFileService.GetLocalResourceContent(resource); } else if (settings.CombineCDNResources) { resource.Content = _resourceFileService.GetRemoteResourceContent(resource); } if (String.IsNullOrEmpty(resource.Content)) return; if (settings.MinifyResources && (settings.MinificationExcludeFilter == null || !settings.MinificationExcludeFilter.IsMatch(absoluteUrlString))) { MinifyResourceContent(resource); if (String.IsNullOrEmpty(resource.Content)) return; } // Better to do after minification, as then urls commented out are removed if (resource.Type == ResourceType.Style) { AdjustRelativePaths(resource); if (settings.EmbedCssImages && (settings.EmbedCssImagesStylesheetExcludeFilter == null || !settings.EmbedCssImagesStylesheetExcludeFilter.IsMatch(absoluteUrlString))) { EmbedImages(resource, settings.EmbeddedImagesMaxSizeKB); } } combinedContent.Append(resource.Content); } else { resource.IsOriginal = true; } }
public void ProcessResource(CombinatorResource resource, StringBuilder combinedContent, ICombinatorSettings settings) { if (resource.IsCdnResource && !settings.CombineCDNResources) { resource.IsOriginal = true; return; } var absoluteUrlString = resource.AbsoluteUrl.ToString(); _resourceFileService.LoadResourceContent(resource); _eventHandler.OnContentLoaded(resource); if (String.IsNullOrEmpty(resource.Content)) return; if (resource.Type == ResourceType.Style) { var stylesheet = new StylesheetParser().Parse(resource.Content); AdjustRelativePaths(resource, stylesheet); if (settings.EmbedCssImages && (settings.EmbedCssImagesStylesheetExcludeFilter == null || !settings.EmbedCssImagesStylesheetExcludeFilter.IsMatch(absoluteUrlString))) { EmbedImages(resource, stylesheet, settings.EmbeddedImagesMaxSizeKB); } resource.Content = stylesheet.ToString(); } if (settings.MinifyResources && (settings.MinificationExcludeFilter == null || !settings.MinificationExcludeFilter.IsMatch(absoluteUrlString))) { MinifyResourceContent(resource); if (String.IsNullOrEmpty(resource.Content)) return; } _eventHandler.OnContentProcessed(resource); combinedContent.Append(resource.Content); }
public void ProcessResource(CombinatorResource resource, StringBuilder combinedContent, ICombinatorSettings settings) { if (resource.IsCdnResource && !settings.CombineCdnResources) { resource.IsOriginal = true; return; } resource.Content = "processed: " + resource.Content; combinedContent.Append(resource.Content); }
/// <summary> /// Combines (and minifies) the content of resources and saves the combinations /// </summary> /// <param name="resources">Resources to combine</param> /// <param name="hashCode">Just so it shouldn't be recalculated</param> /// <param name="resourceType">Type of the resources</param> /// <param name="settings">Combination settings</param> /// <exception cref="ApplicationException">Thrown if there was a problem with a resource file (e.g. it was missing or could not be opened)</exception> private void Combine(IList <ResourceRequiredContext> resources, int hashCode, ResourceType resourceType, ICombinatorSettings settings) { if (resources.Count == 0) { return; } var combinatorResources = new List <CombinatorResource>(resources.Count); foreach (var resource in resources) { var combinatorResource = _combinatorResourceManager.ResourceFactory(resourceType); // Copying the context so the original one won't be touched combinatorResource.FillRequiredContext( resource.Resource.Name, resource.Resource.GetFullPath(), resource.Settings.Culture, resource.Settings.Condition, resource.Settings.Attributes); //var requiredContext = new ResourceRequiredContext(); //var resourceManifest = new ResourceManifest(); //requiredContext.Resource = resourceManifest.DefineResource(ResourceTypeHelper.EnumToStringType(resourceType), resource.Resource.Name); //requiredContext.Resource.SetUrl(resource.Resource.GetFullPath()); //requiredContext.Settings = new RequireSettings(); //requiredContext.Settings.Culture = resource.Settings.Culture; //requiredContext.Settings.Condition = resource.Settings.Condition; //requiredContext.Settings.Attributes = new Dictionary<string, string>(resource.Settings.Attributes); //combinatorResource.RequiredContext = requiredContext; combinatorResources.Add(combinatorResource); } var combinedContent = new StringBuilder(1000); Action <CombinatorResource> saveCombination = (combinedResource) => { if (combinedResource == null) { return; } // Don't save emtpy resources if (combinedContent.Length == 0 && !combinedResource.IsOriginal) { return; } combinedResource.Content = combinedContent.ToString(); _cacheFileService.Save(hashCode, combinedResource); combinedContent.Clear(); }; Regex currentSetRegex = null; for (int i = 0; i < combinatorResources.Count; i++) { var resource = combinatorResources[i]; var previousResource = (i != 0) ? combinatorResources[i - 1] : null; var absoluteUrlString = ""; try { absoluteUrlString = resource.AbsoluteUrl.ToString(); if (settings.CombinationExcludeFilter == null || !settings.CombinationExcludeFilter.IsMatch(absoluteUrlString)) { // If this resource differs from the previous one in terms of settings or CDN they can't be combined if (previousResource != null && (!previousResource.SettingsEqual(resource) || (previousResource.IsCdnResource != resource.IsCdnResource && !settings.CombineCDNResources))) { saveCombination(previousResource); } // If this resource is in a different set than the previous, they can't be combined if (currentSetRegex != null && !currentSetRegex.IsMatch(absoluteUrlString)) { currentSetRegex = null; saveCombination(previousResource); } // Calculate if this resource is in a set if (currentSetRegex == null && settings.ResourceSetFilters != null && settings.ResourceSetFilters.Length > 0) { int r = 0; while (currentSetRegex == null && r < settings.ResourceSetFilters.Length) { if (settings.ResourceSetFilters[r].IsMatch(absoluteUrlString)) { currentSetRegex = settings.ResourceSetFilters[r]; } r++; } // The previous resource is in a different set or in no set so it can't be combined with this resource if (currentSetRegex != null && previousResource != null) { saveCombination(previousResource); } } _resourceProcessingService.ProcessResource(resource, combinedContent, settings); } else { // This is a fully excluded resource if (previousResource != null) { saveCombination(previousResource); } resource.IsOriginal = true; saveCombination(resource); combinatorResources[i] = null; // So previous resource detection works correctly } } catch (Exception ex) { if (ex.IsFatal()) { throw; } throw new OrchardException(T("Processing of resource {0} failed.", absoluteUrlString), ex); } } saveCombination(combinatorResources[combinatorResources.Count - 1]); }
public static string GetCombinatorResourceListFingerprint <T>(this IEnumerable <T> resources, ICombinatorSettings settings) where T : CombinatorResource { return(resources.Select(resource => resource.RequiredContext).GetResourceListFingerprint(settings)); }
public IList <CombinatorResource> GetCombinedResources(string fingerprint, ICombinatorSettings settings) { return((from r in _resourceRepository.Resources where r.Key.Contains(fingerprint + "-") select r.Value).ToList()); }
public IList<ResourceRequiredContext> CombineStylesheets( IList<ResourceRequiredContext> resources, ICombinatorSettings settings) { var fingerprint = resources.GetResourceListFingerprint(settings); if (!_cacheFileService.Exists(fingerprint, settings)) { Combine(resources, fingerprint, ResourceType.Style, settings); } return ProcessCombinedResources(_cacheFileService.GetCombinedResources(fingerprint, settings), settings.ResourceBaseUri); }
public bool Exists(string fingerprint, ICombinatorSettings settings) { var exists = false; if (settings.EnableResourceSharing && CallOnDefaultShell(cacheFileService => exists = cacheFileService.Exists(fingerprint, new CombinatorSettings(settings) { EnableResourceSharing = false }))) { // Because resources were excluded from resource sharing in this set this set could be stored locally, not shared. // Thus we fall back to local storage. if (exists) return true; } var cacheKey = MakeCacheKey("Exists." + fingerprint); return _cacheService.Get(cacheKey, () => { _combinatorEventMonitor.MonitorCacheEmptied(cacheKey); _combinatorEventMonitor.MonitorBundleChanged(cacheKey, fingerprint); // Maybe also check if the file exists? return _fileRepository.Count(file => file.Fingerprint == ConvertFingerprintToStorageFormat(fingerprint)) != 0; }); }
public IList<CombinatorResource> GetCombinedResources(string fingerprint, ICombinatorSettings settings) { IList<CombinatorResource> sharedResources = new List<CombinatorResource>(); if (settings.EnableResourceSharing) { CallOnDefaultShell(cacheFileService => sharedResources = cacheFileService.GetCombinedResources(fingerprint, new CombinatorSettings(settings) { EnableResourceSharing = false })); } var cacheKey = MakeCacheKey("GetCombinedResources." + fingerprint); return _cacheService.Get(cacheKey, () => { _combinatorEventMonitor.MonitorCacheEmptied(cacheKey); _combinatorEventMonitor.MonitorBundleChanged(cacheKey, fingerprint); var files = _fileRepository.Fetch(file => file.Fingerprint == ConvertFingerprintToStorageFormat(fingerprint)).ToList(); var fileCount = files.Count; var resources = new List<CombinatorResource>(fileCount); foreach (var file in files) { var resource = _combinatorResourceManager.ResourceFactory(file.Type); resource.FillRequiredContext("CombinedResource" + file.Id.ToString(), string.Empty); _combinatorResourceManager.DeserializeSettings(file.Settings, resource); if (!resource.IsOriginal) // If the resource is original its url was filled from the settings { resource.RequiredContext.Resource.SetUrl(_storageProvider.GetPublicUrl(MakePath(file))); } resource.LastUpdatedUtc = file.LastUpdatedUtc.HasValue ? file.LastUpdatedUtc.Value : _clock.UtcNow; resources.Add(resource); } // This way if a set of resources contains shared and local resources in two resource sets then both will be returned. // Issue: the order is not necessarily correctly kept... But this should be a rare case. Should be solved eventually. return sharedResources.Union(resources).ToList(); }); }
public void Save(string fingerprint, CombinatorResource resource, ICombinatorSettings settings) { int count; sliceCounts.TryGetValue(fingerprint, out count); sliceCounts[fingerprint] = ++count; var sliceName = fingerprint + "-" + count; var savedResource = _resourceRepository.NewResource(resource.Type); var requiredContext = resource.RequiredContext; savedResource.IsOriginal = resource.IsOriginal; savedResource.LastUpdatedUtc = DateTime.UtcNow; savedResource.FillRequiredContext( requiredContext.Resource.Name, requiredContext.Resource.Url, requiredContext.Settings.Culture, requiredContext.Settings.Condition, requiredContext.Settings.Attributes); savedResource.Content = resource.Content; if (!resource.IsOriginal) { var url = "/Media/Default/_PiedoneModules/Combinator/"; if (resource.Type == ResourceType.Style) url += "Styles/" + sliceName + ".css"; else if (resource.Type == ResourceType.JavaScript) url += "Scripts/" + sliceName + ".js"; savedResource.RequiredContext.Resource.SetUrl(url); } _resourceRepository.SaveResource(sliceName, savedResource); }
public IList<CombinatorResource> GetCombinedResources(string fingerprint, ICombinatorSettings settings) { return (from r in _resourceRepository.Resources where r.Key.Contains(fingerprint + "-") select r.Value).ToList(); }
public bool Exists(string fingerprint, ICombinatorSettings settings) { return false; }
public void ProcessResource(CombinatorResource resource, StringBuilder combinedContent, ICombinatorSettings settings) { if (!resource.IsCdnResource || settings.CombineCDNResources) { var absoluteUrlString = resource.AbsoluteUrl.ToString(); if (!resource.IsCdnResource) { resource.Content = _resourceFileService.GetLocalResourceContent(resource); } else if (settings.CombineCDNResources) { resource.Content = _resourceFileService.GetRemoteResourceContent(resource); } if (String.IsNullOrEmpty(resource.Content)) { return; } if (settings.MinifyResources && (settings.MinificationExcludeFilter == null || !settings.MinificationExcludeFilter.IsMatch(absoluteUrlString))) { MinifyResourceContent(resource); if (String.IsNullOrEmpty(resource.Content)) { return; } } // Better to do after minification, as then urls commented out are removed if (resource.Type == ResourceType.Style) { AdjustRelativePaths(resource); if (settings.EmbedCssImages && (settings.EmbedCssImagesStylesheetExcludeFilter == null || !settings.EmbedCssImagesStylesheetExcludeFilter.IsMatch(absoluteUrlString))) { EmbedImages(resource, settings.EmbeddedImagesMaxSizeKB); } } combinedContent.Append(resource.Content); } else { resource.IsOriginal = true; } }
/// <summary> /// Combines (and minifies) the content of resources and saves the combinations. /// </summary> /// <param name="resources">Resources to combine.</param> /// <param name="fingerprint">Just so it shouldn't be recalculated.</param> /// <param name="resourceType">Type of the resources.</param> /// <param name="settings">Combination setting.s</param> /// <exception cref="ApplicationException">Thrown if there was a problem with a resource file (e.g. it was missing or could not be opened).</exception> private void Combine(IList <ResourceRequiredContext> resources, string fingerprint, ResourceType resourceType, ICombinatorSettings settings) { if (resources.Count == 0) { return; } var combinatorResources = new List <CombinatorResource>(resources.Count); foreach (var resource in resources) { var combinatorResource = _combinatorResourceManager.ResourceFactory(resourceType); // Copying the context so the original one won't be touched. combinatorResource.FillRequiredContext( resource.Resource.Name, resource.Resource.GetFullPath(), resource.Settings.Culture, resource.Settings.Condition, resource.Settings.Attributes, resource.Resource.TagBuilder.Attributes); combinatorResource.IsRemoteStorageResource = settings.RemoteStorageUrlPattern != null && settings.RemoteStorageUrlPattern.IsMatch(combinatorResource.AbsoluteUrl.ToString()); combinatorResources.Add(combinatorResource); } var combinedContent = new StringBuilder(1000); var resourceBaseUri = settings.ResourceBaseUri != null ? settings.ResourceBaseUri : new Uri(_hca.Current().Request.Url, "/"); Action <CombinatorResource, List <CombinatorResource> > saveCombination = (combinedResource, containedResources) => { if (combinedResource == null) { return; } // Don't save emtpy resources. if (combinedContent.Length == 0 && !combinedResource.IsOriginal) { return; } if (!containedResources.Any()) { containedResources = new List <CombinatorResource> { combinedResource } } ; var bundleFingerprint = containedResources.GetCombinatorResourceListFingerprint(settings); var localSettings = new CombinatorSettings(settings); if (localSettings.EnableResourceSharing && settings.ResourceSharingExcludeFilter != null) { foreach (var resource in containedResources) { if (localSettings.EnableResourceSharing) { localSettings.EnableResourceSharing = !settings.ResourceSharingExcludeFilter.IsMatch(resource.AbsoluteUrl.ToString()); } } } if (!combinedResource.IsOriginal) { combinedResource.Content = combinedContent.ToString(); if (combinedResource.Type == ResourceType.Style && !string.IsNullOrEmpty(combinedResource.Content) && settings.GenerateImageSprites) { _resourceProcessingService.ReplaceCssImagesWithSprite(combinedResource); } combinedResource.Content = "/*" + Environment.NewLine + "Resource bundle created by Combinator (http://combinator.codeplex.com/)" + Environment.NewLine + Environment.NewLine + "Resources in this bundle:" + Environment.NewLine + string.Join(Environment.NewLine, containedResources.Select(resource => { var url = resource.AbsoluteUrl.ToString(); if (localSettings.EnableResourceSharing && !resource.IsCdnResource && !resource.IsRemoteStorageResource) { var uriBuilder = new UriBuilder(url); uriBuilder.Host = "DefaultTenant"; url = uriBuilder.Uri.ToStringWithoutScheme(); } return("- " + url); })) + Environment.NewLine + "*/" + Environment.NewLine + Environment.NewLine + Environment.NewLine + combinedResource.Content; } // We save a bundle now. First the bundle should be saved separately under its unique name, then for this resource list. if (bundleFingerprint != fingerprint && containedResources.Count > 1) { if (!_cacheFileService.Exists(bundleFingerprint, localSettings)) { _cacheFileService.Save(bundleFingerprint, combinedResource, localSettings); } // Overriding the url for the resource in this resource list with the url of the set. combinedResource.IsOriginal = true; // The following should fetch one result theoretically but can more if the above Exists()-Save() happens // in multiple requests at the same time. var set = _cacheFileService.GetCombinedResources(bundleFingerprint, localSettings).First(); combinedResource.LastUpdatedUtc = set.LastUpdatedUtc; if (IsOwnedResource(set)) { if (settings.ResourceBaseUri != null && !set.IsRemoteStorageResource) { combinedResource.RequiredContext.Resource.SetUrl(UriHelper.Combine(resourceBaseUri.ToStringWithoutScheme(), set.AbsoluteUrl.PathAndQuery)); } else if (set.IsRemoteStorageResource) { combinedResource.IsRemoteStorageResource = true; combinedResource.RequiredContext.Resource.SetUrl(set.AbsoluteUrl.ToStringWithoutScheme()); } else { combinedResource.RequiredContext.Resource.SetUrl(set.RelativeUrl.ToString()); } AddTimestampToUrlIfNecessary(combinedResource); } else { combinedResource.RequiredContext.Resource.SetUrl(set.AbsoluteUrl.ToStringWithoutScheme()); } } _cacheFileService.Save(fingerprint, combinedResource, localSettings); combinedContent.Clear(); containedResources.Clear(); }; Regex currentSetRegex = null; var resourcesInCombination = new List <CombinatorResource>(); for (int i = 0; i < combinatorResources.Count; i++) { var resource = combinatorResources[i]; var previousResource = (i != 0) ? combinatorResources[i - 1] : null; var absoluteUrlString = ""; var saveOriginalResource = false; try { absoluteUrlString = resource.AbsoluteUrl.ToString(); if (settings.CombinationExcludeFilter == null || !settings.CombinationExcludeFilter.IsMatch(absoluteUrlString)) { // If this resource differs from the previous one in terms of settings or CDN they can't be combined if (previousResource != null && (!previousResource.SettingsEqual(resource) || (previousResource.IsCdnResource != resource.IsCdnResource && !settings.CombineCdnResources))) { saveCombination(previousResource, resourcesInCombination); previousResource = null; // So it doesn't get combined again in if (saveOriginalResource) below. } // If this resource is in a different set than the previous, they can't be combined if (currentSetRegex != null && !currentSetRegex.IsMatch(absoluteUrlString)) { currentSetRegex = null; saveCombination(previousResource, resourcesInCombination); } // Calculate if this resource is in a set if (currentSetRegex == null && settings.ResourceSetFilters != null && settings.ResourceSetFilters.Length > 0) { int r = 0; while (currentSetRegex == null && r < settings.ResourceSetFilters.Length) { if (settings.ResourceSetFilters[r].IsMatch(absoluteUrlString)) { currentSetRegex = settings.ResourceSetFilters[r]; } r++; } // The previous resource is in a different set or in no set so it can't be combined with this resource if (currentSetRegex != null && previousResource != null && resourcesInCombination.Any()) { saveCombination(previousResource, resourcesInCombination); } } // Nesting resources in such blocks is needed because some syntax is valid if in its own file but not anymore // when bundled. if (resourceType == ResourceType.JavaScript) { combinedContent.Append("{"); } combinedContent.Append(Environment.NewLine); _resourceProcessingService.ProcessResource(resource, combinedContent, settings); // This can be because e.g. it's a CDN resource and CDN combination is disabled. if (resource.IsOriginal) { saveOriginalResource = true; } combinedContent.Append(Environment.NewLine); if (resourceType == ResourceType.JavaScript) { combinedContent.Append("}"); } combinedContent.Append(Environment.NewLine); resourcesInCombination.Add(resource); } else { saveOriginalResource = true; } if (saveOriginalResource) { // This is a fully excluded resource if (previousResource != null) { saveCombination(previousResource, resourcesInCombination); } resource.IsOriginal = true; saveCombination(resource, resourcesInCombination); combinatorResources[i] = null; // So previous resource detection works correctly } } catch (Exception ex) { if (ex.IsFatal()) { throw; } throw new OrchardException(T("Processing of resource {0} failed.", absoluteUrlString), ex); } } saveCombination(combinatorResources[combinatorResources.Count - 1], resourcesInCombination); }
public bool Exists(string fingerprint, ICombinatorSettings settings) { return(false); }
public void Save(string fingerprint, CombinatorResource resource, ICombinatorSettings settings) { if (settings.EnableResourceSharing && CallOnDefaultShell(cacheFileService => cacheFileService.Save(fingerprint, resource, new CombinatorSettings(settings) { EnableResourceSharing = false }))) { return; } var sliceCount = _fileRepository.Count(file => file.Fingerprint == ConvertFingerprintToStorageFormat(fingerprint)); if (resource.LastUpdatedUtc == DateTime.MinValue) { resource.LastUpdatedUtc = _clock.UtcNow; } // Ceil-ing timestamp to the second, because sub-second precision is not stored in the DB. This would cause a discrepancy between saved // and fetched vs freshly created date times, causing unwanted cache busting for the same resource. resource.LastUpdatedUtc = new DateTime(resource.LastUpdatedUtc.Year, resource.LastUpdatedUtc.Month, resource.LastUpdatedUtc.Day, resource.LastUpdatedUtc.Hour, resource.LastUpdatedUtc.Minute, resource.LastUpdatedUtc.Second); var fileRecord = new CombinedFileRecord() { Fingerprint = ConvertFingerprintToStorageFormat(fingerprint), Slice = ++sliceCount, Type = resource.Type, LastUpdatedUtc = resource.LastUpdatedUtc, Settings = _combinatorResourceManager.SerializeResourceSettings(resource) }; _fileRepository.Create(fileRecord); if (!string.IsNullOrEmpty(resource.Content)) { var path = MakePath(fileRecord); if (_storageProvider.FileExists(path)) _storageProvider.DeleteFile(path); using (var stream = _storageProvider.CreateFile(path).OpenWrite()) { var bytes = Encoding.UTF8.GetBytes(resource.Content); stream.Write(bytes, 0, bytes.Length); } if (!resource.IsRemoteStorageResource) { // This is needed to adjust relative paths if the resource is stored in a remote storage provider. // Why the double-saving? Before saving the file there is no reliable way to tell whether the storage public url will be a // remote one or not... var testResource = _combinatorResourceManager.ResourceFactory(resource.Type); testResource.FillRequiredContext("TestCombinedResource", _storageProvider.GetPublicUrl(path)); _combinatorResourceManager.DeserializeSettings(fileRecord.Settings, testResource); testResource.IsRemoteStorageResource = settings.RemoteStorageUrlPattern != null && settings.RemoteStorageUrlPattern.IsMatch(testResource.AbsoluteUrl.ToString()); if (testResource.IsRemoteStorageResource) { _storageProvider.DeleteFile(path); testResource.Content = resource.Content; var relativeUrlsBaseUri = settings.ResourceBaseUri != null ? settings.ResourceBaseUri : new Uri(_urlHelper.RequestContext.HttpContext.Request.Url, _urlHelper.Content("~/")); ResourceProcessingService.RegexConvertRelativeUrlsToAbsolute(testResource, relativeUrlsBaseUri); using (var stream = _storageProvider.CreateFile(path).OpenWrite()) { var bytes = Encoding.UTF8.GetBytes(testResource.Content); stream.Write(bytes, 0, bytes.Length); } resource.IsRemoteStorageResource = true; fileRecord.Settings = _combinatorResourceManager.SerializeResourceSettings(resource); } } } _combinatorEventHandler.BundleChanged(fingerprint); }
/// <summary> /// Combines (and minifies) the content of resources and saves the combinations. /// </summary> /// <param name="resources">Resources to combine.</param> /// <param name="fingerprint">Just so it shouldn't be recalculated.</param> /// <param name="resourceType">Type of the resources.</param> /// <param name="settings">Combination setting.s</param> /// <exception cref="ApplicationException">Thrown if there was a problem with a resource file (e.g. it was missing or could not be opened).</exception> private void Combine(IList<ResourceRequiredContext> resources, string fingerprint, ResourceType resourceType, ICombinatorSettings settings) { if (resources.Count == 0) return; var combinatorResources = new List<CombinatorResource>(resources.Count); foreach (var resource in resources) { var combinatorResource = _combinatorResourceManager.ResourceFactory(resourceType); // Copying the context so the original one won't be touched. combinatorResource.FillRequiredContext( resource.Resource.Name, resource.Resource.GetFullPath(), resource.Settings.Culture, resource.Settings.Condition, resource.Settings.Attributes, resource.Resource.TagBuilder.Attributes); combinatorResource.IsRemoteStorageResource = settings.RemoteStorageUrlPattern != null && settings.RemoteStorageUrlPattern.IsMatch(combinatorResource.AbsoluteUrl.ToString()); combinatorResources.Add(combinatorResource); } var combinedContent = new StringBuilder(1000); var resourceBaseUri = settings.ResourceBaseUri != null ? settings.ResourceBaseUri : new Uri(_hca.Current().Request.Url, "/"); Action<CombinatorResource, List<CombinatorResource>> saveCombination = (combinedResource, containedResources) => { if (combinedResource == null) return; // Don't save emtpy resources. if (combinedContent.Length == 0 && !combinedResource.IsOriginal) return; if (!containedResources.Any()) containedResources = new List<CombinatorResource> { combinedResource }; var bundleFingerprint = containedResources.GetCombinatorResourceListFingerprint(settings); var localSettings = new CombinatorSettings(settings); if (localSettings.EnableResourceSharing && settings.ResourceSharingExcludeFilter != null) { foreach (var resource in containedResources) { if (localSettings.EnableResourceSharing) { localSettings.EnableResourceSharing = !settings.ResourceSharingExcludeFilter.IsMatch(resource.AbsoluteUrl.ToString()); } } } if (!combinedResource.IsOriginal) { combinedResource.Content = combinedContent.ToString(); if (combinedResource.Type == ResourceType.Style && !string.IsNullOrEmpty(combinedResource.Content) && settings.GenerateImageSprites) { _resourceProcessingService.ReplaceCssImagesWithSprite(combinedResource); } combinedResource.Content = "/*" + Environment.NewLine + "Resource bundle created by Combinator (http://combinator.codeplex.com/)" + Environment.NewLine + Environment.NewLine + "Resources in this bundle:" + Environment.NewLine + string.Join(Environment.NewLine, containedResources.Select(resource => { var url = resource.AbsoluteUrl.ToString(); if (localSettings.EnableResourceSharing && !resource.IsCdnResource && !resource.IsRemoteStorageResource) { var uriBuilder = new UriBuilder(url); uriBuilder.Host = "DefaultTenant"; url = uriBuilder.Uri.ToStringWithoutScheme(); } return "- " + url; })) + Environment.NewLine + "*/" + Environment.NewLine + Environment.NewLine + Environment.NewLine + combinedResource.Content; } // We save a bundle now. First the bundle should be saved separately under its unique name, then for this resource list. if (bundleFingerprint != fingerprint && containedResources.Count > 1) { if (!_cacheFileService.Exists(bundleFingerprint, localSettings)) { _cacheFileService.Save(bundleFingerprint, combinedResource, localSettings); } // Overriding the url for the resource in this resource list with the url of the set. combinedResource.IsOriginal = true; // The following should fetch one result theoretically but can more if the above Exists()-Save() happens // in multiple requests at the same time. var set = _cacheFileService.GetCombinedResources(bundleFingerprint, localSettings).First(); combinedResource.LastUpdatedUtc = set.LastUpdatedUtc; if (IsOwnedResource(set)) { if (settings.ResourceBaseUri != null && !set.IsRemoteStorageResource) { combinedResource.RequiredContext.Resource.SetUrl(UriHelper.Combine(resourceBaseUri.ToStringWithoutScheme(), set.AbsoluteUrl.PathAndQuery)); } else if (set.IsRemoteStorageResource) { combinedResource.IsRemoteStorageResource = true; combinedResource.RequiredContext.Resource.SetUrl(set.AbsoluteUrl.ToStringWithoutScheme()); } else { combinedResource.RequiredContext.Resource.SetUrl(set.RelativeUrl.ToString()); } AddTimestampToUrlIfNecessary(combinedResource); } else { combinedResource.RequiredContext.Resource.SetUrl(set.AbsoluteUrl.ToStringWithoutScheme()); } } _cacheFileService.Save(fingerprint, combinedResource, localSettings); combinedContent.Clear(); containedResources.Clear(); }; Regex currentSetRegex = null; var resourcesInCombination = new List<CombinatorResource>(); for (int i = 0; i < combinatorResources.Count; i++) { var resource = combinatorResources[i]; var previousResource = (i != 0) ? combinatorResources[i - 1] : null; var absoluteUrlString = ""; var saveOriginalResource = false; try { absoluteUrlString = resource.AbsoluteUrl.ToString(); if (settings.CombinationExcludeFilter == null || !settings.CombinationExcludeFilter.IsMatch(absoluteUrlString)) { // If this resource differs from the previous one in terms of settings or CDN they can't be combined if (previousResource != null && (!previousResource.SettingsEqual(resource) || (previousResource.IsCdnResource != resource.IsCdnResource && !settings.CombineCdnResources))) { saveCombination(previousResource, resourcesInCombination); previousResource = null; // So it doesn't get combined again in if (saveOriginalResource) below. } // If this resource is in a different set than the previous, they can't be combined if (currentSetRegex != null && !currentSetRegex.IsMatch(absoluteUrlString)) { currentSetRegex = null; saveCombination(previousResource, resourcesInCombination); } // Calculate if this resource is in a set if (currentSetRegex == null && settings.ResourceSetFilters != null && settings.ResourceSetFilters.Length > 0) { int r = 0; while (currentSetRegex == null && r < settings.ResourceSetFilters.Length) { if (settings.ResourceSetFilters[r].IsMatch(absoluteUrlString)) currentSetRegex = settings.ResourceSetFilters[r]; r++; } // The previous resource is in a different set or in no set so it can't be combined with this resource if (currentSetRegex != null && previousResource != null && resourcesInCombination.Any()) { saveCombination(previousResource, resourcesInCombination); } } // Nesting resources in such blocks is needed because some syntax is valid if in its own file but not anymore // when bundled. if (resourceType == ResourceType.JavaScript) combinedContent.Append("{"); combinedContent.Append(Environment.NewLine); _resourceProcessingService.ProcessResource(resource, combinedContent, settings); // This can be because e.g. it's a CDN resource and CDN combination is disabled. if (resource.IsOriginal) saveOriginalResource = true; combinedContent.Append(Environment.NewLine); if (resourceType == ResourceType.JavaScript) combinedContent.Append("}"); combinedContent.Append(Environment.NewLine); resourcesInCombination.Add(resource); } else saveOriginalResource = true; if (saveOriginalResource) { // This is a fully excluded resource if (previousResource != null) saveCombination(previousResource, resourcesInCombination); resource.IsOriginal = true; saveCombination(resource, resourcesInCombination); combinatorResources[i] = null; // So previous resource detection works correctly } } catch (Exception ex) { if (ex.IsFatal()) throw; throw new OrchardException(T("Processing of resource {0} failed.", absoluteUrlString), ex); } } saveCombination(combinatorResources[combinatorResources.Count - 1], resourcesInCombination); }
public void Save(string fingerprint, CombinatorResource resource, ICombinatorSettings settings) { if (settings.EnableResourceSharing && CallOnDefaultShell(cacheFileService => cacheFileService.Save(fingerprint, resource, new CombinatorSettings(settings) { EnableResourceSharing = false }))) { return; } var sliceCount = _fileRepository.Count(file => file.Fingerprint == ConvertFingerprintToStorageFormat(fingerprint)); if (resource.LastUpdatedUtc == DateTime.MinValue) { resource.LastUpdatedUtc = _clock.UtcNow; } // Ceil-ing timestamp to the second, because sub-second precision is not stored in the DB. This would cause a discrepancy between saved // and fetched vs freshly created date times, causing unwanted cache busting for the same resource. resource.LastUpdatedUtc = new DateTime(resource.LastUpdatedUtc.Year, resource.LastUpdatedUtc.Month, resource.LastUpdatedUtc.Day, resource.LastUpdatedUtc.Hour, resource.LastUpdatedUtc.Minute, resource.LastUpdatedUtc.Second); var fileRecord = new CombinedFileRecord() { Fingerprint = ConvertFingerprintToStorageFormat(fingerprint), Slice = ++sliceCount, Type = resource.Type, LastUpdatedUtc = resource.LastUpdatedUtc, Settings = _combinatorResourceManager.SerializeResourceSettings(resource) }; _fileRepository.Create(fileRecord); if (!string.IsNullOrEmpty(resource.Content)) { var path = MakePath(fileRecord); if (_storageProvider.FileExists(path)) { _storageProvider.DeleteFile(path); } using (var stream = _storageProvider.CreateFile(path).OpenWrite()) { var bytes = Encoding.UTF8.GetBytes(resource.Content); stream.Write(bytes, 0, bytes.Length); } if (!resource.IsRemoteStorageResource) { // This is needed to adjust relative paths if the resource is stored in a remote storage provider. // Why the double-saving? Before saving the file there is no reliable way to tell whether the storage public url will be a // remote one or not... var testResource = _combinatorResourceManager.ResourceFactory(resource.Type); testResource.FillRequiredContext("TestCombinedResource", _storageProvider.GetPublicUrl(path)); _combinatorResourceManager.DeserializeSettings(fileRecord.Settings, testResource); testResource.IsRemoteStorageResource = settings.RemoteStorageUrlPattern != null && settings.RemoteStorageUrlPattern.IsMatch(testResource.AbsoluteUrl.ToString()); if (testResource.IsRemoteStorageResource) { _storageProvider.DeleteFile(path); testResource.Content = resource.Content; var relativeUrlsBaseUri = settings.ResourceBaseUri != null ? settings.ResourceBaseUri : new Uri(_urlHelper.RequestContext.HttpContext.Request.Url, _urlHelper.Content("~/")); ResourceProcessingService.RegexConvertRelativeUrlsToAbsolute(testResource, relativeUrlsBaseUri); using (var stream = _storageProvider.CreateFile(path).OpenWrite()) { var bytes = Encoding.UTF8.GetBytes(testResource.Content); stream.Write(bytes, 0, bytes.Length); } resource.IsRemoteStorageResource = true; fileRecord.Settings = _combinatorResourceManager.SerializeResourceSettings(resource); } } } _combinatorEventHandler.BundleChanged(fingerprint); }
/// <summary> /// Combines (and minifies) the content of resources and saves the combinations /// </summary> /// <param name="resources">Resources to combine</param> /// <param name="hashCode">Just so it shouldn't be recalculated</param> /// <param name="resourceType">Type of the resources</param> /// <param name="settings">Combination settings</param> /// <exception cref="ApplicationException">Thrown if there was a problem with a resource file (e.g. it was missing or could not be opened)</exception> private void Combine(IList<ResourceRequiredContext> resources, int hashCode, ResourceType resourceType, ICombinatorSettings settings) { if (resources.Count == 0) return; var combinatorResources = new List<CombinatorResource>(resources.Count); foreach (var resource in resources) { var combinatorResource = _combinatorResourceManager.ResourceFactory(resourceType); // Copying the context so the original one won't be touched combinatorResource.FillRequiredContext( resource.Resource.Name, resource.Resource.GetFullPath(), resource.Settings.Culture, resource.Settings.Condition, resource.Settings.Attributes); //var requiredContext = new ResourceRequiredContext(); //var resourceManifest = new ResourceManifest(); //requiredContext.Resource = resourceManifest.DefineResource(ResourceTypeHelper.EnumToStringType(resourceType), resource.Resource.Name); //requiredContext.Resource.SetUrl(resource.Resource.GetFullPath()); //requiredContext.Settings = new RequireSettings(); //requiredContext.Settings.Culture = resource.Settings.Culture; //requiredContext.Settings.Condition = resource.Settings.Condition; //requiredContext.Settings.Attributes = new Dictionary<string, string>(resource.Settings.Attributes); //combinatorResource.RequiredContext = requiredContext; combinatorResources.Add(combinatorResource); } var combinedContent = new StringBuilder(1000); Action<CombinatorResource> saveCombination = (combinedResource) => { if (combinedResource == null) return; // Don't save emtpy resources if (combinedContent.Length == 0 && !combinedResource.IsOriginal) return; combinedResource.Content = combinedContent.ToString(); _cacheFileService.Save(hashCode, combinedResource); combinedContent.Clear(); }; Regex currentSetRegex = null; for (int i = 0; i < combinatorResources.Count; i++) { var resource = combinatorResources[i]; var previousResource = (i != 0) ? combinatorResources[i - 1] : null; var absoluteUrlString = ""; try { absoluteUrlString = resource.AbsoluteUrl.ToString(); if (settings.CombinationExcludeFilter == null || !settings.CombinationExcludeFilter.IsMatch(absoluteUrlString)) { // If this resource differs from the previous one in terms of settings or CDN they can't be combined if (previousResource != null && (!previousResource.SettingsEqual(resource) || (previousResource.IsCdnResource != resource.IsCdnResource && !settings.CombineCDNResources))) { saveCombination(previousResource); } // If this resource is in a different set than the previous, they can't be combined if (currentSetRegex != null && !currentSetRegex.IsMatch(absoluteUrlString)) { currentSetRegex = null; saveCombination(previousResource); } // Calculate if this resource is in a set if (currentSetRegex == null && settings.ResourceSetFilters != null && settings.ResourceSetFilters.Length > 0) { int r = 0; while (currentSetRegex == null && r < settings.ResourceSetFilters.Length) { if (settings.ResourceSetFilters[r].IsMatch(absoluteUrlString)) currentSetRegex = settings.ResourceSetFilters[r]; r++; } // The previous resource is in a different set or in no set so it can't be combined with this resource if (currentSetRegex != null && previousResource != null) { saveCombination(previousResource); } } _resourceProcessingService.ProcessResource(resource, combinedContent, settings); } else { // This is a fully excluded resource if (previousResource != null) saveCombination(previousResource); resource.IsOriginal = true; saveCombination(resource); combinatorResources[i] = null; // So previous resource detection works correctly } } catch (Exception ex) { if (ex.IsFatal()) throw; throw new OrchardException(T("Processing of resource {0} failed.", absoluteUrlString), ex); } } saveCombination(combinatorResources[combinatorResources.Count - 1]); }
public static string GetResourceListFingerprint <T>(this IEnumerable <T> resources, ICombinatorSettings settings) where T : ResourceRequiredContext { var key = string.Empty; resources.ToList().ForEach(resource => key += resource.Resource.GetFullPath() + "__"); return (key.GetHashCode() + "-" + (settings.MinifyResources ? "min" : "nomin") + "-" + (settings.EmbedCssImages ? "embed" + settings.EmbeddedImagesMaxSizeKB : "noembed") + "-" + (settings.GenerateImageSprites ? "sprites" : "nosprites")); }
/// <summary> /// Combines (and minifies) the content of resources and saves the combinations /// </summary> /// <param name="resources">Resources to combine</param> /// <param name="hashCode">Just so it shouldn't be recalculated</param> /// <param name="resourceType">Type of the resources</param> /// <param name="settings">Combination settings</param> /// <exception cref="ApplicationException">Thrown if there was a problem with a resource file (e.g. it was missing or could not be opened)</exception> private void Combine(IList<ResourceRequiredContext> resources, int hashCode, ResourceType resourceType, ICombinatorSettings settings) { if (resources.Count == 0) return; var combinatorResources = new List<CombinatorResource>(resources.Count); foreach (var resource in resources) { var combinatorResource = _combinatorResourceManager.ResourceFactory(resourceType); // Copying the context so the original one won't be touched combinatorResource.FillRequiredContext( resource.Resource.Name, resource.Resource.GetFullPath(), resource.Settings.Culture, resource.Settings.Condition, resource.Settings.Attributes); combinatorResources.Add(combinatorResource); } var combinedContent = new StringBuilder(1000); Action<CombinatorResource, IEnumerable<CombinatorResource>> saveCombination = (combinedResource, containedResources) => { if (combinedResource == null) return; // Don't save emtpy resources if (combinedContent.Length == 0 && !combinedResource.IsOriginal) return; if (!combinedResource.IsOriginal) { combinedResource.Content = combinedContent.ToString(); if (combinedResource.Type == ResourceType.Style && !String.IsNullOrEmpty(combinedResource.Content) && settings.GenerateImageSprites) { _resourceProcessingService.ReplaceCssImagesWithSprite(combinedResource); } combinedResource.Content = "/*" + Environment.NewLine + "Resource bundle created by Combinator (http://combinator.codeplex.com/)" + Environment.NewLine + Environment.NewLine + "Resources in this bundle:" + Environment.NewLine + String.Join(Environment.NewLine, containedResources.Select(resource => "- " + resource.AbsoluteUrl.ToString()).ToArray()) + Environment.NewLine + "*/" + Environment.NewLine + Environment.NewLine + Environment.NewLine + combinedResource.Content; } _cacheFileService.Save(hashCode, combinedResource); combinedContent.Clear(); }; Regex currentSetRegex = null; var resourcesInCombination = new List<CombinatorResource>(); for (int i = 0; i < combinatorResources.Count; i++) { var resource = combinatorResources[i]; var previousResource = (i != 0) ? combinatorResources[i - 1] : null; var absoluteUrlString = ""; try { absoluteUrlString = resource.AbsoluteUrl.ToString(); if (settings.CombinationExcludeFilter == null || !settings.CombinationExcludeFilter.IsMatch(absoluteUrlString)) { resourcesInCombination.Add(resource); // If this resource differs from the previous one in terms of settings or CDN they can't be combined if (previousResource != null && (!previousResource.SettingsEqual(resource) || (previousResource.IsCdnResource != resource.IsCdnResource && !settings.CombineCDNResources))) { saveCombination(previousResource, resourcesInCombination); } // If this resource is in a different set than the previous, they can't be combined if (currentSetRegex != null && !currentSetRegex.IsMatch(absoluteUrlString)) { currentSetRegex = null; saveCombination(previousResource, resourcesInCombination); } // Calculate if this resource is in a set if (currentSetRegex == null && settings.ResourceSetFilters != null && settings.ResourceSetFilters.Length > 0) { int r = 0; while (currentSetRegex == null && r < settings.ResourceSetFilters.Length) { if (settings.ResourceSetFilters[r].IsMatch(absoluteUrlString)) currentSetRegex = settings.ResourceSetFilters[r]; r++; } // The previous resource is in a different set or in no set so it can't be combined with this resource if (currentSetRegex != null && previousResource != null) { saveCombination(previousResource, resourcesInCombination); } } _resourceProcessingService.ProcessResource(resource, combinedContent, settings); } else { // This is a fully excluded resource if (previousResource != null) saveCombination(previousResource, resourcesInCombination); resource.IsOriginal = true; saveCombination(resource, resourcesInCombination); combinatorResources[i] = null; // So previous resource detection works correctly } } catch (Exception ex) { if (ex.IsFatal()) throw; throw new OrchardException(T("Processing of resource {0} failed.", absoluteUrlString), ex); } } saveCombination(combinatorResources[combinatorResources.Count - 1], resourcesInCombination); }
public void ProcessResource(CombinatorResource resource, StringBuilder combinedContent, ICombinatorSettings settings) { if (resource.IsCdnResource && !settings.CombineCdnResources) { resource.IsOriginal = true; return; } var absoluteUrlString = resource.AbsoluteUrl.ToString(); _resourceFileService.LoadResourceContent(resource); _eventHandler.OnContentLoaded(resource); if (string.IsNullOrEmpty(resource.Content)) { return; } if (resource.Type == ResourceType.Style) { //var stylesheet = new StylesheetParser().Parse(resource.Content); //AdjustRelativePaths(resource, stylesheet); //if (settings.EmbedCssImages && (settings.EmbedCssImagesStylesheetExcludeFilter == null || !settings.EmbedCssImagesStylesheetExcludeFilter.IsMatch(absoluteUrlString))) //{ // EmbedImages(resource, stylesheet, settings.EmbeddedImagesMaxSizeKB); //} //resource.Content = stylesheet.ToString(); // Needed until ExCss becomes mature RegexAdjustRelativePaths(resource); if (settings.EmbedCssImages && (settings.EmbedCssImagesStylesheetExcludeFilter == null || !settings.EmbedCssImagesStylesheetExcludeFilter.IsMatch(absoluteUrlString))) { RegexEmbedImages(resource, settings.EmbeddedImagesMaxSizeKB); } } if (settings.MinifyResources && (settings.MinificationExcludeFilter == null || !settings.MinificationExcludeFilter.IsMatch(absoluteUrlString))) { MinifyResourceContent(resource); if (string.IsNullOrEmpty(resource.Content)) { return; } } _eventHandler.OnContentProcessed(resource); combinedContent.Append(resource.Content); }