tap 0.19.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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