pwrake 0.9.9.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/CHANGES_V2.md +90 -0
  4. data/{LICENSE.txt → MIT-LICENSE} +2 -3
  5. data/README +12 -0
  6. data/README.md +75 -52
  7. data/bin/gfwhere-pipe +23 -12
  8. data/bin/pwrake +22 -29
  9. data/bin/pwrake_branch +24 -0
  10. data/lib/pwrake/branch.rb +22 -0
  11. data/lib/pwrake/branch/branch.rb +213 -0
  12. data/lib/pwrake/branch/branch_application.rb +53 -0
  13. data/lib/pwrake/branch/fiber_queue.rb +36 -0
  14. data/lib/pwrake/branch/file_utils.rb +101 -0
  15. data/lib/pwrake/branch/shell.rb +231 -0
  16. data/lib/pwrake/{profiler.rb → branch/shell_profiler.rb} +28 -27
  17. data/lib/pwrake/branch/worker_communicator.rb +104 -0
  18. data/lib/pwrake/{gfarm_feature.rb → gfarm/gfarm_path.rb} +2 -100
  19. data/lib/pwrake/gfarm/gfarm_postprocess.rb +53 -0
  20. data/lib/pwrake/iomux/channel.rb +70 -0
  21. data/lib/pwrake/iomux/handler.rb +124 -0
  22. data/lib/pwrake/iomux/handler_set.rb +35 -0
  23. data/lib/pwrake/iomux/runner.rb +62 -0
  24. data/lib/pwrake/logger.rb +3 -150
  25. data/lib/pwrake/master.rb +30 -137
  26. data/lib/pwrake/master/fiber_pool.rb +69 -0
  27. data/lib/pwrake/master/idle_cores.rb +30 -0
  28. data/lib/pwrake/master/master.rb +345 -0
  29. data/lib/pwrake/master/master_application.rb +150 -0
  30. data/lib/pwrake/master/postprocess.rb +16 -0
  31. data/lib/pwrake/{graphviz.rb → misc/graphviz.rb} +0 -0
  32. data/lib/pwrake/{mcgp.rb → misc/mcgp.rb} +63 -42
  33. data/lib/pwrake/option/host_map.rb +158 -0
  34. data/lib/pwrake/option/option.rb +357 -0
  35. data/lib/pwrake/option/option_filesystem.rb +112 -0
  36. data/lib/pwrake/queue/locality_aware_queue.rb +158 -0
  37. data/lib/pwrake/queue/no_action_queue.rb +67 -0
  38. data/lib/pwrake/queue/queue_array.rb +366 -0
  39. data/lib/pwrake/queue/task_queue.rb +164 -0
  40. data/lib/pwrake/report.rb +1 -0
  41. data/lib/pwrake/report/parallelism.rb +9 -3
  42. data/lib/pwrake/report/report.rb +50 -103
  43. data/lib/pwrake/report/task_stat.rb +83 -0
  44. data/lib/pwrake/task/task_algorithm.rb +107 -0
  45. data/lib/pwrake/task/task_manager.rb +32 -0
  46. data/lib/pwrake/task/task_property.rb +98 -0
  47. data/lib/pwrake/task/task_rank.rb +48 -0
  48. data/lib/pwrake/task/task_wrapper.rb +296 -0
  49. data/lib/pwrake/version.rb +1 -1
  50. data/lib/pwrake/worker/executor.rb +169 -0
  51. data/lib/pwrake/worker/gfarm_directory.rb +90 -0
  52. data/lib/pwrake/worker/invoker.rb +199 -0
  53. data/lib/pwrake/worker/load.rb +14 -0
  54. data/lib/pwrake/worker/log_executor.rb +73 -0
  55. data/lib/pwrake/worker/shared_directory.rb +74 -0
  56. data/lib/pwrake/worker/worker_main.rb +14 -0
  57. data/lib/pwrake/worker/writer.rb +59 -0
  58. data/setup.rb +1212 -1502
  59. data/spec/003/Rakefile +2 -2
  60. data/spec/008/Rakefile +2 -1
  61. data/spec/009/Rakefile +1 -1
  62. data/spec/009/pwrake_conf.yaml +1 -3
  63. data/spec/hosts +0 -2
  64. data/spec/pwrake_spec.rb +9 -8
  65. metadata +50 -21
  66. data/lib/pwrake.rb +0 -19
  67. data/lib/pwrake/application.rb +0 -232
  68. data/lib/pwrake/counter.rb +0 -54
  69. data/lib/pwrake/file_utils.rb +0 -98
  70. data/lib/pwrake/gfwhere_pool.rb +0 -109
  71. data/lib/pwrake/host_list.rb +0 -88
  72. data/lib/pwrake/locality_aware_queue.rb +0 -413
  73. data/lib/pwrake/option.rb +0 -400
  74. data/lib/pwrake/rake_modify.rb +0 -14
  75. data/lib/pwrake/shell.rb +0 -186
  76. data/lib/pwrake/task_algorithm.rb +0 -475
  77. data/lib/pwrake/task_queue.rb +0 -633
  78. data/lib/pwrake/timer.rb +0 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b5f302ea2a00a59015b371e07ddf10f646f06eaa
4
- data.tar.gz: 57d72fefb63e1a2b8270adf3b479aaba0add62f4
3
+ metadata.gz: 06576ed3f8e9a5ce1a3a551d325a1ff8f279e00e
4
+ data.tar.gz: 4303b90a5506a9bb028c63dd8ba344e3ab275c08
5
5
  SHA512:
6
- metadata.gz: 4990bd96c5a5bc7e268d26efbe07e0cb297b6a629f63f350b3d595e8b27c0831569fdece5a4070991ca7c7017b9914e934c5ed6a0ca444cc5ca3ef937721d040
7
- data.tar.gz: 5b89d6aad26a1f802b1e4626aba67815f9914d3549dbb154864eb927558a58e8a16afcdf06025ffafe3724ae99666b8e4ef4db2bf62a3de57cf7f0678d50d7bb
6
+ metadata.gz: e07ed43f6036919a6741c5db56e8fce972e0cbdb454ba252300e232000b882617baa123a0b602c53dd43b3e63d47034788aa11658626d35bdd59d976a5155149
7
+ data.tar.gz: 0da74c52c071489794a83e0eba0be5305c0eaa8e31e477dff4eedbd18cec229f8f5dd1ab66ec78f90a1c1e4170137fddd64e22ec08f133b1f1521b4219ee5791
data/.gitignore CHANGED
@@ -5,6 +5,8 @@
5
5
  .yardoc
6
6
  Gemfile.lock
7
7
  InstalledFiles
8
+ SetupConfig
9
+ SetupReceipt
8
10
  _yardoc
9
11
  coverage
10
12
  doc/
@@ -0,0 +1,90 @@
1
+ # Changes from 0.9.9.2 to 2.0.0
2
+
3
+ ## Command line options
4
+
5
+ Obsolete:
6
+
7
+ -L, --logfile [FILE]
8
+
9
+ New:
10
+
11
+ -L, --log, --log-dir [DIRECTORY]
12
+ --report LOGDIR
13
+ --clear-gfarm2fs
14
+
15
+
16
+ ## pwrake_conf.yaml or environment variables
17
+
18
+ Obsolete:
19
+
20
+ LOGFILE
21
+ TASKLOG
22
+ PROFILE
23
+ NUM_NOACTION_THREADS
24
+ THREAD_CREATE_INTERVAL
25
+ STEAL_WAIT
26
+ STEAL_WAIT_MAX
27
+
28
+ New:
29
+
30
+ LOG_DIR
31
+ LOG_FILE
32
+ TASK_CSV_FILE
33
+ COMMAND_CSV_FILE
34
+ GC_LOG_FILE
35
+ SHELL_COMMAND
36
+ SHELL_RC
37
+ HEARTBEAT
38
+ FAILURE_TERMINATION
39
+ SHELL_START_INTERVAL
40
+ GFARM2FS_OPTION
41
+ GFARM2FS_DEBUG
42
+ GFARM2FS_DEBUG_WAIT
43
+
44
+ ## The use of Fiber instead of Thread
45
+ * Every Rake Task runs in parallel under Fiber context, instead of Thread.
46
+ * Fiber context does not switch in task action blocks.
47
+ Instead, it switches in "sh" methods, or outside of task action blocks.
48
+
49
+ ### Example of Fiber behavior
50
+ Rakefile:
51
+ ```ruby
52
+ T = (1..4).map do |i|
53
+ task "task#{i}" do
54
+ sleep 1 # Ruby's sleep method: no context switch
55
+ end.name
56
+ end
57
+
58
+ task :default => T
59
+ ```
60
+
61
+ Result:
62
+
63
+ $ time pwrake -j 4
64
+
65
+ real 0m4.294s
66
+ user 0m0.151s
67
+ sys 0m0.028s
68
+
69
+ Rakefile:
70
+ ```ruby
71
+ T = (1..4).map do |i|
72
+ task "task#{i}" do
73
+ sh "sleep 1" # sleep processes run in parallel
74
+ end.name
75
+ end
76
+
77
+ task :default => T
78
+ ```
79
+
80
+ Result:
81
+
82
+ $ time pwrake -j 4
83
+ sleep 1
84
+ sleep 1
85
+ sleep 1
86
+ sleep 1
87
+
88
+ real 0m1.299s
89
+ user 0m0.155s
90
+ sys 0m0.030s
@@ -1,6 +1,4 @@
1
- Copyright (c) 2009-2012 Masahiro TANAKA
2
-
3
- MIT License
1
+ Copyright (c) 2009-2012 Masahiro Tanaka
4
2
 
5
3
  Permission is hereby granted, free of charge, to any person obtaining
6
4
  a copy of this software and associated documentation files (the
@@ -20,3 +18,4 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
18
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
19
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
20
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
data/README ADDED
@@ -0,0 +1,12 @@
1
+ Pwrake2 - Parallel Workflow extension for Rake
2
+ Masahiro Tanaka 2012-04-14
3
+
4
+ *** under development ***
5
+
6
+ * Required package
7
+
8
+ - Ruby 1.9.3 + Rake 0.9.2.2
9
+
10
+ * Install
11
+
12
+ $ ruby setup.rb
data/README.md CHANGED
@@ -16,7 +16,7 @@ Parallel workflow extension for Rake
16
16
 
17
17
  ## Installation
18
18
 
19
- Download source tgz/zip and expand, cd to subdir and install:
19
+ Download source tgz/zip and expand, cd to subdirectory and install:
20
20
 
21
21
  $ ruby setup.rb
22
22
 
@@ -52,71 +52,90 @@ Or, gem install:
52
52
 
53
53
  ## Options
54
54
 
55
- ### Command line option
56
-
57
- -F, --hostfile FILE [Pw] Read hostnames from FILE
58
- -j, --jobs [N] [Pw] Number of threads at localhost (default: # of processors)
59
- -L, --logfile [FILE] [Pw] Write log to FILE
60
- --ssh-opt, --ssh-option OPTION
61
- [Pw] Option passed to SSH
62
- --filesystem FILESYSTEM [Pw] Specify FILESYSTEM (nfs|gfarm)
63
- --gfarm [Pw] FILESYSTEM=gfarm
64
- -A, --disable-affinity [Pw] Turn OFF affinity (AFFINITY=off)
65
- -S, --disable-steal [Pw] Turn OFF task steal
66
- -d, --debug [Pw] Output Debug messages
67
- --pwrake-conf [FILE] [Pw] Pwrake configuation file in YAML
68
- --show-conf, --show-config [Pw] Show Pwrake configuration options
69
- --report LOG [Pw] Report profile HTML from LOG and exit.
55
+ ### Pwrake command line options (in addition to Rake option)
56
+
57
+ -F, --hostfile FILE [Pw] Read hostnames from FILE
58
+ -j, --jobs [N] [Pw] Number of threads at localhost (default: # of processors)
59
+ -L, --log, --log-dir [DIRECTORY] [Pw] Write log to DIRECTORY
60
+ --ssh-opt, --ssh-option OPTION
61
+ [Pw] Option passed to SSH
62
+ --filesystem FILESYSTEM [Pw] Specify FILESYSTEM (nfs|gfarm)
63
+ --gfarm [Pw] FILESYSTEM=gfarm
64
+ -A, --disable-affinity [Pw] Turn OFF affinity (AFFINITY=off)
65
+ -S, --disable-steal [Pw] Turn OFF task steal
66
+ -d, --debug [Pw] Output Debug messages
67
+ --pwrake-conf [FILE] [Pw] Pwrake configuation file in YAML
68
+ --show-conf, --show-config [Pw] Show Pwrake configuration options
69
+ --report LOGDIR [Pw] Report workflow statistics from LOGDIR to HTML and exit.
70
+ --clear-gfarm2fs [Pw] Clear gfarm2fs mountpoints left after failure.
70
71
 
71
72
  ### pwrake_conf.yaml
72
73
 
73
74
  * If `pwrake_conf.yaml` exists at current directory, Pwrake reads options from it.
74
75
  * Example (in YAML form):
75
76
 
76
- HOSTFILE : hosts
77
- LOGFILE : true
78
- TASKLOG : true
79
- PROFILE : true
80
- GNU_TIME : true
81
- PLOT_PARALLELISM : true
77
+ HOSTFILE: hosts
78
+ LOG_DIR: true
82
79
  DISABLE_AFFINITY: true
83
80
  DISABLE_STEAL: true
84
- FAILED_TARGET : delete
81
+ FAILED_TARGET: delete
85
82
  PASS_ENV :
86
83
  - ENV1
87
84
  - ENV2
88
85
 
89
86
  * Option list:
90
87
 
91
- HOSTFILE, HOSTS default=false
92
- LOGFILE, LOG default=none, string=filename, true="Pwrake%Y%m%d-%H%M%S_%$.log"
93
- TASKLOG default=none, string=filename, true="Pwrake%Y%m%d-%H%M%S_%$.task"
94
- PROFILE default=none, string=filename, true="Pwrake%Y%m%d-%H%M%S_%$.csv"
88
+ HOSTFILE, HOSTS nil(default, localhost)|filename
89
+ LOG_DIR, LOG nil(default, No log output)|true(dirname="Pwrake%Y%m%d-%H%M%S")|dirname
90
+ LOG_FILE default="pwrake.log"
91
+ TASK_CSV_FILE default="task.csv"
92
+ COMMAND_CSV_FILE default="command.csv"
93
+ GC_LOG_FILE default="gc.log"
95
94
  WORK_DIR default=$PWD
96
- FILESYSTEM default=nil (autodetect)
97
- SSH_OPTION (String) SSH option
95
+ FILESYSTEM default(autodetect)|gfarm
96
+ SSH_OPTION SSH option
97
+ SHELL_COMMAND default=$SHELL
98
+ SHELL_RC Run-Command when shell starts
98
99
  PASS_ENV (Array) Environment variables passed to SSH
99
- GNU_TIME If true, obtains PROFILEs using GNU time
100
- PLOT_PARALLELISM If true, plot parallelism using GNUPLOT
101
- FAILED_TARGET ( rename(default) | delete | leave ) failed files
102
- QUEUE_PRIORITY RANK(default), FIFO, LIFO, LIHR
103
- NOACTION_QUEUE_PRIORITY FIFO(default), LIFO, RAND
104
- NUM_NOACTION_THREADS default=4 when gfarm, else 1
105
- THREAD_CREATE_INTERVAL default=0.01 (sec)
106
- HALT_QUEUE_WHILE_SEARCH true|false
107
- GRAPH_PARTITION true|false
108
-
109
- for Gfarm system:
110
-
111
- DISABLE_AFFINITY default=false
112
- DISABLE_STEAL default=false
113
- STEAL_WAIT default=0 (sec)
114
- STEAL_WAIT_MAX default=10 (sec)
115
- : Wait min(STEAL_WAIT*2**n, STEAL_WAIT_MAX) sec for task steal.
116
- GFARM_BASEDIR default="/tmp"
117
- GFARM_PREFIX default="pwrake_$USER"
118
- GFARM_SUBDIR default='/'
100
+ HEARTBEAT defulat=240 - Hearbeat interval in seconds
101
+ FAILED_TARGET rename(default)|delete|leave - Treatment of failed target files
102
+ FAILURE_TERMINATION wait(default)|kill|continue - Behavior of other tasks when a task is failed
103
+ QUEUE_PRIORITY LIHR(default)|FIFO|LIFO|RANK
104
+ NOACTION_QUEUE_PRIORITY FIFO(default)|LIFO|RAND
105
+ SHELL_START_INTERVAL default=0.012 (sec)
106
+ GRAPH_PARTITION false(default)|true
107
+
108
+ * Options for Gfarm system:
109
+
110
+ DISABLE_AFFINITY default=false
111
+ DISABLE_STEAL default=false
112
+ GFARM_BASEDIR default="/tmp"
113
+ GFARM_PREFIX default="pwrake_$USER"
114
+ GFARM_SUBDIR default='/'
119
115
  MAX_GFWHERE_WORKER default=8
116
+ GFARM2FS_OPTION default=""
117
+ GFARM2FS_DEBUG default=false
118
+ GFARM2FS_DEBUG_WAIT default=1
119
+
120
+ ## Task Properties
121
+
122
+ * Task properties are specified in `desc` strings above task definition in Rakefile.
123
+
124
+ Example of Rakefile:
125
+
126
+ desc "ncore=4 allow=ourhost*"
127
+ rule ".o" => ".c" do
128
+ sh "..."
129
+ end
130
+
131
+ Properties (The leftmost item is default):
132
+
133
+ ncore=integer - The number of cores used by this task.
134
+ exclusive=no|yes - Exclusively execute this task in a single node.
135
+ allow=hostname - Allow this host to execute this task. (accepts wild card)
136
+ deny=hostname - Deny this host to execute this task. (accepts wild card)
137
+ order=deny,allow|allow,deny - The order of evaluation.
138
+ steal=yes|no - Allow task stealing for this task.
120
139
 
121
140
  ## Note for Gfarm
122
141
 
@@ -135,11 +154,15 @@ Or, gem install:
135
154
  --with-metis-include=/usr/local/include \
136
155
  --with-metis-lib=/usr/local/lib
137
156
 
157
+ ## Current version
158
+
159
+ * Pwrake version 2.0.0
160
+
138
161
  ## Tested Platform
139
162
 
140
- * Ruby 2.1.4
141
- * Rake 10.1.0
142
- * CentOS 6.4
163
+ * Ruby 2.2.2
164
+ * Rake 10.4.2
165
+ * CentOS 6.7
143
166
 
144
167
  ## Acknowledgment
145
168
 
@@ -4,6 +4,7 @@ require 'ffi'
4
4
  require 'singleton'
5
5
 
6
6
  module Gfarm
7
+
7
8
  class GfarmError < StandardError
8
9
  end
9
10
  GFARM_ERR_NO_ERROR = 0
@@ -31,20 +32,26 @@ module Gfarm
31
32
  end
32
33
  module_function :find_executable
33
34
 
34
- LIBGFARM_PATH = nil
35
- LIBGFARM_FILE = "libgfarm.so"
36
- if LIBGFARM_PATH
37
- path = File.join(LIBGFARM_PATH,LIBGFARM_FILE)
38
- elsif x = find_executable('gfwhere')
39
- d = File.dirname(x)
40
- %w[lib64 lib].each do |l|
41
- f = File.join(d,"..",l,LIBGFARM_FILE)
42
- if File.file?(f)
43
- path = f
44
- break
45
- end
35
+ if LIBGFARM_PATH = ENV['LIBGFARM_PATH']
36
+ dirs = LIBGFARM_PATH.split(":")
37
+ elsif d = find_executable('gfwhere')
38
+ d = File.dirname(File.dirname(d))
39
+ dirs = %w[lib64 lib].map{|l| File.join(d,l)}
40
+ else
41
+ raise StandardError, "cannot find libgfarm path"
42
+ end
43
+ path = nil
44
+ dirs.each do |d|
45
+ f = File.join(d,"libgfarm.so*")
46
+ g = Dir.glob(f)
47
+ if !g.empty?
48
+ path = g[0]
49
+ break
46
50
  end
47
51
  end
52
+ if !(path && File.exist?(path))
53
+ raise StandardError, "cannot find libgfarm"
54
+ end
48
55
  extend ::FFI::Library
49
56
  ffi_lib path
50
57
  attach_function :gfarm_initialize, [:pointer, :pointer], :int
@@ -142,6 +149,10 @@ module Gfarm
142
149
 
143
150
  end
144
151
 
152
+ [:PIPE,:TERM,:INT].each do |sig|
153
+ Signal.trap(sig, "EXIT")
154
+ end
155
+
145
156
  gfarm = Gfarm.connection
146
157
 
147
158
  while path=$stdin.gets
data/bin/pwrake CHANGED
@@ -1,37 +1,30 @@
1
- #! /usr/bin/env ruby
2
-
3
- #--
4
- # Copyright (c) 2009-2012 Masahiro TANAKA
5
- #
6
- # Permission is hereby granted, free of charge, to any person obtaining a copy
7
- # of this software and associated documentation files (the "Software"), to
8
- # deal in the Software without restriction, including without limitation the
9
- # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10
- # sell copies of the Software, and to permit persons to whom the Software is
11
- # furnished to do so, subject to the following conditions:
12
- #
13
- # The above copyright notice and this permission notice shall be included in
14
- # all copies or substantial portions of the Software.
15
- #
16
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
- # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22
- # IN THE SOFTWARE.
23
- #++
1
+ #!/usr/bin/env ruby
24
2
 
25
3
  begin
26
- require 'rubygems'
27
- gem 'rake'
4
+ require 'rake'
28
5
  rescue LoadError
6
+ require 'rubygems'
7
+ require 'rake'
29
8
  end
30
9
 
31
- require 'rake'
32
-
33
- libpath = File.expand_path(File.dirname(__FILE__))+"/../lib"
10
+ libpath = File.absolute_path(File.dirname(__FILE__))+"/../lib"
34
11
  $LOAD_PATH.unshift libpath
35
- require "pwrake"
36
12
 
13
+ require "pwrake/master"
14
+ require "pwrake/branch"
15
+ class Rake::Application
16
+ include Pwrake::BranchApplication
17
+ prepend Pwrake::MasterApplication
18
+ prepend Pwrake::TaskManager
19
+ end
20
+ class Rake::Task
21
+ include Pwrake::TaskAlgorithm
22
+ end
23
+
24
+ # does NOT exit when writing to broken pipe
25
+ Signal.trap(:PIPE, "IGNORE")
26
+
27
+ #require "tracer"
28
+ #Tracer.on
29
+ #Thread.abort_on_exception = true
37
30
  Rake.application.run
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ begin
4
+ require 'rake'
5
+ rescue LoadError
6
+ require 'rubygems'
7
+ require 'rake'
8
+ end
9
+
10
+ libpath = File.absolute_path(File.dirname(__FILE__))+"/../lib"
11
+ $LOAD_PATH.unshift libpath
12
+
13
+ require "pwrake/branch"
14
+ class Rake::Application
15
+ include Pwrake::BranchApplication
16
+ end
17
+
18
+ #require "tracer"
19
+ #Tracer.on
20
+
21
+ # does NOT exit when writing to broken pipe
22
+ Signal.trap(:PIPE, "IGNORE")
23
+
24
+ Rake.application.run_branch($stdin,$stdout)