tap 0.19.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. data/History +100 -45
  2. data/MIT-LICENSE +1 -1
  3. data/README +95 -51
  4. data/bin/tap +11 -57
  5. data/bin/tapexe +84 -0
  6. data/doc/API +91 -139
  7. data/doc/Configuration +93 -0
  8. data/doc/Examples/Command Line +10 -42
  9. data/doc/Examples/Tapfile +124 -0
  10. data/doc/Ruby to Ruby +87 -0
  11. data/doc/Workflow Syntax +185 -0
  12. data/lib/tap.rb +74 -5
  13. data/lib/tap/app.rb +217 -310
  14. data/lib/tap/app/api.rb +44 -23
  15. data/lib/tap/app/queue.rb +11 -12
  16. data/lib/tap/app/stack.rb +4 -4
  17. data/lib/tap/declarations.rb +200 -0
  18. data/lib/tap/declarations/context.rb +31 -0
  19. data/lib/tap/declarations/description.rb +33 -0
  20. data/lib/tap/env.rb +133 -779
  21. data/lib/tap/env/cache.rb +87 -0
  22. data/lib/tap/env/constant.rb +94 -39
  23. data/lib/tap/env/path.rb +71 -0
  24. data/lib/tap/join.rb +42 -78
  25. data/lib/tap/joins/gate.rb +85 -0
  26. data/lib/tap/joins/switch.rb +4 -2
  27. data/lib/tap/joins/sync.rb +3 -3
  28. data/lib/tap/middleware.rb +5 -5
  29. data/lib/tap/middlewares/debugger.rb +18 -58
  30. data/lib/tap/parser.rb +115 -183
  31. data/lib/tap/root.rb +162 -239
  32. data/lib/tap/signal.rb +72 -0
  33. data/lib/tap/signals.rb +20 -2
  34. data/lib/tap/signals/class_methods.rb +38 -43
  35. data/lib/tap/signals/configure.rb +19 -0
  36. data/lib/tap/signals/help.rb +5 -7
  37. data/lib/tap/signals/load.rb +49 -0
  38. data/lib/tap/signals/module_methods.rb +1 -0
  39. data/lib/tap/task.rb +46 -275
  40. data/lib/tap/tasks/dump.rb +21 -16
  41. data/lib/tap/tasks/list.rb +184 -0
  42. data/lib/tap/tasks/load.rb +4 -4
  43. data/lib/tap/tasks/prompt.rb +128 -0
  44. data/lib/tap/tasks/signal.rb +42 -0
  45. data/lib/tap/tasks/singleton.rb +35 -0
  46. data/lib/tap/tasks/stream.rb +64 -0
  47. data/lib/tap/utils.rb +83 -0
  48. data/lib/tap/version.rb +2 -2
  49. data/lib/tap/workflow.rb +124 -0
  50. data/tap.yml +0 -0
  51. metadata +59 -24
  52. data/cmd/console.rb +0 -43
  53. data/cmd/manifest.rb +0 -118
  54. data/cmd/run.rb +0 -145
  55. data/doc/Examples/Workflow +0 -40
  56. data/lib/tap/app/node.rb +0 -29
  57. data/lib/tap/env/context.rb +0 -61
  58. data/lib/tap/env/gems.rb +0 -63
  59. data/lib/tap/env/manifest.rb +0 -179
  60. data/lib/tap/env/minimap.rb +0 -308
  61. data/lib/tap/intern.rb +0 -50
  62. data/lib/tap/joins.rb +0 -9
  63. data/lib/tap/prompt.rb +0 -36
  64. data/lib/tap/root/utils.rb +0 -220
  65. data/lib/tap/root/versions.rb +0 -138
  66. data/lib/tap/signals/signal.rb +0 -68
@@ -1,43 +0,0 @@
1
- # usage: tap console [options]
2
- #
3
- # Opens up an IRB session with the Tap environment initialized as specified
4
- # in tap.yml. Access a Tap::App instance through 'app' and the execution
5
- # environment through 'env'. For example:
6
- #
7
- # % tap console
8
- # >> app.env[:dump]
9
- # => Tap::Tasks::Dump
10
- # >> app.info
11
- # => "state: 0 (READY) queue: 0"
12
- # >>
13
- #
14
-
15
- ConfigParser.new do |opts|
16
- opts.separator ""
17
- opts.separator "options:"
18
-
19
- opts.on("-h", "--help", "Show this message") do
20
- puts Lazydoc.usage(__FILE__)
21
- puts opts
22
- exit
23
- end
24
- end.parse!(ARGV)
25
-
26
- require "irb"
27
-
28
- def app
29
- @app ||= Tap::App.instance
30
- end
31
-
32
- IRB.start
33
-
34
- # Handles a bug in IRB that causes exit to throw :IRB_EXIT
35
- # and consequentially make a warning message, even on a
36
- # clean exit. This module resets exit to the original
37
- # aliased method.
38
- module CleanExit # :nodoc:
39
- def exit(ret = 0)
40
- __exit__(ret)
41
- end
42
- end
43
- IRB.CurrentContext.extend CleanExit
@@ -1,118 +0,0 @@
1
- # usage: tap manifest [options] [filter]
2
- #
3
- # Prints a manifest of all resources in the current tap environment. Env
4
- # keys may be provided to select a specific set of environments to list.
5
- #
6
- # % tap manifest
7
- # % tap manifest tap-tasks
8
- #
9
- options = {}
10
- ConfigParser.new do |opts|
11
-
12
- opts.separator ""
13
- opts.separator "options:"
14
-
15
- opts.on("-h", "--help", "Show this message") do
16
- puts Lazydoc.usage(__FILE__)
17
- puts opts
18
- exit
19
- end
20
- end.parse!(ARGV)
21
-
22
- template = %Q{<% unless manifests.empty? %>
23
- #{'-' * 80}
24
- <%= (env_key + ':').ljust(width) %> (<%= env.root.root %>)
25
- <% manifests.each do |type, entries| %>
26
- <%= type %>
27
- <% entries.each do |key, paths| %>
28
- <%= key.ljust(width) %> (<%= paths.join(', ') %>)
29
- <% end %>
30
- <% end %>
31
- <% end %>
32
- }
33
-
34
- # filter envs to manifest
35
- env = Tap::App.instance.env
36
- env_keys = env.minihash(true)
37
- filter = if ARGV.empty?
38
- env_keys.keys
39
- else
40
- ARGV.collect do |name|
41
- env.minimatch(name) or raise "could not find an env matching: #{name}"
42
- end
43
- end
44
-
45
- # build the summary
46
- constants = env.constants
47
- summary = env.inspect(template, :width => 10) do |templater, globals|
48
- current = templater.env
49
- manifests = []
50
- templater.manifests = manifests
51
- next unless filter.include?(current)
52
-
53
- # determine the width of the keys
54
- width = globals[:width]
55
- env_key = env_keys[current]
56
- templater.env_key = env_key
57
- width = env_key.length if width < env_key.length
58
-
59
- # build up the entries for each type of resource
60
- types = {}
61
- constants.entries(current).minimap.each do |key, const|
62
- paths = const.require_paths.collect do |path|
63
- current.root.relative_path(:root, path) || path
64
- end.uniq
65
-
66
- width = key.length if width < key.length
67
-
68
- const.types.keys.each do |type|
69
- (types[type] ||= []) << [key, paths]
70
- end
71
- end
72
-
73
- manifests.concat types.to_a.sort_by {|type, minimap| type }
74
- globals[:width] = width
75
- end
76
- puts summary
77
-
78
- if ARGV.empty?
79
- templaters = []
80
- visited = []
81
- globals = env.recursive_inject([nil, nil]) do |(leader, last), current|
82
- current_leader = if leader
83
- leader.to_s + (last == current ? "`- " : "|- ")
84
- else
85
- ""
86
- end
87
-
88
- templaters << Tap::Templater.new("<%= leader %><%= env_key %> \n",
89
- :env_key => env_keys[current],
90
- :leader => current_leader
91
- )
92
-
93
- if leader
94
- leader += (last == current ? ' ' : '| ')
95
- else
96
- leader = ""
97
- end
98
-
99
- visited << current
100
- current.envs.reverse_each do |e|
101
- unless visited.include?(e)
102
- last = e
103
- break
104
- end
105
- end
106
-
107
- [leader, last]
108
- end
109
-
110
- tree = templaters.collect do |templater|
111
- templater.build
112
- end.join
113
-
114
- puts '-' * 80
115
- puts
116
- puts tree
117
- puts
118
- end
data/cmd/run.rb DELETED
@@ -1,145 +0,0 @@
1
- # usage: tap run [args] [options] -- [SCHEMA]
2
- #
3
- # examples:
4
- # tap run --help Prints this help
5
- # tap run -- task --help Prints help for task
6
- # tap run -- load hello --: dump Say hello
7
- #
8
-
9
- app = Tap::App.instance
10
-
11
- opts = {}
12
- parser = ConfigParser.bind(app.config) do |psr|
13
- psr.separator ""
14
- psr.separator "configurations:"
15
-
16
- psr.add Tap::App.configurations
17
-
18
- psr.separator ""
19
- psr.separator "options:"
20
-
21
- psr.on("-h", "--help", "Show this message") do
22
- puts Lazydoc.usage(__FILE__)
23
- puts psr
24
- exit(0)
25
- end
26
-
27
- psr.on('-s', '--serialize', 'Serialize the workflow') do
28
- opts[:serialize] = true
29
- end
30
-
31
- psr.on('-t', '--manifest', 'Print a list of available resources') do
32
- constants = app.env.constants
33
-
34
- tasks, joins, middleware = %w{task join middleware}.collect do |type|
35
- constants.summarize do |constant|
36
- constant.types[type]
37
- end
38
- end
39
-
40
- unless tasks.empty?
41
- puts "=== tasks ===" unless middleware.empty? && joins.empty?
42
- puts tasks
43
- end
44
-
45
- unless joins.empty?
46
- puts "=== joins ===" unless tasks.empty? && middleware.empty?
47
- puts joins
48
- end
49
-
50
- unless middleware.empty?
51
- puts "=== middleware ===" unless tasks.empty? && joins.empty?
52
- puts middleware
53
- end
54
-
55
- exit(0)
56
- end
57
-
58
- psr.on('-T', '--tasks', 'Print a list of available tasks') do
59
- constants = app.env.constants
60
- tasks = constants.summarize do |constant|
61
- constant.types['task']
62
- end
63
-
64
- puts tasks
65
- exit(0)
66
- end
67
-
68
- psr.on('-u', '--quick-queue', 'Removes thread-safety from queue') do
69
- mod = Module.new do
70
- def synchronize
71
- yield
72
- end
73
- end
74
- app.queue.extend(mod)
75
- end
76
- end
77
-
78
- #
79
- # build and run
80
- #
81
-
82
- # Traps interrupt the normal flow of the program and so I assume thread safety
83
- # is an issue (ex if the INT occurs during an enque and a signal specifies
84
- # another enque). A safer way to go is to enque the prompt... when the prompt
85
- # is executed the app won't be be doing anything else so thread safety
86
- # shouldn't be an issue.
87
- Signal.trap('INT') do
88
- puts
89
- puts "Interrupt! Signals from an interruption are not thread-safe."
90
-
91
- require 'tap/prompt'
92
- prompt = Tap::Prompt.new
93
- call_prompt = true
94
- 3.times do
95
- print "Wait for thread-safe break? (y/n): "
96
-
97
- case gets.strip
98
- when /^y(es)?$/i
99
- puts "waiting for break..."
100
- app.queue.unshift(prompt, [])
101
- call_prompt = false
102
- break
103
-
104
- when /^no?$/i
105
- break
106
- end
107
- end
108
-
109
- if call_prompt
110
- prompt.call
111
- end
112
- end
113
-
114
- begin
115
- loop do
116
- break if ARGV.empty?
117
- parser.scan(ARGV,
118
- :option_break => Tap::Parser::BREAK,
119
- :keep_break => true
120
- ) do |path|
121
- YAML.load_file(path).each do |spec|
122
- app.call(spec)
123
- end
124
- end
125
-
126
- break if ARGV.empty?
127
- ARGV.replace app.call('sig' => 'parse', 'args' => ARGV)
128
- end
129
-
130
- if opts[:serialize]
131
- YAML.dump(app.serialize, $stdout)
132
- exit(0)
133
- end
134
-
135
- opts = nil
136
- parser = nil
137
- app.run
138
-
139
- rescue
140
- raise if app.debug?
141
- puts $!.message
142
- exit(1)
143
- end
144
-
145
- exit(0)
@@ -1,40 +0,0 @@
1
- = Workflow Examples
2
-
3
- === Sequence
4
-
5
- A simple sequence using the --: syntax.
6
-
7
- % tap run -- load 'goodnight moon' --: dump
8
- goodnight moon
9
-
10
- === Sequence (canonical)
11
-
12
- The more canonical way of specifying a sequence.
13
-
14
- % tap run -- load 'goodnight moon' -- dump --[0][1]
15
- goodnight moon
16
-
17
- === Fork
18
-
19
- Multiple outputs for a single input.
20
-
21
- % tap run -- load 'goodnight moon' -- dump -- dump --[0][1,2]
22
- goodnight moon
23
- goodnight moon
24
-
25
- === Merge
26
-
27
- Multiple inputs for a single output; note that as seen in the output, dump
28
- receives the inputs in serial, whenever they happen to be ready.
29
-
30
- % tap run -- load goodnight -- load moon -- dump --[0,1][2]
31
- goodnight
32
- moon
33
-
34
- === Synchronized Merge
35
-
36
- Similar to a merge, but the results of each input are collected into an array
37
- before being passed to dump. The printout is: ['goodnight', 'moon'].to_s
38
-
39
- % tap run -- load goodnight -- load moon -- dump --[0,1][2].sync
40
- goodnightmoon
@@ -1,29 +0,0 @@
1
- module Tap
2
- class App
3
-
4
- # Node adds the node API[link:files/doc/API.html] to objects responding
5
- # to call. Additional helper methods are added to simplify the
6
- # construction of workflows; they are not required by the API.
7
- module Node
8
-
9
- # The joins called when call completes
10
- attr_accessor :joins
11
-
12
- # Interns a new node by extending the block with Node.
13
- def self.intern(&block)
14
- block.extend self
15
- end
16
-
17
- # Sets up required variables for extended objects.
18
- def self.extended(obj) # :nodoc:
19
- obj.instance_variable_set(:@joins, [])
20
- end
21
-
22
- # Sets the block as a join for self.
23
- def on_complete(&block) # :yields: result
24
- self.joins << block if block
25
- self
26
- end
27
- end
28
- end
29
- end
@@ -1,61 +0,0 @@
1
- module Tap
2
- class Env
3
-
4
- # Context instances track information shared by a set of Env instances, for
5
- # instance cached manifest data. Caching cross-env data in a shared space
6
- # simplifies managment of this data, especially when dumping and loading it
7
- # from a static file.
8
- #
9
- # Contexts also ensure that only one env in initialized to a given
10
- # directory (at least among envs that share the same context). This
11
- # prevents errors that arise when one env eventually nests itself.
12
- class Context
13
-
14
- # A hash of cached manifest data
15
- attr_reader :cache
16
-
17
- # The config file basename
18
- attr_reader :basename
19
-
20
- # An array of Env instances registered with self
21
- attr_reader :instances
22
-
23
- # Initializes a new Context. Options can specify a cache or a basename.
24
- def initialize(options={})
25
- options = {
26
- :cache => {},
27
- :basename => nil
28
- }.merge(options)
29
-
30
- @cache = options[:cache]
31
- @basename = options[:basename]
32
- @instances = []
33
- end
34
-
35
- # Registers env with self by adding env to instances. Raises an error
36
- # if instances contains an env with the same root directory.
37
- def register(env)
38
- path = env.root.root
39
-
40
- if instance(path)
41
- raise "context already has an env for: #{path}"
42
- end
43
-
44
- instances << env
45
- self
46
- end
47
-
48
- # Gets the instance for the directory currently in instances, or nil
49
- # if such an instance does not exist.
50
- def instance(dir)
51
- instances.find {|env| env.root.root == dir }
52
- end
53
-
54
- # Returns the config filepath for the directory (ie basename under dir).
55
- # If basename is nil, then config_file always return nil.
56
- def config_file(dir)
57
- basename ? File.join(dir, basename) : nil
58
- end
59
- end
60
- end
61
- end
@@ -1,63 +0,0 @@
1
- require 'rubygems'
2
-
3
- module Tap
4
- class Env
5
-
6
- # Methods for working with {RubyGems}[http://www.rubygems.org/].
7
- module Gems
8
- module_function
9
-
10
- # Returns the gemspec for the specified gem. A gem version
11
- # can be specified in the name, like 'gem >= 1.2'. The gem
12
- # is not activated by this method.
13
- def gemspec(gem_name)
14
- return gem_name if gem_name.kind_of?(Gem::Specification)
15
-
16
- dependency = if gem_name.kind_of?(Gem::Dependency)
17
- gem_name
18
- else
19
- # figure the version of the gem, by default >= 0.0.0
20
- gem_name.to_s =~ /^([^~<=>]*)(.*)$/
21
- name, version = $1.strip, $2
22
- return nil if name.empty?
23
- version = Gem::Requirement.default if version.empty?
24
-
25
- # note the last gem matching the dependency requirements
26
- # is the latest matching gem
27
- Gem::Dependency.new(name, version)
28
- end
29
-
30
- Gem.source_index.search(dependency).last
31
- end
32
-
33
- # Selects gem specs for which the block returns true. If
34
- # latest is specified, only the latest version of each
35
- # gem will be passed to the block.
36
- def select_gems(latest=true)
37
- specs = latest ?
38
- Gem.source_index.latest_specs :
39
- Gem.source_index.gems.collect {|(name, spec)| spec }
40
-
41
- # this song and dance is to ensure that specs are sorted
42
- # by name (ascending) then version (descending) so that
43
- # the latest version of a spec appears first
44
- specs_by_name = {}
45
- specs.each do |spec|
46
- next unless !block_given? || yield(spec)
47
- (specs_by_name[spec.name] ||= []) << spec
48
- end
49
-
50
- specs = []
51
- specs_by_name.keys.sort.each do |name|
52
- specs_by_name[name].sort_by do |spec|
53
- spec.version
54
- end.reverse_each do |spec|
55
- specs << spec
56
- end
57
- end
58
-
59
- specs
60
- end
61
- end
62
- end
63
- end