rake-pipeline 0.5.0 → 0.7.0
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.
- 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
@@ -0,0 +1,56 @@
|
|
1
|
+
require "thor"
|
2
|
+
|
3
|
+
module Rake
|
4
|
+
class Pipeline
|
5
|
+
class CLI < Thor
|
6
|
+
class_option :assetfile, :default => "Assetfile", :aliases => "-c"
|
7
|
+
default_task :build
|
8
|
+
|
9
|
+
desc "build", "Build the project."
|
10
|
+
method_option :pretend, :type => :boolean, :aliases => "-p"
|
11
|
+
method_option :clean, :type => :boolean, :aliases => "-C"
|
12
|
+
def build
|
13
|
+
if options[:pretend]
|
14
|
+
project.output_files.each do |file|
|
15
|
+
say_status :create, relative_path(file)
|
16
|
+
end
|
17
|
+
else
|
18
|
+
options[:clean] ? project.clean : project.cleanup_tmpdir
|
19
|
+
project.invoke
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "clean", "Remove the pipeline's temporary and output files."
|
24
|
+
method_option :pretend, :type => :boolean, :aliases => "-p"
|
25
|
+
def clean
|
26
|
+
if options[:pretend]
|
27
|
+
project.files_to_clean.each do |file|
|
28
|
+
say_status :remove, relative_path(file)
|
29
|
+
end
|
30
|
+
else
|
31
|
+
project.clean
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "server", "Run the Rake::Pipeline preview server."
|
36
|
+
def server
|
37
|
+
require "rake-pipeline/server"
|
38
|
+
Rake::Pipeline::Server.new.start
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
def project
|
43
|
+
@project ||= Rake::Pipeline::Project.new(options[:assetfile])
|
44
|
+
end
|
45
|
+
|
46
|
+
# @param [FileWrapper|String] path
|
47
|
+
# @return [String] The path to the file with the current
|
48
|
+
# directory stripped out.
|
49
|
+
def relative_path(path)
|
50
|
+
pathstr = path.respond_to?(:fullpath) ? path.fullpath : path
|
51
|
+
pathstr.sub(%r|#{Dir.pwd}/|, '')
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
data/lib/rake-pipeline/dsl.rb
CHANGED
@@ -1,146 +1,9 @@
|
|
1
1
|
module Rake
|
2
2
|
class Pipeline
|
3
|
-
|
4
|
-
# configuring a pipeline.
|
5
|
-
#
|
6
|
-
# All instance methods of {DSL} are available in the context
|
7
|
-
# the block passed to +Rake::Pipeline.+{Pipeline.build}.
|
8
|
-
#
|
9
|
-
# When configuring a pipeline, you *must* provide both a
|
10
|
-
# root, and a series of files using {#input}.
|
11
|
-
class DSL
|
12
|
-
# @return [Pipeline] the pipeline the DSL should configure
|
13
|
-
attr_reader :pipeline
|
14
|
-
|
15
|
-
# Configure a pipeline with a passed in block.
|
16
|
-
#
|
17
|
-
# @param [Pipeline] pipeline the pipeline that the DSL
|
18
|
-
# should configure.
|
19
|
-
# @param [Proc] block the block describing the
|
20
|
-
# configuration. This block will be evaluated in
|
21
|
-
# the context of a new instance of {DSL}
|
22
|
-
# @return [void]
|
23
|
-
def self.evaluate(pipeline, &block)
|
24
|
-
new(pipeline).instance_eval(&block)
|
25
|
-
copy_filter = Rake::Pipeline::ConcatFilter.new
|
26
|
-
copy_filter.output_name_generator = proc { |input| input }
|
27
|
-
pipeline.add_filter(copy_filter)
|
28
|
-
end
|
29
|
-
|
30
|
-
# Create a new {DSL} to configure a pipeline.
|
31
|
-
#
|
32
|
-
# @param [Pipeline] pipeline the pipeline that the DSL
|
33
|
-
# should configure.
|
34
|
-
# @return [void]
|
35
|
-
def initialize(pipeline)
|
36
|
-
@pipeline = pipeline
|
37
|
-
end
|
38
|
-
|
39
|
-
# Define the input location and files for the pipeline.
|
40
|
-
#
|
41
|
-
# @example
|
42
|
-
# !!!ruby
|
43
|
-
# Rake::Pipeline.build do
|
44
|
-
# input "app/assets", "**/*.js"
|
45
|
-
# # ...
|
46
|
-
# end
|
47
|
-
#
|
48
|
-
# @param [String] root the root path where the pipeline
|
49
|
-
# should find its input files.
|
50
|
-
# @param [String] glob a file pattern that represents
|
51
|
-
# the list of all files that the pipeline should
|
52
|
-
# process. The default is +"**/*"+.
|
53
|
-
# @return [void]
|
54
|
-
def input(root, glob="**/*")
|
55
|
-
pipeline.input_root = root
|
56
|
-
pipeline.input_glob = glob
|
57
|
-
end
|
58
|
-
|
59
|
-
# Add a filter to the pipeline.
|
60
|
-
#
|
61
|
-
# In addition to a filter class, {#filter} takes a
|
62
|
-
# block that describes how the filter should map
|
63
|
-
# input files to output files.
|
64
|
-
#
|
65
|
-
# By default, the block maps an input file into
|
66
|
-
# an output file with the same name.
|
67
|
-
#
|
68
|
-
# Any additional arguments passed to {#filter} will
|
69
|
-
# be passed on to the filter class's constructor.
|
70
|
-
#
|
71
|
-
# @see Filter#outputs Filter#output (for an example
|
72
|
-
# of how a list of input files gets mapped to
|
73
|
-
# its outputs)
|
74
|
-
#
|
75
|
-
# @param [Class] filter_class the class of the filter.
|
76
|
-
# @param [Array] ctor_args a list of arguments to pass
|
77
|
-
# to the filter's constructor.
|
78
|
-
# @param [Proc] block an output file name generator.
|
79
|
-
# @return [void]
|
80
|
-
def filter(filter_class, *ctor_args, &block)
|
81
|
-
filter = filter_class.new(*ctor_args, &block)
|
82
|
-
pipeline.add_filter(filter)
|
83
|
-
end
|
84
|
-
|
85
|
-
# Apply a number of filters, but only to files matching
|
86
|
-
# a particular pattern.
|
87
|
-
#
|
88
|
-
# Inside the block passed to {#match match}, you may
|
89
|
-
# specify any number of filters that should be applied
|
90
|
-
# to files matching the pattern.
|
91
|
-
#
|
92
|
-
# @param [String] pattern a glob pattern to match
|
93
|
-
# @param [Proc] block a block that supplies filters
|
94
|
-
# @return [Matcher]
|
95
|
-
#
|
96
|
-
# @example
|
97
|
-
# !!!ruby
|
98
|
-
# Pipeline.build do
|
99
|
-
# input "app/assets"
|
100
|
-
# output "public"
|
101
|
-
#
|
102
|
-
# # compile coffee files into JS files
|
103
|
-
# match "*.coffee" do
|
104
|
-
# filter CompileCoffee do |input|
|
105
|
-
# input.sub(/coffee$/, "js")
|
106
|
-
# end
|
107
|
-
# end
|
108
|
-
#
|
109
|
-
# # because the previous step converted coffeee
|
110
|
-
# # into JS, the coffee files will be included here
|
111
|
-
# match "*.js" do
|
112
|
-
# filter MinifyFilter
|
113
|
-
# filter Rake::Pipeline::ConcatFilter, "application.js"
|
114
|
-
# end
|
115
|
-
# end
|
116
|
-
def match(pattern, &block)
|
117
|
-
matcher = pipeline.copy(Matcher, &block)
|
118
|
-
matcher.glob = pattern
|
119
|
-
pipeline.add_filter matcher
|
120
|
-
matcher
|
121
|
-
end
|
122
|
-
|
123
|
-
# Specify the output directory for the pipeline.
|
124
|
-
#
|
125
|
-
# @param [String] root the output directory.
|
126
|
-
# @return [void]
|
127
|
-
def output(root)
|
128
|
-
pipeline.output_root = root
|
129
|
-
end
|
130
|
-
|
131
|
-
# Specify the location of the temporary directory.
|
132
|
-
# Filters will store intermediate build artifacts
|
133
|
-
# here.
|
134
|
-
#
|
135
|
-
# This defaults "tmp" in the current working directory.
|
136
|
-
#
|
137
|
-
# @param [String] root the temporary directory
|
138
|
-
# @return [void]
|
139
|
-
def tmpdir(root)
|
140
|
-
pipeline.tmpdir = root
|
141
|
-
end
|
3
|
+
module DSL
|
142
4
|
end
|
143
5
|
end
|
144
6
|
end
|
145
7
|
|
146
|
-
|
8
|
+
require 'rake-pipeline/dsl/pipeline_dsl'
|
9
|
+
require 'rake-pipeline/dsl/project_dsl'
|
@@ -0,0 +1,168 @@
|
|
1
|
+
module Rake
|
2
|
+
class Pipeline
|
3
|
+
module DSL
|
4
|
+
# This class is used by {ProjectDSL} to provide a convenient DSL for
|
5
|
+
# configuring a pipeline.
|
6
|
+
#
|
7
|
+
# All instance methods of {PipelineDSL} are available in the context
|
8
|
+
# the block passed to +Rake::Pipeline.+{Pipeline.build}.
|
9
|
+
class PipelineDSL
|
10
|
+
# @return [Pipeline] the pipeline the DSL should configure
|
11
|
+
attr_reader :pipeline
|
12
|
+
|
13
|
+
# Configure a pipeline with a passed in block.
|
14
|
+
#
|
15
|
+
# @param [Pipeline] pipeline the pipeline that the PipelineDSL
|
16
|
+
# should configure.
|
17
|
+
# @param [Proc] block the block describing the
|
18
|
+
# configuration. This block will be evaluated in
|
19
|
+
# the context of a new instance of {PipelineDSL}
|
20
|
+
# @return [void]
|
21
|
+
def self.evaluate(pipeline, options, &block)
|
22
|
+
dsl = new(pipeline)
|
23
|
+
|
24
|
+
# If any before filters, apply them to the pipeline.
|
25
|
+
# They will be run in reverse of insertion order.
|
26
|
+
if before_filters = options[:before_filters]
|
27
|
+
before_filters.each do |klass, args, block|
|
28
|
+
dsl.filter klass, *args, &block
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Evaluate the block in the context of the DSL.
|
33
|
+
dsl.instance_eval(&block)
|
34
|
+
|
35
|
+
# If any after filters, apply them to the pipeline.
|
36
|
+
# They will be run in insertion order.
|
37
|
+
if after_filters = options[:after_filters]
|
38
|
+
after_filters.each do |klass, args, block|
|
39
|
+
dsl.filter klass, *args, &block
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# the FinalizingFilter should always come after all
|
44
|
+
# user specified after filters
|
45
|
+
pipeline.finalize
|
46
|
+
end
|
47
|
+
|
48
|
+
# Create a new {PipelineDSL} to configure a pipeline.
|
49
|
+
#
|
50
|
+
# @param [Pipeline] pipeline the pipeline that the PipelineDSL
|
51
|
+
# should configure.
|
52
|
+
# @return [void]
|
53
|
+
def initialize(pipeline)
|
54
|
+
@pipeline = pipeline
|
55
|
+
end
|
56
|
+
|
57
|
+
# Add an input location and files to a pipeline.
|
58
|
+
#
|
59
|
+
# @example
|
60
|
+
# !!!ruby
|
61
|
+
# Rake::Pipeline::Project.build do
|
62
|
+
# input "app" do
|
63
|
+
# input "assets", "**/*.js"
|
64
|
+
# # ...
|
65
|
+
# end
|
66
|
+
# end
|
67
|
+
#
|
68
|
+
# @param [String] root the root path where the pipeline
|
69
|
+
# should find its input files.
|
70
|
+
# @param [String] glob a file pattern that represents
|
71
|
+
# the list of files that the pipeline should
|
72
|
+
# process within +root+. The default is +"**/*"+.
|
73
|
+
# @return [void]
|
74
|
+
def input(root, glob="**/*")
|
75
|
+
pipeline.add_input root, glob
|
76
|
+
end
|
77
|
+
|
78
|
+
# Add a filter to the pipeline.
|
79
|
+
#
|
80
|
+
# In addition to a filter class, {#filter} takes a
|
81
|
+
# block that describes how the filter should map
|
82
|
+
# input files to output files.
|
83
|
+
#
|
84
|
+
# By default, the block maps an input file into
|
85
|
+
# an output file with the same name.
|
86
|
+
#
|
87
|
+
# Any additional arguments passed to {#filter} will
|
88
|
+
# be passed on to the filter class's constructor.
|
89
|
+
#
|
90
|
+
# @see Filter#outputs Filter#output (for an example
|
91
|
+
# of how a list of input files gets mapped to
|
92
|
+
# its outputs)
|
93
|
+
#
|
94
|
+
# @param [Class] filter_class the class of the filter.
|
95
|
+
# @param [Array] ctor_args a list of arguments to pass
|
96
|
+
# to the filter's constructor.
|
97
|
+
# @param [Proc] block an output file name generator.
|
98
|
+
# @return [void]
|
99
|
+
def filter(filter_class, *ctor_args, &block)
|
100
|
+
filter = filter_class.new(*ctor_args, &block)
|
101
|
+
pipeline.add_filter(filter)
|
102
|
+
end
|
103
|
+
|
104
|
+
# Apply a number of filters, but only to files matching
|
105
|
+
# a particular pattern.
|
106
|
+
#
|
107
|
+
# Inside the block passed to {#match match}, you may
|
108
|
+
# specify any number of filters that should be applied
|
109
|
+
# to files matching the pattern.
|
110
|
+
#
|
111
|
+
# @param [String] pattern a glob pattern to match
|
112
|
+
# @param [Proc] block a block that supplies filters
|
113
|
+
# @return [Matcher]
|
114
|
+
#
|
115
|
+
# @example
|
116
|
+
# !!!ruby
|
117
|
+
# Rake::Pipeline::Project.build do
|
118
|
+
# output "public"
|
119
|
+
#
|
120
|
+
# input "app/assets" do
|
121
|
+
# # compile coffee files into JS files
|
122
|
+
# match "*.coffee" do
|
123
|
+
# coffee_script
|
124
|
+
# end
|
125
|
+
#
|
126
|
+
# # because the previous step converted coffeee
|
127
|
+
# # into JS, the coffee files will be included here
|
128
|
+
# match "*.js" do
|
129
|
+
# uglify
|
130
|
+
# concat "application.js"
|
131
|
+
# end
|
132
|
+
# end
|
133
|
+
# end
|
134
|
+
def match(pattern, &block)
|
135
|
+
matcher = pipeline.copy(Matcher, &block)
|
136
|
+
matcher.glob = pattern
|
137
|
+
pipeline.add_filter matcher
|
138
|
+
matcher
|
139
|
+
end
|
140
|
+
|
141
|
+
# Specify the output directory for the pipeline.
|
142
|
+
#
|
143
|
+
# @param [String] root the output directory.
|
144
|
+
# @return [void]
|
145
|
+
def output(root)
|
146
|
+
pipeline.output_root = root
|
147
|
+
end
|
148
|
+
|
149
|
+
# A helper method for adding a concat filter to
|
150
|
+
# the pipeline.
|
151
|
+
# If the first argument is an Array, it adds a new
|
152
|
+
# {OrderingConcatFilter}, otherwise it adds a new
|
153
|
+
# {ConcatFilter}.
|
154
|
+
#
|
155
|
+
# @see OrderingConcatFilter#initialize
|
156
|
+
# @see ConcatFilter#initialize
|
157
|
+
def concat(*args, &block)
|
158
|
+
if args.first.kind_of?(Array)
|
159
|
+
filter(Rake::Pipeline::OrderingConcatFilter, *args, &block)
|
160
|
+
else
|
161
|
+
filter(Rake::Pipeline::ConcatFilter, *args, &block)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
alias_method :copy, :concat
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module Rake
|
2
|
+
class Pipeline
|
3
|
+
module DSL
|
4
|
+
# This class exists purely to provide a convenient DSL for
|
5
|
+
# configuring a project.
|
6
|
+
#
|
7
|
+
# All instance methods of {ProjectDSL} are available in the context
|
8
|
+
# the block passed to +Rake::Pipeline::Project.+{Project.build}.
|
9
|
+
#
|
10
|
+
# When configuring a project, you *must* provide an output root
|
11
|
+
# and a series of files using at least one {#input} block.
|
12
|
+
class ProjectDSL
|
13
|
+
# @return [Project] the project the DSL should configure
|
14
|
+
attr_reader :project
|
15
|
+
|
16
|
+
# Configure a project with a passed in block.
|
17
|
+
#
|
18
|
+
# @param [Project] project the project that the ProjectDSL
|
19
|
+
# should configure.
|
20
|
+
# @param [Proc] block the block describing the
|
21
|
+
# configuration. This block will be evaluated in
|
22
|
+
# the context of a new instance of {ProjectDSL}
|
23
|
+
# @return [void]
|
24
|
+
def self.evaluate(project, &block)
|
25
|
+
new(project).instance_eval(&block)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Create a new {ProjectDSL} to configure a project.
|
29
|
+
#
|
30
|
+
# @param [Project] project
|
31
|
+
# the project that the ProjectDSL should configure.
|
32
|
+
# @return [void]
|
33
|
+
def initialize(project)
|
34
|
+
@project = project
|
35
|
+
@before_filters = []
|
36
|
+
@after_filters = []
|
37
|
+
@project.before_filters = @before_filters
|
38
|
+
@project.after_filters = @after_filters
|
39
|
+
end
|
40
|
+
|
41
|
+
# Add a filter to every input block. The parameters
|
42
|
+
# to +before_filter+ are the same as the parameters
|
43
|
+
# to {PipelineDSL#filter}.
|
44
|
+
#
|
45
|
+
# Filters will be executed before the specified
|
46
|
+
# filters in reverse of insertion order.
|
47
|
+
#
|
48
|
+
# @see {PipelineDSL#filter}
|
49
|
+
def before_filter(klass, *args, &block)
|
50
|
+
@before_filters.unshift [klass, args, block]
|
51
|
+
end
|
52
|
+
|
53
|
+
# Add a filter to every input block. The parameters
|
54
|
+
# to +after_filter+ are the same as the parameters
|
55
|
+
# to {PipelineDSL#filter}.
|
56
|
+
#
|
57
|
+
# Filters will be executed after the specified
|
58
|
+
# filters in insertion order.
|
59
|
+
#
|
60
|
+
# @see {PipelineDSL#filter}
|
61
|
+
def after_filter(klass, *args, &block)
|
62
|
+
@after_filters.push [klass, args, block]
|
63
|
+
end
|
64
|
+
|
65
|
+
# Specify the default output directory for the project.
|
66
|
+
#
|
67
|
+
# Pipelines created in this project will place their
|
68
|
+
# outputs here unless the value is overriden in their
|
69
|
+
# {#input} block.
|
70
|
+
#
|
71
|
+
# @param [String] root the output directory.
|
72
|
+
# @return [void]
|
73
|
+
def output(root)
|
74
|
+
project.default_output_root = root
|
75
|
+
end
|
76
|
+
|
77
|
+
# Specify the location of the root temporary directory.
|
78
|
+
#
|
79
|
+
# Pipelines will store intermediate build artifacts
|
80
|
+
# in a subdirectory of this directory.
|
81
|
+
#
|
82
|
+
# This defaults to "tmp" in the current working directory.
|
83
|
+
#
|
84
|
+
# @param [String] root the temporary directory
|
85
|
+
# @return [void]
|
86
|
+
def tmpdir(root)
|
87
|
+
project.tmpdir = root
|
88
|
+
end
|
89
|
+
|
90
|
+
# Add a new pipeline with the given inputs to the project.
|
91
|
+
#
|
92
|
+
# @see Project.build_pipeline
|
93
|
+
def input(*inputs, &block)
|
94
|
+
# Allow pipelines without a specified block. This is possible
|
95
|
+
# if before and after filters are all that are needed for a
|
96
|
+
# given input.
|
97
|
+
block = proc {} unless block_given?
|
98
|
+
project.build_pipeline(*inputs, &block)
|
99
|
+
end
|
100
|
+
alias inputs input
|
101
|
+
|
102
|
+
def map(path, &block)
|
103
|
+
project.maps[path] = block
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|