bpm 1.0.0.beta.8 → 1.0.0.beta.9
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/CHANGELOG.md +9 -0
- data/bpm.gemspec +2 -7
- data/lib/bpm/pipeline/generated_asset.rb +19 -21
- data/lib/bpm/pipeline/plugin_context.rb +7 -7
- data/lib/bpm/pipeline/plugin_processor.rb +11 -20
- data/lib/bpm/pipeline/transport_processor.rb +8 -13
- data/lib/bpm/pipeline.rb +47 -42
- data/lib/bpm/project_generator.rb +2 -2
- data/lib/bpm/version.rb +1 -1
- data/lib/bpm.rb +0 -3
- data/spec/cli/init_spec.rb +48 -48
- data/spec/cli/rebuild_spec.rb +30 -30
- data/spec/fixtures/projects/init_app/assets/bpm_libs.js +1 -1
- data/spec/fixtures/projects/init_app/assets/bpm_styles.css +1 -1
- data/spec/fixtures/projects/init_default/assets/bpm_libs.js +1 -1
- data/spec/fixtures/projects/init_default/assets/bpm_styles.css +1 -1
- data/spec/plugins/minifier_spec.rb +8 -8
- data/templates/project/index.html +0 -2
- data/templates/project/{app → lib}/main.js +0 -0
- metadata +24 -209
- data/.gitmodules +0 -3
- data/vendor/sprockets/.gitignore +0 -7
- data/vendor/sprockets/.travis.yml +0 -7
- data/vendor/sprockets/Gemfile +0 -2
- data/vendor/sprockets/LICENSE +0 -20
- data/vendor/sprockets/README.md +0 -22
- data/vendor/sprockets/Rakefile +0 -8
- data/vendor/sprockets/lib/sprockets/asset.rb +0 -198
- data/vendor/sprockets/lib/sprockets/asset_attributes.rb +0 -178
- data/vendor/sprockets/lib/sprockets/base.rb +0 -134
- data/vendor/sprockets/lib/sprockets/bundled_asset.rb +0 -249
- data/vendor/sprockets/lib/sprockets/cache/file_store.rb +0 -41
- data/vendor/sprockets/lib/sprockets/caching.rb +0 -126
- data/vendor/sprockets/lib/sprockets/charset_normalizer.rb +0 -41
- data/vendor/sprockets/lib/sprockets/context.rb +0 -221
- data/vendor/sprockets/lib/sprockets/digest.rb +0 -73
- data/vendor/sprockets/lib/sprockets/directive_processor.rb +0 -397
- data/vendor/sprockets/lib/sprockets/eco_template.rb +0 -38
- data/vendor/sprockets/lib/sprockets/ejs_template.rb +0 -37
- data/vendor/sprockets/lib/sprockets/engines.rb +0 -117
- data/vendor/sprockets/lib/sprockets/environment.rb +0 -94
- data/vendor/sprockets/lib/sprockets/errors.rb +0 -17
- data/vendor/sprockets/lib/sprockets/index.rb +0 -81
- data/vendor/sprockets/lib/sprockets/jst_processor.rb +0 -26
- data/vendor/sprockets/lib/sprockets/mime.rb +0 -38
- data/vendor/sprockets/lib/sprockets/processing.rb +0 -269
- data/vendor/sprockets/lib/sprockets/processor.rb +0 -32
- data/vendor/sprockets/lib/sprockets/safety_colons.rb +0 -28
- data/vendor/sprockets/lib/sprockets/server.rb +0 -270
- data/vendor/sprockets/lib/sprockets/static_asset.rb +0 -86
- data/vendor/sprockets/lib/sprockets/static_compilation.rb +0 -74
- data/vendor/sprockets/lib/sprockets/trail.rb +0 -123
- data/vendor/sprockets/lib/sprockets/utils.rb +0 -67
- data/vendor/sprockets/lib/sprockets/version.rb +0 -3
- data/vendor/sprockets/lib/sprockets.rb +0 -31
- data/vendor/sprockets/sprockets.gemspec +0 -30
- data/vendor/sprockets/test/fixtures/asset/POW.png +0 -0
- data/vendor/sprockets/test/fixtures/asset/application.js +0 -6
- data/vendor/sprockets/test/fixtures/asset/bar-utf8.css +0 -2
- data/vendor/sprockets/test/fixtures/asset/charset.css +0 -2
- data/vendor/sprockets/test/fixtures/asset/circle/a.js +0 -2
- data/vendor/sprockets/test/fixtures/asset/circle/b.js +0 -2
- data/vendor/sprockets/test/fixtures/asset/circle/c.js +0 -2
- data/vendor/sprockets/test/fixtures/asset/compat.js +0 -4
- data/vendor/sprockets/test/fixtures/asset/constants.js +0 -2
- data/vendor/sprockets/test/fixtures/asset/constants.yml +0 -1
- data/vendor/sprockets/test/fixtures/asset/default_mime_type.js +0 -1
- data/vendor/sprockets/test/fixtures/asset/filename.js.erb +0 -1
- data/vendor/sprockets/test/fixtures/asset/foo-utf8.css +0 -2
- data/vendor/sprockets/test/fixtures/asset/included_header.js +0 -4
- data/vendor/sprockets/test/fixtures/asset/jquery.tmpl.min.js +0 -1
- data/vendor/sprockets/test/fixtures/asset/mismatch.js +0 -1
- data/vendor/sprockets/test/fixtures/asset/multiple.js +0 -2
- data/vendor/sprockets/test/fixtures/asset/multipleengine.js +0 -1
- data/vendor/sprockets/test/fixtures/asset/noengine.js +0 -1
- data/vendor/sprockets/test/fixtures/asset/noformat.coffee +0 -1
- data/vendor/sprockets/test/fixtures/asset/one.css +0 -1
- data/vendor/sprockets/test/fixtures/asset/oneengine.js +0 -1
- data/vendor/sprockets/test/fixtures/asset/project.css +0 -1
- data/vendor/sprockets/test/fixtures/asset/project.js.erb +0 -4
- data/vendor/sprockets/test/fixtures/asset/relative/include.js +0 -4
- data/vendor/sprockets/test/fixtures/asset/relative/require.js +0 -1
- data/vendor/sprockets/test/fixtures/asset/relative/require_outside_path.js +0 -1
- data/vendor/sprockets/test/fixtures/asset/require_self.css +0 -9
- data/vendor/sprockets/test/fixtures/asset/require_self_twice.css +0 -8
- data/vendor/sprockets/test/fixtures/asset/semicolons/bar.js +0 -1
- data/vendor/sprockets/test/fixtures/asset/semicolons/index.js +0 -5
- data/vendor/sprockets/test/fixtures/asset/sprite.css.erb +0 -12
- data/vendor/sprockets/test/fixtures/asset/tree/all/b/c/d.js +0 -2
- data/vendor/sprockets/test/fixtures/asset/tree/all/b/c/e.js +0 -1
- data/vendor/sprockets/test/fixtures/asset/tree/all/b/c.js +0 -1
- data/vendor/sprockets/test/fixtures/asset/tree/all/b.css +0 -2
- data/vendor/sprockets/test/fixtures/asset/tree/all/b.js.erb +0 -1
- data/vendor/sprockets/test/fixtures/asset/tree/all/d/c.js.coffee +0 -1
- data/vendor/sprockets/test/fixtures/asset/tree/all/d/e.js +0 -1
- data/vendor/sprockets/test/fixtures/asset/tree/all_with_require.js +0 -7
- data/vendor/sprockets/test/fixtures/asset/tree/all_with_require_directory.js +0 -1
- data/vendor/sprockets/test/fixtures/asset/tree/all_with_require_tree.js +0 -2
- data/vendor/sprockets/test/fixtures/asset/tree/directory/application.js +0 -2
- data/vendor/sprockets/test/fixtures/asset/tree/directory/bar.js +0 -1
- data/vendor/sprockets/test/fixtures/asset/tree/directory/foo.js +0 -1
- data/vendor/sprockets/test/fixtures/asset/tree/tree/application.js +0 -2
- data/vendor/sprockets/test/fixtures/asset/tree/tree/bar.js +0 -1
- data/vendor/sprockets/test/fixtures/asset/tree/tree/foo.js +0 -1
- data/vendor/sprockets/test/fixtures/asset/tree/with_logical_path/a/a.js +0 -1
- data/vendor/sprockets/test/fixtures/asset/tree/with_logical_path/require_tree_with_logical_path.js +0 -1
- data/vendor/sprockets/test/fixtures/asset/tree/without_argument/a.js +0 -1
- data/vendor/sprockets/test/fixtures/asset/tree/without_argument/b.js +0 -1
- data/vendor/sprockets/test/fixtures/asset/tree/without_argument/require_tree_without_argument.js +0 -1
- data/vendor/sprockets/test/fixtures/asset/two.css +0 -1
- data/vendor/sprockets/test/fixtures/asset/unicode.js +0 -2
- data/vendor/sprockets/test/fixtures/asset/unknownexts.min.js +0 -2
- data/vendor/sprockets/test/fixtures/asset/users.js.erb.str +0 -4
- data/vendor/sprockets/test/fixtures/context/POW.png +0 -0
- data/vendor/sprockets/test/fixtures/context/application.js.yml +0 -3
- data/vendor/sprockets/test/fixtures/context/bar.js +0 -1
- data/vendor/sprockets/test/fixtures/context/foo.js +0 -2
- data/vendor/sprockets/test/fixtures/context/helpers.css.erb +0 -3
- data/vendor/sprockets/test/fixtures/context/properties.js.erb +0 -7
- data/vendor/sprockets/test/fixtures/context/require_glob.js +0 -1
- data/vendor/sprockets/test/fixtures/context/resolve_content_type.js.erb +0 -4
- data/vendor/sprockets/test/fixtures/context/sprite.css.embed +0 -3
- data/vendor/sprockets/test/fixtures/default/application.js.coffee +0 -4
- data/vendor/sprockets/test/fixtures/default/blank.gif +0 -0
- data/vendor/sprockets/test/fixtures/default/coffee/foo.coffee +0 -1
- data/vendor/sprockets/test/fixtures/default/coffee/index.js +0 -3
- data/vendor/sprockets/test/fixtures/default/empty +0 -0
- data/vendor/sprockets/test/fixtures/default/gallery.css.erb +0 -3
- data/vendor/sprockets/test/fixtures/default/gallery.js +0 -1
- data/vendor/sprockets/test/fixtures/default/goodbye.jst.eco +0 -1
- data/vendor/sprockets/test/fixtures/default/hello.jst.ejs +0 -1
- data/vendor/sprockets/test/fixtures/default/hello.txt +0 -1
- data/vendor/sprockets/test/fixtures/default/interpolation.js +0 -1
- data/vendor/sprockets/test/fixtures/default/missing_require.js +0 -1
- data/vendor/sprockets/test/fixtures/default/mobile/a.js +0 -1
- data/vendor/sprockets/test/fixtures/default/mobile/b.js +0 -1
- data/vendor/sprockets/test/fixtures/default/mobile/c.css +0 -1
- data/vendor/sprockets/test/fixtures/default/mobile/d.css +0 -1
- data/vendor/sprockets/test/fixtures/default/mobile/index.css +0 -3
- data/vendor/sprockets/test/fixtures/default/mobile/index.js +0 -1
- data/vendor/sprockets/test/fixtures/default/noreturn.js +0 -1
- data/vendor/sprockets/test/fixtures/default/project.js.coffee.erb +0 -2
- data/vendor/sprockets/test/fixtures/default/with_data_uri.css.erb +0 -3
- data/vendor/sprockets/test/fixtures/directives/code_before_comment +0 -3
- data/vendor/sprockets/test/fixtures/directives/comment_without_directives +0 -6
- data/vendor/sprockets/test/fixtures/directives/directive_word_splitting +0 -6
- data/vendor/sprockets/test/fixtures/directives/directives_after_header +0 -16
- data/vendor/sprockets/test/fixtures/directives/double_slash +0 -9
- data/vendor/sprockets/test/fixtures/directives/hash +0 -8
- data/vendor/sprockets/test/fixtures/directives/no_header +0 -2
- data/vendor/sprockets/test/fixtures/directives/slash_star +0 -10
- data/vendor/sprockets/test/fixtures/directives/slash_star_single +0 -4
- data/vendor/sprockets/test/fixtures/directives/space_between_directive_word +0 -2
- data/vendor/sprockets/test/fixtures/directives/triple_hash +0 -10
- data/vendor/sprockets/test/fixtures/encoding/ascii.js +0 -1
- data/vendor/sprockets/test/fixtures/encoding/ascii_utf8.js +0 -2
- data/vendor/sprockets/test/fixtures/encoding/utf16.js +0 -0
- data/vendor/sprockets/test/fixtures/encoding/utf8.js +0 -1
- data/vendor/sprockets/test/fixtures/encoding/utf8_bom.js +0 -1
- data/vendor/sprockets/test/fixtures/engines/hello.alert +0 -1
- data/vendor/sprockets/test/fixtures/engines/moo.js.str +0 -1
- data/vendor/sprockets/test/fixtures/public/compiled-digest-0aa2105d29558f3eb790d411d7d8fb66.js +0 -3
- data/vendor/sprockets/test/fixtures/public/compiled-digest-1c41eb0cf934a0c76babe875f982f9d1.js +0 -1
- data/vendor/sprockets/test/fixtures/server/app/javascripts/application.js +0 -5
- data/vendor/sprockets/test/fixtures/server/app/javascripts/bar.js +0 -1
- data/vendor/sprockets/test/fixtures/server/app/javascripts/foo.js +0 -1
- data/vendor/sprockets/test/fixtures/server/app/javascripts/hello.txt +0 -2
- data/vendor/sprockets/test/fixtures/server/app/javascripts/tree.js +0 -1
- data/vendor/sprockets/test/fixtures/server/vendor/javascripts/missing_require.js +0 -1
- data/vendor/sprockets/test/fixtures/server/vendor/stylesheets/missing_require.css +0 -1
- data/vendor/sprockets/test/sprockets_test.rb +0 -56
- data/vendor/sprockets/test/test_asset.rb +0 -699
- data/vendor/sprockets/test/test_asset_attributes.rb +0 -150
- data/vendor/sprockets/test/test_caching.rb +0 -62
- data/vendor/sprockets/test/test_context.rb +0 -115
- data/vendor/sprockets/test/test_directive_processor.rb +0 -124
- data/vendor/sprockets/test/test_encoding.rb +0 -65
- data/vendor/sprockets/test/test_engines.rb +0 -73
- data/vendor/sprockets/test/test_environment.rb +0 -587
- data/vendor/sprockets/test/test_server.rb +0 -227
@@ -1,270 +0,0 @@
|
|
1
|
-
require 'rack/request'
|
2
|
-
require 'time'
|
3
|
-
|
4
|
-
module Sprockets
|
5
|
-
# `Server` is a concern mixed into `Environment` and
|
6
|
-
# `Index` that provides a Rack compatible `call`
|
7
|
-
# interface and url generation helpers.
|
8
|
-
module Server
|
9
|
-
# `call` implements the Rack 1.x specification which accepts an
|
10
|
-
# `env` Hash and returns a three item tuple with the status code,
|
11
|
-
# headers, and body.
|
12
|
-
#
|
13
|
-
# Mapping your environment at a url prefix will serve all assets
|
14
|
-
# in the path.
|
15
|
-
#
|
16
|
-
# map "/assets" do
|
17
|
-
# run Sprockets::Environment.new
|
18
|
-
# end
|
19
|
-
#
|
20
|
-
# A request for `"/assets/foo/bar.js"` will search your
|
21
|
-
# environment for `"foo/bar.js"`.
|
22
|
-
def call(env)
|
23
|
-
start_time = Time.now.to_f
|
24
|
-
time_elapsed = lambda { ((Time.now.to_f - start_time) * 1000).to_i }
|
25
|
-
|
26
|
-
msg = "Served asset #{env['PATH_INFO']} -"
|
27
|
-
|
28
|
-
# URLs containing a `".."` are rejected for security reasons.
|
29
|
-
if forbidden_request?(env)
|
30
|
-
return forbidden_response
|
31
|
-
end
|
32
|
-
|
33
|
-
# Mark session as "skipped" so no `Set-Cookie` header is set
|
34
|
-
env['rack.session.options'] ||= {}
|
35
|
-
env['rack.session.options'][:defer] = true
|
36
|
-
env['rack.session.options'][:skip] = true
|
37
|
-
|
38
|
-
# Extract the path from everything after the leading slash
|
39
|
-
path = env['PATH_INFO'].to_s.sub(/^\//, '')
|
40
|
-
|
41
|
-
# Look up the asset.
|
42
|
-
asset = find_asset(path)
|
43
|
-
asset.to_a if asset
|
44
|
-
|
45
|
-
# `find_asset` returns nil if the asset doesn't exist
|
46
|
-
if asset.nil?
|
47
|
-
logger.info "#{msg} 404 Not Found (#{time_elapsed.call}ms)"
|
48
|
-
|
49
|
-
# Return a 404 Not Found
|
50
|
-
not_found_response
|
51
|
-
|
52
|
-
# Check request headers `HTTP_IF_MODIFIED_SINCE` and
|
53
|
-
# `HTTP_IF_NONE_MATCH` against the assets mtime and digest
|
54
|
-
elsif not_modified?(asset, env) || etag_match?(asset, env)
|
55
|
-
logger.info "#{msg} 304 Not Modified (#{time_elapsed.call}ms)"
|
56
|
-
|
57
|
-
# Return a 304 Not Modified
|
58
|
-
not_modified_response(asset, env)
|
59
|
-
|
60
|
-
else
|
61
|
-
logger.info "#{msg} 200 OK (#{time_elapsed.call}ms)"
|
62
|
-
|
63
|
-
# Return a 200 with the asset contents
|
64
|
-
ok_response(asset, env)
|
65
|
-
end
|
66
|
-
rescue Exception => e
|
67
|
-
logger.error "Error compiling asset #{path}:"
|
68
|
-
logger.error "#{e.class.name}: #{e.message}"
|
69
|
-
|
70
|
-
case content_type_of(path)
|
71
|
-
when "application/javascript"
|
72
|
-
# Re-throw JavaScript asset exceptions to the browser
|
73
|
-
logger.info "#{msg} 500 Internal Server Error\n\n"
|
74
|
-
return javascript_exception_response(e)
|
75
|
-
when "text/css"
|
76
|
-
# Display CSS asset exceptions in the browser
|
77
|
-
logger.info "#{msg} 500 Internal Server Error\n\n"
|
78
|
-
return css_exception_response(e)
|
79
|
-
else
|
80
|
-
raise
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
# `path` is a url helper that looks up an asset given a
|
85
|
-
# `logical_path` and returns a path String. By default, the
|
86
|
-
# asset's digest fingerprint is spliced into the filename.
|
87
|
-
#
|
88
|
-
# /assets/application-3676d55f84497cbeadfc614c1b1b62fc.js
|
89
|
-
#
|
90
|
-
# A third `prefix` argument can be pass along to be prepended to
|
91
|
-
# the string.
|
92
|
-
def path(logical_path, fingerprint = true, prefix = nil)
|
93
|
-
if fingerprint && asset = find_asset(logical_path.to_s.sub(/^\//, ''))
|
94
|
-
url = attributes_for(logical_path).path_with_fingerprint(asset.digest)
|
95
|
-
else
|
96
|
-
url = logical_path
|
97
|
-
end
|
98
|
-
|
99
|
-
url = File.join(prefix, url) if prefix
|
100
|
-
url = "/#{url}" unless url =~ /^\//
|
101
|
-
|
102
|
-
url
|
103
|
-
end
|
104
|
-
|
105
|
-
# Similar to `path`, `url` returns a full url given a Rack `env`
|
106
|
-
# Hash and a `logical_path`.
|
107
|
-
def url(env, logical_path, fingerprint = true, prefix = nil)
|
108
|
-
req = Rack::Request.new(env)
|
109
|
-
|
110
|
-
url = req.scheme + "://"
|
111
|
-
url << req.host
|
112
|
-
|
113
|
-
if req.scheme == "https" && req.port != 443 ||
|
114
|
-
req.scheme == "http" && req.port != 80
|
115
|
-
url << ":#{req.port}"
|
116
|
-
end
|
117
|
-
|
118
|
-
url << path(logical_path, fingerprint, prefix)
|
119
|
-
|
120
|
-
url
|
121
|
-
end
|
122
|
-
|
123
|
-
private
|
124
|
-
def forbidden_request?(env)
|
125
|
-
# Prevent access to files elsewhere on the file system
|
126
|
-
#
|
127
|
-
# http://example.org/assets/../../../etc/passwd
|
128
|
-
#
|
129
|
-
env["PATH_INFO"].include?("..")
|
130
|
-
end
|
131
|
-
|
132
|
-
# Returns a 403 Forbidden response tuple
|
133
|
-
def forbidden_response
|
134
|
-
[ 403, { "Content-Type" => "text/plain", "Content-Length" => "9" }, [ "Forbidden" ] ]
|
135
|
-
end
|
136
|
-
|
137
|
-
# Returns a 404 Not Found response tuple
|
138
|
-
def not_found_response
|
139
|
-
[ 404, { "Content-Type" => "text/plain", "Content-Length" => "9", "X-Cascade" => "pass" }, [ "Not found" ] ]
|
140
|
-
end
|
141
|
-
|
142
|
-
# Returns a JavaScript response that re-throws a Ruby exception
|
143
|
-
# in the browser
|
144
|
-
def javascript_exception_response(exception)
|
145
|
-
err = "#{exception.class.name}: #{exception.message}"
|
146
|
-
body = "throw Error(#{err.inspect})"
|
147
|
-
[ 200, { "Content-Type" => "application/javascript", "Content-Length" => Rack::Utils.bytesize(body).to_s }, [ body ] ]
|
148
|
-
end
|
149
|
-
|
150
|
-
# Returns a CSS response that hides all elements on the page and
|
151
|
-
# displays the exception
|
152
|
-
def css_exception_response(exception)
|
153
|
-
message = "\n#{exception.class.name}: #{exception.message}"
|
154
|
-
backtrace = "\n #{exception.backtrace.first}"
|
155
|
-
|
156
|
-
body = <<-CSS
|
157
|
-
html {
|
158
|
-
padding: 18px 36px;
|
159
|
-
}
|
160
|
-
|
161
|
-
head {
|
162
|
-
display: block;
|
163
|
-
}
|
164
|
-
|
165
|
-
body {
|
166
|
-
margin: 0;
|
167
|
-
padding: 0;
|
168
|
-
}
|
169
|
-
|
170
|
-
body > * {
|
171
|
-
display: none !important;
|
172
|
-
}
|
173
|
-
|
174
|
-
head:after, body:before, body:after {
|
175
|
-
display: block !important;
|
176
|
-
}
|
177
|
-
|
178
|
-
head:after {
|
179
|
-
font-family: sans-serif;
|
180
|
-
font-size: large;
|
181
|
-
font-weight: bold;
|
182
|
-
content: "Error compiling CSS asset";
|
183
|
-
}
|
184
|
-
|
185
|
-
body:before, body:after {
|
186
|
-
font-family: monospace;
|
187
|
-
white-space: pre-wrap;
|
188
|
-
}
|
189
|
-
|
190
|
-
body:before {
|
191
|
-
font-weight: bold;
|
192
|
-
content: "#{escape_css_content(message)}";
|
193
|
-
}
|
194
|
-
|
195
|
-
body:after {
|
196
|
-
content: "#{escape_css_content(backtrace)}";
|
197
|
-
}
|
198
|
-
CSS
|
199
|
-
|
200
|
-
[ 200, { "Content-Type" => "text/css;charset=utf-8", "Content-Length" => Rack::Utils.bytesize(body).to_s }, [ body ] ]
|
201
|
-
end
|
202
|
-
|
203
|
-
# Escape special characters for use inside a CSS content("...") string
|
204
|
-
def escape_css_content(content)
|
205
|
-
content.
|
206
|
-
gsub('\\', '\\\\005c ').
|
207
|
-
gsub("\n", '\\\\000a ').
|
208
|
-
gsub('"', '\\\\0022 ').
|
209
|
-
gsub('/', '\\\\002f ')
|
210
|
-
end
|
211
|
-
|
212
|
-
# Compare the requests `HTTP_IF_MODIFIED_SINCE` against the
|
213
|
-
# assets mtime
|
214
|
-
def not_modified?(asset, env)
|
215
|
-
env["HTTP_IF_MODIFIED_SINCE"] == asset.mtime.httpdate
|
216
|
-
end
|
217
|
-
|
218
|
-
# Compare the requests `HTTP_IF_NONE_MATCH` against the assets digest
|
219
|
-
def etag_match?(asset, env)
|
220
|
-
env["HTTP_IF_NONE_MATCH"] == etag(asset)
|
221
|
-
end
|
222
|
-
|
223
|
-
# Test if `?body=1` or `body=true` query param is set
|
224
|
-
def body_only?(env)
|
225
|
-
env["QUERY_STRING"].to_s =~ /body=(1|t)/
|
226
|
-
end
|
227
|
-
|
228
|
-
# Returns a 304 Not Modified response tuple
|
229
|
-
def not_modified_response(asset, env)
|
230
|
-
[ 304, {}, [] ]
|
231
|
-
end
|
232
|
-
|
233
|
-
# Returns a 200 OK response tuple
|
234
|
-
def ok_response(asset, env)
|
235
|
-
if body_only?(env)
|
236
|
-
[ 200, headers(env, asset, Rack::Utils.bytesize(asset.body)), [asset.body] ]
|
237
|
-
else
|
238
|
-
[ 200, headers(env, asset, asset.length), asset ]
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
|
-
def headers(env, asset, length)
|
243
|
-
Hash.new.tap do |headers|
|
244
|
-
# Set content type and length headers
|
245
|
-
headers["Content-Type"] = asset.content_type
|
246
|
-
headers["Content-Length"] = length.to_s
|
247
|
-
|
248
|
-
# Set caching headers
|
249
|
-
headers["Cache-Control"] = "public"
|
250
|
-
headers["Last-Modified"] = asset.mtime.httpdate
|
251
|
-
headers["ETag"] = etag(asset)
|
252
|
-
|
253
|
-
# If the request url contains a fingerprint, set a long
|
254
|
-
# expires on the response
|
255
|
-
if attributes_for(env["PATH_INFO"]).path_fingerprint
|
256
|
-
headers["Cache-Control"] << ", max-age=31536000"
|
257
|
-
|
258
|
-
# Otherwise set `must-revalidate` since the asset could be modified.
|
259
|
-
else
|
260
|
-
headers["Cache-Control"] << ", must-revalidate"
|
261
|
-
end
|
262
|
-
end
|
263
|
-
end
|
264
|
-
|
265
|
-
# Helper to quote the assets digest for use as an ETag.
|
266
|
-
def etag(asset)
|
267
|
-
%("#{asset.digest}")
|
268
|
-
end
|
269
|
-
end
|
270
|
-
end
|
@@ -1,86 +0,0 @@
|
|
1
|
-
require 'sprockets/asset'
|
2
|
-
require 'fileutils'
|
3
|
-
require 'zlib'
|
4
|
-
|
5
|
-
module Sprockets
|
6
|
-
# `StaticAsset`s are used for files that are served verbatim without
|
7
|
-
# any processing or concatenation. These are typical images and
|
8
|
-
# other binary files.
|
9
|
-
class StaticAsset < Asset
|
10
|
-
# Define extra attributes to be serialized.
|
11
|
-
def self.serialized_attributes
|
12
|
-
super + %w( content_type mtime length digest )
|
13
|
-
end
|
14
|
-
|
15
|
-
def initialize(environment, logical_path, pathname, digest = nil)
|
16
|
-
super(environment, logical_path, pathname)
|
17
|
-
@digest = digest
|
18
|
-
load!
|
19
|
-
end
|
20
|
-
|
21
|
-
# Returns file contents as its `body`.
|
22
|
-
def body
|
23
|
-
# File is read everytime to avoid memory bloat of large binary files
|
24
|
-
pathname.open('rb') { |f| f.read }
|
25
|
-
end
|
26
|
-
|
27
|
-
# Checks if Asset is fresh by comparing the actual mtime and
|
28
|
-
# digest to the inmemory model.
|
29
|
-
def fresh?
|
30
|
-
# Check current mtime and digest
|
31
|
-
dependency_fresh?('path' => pathname, 'mtime' => mtime, 'hexdigest' => digest)
|
32
|
-
end
|
33
|
-
|
34
|
-
# Implemented for Rack SendFile support.
|
35
|
-
def to_path
|
36
|
-
pathname.to_s
|
37
|
-
end
|
38
|
-
|
39
|
-
# `to_s` is aliased to body since static assets can't have any dependencies.
|
40
|
-
def to_s
|
41
|
-
body
|
42
|
-
end
|
43
|
-
|
44
|
-
# Save asset to disk.
|
45
|
-
def write_to(filename, options = {})
|
46
|
-
# Gzip contents if filename has '.gz'
|
47
|
-
options[:compress] ||= File.extname(filename) == '.gz'
|
48
|
-
|
49
|
-
if options[:compress]
|
50
|
-
# Open file and run it through `Zlib`
|
51
|
-
pathname.open('rb') do |rd|
|
52
|
-
File.open("#{filename}+", 'wb') do |wr|
|
53
|
-
gz = Zlib::GzipWriter.new(wr, Zlib::BEST_COMPRESSION)
|
54
|
-
buf = ""
|
55
|
-
while rd.read(16384, buf)
|
56
|
-
gz.write(buf)
|
57
|
-
end
|
58
|
-
gz.close
|
59
|
-
end
|
60
|
-
end
|
61
|
-
else
|
62
|
-
# If no compression needs to be done, we can just copy it into place.
|
63
|
-
FileUtils.cp(pathname, "#{filename}+")
|
64
|
-
end
|
65
|
-
|
66
|
-
# Atomic write
|
67
|
-
FileUtils.mv("#{filename}+", filename)
|
68
|
-
|
69
|
-
# Set mtime correctly
|
70
|
-
File.utime(mtime, mtime, filename)
|
71
|
-
|
72
|
-
nil
|
73
|
-
ensure
|
74
|
-
# Ensure tmp file gets cleaned up
|
75
|
-
FileUtils.rm("#{filename}+") if File.exist?("#{filename}+")
|
76
|
-
end
|
77
|
-
|
78
|
-
private
|
79
|
-
def load!
|
80
|
-
content_type
|
81
|
-
mtime
|
82
|
-
length
|
83
|
-
digest
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
@@ -1,74 +0,0 @@
|
|
1
|
-
require 'sprockets/static_asset'
|
2
|
-
|
3
|
-
require 'fileutils'
|
4
|
-
require 'pathname'
|
5
|
-
|
6
|
-
module Sprockets
|
7
|
-
# `Caching` is an internal mixin whose public methods are exposed on
|
8
|
-
# the `Environment` and `Index` classes.
|
9
|
-
module StaticCompilation
|
10
|
-
# `static_root` is a special path where compiled assets are served
|
11
|
-
# from. This is usually set to a `/public` or `/static` directory.
|
12
|
-
#
|
13
|
-
# In a production environment, Apache or nginx should be
|
14
|
-
# configured to serve assets from the directory.
|
15
|
-
def static_root
|
16
|
-
@static_root
|
17
|
-
end
|
18
|
-
|
19
|
-
# Assign a static root directory.
|
20
|
-
def static_root=(root)
|
21
|
-
expire_index!
|
22
|
-
@static_root = root ? Pathname.new(root) : nil
|
23
|
-
end
|
24
|
-
|
25
|
-
# `precompile` takes a like of paths, globs, or `Regexp`s to
|
26
|
-
# compile into `static_root`.
|
27
|
-
#
|
28
|
-
# precompile "application.js", "*.css", /.+\.(png|jpg)/
|
29
|
-
#
|
30
|
-
# This usually ran via a rake task.
|
31
|
-
def precompile(*paths)
|
32
|
-
raise "missing static root" unless static_root
|
33
|
-
|
34
|
-
paths.each do |path|
|
35
|
-
files.each do |logical_path|
|
36
|
-
if path.is_a?(Regexp)
|
37
|
-
# Match path against `Regexp`
|
38
|
-
next unless path.match(logical_path)
|
39
|
-
else
|
40
|
-
# Otherwise use fnmatch glob syntax
|
41
|
-
next unless File.fnmatch(path.to_s, logical_path)
|
42
|
-
end
|
43
|
-
|
44
|
-
if asset = find_asset(logical_path)
|
45
|
-
attributes = attributes_for(logical_path)
|
46
|
-
digest_path = attributes.path_with_fingerprint(asset.digest)
|
47
|
-
filename = static_root.join(digest_path)
|
48
|
-
|
49
|
-
# Ensure directory exists
|
50
|
-
FileUtils.mkdir_p filename.dirname
|
51
|
-
|
52
|
-
# Write file
|
53
|
-
asset.write_to(filename)
|
54
|
-
|
55
|
-
# Write compressed file if its a bundled asset like .js or .css
|
56
|
-
asset.write_to("#{filename}.gz") if asset.is_a?(BundledAsset)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
private
|
63
|
-
# Get all reachable files in environment path
|
64
|
-
def files
|
65
|
-
files = Set.new
|
66
|
-
paths.each do |base_path|
|
67
|
-
Dir["#{base_path}/**/*"].each do |filename|
|
68
|
-
files << attributes_for(filename).logical_path
|
69
|
-
end
|
70
|
-
end
|
71
|
-
files
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
@@ -1,123 +0,0 @@
|
|
1
|
-
require 'sprockets/errors'
|
2
|
-
require 'pathname'
|
3
|
-
|
4
|
-
module Sprockets
|
5
|
-
# `Trail` is an internal mixin whose public methods are exposed on
|
6
|
-
# the `Environment` and `Index` classes.
|
7
|
-
module Trail
|
8
|
-
# Returns `Environment` root.
|
9
|
-
#
|
10
|
-
# All relative paths are expanded with root as its base. To be
|
11
|
-
# useful set this to your applications root directory. (`Rails.root`)
|
12
|
-
def root
|
13
|
-
trail.root.dup
|
14
|
-
end
|
15
|
-
|
16
|
-
# Returns an `Array` of path `String`s.
|
17
|
-
#
|
18
|
-
# These paths will be used for asset logical path lookups.
|
19
|
-
#
|
20
|
-
# Note that a copy of the `Array` is returned so mutating will
|
21
|
-
# have no affect on the environment. See `append_path`,
|
22
|
-
# `prepend_path`, and `clear_paths`.
|
23
|
-
def paths
|
24
|
-
trail.paths.dup
|
25
|
-
end
|
26
|
-
|
27
|
-
# Prepend a `path` to the `paths` list.
|
28
|
-
#
|
29
|
-
# Paths at the end of the `Array` have the least priority.
|
30
|
-
def prepend_path(path)
|
31
|
-
expire_index!
|
32
|
-
@trail.paths.unshift(path)
|
33
|
-
end
|
34
|
-
|
35
|
-
# Append a `path` to the `paths` list.
|
36
|
-
#
|
37
|
-
# Paths at the beginning of the `Array` have a higher priority.
|
38
|
-
def append_path(path)
|
39
|
-
expire_index!
|
40
|
-
@trail.paths.push(path)
|
41
|
-
end
|
42
|
-
|
43
|
-
# Clear all paths and start fresh.
|
44
|
-
#
|
45
|
-
# There is no mechanism for reordering paths, so its best to
|
46
|
-
# completely wipe the paths list and reappend them in the order
|
47
|
-
# you want.
|
48
|
-
def clear_paths
|
49
|
-
expire_index!
|
50
|
-
@trail.paths.clear
|
51
|
-
end
|
52
|
-
|
53
|
-
# Returns an `Array` of extensions.
|
54
|
-
#
|
55
|
-
# These extensions maybe omitted from logical path searches.
|
56
|
-
#
|
57
|
-
# # => [".js", ".css", ".coffee", ".sass", ...]
|
58
|
-
#
|
59
|
-
def extensions
|
60
|
-
trail.extensions.dup
|
61
|
-
end
|
62
|
-
|
63
|
-
# Finds the expanded real path for a given logical path by
|
64
|
-
# searching the environment's paths.
|
65
|
-
#
|
66
|
-
# resolve("application.js")
|
67
|
-
# # => "/path/to/app/javascripts/application.js.coffee"
|
68
|
-
#
|
69
|
-
# A `FileNotFound` exception is raised if the file does not exist.
|
70
|
-
def resolve(logical_path, options = {})
|
71
|
-
# If a block is given, preform an iterable search
|
72
|
-
if block_given?
|
73
|
-
args = attributes_for(logical_path).search_paths + [options]
|
74
|
-
trail.find(*args) do |path|
|
75
|
-
yield Pathname.new(path)
|
76
|
-
end
|
77
|
-
else
|
78
|
-
resolve(logical_path, options) do |pathname|
|
79
|
-
return pathname
|
80
|
-
end
|
81
|
-
raise FileNotFound, "couldn't find file '#{logical_path}'"
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
protected
|
86
|
-
def trail
|
87
|
-
@trail
|
88
|
-
end
|
89
|
-
|
90
|
-
def compute_digest
|
91
|
-
digest = super
|
92
|
-
|
93
|
-
# Add paths to environment digest.
|
94
|
-
digest << trail.paths.map { |p| attributes_for(p).relativize_root }.join(',')
|
95
|
-
|
96
|
-
digest
|
97
|
-
end
|
98
|
-
|
99
|
-
def find_asset_in_path(logical_path, options = {})
|
100
|
-
# Strip fingerprint on logical path if there is one.
|
101
|
-
# Not sure how valuable this feature is...
|
102
|
-
if fingerprint = attributes_for(logical_path).path_fingerprint
|
103
|
-
pathname = resolve(logical_path.to_s.sub("-#{fingerprint}", ''))
|
104
|
-
else
|
105
|
-
pathname = resolve(logical_path)
|
106
|
-
end
|
107
|
-
rescue FileNotFound
|
108
|
-
nil
|
109
|
-
else
|
110
|
-
# Build the asset for the actual pathname
|
111
|
-
asset = build_asset(logical_path, pathname, options)
|
112
|
-
|
113
|
-
# Double check request fingerprint against actual digest
|
114
|
-
# Again, not sure if this code path is even reachable
|
115
|
-
if fingerprint && fingerprint != asset.digest
|
116
|
-
logger.error "Nonexistent asset #{logical_path} @ #{fingerprint}"
|
117
|
-
asset = nil
|
118
|
-
end
|
119
|
-
|
120
|
-
asset
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
@@ -1,67 +0,0 @@
|
|
1
|
-
module Sprockets
|
2
|
-
# `Utils`, we didn't know where else to put it!
|
3
|
-
module Utils
|
4
|
-
# If theres encoding support (aka Ruby 1.9)
|
5
|
-
if "".respond_to?(:valid_encoding?)
|
6
|
-
# Define UTF-8 BOM pattern matcher.
|
7
|
-
# Avoid using a Regexp literal because it inheirts the files
|
8
|
-
# encoding and we want to avoid syntax errors in other interpreters.
|
9
|
-
UTF8_BOM_PATTERN = Regexp.new("\\A\uFEFF".encode('utf-8'))
|
10
|
-
|
11
|
-
def self.read_unicode(pathname)
|
12
|
-
pathname.read.tap do |data|
|
13
|
-
# Eager validate the file's encoding. In most cases we
|
14
|
-
# expect it to be UTF-8 unless `default_external` is set to
|
15
|
-
# something else. An error is usually raised if the file is
|
16
|
-
# saved as UTF-16 when we expected UTF-8.
|
17
|
-
if !data.valid_encoding?
|
18
|
-
raise EncodingError, "#{pathname} has a invalid " +
|
19
|
-
"#{data.encoding} byte sequence"
|
20
|
-
|
21
|
-
# If the file is UTF-8 and theres a BOM, strip it for safe concatenation.
|
22
|
-
elsif data.encoding.name == "UTF-8" && data =~ UTF8_BOM_PATTERN
|
23
|
-
data.sub!(UTF8_BOM_PATTERN, "")
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
else
|
29
|
-
# Define UTF-8 and UTF-16 BOM pattern matchers.
|
30
|
-
# Avoid using a Regexp literal to prevent syntax errors in other interpreters.
|
31
|
-
UTF8_BOM_PATTERN = Regexp.new("\\A\\xEF\\xBB\\xBF")
|
32
|
-
UTF16_BOM_PATTERN = Regexp.new("\\A(\\xFE\\xFF|\\xFF\\xFE)")
|
33
|
-
|
34
|
-
def self.read_unicode(pathname)
|
35
|
-
pathname.read.tap do |data|
|
36
|
-
# If the file is UTF-8 and theres a BOM, strip it for safe concatenation.
|
37
|
-
if data =~ UTF8_BOM_PATTERN
|
38
|
-
data.sub!(UTF8_BOM_PATTERN, "")
|
39
|
-
|
40
|
-
# If we find a UTF-16 BOM, theres nothing we can do on
|
41
|
-
# 1.8. Only UTF-8 is supported.
|
42
|
-
elsif data =~ UTF16_BOM_PATTERN
|
43
|
-
raise EncodingError, "#{pathname} has a UTF-16 BOM. " +
|
44
|
-
"Resave the file as UTF-8 or upgrade to Ruby 1.9."
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
# Prepends a leading "." to an extension if its missing.
|
51
|
-
#
|
52
|
-
# normalize_extension("js")
|
53
|
-
# # => ".js"
|
54
|
-
#
|
55
|
-
# normalize_extension(".css")
|
56
|
-
# # => ".css"
|
57
|
-
#
|
58
|
-
def self.normalize_extension(extension)
|
59
|
-
extension = extension.to_s
|
60
|
-
if extension[/^\./]
|
61
|
-
extension
|
62
|
-
else
|
63
|
-
".#{extension}"
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
require 'sprockets/version'
|
2
|
-
|
3
|
-
module Sprockets
|
4
|
-
autoload :ArgumentError, "sprockets/errors"
|
5
|
-
autoload :Asset, "sprockets/asset"
|
6
|
-
autoload :AssetAttributes, "sprockets/asset_attributes"
|
7
|
-
autoload :BundledAsset, "sprockets/bundled_asset"
|
8
|
-
autoload :CharsetNormalizer, "sprockets/charset_normalizer"
|
9
|
-
autoload :CircularDependencyError, "sprockets/errors"
|
10
|
-
autoload :ContentTypeMismatch, "sprockets/errors"
|
11
|
-
autoload :Context, "sprockets/context"
|
12
|
-
autoload :DirectiveProcessor, "sprockets/directive_processor"
|
13
|
-
autoload :EcoTemplate, "sprockets/eco_template"
|
14
|
-
autoload :EjsTemplate, "sprockets/ejs_template"
|
15
|
-
autoload :EngineError, "sprockets/errors"
|
16
|
-
autoload :Engines, "sprockets/engines"
|
17
|
-
autoload :Environment, "sprockets/environment"
|
18
|
-
autoload :Error, "sprockets/errors"
|
19
|
-
autoload :FileNotFound, "sprockets/errors"
|
20
|
-
autoload :Index, "sprockets/index"
|
21
|
-
autoload :JstProcessor, "sprockets/jst_processor"
|
22
|
-
autoload :Processing, "sprockets/processing"
|
23
|
-
autoload :Processor, "sprockets/processor"
|
24
|
-
autoload :Server, "sprockets/server"
|
25
|
-
autoload :StaticAsset, "sprockets/static_asset"
|
26
|
-
autoload :Utils, "sprockets/utils"
|
27
|
-
|
28
|
-
module Cache
|
29
|
-
autoload :FileStore, "sprockets/cache/file_store"
|
30
|
-
end
|
31
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
unless defined? Sprockets::VERSION
|
2
|
-
$:.unshift File.expand_path("../lib", __FILE__)
|
3
|
-
require "sprockets/version"
|
4
|
-
end
|
5
|
-
|
6
|
-
Gem::Specification.new do |s|
|
7
|
-
s.name = "sprockets"
|
8
|
-
s.version = Sprockets::VERSION
|
9
|
-
s.summary = "Rack-based asset packaging system"
|
10
|
-
s.description = "Sprockets is a Rack-based asset packaging system that concatenates and serves JavaScript, CoffeeScript, CSS, LESS, Sass, and SCSS."
|
11
|
-
|
12
|
-
s.files = Dir["README.md", "LICENSE", "lib/**/*.rb"]
|
13
|
-
|
14
|
-
s.add_dependency "hike", "~> 1.1"
|
15
|
-
s.add_dependency "rack", "~> 1.0"
|
16
|
-
s.add_dependency "tilt", ["~> 1.1", "!= 1.3.0"]
|
17
|
-
|
18
|
-
s.add_development_dependency "coffee-script", "~> 2.0"
|
19
|
-
s.add_development_dependency "eco", "~> 1.0"
|
20
|
-
s.add_development_dependency "ejs", "~> 1.0"
|
21
|
-
s.add_development_dependency "execjs", "~> 1.0"
|
22
|
-
s.add_development_dependency "json"
|
23
|
-
s.add_development_dependency "rack-test"
|
24
|
-
s.add_development_dependency "rake"
|
25
|
-
|
26
|
-
s.authors = ["Sam Stephenson", "Joshua Peek"]
|
27
|
-
s.email = "sstephenson@gmail.com"
|
28
|
-
s.homepage = "http://getsprockets.org/"
|
29
|
-
s.rubyforge_project = "sprockets"
|
30
|
-
end
|
Binary file
|