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
@@ -2,14 +2,29 @@ require "rake-pipeline/middleware"
|
|
2
2
|
|
3
3
|
module Rake
|
4
4
|
class Pipeline
|
5
|
+
# Use Rake::Pipeline inside of Rails 3.x. To use, simply add
|
6
|
+
# Rake::Pipeline to your +Gemfile+:
|
7
|
+
#
|
8
|
+
# !!!ruby
|
9
|
+
# gem 'rake-pipeline'
|
10
|
+
#
|
11
|
+
# Then, activate it in development mode. In config/development.rb:
|
12
|
+
#
|
13
|
+
# !!!ruby
|
14
|
+
# config.rake_pipeline_enabled = true
|
15
|
+
#
|
5
16
|
class Railtie < ::Rails::Railtie
|
6
17
|
config.rake_pipeline_enabled = false
|
7
18
|
config.rake_pipeline_assetfile = 'Assetfile'
|
8
19
|
|
20
|
+
rake_tasks do
|
21
|
+
load "rake-pipeline/precompile.rake"
|
22
|
+
end
|
23
|
+
|
9
24
|
initializer "rake-pipeline.assetfile" do |app|
|
10
25
|
if config.rake_pipeline_enabled
|
11
26
|
assetfile = File.join(Rails.root, config.rake_pipeline_assetfile)
|
12
|
-
config.app_middleware.
|
27
|
+
config.app_middleware.insert ActionDispatch::Static, Rake::Pipeline::Middleware, assetfile
|
13
28
|
end
|
14
29
|
end
|
15
30
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "rake-pipeline/middleware"
|
2
|
+
require "rack/server"
|
3
|
+
|
4
|
+
module Rake
|
5
|
+
class Pipeline
|
6
|
+
class Server < Rack::Server
|
7
|
+
def app
|
8
|
+
not_found = proc { [404, { "Content-Type" => "text/plain" }, ["not found"]] }
|
9
|
+
config = "Assetfile"
|
10
|
+
|
11
|
+
Middleware.new(not_found, config)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/rake-pipeline.gemspec
CHANGED
@@ -16,6 +16,8 @@ Gem::Specification.new do |gem|
|
|
16
16
|
gem.version = Rake::Pipeline::VERSION
|
17
17
|
|
18
18
|
gem.add_dependency "rake", "~> 0.9.0"
|
19
|
+
gem.add_dependency "thor"
|
20
|
+
gem.add_dependency "json"
|
19
21
|
|
20
22
|
gem.add_development_dependency "rspec"
|
21
23
|
gem.add_development_dependency "rack-test"
|
data/spec/cli_spec.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
describe "Rake::Pipeline::CLI" do
|
2
|
+
attr_reader :project, :pipeline
|
3
|
+
|
4
|
+
before do
|
5
|
+
@project = Rake::Pipeline::Project.new
|
6
|
+
@project.stub(:clean)
|
7
|
+
@project.stub(:invoke)
|
8
|
+
@project.stub(:output_files).and_return([])
|
9
|
+
Rake::Pipeline::Project.stub(:new).and_return(@project)
|
10
|
+
end
|
11
|
+
|
12
|
+
def rakep(*args)
|
13
|
+
Rake::Pipeline::CLI.start(args)
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "build" do
|
17
|
+
context "with no arguments" do
|
18
|
+
it "invokes a project" do
|
19
|
+
project.should_receive :invoke
|
20
|
+
rakep "build"
|
21
|
+
end
|
22
|
+
|
23
|
+
it "cleans up the tmpdir" do
|
24
|
+
project.should_receive :cleanup_tmpdir
|
25
|
+
rakep "build"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "with a --pretend argument" do
|
30
|
+
it "doesn't invoke a project" do
|
31
|
+
project.should_not_receive :invoke
|
32
|
+
rakep "build", "--pretend"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "with a --clean argument" do
|
37
|
+
it "cleans a project" do
|
38
|
+
project.should_receive :clean
|
39
|
+
rakep "build", "--clean"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "invokes a project" do
|
43
|
+
project.should_receive :invoke
|
44
|
+
rakep "build", "--clean"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "clean" do
|
50
|
+
context "with no arguments" do
|
51
|
+
it "cleans a project" do
|
52
|
+
project.should_receive :clean
|
53
|
+
rakep "clean"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "server" do
|
59
|
+
let(:server) { double "server" }
|
60
|
+
|
61
|
+
before do
|
62
|
+
require 'rake-pipeline/server'
|
63
|
+
Rake::Pipeline::Server.stub(:new).and_return(server)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "starts a Rake::Pipeline::Server" do
|
67
|
+
server.should_receive :start
|
68
|
+
rakep "server"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/spec/concat_filter_spec.rb
CHANGED
@@ -1,31 +1,5 @@
|
|
1
1
|
describe "ConcatFilter" do
|
2
|
-
|
3
|
-
@@files = {}
|
4
|
-
|
5
|
-
def self.files
|
6
|
-
@@files
|
7
|
-
end
|
8
|
-
|
9
|
-
def with_encoding(new_encoding)
|
10
|
-
self.class.new(root, path, new_encoding, body)
|
11
|
-
end
|
12
|
-
|
13
|
-
def fullpath
|
14
|
-
File.join(root, path)
|
15
|
-
end
|
16
|
-
|
17
|
-
def create
|
18
|
-
@@files[fullpath] = self
|
19
|
-
self.body = ""
|
20
|
-
yield
|
21
|
-
end
|
22
|
-
|
23
|
-
alias read body
|
24
|
-
|
25
|
-
def write(contents)
|
26
|
-
self.body << contents
|
27
|
-
end
|
28
|
-
end
|
2
|
+
MemoryFileWrapper = Rake::Pipeline::SpecHelpers::MemoryFileWrapper
|
29
3
|
|
30
4
|
let(:input_files) {
|
31
5
|
[
|
@@ -1,11 +1,11 @@
|
|
1
|
-
describe "Rake::Pipeline::
|
1
|
+
describe "Rake::Pipeline::PipelineDSL" do
|
2
2
|
ConcatFilter = Rake::Pipeline::SpecHelpers::Filters::ConcatFilter
|
3
3
|
|
4
4
|
let(:pipeline) { Rake::Pipeline.new }
|
5
|
-
let(:dsl) { Rake::Pipeline::DSL.new(pipeline) }
|
5
|
+
let(:dsl) { Rake::Pipeline::DSL::PipelineDSL.new(pipeline) }
|
6
6
|
|
7
|
-
|
8
|
-
pipeline.
|
7
|
+
def filter
|
8
|
+
pipeline.filters.last
|
9
9
|
end
|
10
10
|
|
11
11
|
it "accepts a pipeline in its constructor" do
|
@@ -13,19 +13,19 @@ describe "Rake::Pipeline::DSL" do
|
|
13
13
|
end
|
14
14
|
|
15
15
|
describe "#input" do
|
16
|
-
it "
|
16
|
+
it "adds an input to the pipeline" do
|
17
17
|
dsl.input "/app"
|
18
|
-
pipeline.
|
18
|
+
pipeline.inputs["/app"].should == '**/*'
|
19
19
|
end
|
20
20
|
|
21
|
-
it "configures the
|
21
|
+
it "configures the input's glob" do
|
22
22
|
dsl.input "/app", "*.js"
|
23
|
-
pipeline.
|
23
|
+
pipeline.inputs['/app'].should == "*.js"
|
24
24
|
end
|
25
25
|
|
26
|
-
it "defaults
|
26
|
+
it "defaults input's glob to **/*" do
|
27
27
|
dsl.input "/app"
|
28
|
-
pipeline.
|
28
|
+
pipeline.inputs['/app'].should == "**/*"
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
@@ -35,13 +35,13 @@ describe "Rake::Pipeline::DSL" do
|
|
35
35
|
pipeline.filters.should be_empty
|
36
36
|
dsl.filter ConcatFilter
|
37
37
|
pipeline.filters.should_not be_empty
|
38
|
-
|
38
|
+
filter.should be_kind_of(ConcatFilter)
|
39
39
|
end
|
40
40
|
|
41
41
|
it "takes a block to configure the filter's output file names" do
|
42
42
|
generator = proc { |input| "main.js" }
|
43
43
|
dsl.filter(ConcatFilter, &generator)
|
44
|
-
|
44
|
+
filter.output_name_generator.should == generator
|
45
45
|
end
|
46
46
|
|
47
47
|
it "passes any extra arguments to the filter's constructor" do
|
@@ -53,7 +53,7 @@ describe "Rake::Pipeline::DSL" do
|
|
53
53
|
end
|
54
54
|
|
55
55
|
dsl.filter filter_class, "foo", "bar"
|
56
|
-
|
56
|
+
filter.args.should == %w(foo bar)
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
@@ -66,7 +66,7 @@ describe "Rake::Pipeline::DSL" do
|
|
66
66
|
|
67
67
|
it "adds the new matcher to the pipeline's filters" do
|
68
68
|
matcher = dsl.match("*.glob") {}
|
69
|
-
|
69
|
+
filter.should == matcher
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
@@ -77,10 +77,24 @@ describe "Rake::Pipeline::DSL" do
|
|
77
77
|
end
|
78
78
|
end
|
79
79
|
|
80
|
-
describe "#
|
81
|
-
it "
|
82
|
-
dsl.
|
83
|
-
|
80
|
+
describe "#concat" do
|
81
|
+
it "creates a ConcatFilter" do
|
82
|
+
dsl.concat "octopus"
|
83
|
+
filter.should be_kind_of(Rake::Pipeline::ConcatFilter)
|
84
|
+
end
|
85
|
+
|
86
|
+
context "passed an Array first argument" do
|
87
|
+
it "creates an OrderingConcatFilter" do
|
88
|
+
dsl.concat ["octopus"]
|
89
|
+
filter.should be_kind_of(Rake::Pipeline::OrderingConcatFilter)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "#copy" do
|
95
|
+
it "creates a ConcatFilter" do
|
96
|
+
dsl.copy
|
97
|
+
filter.should be_kind_of(Rake::Pipeline::ConcatFilter)
|
84
98
|
end
|
85
99
|
end
|
86
100
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
describe "Rake::Pipeline::ProjectDSL" do
|
2
|
+
ConcatFilter = Rake::Pipeline::SpecHelpers::Filters::ConcatFilter
|
3
|
+
|
4
|
+
let(:project) { Rake::Pipeline::Project.new }
|
5
|
+
let(:dsl) { Rake::Pipeline::DSL::ProjectDSL.new(project) }
|
6
|
+
|
7
|
+
it "accepts a project in its constructor" do
|
8
|
+
dsl.project.should == project
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "#output" do
|
12
|
+
it "configures the project's default_output_root" do
|
13
|
+
dsl.output "/path/to/output"
|
14
|
+
project.default_output_root.should == "/path/to/output"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#tmpdir" do
|
19
|
+
it "sets the project's tmpdir" do
|
20
|
+
dsl.tmpdir "/path/to/tmpdir"
|
21
|
+
project.tmpdir.should == "/path/to/tmpdir"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "#input" do
|
26
|
+
it "uses Project#build_pipeline to add a new pipeline to the project" do
|
27
|
+
project.should_receive(:build_pipeline)
|
28
|
+
dsl.input("app") {}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#map" do
|
33
|
+
it "saves the block in a hash on the project" do
|
34
|
+
project.maps.keys.size.should == 0
|
35
|
+
run_me = lambda { }
|
36
|
+
dsl.map("foo", &run_me)
|
37
|
+
dsl.project.maps["foo"].should == run_me
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Rake::Pipeline::DynamicFileTask do
|
4
|
+
let(:invoked_tasks) { [] }
|
5
|
+
|
6
|
+
def define_task(deps, klass=Rake::Pipeline::DynamicFileTask, &task_proc)
|
7
|
+
task_proc ||= proc do |task|
|
8
|
+
touch(task.name)
|
9
|
+
invoked_tasks << task
|
10
|
+
end
|
11
|
+
|
12
|
+
klass.define_task(deps, &task_proc)
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:task) { define_task('output') }
|
16
|
+
|
17
|
+
before do
|
18
|
+
# Make sure date conversions happen in UTC, not local time
|
19
|
+
ENV['TZ'] = 'UTC'
|
20
|
+
end
|
21
|
+
|
22
|
+
after do
|
23
|
+
# Clean out all defined tasks after each test runs
|
24
|
+
Rake.application = Rake::Application.new
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#dynamic" do
|
28
|
+
it "saves a block that can be called later with #invoke_dynamic_block" do
|
29
|
+
block = proc {}
|
30
|
+
task.dynamic(&block)
|
31
|
+
block.should_receive(:call).with(task)
|
32
|
+
task.invoke_dynamic_block
|
33
|
+
end
|
34
|
+
|
35
|
+
it "returns the task" do
|
36
|
+
(task.dynamic {}).should eq(task)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "#invoke" do
|
41
|
+
let(:static) { define_task('static', Rake::FileTask) }
|
42
|
+
let!(:dynamic) { define_task('dynamic', Rake::FileTask) }
|
43
|
+
let!(:dynamic_task) { define_task('output' => static).dynamic { ['dynamic'] } }
|
44
|
+
|
45
|
+
it "invokes the task's static and dynamic prerequisites" do
|
46
|
+
dynamic_task.invoke
|
47
|
+
invoked_tasks.should include(static)
|
48
|
+
invoked_tasks.should include(dynamic)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "adds dynamic dependencies to its manifest entry" do
|
52
|
+
dynamic_task.invoke
|
53
|
+
dynamic_task.manifest_entry.deps.should == {
|
54
|
+
'dynamic' => File.mtime('dynamic')
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
it "adds the current task's mtime to its manifest entry" do
|
59
|
+
dynamic_task.invoke
|
60
|
+
dynamic_task.manifest_entry.mtime.should == File.mtime('output')
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "#needed?" do
|
65
|
+
it "is true if the task has no previous manifest entry" do
|
66
|
+
task.last_manifest_entry.should be_nil
|
67
|
+
task.should be_needed
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "#dynamic_prerequisites" do
|
72
|
+
def make_file(name, mtime=nil)
|
73
|
+
touch(name)
|
74
|
+
if mtime
|
75
|
+
File.utime(mtime, mtime, name)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
it "returns an empty array if the task has no dynamic block" do
|
80
|
+
task.dynamic_prerequisites.should == []
|
81
|
+
end
|
82
|
+
|
83
|
+
it "returns the result of invoking the dynamic block" do
|
84
|
+
task.dynamic { %w[blinky] }
|
85
|
+
task.dynamic_prerequisites.should == %w[blinky]
|
86
|
+
end
|
87
|
+
|
88
|
+
it "filters the task itself from the list" do
|
89
|
+
task.dynamic { %w[output blinky] }
|
90
|
+
task.dynamic_prerequisites.should == %w[blinky]
|
91
|
+
end
|
92
|
+
|
93
|
+
it "loads dependency information from the manifest first" do
|
94
|
+
time = Time.utc(2000)
|
95
|
+
%w[blinky output].each { |f| make_file f, time }
|
96
|
+
|
97
|
+
manifest_entry = Rake::Pipeline::ManifestEntry.from_hash({
|
98
|
+
"deps" => {
|
99
|
+
"blinky" => "2000-01-01 00:00:00 +0000"
|
100
|
+
},
|
101
|
+
"mtime" => "2000-01-01 00:00:00 +0000"
|
102
|
+
})
|
103
|
+
|
104
|
+
task.dynamic { %w[] }
|
105
|
+
task.stub(:last_manifest_entry) { manifest_entry }
|
106
|
+
task.should_not_receive(:invoke_dynamic_block)
|
107
|
+
task.dynamic_prerequisites.should == %w[blinky]
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
data/spec/encoding_spec.rb
CHANGED
@@ -57,11 +57,10 @@ if "".respond_to?(:encode)
|
|
57
57
|
create_files
|
58
58
|
|
59
59
|
@pipeline = Rake::Pipeline.build do
|
60
|
-
tmpdir "temporary"
|
61
|
-
input tmp, "app/javascripts/*.js"
|
62
|
-
filter Filters::ConcatFilter, "javascripts/application.js"
|
63
|
-
filter Filters::StripAssertsFilter
|
64
60
|
output "public"
|
61
|
+
input "#{tmp}/app/javascripts/", "*.js"
|
62
|
+
concat "javascripts/application.js"
|
63
|
+
filter Filters::StripAssertsFilter
|
65
64
|
end
|
66
65
|
end
|
67
66
|
|
@@ -86,11 +85,10 @@ if "".respond_to?(:encode)
|
|
86
85
|
let(:encoding) { "EUC-JP" }
|
87
86
|
|
88
87
|
it "does not raise an exception" do
|
89
|
-
|
90
|
-
tmpdir "temporary"
|
91
|
-
input tmp, "app/javascripts/*.js"
|
92
|
-
filter Filters::ConcatFilter, "javascripts/application.js"
|
88
|
+
pipeline = Rake::Pipeline.build do
|
93
89
|
output "public"
|
90
|
+
input "#{tmp}/app/javascripts/", "*.js"
|
91
|
+
concat "javascripts/application.js"
|
94
92
|
end
|
95
93
|
|
96
94
|
pipeline.invoke
|