tap 0.10.1 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. data/History +12 -0
  2. data/MIT-LICENSE +0 -2
  3. data/README +23 -32
  4. data/bin/rap +116 -0
  5. data/bin/tap +6 -9
  6. data/cgi/run.rb +67 -0
  7. data/cmd/console.rb +1 -1
  8. data/cmd/destroy.rb +4 -4
  9. data/cmd/generate.rb +4 -4
  10. data/cmd/manifest.rb +61 -53
  11. data/cmd/run.rb +8 -75
  12. data/doc/Class Reference +130 -121
  13. data/doc/Command Reference +76 -124
  14. data/doc/Syntax Reference +290 -0
  15. data/doc/Tutorial +305 -237
  16. data/lib/tap/app.rb +140 -467
  17. data/lib/tap/constants.rb +2 -2
  18. data/lib/tap/declarations.rb +211 -0
  19. data/lib/tap/env.rb +171 -193
  20. data/lib/tap/exe.rb +100 -21
  21. data/lib/tap/file_task.rb +3 -3
  22. data/lib/tap/generator/base.rb +1 -1
  23. data/lib/tap/generator/destroy.rb +10 -10
  24. data/lib/tap/generator/generate.rb +29 -18
  25. data/lib/tap/generator/generators/command/command_generator.rb +2 -2
  26. data/lib/tap/generator/generators/command/templates/command.erb +2 -2
  27. data/lib/tap/generator/generators/config/config_generator.rb +3 -3
  28. data/lib/tap/generator/generators/config/templates/doc.erb +1 -1
  29. data/lib/tap/generator/generators/file_task/file_task_generator.rb +1 -1
  30. data/lib/tap/generator/generators/file_task/templates/task.erb +1 -1
  31. data/lib/tap/generator/generators/file_task/templates/test.erb +1 -1
  32. data/lib/tap/generator/generators/generator/generator_generator.rb +27 -0
  33. data/lib/tap/generator/generators/generator/templates/task.erb +27 -0
  34. data/lib/tap/generator/generators/root/root_generator.rb +13 -13
  35. data/lib/tap/generator/generators/root/templates/README +0 -0
  36. data/lib/tap/generator/generators/root/templates/Rakefile +2 -2
  37. data/lib/tap/generator/generators/root/templates/gemspec +4 -5
  38. data/lib/tap/generator/generators/root/templates/tapfile +11 -8
  39. data/lib/tap/generator/generators/root/templates/test/tap_test_suite.rb +1 -1
  40. data/lib/tap/generator/generators/task/task_generator.rb +1 -3
  41. data/lib/tap/generator/generators/task/templates/test.erb +1 -3
  42. data/lib/tap/patches/optparse/summarize.rb +62 -0
  43. data/lib/tap/root.rb +41 -29
  44. data/lib/tap/support/aggregator.rb +16 -3
  45. data/lib/tap/support/assignments.rb +10 -9
  46. data/lib/tap/support/audit.rb +58 -64
  47. data/lib/tap/support/class_configuration.rb +33 -44
  48. data/lib/tap/support/combinator.rb +125 -0
  49. data/lib/tap/support/configurable.rb +13 -14
  50. data/lib/tap/support/configurable_class.rb +21 -43
  51. data/lib/tap/support/configuration.rb +55 -9
  52. data/lib/tap/support/constant.rb +87 -13
  53. data/lib/tap/support/constant_manifest.rb +116 -0
  54. data/lib/tap/support/dependencies.rb +54 -0
  55. data/lib/tap/support/dependency.rb +44 -0
  56. data/lib/tap/support/executable.rb +247 -32
  57. data/lib/tap/support/executable_queue.rb +1 -1
  58. data/lib/tap/support/gems/rake.rb +29 -8
  59. data/lib/tap/support/gems.rb +10 -30
  60. data/lib/tap/support/instance_configuration.rb +29 -3
  61. data/lib/tap/support/intern.rb +46 -0
  62. data/lib/tap/support/join.rb +143 -0
  63. data/lib/tap/support/joins/fork.rb +19 -0
  64. data/lib/tap/support/joins/merge.rb +22 -0
  65. data/lib/tap/support/joins/sequence.rb +21 -0
  66. data/lib/tap/support/joins/switch.rb +25 -0
  67. data/lib/tap/support/joins/sync_merge.rb +63 -0
  68. data/lib/tap/support/joins.rb +15 -0
  69. data/lib/tap/support/lazy_attributes.rb +17 -2
  70. data/lib/tap/support/lazydoc/comment.rb +503 -0
  71. data/lib/tap/support/lazydoc/config.rb +17 -0
  72. data/lib/tap/support/lazydoc/definition.rb +36 -0
  73. data/lib/tap/support/lazydoc/document.rb +152 -0
  74. data/lib/tap/support/lazydoc/method.rb +24 -0
  75. data/lib/tap/support/lazydoc.rb +269 -343
  76. data/lib/tap/support/manifest.rb +121 -103
  77. data/lib/tap/support/minimap.rb +90 -0
  78. data/lib/tap/support/node.rb +56 -0
  79. data/lib/tap/support/parser.rb +436 -0
  80. data/lib/tap/support/schema.rb +359 -0
  81. data/lib/tap/support/shell_utils.rb +3 -5
  82. data/lib/tap/support/string_ext.rb +60 -0
  83. data/lib/tap/support/tdoc.rb +7 -2
  84. data/lib/tap/support/templater.rb +30 -16
  85. data/lib/tap/support/validation.rb +77 -8
  86. data/lib/tap/task.rb +431 -143
  87. data/lib/tap/tasks/dump.rb +15 -10
  88. data/lib/tap/tasks/load.rb +112 -0
  89. data/lib/tap/tasks/rake.rb +4 -41
  90. data/lib/tap/test/assertions.rb +38 -0
  91. data/lib/tap/test/env_vars.rb +1 -1
  92. data/lib/tap/test/extensions.rb +79 -0
  93. data/lib/tap/test/file_test.rb +420 -0
  94. data/lib/tap/test/file_test_class.rb +12 -0
  95. data/lib/tap/test/regexp_escape.rb +87 -0
  96. data/lib/tap/test/script_test.rb +46 -0
  97. data/lib/tap/test/script_tester.rb +115 -0
  98. data/lib/tap/test/subset_test.rb +260 -0
  99. data/lib/tap/test/subset_test_class.rb +99 -0
  100. data/lib/tap/test/{tap_methods.rb → tap_test.rb} +45 -43
  101. data/lib/tap/test/utils.rb +231 -0
  102. data/lib/tap/test.rb +53 -26
  103. data/lib/tap.rb +3 -20
  104. metadata +50 -27
  105. data/lib/tap/generator/generators/root/templates/test/tapfile_test.rb +0 -15
  106. data/lib/tap/patches/rake/rake_test_loader.rb +0 -8
  107. data/lib/tap/patches/rake/testtask.rb +0 -57
  108. data/lib/tap/patches/ruby19/backtrace_filter.rb +0 -51
  109. data/lib/tap/patches/ruby19/parsedate.rb +0 -16
  110. data/lib/tap/support/batchable.rb +0 -47
  111. data/lib/tap/support/batchable_class.rb +0 -107
  112. data/lib/tap/support/command_line.rb +0 -98
  113. data/lib/tap/support/comment.rb +0 -270
  114. data/lib/tap/support/constant_utils.rb +0 -127
  115. data/lib/tap/support/declarations.rb +0 -111
  116. data/lib/tap/support/framework.rb +0 -83
  117. data/lib/tap/support/framework_class.rb +0 -180
  118. data/lib/tap/support/run_error.rb +0 -39
  119. data/lib/tap/support/summary.rb +0 -30
  120. data/lib/tap/test/file_methods.rb +0 -377
  121. data/lib/tap/test/script_methods/script_test.rb +0 -98
  122. data/lib/tap/test/script_methods.rb +0 -107
  123. data/lib/tap/test/subset_methods.rb +0 -420
  124. data/lib/tap/workflow.rb +0 -200
data/lib/tap/env.rb CHANGED
@@ -1,6 +1,4 @@
1
- require 'tap/support/manifest'
2
- require 'tap/support/constant'
3
- require 'tap/support/summary'
1
+ require 'tap/support/constant_manifest'
4
2
  require 'tap/support/gems'
5
3
 
6
4
  module Tap
@@ -9,8 +7,9 @@ module Tap
9
7
  # Note that gems and env_paths reset envs -- custom modifications to envs will be lost
10
8
  # whenever these configs are reset.
11
9
  class Env
12
- include Support::Configurable
13
10
  include Enumerable
11
+ include Support::Configurable
12
+ include Support::Minimap
14
13
 
15
14
  class << self
16
15
 
@@ -26,13 +25,6 @@ module Tap
26
25
  @@instances
27
26
  end
28
27
 
29
- # A hash of predefined manifest classes that can be initialized
30
- # from an env. These classes are instantiated by instances
31
- # of Env, as needed.
32
- def manifests
33
- @@manifests
34
- end
35
-
36
28
  # Creates a new Env for the specified path and adds it to Env#instances, or
37
29
  # returns the existing instance for the path. Paths can point to an env config
38
30
  # file, or to a directory. If a directory is provided, instantiate treats
@@ -77,77 +69,24 @@ module Tap
77
69
  File.expand_path(path)
78
70
  end
79
71
 
80
- def manifest(name, pattern, default_paths=[], &block) # :yields: search_path
81
- manifest_class = Class.new(Support::Manifest)
82
- manifest_class.send(:define_method, :entries_for, &block) if block_given?
83
- manifest_class.send(:attr_reader, :env)
84
- manifest_class.send(:define_method, :initialize) do |env|
85
- @env = env
86
- search_paths = default_paths.collect {|path| env.root[path] }
87
- search_paths += env.root.glob(:root, pattern)
88
- super search_paths.sort_by {|p| File.basename(p) }
89
- end
90
-
91
- manifests[name] = manifest_class
92
- end
93
-
94
- #--
95
- # To manifest simply requires an glob_<name> method which
96
- # yields each (key, path) pair for the manifested object in
97
- # a predictable order.
98
- #
99
- #--
100
- # Alternate implementation would create the manifest for each individual
101
- # env, then merge the manifests. On the plus side, each env would then
102
- # carry it's own slice of the manifest without having to recalculate.
103
- # On the down side, the merging would have to occur in some separate
104
- # method that cannot be defined here.
105
- def path_manifest(name, paths_key, pattern, default_paths=[], &block) # :yields: search_path_root, search_path
106
- manifest_class = Class.new(Support::Manifest)
107
- manifest_class.send(:define_method, :entries_for, &block) if block_given?
108
- manifest_class.send(:attr_reader, :env)
109
- manifest_class.send(:define_method, :initialize) do |env|
110
- @env = env
111
- search_paths = default_paths.collect do |path|
112
- [env.root.root, env.root[path]]
113
- end
114
-
115
- env.send(paths_key).each do |search_path_root|
116
- env.root.glob(search_path_root, pattern).each do |search_path|
117
- search_paths << [search_path_root, search_path]
118
- end
119
- end
120
-
121
- super search_paths.sort_by {|pr, p| File.basename(p) }
72
+ def manifest(name, &block) # :yields: env (returns manifest)
73
+ name = name.to_sym
74
+ define_method(name) do
75
+ self.manifests[name] ||= block.call(self).bind(self, name)
122
76
  end
123
- manifests[name] = manifest_class
124
77
  end
125
78
 
126
- # Returns the gemspecs for all installed gems with a DEFAULT_TASK_FILE
127
- # or DEFAULT_CONFIG_FILE. If latest==true, then only the specs for the
128
- # most current gems will be returned.
79
+ # Returns the gemspecs for all installed gems with a DEFAULT_CONFIG_FILE.
80
+ # If latest==true, then only the specs for the most current gems will be
81
+ # returned.
129
82
  def gemspecs(latest=true)
130
83
  Support::Gems.select_gems(latest) do |spec|
131
- File.exists?(File.join(spec.full_gem_path, DEFAULT_TASK_FILE)) ||
132
84
  File.exists?(File.join(spec.full_gem_path, DEFAULT_CONFIG_FILE))
133
85
  end
134
86
  end
135
87
 
136
88
  protected
137
89
 
138
- # Defines a config that raises an error if set when the
139
- # instance is active. static_config MUST take a block
140
- # and raises an error if a block is not given.
141
- def static_config(key, value=nil, &block)
142
- raise ArgumentError.new("active config requires block") unless block_given?
143
-
144
- instance_variable = "@#{key}".to_sym
145
- config_attr(key, value) do |input|
146
- check_configurable
147
- instance_variable_set(instance_variable, block.call(input))
148
- end
149
- end
150
-
151
90
  # Defines a config that collects the input into a unique,
152
91
  # compact array where each member has been resolved using
153
92
  # root[]. In short, ['lib', nil, 'lib', 'alt] becomes
@@ -165,45 +104,32 @@ module Tap
165
104
  end
166
105
  end
167
106
 
168
- class Manifest < Support::Manifest
169
- def initialize(env)
170
- super([])
171
- @entries = env.collect {|e| [e.root.root, e] }
172
- end
173
- end
174
-
175
107
  @@instance = nil
176
108
  @@instances = {}
177
- @@manifests = {:envs => Manifest}
178
109
 
179
- # The global config file path
180
- GLOBAL_CONFIG_FILE = File.join(Support::Gems.user_home, ".tap.yml")
181
-
182
110
  # The default config file path
183
111
  DEFAULT_CONFIG_FILE = "tap.yml"
184
112
 
185
- # The default task file path
186
- DEFAULT_TASK_FILE = "tapfile.rb"
187
-
188
113
  # The Root directory structure for self.
189
114
  attr_reader :root
190
115
 
191
116
  # Gets or sets the logger for self
192
117
  attr_accessor :logger
193
118
 
194
- # A hash of the manifests for self.
195
- attr_reader :manifests
119
+ # Specify files to require when self is activated.
120
+ config :requires, [], &c.array_or_nil
121
+
122
+ # Specify files to load when self is activated.
123
+ config :loads, [], &c.array_or_nil
196
124
 
197
125
  # Specify gems to load as nested Envs. Gems may be specified
198
126
  # by name and/or version, like 'gemname >= 1.2'; by default the
199
127
  # latest version of the gem is selected.
200
128
  #
201
129
  # Gems are immediately loaded (via gem) through this method.
202
- #--
203
- # Note that the gems are resolved to gemspecs using Env.gemspec,
204
- # so self.gems returns an array of gemspecs.
205
130
  config_attr :gems, [] do |input|
206
131
  check_configurable
132
+ specs_by_name = {}
207
133
  @gems = [*input].compact.collect do |gem_name|
208
134
  spec = Support::Gems.gemspec(gem_name)
209
135
 
@@ -212,8 +138,20 @@ module Tap
212
138
  else Env.instance_for(spec.full_gem_path)
213
139
  end
214
140
 
215
- spec
141
+ (specs_by_name[spec.name] ||= []) << spec
142
+ spec.name
216
143
  end.uniq
144
+
145
+ # this song and dance is to ensure that the latest spec for a
146
+ # given gem appears first in the manifest
147
+ specs_by_name.each_pair do |name, specs|
148
+ specs_by_name[name] = specs.uniq.sort_by {|spec| spec.version }.reverse
149
+ end
150
+
151
+ @gems.collect! do |name|
152
+ specs_by_name[name]
153
+ end.flatten!
154
+
217
155
  reset_envs
218
156
  end
219
157
 
@@ -235,46 +173,44 @@ module Tap
235
173
  # Designate paths for discovering generators.
236
174
  path_config :generator_paths, ["lib"]
237
175
 
238
- path_manifest(:tasks, :load_paths, "**/*.rb", [DEFAULT_TASK_FILE]) do |load_path, path|
239
- next unless File.file?(path) && document = Support::Lazydoc.scan_doc(path, 'manifest')
240
-
241
- document.const_names.collect do |const_name|
242
- if const_name.empty?
243
- key = env.root.relative_filepath(load_path, path).chomp('.rb')
244
- [key, Support::Constant.new(key.camelize, path)]
245
- else
246
- [const_name.underscore, Support::Constant.new(const_name, path)]
247
- end
176
+ manifest(:commands) do |env|
177
+ paths = []
178
+ env.command_paths.each do |path_root|
179
+ paths.concat env.root.glob(path_root)
248
180
  end
181
+
182
+ paths = paths.sort_by {|path| File.basename(path) }
183
+ Support::Manifest.new(paths)
249
184
  end
250
185
 
251
- path_manifest(:commands, :command_paths, "**/*.rb") do |command_path, path|
252
- File.file?(path) ? [[path, path]] : nil
186
+ manifest(:tasks) do |env|
187
+ tasks = Support::ConstantManifest.new('manifest')
188
+ env.load_paths.each do |path_root|
189
+ tasks.register(path_root, '**/*.rb')
190
+ end
191
+ # tasks.cache = env.cache[:tasks]
192
+ tasks
253
193
  end
254
-
255
- path_manifest(:generators, :generator_paths, '**/*_generator.rb') do |generator_path, path|
256
- dirname = File.dirname(path)
257
- next unless File.file?(path) && "#{File.basename(dirname)}_generator.rb" == File.basename(path)
258
-
259
- next unless document = Support::Lazydoc.scan_doc(path, 'generator')
260
- document.const_names.collect do |const_name|
261
- if const_name.empty?
262
- key = env.root.relative_filepath(generator_path, dirname)
263
- [key, Support::Constant.new((key + '_generator').camelize, path)]
264
- else
265
- [const_name.underscore, Support::Constant.new(const_name, path)]
266
- end
194
+
195
+ manifest(:generators) do |env|
196
+ generators = Support::ConstantManifest.intern('generator') do |manifest, const|
197
+ const.name.underscore.chomp('_generator')
198
+ end
199
+
200
+ env.generator_paths.each do |path_root|
201
+ generators.register(path_root, '**/*_generator.rb')
267
202
  end
203
+ # generators.cache = env.cache[:generators]
204
+ generators
268
205
  end
269
-
206
+
270
207
  def initialize(config={}, root=Tap::Root.new, logger=nil)
271
208
  @root = root
272
209
  @logger = logger
273
210
  @envs = []
274
211
  @active = false
275
212
  @manifests = {}
276
- @manifested = []
277
-
213
+
278
214
  # initialize these for reset_env
279
215
  @gems = []
280
216
  @env_paths = []
@@ -455,6 +391,17 @@ module Tap
455
391
  end
456
392
 
457
393
  $LOAD_PATH.uniq!
394
+
395
+ # perform requires
396
+ requires.each do |path|
397
+ require path
398
+ end
399
+
400
+ # perform loads
401
+ loads.each do |path|
402
+ load path
403
+ end
404
+
458
405
  true
459
406
  end
460
407
 
@@ -496,96 +443,127 @@ module Tap
496
443
  @active
497
444
  end
498
445
 
499
- # Returns the manifest in manifests by the specified name. Yields
500
- # each entry in the manifest to the block, if given, or simply
501
- # builds and returns the manifest.
446
+ # Searches each env for the first existing file or directory at
447
+ # env.root.filepath(dir, path). Paths are expanded, and search_path
448
+ # checks to make sure the file is, in fact, relative to env.root[dir].
449
+ # An optional block may be used to check the file; the file will only
450
+ # be returned if the block returns true.
502
451
  #
503
- # If the specified manifest does not exists, the manifest class
504
- # in self.class.manifests will be instatiated with self to make
505
- # the manifest. Raises an error if no manifest could be found
506
- # or instantiated.
507
- def manifest(name, build=false)
508
- manifest = manifests[name] ||= case
509
- when manifests_class = self.class.manifests[name]
510
- manifests_class.new(self)
511
- else
512
- raise "unknown manifest: #{name}"
513
- end
514
-
515
- manifest.build if build
516
- manifest
517
- end
518
-
519
- # Returns the first value in the specified manifest where the key
520
- # mini-matches the input pattern. See Tap::Root.minimal_match?
521
- # for details on mini-matching.
522
- def find(name, pattern, value_only=true)
523
- manifest(name).each do |key, value|
524
- return(value_only ? value : [key, value]) if Root.minimal_match?(key, pattern)
525
- end
526
- nil
527
- end
528
-
529
- # Like find, but searches across all envs for the matching value.
530
- # An env pattern can be provided in pattern, to select a single
531
- # env to search.
532
- #
533
- # The :envs manifest cannot be searched; use find instead.
534
- def search(name, pattern, value_only=true)
535
- if name == :envs
536
- raise ArgumentError, "cannot search the :envs manifest; use find instead"
537
- end
538
-
539
- envs = case pattern
540
- when /^(.*):([^:]+)$/
541
- env_pattern = $1
542
- pattern = $2
543
- find(:envs, env_pattern)
544
- else manifest(:envs).values
545
- end
546
-
547
- envs.each do |env|
548
- if result = env.find(name, pattern, value_only)
549
- return result
452
+ # Returns nil if no file can be found.
453
+ def search_path(dir, path)
454
+ each do |env|
455
+ directory = env.root.filepath(dir)
456
+ file = env.root.filepath(dir, path)
457
+
458
+ # check the file is relative to the
459
+ # directory, and that the file exists.
460
+ if file.rindex(directory, 0) == 0 &&
461
+ File.exists?(file) &&
462
+ (!block_given? || yield(file))
463
+ return file
550
464
  end
551
- end if envs
465
+ end
552
466
 
553
467
  nil
554
468
  end
555
469
 
556
- def constantize(name, *patterns)
557
- patterns.collect do |pattern|
558
- case const = search(name, pattern)
559
- when Support::Constant then const.constantize
560
- else raise "could not constantize: #{pattern} (#{name})"
561
- end
562
- end
563
- end
470
+ # def reset(name, &block)
471
+ # each do |env|
472
+ # env.manifests[name].each(&block)
473
+ # env.manifests[name] = nil
474
+ # end
475
+ # end
564
476
 
565
- def summary(name)
566
- summary = Support::Summary.new
567
- manifest(:envs, true).minimize.each do |(key, env)|
568
- summary.add(key, env, env.manifest(name, true).minimize)
477
+ #
478
+ TEMPLATES = {}
479
+ TEMPLATES[:commands] = %Q{<% if count > 1 %>
480
+ <%= env_name %>:
481
+ <% end %>
482
+ <% entries.each do |name, const| %>
483
+ <%= name.ljust(width) %>
484
+ <% end %>}
485
+ TEMPLATES[:tasks] = %Q{<% if count > 1 %>
486
+ <%= env_name %>:
487
+ <% end %>
488
+ <% entries.each do |name, const| %>
489
+ <% desc = const.document[const.name]['manifest'] %>
490
+ <%= name.ljust(width) %><%= desc.empty? ? '' : ' # ' %><%= desc %>
491
+ <% end %>}
492
+ TEMPLATES[:generators] = %Q{<% if count > 1 %>
493
+ <%= env_name %>:
494
+ <% end %>
495
+ <% entries.each do |name, const| %>
496
+ <% desc = const.document[const.name]['generator'] %>
497
+ <%= name.ljust(width) %><%= desc.empty? ? '' : ' # ' %><%= desc %>
498
+ <% end %>}
499
+
500
+ def summarize(name, template=TEMPLATES[name])
501
+ count = 0
502
+ width = 10
503
+
504
+ env_names = {}
505
+ minimap.each do |env_name, env|
506
+ env_names[env] = env_name
507
+ end
508
+
509
+ inspect(template) do |templater, share|
510
+ env = templater.env
511
+ entries = env.send(name).minimap
512
+ next(false) if entries.empty?
513
+
514
+ templater.env_name = env_names[env]
515
+ templater.entries = entries
516
+
517
+ count += 1
518
+ entries.each do |entry_name, entry|
519
+ width = entry_name.length if width < entry_name.length
520
+ end
521
+
522
+ share[:count] = count
523
+ share[:width] = width
524
+ true
569
525
  end
570
- summary
571
526
  end
572
527
 
573
- def summarize(name, &block)
574
- lines = summary(name).lines(&block)
575
- lines << "=== no #{name} found" if lines.empty?
576
- lines.join("\n")
577
- end
578
-
579
- def inspect(brief=false)
580
- brief ? "#<#{self.class}:#{object_id} root='#{root.root}'>" : super()
528
+ def inspect(template=nil) # :yields: templater, attrs
529
+ return "#<#{self.class}:#{object_id} root='#{root.root}'>" if template == nil
530
+
531
+ attrs = {}
532
+ collect do |env|
533
+ templater = Support::Templater.new(template, :env => env)
534
+ block_given? ? (yield(templater, attrs) ? templater : nil) : templater
535
+ end.compact.collect do |templater|
536
+ templater.build(attrs)
537
+ end.join
581
538
  end
582
539
 
583
- def to_s
584
- inspect(true)
540
+ def recursive_inspect(template=nil, *args) # :yields: templater, attrs
541
+ return "#<#{self.class}:#{object_id} root='#{root.root}'>" if template == nil
542
+
543
+ attrs = {}
544
+ templaters = []
545
+ recursive_each(*args) do |env, *argv|
546
+ templater = Support::Templater.new(template, :env => env)
547
+ next_args = block_given? ? yield(templater, attrs, *argv) : argv
548
+ templaters << templater if next_args
549
+
550
+ next_args
551
+ end
552
+
553
+ templaters.collect do |templater|
554
+ templater.build(attrs)
555
+ end.join
585
556
  end
586
557
 
587
558
  protected
588
559
 
560
+ # A hash of the manifests for self.
561
+ attr_reader :manifests
562
+
563
+ def minikey(env)
564
+ env.root.root
565
+ end
566
+
589
567
  # Raises an error if self is already active (and hence, configurations
590
568
  # should not be modified)
591
569
  def check_configurable
data/lib/tap/exe.rb CHANGED
@@ -1,20 +1,25 @@
1
+ require 'tap/env'
2
+ require 'tap/app'
3
+ require 'tap/support/schema'
4
+
1
5
  module Tap
2
6
  class Exe < Env
3
-
7
+
4
8
  class << self
5
- def instantiate
6
- app = Tap::App.instance
7
- exe = super(app, load_config(Tap::Env::GLOBAL_CONFIG_FILE), app.logger)
9
+ def instantiate(path=Dir.pwd, logger=Tap::App::DEFAULT_LOGGER, &block)
10
+ app = Tap::App.instance = Tap::App.new({:root => path}, logger)
11
+ exe = super(app, load_config(GLOBAL_CONFIG_FILE), app.logger, &block)
8
12
 
9
13
  # add all gems if no gems are specified (Note this is VERY SLOW ~ 1/3 the overhead for tap)
10
14
  if !File.exists?(Tap::Env::DEFAULT_CONFIG_FILE)
11
- exe.gems = gemspecs(true)
15
+ exe.gems = gemspecs(false)
12
16
  end
13
-
17
+
18
+ # add the default tap instance
14
19
  tap = instance_for("#{File.dirname(__FILE__)}/../..")
15
- tap.manifest(:tasks).search_paths = tap.root.glob(:lib, "tap/tasks/*").collect do |path|
16
- [tap.root[:lib], path]
17
- end
20
+ # tap.tasks.paths = tap.root.glob(:lib, "tap/tasks/*").collect do |task_path|
21
+ # [tap.root[:lib], task_path]
22
+ # end
18
23
  exe.push(tap)
19
24
  exe
20
25
  end
@@ -28,18 +33,26 @@ module Tap
28
33
  config :before, nil
29
34
  config :after, nil
30
35
  config :aliases, {}, &c.hash_or_nil
31
-
32
- def handle_error(err)
33
- case
34
- when $DEBUG
35
- puts err.message
36
- puts
37
- puts err.backtrace
38
- else puts err.message
39
- end
40
- end
41
36
 
42
- def run(argv=ARGV)
37
+ # The global config file path
38
+ GLOBAL_CONFIG_FILE = File.join(Gem.user_home, ".tap.yml")
39
+
40
+ # Alias for root (Exe should have a Tap::App as root)
41
+ def app
42
+ root
43
+ end
44
+
45
+ def handle_error(err)
46
+ case
47
+ when $DEBUG
48
+ puts err.message
49
+ puts
50
+ puts err.backtrace
51
+ else puts err.message
52
+ end
53
+ end
54
+
55
+ def execute(argv=ARGV)
43
56
  command = argv.shift.to_s
44
57
 
45
58
  if aliases && aliases.has_key?(command)
@@ -51,7 +64,7 @@ module Tap
51
64
  when '', '--help'
52
65
  yield
53
66
  else
54
- if path = search(:commands, command)
67
+ if path = commands.search(command)
55
68
  load path # run the command, if it exists
56
69
  else
57
70
  puts "Unknown command: '#{command}'"
@@ -59,5 +72,71 @@ module Tap
59
72
  end
60
73
  end
61
74
  end
75
+
76
+ def build(argv=ARGV)
77
+ Support::Schema.parse(argv).compact.build(app) do |args|
78
+ task = args.shift
79
+ const = tasks.search(task)
80
+
81
+ task_class = case
82
+ when const then const.constantize
83
+ when block_given?
84
+ args.unshift(task)
85
+ yield(args)
86
+ else nil
87
+ end
88
+
89
+ task_class or raise ArgumentError, "unknown task: #{task}"
90
+ task_class.parse(args, app) do |help|
91
+ puts help
92
+ exit
93
+ end
94
+ end
95
+ end
96
+
97
+ def set_signals
98
+ # info signal -- Note: some systems do
99
+ # not support the INFO signal
100
+ # (windows, fedora, at least)
101
+ signals = Signal.list.keys
102
+ if signals.include?("INFO")
103
+ Signal.trap("INFO") do
104
+ puts app.info
105
+ end
106
+ end
107
+
108
+ # interuption signal
109
+ if signals.include?("INT")
110
+ Signal.trap("INT") do
111
+ puts " interrupted!"
112
+ # prompt for decision
113
+ while true
114
+ print "stop, terminate, exit, or resume? (s/t/e/r):"
115
+ case gets.strip
116
+ when /s(top)?/i
117
+ app.stop
118
+ break
119
+ when /t(erminate)?/i
120
+ app.terminate
121
+ break
122
+ when /e(xit)?/i
123
+ exit
124
+ when /r(esume)?/i
125
+ break
126
+ else
127
+ puts "unexpected response..."
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
133
+
134
+ def run(queues)
135
+ queues.each_with_index do |queue, i|
136
+ app.queue.concat(queue)
137
+ app.run
138
+ end
139
+ end
140
+
62
141
  end
63
142
  end
data/lib/tap/file_task.rb CHANGED
@@ -21,7 +21,7 @@ module Tap
21
21
  # # this file will be backed up and restored
22
22
  # File.open("file.txt", "w") {|f| f << "original content"}
23
23
  #
24
- # t = FileTask.new do |task|
24
+ # t = FileTask.intern do |task|
25
25
  # task.mkdir("some/dir") # marked for rollback
26
26
  # task.prepare("file.txt", "path/to/file.txt") # marked for rollback
27
27
  #
@@ -46,7 +46,7 @@ module Tap
46
46
  class FileTask < Task
47
47
  include Tap::Support::ShellUtils
48
48
 
49
- # A hash of backup (source, target) pairs, such that the
49
+ # A hash of backup [source, target] pairs, such that the
50
50
  # backed-up files are backed_up_files.keys and the actual
51
51
  # backup files are backed_up_files.values. All filepaths
52
52
  # in backed_up_files should be expanded.
@@ -66,7 +66,7 @@ module Tap
66
66
  # error, defaults to the class rollback_on_error
67
67
  config :rollback_on_error, true, &c.switch # rollback changes on error
68
68
 
69
- def initialize(config={}, name=nil, app=App.instance, &task_block)
69
+ def initialize(config={}, name=nil, app=App.instance)
70
70
  super
71
71
 
72
72
  @backed_up_files = {}
@@ -6,7 +6,7 @@ module Tap
6
6
  class << self
7
7
  def lazydoc(resolve=true)
8
8
  lazydoc = super(false)
9
- lazydoc.register_method_pattern('args', :manifest, 1..-1) unless lazydoc.resolved?
9
+ lazydoc[self.to_s]['args'] ||= lazydoc.register_method(:manifest, Task::Args)
10
10
  super
11
11
  end
12
12
  end