sprout 0.7.191-mswin32

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,248 @@
1
+ =begin
2
+ Copyright (c) 2007 Pattern Park
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ This class has been commented out because the termios feature
24
+ that allows users to more securely enter passwords does not
25
+ work in a DOS shell.
26
+
27
+ It would be greatly appreciate if someone refactored this to either:
28
+ a) Get the same functionality in a cross-platform manner
29
+ b) Only require and use termios on systems that allow it
30
+ =end
31
+
32
+ #gem 'net-ssh', '1.1.4'
33
+ #gem 'net-sftp', '1.1.1'
34
+
35
+ require 'net/ssh'
36
+ require 'net/sftp'
37
+
38
+ #require 'termios'
39
+
40
+ module Sprout
41
+ class SFTPError < StandardError #:nodoc:
42
+ end
43
+
44
+ # The SFTPTask provides a simple rake task interface to the SFTP client RubyGem.
45
+ # This task can allow you to easily push build artifacts to a remote server
46
+ # with a single shell command.
47
+ class SFTPTask < Rake::Task
48
+
49
+ # Collection of files that should be transmitted to the remote server
50
+ attr_accessor :files
51
+ # Host name of the server to connect to with no protocol prefix, like: sub.yourhost.com
52
+ attr_accessor :host
53
+ # Username to send to the remote host. You will be prompted for this value if it is left null.
54
+ #
55
+ # NOTE: You should never check a file into version control with this field filled in, it is
56
+ # provided here as a convenience for getting set up.
57
+ attr_accessor :username
58
+ # The mode for transmitted files. Defaults to 0644
59
+ attr_accessor :file_mode
60
+ # the mode for created directories. Defaults to 0755
61
+ attr_accessor :dir_mode
62
+ # The local path to mask from transmitted files. This is key feature for automated file transmission.
63
+ # For example, if you are sending a file:
64
+ # bin/assets/img/SomeImage.jpg
65
+ # into a directory on your server like:
66
+ # /var/www/someproject/
67
+ # You don't necessarily want the 'bin' folder copied over, so you set the local_path to 'bin' like:
68
+ # t.local_path = 'bin'
69
+ # and your server will have the file uploaded to:
70
+ # /var/www/someproject/assets/img/SomeImage.jpg
71
+ attr_accessor :local_path
72
+ # The Remote base path where files should be transmitted, can be absolute or relative.
73
+ attr_accessor :remote_path
74
+ # Password to send to the remote host. You will be prompted for this value if it is left null.
75
+ #
76
+ # NOTE: You should never check a file into version control with this field filled in, it is
77
+ # provided here as a convenience for getting set up.
78
+ attr_accessor :password
79
+
80
+ def initialize(task_name, app)
81
+ super(task_name, app)
82
+ @name = name
83
+ @files = []
84
+ @dir_mode = 0755
85
+ @file_mode = 0644
86
+ @host = nil
87
+ end
88
+
89
+ def self.define_task(args, &block) # :nodoc:
90
+ t = super
91
+ yield t if block_given?
92
+ end
93
+
94
+ def execute(*args) # :nodoc:
95
+ if(@files.size == 0)
96
+ if(@local_path)
97
+ expr = @local_path + '/**/**/*'
98
+ @files = FileList[expr]
99
+ else
100
+ raise SFTPError.new('SFTP requires either a local_path or files to be transmitted')
101
+ end
102
+ else
103
+ if(!@local_path)
104
+ @local_path = ''
105
+ end
106
+ end
107
+
108
+ if(@host.nil?)
109
+ raise SFTPError.new('SFTP requires non-nil host parameter')
110
+ end
111
+
112
+ if(@username.nil?)
113
+ print "Username: "
114
+ @username = $stdin.gets.chomp!
115
+ raise SFTPError.new('SFTP requires username parameter') unless @username
116
+ end
117
+
118
+ if(@password.nil?)
119
+ print "Password: "
120
+ @password = $stdin.gets.chomp!
121
+ # @password = Password.get
122
+ raise SFTPError.new('SFTP requires password parameter') unless @password
123
+ end
124
+
125
+ if(get_confirmation)
126
+ puts ">> Connecting to Remote Server: #{@username}@#{@host}:#{@remote_path}"
127
+
128
+ Net::SFTP.start(@host, @username, @password) do |sftp|
129
+ begin
130
+ dir = sftp.opendir(@remote_path)
131
+ rescue Net::SFTP::Operations::StatusException
132
+ puts "[ERROR] [#{@remote_path}] does not exist on the server"
133
+ return
134
+ end
135
+ for file in @files
136
+ next if File.stat(file).directory?
137
+ remote_file = remote_file_name(file)
138
+ put_file(file, remote_file, sftp)
139
+ end
140
+ end
141
+ else
142
+ puts "[WARNING] Publish aborted by user request"
143
+ end
144
+ end
145
+
146
+ def put_file(local_file, remote_file, sftp) # :nodoc:
147
+ begin
148
+ create_remote_dir(remote_file, sftp)
149
+
150
+ if(file_changed(local_file, remote_file, sftp))
151
+ puts ">> Pushing #{local_file} to: #{remote_file}"
152
+ sftp.put_file(local_file, remote_file)
153
+ end
154
+ rescue Net::SFTP::Operations::StatusException => e
155
+ raise unless e.code == 2
156
+ sftp.put_file(local_file, remote_file)
157
+ sftp.setstat(remote_file, :permissions => @file_mode)
158
+ end
159
+ end
160
+
161
+ def create_remote_dir(path, sftp) # :nodoc:
162
+ begin
163
+ sftp.stat(File.dirname(path))
164
+ rescue Net::SFTP::Operations::StatusException => e
165
+ raise unless e.code == 2
166
+ dir = File.dirname(path.sub(@remote_path, ''))
167
+ parts = dir.split(File::SEPARATOR)
168
+ part = File.join(@remote_path, parts.shift)
169
+ while(part)
170
+ begin
171
+ sftp.stat(part)
172
+ rescue Net::SFTP::Operations::StatusException => e
173
+ raise unless e.code == 2
174
+ sftp.mkdir(part, :permissions => @dir_mode)
175
+ end
176
+ if(parts.size > 0)
177
+ part = File.join(part, parts.shift)
178
+ else
179
+ part = nil
180
+ end
181
+ end
182
+ end
183
+ end
184
+
185
+ def file_changed(local_file, remote_file, sftp) # :nodoc:
186
+ local_stat = File.stat(local_file)
187
+ remote_stat = sftp.stat(remote_file)
188
+ time_difference = (local_stat.mtime > Time.at(remote_stat.mtime))
189
+ size_difference = (local_stat.size != remote_stat.size)
190
+ return (time_difference || size_difference)
191
+ end
192
+
193
+ def remote_file_name(file) # :nodoc:
194
+ return @remote_path + file.sub(@local_path, '')
195
+ end
196
+
197
+ def get_confirmation # :nodoc:
198
+ puts "-----------------------------------------"
199
+ puts "Are you sure you want to publish #{@files.size} files to:"
200
+ puts "#{@username}@#{@host}:#{@remote_path}? [Yn]"
201
+ response = $stdin.gets.chomp!
202
+ return (response.downcase == 'y' || response == "")
203
+ end
204
+
205
+ end
206
+
207
+ =begin
208
+ # The following implementation does not work at all on DOS machines,
209
+ # is there a cross-platform way to solve the secure password prompt problem?
210
+ # Password handling snippet found at: http://www.caliban.org/ruby/ruby-password.shtml
211
+ class Password
212
+
213
+ def Password.get(message="Password: ")
214
+ begin
215
+ if $stdin.tty?
216
+ Password.echo false
217
+ print message if message
218
+ end
219
+
220
+ return $stdin.gets.chomp
221
+ ensure
222
+ if $stdin.tty?
223
+ Password.echo true
224
+ print "\n"
225
+ end
226
+ end
227
+ end
228
+
229
+ def Password.echo(on=true, masked=false)
230
+ term = Termios::getattr( $stdin )
231
+
232
+ if on
233
+ term.c_lflag |= ( Termios::ECHO | Termios::ICANON )
234
+ else # off
235
+ term.c_lflag &= ~Termios::ECHO
236
+ term.c_lflag &= ~Termios::ICANON if masked
237
+ end
238
+
239
+ Termios::setattr( $stdin, Termios::TCSANOW, term )
240
+ end
241
+ end
242
+ =end
243
+ end
244
+
245
+
246
+ def sftp(args, &block)
247
+ Sprout::SFTPTask.define_task(args, &block)
248
+ end
@@ -0,0 +1,153 @@
1
+ =begin
2
+ Copyright (c) 2007 Pattern Park
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ This class has been commented out because the termios feature
24
+ that allows users to more securely enter passwords does not
25
+ work in a DOS shell.
26
+
27
+ It would be greatly appreciate if someone refactored this to either:
28
+ a) Get the same functionality in a cross-platform manner
29
+ b) Only require and use termios on systems that allow it
30
+ =end
31
+
32
+ #gem 'net-ssh', '1.1.4'
33
+ #gem 'net-sftp', '1.1.1'
34
+
35
+ require 'net/ssh'
36
+ require 'net/sftp'
37
+ #require 'termios'
38
+
39
+ module Sprout
40
+ class SSHError < StandardError #:nodoc:
41
+ end
42
+
43
+ # The SSHTask allows you to execute arbitrary commands on a remote host.
44
+ #
45
+ # ssh :update_gem_index do |t|
46
+ # t.host = 'dev.projectsprouts.com'
47
+ # t.username = 'someUser'
48
+ # t.commands << 'cd /var/www/projectsprouts/current/gems'
49
+ # t.commands << 'gem generate_index -d .'
50
+ # end
51
+ #
52
+ class SSHTask < Rake::Task
53
+
54
+ # Host name of the server to connect to with no protocol prefix, like: sub.yourhost.com
55
+ attr_accessor :host
56
+ # Array of commands that will be executed on the remote machine
57
+ attr_accessor :commands
58
+ # Username to send to the remote host. You will be prompted for this value if it is left null.
59
+ attr_accessor :username
60
+ # Password to send to the remote host. You will be prompted for this value if it is left null.
61
+ #
62
+ # NOTE: You should never check a file into version control with this field filled in, it is
63
+ # provided here as a convenience for getting set up.
64
+ attr_accessor :password
65
+
66
+ def initialize(task_name, app)
67
+ super(task_name, app)
68
+ @name = name
69
+ @host = nil
70
+ @queue = []
71
+ @commands = []
72
+ end
73
+
74
+ def self.define_task(args, &block) # :nodoc:
75
+ t = super
76
+ yield t if block_given?
77
+ end
78
+
79
+ def execute(*args) # :nodoc:
80
+ if(@host.nil?)
81
+ throw SSHError.new('SSH requires a valid host parameter')
82
+ end
83
+
84
+ if(@username.nil?)
85
+ print "Username: "
86
+ @username = $stdin.gets.chomp!
87
+ raise SFTPError.new('SFTP requires username parameter') unless @username
88
+ end
89
+
90
+ if(@password.nil?)
91
+ print "Password: "
92
+ @password = $stdin.gets.chomp!
93
+ # @password = Password.get
94
+ raise SFTPError.new('SFTP requires password parameter') unless @password
95
+ end
96
+
97
+ puts ">> Connecting to Remote Server: #{@username}@#{@host}:#{@remote_path}"
98
+ Net::SSH.start(@host, @username, @password) do |session|
99
+ session.open_channel do |channel|
100
+ commands.each do |command|
101
+ puts ">> #{command}"
102
+ channel.exec command
103
+ end
104
+ channel.close
105
+ end
106
+ session.loop
107
+ end
108
+ end
109
+
110
+ end
111
+
112
+ =begin
113
+ # The following implementation does not work at all on DOS machines,
114
+ # is there a cross-platform way to solve the secure password prompt problem?
115
+ # Password handling snippet found at: http://www.caliban.org/ruby/ruby-password.shtml
116
+ class Password
117
+
118
+ def Password.get(message="Password: ")
119
+ begin
120
+ if $stdin.tty?
121
+ Password.echo false
122
+ print message if message
123
+ end
124
+
125
+ return $stdin.gets.chomp
126
+ ensure
127
+ if $stdin.tty?
128
+ Password.echo true
129
+ print "\n"
130
+ end
131
+ end
132
+ end
133
+
134
+ def Password.echo(on=true, masked=false)
135
+ term = Termios::getattr( $stdin )
136
+
137
+ if on
138
+ term.c_lflag |= ( Termios::ECHO | Termios::ICANON )
139
+ else # off
140
+ term.c_lflag &= ~Termios::ECHO
141
+ term.c_lflag &= ~Termios::ICANON if masked
142
+ end
143
+
144
+ Termios::setattr( $stdin, Termios::TCSANOW, term )
145
+ end
146
+ end
147
+ =end
148
+ end
149
+
150
+
151
+ def ssh(args, &block)
152
+ Sprout::SSHTask.define_task(args, &block)
153
+ end
@@ -0,0 +1,569 @@
1
+
2
+ module Sprout
3
+
4
+ class ToolTaskError < StandardError #:nodoc:
5
+ end
6
+
7
+ # The ToolTask provides some base functionality for any Command Line Interface (CLI) tool.
8
+ # It also provides support for GUI tools that you would like to expose from the
9
+ # Command Line (Like the Flash Player for example).
10
+ #
11
+ # ToolTask extends Rake::FileTask, and should be thought of in the same way.
12
+ # Martin Fowler did a much better job of describing Rake and specifically FileTasks than
13
+ # I can in his (now classic) Rake article[http://martinfowler.com/articles/rake.html#FileTasks] from 2005.
14
+ #
15
+ # What this means is that most tool task instances should be named for the file that they will create.
16
+ # For example, an Sprout::MXMLCTask instance should be named for the SWF that it will generate.
17
+ #
18
+ # mxmlc 'bin/SomeProject.swf' => :corelib do |t|
19
+ # t.input = 'src/SomeProject.as'
20
+ # t.default_size = '800 600'
21
+ # end
22
+ #
23
+ # In general, a tool task will only be executed if it's output file (name) does not exist or
24
+ # if the output file is older than any file identified as a prerequisite.
25
+ #
26
+ # Many of the compiler tasks take advantage of this feature by opting out of unnecessary compilation.
27
+ #
28
+ # Subclasses can add and configure command line parameters by calling the protected add_param method
29
+ # that is implemented on this class.
30
+ #
31
+ class ToolTask < Rake::FileTask
32
+
33
+ # Arguments to be prepended in front of the command line output
34
+ attr_accessor :prepended_args
35
+ # Arguments to appended at the end of the command line output
36
+ attr_accessor :appended_args
37
+
38
+ def initialize(name, app) # :nodoc:
39
+ super
40
+ @prepended_args = nil
41
+ @appended_args = nil
42
+ @default_gem_name = nil
43
+ @default_gem_path = nil
44
+ initialize_task
45
+ end
46
+
47
+ def self.define_task(args, &block)
48
+ t = super
49
+ if(t.is_a?(ToolTask))
50
+ yield t if block_given?
51
+ t.define
52
+ t.prepare
53
+ end
54
+ return t
55
+ end
56
+
57
+ # Full name of the sprout tool gem that this tool task will use. For example, the MXMLCTask
58
+ # uses the sprout-flex3sdk-tool at the time of this writing, but will at some point
59
+ # change to use the sprout-flex3sdk-tool. You can combine this value with gem_version
60
+ # in order to specify exactly which gem your tool task is executing.
61
+ def gem_name
62
+ return @gem_name ||= @default_gem_name
63
+ end
64
+
65
+ def gem_name=(name)
66
+ @gem_name = name
67
+ end
68
+
69
+ # The exact gem version that you would like the ToolTask to execute. By default this value
70
+ # should be nil and will download the latest version of the gem that is available unless
71
+ # there is a version already installed on your system.
72
+ #
73
+ # This attribute could be an easy
74
+ # way to update your local gem to the latest version without leaving your build file,
75
+ # but it's primary purpose is to allow you to specify very specific versions of the tools
76
+ # that your project depends on. This way your team can rest assured that they are all
77
+ # working with the same tools.
78
+ def gem_version
79
+ return @gem_version ||= nil
80
+ end
81
+
82
+ def gem_version=(version)
83
+ @gem_version = version
84
+ end
85
+
86
+ # The path inside the installed gem where an executable can be found. For the MXMLCTask, this
87
+ # value is 'bin/mxmlc'.
88
+ def gem_path
89
+ return @gem_path ||= @default_gem_path
90
+ end
91
+
92
+ # Create a string that can be turned into a file
93
+ # that rdoc can parse to describe the customized
94
+ # or generated task using param name, type and
95
+ # description
96
+ def to_rdoc
97
+ result = ''
98
+ parts = self.class.to_s.split('::')
99
+ class_name = parts.pop
100
+ module_count = 0
101
+ while(module_name = parts.shift)
102
+ result << "module #{module_name}\n"
103
+ module_count += 1
104
+ end
105
+
106
+ result << "class #{class_name} < ToolTask\n"
107
+
108
+ params.each do |param|
109
+ result << param.to_rdoc
110
+ end
111
+
112
+ while((module_count -= 1) >= 0)
113
+ result << "end\nend\n"
114
+ end
115
+
116
+ return result
117
+ end
118
+
119
+ def execute(*args)
120
+ #puts ">> Executing #{File.basename(exe)} #{to_shell}"
121
+ exe = Sprout.get_executable(gem_name, gem_path, gem_version)
122
+ User.execute(exe, to_shell)
123
+ end
124
+
125
+ # Create a string that represents this configured tool for shell execution
126
+ def to_shell
127
+ result = []
128
+ result << @prepended_args unless @prepended_args.nil?
129
+ params.each do |param|
130
+ if(param.visible?)
131
+ result << param.to_shell
132
+ end
133
+ end
134
+ result << @appended_args unless @appended_args.nil?
135
+ return result.join(' ')
136
+ end
137
+
138
+ # An Array of all parameters that have been added to this Tool.
139
+ def params
140
+ @params ||= []
141
+ end
142
+
143
+ # Called after initialize and define, usually subclasses should
144
+ # only override define.
145
+ def prepare
146
+ # Get each added param to inject prerequisites as necessary
147
+ params.each do |param|
148
+ param.prepare
149
+ end
150
+ # Ensure there are no duplicates in the prerequisite collection
151
+ @prerequisites = prerequisites.uniq
152
+ end
153
+
154
+ def define
155
+ resolve_libraries(prerequisites)
156
+ end
157
+
158
+ # The default file expression to append to each PathParam
159
+ # in order to build file change prerequisites.
160
+ #
161
+ # Defaults to '/**/**/*'
162
+ #
163
+ def default_file_expression
164
+ @default_file_expression ||= '/**/**/*'
165
+ end
166
+
167
+ protected
168
+
169
+ def initialize_task
170
+ end
171
+
172
+ def validate
173
+ params.each do |param|
174
+ param.validate
175
+ end
176
+ end
177
+
178
+ # +add_param+ is the workhorse of the ToolTask.
179
+ # This method is used to add new shell parameters to the task.
180
+ # +name+ is a symbol or string that represents the parameter that you would like to add
181
+ # such as :debug or :source_path.
182
+ # +type+ is usually sent as a Ruby symbol and can be one of the following:
183
+ #
184
+ # [:string] Any string value
185
+ # [:boolean] true or false
186
+ # [:number] Any number
187
+ # [:file] Path to a file
188
+ # [:url] Basic URL
189
+ # [:path] Path to a directory
190
+ # [:files] Collection of files
191
+ # [:paths] Collection of directories
192
+ # [:strings] Collection of arbitrary strings
193
+ # [:urls] Collection of URLs
194
+ #
195
+ # Be sure to check out the Sprout::TaskParam class to learn more about
196
+ # block editing the parameters.
197
+ #
198
+ # Once parameters have been added using the +add_param+ method, clients
199
+ # can set and get those parameters from the newly created task.
200
+ #
201
+ def add_param(name, type, &block) # :yields: Sprout::TaskParam
202
+ name = name.to_s
203
+
204
+ # First ensure the named accessor doesn't yet exist...
205
+ if(param_hash[name])
206
+ raise ToolTaskError.new("TaskBase.add_param called with existing parameter name: #{name}")
207
+ end
208
+
209
+ param = create_param(type)
210
+ param.init do |p|
211
+ p.belongs_to = self
212
+ p.name = name
213
+ p.type = type
214
+ yield p if block_given?
215
+ end
216
+
217
+ param_hash[name] = param
218
+ params << param
219
+ end
220
+
221
+ # Alias an existing parameter with another name. For example, the
222
+ # existing parameter :source_path might be given an alias '-sp' as follows:
223
+ #
224
+ # add_param_alias(:sp, :source_path)
225
+ #
226
+ # Alias parameters cannot be configured differently from the parameter
227
+ # that they alias
228
+ #
229
+ def add_param_alias(name, other_param)
230
+ if(param_hash.has_key? other_param.to_s)
231
+ param_hash[name.to_s] = param_hash[other_param.to_s]
232
+ else
233
+ raise ToolTaskError.new("TaskBase.add_param_alis called with")
234
+ end
235
+ end
236
+
237
+ protected
238
+
239
+ def create_param(type)
240
+ return eval("#{type.to_s.capitalize}Param.new")
241
+ end
242
+
243
+ def param_hash
244
+ @param_hash ||= {}
245
+ end
246
+
247
+ def respond_to?(name)
248
+ result = super
249
+ if(!result)
250
+ result = param_hash.has_key? name
251
+ end
252
+ return result
253
+ end
254
+
255
+ def clean_name(name)
256
+ name.gsub(/=$/, '')
257
+ end
258
+
259
+ def method_missing(name,*args)
260
+ name = name.to_s
261
+ cleaned = clean_name(name)
262
+ if(!respond_to?(cleaned))
263
+ raise NoMethodError.new("undefined method '#{name}' for #{self.class}")
264
+ end
265
+ param = param_hash[cleaned]
266
+
267
+ if(name =~ /=$/)
268
+ param.value = args.shift
269
+ elsif(param)
270
+ param.value
271
+ else
272
+ raise ToolTaskError.new("method_missing called with undefined parameter [#{name}]")
273
+ end
274
+ end
275
+
276
+ # Iterate over all prerequisites looking for any
277
+ # that are a LibraryTask.
278
+ # Concrete ToolTask implementations should
279
+ # override resolve_library in order to add
280
+ # the library sources or binaries appropriately.
281
+ def resolve_libraries(prerequisites)
282
+ prerequisites.each do |prereq|
283
+ instance = Rake::application[prereq]
284
+ if(instance.is_a?(LibraryTask))
285
+ resolve_library(instance)
286
+ end
287
+ end
288
+ end
289
+
290
+ # Concrete ToolTasks should override this method
291
+ # and add any dependent libraries appropriately
292
+ def resolve_library(library_task)
293
+ end
294
+
295
+ # If the provided path contains spaces, wrap it in quotes so that
296
+ # shell tools won't choke on the spaces
297
+ def clean_path(path)
298
+ if(path.index(' '))
299
+ path = %{"#{path}"}
300
+ end
301
+ return path
302
+ end
303
+
304
+ end
305
+
306
+ #######################################################
307
+ # Parameter Implementations
308
+
309
+ # The base class for all ToolTask parameters. This class is extended by a variety
310
+ # of concrete implementations.
311
+ #
312
+ # At the time of this writing, only the :boolean TaskParam modifies the interface by
313
+ # adding the +show_on_false+ attribute.
314
+ #
315
+ # Some other helpful features are as follows:
316
+ #
317
+ # :file, :files, :path and :paths will all add any items that have been added to
318
+ # their values as file task prerequisites. This is especially helpful when writing
319
+ # rake tasks for Command Line Interface (CLI) compilers.
320
+ #
321
+ class TaskParam
322
+ attr_accessor :name
323
+ attr_accessor :type
324
+ attr_accessor :validator
325
+ attr_accessor :description
326
+ attr_accessor :visible
327
+ attr_accessor :hidden_name
328
+ attr_accessor :hidden_value
329
+ attr_accessor :required
330
+ attr_accessor :belongs_to
331
+
332
+ attr_writer :prefix
333
+ attr_writer :value
334
+ attr_writer :delimiter
335
+ attr_writer :shell_name
336
+
337
+ # Set the file_expression (blob) to append to each path
338
+ # in order to build the prerequisites FileList.
339
+ #
340
+ # Defaults to parent ToolTask.default_file_expression
341
+ attr_writer :file_expression
342
+
343
+ def init
344
+ yield self if block_given?
345
+ end
346
+
347
+ # By default, ToolParams only appear in the shell
348
+ # output when they are not nil
349
+ def visible?
350
+ @visible ||= value
351
+ end
352
+
353
+ def required?
354
+ (required == true)
355
+ end
356
+
357
+ def validate
358
+ if(required? && !visible?)
359
+ raise ToolTaskError.new("#{name} is required and must not be nil")
360
+ end
361
+ end
362
+
363
+ def prepare
364
+ prepare_prerequisites
365
+ end
366
+
367
+ def prepare_prerequisites
368
+ end
369
+
370
+ # Should the param name be hidden from the shell?
371
+ # Used for params like 'input' on mxmlc
372
+ def hidden_name?
373
+ @hidden_name ||= false
374
+ end
375
+
376
+ # Should the param value be hidden from the shell?
377
+ # Usually used for Boolean toggles like '-debug'
378
+ def hidden_value?
379
+ @hidden_value ||= false
380
+ end
381
+
382
+ # Leading character for each parameter
383
+ # Can sometimes be an empty string,
384
+ # other times it's a double dash '--'
385
+ # but usually it's just a single dash '-'
386
+ def prefix
387
+ @prefix ||= '-'
388
+ end
389
+
390
+ def value
391
+ @value ||= nil
392
+ end
393
+
394
+ def shell_value
395
+ value.to_s
396
+ end
397
+
398
+ def file_expression # :nodoc:
399
+ @file_expression ||= belongs_to.default_file_expression
400
+ end
401
+
402
+ # ToolParams join their name/value pair with an
403
+ # equals sign by default, this can be modified
404
+ # To a space or whatever you wish
405
+ def delimiter
406
+ @delimiter ||= '='
407
+ end
408
+
409
+ # Return the name with a single leading dash
410
+ # and underscores replaced with dashes
411
+ def shell_name
412
+ @shell_name ||= prefix + name.split('_').join('-')
413
+ end
414
+
415
+ def to_shell
416
+ if(hidden_name?)
417
+ return shell_value
418
+ elsif(hidden_value?)
419
+ return shell_name
420
+ else
421
+ return "#{shell_name}#{delimiter}#{shell_value}"
422
+ end
423
+ end
424
+
425
+ # Create a string that can be turned into a file
426
+ # that rdoc can parse to describe the customized
427
+ # or generated task using param name, type and
428
+ # description
429
+ def to_rdoc
430
+ result = ''
431
+ parts = description.split("\n") unless description.nil?
432
+ result << "# #{parts.join("\n# ")}\n" unless description.nil?
433
+ result << "def #{name}=(#{type})\n @#{name} = #{type}\nend\n\n"
434
+ return result
435
+ end
436
+
437
+ end
438
+
439
+ # Concrete param object for :string values
440
+ class StringParam < TaskParam # :nodoc:
441
+
442
+ end
443
+
444
+ # Concrete param object for :symbol values
445
+ # like class names
446
+ class SymbolParam < TaskParam # :nodoc:
447
+ end
448
+
449
+ # Concrete param object for :url values
450
+ class UrlParam < TaskParam # :nodoc:
451
+ end
452
+
453
+ # Concrete param object for :number values
454
+ class NumberParam < TaskParam # :nodoc:
455
+ end
456
+
457
+ # Concrete param object for :file values
458
+ class FileParam < TaskParam # :nodoc:
459
+ def prepare_prerequisites
460
+ if(value && value != belongs_to.name.to_s)
461
+ file value
462
+ belongs_to.prerequisites << value
463
+ end
464
+ end
465
+ end
466
+
467
+ # Concrete param object for :path values
468
+ class PathParam < FileParam # :nodoc:
469
+ end
470
+
471
+ # Concrete param object for :boolean values
472
+ class BooleanParam < TaskParam # :nodoc:
473
+ attr_writer :show_on_false
474
+
475
+ def visible?
476
+ @visible ||= value
477
+ if(show_on_false)
478
+ return true unless value
479
+ else
480
+ return @visible
481
+ end
482
+ end
483
+
484
+ def show_on_false
485
+ @show_on_false ||= false
486
+ end
487
+
488
+ def value
489
+ @value ||= false
490
+ end
491
+
492
+ end
493
+
494
+ # Concrete param object for collections of strings
495
+ class StringsParam < TaskParam # :nodoc:
496
+
497
+ # Files lists are initialized to an empty array by default
498
+ def value
499
+ @value ||= []
500
+ end
501
+
502
+ # By default, the FilesParams will not appear in the shell
503
+ # output if there are zero items in the collection
504
+ def visible?
505
+ @visible ||= (value && value.size > 0)
506
+ end
507
+
508
+ # Default delimiter is +=
509
+ # This is what will appear between each name/value pair as in:
510
+ # "source_path+=src source_path+=test source_path+=lib"
511
+ def delimiter
512
+ @delimiter ||= "+="
513
+ end
514
+
515
+ # Returns a shell formatted string of the collection
516
+ def to_shell
517
+ result = []
518
+ value.each do |str|
519
+ result << "#{shell_name}#{delimiter}#{str}"
520
+ end
521
+ return result.join(' ')
522
+ end
523
+ end
524
+
525
+ # Concrete param object for collections of symbols (like class names)
526
+ class SymbolsParam < StringsParam # :nodoc:
527
+ end
528
+
529
+ # Concrete param object for collections of files
530
+ class FilesParam < StringsParam # :nodoc:
531
+
532
+ def prepare
533
+ super
534
+ usr = User.new
535
+ path = nil
536
+ value.each_index do |index|
537
+ path = value[index]
538
+ value[index] = usr.clean_path path
539
+ end
540
+ end
541
+
542
+ def prepare_prerequisites
543
+ value.each do |f|
544
+ file f
545
+ belongs_to.prerequisites << f
546
+ end
547
+ end
548
+ end
549
+
550
+ # Concrete param object for collections of paths
551
+ class PathsParam < FilesParam # :nodoc:
552
+
553
+ def prepare_prerequisites
554
+ usr = User.new
555
+ value.each do |f|
556
+ files = FileList[f + file_expression]
557
+ files.each do |req_file|
558
+ file req_file
559
+ belongs_to.prerequisites << req_file
560
+ end
561
+ end
562
+ end
563
+ end
564
+
565
+ # Concrete param object for collections of files
566
+ class UrlsParam < StringsParam # :nodoc:
567
+ end
568
+
569
+ end