rap 0.13.1 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
data/History CHANGED
@@ -1,4 +1,11 @@
1
- == 0.17.1 / 2009-06-06
1
+ == 0.14.0 / 2009-06-17
2
+
3
+ * added dependencies directly to Rap::Task
4
+ * removed sh method from Declarations
5
+ (include Rap::Utils instead)
6
+ * updates for Tap-0.18.0
7
+
8
+ == 0.13.1 / 2009-06-06
2
9
 
3
10
  Updates for Tap-0.17.1.
4
11
 
data/README CHANGED
@@ -43,7 +43,7 @@ Now from the command line:
43
43
  --------------------------------------------------------------------------------
44
44
  Says goodnight with a configurable message.
45
45
  --------------------------------------------------------------------------------
46
- usage: rap goodnight OBJ
46
+ usage: tap run -- goodnight OBJ
47
47
 
48
48
  configurations:
49
49
  --message MESSAGE
data/bin/rap CHANGED
@@ -24,6 +24,7 @@ end
24
24
 
25
25
  Dir.glob('[TtRr]apfile{,.rb}').each do |rapfile|
26
26
  next unless File.file?(rapfile)
27
+ env.scan(rapfile, "task|join|middleware")
27
28
  load rapfile
28
29
  end
29
30
 
@@ -52,7 +53,7 @@ when '--help', nil, '-T'
52
53
  end
53
54
 
54
55
  puts
55
- puts "version #{Tap::VERSION} -- #{Tap::WEBSITE}"
56
+ puts "version #{Rap::VERSION} -- #{Rap::WEBSITE}"
56
57
  else
57
58
  begin
58
59
  schema = Tap::Schema.parse(ARGV)
data/lib/rap.rb CHANGED
@@ -3,4 +3,11 @@ require 'rap/declarations'
3
3
 
4
4
  module Rap
5
5
  autoload(:Rake, 'rap/rake')
6
+
7
+ MAJOR = 0
8
+ MINOR = 14
9
+ TINY = 0
10
+
11
+ VERSION="#{MAJOR}.#{MINOR}.#{TINY}"
12
+ WEBSITE="http://tap.rubyforge.org/rap"
6
13
  end
@@ -1,5 +1,4 @@
1
1
  require 'rap/task'
2
- require 'rap/utils'
3
2
 
4
3
  module Rap
5
4
 
@@ -51,8 +50,6 @@ module Rap
51
50
  # See the {Syntax Reference}[link:files/doc/Syntax%20Reference.html] for more
52
51
  # information.
53
52
  module Declarations
54
- include Utils
55
-
56
53
  # The environment in which declared task classes are registered.
57
54
  # By default a Tap::Env for Dir.pwd.
58
55
  def Declarations.env() @@env ||= Tap::Env.new; end
@@ -238,7 +235,7 @@ module Rap
238
235
  alias desc original_desc
239
236
 
240
237
  # hide remaining Declarations methods (including Utils methods)
241
- private :namespace, :sh
238
+ private :namespace
242
239
  # :startdoc:
243
240
 
244
241
  private
@@ -35,6 +35,24 @@ module Rap
35
35
  class Task < Tap::Task
36
36
  class << self
37
37
 
38
+ # Returns class dependencies
39
+ attr_reader :dependencies
40
+
41
+ # Returns or initializes the instance of self cached with app.
42
+ def instance(app=Tap::App.instance, auto_initialize=true)
43
+ app.cache[self] ||= (auto_initialize ? new({}, app) : nil)
44
+ end
45
+
46
+ def inherited(child) # :nodoc:
47
+ unless child.instance_variable_defined?(:@source_file)
48
+ caller[0] =~ Lazydoc::CALLER_REGEXP
49
+ child.instance_variable_set(:@source_file, File.expand_path($1))
50
+ end
51
+
52
+ child.instance_variable_set(:@dependencies, dependencies.dup)
53
+ super
54
+ end
55
+
38
56
  # Sets actions.
39
57
  attr_writer :actions
40
58
 
@@ -73,7 +91,12 @@ module Rap
73
91
  #
74
92
  def parse!(argv=ARGV, app=Tap::App.instance)
75
93
  instance = super
76
- instance.args = argv
94
+
95
+ # store args on instance and clear so that instance
96
+ # will not be enqued with any inputs
97
+ instance.args = argv.dup
98
+ argv.clear
99
+
77
100
  instance
78
101
  end
79
102
 
@@ -135,62 +158,115 @@ module Rap
135
158
 
136
159
  subclass
137
160
  end
161
+
162
+ # Sets a class-level dependency; when task class B depends_on another
163
+ # task class A, instances of B are initialized to depend on a shared
164
+ # instance of A. The shared instance is specific to an app and can
165
+ # be accessed through instance(app).
166
+ #
167
+ # If a non-nil name is specified, depends_on will create a reader of
168
+ # the dependency instance.
169
+ #
170
+ # class A < Rap::Task
171
+ # end
172
+ #
173
+ # class B < Rap::Task
174
+ # depends_on :a, A
175
+ # end
176
+ #
177
+ # app = Tap::App.new
178
+ # b = B.new({}, app)
179
+ # b.dependencies # => [A.instance(app)]
180
+ # b.a # => A.instance(app)
181
+ #
182
+ # Returns self.
183
+ def depends_on(name, dependency_class)
184
+ unless dependency_class.ancestors.include?(Rap::Task)
185
+ raise "not a Rap::Task: #{dependency_class}"
186
+ end
187
+
188
+ unless dependencies.include?(dependency_class)
189
+ dependencies << dependency_class
190
+ end
191
+
192
+ if name
193
+ # returns the resolved result of the dependency
194
+ define_method(name) do
195
+ dependency_class.instance(app)
196
+ end
197
+
198
+ public(name)
199
+ end
200
+
201
+ self
202
+ end
138
203
  end
139
204
 
140
- # The result of self, set by call.
141
- attr_reader :result
205
+ instance_variable_set(:@dependencies, [])
142
206
 
143
- # The arguments assigned to self during call.
207
+ # An array of node dependencies
208
+ attr_reader :dependencies
209
+
210
+ # The arguments assigned to self.
144
211
  attr_accessor :args
145
212
 
146
213
  def initialize(config={}, app=Tap::App.instance)
147
214
  super
215
+ @dependencies = []
148
216
  @resolved = false
149
- @result = nil
150
217
  @args = nil
218
+
219
+ # setup class dependencies
220
+ self.class.dependencies.each do |dependency_class|
221
+ depends_on dependency_class.instance(app)
222
+ end
151
223
  end
152
224
 
153
- # Conditional call to the super call; only calls once. Returns result.
154
- def call(*args)
225
+ # Conditional call to the super call; only calls once and with args (if
226
+ # set). Call recursively resolves dependencies and raises an error for
227
+ # circular dependencies.
228
+ #
229
+ def call
230
+ if resolved?
231
+ return
232
+ end
155
233
 
156
- # Declaration tasks function as dependencies, but unlike normal
157
- # dependencies, they CAN take arguments from the command line.
158
- # Such arguments will be set as args, and be used to enque the
159
- # task.
160
- #
161
- # If the task executes from the queue first, args will be
162
- # provided to call and they should equal self.args. If the task
163
- # executes as a dependency first, call will not receive args and
164
- # in that case self.args will be used.
165
- #
166
- # This warns for cases that odd workflows can produce where the
167
- # args have been set and DIFFERENT args are used to enque the task.
168
- # In these cases always go with the pre-set args but warn the issue.
169
- self.args ||= args
170
- unless self.args == args
171
- if @resolved
172
- warn "warn: ignorning dependency task inputs #{args.inspect} (#{self})"
173
- else
174
- warn "warn: invoking dependency task with preset args #{self.args.inspect} and not inputs #{args.inspect} (#{self})"
175
- end
234
+ if resolving?
235
+ raise DependencyError.new(self)
176
236
  end
177
237
 
178
- unless @resolved
179
- @resolved = true
180
- @result = super(*self.args)
238
+ @resolved = nil
239
+ begin
240
+ dependencies.each do |dependency|
241
+ dependency.call
242
+ end
243
+ rescue(DependencyError)
244
+ $!.trace.unshift(self)
245
+ raise $!
181
246
  end
182
- result
247
+
248
+ @resolved = true
249
+ args ? super(*args) : super()
183
250
  end
184
251
 
252
+ # Alias for call.
253
+ def resolve!
254
+ call
255
+ end
256
+
185
257
  # Returns true if already resolved by call.
186
258
  def resolved?
187
- @resolved
259
+ @resolved == true
260
+ end
261
+
262
+ def resolving?
263
+ @resolved == nil
188
264
  end
189
265
 
190
266
  # Resets self so call will call again. Also sets result to nil.
191
267
  def reset
268
+ raise "cannot reset when resolving" if resolving?
192
269
  @resolved = false
193
- @result = nil
194
270
  end
195
271
 
196
272
  # Collects the inputs into an OpenStruct according to the class arg_names,
@@ -216,5 +292,29 @@ module Rap
216
292
 
217
293
  nil
218
294
  end
295
+
296
+ # Adds the dependency to self.
297
+ def depends_on(dependency)
298
+ raise "cannot depend on self" if dependency == self
299
+ unless dependencies.include?(dependency)
300
+ dependencies << dependency
301
+ end
302
+ self
303
+ end
304
+
305
+ end
306
+
307
+ # Raised for circular dependencies during Rap::Task.resolve!
308
+ class DependencyError < StandardError
309
+ attr_reader :trace
310
+
311
+ def initialize(task)
312
+ @trace = [task]
313
+ super()
314
+ end
315
+
316
+ def message
317
+ "circular dependency: [#{trace.collect {|task| task.class.to_s }.join(', ')}]"
318
+ end
219
319
  end
220
320
  end
@@ -1,18 +1,67 @@
1
+ require 'tempfile'
2
+
1
3
  module Rap
4
+ # Provides several shell utility methods for calling programs.
5
+ #
6
+ # == Windows
7
+ # MSDOS has command line length limits specific to the version of Windows being
8
+ # run (from http://www.ss64.com/nt/cmd.html):
9
+ #
10
+ # Windows NT:: 256 characters
11
+ # Windows 2000:: 2046 characters
12
+ # Windows XP:: 8190 characters
13
+ #
14
+ # Commands longer than these limits fail, usually with something like: 'the input
15
+ # line is too long'
2
16
  module Utils
17
+
18
+ # :startdoc:::-
3
19
  # Run the system command +cmd+, passing the result to the block, if given.
4
20
  # Raises an error if the command fails. Uses the same semantics as
5
21
  # Kernel::exec and Kernel::system.
6
22
  #
7
23
  # Based on FileUtils#sh from Rake.
24
+ # :startdoc:::+
8
25
  def sh(*cmd) # :yields: ok, status
9
26
  ok = system(*cmd)
10
27
 
11
28
  if block_given?
12
29
  yield(ok, $?)
13
30
  else
14
- ok or raise "Command failed with status (#{$?.exitstatus}): [#{cmd.join(' ')}]"
31
+ ok or raise "Command failed with status (#{$?.exitstatus}): [#{ cmd.join(' ')}]"
32
+ end
33
+ end
34
+
35
+ # Runs the system command +cmd+ using sh, redirecting the output to the
36
+ # specified file path. Uses the redirection command:
37
+ #
38
+ # "> \"#{path}\" 2>&1 #{cmd}"
39
+ #
40
+ # This redirection has been tested on Windows, OS X, and Fedora. See
41
+ # http://en.wikipedia.org/wiki/Redirection_(Unix) for pointers on
42
+ # redirection. This style of redirection SHOULD NOT be used with
43
+ # commands that contain other redirections.
44
+ def redirect_sh(cmd, path, &block) # :yields: ok, status
45
+ sh( "> \"#{path}\" 2>&1 #{cmd}", &block)
46
+ end
47
+
48
+ # Runs the system command +cmd+ and returns the output as a string.
49
+ def capture_sh(cmd, quiet=false, &block) # :yields: ok, status, tempfile_path
50
+ tempfile = Tempfile.new('shell_utils')
51
+ tempfile.close
52
+ redirect_sh(cmd, tempfile.path) do |ok, status|
53
+ if block_given?
54
+ yield(ok, $?, tempfile.path)
55
+ else
56
+ ok or raise %Q{Command failed with status (#{$?.exitstatus}): [#{cmd}]
57
+ -------------- command output -------------------
58
+ #{File.read(tempfile.path)}
59
+ -------------------------------------------------
60
+ }
61
+ end
15
62
  end
63
+
64
+ quiet == true ? "" : File.read(tempfile.path)
16
65
  end
17
66
  end
18
67
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.1
4
+ version: 0.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simon Chiang
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-06-06 00:00:00 -06:00
12
+ date: 2009-06-17 00:00:00 -06:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -20,7 +20,7 @@ dependencies:
20
20
  requirements:
21
21
  - - ">="
22
22
  - !ruby/object:Gem::Version
23
- version: 0.17.1
23
+ version: 0.18.0
24
24
  version:
25
25
  description:
26
26
  email: simon.a.chiang@gmail.com
@@ -38,8 +38,8 @@ files:
38
38
  - lib/rap/declarations.rb
39
39
  - lib/rap/description.rb
40
40
  - lib/rap/rake.rb
41
- - lib/rap/utils.rb
42
41
  - lib/rap.rb
42
+ - lib/rap/utils.rb
43
43
  - tap.yml
44
44
  - README
45
45
  - MIT-LICENSE