sprout 0.7.191-mswin32

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sprout might be problematic. Click here for more details.

@@ -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