capistrano-filter 0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,8 @@
1
+ unless Capistrano::Configuration.respond_to?(:instance)
2
+ abort "capistrano/ext/filter requires Capistrano 2"
3
+ end
4
+
5
+ Capistrano::Configuration.instance.load do
6
+ require 'capistrano/recipes/deploy/strategy/copy_and_filter'
7
+ require 'capistrano/recipes/deploy/strategy/filter'
8
+ end
@@ -0,0 +1,232 @@
1
+ require 'capistrano/recipes/deploy/strategy/base'
2
+ require 'fileutils'
3
+ require 'tempfile' # Dir.tmpdir
4
+ #require 'filter.rb'
5
+
6
+ module Capistrano
7
+ module Deploy
8
+ module Strategy
9
+
10
+ # This class implements the strategy for deployments which work
11
+ # by preparing the source code locally, compressing it, copying the
12
+ # file to each target host, and uncompressing it to the deployment
13
+ # directory.
14
+ #
15
+ # By default, the SCM checkout command is used to obtain the local copy
16
+ # of the source code. If you would rather use the export operation,
17
+ # you can set the :copy_strategy variable to :export.
18
+ #
19
+ # set :copy_strategy, :export
20
+ #
21
+ # For even faster deployments, you can set the :copy_cache variable to
22
+ # true. This will cause deployments to do a new checkout of your
23
+ # repository to a new directory, and then copy that checkout. Subsequent
24
+ # deploys will just resync that copy, rather than doing an entirely new
25
+ # checkout. Additionally, you can specify file patterns to exclude from
26
+ # the copy when using :copy_cache; just set the :copy_exclude variable
27
+ # to a file glob (or an array of globs).
28
+ #
29
+ # set :copy_cache, true
30
+ # set :copy_exclude, ".git/*"
31
+ #
32
+ # Note that :copy_strategy is ignored when :copy_cache is set. Also, if
33
+ # you want the copy cache put somewhere specific, you can set the variable
34
+ # to the path you want, instead of merely 'true':
35
+ #
36
+ # set :copy_cache, "/tmp/caches/myapp"
37
+ #
38
+ # This deployment strategy also supports a special variable,
39
+ # :copy_compression, which must be one of :gzip, :bz2, or
40
+ # :zip, and which specifies how the source should be compressed for
41
+ # transmission to each host.
42
+ class CopyAndFilter < Base
43
+ # Obtains a copy of the source code locally (via the #command method),
44
+ # compresses it to a single file, copies that file to all target
45
+ # servers, and uncompresses it on each of them into the deployment
46
+ # directory.
47
+ def deploy!
48
+ if copy_cache
49
+ if File.exists?(copy_cache)
50
+ logger.debug "refreshing local cache to revision #{revision} at #{copy_cache}"
51
+ system(source.sync(revision, copy_cache))
52
+ else
53
+ logger.debug "preparing local cache at #{copy_cache}"
54
+ system(source.checkout(revision, copy_cache))
55
+ end
56
+
57
+ # Check the return code of last system command and rollback if not 0
58
+ unless $? == 0
59
+ raise Capistrano::Error, "shell command failed with return code #{$?}"
60
+ end
61
+
62
+ logger.debug "copying cache to deployment staging area #{destination}"
63
+ Dir.chdir(copy_cache) do
64
+ FileUtils.mkdir_p(destination)
65
+ queue = Dir.glob("*", File::FNM_DOTMATCH)
66
+ while queue.any?
67
+ item = queue.shift
68
+ name = File.basename(item)
69
+
70
+ next if name == "." || name == ".."
71
+ next if copy_exclude.any? { |pattern| File.fnmatch(pattern, item) }
72
+
73
+ if File.symlink?(item)
74
+ FileUtils.ln_s(File.readlink(File.join(copy_cache, item)), File.join(destination, item))
75
+ elsif File.directory?(item)
76
+ queue += Dir.glob("#{item}/*", File::FNM_DOTMATCH)
77
+ FileUtils.mkdir(File.join(destination, item))
78
+ else
79
+ FileUtils.ln(File.join(copy_cache, item), File.join(destination, item))
80
+ end
81
+ end
82
+ end
83
+ else
84
+ logger.debug "getting (via #{copy_strategy}) revision #{revision} to #{destination}"
85
+ system(command)
86
+
87
+ if copy_exclude.any?
88
+ logger.debug "processing exclusions..."
89
+ if copy_exclude.any?
90
+ copy_exclude.each do |pattern|
91
+ delete_list = Dir.glob(File.join(destination, pattern), File::FNM_DOTMATCH)
92
+ # avoid the /.. trap that deletes the parent directories
93
+ delete_list.delete_if { |dir| dir =~ /\/\.\.$/ }
94
+ FileUtils.rm_rf(delete_list.compact)
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ if filtering_props and not filtering_props.empty? then
101
+ #_cset(:filtering_files, "*") unless filtering_files
102
+ #filtering_files = [*filtering_files]
103
+ _filter_using = filtering_using #FIXME Valor default? ? filtering_using : :ruby
104
+ _filter_files = [*filtering_files]
105
+ logger.info "filtering files #{destination} with pattern #{_filter_files.join(',')}"
106
+ _filter_criteria = filter.from(destination).force().using(_filter_using, filtering_props)
107
+ _filter_files.each do |file|
108
+ _filter_criteria.include(file)
109
+ end
110
+ _filter_criteria.into(destination).run()
111
+ end
112
+
113
+ File.open(File.join(destination, "REVISION"), "w") { |f| f.puts(revision) }
114
+
115
+ logger.trace "compressing #{destination} to #{filename}"
116
+ Dir.chdir(tmpdir) { system(compress(File.basename(destination), File.basename(filename)).join(" ")) }
117
+
118
+ upload(filename, remote_filename)
119
+ run "cd #{configuration[:releases_path]} && #{decompress(remote_filename).join(" ")} && rm #{remote_filename}"
120
+ ensure
121
+ FileUtils.rm filename rescue nil
122
+ FileUtils.rm_rf destination rescue nil
123
+ end
124
+
125
+ def check!
126
+ super.check do |d|
127
+ d.local.command(source.local.command) if source.local.command
128
+ d.local.command(compress(nil, nil).first)
129
+ d.remote.command(decompress(nil).first)
130
+ end
131
+ end
132
+
133
+ # Returns the location of the local copy cache, if the strategy should
134
+ # use a local cache + copy instead of a new checkout/export every
135
+ # time. Returns +nil+ unless :copy_cache has been set. If :copy_cache
136
+ # is +true+, a default cache location will be returned.
137
+ def copy_cache
138
+ @copy_cache ||= configuration[:copy_cache] == true ?
139
+ File.join(Dir.tmpdir, configuration[:application]) :
140
+ configuration[:copy_cache]
141
+ end
142
+
143
+ private
144
+
145
+ # Specify patterns to exclude from the copy. This is only valid
146
+ # when using a local cache.
147
+ def copy_exclude
148
+ @copy_exclude ||= Array(configuration.fetch(:copy_exclude, []))
149
+ end
150
+
151
+ # Returns the basename of the release_path, which will be used to
152
+ # name the local copy and archive file.
153
+ def destination
154
+ @destination ||= File.join(tmpdir, File.basename(configuration[:release_path]))
155
+ end
156
+
157
+ # Returns the value of the :copy_strategy variable, defaulting to
158
+ # :checkout if it has not been set.
159
+ def copy_strategy
160
+ @copy_strategy ||= configuration.fetch(:copy_strategy, :checkout)
161
+ end
162
+
163
+ # Should return the command(s) necessary to obtain the source code
164
+ # locally.
165
+ def command
166
+ @command ||= case copy_strategy
167
+ when :checkout
168
+ source.checkout(revision, destination)
169
+ when :export
170
+ source.export(revision, destination)
171
+ end
172
+ end
173
+
174
+ # Returns the name of the file that the source code will be
175
+ # compressed to.
176
+ def filename
177
+ @filename ||= File.join(tmpdir, "#{File.basename(destination)}.#{compression.extension}")
178
+ end
179
+
180
+ # The directory to which the copy should be checked out
181
+ def tmpdir
182
+ @tmpdir ||= configuration[:copy_dir] || Dir.tmpdir
183
+ end
184
+
185
+ # The directory on the remote server to which the archive should be
186
+ # copied
187
+ def remote_dir
188
+ @remote_dir ||= configuration[:copy_remote_dir] || "/tmp"
189
+ end
190
+
191
+ # The location on the remote server where the file should be
192
+ # temporarily stored.
193
+ def remote_filename
194
+ @remote_filename ||= File.join(remote_dir, File.basename(filename))
195
+ end
196
+
197
+ # A struct for representing the specifics of a compression type.
198
+ # Commands are arrays, where the first element is the utility to be
199
+ # used to perform the compression or decompression.
200
+ Compression = Struct.new(:extension, :compress_command, :decompress_command)
201
+
202
+ # The compression method to use, defaults to :gzip.
203
+ def compression
204
+ remote_tar = configuration[:copy_remote_tar] || 'tar'
205
+ local_tar = configuration[:copy_local_tar] || 'tar'
206
+
207
+ type = configuration[:copy_compression] || :gzip
208
+ case type
209
+ when :gzip, :gz then Compression.new("tar.gz", [local_tar, 'czf'], [remote_tar, 'xzf'])
210
+ when :bzip2, :bz2 then Compression.new("tar.bz2", [local_tar, 'cjf'], [remote_tar, 'xjf'])
211
+ when :zip then Compression.new("zip", %w(zip -qr), %w(unzip -q))
212
+ else raise ArgumentError, "invalid compression type #{type.inspect}"
213
+ end
214
+ end
215
+
216
+ # Returns the command necessary to compress the given directory
217
+ # into the given file.
218
+ def compress(directory, file)
219
+ compression.compress_command + [file, directory]
220
+ end
221
+
222
+ # Returns the command necessary to decompress the given file,
223
+ # relative to the current working directory. It must also
224
+ # preserve the directory structure in the file.
225
+ def decompress(file)
226
+ compression.decompress_command + [file]
227
+ end
228
+ end
229
+
230
+ end
231
+ end
232
+ end
@@ -0,0 +1,423 @@
1
+ # Licensed to the Apache Software Foundation (ASF) under one or more
2
+ # contributor license agreements. See the NOTICE file distributed with this
3
+ # work for additional information regarding copyright ownership. The ASF
4
+ # licenses this file to you under the Apache License, Version 2.0 (the
5
+ # "License"); you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+ # License for the specific language governing permissions and limitations under
14
+ # the License.
15
+
16
+
17
+ require 'erb'
18
+ require 'rake'
19
+
20
+ # A filter knows how to copy files from one directory to another, applying mappings to the
21
+ # contents of these files.
22
+ #
23
+ # You can specify the mapping using a Hash, and it will map ${key} fields found in each source
24
+ # file into the appropriate value in the target file. For example:
25
+ #
26
+ # filter.using 'version'=>'1.2', 'build'=>Time.now
27
+ #
28
+ # will replace all occurrences of <tt>${version}</tt> with <tt>1.2</tt>, and <tt>${build}</tt>
29
+ # with the current date/time.
30
+ #
31
+ # You can also specify the mapping by passing a proc or a method, that will be called for
32
+ # each source file, with the file name and content, returning the modified content.
33
+ #
34
+ # Without any mapping, the filter simply copies files from the source directory into the target
35
+ # directory.
36
+ #
37
+ # A filter has one target directory, but you can specify any number of source directories,
38
+ # either when creating the filter or calling #from. Include/exclude patterns are specified
39
+ # relative to the source directories, so:
40
+ # filter.include '*.png'
41
+ # will only include PNG files from any of the source directories.
42
+ # In the same way, you can use regular expressions, so:
43
+ # filter.include /picture_.*\.png/
44
+ # will only include PNG files starting with picture_ from any of the sources directories.
45
+ #
46
+ # See Buildr#filter.
47
+ class Filter
48
+
49
+ def initialize #:nodoc:
50
+ clear
51
+ @force = true
52
+ end
53
+
54
+ # Returns the list of source directories (each being a file task).
55
+ attr_reader :sources
56
+
57
+ # :call-seq:
58
+ # clear => self
59
+ #
60
+ # Clear filter sources and include/exclude patterns
61
+ def clear
62
+ @include = []
63
+ @exclude = []
64
+ @sources = Rake::FileList[]
65
+ @mapper = Mapper.new
66
+ self
67
+ end
68
+
69
+ def force
70
+ @force = true
71
+ self
72
+ end
73
+
74
+ def noforce
75
+ @force = false
76
+ self
77
+ end
78
+
79
+ # :call-seq:
80
+ # from(*sources) => self
81
+ #
82
+ # Adds additional directories from which to copy resources.
83
+ #
84
+ # For example:
85
+ # filter.from('src').into('target').using('build'=>Time.now)
86
+ def from(*sources)
87
+ @sources |= sources.flatten.map { |dir| file(File.expand_path(dir.to_s)) }
88
+ self
89
+ end
90
+
91
+ # The target directory as a file task.
92
+ def target
93
+ return nil unless @target_dir
94
+ unless @target
95
+ @target = file(File.expand_path(@target_dir)) { |task| run if @target == task }
96
+ @target.enhance @include.select {|f| f.is_a?(Rake::FileTask)}
97
+ @target.enhance @exclude.select {|f| f.is_a?(Rake::FileTask)}
98
+ @target.enhance copy_map.values
99
+ end
100
+ @target
101
+ end
102
+
103
+ # :call-seq:
104
+ # into(dir) => self
105
+ #
106
+ # Sets the target directory into which files are copied and returns self.
107
+ #
108
+ # For example:
109
+ # filter.from('src').into('target').using('build'=>Time.now)
110
+ def into(dir)
111
+ @target_dir = dir.to_s
112
+ @target = nil
113
+ self
114
+ end
115
+
116
+ # :call-seq:
117
+ # include(*files) => self
118
+ #
119
+ # Specifies files to include and returns self. See FileList#include.
120
+ #
121
+ # By default all files are included. You can use this method to only include specific
122
+ # files from the source directory.
123
+ def include(*files)
124
+ @include += files.flatten
125
+ self
126
+ end
127
+ alias :add :include
128
+
129
+ # :call-seq:
130
+ # exclude(*files) => self
131
+ #
132
+ # Specifies files to exclude and returns self. See FileList#exclude.
133
+ def exclude(*files)
134
+ @exclude += files.flatten
135
+ self
136
+ end
137
+
138
+ # The mapping. See #using.
139
+ def mapping #:nodoc:
140
+ @mapper.config
141
+ end
142
+
143
+ # The mapper to use. See #using.
144
+ def mapper #:nodoc:
145
+ @mapper.mapper_type
146
+ end
147
+
148
+ # :call-seq:
149
+ # using(mapping) => self
150
+ # using { |file_name, contents| ... } => self
151
+ #
152
+ # Specifies the mapping to use and returns self.
153
+ #
154
+ # The most typical mapping uses a Hash, and the default mapping uses the Maven style, so
155
+ # <code>${key}</code> are mapped to the values. You can change that by passing a different
156
+ # format as the first argument. Currently supports:
157
+ # * :ant -- Map <code>@key@</code>.
158
+ # * :maven -- Map <code>${key}</code> (default).
159
+ # * :ruby -- Map <code>#{key}</code>.
160
+ # * :erb -- Map <code><%= key %></code>.
161
+ # * Regexp -- Maps the matched data (e.g. <code>/=(.*?)=/</code>
162
+ #
163
+ # For example:
164
+ # filter.using 'version'=>'1.2'
165
+ # Is the same as:
166
+ # filter.using :maven, 'version'=>'1.2'
167
+ #
168
+ # You can also pass a proc or method. It will be called with the file name and content,
169
+ # to return the mapped content.
170
+ #
171
+ # Without any mapping, all files are copied as is.
172
+ #
173
+ # To register new mapping type see the Mapper class.
174
+ def using(*args, &block)
175
+ @mapper.using(*args, &block)
176
+ self
177
+ end
178
+
179
+ def recursive_with_dot_files(*dirs)
180
+ FileList[dirs.map { |dir| File.join(dir, '/**/{*,.*}') }].reject { |file| File.basename(file) =~ /^[.]{1,2}$/ }
181
+ end
182
+
183
+ def relative_path(to, from = '.')
184
+ to = Pathname.new(to).cleanpath
185
+ return to.to_s if from.nil?
186
+ to_path = Pathname.new(File.expand_path(to.to_s, "/"))
187
+ from_path = Pathname.new(File.expand_path(from.to_s, "/"))
188
+ to_path.relative_path_from(from_path).to_s
189
+ end
190
+
191
+ # :call-seq:
192
+ # run => boolean
193
+ #
194
+ # Runs the filter.
195
+ def run
196
+ copy_map = copy_map()
197
+
198
+ mkpath target.to_s
199
+ return false if copy_map.empty?
200
+
201
+ copy_map.each do |path, source|
202
+ dest = File.expand_path(path, target.to_s)
203
+ if File.directory?(source)
204
+ mkpath dest
205
+ else
206
+ mkpath File.dirname(dest)
207
+ if @mapper.mapper_type
208
+ mapped = @mapper.transform(File.open(source, 'rb') { |file| file.read }, path)
209
+ File.open(dest, 'wb') { |file| file.write mapped }
210
+ else # no mapping
211
+ cp source, dest
212
+ end
213
+ end
214
+ File.chmod(File.stat(source).mode | 0200, dest)
215
+ end
216
+ touch target.to_s
217
+ true
218
+ end
219
+
220
+ # Returns the target directory.
221
+ def to_s
222
+ target.to_s
223
+ end
224
+
225
+ protected
226
+
227
+ # :call-seq:
228
+ # pattern_match(file, pattern) => boolean
229
+ #
230
+ # This method returns true if the file name matches the pattern.
231
+ # The pattern may be a String, a Regexp or a Proc.
232
+ #
233
+ def pattern_match(file, pattern)
234
+ case
235
+ when pattern.is_a?(Regexp)
236
+ return file.match(pattern)
237
+ when pattern.is_a?(String)
238
+ return File.fnmatch(pattern, file)
239
+ when pattern.is_a?(Proc)
240
+ return pattern.call(file)
241
+ when pattern.is_a?(Rake::FileTask)
242
+ return pattern.to_s.match(file)
243
+ else
244
+ raise "Cannot interpret pattern #{pattern}"
245
+ end
246
+ end
247
+
248
+ private
249
+ def copy_map
250
+ sources.each { |source| raise "Source directory #{source} doesn't exist" unless File.exist?(source.to_s) }
251
+ raise 'No target directory specified, where am I going to copy the files to?' if target.nil?
252
+
253
+ sources.flatten.map(&:to_s).inject({}) do |map, source|
254
+ files = recursive_with_dot_files(source).
255
+ map { |file| relative_path(file, source) }.
256
+ select { |file| @include.empty? || @include.any? { |pattern| pattern_match(file, pattern) } }.
257
+ reject { |file| @exclude.any? { |pattern| pattern_match(file, pattern) } }
258
+ files.each do |file|
259
+ src, dest = File.expand_path(file, source), File.expand_path(file, target.to_s)
260
+ map[file] = src if !File.exist?(dest) || File.stat(src).mtime >= File.stat(dest).mtime || @force
261
+ end
262
+ map
263
+ end
264
+ end
265
+
266
+ # This class implements content replacement logic for Filter.
267
+ #
268
+ # To register a new template engine @:foo@, extend this class with a method like:
269
+ #
270
+ # def foo_transform(content, path = nil)
271
+ # # if this method yields a key, the value comes from the mapping hash
272
+ # content.gsub(/world/) { |str| yield :bar }
273
+ # end
274
+ #
275
+ # Then you can use :foo mapping type on a Filter
276
+ #
277
+ # filter.using :foo, :bar => :baz
278
+ #
279
+ # Or all by your own, simply
280
+ #
281
+ # Mapper.new(:foo, :bar => :baz).transform("Hello world") # => "Hello baz"
282
+ #
283
+ # You can handle configuration arguments by providing a @*_config@ method like:
284
+ #
285
+ # # The return value of this method is available with the :config accessor.
286
+ # def moo_config(*args, &block)
287
+ # raise ArgumentError, "Expected moo block" unless block_given?
288
+ # { :moos => args, :callback => block }
289
+ # end
290
+ #
291
+ # def moo_transform(content, path = nil)
292
+ # content.gsub(/moo+/i) do |str|
293
+ # moos = yield :moos # same than config[:moos]
294
+ # moo = moos[str.size - 3] || str
295
+ # config[:callback].call(moo)
296
+ # end
297
+ # end
298
+ #
299
+ # Usage for the @:moo@ mapper would be something like:
300
+ #
301
+ # mapper = Mapper.new(:moo, 'ooone', 'twoo') do |str|
302
+ # i = nil; str.capitalize.gsub(/\w/) { |s| s.send( (i = !i) ? 'upcase' : 'downcase' ) }
303
+ # end
304
+ # mapper.transform('Moo cow, mooo cows singing mooooo') # => 'OoOnE cow, TwOo cows singing MoOoOo'
305
+ class Mapper
306
+
307
+ attr_reader :mapper_type, :config
308
+
309
+ def initialize(*args, &block) #:nodoc:
310
+ using(*args, &block)
311
+ end
312
+
313
+ def using(*args, &block)
314
+ case args.first
315
+ when Hash # Maven hash mapping
316
+ using :maven, *args
317
+ when Binding # Erb binding
318
+ using :erb, *args
319
+ when Symbol # Mapping from a method
320
+ raise ArgumentError, "Unknown mapping type: #{args.first}" unless respond_to?("#{args.first}_transform", true)
321
+ configure(*args, &block)
322
+ when Regexp # Mapping using a regular expression
323
+ raise ArgumentError, 'Expected regular expression followed by mapping hash' unless args.size == 2 && Hash === args[1]
324
+ @mapper_type, @config = *args
325
+ else
326
+ unless args.empty? && block.nil?
327
+ raise ArgumentError, 'Expected proc, method or a block' if args.size > 1 || (args.first && block)
328
+ @mapper_type = :callback
329
+ config = args.first || block
330
+ raise ArgumentError, 'Expected proc, method or callable' unless config.respond_to?(:call)
331
+ @config = config
332
+ end
333
+ end
334
+ self
335
+ end
336
+
337
+ def transform(content, path = nil)
338
+ type = Regexp === mapper_type ? :regexp : mapper_type
339
+ raise ArgumentError, "Invalid mapper type: #{type.inspect}" unless respond_to?("#{type}_transform", true)
340
+ self.__send__("#{type}_transform", content, path) { |key| config[key] || config[key.to_s.to_sym] }
341
+ end
342
+
343
+ private
344
+ def configure(mapper_type, *args, &block)
345
+ configurer = method("#{mapper_type}_config") rescue nil
346
+ if configurer
347
+ @config = configurer.call(*args, &block)
348
+ else
349
+ raise ArgumentError, "Missing hash argument after :#{mapper_type}" unless args.size == 1 && Hash === args[0]
350
+ @config = {} unless Hash === @config
351
+ args.first.each_pair { |k, v| @config[k] = v.to_s }
352
+ end
353
+ @mapper_type = mapper_type
354
+ end
355
+
356
+ def maven_transform(content, path = nil)
357
+ content.gsub(/\$\{.*?\}/) { |str| yield(str[2..-2]) || str }
358
+ end
359
+
360
+ def ant_transform(content, path = nil)
361
+ content.gsub(/@.*?@/) { |str| yield(str[1..-2]) || str }
362
+ end
363
+
364
+ def ruby_transform(content, path = nil)
365
+ content.gsub(/#\{.*?\}/) { |str| yield(str[2..-2]) || str }
366
+ end
367
+
368
+ def regexp_transform(content, path = nil)
369
+ content.gsub(mapper_type) { |str| yield(str.scan(mapper_type).join) || str }
370
+ end
371
+
372
+ def callback_transform(content, path = nil)
373
+ config.call(path, content)
374
+ end
375
+
376
+ def erb_transform(content, path = nil)
377
+ case config
378
+ when Binding
379
+ bnd = config
380
+ when Hash
381
+ bnd = OpenStruct.new
382
+ table = config.inject({}) { |h, e| h[e.first.to_sym] = e.last; h }
383
+ bnd.instance_variable_set(:@table, table)
384
+ bnd = bnd.instance_eval { binding }
385
+ else
386
+ bnd = config.instance_eval { binding }
387
+ end
388
+ require 'erb'
389
+ ERB.new(content).result(bnd)
390
+ end
391
+
392
+ def erb_config(*args, &block)
393
+ if block_given?
394
+ raise ArgumentError, "Expected block or single argument, but both given." unless args.empty?
395
+ block
396
+ elsif args.size > 1
397
+ raise ArgumentError, "Expected block or single argument."
398
+ else
399
+ args.first
400
+ end
401
+ end
402
+
403
+ end # class Mapper
404
+
405
+ end
406
+
407
+ # :call-seq:
408
+ # filter(*source) => Filter
409
+ #
410
+ # Creates a filter that will copy files from the source directory(ies) into the target directory.
411
+ # You can extend the filter to modify files by mapping <tt>${key}</tt> into values in each
412
+ # of the copied files, and by including or excluding specific files.
413
+ #
414
+ # A filter is not a task, you must call the Filter#run method to execute it.
415
+ #
416
+ # For example, to copy all files from one directory to another:
417
+ # filter('src/files').into('target/classes').run
418
+ # To include only the text files, and replace each instance of <tt>${build}</tt> with the current
419
+ # date/time:
420
+ # filter('src/files').into('target/classes').include('*.txt').using('build'=>Time.now).run
421
+ def filter(*sources)
422
+ Filter.new.from(*sources)
423
+ end
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: capistrano-filter
3
+ version: !ruby/object:Gem::Version
4
+ hash: 15
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 2
9
+ version: "0.2"
10
+ platform: ruby
11
+ authors:
12
+ - "@"
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-05-13 00:00:00 -03:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: capistrano
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - "="
27
+ - !ruby/object:Gem::Version
28
+ hash: 61
29
+ segments:
30
+ - 2
31
+ - 5
32
+ - 19
33
+ version: 2.5.19
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ description: ops
37
+ email:
38
+ - "@"
39
+ executables: []
40
+
41
+ extensions: []
42
+
43
+ extra_rdoc_files: []
44
+
45
+ files:
46
+ - lib/capistrano/ext/filter.rb
47
+ - lib/capistrano/recipes/deploy/strategy/filter.rb
48
+ - lib/capistrano/recipes/deploy/strategy/copy_and_filter.rb
49
+ has_rdoc: true
50
+ homepage: ""
51
+ licenses: []
52
+
53
+ post_install_message:
54
+ rdoc_options: []
55
+
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ hash: 3
64
+ segments:
65
+ - 0
66
+ version: "0"
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ hash: 3
73
+ segments:
74
+ - 0
75
+ version: "0"
76
+ requirements: []
77
+
78
+ rubyforge_project: capistrano-filter
79
+ rubygems_version: 1.5.2
80
+ signing_key:
81
+ specification_version: 3
82
+ summary: possibilita o uso de filtro no deploy pelo capistrano
83
+ test_files: []
84
+