Hello community, here is the log from the commit of package rubygem-sprockets for openSUSE:Factory checked in at 2015-08-27 08:57:46 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/rubygem-sprockets (Old) and /work/SRC/openSUSE:Factory/.rubygem-sprockets.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "rubygem-sprockets" Changes: -------- --- /work/SRC/openSUSE:Factory/rubygem-sprockets/rubygem-sprockets.changes 2015-06-12 20:30:54.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.rubygem-sprockets.new/rubygem-sprockets.changes 2015-08-27 08:57:47.000000000 +0200 @@ -1,0 +2,24 @@ +Mon Aug 24 04:31:26 UTC 2015 - [email protected] + +- updated to version 3.3.3 + see installed CHANGELOG.md + + **3.3.3** (August 21, 2015) + + * Remove more absolute paths from cache contents. + + **3.3.2** (August 19, 2015) + + * Fix cache contents to use relative paths instead of absolute paths. + + **3.3.1** (August 15, 2015) + + * Fix legacy Tilt integration when locals is required argument. + +------------------------------------------------------------------- +Thu Aug 13 04:30:50 UTC 2015 - [email protected] + +- updated to version 3.3.0 + no changelog found + +------------------------------------------------------------------- Old: ---- sprockets-3.2.0.gem New: ---- sprockets-3.3.3.gem ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ rubygem-sprockets.spec ++++++ --- /var/tmp/diff_new_pack.v2bgCN/_old 2015-08-27 08:57:47.000000000 +0200 +++ /var/tmp/diff_new_pack.v2bgCN/_new 2015-08-27 08:57:47.000000000 +0200 @@ -24,7 +24,7 @@ # Name: rubygem-sprockets -Version: 3.2.0 +Version: 3.3.3 Release: 0 %define mod_name sprockets %define mod_full_name %{mod_name}-%{version} @@ -52,7 +52,7 @@ %install %gem_install \ --symlink-binaries \ - --doc-files="LICENSE README.md" \ + --doc-files="CHANGELOG.md LICENSE README.md" \ -f %gem_packages ++++++ sprockets-3.2.0.gem -> sprockets-3.3.3.gem ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/CHANGELOG.md new/CHANGELOG.md --- old/CHANGELOG.md 1970-01-01 01:00:00.000000000 +0100 +++ new/CHANGELOG.md 2015-08-21 23:07:31.000000000 +0200 @@ -0,0 +1,234 @@ +**3.3.3** (August 21, 2015) + +* Remove more absolute paths from cache contents. + +**3.3.2** (August 19, 2015) + +* Fix cache contents to use relative paths instead of absolute paths. + +**3.3.1** (August 15, 2015) + +* Fix legacy Tilt integration when locals is required argument. + +**3.3.0** (August 12, 2015) + +* Change internal cache key to use relative asset paths instead of absolute paths. + +**3.2.0** (June 2, 2015) + +* Updated SRI integrity to align with spec changes +* Deprecated Manifest integrity attribute +* Cleanup concatenating JS sources with newlines + +**3.1.0** (May 10, 2015) + +* Removed "index" logical path normalization. Asset#logical_path is always the + full logical path to the index file. +* Fixed static asset mtimes +* Fix manifest cleanup by age +* Removed redundant minifier level cache +* Updated SRI format according to spec changes + +**3.0.3** (April 27, 2015) + +* Fix static asset mtime fallback +* Only warn when specified asset version can not be loaded. + +**3.0.2** (April 22, 2015) + +* Ensure legacy Tilt handlers return String class data. Fixes issues with Haml + Tilt handler. +* Type check and improve error messages raised on bad processor returned results. +* Improve error message for relative paths not under load path. +* Changed HTML encoding fallback from ISO-8859-1 to default external. +* Avoid falling back to 0 mtimes which may cause warnings with tar + +**3.0.1** (April 14, 2015) + +* Fixed `Context#depend_on` with paths outside the load path + +**3.0.0** (April 12, 2015) + +[Guide to upgrading from Sprockets 2.x to 3.x](https://github.com/rails/sprockets/blob/master/UPGRADING.md) + +* New processor API. Tilt interface is deprecated. +* Improved file store caching backend. +* MIME Types now accept charset custom charset detecters. Improves support for UTF-16/32 files. +* Environment#version no longer affects asset digests. Only used for busting the asset cache. +* Removed builtin support for LESS. +* Removed `//= include` directive support. +* Deprecated `BundledAsset#to_a`. Use `BundledAsset#included` to access debugging subcomponents. +* Support circular dependencies. For parity with ES6 modules. +* Manifest compilation will no longer generate .gz files by default. [Mixing + Content-Encoding and ETags is just a bad + idea](https://issues.apache.org/bugzilla/show_bug.cgi?id=39727) +* Added linked or referenced assets. When an asset is compiled, any of its links will be compiled as well. +* Introduce some limitations around enumerating all logical paths. 4.x will deprecate it and favor linked manifests for compliation. +* Add Asset integrity attribute for Subresource Integrity +* Default digest changed to SHA256. Configuring `digest_class` is deprecated. +* Rename `Asset#digest` to `Asset#hexdigest`. `Asset#digest` is deprecated and will + return a raw byte String in 4.x. +* Added transitional compatibility flag to `Environment#resolve(path, compat: true)`. 2.x mode operates with `compat: true` and 4.x with `compat: false` +* `manifest-abc123.json` renamed to `.sprockets-abc123.json` + +**2.12.3** (October 28, 2014) + +* Security: Fix directory traversal bug in development mode server. + +**2.12.2** (September 5, 2014) + +* Ensure internal asset lookups calls are still restricted to load paths within + asset compiles. Though, you should not depend on internal asset resolves to be + completely restricted for security reasons. Assets themselves should be + considered full scripting environments with filesystem access. + +**2.12.1** (April 17, 2014) + +* Fix making manifest target directory when its different than the output directory. + +**2.12.0** (March 13, 2014) + +* Avoid context reference in SassImporter hack so its Marshallable. Fixes + issues with Sass 3.3.x. + +**2.11.0** (February 19, 2014) + +* Cache store must now be an LRU implementation. +* Default digest changed to SHA1. To continue using MD5. + `env.digest_class = Digest::MD5`. + +**2.10.0** (May 24, 2013) + +* Support for `bower.json` + +**2.9.3** (April 20, 2013) + +* Fixed sass caching bug + +**2.9.2** (April 8, 2013) + +* Improve file freshness check performance +* Directive processor encoding fixes + +**2.9.1** (April 6, 2013) + +* Support for Uglifier 2.x + +**2.9.0** (February 25, 2013) + +* Write out gzipped variants of bundled assets. + +**2.8.2** (December 10, 2012) + +* Fixed top level Sass constant references +* Fixed manifest logger when environment is disabled + +**2.8.1** (October 31, 2012) + +* Fixed Sass importer bug + +**2.8.0** (October 16, 2012) + +* Allow manifest location to be separated from output directory +* Pass logical path and absolute path to each_logical_path iterator + +**2.7.0** (October 10, 2012) + +* Added --css-compressor and --js-compressor command line flags +* Added css/js compressor shorthand +* Change default manifest.json filename to be a randomized manifest-16HEXBYTES.json +* Allow nil environment to be passed to manifest +* Allow manifest instance to be set on rake task + +**2.6.0** (September 19, 2012) + +* Added bower component.json require support + +**2.5.0** (September 4, 2012) + +* Fixed Ruby 2.0 RegExp warning +* Provide stubbed implementation of context *_path helpers +* Add SassCompressor + +**2.4.5** (July 10, 2012) + +* Tweaked some logger levels + +**2.4.4** (July 2, 2012) + +* Canonicalize logical path extensions +* Check absolute paths passed to depend_on + +**2.4.3** (May 16, 2012) + +* Exposed :sprockets in sass options +* Include dependency paths in asset mtime + +**2.4.2** (May 7, 2012) + +* Fixed MultiJson feature detect + +**2.4.1** (April 26, 2012) + +* Fixed MultiJson API change +* Fixed gzip mtime + +**2.4.0** (March 27, 2012) + +* Added global path registry +* Added global processor registry + +**2.3.2** (March 26, 2012) + +* Fix Context#logical_path with dots + +**2.3.1** (February 11, 2012) + +* Added bytesize to manifest +* Added Asset#bytesize alias +* Security: Check path for forbidden access after unescaping + +**2.3.0** (January 16, 2012) + +* Added special Sass importer that automatically tracks any `@import`ed files. + +**2.2.0** (January 10, 2012) + +* Added `sprockets` command line utility. +* Added rake/sprocketstask. +* Added json manifest log of compiled assets. +* Added `stub` directive that allows you to exclude files from the bundle. +* Added per environment external encoding (Environment#default_external_encoding). Defaults to UTF-8. Fixes issues where LANG is not set correctly and Rubys default external is set to ASCII. + +**2.1.2** (November 20, 2011) + +* Disabled If-Modified-Since server checks. Fixes some browser caching issues when serving the asset body only. If-None-Match caching is sufficient. + +**2.1.1** (November 18, 2011) + +* Fix windows absolute path check bug. + +**2.1.0** (November 11, 2011) + +* Directive comment lines are now turned into empty lines instead of removed. This way line numbers in + CoffeeScript syntax errors are correct. +* Performance and caching bug fixes. + +**2.0.3** (October 17, 2011) + +* Detect format extensions from right to left. +* Make JST namespace configurable. + +**2.0.2** (October 4, 2011) + +* Fixed loading stale cache from bundler gems. + +**2.0.1** (September 30, 2011) + +* Fixed bug with fingerprinting file names with multiple dots. +* Decode URIs as default internal. +* Fix symlinked asset directories. + +**2.0.0** (August 29, 2011) + +* Initial public release. Files old/checksums.yaml.gz and new/checksums.yaml.gz differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/sprockets/base.rb new/lib/sprockets/base.rb --- old/lib/sprockets/base.rb 2015-06-02 22:21:36.000000000 +0200 +++ new/lib/sprockets/base.rb 2015-08-21 23:07:31.000000000 +0200 @@ -10,6 +10,8 @@ require 'sprockets/path_utils' require 'sprockets/resolve' require 'sprockets/server' +require 'sprockets/loader' +require 'sprockets/uri_tar' module Sprockets # `Base` class for `Environment` and `Cached`. @@ -48,9 +50,10 @@ # Caveat: Digests are cached by the path's current mtime. Its possible # for a files contents to have changed and its mtime to have been # negligently reset thus appearing as if the file hasn't changed on - # disk. Also, the mtime is only read to the nearest second. Its + # disk. Also, the mtime is only read to the nearest second. It's # also possible the file was updated more than once in a given second. - cache.fetch("file_digest:#{path}:#{stat.mtime.to_i}") do + key = UnloadedAsset.new(path, self).file_digest_key(stat.mtime.to_i) + cache.fetch(key) do self.stat_digest(path, stat) end end @@ -95,5 +98,13 @@ "root=#{root.to_s.inspect}, " + "paths=#{paths.inspect}>" end + + def compress_from_root(uri) + URITar.new(uri, self).compress + end + + def expand_from_root(uri) + URITar.new(uri, self).expand + end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/sprockets/dependencies.rb new/lib/sprockets/dependencies.rb --- old/lib/sprockets/dependencies.rb 2015-06-02 22:21:36.000000000 +0200 +++ new/lib/sprockets/dependencies.rb 2015-08-21 23:07:31.000000000 +0200 @@ -51,18 +51,18 @@ end alias_method :depend_on, :add_dependency - # Internal: Resolve set of dependency URIs. - # - # Returns Array of resolved Objects. - def resolve_dependencies(uris) - uris.map { |uri| resolve_dependency(uri) } - end - # Internal: Resolve dependency URIs. # # Returns resolved Object. def resolve_dependency(str) - scheme = str[/([^:]+)/, 1] + # Optimize for the most common scheme to + # save 22k allocations on an average Spree app. + scheme = if str.start_with?('file-digest:'.freeze) + 'file-digest'.freeze + else + str[/([^:]+)/, 1] + end + if resolver = config[:dependency_resolvers][scheme] resolver.call(self, str) else diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/sprockets/digest_utils.rb new/lib/sprockets/digest_utils.rb --- old/lib/sprockets/digest_utils.rb 2015-06-02 22:21:36.000000000 +0200 +++ new/lib/sprockets/digest_utils.rb 2015-08-21 23:07:31.000000000 +0200 @@ -66,7 +66,7 @@ elsif klass == FalseClass digest << 'FalseClass' elsif klass == NilClass - digest << 'NilClass' + digest << 'NilClass'.freeze elsif klass == Array digest << 'Array' queue.concat(obj) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/sprockets/legacy_tilt_processor.rb new/lib/sprockets/legacy_tilt_processor.rb --- old/lib/sprockets/legacy_tilt_processor.rb 2015-06-02 22:21:36.000000000 +0200 +++ new/lib/sprockets/legacy_tilt_processor.rb 2015-08-21 23:07:31.000000000 +0200 @@ -22,7 +22,7 @@ data = input[:data] context = input[:environment].context_class.new(input) - data = @klass.new(filename) { data }.render(context) + data = @klass.new(filename) { data }.render(context, {}) context.metadata.merge(data: data.to_str) end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/sprockets/loader.rb new/lib/sprockets/loader.rb --- old/lib/sprockets/loader.rb 2015-06-02 22:21:36.000000000 +0200 +++ new/lib/sprockets/loader.rb 2015-08-21 23:07:31.000000000 +0200 @@ -10,39 +10,54 @@ require 'sprockets/resolve' require 'sprockets/transformers' require 'sprockets/uri_utils' +require 'sprockets/unloaded_asset' module Sprockets + # The loader phase takes a asset URI location and returns a constructed Asset # object. module Loader include DigestUtils, PathUtils, ProcessorUtils, URIUtils include Engines, Mime, Processing, Resolve, Transformers - # Public: Load Asset by AssetURI. + + # Public: Load Asset by Asset URI. + # + # uri - A String containing complete URI to a file including schema + # and full path such as: + # "file:///Path/app/assets/js/app.js?type=application/javascript" # - # uri - AssetURI # # Returns Asset. def load(uri) - filename, params = parse_asset_uri(uri) - if params.key?(:id) - unless asset = cache.get("asset-uri:#{VERSION}:#{uri}", true) - id = params.delete(:id) - uri_without_id = build_asset_uri(filename, params) - asset = load_asset_by_uri(uri_without_id, filename, params) + unloaded = UnloadedAsset.new(uri, self) + if unloaded.params.key?(:id) + unless asset = asset_from_cache(unloaded.asset_key) + id = unloaded.params.delete(:id) + uri_without_id = build_asset_uri(unloaded.filename, unloaded.params) + asset = load_from_unloaded(UnloadedAsset.new(uri_without_id, self)) if asset[:id] != id @logger.warn "Sprockets load error: Tried to find #{uri}, but latest was id #{asset[:id]}" end end else - asset = fetch_asset_from_dependency_cache(uri, filename) do |paths| + asset = fetch_asset_from_dependency_cache(unloaded) do |paths| + # When asset is previously generated, its "dependencies" are stored in the cache. + # The presence of `paths` indicates dependencies were stored. + # We can check to see if the dependencies have not changed by "resolving" them and + # generating a digest key from the resolved entries. If this digest key has not + # changed the asset will be pulled from cache. + # + # If this `paths` is present but the cache returns nothing then `fetch_asset_from_dependency_cache` + # will confusingly be called again with `paths` set to nil where the asset will be + # loaded from disk. if paths - digest = digest(resolve_dependencies(paths)) - if id_uri = cache.get("asset-uri-digest:#{VERSION}:#{uri}:#{digest}", true) - cache.get("asset-uri:#{VERSION}:#{id_uri}", true) + digest = DigestUtils.digest(resolve_dependencies(paths)) + if uri_from_cache = cache.get(unloaded.digest_key(digest), true) + asset_from_cache(UnloadedAsset.new(uri_from_cache, self).asset_key) end else - load_asset_by_uri(uri, filename, params) + load_from_unloaded(unloaded) end end end @@ -50,25 +65,58 @@ end private - def load_asset_by_uri(uri, filename, params) - unless file?(filename) - raise FileNotFound, "could not find file: #{filename}" + + # Internal: Load asset hash from cache + # + # key - A String containing lookup information for an asset + # + # This method converts all "compressed" paths to absolute paths. + # Returns a hash of values representing an asset + def asset_from_cache(key) + asset = cache.get(key, true) + if asset + asset[:uri] = expand_from_root(asset[:uri]) + asset[:load_path] = expand_from_root(asset[:load_path]) + asset[:filename] = expand_from_root(asset[:filename]) + asset[:metadata][:included].map! { |uri| expand_from_root(uri) } if asset[:metadata][:included] + asset[:metadata][:links].map! { |uri| expand_from_root(uri) } if asset[:metadata][:links] + asset[:metadata][:stubbed].map! { |uri| expand_from_root(uri) } if asset[:metadata][:stubbed] + asset[:metadata][:required].map! { |uri| expand_from_root(uri) } if asset[:metadata][:required] + asset[:metadata][:dependencies].map! { |uri| uri.start_with?("file-digest://") ? expand_from_root(uri) : uri } if asset[:metadata][:dependencies] + + asset[:metadata].each_key do |k| + next unless k =~ /_dependencies\z/ + asset[:metadata][k].map! { |uri| expand_from_root(uri) } + end + end + asset + end + + # Internal: Loads an asset and saves it to cache + # + # unloaded - An UnloadedAsset + # + # This method is only called when the given unloaded asset could not be + # successfully pulled from cache. + def load_from_unloaded(unloaded) + unless file?(unloaded.filename) + raise FileNotFound, "could not find file: #{unloaded.filename}" end - load_path, logical_path = paths_split(config[:paths], filename) + load_path, logical_path = paths_split(config[:paths], unloaded.filename) unless load_path - raise FileOutsidePaths, "#{filename} is no longer under a load path: #{self.paths.join(', ')}" + raise FileOutsidePaths, "#{unloaded.filename} is no longer under a load path: #{self.paths.join(', ')}" end logical_path, file_type, engine_extnames, _ = parse_path_extnames(logical_path) name = logical_path - if pipeline = params[:pipeline] + if pipeline = unloaded.params[:pipeline] logical_path += ".#{pipeline}" end - if type = params[:type] + if type = unloaded.params[:type] logical_path += config[:mime_types][type][:extensions].first end @@ -86,8 +134,8 @@ result = call_processors(processors, { environment: self, cache: self.cache, - uri: uri, - filename: filename, + uri: unloaded.uri, + filename: unloaded.filename, load_path: load_path, name: name, content_type: type, @@ -101,28 +149,28 @@ length: source.bytesize ) else - dependencies << build_file_digest_uri(filename) + dependencies << build_file_digest_uri(unloaded.filename) metadata = { - digest: file_digest(filename), - length: self.stat(filename).size, + digest: file_digest(unloaded.filename), + length: self.stat(unloaded.filename).size, dependencies: dependencies } end asset = { - uri: uri, + uri: unloaded.uri, load_path: load_path, - filename: filename, + filename: unloaded.filename, name: name, logical_path: logical_path, content_type: type, source: source, metadata: metadata, - dependencies_digest: digest(resolve_dependencies(metadata[:dependencies])) + dependencies_digest: DigestUtils.digest(resolve_dependencies(metadata[:dependencies])) } asset[:id] = pack_hexdigest(digest(asset)) - asset[:uri] = build_asset_uri(filename, params.merge(id: asset[:id])) + asset[:uri] = build_asset_uri(unloaded.filename, unloaded.params.merge(id: asset[:id])) # Deprecated: Avoid tracking Asset mtime asset[:mtime] = metadata[:dependencies].map { |u| @@ -133,19 +181,132 @@ nil end }.compact.max - asset[:mtime] ||= self.stat(filename).mtime.to_i - - cache.set("asset-uri:#{VERSION}:#{asset[:uri]}", asset, true) - cache.set("asset-uri-digest:#{VERSION}:#{uri}:#{asset[:dependencies_digest]}", asset[:uri], true) + asset[:mtime] ||= self.stat(unloaded.filename).mtime.to_i + store_asset(asset, unloaded) asset end - def fetch_asset_from_dependency_cache(uri, filename, limit = 3) - key = "asset-uri-cache-dependencies:#{VERSION}:#{uri}:#{file_digest(filename)}" - history = cache.get(key) || [] + # Internal: Save a given asset to the cache + # + # asset - A hash containing values of loaded asset + # unloaded - The UnloadedAsset used to lookup the `asset` + # + # This method converts all absolute paths to "compressed" paths + # which are relative if they're in the root. + def store_asset(asset, unloaded) + # Save the asset in the cache under the new URI + cached_asset = asset.dup + cached_asset[:uri] = compress_from_root(asset[:uri]) + cached_asset[:filename] = compress_from_root(asset[:filename]) + cached_asset[:load_path] = compress_from_root(asset[:load_path]) + + if cached_asset[:metadata] + # Deep dup to avoid modifying `asset` + cached_asset[:metadata] = cached_asset[:metadata].dup + if cached_asset[:metadata][:included] && !cached_asset[:metadata][:included].empty? + cached_asset[:metadata][:included] = cached_asset[:metadata][:included].dup + cached_asset[:metadata][:included].map! { |uri| compress_from_root(uri) } + end + + if cached_asset[:metadata][:links] && !cached_asset[:metadata][:links].empty? + cached_asset[:metadata][:links] = cached_asset[:metadata][:links].dup + cached_asset[:metadata][:links].map! { |uri| compress_from_root(uri) } + end + + if cached_asset[:metadata][:stubbed] && !cached_asset[:metadata][:stubbed].empty? + cached_asset[:metadata][:stubbed] = cached_asset[:metadata][:stubbed].dup + cached_asset[:metadata][:stubbed].map! { |uri| compress_from_root(uri) } + end + if cached_asset[:metadata][:required] && !cached_asset[:metadata][:required].empty? + cached_asset[:metadata][:required] = cached_asset[:metadata][:required].dup + cached_asset[:metadata][:required].map! { |uri| compress_from_root(uri) } + end + + if cached_asset[:metadata][:dependencies] && !cached_asset[:metadata][:dependencies].empty? + cached_asset[:metadata][:dependencies] = cached_asset[:metadata][:dependencies].dup + cached_asset[:metadata][:dependencies].map! do |uri| + uri.start_with?("file-digest://".freeze) ? compress_from_root(uri) : uri + end + end + + # compress all _dependencies in metadata like `sass_dependencies` + cached_asset[:metadata].each do |key, value| + next unless key =~ /_dependencies\z/ + cached_asset[:metadata][key] = value.dup + cached_asset[:metadata][key].map! {|uri| compress_from_root(uri) } + end + end + + # Unloaded asset and stored_asset now have a different URI + stored_asset = UnloadedAsset.new(asset[:uri], self) + cache.set(stored_asset.asset_key, cached_asset, true) + + # Save the new relative path for the digest key of the unloaded asset + cache.set(unloaded.digest_key(asset[:dependencies_digest]), stored_asset.compressed_path, true) + end + + + # Internal: Resolve set of dependency URIs. + # + # uris - An Array of "dependencies" for example: + # ["environment-version", "environment-paths", "processors:type=text/css&file_type=text/css", + # "file-digest:///Full/path/app/assets/stylesheets/application.css", + # "processors:type=text/css&file_type=text/css&pipeline=self", + # "file-digest:///Full/path/app/assets/stylesheets"] + # + # Returns back array of things that the given uri dpends on + # For example the environment version, if you're using a different version of sprockets + # then the dependencies should be different, this is used only for generating cache key + # for example the "environment-version" may be resolved to "environment-1.0-3.2.0" for + # version "3.2.0" of sprockets. + # + # Any paths that are returned are converted to relative paths + # + # Returns array of resolved dependencies + def resolve_dependencies(uris) + uris.map { |uri| resolve_dependency(uri) } + end + + # Internal: Retrieves an asset based on its digest + # + # unloaded - An UnloadedAsset + # limit - A Fixnum which sets the maximum number of versions of "histories" + # stored in the cache + # + # This method attempts to retrieve the last `limit` number of histories of an asset + # from the cache a "history" which is an array of unresolved "dependencies" that the asset needs + # to compile. In this case A dependency can refer to either an asset i.e. index.js + # may rely on jquery.js (so jquery.js is a depndency), or other factors that may affect + # compilation, such as the VERSION of sprockets (i.e. the environment) and what "processors" + # are used. + # + # For example a history array may look something like this + # + # [["environment-version", "environment-paths", "processors:type=text/css&file_type=text/css", + # "file-digest:///Full/path/app/assets/stylesheets/application.css", + # "processors:type=text/css&file_digesttype=text/css&pipeline=self", + # "file-digest:///Full/path/app/assets/stylesheets"]] + # + # Where the first entry is a Set of dependencies for last generated version of that asset. + # Multiple versions are stored since sprockets keeps the last `limit` number of assets + # generated present in the system. + # + # If a "history" of dependencies is present in the cache, each version of "history" will be + # yielded to the passed block which is responsible for loading the asset. If found, the existing + # history will be saved with the dependency that found a valid asset moved to the front. + # + # If no history is present, or if none of the histories could be resolved to a valid asset then, + # the block is yielded to and expected to return a valid asset. + # When this happens the dependencies for the returned asset are added to the "history", and older + # entries are removed if the "history" is above `limit`. + def fetch_asset_from_dependency_cache(unloaded, limit = 3) + key = unloaded.dependency_history_key + + history = cache.get(key) || [] history.each_with_index do |deps, index| + deps.map! { |path| path.start_with?("file-digest://") ? expand_from_root(path) : path } if asset = yield(deps) cache.set(key, history.rotate!(index)) if index > 0 return asset @@ -153,7 +314,9 @@ end asset = yield - deps = asset[:metadata][:dependencies] + deps = asset[:metadata][:dependencies].dup.map! do |uri| + uri.start_with?("file-digest://") ? compress_from_root(uri) : uri + end cache.set(key, history.unshift(deps).take(limit)) asset end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/sprockets/unloaded_asset.rb new/lib/sprockets/unloaded_asset.rb --- old/lib/sprockets/unloaded_asset.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/lib/sprockets/unloaded_asset.rb 2015-08-21 23:07:31.000000000 +0200 @@ -0,0 +1,137 @@ +require 'sprockets/uri_utils' +require 'sprockets/uri_tar' + +module Sprockets + # Internal: Used to parse and store the URI to an unloaded asset + # Generates keys used to store and retrieve items from cache + class UnloadedAsset + + # Internal: Initialize object for generating cache keys + # + # uri - A String containing complete URI to a file including scheme + # and full path such as + # "file:///Path/app/assets/js/app.js?type=application/javascript" + # env - The current "environment" that assets are being loaded into. + # We need it so we know where the +root+ (directory where sprockets + # is being invoked). We also need for the `file_digest` method, + # since, for some strange reason, memoization is provided by + # overriding methods such as `stat` in the `PathUtils` module. + # + # Returns UnloadedAsset. + def initialize(uri, env) + @uri = uri + @env = env + @compressed_path = URITar.new(uri, env).compressed_path + @params = nil # lazy loaded + @filename = nil # lazy loaded + end + attr_reader :compressed_path, :uri + + # Internal: Full file path without schema + # + # This returns a string containing the full path to the asset without the schema. + # Information is loaded lazilly since we want `UnloadedAsset.new(dep, self).relative_path` + # to be fast. Calling this method the first time allocates an array and a hash. + # + # Example + # + # If the URI is `file:///Full/path/app/assets/javascripts/application.js"` then the + # filename would be `"/Full/path/app/assets/javascripts/application.js"` + # + # Returns a String. + def filename + unless @filename + load_file_params + end + @filename + end + + # Internal: Hash of param values + # + # This information is generated and used internally by sprockets. + # Known keys include `:type` which store the asset's mime-type, `:id` which is a fully resolved + # digest for the asset (includes dependency digest as opposed to a digest of only file contents) + # and `:pipeline`. Hash may be empty. + # + # Example + # + # If the URI is `file:///Full/path/app/assets/javascripts/application.js"type=application/javascript` + # Then the params would be `{type: "application/javascript"}` + # + # Returns a Hash. + def params + unless @params + load_file_params + end + @params + end + + # Internal: Key of asset + # + # Used to retrieve an asset from the cache based on "compressed" path to asset. + # A "compressed" path can either be relative to the root of the project or an + # absolute path. + # + # Returns a String. + def asset_key + "asset-uri:#{compressed_path}" + end + + # Public: Dependency History key + # + # Used to retrieve an array of "histories" each of which contain a set of stored dependencies + # for a given asset path and filename digest. + # + # A dependency can refer to either an asset i.e. index.js + # may rely on jquery.js (so jquery.js is a dependency), or other factors that may affect + # compilation, such as the VERSION of sprockets (i.e. the environment) and what "processors" + # are used. + # + # For example a history array with one Set of dependencies may look like: + # + # [["environment-version", "environment-paths", "processors:type=text/css&file_type=text/css", + # "file-digest:///Full/path/app/assets/stylesheets/application.css", + # "processors:type=text/css&file_type=text/css&pipeline=self", + # "file-digest:///Full/path/app/assets/stylesheets"]] + # + # This method of asset lookup is used to ensure that none of the dependencies have been modified + # since last lookup. If one of them has, the key will be different and a new entry must be stored. + # + # URI depndencies are later converted to "compressed" paths + # + # Returns a String. + def dependency_history_key + "asset-uri-cache-dependencies:#{compressed_path}:#{ @env.file_digest(filename) }" + end + + # Internal: Digest key + # + # Used to retrieve a string containing the "compressed" path to an asset based on + # a digest. The digest is generated from dependencies stored via information stored in + # the `dependency_history_key` after each of the "dependencies" is "resolved" for example + # "environment-version" may be resolved to "environment-1.0-3.2.0" for version "3.2.0" of sprockets + # + # Returns a String. + def digest_key(digest) + "asset-uri-digest:#{compressed_path}:#{digest}" + end + + # Internal: File digest key + # + # The digest for a given file won't change if the path and the stat time hasn't changed + # We can save time by not re-computing this information and storing it in the cache + # + # Returns a String. + def file_digest_key(stat) + "file_digest:#{compressed_path}:#{stat}" + end + + private + # Internal: Parses uri into filename and params hash + # + # Returns Array with filename and params hash + def load_file_params + @filename, @params = URIUtils.parse_asset_uri(uri) + end + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/sprockets/uri_tar.rb new/lib/sprockets/uri_tar.rb --- old/lib/sprockets/uri_tar.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/lib/sprockets/uri_tar.rb 2015-08-21 23:07:31.000000000 +0200 @@ -0,0 +1,76 @@ +module Sprockets + # Internal: used to "expand" and "compress" values for storage + class URITar + attr_reader :scheme, :root, :path + + # Internal: Initialize object for compression or expansion + # + # uri - A String containing URI that may or may not contain the scheme + # env - The current "environment" that assets are being loaded into. + def initialize(uri, env) + @root = env.root + @env = env + if uri.include?("://".freeze) + uri_array = uri.split("://".freeze) + @scheme = uri_array.shift + @scheme << "://".freeze + @path = uri_array.join("".freeze) + else + @scheme = "".freeze + @path = uri + end + end + + # Internal: Converts full uri to a "compressed" uri + # + # If a uri is inside of an environment's root it will + # be shortened to be a relative path. + # + # If a uri is outside of the environment's root the original + # uri will be returned. + # + # Returns String + def compress + scheme + compressed_path + end + + # Internal: Convert a "compressed" uri to an absolute path + # + # If a uri is inside of the environment's root it will not + # start with a slash for example: + # + # file://this/is/a/relative/path + # + # If a uri is outside the root, it will start with a slash: + # + # file:///This/is/an/absolute/path + # + # Returns String + def expand + if path.start_with?("/".freeze) + # Stored path was absolute, don't add root + scheme + path + else + # Stored path was relative, add root + scheme + File.join(root, path) + end + end + + # Internal: Returns "compressed" path + # + # If the input uri is relative to the environment root + # it will return a path relative to the environment root. + # Otherwise an absolute path will be returned. + # + # Only path information is returned, and not scheme. + # + # Returns String + def compressed_path + if compressed_path = @env.split_subpath(root, path) + compressed_path + else + path + end + end + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/sprockets/uri_utils.rb new/lib/sprockets/uri_utils.rb --- old/lib/sprockets/uri_utils.rb 2015-06-02 22:21:37.000000000 +0200 +++ new/lib/sprockets/uri_utils.rb 2015-08-21 23:07:31.000000000 +0200 @@ -48,7 +48,7 @@ path.force_encoding(Encoding::UTF_8) # Hack for parsing Windows "file:///C:/Users/IEUser" paths - path.gsub!(/^\/([a-zA-Z]:)/, '\1') + path.gsub!(/^\/([a-zA-Z]:)/, '\1'.freeze) [scheme, host, path, query] end @@ -125,7 +125,7 @@ def parse_file_digest_uri(uri) scheme, _, path, _ = split_file_uri(uri) - unless scheme == 'file-digest' + unless scheme == 'file-digest'.freeze raise URI::InvalidURIError, "expected file-digest scheme: #{uri}" end @@ -143,7 +143,7 @@ # # Returns String URI. def build_file_digest_uri(path) - join_file_uri("file-digest", nil, path, nil) + join_file_uri('file-digest'.freeze, nil, path, nil) end # Internal: Serialize hash of params into query string. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/sprockets/version.rb new/lib/sprockets/version.rb --- old/lib/sprockets/version.rb 2015-06-02 22:21:37.000000000 +0200 +++ new/lib/sprockets/version.rb 2015-08-21 23:07:31.000000000 +0200 @@ -1,3 +1,3 @@ module Sprockets - VERSION = "3.2.0" + VERSION = "3.3.3" end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/sprockets.rb new/lib/sprockets.rb --- old/lib/sprockets.rb 2015-06-02 22:21:36.000000000 +0200 +++ new/lib/sprockets.rb 2015-08-21 23:07:31.000000000 +0200 @@ -144,7 +144,7 @@ env.version end register_dependency_resolver 'environment-paths' do |env| - env.paths + env.paths.map {|path| env.compress_from_root(path) } end register_dependency_resolver 'file-digest' do |env, str| env.file_digest(env.parse_file_digest_uri(str)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/metadata new/metadata --- old/metadata 2015-06-02 22:21:36.000000000 +0200 +++ new/metadata 2015-08-21 23:07:31.000000000 +0200 @@ -1,7 +1,7 @@ --- !ruby/object:Gem::Specification name: sprockets version: !ruby/object:Gem::Version - version: 3.2.0 + version: 3.3.3 platform: ruby authors: - Sam Stephenson @@ -9,7 +9,7 @@ autorequire: bindir: bin cert_chain: [] -date: 2015-06-02 00:00:00.000000000 Z +date: 2015-08-21 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: rack @@ -217,6 +217,7 @@ extensions: [] extra_rdoc_files: [] files: +- CHANGELOG.md - LICENSE - README.md - bin/sprockets @@ -284,6 +285,8 @@ - lib/sprockets/server.rb - lib/sprockets/transformers.rb - lib/sprockets/uglifier_compressor.rb +- lib/sprockets/unloaded_asset.rb +- lib/sprockets/uri_tar.rb - lib/sprockets/uri_utils.rb - lib/sprockets/utils.rb - lib/sprockets/version.rb @@ -308,7 +311,7 @@ version: '0' requirements: [] rubyforge_project: sprockets -rubygems_version: 2.4.5 +rubygems_version: 2.4.5.1 signing_key: specification_version: 4 summary: Rack-based asset packaging system
