sprockets 3.7.2 → 4.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +47 -267
- data/README.md +477 -321
- data/bin/sprockets +11 -7
- data/lib/rake/sprocketstask.rb +3 -2
- data/lib/sprockets.rb +99 -39
- data/lib/sprockets/add_source_map_comment_to_asset_processor.rb +60 -0
- data/lib/sprockets/asset.rb +31 -23
- data/lib/sprockets/autoload.rb +5 -0
- data/lib/sprockets/autoload/babel.rb +8 -0
- data/lib/sprockets/autoload/closure.rb +1 -0
- data/lib/sprockets/autoload/coffee_script.rb +1 -0
- data/lib/sprockets/autoload/eco.rb +1 -0
- data/lib/sprockets/autoload/ejs.rb +1 -0
- data/lib/sprockets/autoload/jsminc.rb +8 -0
- data/lib/sprockets/autoload/sass.rb +1 -0
- data/lib/sprockets/autoload/sassc.rb +8 -0
- data/lib/sprockets/autoload/uglifier.rb +1 -0
- data/lib/sprockets/autoload/yui.rb +1 -0
- data/lib/sprockets/autoload/zopfli.rb +7 -0
- data/lib/sprockets/babel_processor.rb +66 -0
- data/lib/sprockets/base.rb +49 -12
- data/lib/sprockets/bower.rb +5 -2
- data/lib/sprockets/bundle.rb +40 -4
- data/lib/sprockets/cache.rb +36 -1
- data/lib/sprockets/cache/file_store.rb +25 -3
- data/lib/sprockets/cache/memory_store.rb +9 -0
- data/lib/sprockets/cache/null_store.rb +8 -0
- data/lib/sprockets/cached_environment.rb +14 -19
- data/lib/sprockets/closure_compressor.rb +1 -0
- data/lib/sprockets/coffee_script_processor.rb +18 -4
- data/lib/sprockets/compressing.rb +43 -3
- data/lib/sprockets/configuration.rb +3 -7
- data/lib/sprockets/context.rb +97 -24
- data/lib/sprockets/dependencies.rb +1 -0
- data/lib/sprockets/digest_utils.rb +25 -5
- data/lib/sprockets/directive_processor.rb +45 -35
- data/lib/sprockets/eco_processor.rb +1 -0
- data/lib/sprockets/ejs_processor.rb +1 -0
- data/lib/sprockets/encoding_utils.rb +1 -0
- data/lib/sprockets/environment.rb +9 -4
- data/lib/sprockets/erb_processor.rb +28 -21
- data/lib/sprockets/errors.rb +1 -0
- data/lib/sprockets/exporters/base.rb +71 -0
- data/lib/sprockets/exporters/file_exporter.rb +24 -0
- data/lib/sprockets/exporters/zlib_exporter.rb +33 -0
- data/lib/sprockets/exporters/zopfli_exporter.rb +14 -0
- data/lib/sprockets/exporting.rb +73 -0
- data/lib/sprockets/file_reader.rb +1 -0
- data/lib/sprockets/http_utils.rb +25 -7
- data/lib/sprockets/jsminc_compressor.rb +32 -0
- data/lib/sprockets/jst_processor.rb +11 -10
- data/lib/sprockets/loader.rb +87 -67
- data/lib/sprockets/manifest.rb +64 -62
- data/lib/sprockets/manifest_utils.rb +9 -6
- data/lib/sprockets/mime.rb +8 -42
- data/lib/sprockets/npm.rb +52 -0
- data/lib/sprockets/path_dependency_utils.rb +3 -11
- data/lib/sprockets/path_digest_utils.rb +2 -1
- data/lib/sprockets/path_utils.rb +87 -7
- data/lib/sprockets/paths.rb +1 -0
- data/lib/sprockets/preprocessors/default_source_map.rb +49 -0
- data/lib/sprockets/processing.rb +31 -61
- data/lib/sprockets/processor_utils.rb +24 -35
- data/lib/sprockets/resolve.rb +177 -93
- data/lib/sprockets/sass_cache_store.rb +2 -6
- data/lib/sprockets/sass_compressor.rb +13 -1
- data/lib/sprockets/sass_functions.rb +1 -0
- data/lib/sprockets/sass_importer.rb +1 -0
- data/lib/sprockets/sass_processor.rb +30 -9
- data/lib/sprockets/sassc_compressor.rb +56 -0
- data/lib/sprockets/sassc_processor.rb +297 -0
- data/lib/sprockets/server.rb +26 -23
- data/lib/sprockets/source_map_processor.rb +66 -0
- data/lib/sprockets/source_map_utils.rb +483 -0
- data/lib/sprockets/transformers.rb +63 -35
- data/lib/sprockets/uglifier_compressor.rb +21 -11
- data/lib/sprockets/unloaded_asset.rb +13 -11
- data/lib/sprockets/uri_tar.rb +1 -0
- data/lib/sprockets/uri_utils.rb +11 -8
- data/lib/sprockets/utils.rb +41 -74
- data/lib/sprockets/utils/gzip.rb +46 -14
- data/lib/sprockets/version.rb +2 -1
- data/lib/sprockets/yui_compressor.rb +1 -0
- metadata +127 -23
- data/LICENSE +0 -21
- data/lib/sprockets/coffee_script_template.rb +0 -17
- data/lib/sprockets/deprecation.rb +0 -90
- data/lib/sprockets/eco_template.rb +0 -17
- data/lib/sprockets/ejs_template.rb +0 -17
- data/lib/sprockets/engines.rb +0 -92
- data/lib/sprockets/erb_template.rb +0 -11
- data/lib/sprockets/legacy.rb +0 -330
- data/lib/sprockets/legacy_proc_processor.rb +0 -35
- data/lib/sprockets/legacy_tilt_processor.rb +0 -29
- data/lib/sprockets/sass_template.rb +0 -19
data/lib/sprockets/manifest.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'json'
|
2
3
|
require 'time'
|
3
4
|
|
4
5
|
require 'concurrent'
|
5
6
|
|
6
7
|
require 'sprockets/manifest_utils'
|
7
|
-
require 'sprockets/utils/gzip'
|
8
8
|
|
9
9
|
module Sprockets
|
10
10
|
# The Manifest logs the contents of assets compiled to a single directory. It
|
@@ -52,14 +52,8 @@ module Sprockets
|
|
52
52
|
@directory ||= File.dirname(@filename) if @filename
|
53
53
|
|
54
54
|
# If directory is given w/o filename, pick a random manifest location
|
55
|
-
@rename_filename = nil
|
56
55
|
if @directory && @filename.nil?
|
57
|
-
@filename = find_directory_manifest(@directory)
|
58
|
-
|
59
|
-
# If legacy manifest name autodetected, mark to rename on save
|
60
|
-
if File.basename(@filename).start_with?("manifest")
|
61
|
-
@rename_filename = File.join(@directory, generate_manifest_path)
|
62
|
-
end
|
56
|
+
@filename = find_directory_manifest(@directory, logger)
|
63
57
|
end
|
64
58
|
|
65
59
|
unless @directory && @filename
|
@@ -125,26 +119,15 @@ module Sprockets
|
|
125
119
|
|
126
120
|
return to_enum(__method__, *args) unless block_given?
|
127
121
|
|
128
|
-
paths, filters = args.flatten.partition { |arg| self.class.simple_logical_path?(arg) }
|
129
|
-
filters = filters.map { |arg| self.class.compile_match_filter(arg) }
|
130
|
-
|
131
122
|
environment = self.environment.cached
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
if filters.any?
|
140
|
-
environment.logical_paths do |logical_path, filename|
|
141
|
-
if filters.any? { |f| f.call(logical_path, filename) }
|
142
|
-
environment.find_all_linked_assets(filename) do |asset|
|
143
|
-
yield asset
|
144
|
-
end
|
123
|
+
promises = args.flatten.map do |path|
|
124
|
+
Concurrent::Promise.execute(executor: executor) do
|
125
|
+
environment.find_all_linked_assets(path) do |asset|
|
126
|
+
yield asset
|
145
127
|
end
|
146
128
|
end
|
147
129
|
end
|
130
|
+
promises.each(&:wait!)
|
148
131
|
|
149
132
|
nil
|
150
133
|
end
|
@@ -167,7 +150,7 @@ module Sprockets
|
|
167
150
|
end
|
168
151
|
end
|
169
152
|
|
170
|
-
# Compile
|
153
|
+
# Compile asset to directory. The asset is written to a
|
171
154
|
# fingerprinted filename like
|
172
155
|
# `application-2e8e9a7c6b0aafa0c9bdeec90ea30213.js`. An entry is
|
173
156
|
# also inserted into the manifest file.
|
@@ -179,14 +162,19 @@ module Sprockets
|
|
179
162
|
raise Error, "manifest requires environment for compilation"
|
180
163
|
end
|
181
164
|
|
182
|
-
filenames
|
183
|
-
|
184
|
-
concurrent_writers = []
|
165
|
+
filenames = []
|
166
|
+
concurrent_exporters = []
|
185
167
|
|
168
|
+
assets_to_export = Concurrent::Array.new
|
186
169
|
find(*args) do |asset|
|
170
|
+
assets_to_export << asset
|
171
|
+
end
|
172
|
+
|
173
|
+
assets_to_export.each do |asset|
|
174
|
+
mtime = Time.now.iso8601
|
187
175
|
files[asset.digest_path] = {
|
188
176
|
'logical_path' => asset.logical_path,
|
189
|
-
'mtime' =>
|
177
|
+
'mtime' => mtime,
|
190
178
|
'size' => asset.bytesize,
|
191
179
|
'digest' => asset.hexdigest,
|
192
180
|
|
@@ -197,38 +185,23 @@ module Sprockets
|
|
197
185
|
}
|
198
186
|
assets[asset.logical_path] = asset.digest_path
|
199
187
|
|
200
|
-
if alias_logical_path = self.class.compute_alias_logical_path(asset.logical_path)
|
201
|
-
assets[alias_logical_path] = asset.digest_path
|
202
|
-
end
|
203
|
-
|
204
|
-
target = File.join(dir, asset.digest_path)
|
205
|
-
|
206
|
-
if File.exist?(target)
|
207
|
-
logger.debug "Skipping #{target}, already exists"
|
208
|
-
else
|
209
|
-
logger.info "Writing #{target}"
|
210
|
-
write_file = Concurrent::Future.execute { asset.write_to target }
|
211
|
-
concurrent_writers << write_file
|
212
|
-
end
|
213
188
|
filenames << asset.filename
|
214
189
|
|
215
|
-
|
216
|
-
|
217
|
-
|
190
|
+
promise = nil
|
191
|
+
exporters_for_asset(asset) do |exporter|
|
192
|
+
next if exporter.skip?(logger)
|
218
193
|
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
write_file.wait! if write_file
|
225
|
-
gzip.compress(target)
|
194
|
+
if promise.nil?
|
195
|
+
promise = Concurrent::Promise.new(executor: executor) { exporter.call }
|
196
|
+
concurrent_exporters << promise.execute
|
197
|
+
else
|
198
|
+
concurrent_exporters << promise.then { exporter.call }
|
226
199
|
end
|
227
200
|
end
|
228
|
-
|
229
201
|
end
|
230
|
-
|
231
|
-
|
202
|
+
|
203
|
+
# make sure all exporters have finished before returning the main thread
|
204
|
+
concurrent_exporters.each(&:wait!)
|
232
205
|
save
|
233
206
|
|
234
207
|
filenames
|
@@ -295,18 +268,13 @@ module Sprockets
|
|
295
268
|
def clobber
|
296
269
|
FileUtils.rm_r(directory) if File.exist?(directory)
|
297
270
|
logger.info "Removed #{directory}"
|
271
|
+
# if we have an environment clear the cache too
|
272
|
+
environment.cache.clear if environment
|
298
273
|
nil
|
299
274
|
end
|
300
275
|
|
301
276
|
# Persist manfiest back to FS
|
302
277
|
def save
|
303
|
-
if @rename_filename
|
304
|
-
logger.info "Renaming #{@filename} to #{@rename_filename}"
|
305
|
-
FileUtils.mv(@filename, @rename_filename)
|
306
|
-
@filename = @rename_filename
|
307
|
-
@rename_filename = nil
|
308
|
-
end
|
309
|
-
|
310
278
|
data = json_encode(@data)
|
311
279
|
FileUtils.mkdir_p File.dirname(@filename)
|
312
280
|
PathUtils.atomic_write(@filename) do |f|
|
@@ -315,6 +283,36 @@ module Sprockets
|
|
315
283
|
end
|
316
284
|
|
317
285
|
private
|
286
|
+
|
287
|
+
# Given an asset, finds all exporters that
|
288
|
+
# match its mime-type.
|
289
|
+
#
|
290
|
+
# Will yield each expoter to the passed in block.
|
291
|
+
#
|
292
|
+
# array = []
|
293
|
+
# puts asset.content_type # => "application/javascript"
|
294
|
+
# exporters_for_asset(asset) do |exporter|
|
295
|
+
# array << exporter
|
296
|
+
# end
|
297
|
+
# # puts array => [Exporters::FileExporter, Exporters::ZlibExporter]
|
298
|
+
def exporters_for_asset(asset)
|
299
|
+
exporters = [Exporters::FileExporter]
|
300
|
+
|
301
|
+
environment.exporters.each do |mime_type, exporter_list|
|
302
|
+
next unless asset.content_type
|
303
|
+
next unless environment.match_mime_type? asset.content_type, mime_type
|
304
|
+
exporter_list.each do |exporter|
|
305
|
+
exporters << exporter
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
exporters.uniq!
|
310
|
+
|
311
|
+
exporters.each do |exporter|
|
312
|
+
yield exporter.new(asset: asset, environment: environment, directory: dir)
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
318
316
|
def json_decode(obj)
|
319
317
|
JSON.parse(obj, create_additions: false)
|
320
318
|
end
|
@@ -332,5 +330,9 @@ module Sprockets
|
|
332
330
|
logger
|
333
331
|
end
|
334
332
|
end
|
333
|
+
|
334
|
+
def executor
|
335
|
+
@executor ||= environment.export_concurrent ? :fast : :immediate
|
336
|
+
end
|
335
337
|
end
|
336
338
|
end
|
@@ -1,4 +1,6 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'securerandom'
|
3
|
+
require 'logger'
|
2
4
|
|
3
5
|
module Sprockets
|
4
6
|
# Public: Manifest utilities.
|
@@ -6,7 +8,6 @@ module Sprockets
|
|
6
8
|
extend self
|
7
9
|
|
8
10
|
MANIFEST_RE = /^\.sprockets-manifest-[0-9a-f]{32}.json$/
|
9
|
-
LEGACY_MANIFEST_RE = /^manifest(-[0-9a-f]{32})?.json$/
|
10
11
|
|
11
12
|
# Public: Generate a new random manifest path.
|
12
13
|
#
|
@@ -33,12 +34,14 @@ module Sprockets
|
|
33
34
|
# # => "/app/public/assets/.sprockets-manifest-abc123.json"
|
34
35
|
#
|
35
36
|
# Returns String filename.
|
36
|
-
def find_directory_manifest(dirname)
|
37
|
+
def find_directory_manifest(dirname, logger = Logger.new($stderr))
|
37
38
|
entries = File.directory?(dirname) ? Dir.entries(dirname) : []
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
manifest_entries = entries.select { |e| e =~ MANIFEST_RE }
|
40
|
+
if manifest_entries.length > 1
|
41
|
+
manifest_entries.sort!
|
42
|
+
logger.warn("Found multiple manifests: #{manifest_entries}. Choosing the first alphabetically: #{manifest_entries.first}")
|
43
|
+
end
|
44
|
+
entry = manifest_entries.first || generate_manifest_path
|
42
45
|
File.join(dirname, entry)
|
43
46
|
end
|
44
47
|
end
|
data/lib/sprockets/mime.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'sprockets/encoding_utils'
|
2
3
|
require 'sprockets/http_utils'
|
3
4
|
require 'sprockets/utils'
|
@@ -36,29 +37,18 @@ module Sprockets
|
|
36
37
|
|
37
38
|
# Public: Register a new mime type.
|
38
39
|
#
|
39
|
-
# mime_type
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
# See EncodingUtils.
|
40
|
+
# mime_type - String MIME Type
|
41
|
+
# extensions - Array of String extnames
|
42
|
+
# charset - Proc/Method that detects the charset of a file.
|
43
|
+
# See EncodingUtils.
|
44
44
|
#
|
45
45
|
# Returns nothing.
|
46
|
-
def register_mime_type(mime_type,
|
47
|
-
|
48
|
-
if options.is_a?(String)
|
49
|
-
options = { extensions: [options] }
|
50
|
-
end
|
51
|
-
|
52
|
-
extnames = Array(options[:extensions]).map { |extname|
|
53
|
-
Sprockets::Utils.normalize_extension(extname)
|
54
|
-
}
|
46
|
+
def register_mime_type(mime_type, extensions: [], charset: nil)
|
47
|
+
extnames = Array(extensions)
|
55
48
|
|
56
|
-
charset = options[:charset]
|
57
49
|
charset ||= :default if mime_type.start_with?('text/')
|
58
50
|
charset = EncodingUtils::CHARSET_DETECT[charset] if charset.is_a?(Symbol)
|
59
51
|
|
60
|
-
self.computed_config = {}
|
61
|
-
|
62
52
|
self.config = hash_reassoc(config, :mime_exts) do |mime_exts|
|
63
53
|
extnames.each do |extname|
|
64
54
|
mime_exts[extname] = mime_type
|
@@ -97,34 +87,10 @@ module Sprockets
|
|
97
87
|
data = File.binread(filename)
|
98
88
|
|
99
89
|
if detect = mime_type_charset_detecter(content_type)
|
100
|
-
detect.call(data).encode(Encoding::UTF_8, :
|
90
|
+
detect.call(data).encode(Encoding::UTF_8, universal_newline: true)
|
101
91
|
else
|
102
92
|
data
|
103
93
|
end
|
104
94
|
end
|
105
|
-
|
106
|
-
private
|
107
|
-
def extname_map
|
108
|
-
self.computed_config[:_extnames] ||= compute_extname_map
|
109
|
-
end
|
110
|
-
|
111
|
-
def compute_extname_map
|
112
|
-
graph = {}
|
113
|
-
|
114
|
-
([nil] + pipelines.keys.map(&:to_s)).each do |pipeline|
|
115
|
-
pipeline_extname = ".#{pipeline}" if pipeline
|
116
|
-
([[nil, nil]] + config[:mime_exts].to_a).each do |format_extname, format_type|
|
117
|
-
4.times do |n|
|
118
|
-
config[:engines].keys.permutation(n).each do |engine_extnames|
|
119
|
-
key = "#{pipeline_extname}#{format_extname}#{engine_extnames.join}"
|
120
|
-
type = format_type || config[:engine_mime_types][engine_extnames.first]
|
121
|
-
graph[key] = {type: type, engines: engine_extnames, pipeline: pipeline}
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
graph
|
128
|
-
end
|
129
95
|
end
|
130
96
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Sprockets
|
5
|
+
module Npm
|
6
|
+
# Internal: Override resolve_alternates to install package.json behavior.
|
7
|
+
#
|
8
|
+
# load_path - String environment path
|
9
|
+
# logical_path - String path relative to base
|
10
|
+
#
|
11
|
+
# Returns candiate filenames.
|
12
|
+
def resolve_alternates(load_path, logical_path)
|
13
|
+
candidates, deps = super
|
14
|
+
|
15
|
+
dirname = File.join(load_path, logical_path)
|
16
|
+
|
17
|
+
if directory?(dirname)
|
18
|
+
filename = File.join(dirname, 'package.json')
|
19
|
+
|
20
|
+
if self.file?(filename)
|
21
|
+
deps << build_file_digest_uri(filename)
|
22
|
+
read_package_directives(dirname, filename) do |path|
|
23
|
+
if file?(path)
|
24
|
+
candidates << path
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
return candidates, deps
|
31
|
+
end
|
32
|
+
|
33
|
+
# Internal: Read package.json's main and style directives.
|
34
|
+
#
|
35
|
+
# dirname - String path to component directory.
|
36
|
+
# filename - String path to package.json.
|
37
|
+
#
|
38
|
+
# Returns nothing.
|
39
|
+
def read_package_directives(dirname, filename)
|
40
|
+
package = JSON.parse(File.read(filename), create_additions: false)
|
41
|
+
|
42
|
+
case package['main']
|
43
|
+
when String
|
44
|
+
yield File.expand_path(package['main'], dirname)
|
45
|
+
when nil
|
46
|
+
yield File.expand_path('index.js', dirname)
|
47
|
+
end
|
48
|
+
|
49
|
+
yield File.expand_path(package['style'], dirname) if package['style']
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'set'
|
2
3
|
require 'sprockets/path_utils'
|
3
4
|
require 'sprockets/uri_utils'
|
@@ -41,7 +42,7 @@ module Sprockets
|
|
41
42
|
#
|
42
43
|
# Returns an Array of entry names and a Set of dependency URIs.
|
43
44
|
def entries_with_dependencies(path)
|
44
|
-
return entries(path),
|
45
|
+
return entries(path), Set.new([build_file_digest_uri(path)])
|
45
46
|
end
|
46
47
|
|
47
48
|
# Internal: List directory filenames and associated Stats under a
|
@@ -53,16 +54,7 @@ module Sprockets
|
|
53
54
|
#
|
54
55
|
# Returns an Array of filenames and a Set of dependency URIs.
|
55
56
|
def stat_directory_with_dependencies(dir)
|
56
|
-
return stat_directory(dir).to_a,
|
57
|
-
end
|
58
|
-
|
59
|
-
# Internal: Returns a set of dependencies for a particular path.
|
60
|
-
#
|
61
|
-
# path - String directory path
|
62
|
-
#
|
63
|
-
# Returns a Set of dependency URIs.
|
64
|
-
def file_digest_dependency_set(path)
|
65
|
-
Set.new([build_file_digest_uri(path)])
|
57
|
+
return stat_directory(dir).to_a, Set.new([build_file_digest_uri(dir)])
|
66
58
|
end
|
67
59
|
|
68
60
|
# Internal: List directory filenames and associated Stats under an entire
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'sprockets/digest_utils'
|
2
3
|
require 'sprockets/path_utils'
|
3
4
|
|
@@ -15,7 +16,7 @@ module Sprockets
|
|
15
16
|
def stat_digest(path, stat)
|
16
17
|
if stat.directory?
|
17
18
|
# If its a directive, digest the list of filenames
|
18
|
-
digest_class.digest(self.entries(path).join(','))
|
19
|
+
digest_class.digest(self.entries(path).join(','.freeze))
|
19
20
|
elsif stat.file?
|
20
21
|
# If its a file, digest the contents
|
21
22
|
digest_class.file(path.to_s).digest
|
data/lib/sprockets/path_utils.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Sprockets
|
2
3
|
# Internal: File and path related utilities. Mixed into Environment.
|
3
4
|
#
|
@@ -5,6 +6,7 @@ module Sprockets
|
|
5
6
|
# when code actually wants to reference ::FileUtils.
|
6
7
|
module PathUtils
|
7
8
|
extend self
|
9
|
+
require 'pathname'
|
8
10
|
|
9
11
|
# Public: Like `File.stat`.
|
10
12
|
#
|
@@ -53,13 +55,14 @@ module Sprockets
|
|
53
55
|
# Returns an empty `Array` if the directory does not exist.
|
54
56
|
def entries(path)
|
55
57
|
if File.directory?(path)
|
56
|
-
entries = Dir.entries(path, :
|
58
|
+
entries = Dir.entries(path, encoding: Encoding.default_internal)
|
57
59
|
entries.reject! { |entry|
|
58
60
|
entry.start_with?(".".freeze) ||
|
59
61
|
(entry.start_with?("#".freeze) && entry.end_with?("#".freeze)) ||
|
60
62
|
entry.end_with?("~".freeze)
|
61
63
|
}
|
62
64
|
entries.sort!
|
65
|
+
entries
|
63
66
|
else
|
64
67
|
[]
|
65
68
|
end
|
@@ -71,8 +74,6 @@ module Sprockets
|
|
71
74
|
#
|
72
75
|
# Returns true if path is absolute, otherwise false.
|
73
76
|
if File::ALT_SEPARATOR
|
74
|
-
require 'pathname'
|
75
|
-
|
76
77
|
# On Windows, ALT_SEPARATOR is \
|
77
78
|
# Delegate to Pathname since the logic gets complex.
|
78
79
|
def absolute_path?(path)
|
@@ -80,7 +81,7 @@ module Sprockets
|
|
80
81
|
end
|
81
82
|
else
|
82
83
|
def absolute_path?(path)
|
83
|
-
path
|
84
|
+
path.start_with?(File::SEPARATOR)
|
84
85
|
end
|
85
86
|
end
|
86
87
|
|
@@ -97,7 +98,58 @@ module Sprockets
|
|
97
98
|
#
|
98
99
|
# Returns true if path is relative, otherwise false.
|
99
100
|
def relative_path?(path)
|
100
|
-
path
|
101
|
+
path.match?(/^\.\.?($|#{SEPARATOR_PATTERN})/) ? true : false
|
102
|
+
end
|
103
|
+
|
104
|
+
# Public: Get relative path from `start` to `dest`.
|
105
|
+
#
|
106
|
+
# start - String start path (file or dir)
|
107
|
+
# dest - String destination path
|
108
|
+
#
|
109
|
+
# Returns relative String path from `start` to `dest`
|
110
|
+
def relative_path_from(start, dest)
|
111
|
+
start, dest = Pathname.new(start), Pathname.new(dest)
|
112
|
+
start = start.dirname unless start.directory?
|
113
|
+
dest.relative_path_from(start).to_s
|
114
|
+
end
|
115
|
+
|
116
|
+
# Public: Joins path to base path.
|
117
|
+
#
|
118
|
+
# base - Root path
|
119
|
+
# path - Extending path
|
120
|
+
#
|
121
|
+
# Example
|
122
|
+
#
|
123
|
+
# join('base/path/', '../file.js')
|
124
|
+
# # => 'base/file.js'
|
125
|
+
#
|
126
|
+
# Returns string path starting from base and ending at path
|
127
|
+
def join(base, path)
|
128
|
+
(Pathname.new(base) + path).to_s
|
129
|
+
end
|
130
|
+
|
131
|
+
# Public: Sets pipeline for path
|
132
|
+
#
|
133
|
+
# path - String path
|
134
|
+
# extensions - List of file extensions
|
135
|
+
# pipeline - Pipeline
|
136
|
+
#
|
137
|
+
# Examples
|
138
|
+
#
|
139
|
+
# set_pipeline('path/file.js.erb', config[:mime_exts], config[:pipeline_exts], :source)
|
140
|
+
# # => 'path/file.source.js.erb'
|
141
|
+
#
|
142
|
+
# set_pipeline('path/some.file.source.js.erb', config[:mime_exts], config[:pipeline_exts], :debug)
|
143
|
+
# # => 'path/some.file.debug.js.erb'
|
144
|
+
#
|
145
|
+
# Returns string path with pipeline parsed in
|
146
|
+
def set_pipeline(path, mime_exts, pipeline_exts, pipeline)
|
147
|
+
extension, _ = match_path_extname(path, mime_exts)
|
148
|
+
path.chomp!(extension)
|
149
|
+
pipeline_old, _ = match_path_extname(path, pipeline_exts)
|
150
|
+
path.chomp!(pipeline_old)
|
151
|
+
|
152
|
+
"#{path}.#{pipeline}#{extension}"
|
101
153
|
end
|
102
154
|
|
103
155
|
# Internal: Get relative path for root path and subpath.
|
@@ -109,7 +161,7 @@ module Sprockets
|
|
109
161
|
# subpath is outside of path.
|
110
162
|
def split_subpath(path, subpath)
|
111
163
|
return "" if path == subpath
|
112
|
-
path = File.join(path, '')
|
164
|
+
path = File.join(path, ''.freeze)
|
113
165
|
if subpath.start_with?(path)
|
114
166
|
subpath[path.length..-1]
|
115
167
|
else
|
@@ -163,6 +215,34 @@ module Sprockets
|
|
163
215
|
nil
|
164
216
|
end
|
165
217
|
|
218
|
+
# Internal: Match paths in a directory against available extensions.
|
219
|
+
#
|
220
|
+
# path - String directory
|
221
|
+
# basename - String basename of target file
|
222
|
+
# extensions - Hash of String extnames to values
|
223
|
+
#
|
224
|
+
# Examples
|
225
|
+
#
|
226
|
+
# exts = { ".js" => "application/javascript" }
|
227
|
+
# find_matching_path_for_extensions("app/assets", "application", exts)
|
228
|
+
# # => ["app/assets/application.js", "application/javascript"]
|
229
|
+
#
|
230
|
+
# Returns an Array of [String path, Object value] matches.
|
231
|
+
def find_matching_path_for_extensions(path, basename, extensions)
|
232
|
+
matches = []
|
233
|
+
entries(path).each do |entry|
|
234
|
+
next unless File.basename(entry).start_with?(basename)
|
235
|
+
extname, value = match_path_extname(entry, extensions)
|
236
|
+
if basename == entry.chomp(extname)
|
237
|
+
filename = File.join(path, entry)
|
238
|
+
if file?(filename)
|
239
|
+
matches << [filename, value]
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
matches
|
244
|
+
end
|
245
|
+
|
166
246
|
# Internal: Returns all parents for path
|
167
247
|
#
|
168
248
|
# path - String absolute filename or directory
|
@@ -272,7 +352,7 @@ module Sprockets
|
|
272
352
|
Thread.current.object_id,
|
273
353
|
Process.pid,
|
274
354
|
rand(1000000)
|
275
|
-
].join('.')
|
355
|
+
].join('.'.freeze)
|
276
356
|
tmpname = File.join(dirname, basename)
|
277
357
|
|
278
358
|
File.open(tmpname, 'wb+') do |f|
|