rake-pipeline 0.5.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +12 -0
- data/Gemfile +1 -0
- data/README.markdown +1 -1
- data/README.yard +61 -32
- data/Rakefile +9 -0
- data/bin/rakep +1 -24
- data/lib/generators/rake/pipeline/install/install_generator.rb +70 -0
- data/lib/rake-pipeline.rb +117 -53
- data/lib/rake-pipeline/cli.rb +56 -0
- data/lib/rake-pipeline/dsl.rb +3 -140
- data/lib/rake-pipeline/dsl/pipeline_dsl.rb +168 -0
- data/lib/rake-pipeline/dsl/project_dsl.rb +108 -0
- data/lib/rake-pipeline/dynamic_file_task.rb +188 -0
- data/lib/rake-pipeline/file_wrapper.rb +1 -1
- data/lib/rake-pipeline/filter.rb +45 -15
- data/lib/rake-pipeline/filters.rb +3 -1
- data/lib/rake-pipeline/filters/{concat.rb → concat_filter.rb} +0 -0
- data/lib/rake-pipeline/filters/ordering_concat_filter.rb +38 -0
- data/lib/rake-pipeline/filters/pipeline_finalizing_filter.rb +19 -0
- data/lib/rake-pipeline/graph.rb +178 -0
- data/lib/rake-pipeline/manifest.rb +63 -0
- data/lib/rake-pipeline/manifest_entry.rb +34 -0
- data/lib/rake-pipeline/matcher.rb +65 -30
- data/lib/rake-pipeline/middleware.rb +15 -12
- data/lib/rake-pipeline/precompile.rake +8 -0
- data/lib/rake-pipeline/project.rb +280 -0
- data/lib/rake-pipeline/railtie.rb +16 -1
- data/lib/rake-pipeline/server.rb +15 -0
- data/lib/rake-pipeline/version.rb +2 -2
- data/rake-pipeline.gemspec +2 -0
- data/spec/cli_spec.rb +71 -0
- data/spec/concat_filter_spec.rb +1 -27
- data/spec/{dsl_spec.rb → dsl/pipeline_dsl_spec.rb} +32 -18
- data/spec/dsl/project_dsl_spec.rb +41 -0
- data/spec/dynamic_file_task_spec.rb +111 -0
- data/spec/encoding_spec.rb +6 -8
- data/spec/file_wrapper_spec.rb +19 -2
- data/spec/filter_spec.rb +120 -22
- data/spec/graph_spec.rb +56 -0
- data/spec/manifest_entry_spec.rb +51 -0
- data/spec/manifest_spec.rb +67 -0
- data/spec/matcher_spec.rb +35 -2
- data/spec/middleware_spec.rb +123 -75
- data/spec/ordering_concat_filter_spec.rb +39 -0
- data/spec/pipeline_spec.rb +95 -34
- data/spec/project_spec.rb +293 -0
- data/spec/rake_acceptance_spec.rb +307 -67
- data/spec/rake_tasks_spec.rb +21 -0
- data/spec/spec_helper.rb +11 -48
- data/spec/support/spec_helpers/file_utils.rb +35 -0
- data/spec/support/spec_helpers/filters.rb +16 -0
- data/spec/support/spec_helpers/input_helpers.rb +23 -0
- data/spec/support/spec_helpers/memory_file_wrapper.rb +31 -0
- data/tools/perfs +107 -0
- metadata +100 -12
data/spec/middleware_spec.rb
CHANGED
@@ -5,16 +5,6 @@ require "rack/test"
|
|
5
5
|
describe "Rake::Pipeline Middleware" do
|
6
6
|
include Rack::Test::Methods
|
7
7
|
|
8
|
-
ConcatFilter = Rake::Pipeline::SpecHelpers::Filters::ConcatFilter
|
9
|
-
|
10
|
-
class StripAssertsFilter < Rake::Pipeline::Filter
|
11
|
-
def generate_output(inputs, output)
|
12
|
-
inputs.each do |input|
|
13
|
-
output.write input.read.gsub(%r{^\s*assert\(.*\)\s*;?\s*$}m, '')
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
8
|
inputs = {
|
19
9
|
"app/javascripts/jquery.js" => "var jQuery = {};\n",
|
20
10
|
|
@@ -25,8 +15,8 @@ describe "Rake::Pipeline Middleware" do
|
|
25
15
|
HERE
|
26
16
|
|
27
17
|
"app/index.html" => "<html>HI</html>",
|
28
|
-
|
29
|
-
|
18
|
+
"app/javascripts/index.html" => "<html>JAVASCRIPT</html>",
|
19
|
+
"app/empty_dir" => nil
|
30
20
|
}
|
31
21
|
|
32
22
|
expected_output = <<-HERE.gsub(/^ {4}/, '')
|
@@ -36,114 +26,172 @@ describe "Rake::Pipeline Middleware" do
|
|
36
26
|
SC.hi = function() { console.log("hi"); };
|
37
27
|
HERE
|
38
28
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
app = lambda { |env| [404, {}, ['not found']] }
|
29
|
+
assetfile_source = <<-HERE.gsub(/^ {4}/, '')
|
30
|
+
require "#{tmp}/../support/spec_helpers/filters"
|
31
|
+
output "public"
|
43
32
|
|
44
|
-
|
45
|
-
|
33
|
+
map "/dynamic-request.js" do
|
34
|
+
[200, { "Content-Type" => "text/plain" }, ["I am dynamic!"]]
|
35
|
+
end
|
46
36
|
|
37
|
+
input "#{tmp}", "app/**/*" do
|
47
38
|
match "*.js" do
|
48
|
-
|
49
|
-
filter(StripAssertsFilter) { |input| input }
|
39
|
+
concat "javascripts/application.js"
|
40
|
+
filter(Rake::Pipeline::SpecHelpers::Filters::StripAssertsFilter) { |input| input }
|
50
41
|
end
|
51
42
|
|
52
43
|
# copy the rest
|
53
|
-
|
54
|
-
|
55
|
-
output "public"
|
44
|
+
concat { |input| input.sub(%r|^app/|, '') }
|
56
45
|
end
|
46
|
+
HERE
|
57
47
|
|
58
|
-
|
48
|
+
modified_assetfile_source = <<-HERE.gsub(/^ {4}/, '')
|
49
|
+
require "#{tmp}/../support/spec_helpers/filters"
|
50
|
+
output "public"
|
59
51
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
File.open(path, "w") { |file| file.write(string) }
|
65
|
-
else
|
66
|
-
mkdir_p path
|
52
|
+
input "#{tmp}", "app/**/*" do
|
53
|
+
match "*.js" do
|
54
|
+
concat { "javascripts/app.js" }
|
55
|
+
filter(Rake::Pipeline::SpecHelpers::Filters::StripAssertsFilter) { |input| input }
|
67
56
|
end
|
57
|
+
|
58
|
+
# copy the rest
|
59
|
+
concat { |input| input.sub(%r|^app/|, '') }
|
68
60
|
end
|
61
|
+
HERE
|
69
62
|
|
70
|
-
|
71
|
-
end
|
63
|
+
app = middleware = nil
|
72
64
|
|
73
65
|
let(:app) { middleware }
|
74
66
|
|
75
|
-
|
76
|
-
|
67
|
+
before do
|
68
|
+
assetfile_path = File.join(tmp, "Assetfile")
|
69
|
+
File.open(assetfile_path, "w") { |file| file.write(assetfile_source) }
|
77
70
|
|
78
|
-
|
79
|
-
|
71
|
+
app = lambda { |env| [404, {}, ['not found']] }
|
72
|
+
middleware = Rake::Pipeline::Middleware.new(app, assetfile_path)
|
80
73
|
end
|
81
74
|
|
82
|
-
|
83
|
-
|
75
|
+
describe "dynamic requests" do
|
76
|
+
it "returns the value from the given block for paths that have been mapped" do
|
77
|
+
get "/dynamic-request.js"
|
84
78
|
|
85
|
-
|
86
|
-
|
79
|
+
last_response.should be_ok
|
80
|
+
last_response.headers["Content-Type"].should == "text/plain"
|
81
|
+
last_response.body.should == "I am dynamic!"
|
87
82
|
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "static requests" do
|
86
|
+
before do
|
87
|
+
inputs.each do |name, string|
|
88
|
+
path = File.join(tmp, name)
|
89
|
+
if string
|
90
|
+
mkdir_p File.dirname(path)
|
91
|
+
File.open(path, "w") { |file| file.write(string) }
|
92
|
+
else
|
93
|
+
mkdir_p path
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
get "/javascripts/application.js"
|
98
|
+
end
|
99
|
+
|
100
|
+
it "returns files relative to the output directory" do
|
101
|
+
last_response.should be_ok
|
102
|
+
|
103
|
+
last_response.body.should == expected_output
|
104
|
+
last_response.headers["Content-Type"].should == "application/javascript"
|
105
|
+
end
|
106
|
+
|
107
|
+
it "updates the output when files change" do
|
108
|
+
age_existing_files
|
88
109
|
|
89
|
-
|
110
|
+
File.open(File.join(tmp, "app/javascripts/jquery.js"), "w") do |file|
|
111
|
+
file.write "var jQuery = {};\njQuery.trim = function() {};\n"
|
112
|
+
end
|
113
|
+
|
114
|
+
expected = <<-HERE.gsub(/^ {6}/, '')
|
90
115
|
var jQuery = {};
|
91
116
|
jQuery.trim = function() {};
|
92
117
|
var SC = {};
|
93
118
|
|
94
119
|
SC.hi = function() { console.log("hi"); };
|
95
|
-
|
120
|
+
HERE
|
96
121
|
|
97
|
-
|
122
|
+
get "/javascripts/application.js"
|
98
123
|
|
99
|
-
|
100
|
-
|
101
|
-
|
124
|
+
last_response.body.should == expected
|
125
|
+
last_response.headers["Content-Type"].should == "application/javascript"
|
126
|
+
end
|
102
127
|
|
103
|
-
|
104
|
-
|
128
|
+
it "updates the output when new files are added" do
|
129
|
+
age_existing_files
|
105
130
|
|
106
|
-
|
107
|
-
|
108
|
-
|
131
|
+
File.open(File.join(tmp, "app/javascripts/history.js"), "w") do |file|
|
132
|
+
file.write "var History = {};\n"
|
133
|
+
end
|
109
134
|
|
110
|
-
|
135
|
+
expected = <<-HERE.gsub(/^ {6}/, '')
|
111
136
|
var History = {};
|
112
137
|
var jQuery = {};
|
113
138
|
var SC = {};
|
114
139
|
|
115
140
|
SC.hi = function() { console.log("hi"); };
|
116
|
-
|
141
|
+
HERE
|
117
142
|
|
118
|
-
|
143
|
+
get "/javascripts/application.js"
|
119
144
|
|
120
|
-
|
121
|
-
|
122
|
-
|
145
|
+
last_response.body.should == expected
|
146
|
+
last_response.headers["Content-Type"].should == "application/javascript"
|
147
|
+
end
|
123
148
|
|
124
|
-
|
125
|
-
|
149
|
+
it "returns index.html for directories" do
|
150
|
+
get "/"
|
126
151
|
|
127
|
-
|
128
|
-
|
152
|
+
last_response.body.should == "<html>HI</html>"
|
153
|
+
last_response.headers["Content-Type"].should == "text/html"
|
129
154
|
|
130
|
-
|
155
|
+
get "/javascripts"
|
131
156
|
|
132
|
-
|
133
|
-
|
134
|
-
|
157
|
+
last_response.body.should == "<html>JAVASCRIPT</html>"
|
158
|
+
last_response.headers["Content-Type"].should == "text/html"
|
159
|
+
end
|
135
160
|
|
136
|
-
|
137
|
-
|
161
|
+
it "ignores directories without index.html" do
|
162
|
+
get "/empty_dir"
|
138
163
|
|
139
|
-
|
140
|
-
|
141
|
-
|
164
|
+
last_response.body.should == "not found"
|
165
|
+
last_response.status.should == 404
|
166
|
+
end
|
167
|
+
|
168
|
+
it "falls back to the app" do
|
169
|
+
get "/zomg.notfound"
|
170
|
+
|
171
|
+
last_response.body.should == "not found"
|
172
|
+
last_response.status.should == 404
|
173
|
+
end
|
142
174
|
|
143
|
-
|
144
|
-
|
175
|
+
it "recreates the pipeline when the Assetfile changes" do
|
176
|
+
get "/javascripts/app.js"
|
177
|
+
last_response.body.should == "not found"
|
178
|
+
last_response.status.should == 404
|
145
179
|
|
146
|
-
|
147
|
-
|
180
|
+
File.open(File.join(tmp, "Assetfile"), "w") do |file|
|
181
|
+
file.write(modified_assetfile_source)
|
182
|
+
end
|
183
|
+
|
184
|
+
expected = <<-HERE.gsub(/^ {6}/, '')
|
185
|
+
var jQuery = {};
|
186
|
+
var SC = {};
|
187
|
+
|
188
|
+
SC.hi = function() { console.log("hi"); };
|
189
|
+
HERE
|
190
|
+
|
191
|
+
get "/javascripts/app.js"
|
192
|
+
|
193
|
+
last_response.body.should == expected
|
194
|
+
last_response.headers["Content-Type"].should == "application/javascript"
|
195
|
+
end
|
148
196
|
end
|
149
197
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
describe "OrderingConcatFilter" do
|
2
|
+
MemoryFileWrapper = Rake::Pipeline::SpecHelpers::MemoryFileWrapper
|
3
|
+
|
4
|
+
let(:input_files) {
|
5
|
+
[
|
6
|
+
MemoryFileWrapper.new("/path/to/input", "first.txt", "UTF-8", "FIRST"),
|
7
|
+
MemoryFileWrapper.new("/path/to/input", "second.txt", "UTF-8", "SECOND"),
|
8
|
+
MemoryFileWrapper.new("/path/to/input", "last.txt", "UTF-8", "LAST")
|
9
|
+
]
|
10
|
+
}
|
11
|
+
|
12
|
+
let(:output_files) {
|
13
|
+
[
|
14
|
+
MemoryFileWrapper.new("/path/to/output", "all.txt", "BINARY")
|
15
|
+
]
|
16
|
+
}
|
17
|
+
|
18
|
+
let(:output_file) {
|
19
|
+
MemoryFileWrapper.files["/path/to/output/all.txt"]
|
20
|
+
}
|
21
|
+
|
22
|
+
def make_filter(ordering)
|
23
|
+
filter = Rake::Pipeline::OrderingConcatFilter.new(ordering, "all.txt")
|
24
|
+
filter.file_wrapper_class = MemoryFileWrapper
|
25
|
+
filter.input_files = input_files
|
26
|
+
filter.output_root = "/path/to/output"
|
27
|
+
filter.rake_application = Rake::Application.new
|
28
|
+
filter.generate_rake_tasks.each(&:invoke)
|
29
|
+
filter
|
30
|
+
end
|
31
|
+
|
32
|
+
it "generates output" do
|
33
|
+
filter = make_filter(["first.txt", "second.txt"])
|
34
|
+
|
35
|
+
filter.output_files.should == output_files
|
36
|
+
output_file.body.should == "FIRSTSECONDLAST"
|
37
|
+
output_file.encoding.should == "BINARY"
|
38
|
+
end
|
39
|
+
end
|
data/spec/pipeline_spec.rb
CHANGED
@@ -5,17 +5,11 @@ describe "Rake::Pipeline" do
|
|
5
5
|
let(:pipeline) { Rake::Pipeline.new }
|
6
6
|
|
7
7
|
it "accepts a input root" do
|
8
|
-
pipeline.
|
9
|
-
pipeline.
|
8
|
+
pipeline.add_input "app/assets"
|
9
|
+
pipeline.inputs["app/assets"].should == '**/*'
|
10
10
|
end
|
11
11
|
|
12
12
|
it "raises an exception on #relative_input_files if input_files are not provided" do
|
13
|
-
pipeline.input_root = "app/assets"
|
14
|
-
lambda { pipeline.input_files }.should raise_error(Rake::Pipeline::Error)
|
15
|
-
end
|
16
|
-
|
17
|
-
it "raises an exception on #relative_input_files if input_root is not provided" do
|
18
|
-
pipeline.input_glob = "app/assets/javascripts/**/*.js"
|
19
13
|
lambda { pipeline.input_files }.should raise_error(Rake::Pipeline::Error)
|
20
14
|
end
|
21
15
|
|
@@ -39,15 +33,73 @@ describe "Rake::Pipeline" do
|
|
39
33
|
pipeline.rake_application.should == Rake.application
|
40
34
|
end
|
41
35
|
|
42
|
-
|
43
|
-
|
44
|
-
|
36
|
+
describe ".build" do
|
37
|
+
it "evaluates a block against a new Pipeline" do
|
38
|
+
pipeline = Rake::Pipeline.build do
|
39
|
+
output "octopus"
|
40
|
+
end
|
41
|
+
pipeline.should be_kind_of(Rake::Pipeline)
|
42
|
+
pipeline.output_root.should == File.expand_path("octopus")
|
43
|
+
end
|
45
44
|
end
|
46
45
|
|
47
|
-
|
48
|
-
|
49
|
-
Rake::Pipeline
|
46
|
+
describe "#build" do
|
47
|
+
it "evaluates a block against an existing Pipeline" do
|
48
|
+
pipeline = Rake::Pipeline.new
|
49
|
+
pipeline.output_root = "octopus"
|
50
|
+
|
51
|
+
pipeline.build do
|
52
|
+
output "squid"
|
53
|
+
end
|
54
|
+
pipeline.output_root.should == File.expand_path("squid")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "the constructor" do
|
59
|
+
it "accepts an :inputs option" do
|
60
|
+
pipeline = Rake::Pipeline.new(:inputs => {"app/assets" => "**/*"})
|
61
|
+
pipeline.inputs.should == {"app/assets" => "**/*"}
|
62
|
+
end
|
63
|
+
|
64
|
+
it "accepts a :tmpdir option" do
|
65
|
+
pipeline = Rake::Pipeline.new(:tmpdir => "tmp")
|
66
|
+
pipeline.tmpdir.should == "tmp"
|
67
|
+
end
|
68
|
+
|
69
|
+
it "accepts an :output_root option" do
|
70
|
+
pipeline = Rake::Pipeline.new(:output_root => "public")
|
71
|
+
pipeline.output_root.should == File.expand_path("public")
|
72
|
+
end
|
73
|
+
|
74
|
+
it "accepts a :rake_application option" do
|
75
|
+
app = Rake::Application.new
|
76
|
+
pipeline = Rake::Pipeline.new(:rake_application => app)
|
77
|
+
pipeline.rake_application.should == app
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "adding filters" do
|
82
|
+
let(:filter) { ConcatFilter.new }
|
83
|
+
|
84
|
+
it "can have filters added to it" do
|
85
|
+
pipeline.add_filter filter
|
86
|
+
end
|
87
|
+
|
88
|
+
it "sets an added filter's rake_application" do
|
89
|
+
app = Rake::Application.new
|
90
|
+
pipeline.rake_application = app
|
91
|
+
pipeline.add_filter filter
|
92
|
+
filter.rake_application.should == app
|
93
|
+
end
|
94
|
+
|
95
|
+
it "sets an added filter's pipeline" do
|
96
|
+
pipeline.add_filter filter
|
97
|
+
filter.pipeline.should == pipeline
|
50
98
|
end
|
99
|
+
end
|
100
|
+
|
101
|
+
shared_examples_for "when working with input" do
|
102
|
+
include Rake::Pipeline::SpecHelpers::InputHelpers
|
51
103
|
|
52
104
|
let(:files) do
|
53
105
|
%w(javascripts/jquery.js javascripts/sproutcore.js).map do |filename|
|
@@ -55,18 +107,14 @@ describe "Rake::Pipeline" do
|
|
55
107
|
end
|
56
108
|
end
|
57
109
|
|
110
|
+
def setup_roots
|
111
|
+
pipeline.add_input "app/assets"
|
112
|
+
end
|
113
|
+
|
58
114
|
before do
|
59
115
|
Rake.application = Rake::Application.new
|
60
|
-
|
61
|
-
|
62
|
-
mkdir_p File.dirname(file.fullpath)
|
63
|
-
|
64
|
-
File.open(file.fullpath, "w") do |file|
|
65
|
-
file.write "// This is #{file.path}\n"
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
pipeline.input_root = "app/assets"
|
116
|
+
create_files(files)
|
117
|
+
setup_roots
|
70
118
|
setup_input(pipeline)
|
71
119
|
pipeline.output_root = "public"
|
72
120
|
end
|
@@ -111,8 +159,11 @@ describe "Rake::Pipeline" do
|
|
111
159
|
|
112
160
|
deps = task.prerequisites
|
113
161
|
deps.size.should == 2
|
114
|
-
|
115
|
-
|
162
|
+
|
163
|
+
root = File.expand_path(pipeline.inputs.keys.first)
|
164
|
+
|
165
|
+
deps[0].should == File.join(root, "javascripts/jquery.js")
|
166
|
+
deps[1].should == File.join(root, "javascripts/sproutcore.js")
|
116
167
|
|
117
168
|
Rake.application.tasks.size.should == 3
|
118
169
|
end
|
@@ -128,19 +179,29 @@ describe "Rake::Pipeline" do
|
|
128
179
|
end
|
129
180
|
end
|
130
181
|
|
131
|
-
describe "using
|
182
|
+
describe "when using multiple input roots" do
|
132
183
|
it_behaves_like "when working with input"
|
133
184
|
|
185
|
+
def setup_roots
|
186
|
+
pipeline.add_input File.join(tmp, 'tmp1', "app/assets"), '**/*.js'
|
187
|
+
pipeline.add_input File.join(tmp, 'tmp2', "app/assets"), '**/*.css'
|
188
|
+
end
|
189
|
+
|
134
190
|
def setup_input(pipeline)
|
135
|
-
pipeline.input_glob = "javascripts/**/*.js"
|
136
191
|
end
|
137
|
-
end
|
138
192
|
|
139
|
-
|
140
|
-
|
193
|
+
let(:files) do
|
194
|
+
f = []
|
141
195
|
|
142
|
-
|
143
|
-
|
196
|
+
%w(javascripts/jquery.js javascripts/sproutcore.js).map do |filename|
|
197
|
+
f << input_file(filename, File.join(tmp, 'tmp1', "app/assets"))
|
198
|
+
end
|
199
|
+
|
200
|
+
%w(stylesheets/jquery.css stylesheets/sproutcore.css).map do |filename|
|
201
|
+
f << input_file(filename, File.join(tmp, 'tmp2', "app/assets"))
|
202
|
+
end
|
203
|
+
|
204
|
+
f
|
144
205
|
end
|
145
206
|
end
|
146
207
|
|
@@ -149,7 +210,7 @@ describe "Rake::Pipeline" do
|
|
149
210
|
|
150
211
|
def setup_input(pipeline)
|
151
212
|
Dir.chdir("app/assets") do
|
152
|
-
files = Dir["javascripts/**/*.js"]
|
213
|
+
files = Dir["javascripts/**/*.js"].sort
|
153
214
|
wrappers = files.map do |file|
|
154
215
|
Rake::Pipeline::FileWrapper.new(File.join(tmp, "app/assets"), file)
|
155
216
|
end
|