tap 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Basic Overview +151 -0
- data/Command Reference +99 -0
- data/History +24 -0
- data/MIT-LICENSE +1 -1
- data/README +29 -57
- data/Rakefile +30 -37
- data/Tutorial +243 -191
- data/bin/tap +66 -35
- data/lib/tap.rb +47 -29
- data/lib/tap/app.rb +700 -342
- data/lib/tap/{script → cmd}/console.rb +0 -0
- data/lib/tap/{script → cmd}/destroy.rb +0 -0
- data/lib/tap/{script → cmd}/generate.rb +0 -0
- data/lib/tap/cmd/run.rb +156 -0
- data/lib/tap/constants.rb +4 -0
- data/lib/tap/dump.rb +57 -0
- data/lib/tap/env.rb +316 -0
- data/lib/tap/file_task.rb +106 -109
- data/lib/tap/generator.rb +4 -1
- data/lib/tap/generator/generators/command/USAGE +6 -0
- data/lib/tap/generator/generators/command/command_generator.rb +17 -0
- data/lib/tap/generator/generators/{script/templates/script.erb → command/templates/command.erb} +10 -10
- data/lib/tap/generator/generators/config/USAGE +21 -0
- data/lib/tap/generator/generators/config/config_generator.rb +17 -7
- data/lib/tap/generator/generators/file_task/USAGE +3 -0
- data/lib/tap/generator/generators/file_task/file_task_generator.rb +16 -0
- data/lib/tap/generator/generators/file_task/templates/file.txt +2 -0
- data/lib/tap/generator/generators/file_task/templates/file.yml +3 -0
- data/lib/tap/generator/generators/file_task/templates/task.erb +26 -20
- data/lib/tap/generator/generators/file_task/templates/test.erb +20 -10
- data/lib/tap/generator/generators/generator/generator_generator.rb +1 -1
- data/lib/tap/generator/generators/generator/templates/generator.erb +21 -12
- data/lib/tap/generator/generators/root/templates/Rakefile +33 -24
- data/lib/tap/generator/generators/root/templates/tap.yml +28 -31
- data/lib/tap/generator/generators/root/templates/test/tap_test_helper.rb +1 -0
- data/lib/tap/generator/generators/task/USAGE +3 -0
- data/lib/tap/generator/generators/task/task_generator.rb +18 -5
- data/lib/tap/generator/generators/task/templates/task.erb +7 -12
- data/lib/tap/generator/generators/task/templates/test.erb +10 -11
- data/lib/tap/generator/generators/workflow/templates/task.erb +1 -1
- data/lib/tap/generator/generators/workflow/templates/test.erb +1 -1
- data/lib/tap/patches/rake/rake_test_loader.rb +8 -0
- data/lib/tap/patches/rake/testtask.rb +55 -0
- data/lib/tap/patches/ruby19/backtrace_filter.rb +51 -0
- data/lib/tap/patches/ruby19/parsedate.rb +16 -0
- data/lib/tap/root.rb +172 -67
- data/lib/tap/script.rb +70 -336
- data/lib/tap/support/aggregator.rb +55 -0
- data/lib/tap/support/audit.rb +281 -280
- data/lib/tap/support/batchable.rb +59 -0
- data/lib/tap/support/class_configuration.rb +279 -0
- data/lib/tap/support/configurable.rb +92 -0
- data/lib/tap/support/configurable_methods.rb +296 -0
- data/lib/tap/support/executable.rb +98 -0
- data/lib/tap/support/executable_queue.rb +82 -0
- data/lib/tap/support/logger.rb +9 -15
- data/lib/tap/support/rake.rb +43 -54
- data/lib/tap/support/run_error.rb +32 -13
- data/lib/tap/support/shell_utils.rb +47 -0
- data/lib/tap/support/tdoc.rb +9 -8
- data/lib/tap/support/tdoc/config_attr.rb +40 -16
- data/lib/tap/support/validation.rb +77 -0
- data/lib/tap/support/versions.rb +36 -36
- data/lib/tap/task.rb +276 -482
- data/lib/tap/test.rb +20 -261
- data/lib/tap/test/env_vars.rb +7 -5
- data/lib/tap/test/file_methods.rb +126 -121
- data/lib/tap/test/subset_methods.rb +86 -45
- data/lib/tap/test/tap_methods.rb +271 -0
- data/lib/tap/workflow.rb +174 -46
- data/test/app/config/another/task.yml +1 -0
- data/test/app/config/erb.yml +2 -1
- data/test/app/config/some/task.yml +1 -0
- data/test/app/config/template.yml +2 -6
- data/test/app_test.rb +1241 -1008
- data/test/env/test_configure/recurse_a.yml +2 -0
- data/test/env/test_configure/recurse_b.yml +2 -0
- data/test/env/test_configure/tap.yml +23 -0
- data/test/env/test_load_env_config/dir/tap.yml +3 -0
- data/test/env/test_load_env_config/recurse_a.yml +2 -0
- data/test/env/test_load_env_config/recurse_b.yml +2 -0
- data/test/env/test_load_env_config/tap.yml +3 -0
- data/test/env_test.rb +198 -0
- data/test/file_task_test.rb +70 -53
- data/{lib/tap/generator/generators/package/USAGE → test/root/file.txt} +0 -0
- data/test/root_test.rb +621 -454
- data/test/script_test.rb +38 -174
- data/test/support/aggregator_test.rb +99 -0
- data/test/support/audit_test.rb +409 -416
- data/test/support/batchable_test.rb +74 -0
- data/test/support/{task_configuration_test.rb → class_configuration_test.rb} +106 -47
- data/test/{task/config/overriding.yml → support/configurable/config/configured.yml} +0 -0
- data/test/support/configurable_test.rb +295 -0
- data/test/support/executable_queue_test.rb +103 -0
- data/test/support/executable_test.rb +38 -0
- data/test/support/logger_test.rb +17 -17
- data/test/support/rake_test.rb +4 -2
- data/test/support/shell_utils_test.rb +24 -0
- data/test/support/tdoc_test.rb +265 -258
- data/test/support/validation_test.rb +54 -0
- data/test/support/versions_test.rb +38 -38
- data/test/tap_test_helper.rb +19 -5
- data/test/tap_test_suite.rb +5 -2
- data/test/task_base_test.rb +13 -104
- data/test/task_syntax_test.rb +300 -0
- data/test/task_test.rb +258 -381
- data/test/test/env_vars_test.rb +40 -40
- data/test/test/file_methods/{test_assert_output_files_equal → test_assert_files}/expected/one.txt +0 -0
- data/test/test/file_methods/{test_assert_output_files_equal → test_assert_files}/expected/two.txt +0 -0
- data/test/test/file_methods/{test_assert_output_files_equal → test_assert_files}/input/one.txt +0 -0
- data/test/test/file_methods/{test_assert_output_files_equal → test_assert_files}/input/two.txt +0 -0
- data/test/test/{test_file_task_test → file_methods/test_assert_files_can_have_no_expected_files_if_specified}/input/one.txt +0 -0
- data/test/test/{test_file_task_test → file_methods/test_assert_files_can_have_no_expected_files_if_specified}/input/two.txt +0 -0
- data/test/test/file_methods/test_assert_files_fails_for_different_content/expected/one.txt +1 -0
- data/test/test/{test_file_task_test → file_methods/test_assert_files_fails_for_different_content}/expected/two.txt +0 -0
- data/test/test/file_methods/test_assert_files_fails_for_different_content/input/one.txt +1 -0
- data/test/test/file_methods/test_assert_files_fails_for_different_content/input/two.txt +1 -0
- data/test/test/{test_file_task_test → file_methods/test_assert_files_fails_for_missing_expected_file}/expected/one.txt +0 -0
- data/test/test/file_methods/test_assert_files_fails_for_missing_expected_file/input/one.txt +1 -0
- data/test/test/file_methods/test_assert_files_fails_for_missing_expected_file/input/two.txt +1 -0
- data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/expected/one.txt +1 -0
- data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/expected/two.txt +1 -0
- data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/input/one.txt +1 -0
- data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/input/two.txt +1 -0
- data/test/test/file_methods/test_assert_files_fails_for_no_expected_files/input/one.txt +1 -0
- data/test/test/file_methods/test_assert_files_fails_for_no_expected_files/input/two.txt +1 -0
- data/test/test/file_methods_doc/test_sub/expected/one.txt +1 -0
- data/test/test/file_methods_doc/test_sub/expected/two.txt +1 -0
- data/test/test/file_methods_doc/test_sub/input/one.txt +1 -0
- data/test/test/file_methods_doc/test_sub/input/two.txt +1 -0
- data/test/test/file_methods_doc_test.rb +29 -0
- data/test/test/file_methods_test.rb +214 -143
- data/test/test/subset_methods_test.rb +111 -115
- data/test/test/{test_assert_expected_result_files → tap_methods/test_assert_files}/expected/task/name/a.txt +0 -0
- data/test/test/{test_assert_expected_result_files → tap_methods/test_assert_files}/expected/task/name/b.txt +0 -0
- data/test/test/{test_assert_expected_result_files → tap_methods/test_assert_files}/input/a.txt +0 -0
- data/test/test/{test_assert_expected_result_files → tap_methods/test_assert_files}/input/b.txt +0 -0
- data/test/test/tap_methods_test.rb +399 -0
- data/test/workflow_test.rb +101 -91
- metadata +86 -70
- data/lib/tap/generator/generators/package/package_generator.rb +0 -38
- data/lib/tap/generator/generators/package/templates/package.erb +0 -186
- data/lib/tap/generator/generators/script/USAGE +0 -0
- data/lib/tap/generator/generators/script/script_generator.rb +0 -17
- data/lib/tap/script/run.rb +0 -154
- data/lib/tap/support/batch_queue.rb +0 -162
- data/lib/tap/support/combinator.rb +0 -114
- data/lib/tap/support/task_configuration.rb +0 -169
- data/lib/tap/support/template.rb +0 -81
- data/lib/tap/support/templater.rb +0 -155
- data/lib/tap/version.rb +0 -4
- data/test/app/config/addition_template.yml +0 -6
- data/test/app_class_test.rb +0 -33
- data/test/check/binding_eval.rb +0 -23
- data/test/check/define_method_check.rb +0 -22
- data/test/check/dependencies_check.rb +0 -175
- data/test/check/inheritance_check.rb +0 -22
- data/test/support/batch_queue_test.rb +0 -320
- data/test/support/combinator_test.rb +0 -249
- data/test/support/template_test.rb +0 -122
- data/test/support/templater/erb.txt +0 -2
- data/test/support/templater/erb.yml +0 -2
- data/test/support/templater/somefile.txt +0 -2
- data/test/support/templater_test.rb +0 -192
- data/test/task/config/template.yml +0 -4
- data/test/task_class_test.rb +0 -170
- data/test/task_execute_test.rb +0 -262
- data/test/test/file_methods/test_assert_expected/expected/file.txt +0 -1
- data/test/test/file_methods/test_assert_expected/expected/folder/file.txt +0 -1
- data/test/test/file_methods/test_assert_expected/input/file.txt +0 -1
- data/test/test/file_methods/test_assert_expected/input/folder/file.txt +0 -1
- data/test/test/file_methods/test_assert_files_exist/input/input_1.txt +0 -0
- data/test/test/file_methods/test_assert_files_exist/input/input_2.txt +0 -0
- data/test/test/file_methods/test_file_compare/expected/output_1.txt +0 -3
- data/test/test/file_methods/test_file_compare/expected/output_2.txt +0 -1
- data/test/test/file_methods/test_file_compare/input/input_1.txt +0 -3
- data/test/test/file_methods/test_file_compare/input/input_2.txt +0 -3
- data/test/test/file_methods/test_infer_glob/expected/file.yml +0 -0
- data/test/test/file_methods/test_infer_glob/expected/file_1.txt +0 -0
- data/test/test/file_methods/test_infer_glob/expected/file_2.txt +0 -0
- data/test/test/file_methods/test_yml_compare/expected/output_1.yml +0 -6
- data/test/test/file_methods/test_yml_compare/expected/output_2.yml +0 -6
- data/test/test/file_methods/test_yml_compare/input/input_1.yml +0 -4
- data/test/test/file_methods/test_yml_compare/input/input_2.yml +0 -4
- data/test/test_test.rb +0 -373
File without changes
|
File without changes
|
File without changes
|
data/lib/tap/cmd/run.rb
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
# = Usage
|
2
|
+
# tap run {options} -- {task options} task INPUTS...
|
3
|
+
#
|
4
|
+
# examples:
|
5
|
+
# tap run --help Prints this help
|
6
|
+
# tap run -- task --help Prints help for task
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'tap/script'
|
10
|
+
env = Tap::Env.instance
|
11
|
+
app = Tap::App.instance
|
12
|
+
|
13
|
+
#
|
14
|
+
# handle options
|
15
|
+
#
|
16
|
+
|
17
|
+
opts = [
|
18
|
+
['--help', '-h', GetoptLong::NO_ARGUMENT, "Print this help"],
|
19
|
+
['--debug', '-d', GetoptLong::NO_ARGUMENT, "Trace execution and debug"],
|
20
|
+
['--force', '-f', GetoptLong::NO_ARGUMENT, "Force execution at checkpoints"],
|
21
|
+
['--quiet', '-q', GetoptLong::NO_ARGUMENT, "Suppress logging"]]
|
22
|
+
|
23
|
+
Tap::Script.handle_options(*opts) do |opt, value|
|
24
|
+
case opt
|
25
|
+
when '--help'
|
26
|
+
puts Tap::Script.usage(__FILE__, "Usage", :keep_headers => false)
|
27
|
+
puts
|
28
|
+
puts "Options:"
|
29
|
+
puts Tap::Script.usage_options(opts)
|
30
|
+
exit
|
31
|
+
|
32
|
+
when '--quiet', '--force', '--debug'
|
33
|
+
# simply track these have been set
|
34
|
+
opt =~ /^-+(\w+)/
|
35
|
+
app.options.send("#{$1}=", true)
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
#
|
41
|
+
# handle options for each specified task
|
42
|
+
#
|
43
|
+
rounds = Tap::Script.split_argv(ARGV).collect do |argv|
|
44
|
+
argv.each do |args|
|
45
|
+
ARGV.clear
|
46
|
+
ARGV.concat(args)
|
47
|
+
|
48
|
+
td = Tap::Script.next_arg(ARGV)
|
49
|
+
case td
|
50
|
+
when 'rake', nil
|
51
|
+
# remove --help as this will print the Rake help
|
52
|
+
ARGV.delete_if do |arg|
|
53
|
+
if arg == "--help"
|
54
|
+
env.log(:warn, "ignoring --help config for rake command")
|
55
|
+
true
|
56
|
+
else
|
57
|
+
false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
next if ARGV.empty?
|
61
|
+
|
62
|
+
rake = env.rake_setup
|
63
|
+
|
64
|
+
# takes the place of rake.top_level
|
65
|
+
if rake.options.show_tasks
|
66
|
+
rake.display_tasks_and_comments
|
67
|
+
exit
|
68
|
+
elsif rake.options.show_prereqs
|
69
|
+
rake.display_prerequisites
|
70
|
+
exit
|
71
|
+
else
|
72
|
+
rake.top_level_tasks.each do |task_name|
|
73
|
+
app.task(task_name).enq
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
else
|
78
|
+
begin
|
79
|
+
# attempt lookup the task class
|
80
|
+
task_class = app.task_class(td)
|
81
|
+
rescue(Tap::App::LookupError)
|
82
|
+
end
|
83
|
+
|
84
|
+
# unless a Tap::Task was found, treat the
|
85
|
+
# args as a specification for Rake.
|
86
|
+
if task_class == nil || !task_class.include?(Tap::Support::Configurable)
|
87
|
+
args.unshift('rake')
|
88
|
+
redo
|
89
|
+
end
|
90
|
+
|
91
|
+
# now let the class handle the argv
|
92
|
+
ARGV.collect! {|str| Tap::Script.parse_yaml(str) }
|
93
|
+
ARGV.unshift(td)
|
94
|
+
task_class.argv_enq(app)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
app.queue.clear
|
99
|
+
end
|
100
|
+
ARGV.clear
|
101
|
+
|
102
|
+
rounds.delete_if {|round| round.empty? }
|
103
|
+
if rounds.empty?
|
104
|
+
puts "no task specified"
|
105
|
+
exit
|
106
|
+
end
|
107
|
+
|
108
|
+
#
|
109
|
+
# set signals
|
110
|
+
#
|
111
|
+
|
112
|
+
# info signal -- Note: some systems do
|
113
|
+
# not support the INFO signal
|
114
|
+
# (windows, fedora, at least)
|
115
|
+
signals = Signal.list.keys
|
116
|
+
if signals.include?("INFO")
|
117
|
+
Signal.trap("INFO") do
|
118
|
+
puts app.info
|
119
|
+
end
|
120
|
+
|
121
|
+
puts "ctl-i prints information"
|
122
|
+
end
|
123
|
+
|
124
|
+
# interuption signal
|
125
|
+
if signals.include?("INT")
|
126
|
+
Signal.trap("INT") do
|
127
|
+
puts " interrupted!"
|
128
|
+
# prompt for decision
|
129
|
+
while true
|
130
|
+
print "stop, terminate, or resume? (s/t/r):"
|
131
|
+
case gets.strip
|
132
|
+
when /s(top)?/i
|
133
|
+
app.stop
|
134
|
+
break
|
135
|
+
when /t(erminate)?/i
|
136
|
+
app.terminate
|
137
|
+
break
|
138
|
+
when /r(esume)?/i
|
139
|
+
break
|
140
|
+
else
|
141
|
+
puts "unexpected response..."
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
puts "ctl-c interupts execution"
|
147
|
+
end
|
148
|
+
|
149
|
+
#
|
150
|
+
# enque tasks and run!
|
151
|
+
#
|
152
|
+
puts "beginning run..."
|
153
|
+
rounds.each_with_index do |queue, i|
|
154
|
+
app.queue.concat(queue)
|
155
|
+
app.run
|
156
|
+
end
|
data/lib/tap/dump.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
module Tap
|
2
|
+
# == Description
|
3
|
+
# A primitive dump task (still in development) to print
|
4
|
+
# application results to a file or IO. The results are
|
5
|
+
# printed in a tap-readable format allowing the use of
|
6
|
+
# dumped results as inputs to other tasks.
|
7
|
+
#
|
8
|
+
# Usually dump is used as the final task in a round of
|
9
|
+
# tasks executed through 'tap run'.
|
10
|
+
# === Usage
|
11
|
+
# % tap run -- [your tasks] --+ dump filepath
|
12
|
+
#
|
13
|
+
# If no filepath is specified, the results are printed
|
14
|
+
# to stdout.
|
15
|
+
#
|
16
|
+
class Dump < Tap::FileTask
|
17
|
+
|
18
|
+
config :datetime_format, '%Y-%m-%d %H:%M:%S'
|
19
|
+
config :print_audit, true
|
20
|
+
config :print_date, true
|
21
|
+
|
22
|
+
#config :overwrite
|
23
|
+
|
24
|
+
def process(target=$stdout)
|
25
|
+
case target
|
26
|
+
when IO then dump_to(target)
|
27
|
+
else
|
28
|
+
log_basename(:dump, target)
|
29
|
+
prepare(target)
|
30
|
+
File.open(target, "wb") {|file| dump_to(file) }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def dump_to(io)
|
35
|
+
trails = []
|
36
|
+
results = {}
|
37
|
+
app.aggregator.to_hash.each_pair do |src, _results|
|
38
|
+
name = src.respond_to?(:name) ? src.name : ''
|
39
|
+
|
40
|
+
results["#{name} (#{src.object_id})"] = _results.collect {|_audit| _audit._current }
|
41
|
+
_results.each {|_audit| trails << _audit._to_s }
|
42
|
+
end
|
43
|
+
|
44
|
+
if print_audit
|
45
|
+
io.puts "# audit:"
|
46
|
+
trails.each {|trail| io.puts "# #{trail.gsub("\n", "\n# ")}"}
|
47
|
+
end
|
48
|
+
|
49
|
+
if print_date
|
50
|
+
io.puts "# date: #{Time.now.strftime(datetime_format)}"
|
51
|
+
end
|
52
|
+
|
53
|
+
YAML::dump(results, io)
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
data/lib/tap/env.rb
ADDED
@@ -0,0 +1,316 @@
|
|
1
|
+
require 'tap/root'
|
2
|
+
require 'singleton'
|
3
|
+
autoload(:PP, "pp")
|
4
|
+
|
5
|
+
module Tap
|
6
|
+
|
7
|
+
# == Under Construction
|
8
|
+
#
|
9
|
+
# Env manages configuration of the Tap execution environment, including the
|
10
|
+
# specification of gems that should be available through the tap command.
|
11
|
+
class Env
|
12
|
+
|
13
|
+
# A variety of configuration loading/handling methods for use in
|
14
|
+
# conjuction with Tap::Env, to aid in configuring the running
|
15
|
+
# environment for Tap.
|
16
|
+
module Configuration
|
17
|
+
module_function
|
18
|
+
|
19
|
+
# Templates the input filepath using ERB then loads it as YAML.
|
20
|
+
# Returns an empty hash if the file doesn't exist, or loads to
|
21
|
+
# nil or false (as for an empty file). Raises an error if the
|
22
|
+
# filepath doesn't load to a hash.
|
23
|
+
def read_config(filepath)
|
24
|
+
return {} if !File.exists?(filepath) || File.directory?(filepath)
|
25
|
+
|
26
|
+
input = ERB.new(File.read(filepath)).result
|
27
|
+
config = YAML.load(input)
|
28
|
+
|
29
|
+
case config
|
30
|
+
when Hash then config
|
31
|
+
when nil, false then {}
|
32
|
+
else
|
33
|
+
raise "expected hash from config file: #{filepath}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Partitions a configuration hash into environment, execution,
|
38
|
+
# and application configurations, as determined by ENV_CONFIG_KEYS
|
39
|
+
# and EXE_CONFIG_KEYS. All non-env, non-exe configurations are
|
40
|
+
# considered application configurations.
|
41
|
+
def partition_configs(hash, *sets)
|
42
|
+
partitions = Array.new(sets.length + 1) { Hash.new }
|
43
|
+
|
44
|
+
hash.each_pair do |key, value|
|
45
|
+
index = 0
|
46
|
+
sets.each do |keys|
|
47
|
+
break if keys.include?(key)
|
48
|
+
index += 1
|
49
|
+
end
|
50
|
+
|
51
|
+
partitions[index][key] = value
|
52
|
+
end
|
53
|
+
|
54
|
+
partitions
|
55
|
+
end
|
56
|
+
|
57
|
+
# Joins the input configuration hashes, concatenating
|
58
|
+
# values for matching keys. Values will be made into
|
59
|
+
# arrays if they are not so already; duplicate values
|
60
|
+
# are removed from the result on a key-per-key basis.
|
61
|
+
def join_configs(*configs)
|
62
|
+
merge = {}
|
63
|
+
configs.each do |hash|
|
64
|
+
hash.each_pair do |key, values|
|
65
|
+
values = [values] unless values.kind_of?(Array)
|
66
|
+
(merge[key] ||= []).concat(values)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
merge.values.each {|values| values.uniq! }
|
70
|
+
merge
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
include Configuration
|
75
|
+
include Singleton
|
76
|
+
|
77
|
+
DEFAULT_CONFIG_FILE = "tap.yml"
|
78
|
+
|
79
|
+
# Currently these are ALWAYS included.
|
80
|
+
DEFAULT_CONFIG = {
|
81
|
+
"load_paths" => ["lib"],
|
82
|
+
"load_once_paths" => [],
|
83
|
+
"config_paths" => [],
|
84
|
+
"command_paths" => ["cmd"],
|
85
|
+
"gems" => [],
|
86
|
+
"generator_paths" => ["lib/generators"]
|
87
|
+
}
|
88
|
+
|
89
|
+
attr_reader :config
|
90
|
+
attr_accessor :logger
|
91
|
+
|
92
|
+
def initialize
|
93
|
+
@config = nil
|
94
|
+
@logger = nil
|
95
|
+
# @on_handle_unknown_configs = nil
|
96
|
+
reset
|
97
|
+
end
|
98
|
+
|
99
|
+
def debug_setup
|
100
|
+
$DEBUG = true
|
101
|
+
logger.level = Logger::DEBUG
|
102
|
+
end
|
103
|
+
|
104
|
+
def rails_setup(app=Tap::App.instance)
|
105
|
+
Object.const_set('RAILS_ROOT', app.root)
|
106
|
+
Object.const_set('RAILS_DEFAULT_LOGGER', app.logger)
|
107
|
+
Dependencies.log_activity = app.debug?
|
108
|
+
end
|
109
|
+
|
110
|
+
def rake_setup(argv=ARGV, app=Tap::App.instance)
|
111
|
+
Tap::Support.autoload(:Rake, 'tap/support/rake')
|
112
|
+
|
113
|
+
# setup
|
114
|
+
app.extend Tap::Support::Rake
|
115
|
+
rake = Rake.application
|
116
|
+
options = rake.options
|
117
|
+
|
118
|
+
# merge options down from app
|
119
|
+
app.options.marshal_dump.each_pair do |key, value|
|
120
|
+
options.send("#{key}=", value)
|
121
|
+
end
|
122
|
+
options.silent = true
|
123
|
+
|
124
|
+
# run as if from command line using argv
|
125
|
+
current_argv = ARGV.dup
|
126
|
+
begin
|
127
|
+
ARGV.concat(argv)
|
128
|
+
|
129
|
+
# now follow the same protocol as
|
130
|
+
# in run, handling options
|
131
|
+
rake.init
|
132
|
+
rake.load_rakefile
|
133
|
+
ensure
|
134
|
+
ARGV.clear
|
135
|
+
ARGV.concat(current_argv)
|
136
|
+
end
|
137
|
+
|
138
|
+
rake
|
139
|
+
end
|
140
|
+
|
141
|
+
# Resets Env. Load paths (load_paths and load_once_paths) are
|
142
|
+
# not reset unless dependencies==true; in which case Dependencies
|
143
|
+
# are cleared before load paths are cleared. The load paths added
|
144
|
+
# to $LOAD_PATH are not cleared.
|
145
|
+
#
|
146
|
+
# Generally not recommended.
|
147
|
+
def reset
|
148
|
+
unless @config == nil
|
149
|
+
$LOAD_PATH.delete_if {|path| config['load_paths'].include?(path) }
|
150
|
+
|
151
|
+
Dependencies.clear
|
152
|
+
Dependencies.load_paths.delete_if {|path| config['load_paths'].include?(path) }
|
153
|
+
Dependencies.load_once_paths.delete_if {|path| config['load_once_paths'].include?(path) }
|
154
|
+
end
|
155
|
+
|
156
|
+
@config = {}
|
157
|
+
DEFAULT_CONFIG.keys.each do |key|
|
158
|
+
@config[key] = []
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# Logs the action and message at the input level (default INFO).
|
163
|
+
# Logging is suppressed if no logger is set.
|
164
|
+
def log(action, msg="", level=Logger::INFO)
|
165
|
+
logger.add(level, msg, action.to_s) if logger
|
166
|
+
end
|
167
|
+
|
168
|
+
# Configures the specified App using the configurations in config_file.
|
169
|
+
# Loading of environement configurations occcurs via load_env_config;
|
170
|
+
# all environment paths are resolved using the app, after the app has
|
171
|
+
# been configured.
|
172
|
+
|
173
|
+
# Loads environment configurations from the specified path. If a directory
|
174
|
+
# is given as path, then the DEFAULT_CONFIG_FILE relative to that location
|
175
|
+
# will be loaded. The loading cycle recurses as specified by the configurations.
|
176
|
+
#
|
177
|
+
# Configuration paths are expanded relative to the parent directory
|
178
|
+
# of the loaded file. Raises an error if non-env configuration are
|
179
|
+
# found (as determined by Tap::Env::Configurtion::ENV_CONFIG_KEYS).
|
180
|
+
def load_config(path, root=Tap::Root.new, &block)
|
181
|
+
path = File.join(path, DEFAULT_CONFIG_FILE) if File.directory?(path)
|
182
|
+
path = File.expand_path(path)
|
183
|
+
|
184
|
+
# prevent infinite looping
|
185
|
+
config_paths = config['config_paths']
|
186
|
+
return false if config_paths.include?(path)
|
187
|
+
|
188
|
+
# load config
|
189
|
+
log(:load_config, path, Logger::DEBUG)
|
190
|
+
config_paths << path
|
191
|
+
|
192
|
+
config = read_config(path)
|
193
|
+
config['root'] = File.dirname(path) unless config['root']
|
194
|
+
|
195
|
+
configure(config, root) do |configured_root, other_configs|
|
196
|
+
if block_given?
|
197
|
+
yield(configured_root, path, other_configs)
|
198
|
+
else
|
199
|
+
log(:warn, "ignoring configs: #{path} (#{other_configs.keys.join(',')})", Logger::WARN)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
204
|
+
|
205
|
+
def configure(config, root=Tap::Root.new, &block)
|
206
|
+
root_configs, env_configs, other_configs = partition_configs(config, ['root', 'directories', 'absolute_paths'], DEFAULT_CONFIG.keys)
|
207
|
+
env_configs = join_configs(DEFAULT_CONFIG, env_configs)
|
208
|
+
|
209
|
+
# assign root configs
|
210
|
+
root.send(:assign_paths,
|
211
|
+
root_configs['root'] || root.root,
|
212
|
+
root_configs['directories'] || root.directories,
|
213
|
+
root_configs['absolute_paths'] || root.absolute_paths)
|
214
|
+
|
215
|
+
# handle unknown configs (handle before setting
|
216
|
+
# env configs in case the configs modify root)
|
217
|
+
unless other_configs.empty?
|
218
|
+
if block_given?
|
219
|
+
yield(root, other_configs)
|
220
|
+
else
|
221
|
+
log(:warn, "ignoring configs: (#{other_configs.keys.join(',')})", Logger::WARN)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
# load gems and configurations
|
226
|
+
gem_paths = env_configs.delete('gems').collect do |gem_name|
|
227
|
+
full_gem_path(gem_name)
|
228
|
+
end
|
229
|
+
config_paths = env_configs.delete('config_paths') + gem_paths
|
230
|
+
config_paths.each {|path| load_config(root[path], &block) }
|
231
|
+
|
232
|
+
# assign env configs
|
233
|
+
env_configs.each_pair do |key, value|
|
234
|
+
case key
|
235
|
+
when 'load_paths'
|
236
|
+
assign_paths(root, value, self.config[key], $LOAD_PATH, Dependencies.load_paths)
|
237
|
+
when 'load_once_paths'
|
238
|
+
assign_paths(root, value, self.config[key], Dependencies.load_once_paths)
|
239
|
+
when /_paths$/
|
240
|
+
assign_paths(root, value, self.config[key])
|
241
|
+
else
|
242
|
+
handle_unknown_config(key, value)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
true
|
247
|
+
end
|
248
|
+
|
249
|
+
# Loads env configurations from a gem, specifically from
|
250
|
+
# gemspec.full_gem_path. A gem version can be specified
|
251
|
+
# in the name, like 'gem >= 1.2'.
|
252
|
+
def full_gem_path(gem_name)
|
253
|
+
# figure the version of the gem, by default >= 0.0.0
|
254
|
+
gem_name =~ /^([^<=>]*)(.*)$/
|
255
|
+
name, version = $1, $2
|
256
|
+
version = ">= 0.0.0" if version.empty?
|
257
|
+
|
258
|
+
# load the gem and get the spec
|
259
|
+
gem(name, version)
|
260
|
+
spec = Gem.loaded_specs[name]
|
261
|
+
|
262
|
+
if spec == nil
|
263
|
+
log(:warn, "unknown gem: #{gem_name}", Logger::WARN)
|
264
|
+
end
|
265
|
+
|
266
|
+
spec.full_gem_path
|
267
|
+
end
|
268
|
+
|
269
|
+
def load_gem(gem_name)
|
270
|
+
load_config(full_gem_path(gem_name))
|
271
|
+
end
|
272
|
+
|
273
|
+
# Searches for and returns all .rb files under each of the command_paths
|
274
|
+
# as well as the default tap commands. Commands with conflicting names
|
275
|
+
# raise an error; however, user commands are allowed to override the
|
276
|
+
# default tap commands and will NOT raise an error.
|
277
|
+
def commands
|
278
|
+
commands = {}
|
279
|
+
config['command_paths'].each do |path|
|
280
|
+
pattern = File.join(path, "**/*.rb")
|
281
|
+
|
282
|
+
Dir.glob(pattern).each do |file|
|
283
|
+
cmd = Tap::App.relative_filepath(path, file).chomp(".rb")
|
284
|
+
raise "command name confict: #{cmd}" if commands.include?(cmd)
|
285
|
+
commands[cmd] = file
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
# allow all other scripts to override default scripts
|
290
|
+
# (hence do this second)
|
291
|
+
tap_command_dir = File.expand_path(File.join( File.dirname(__FILE__), "cmd"))
|
292
|
+
Dir.glob( tap_command_dir + "/**/*.rb" ).each do |file|
|
293
|
+
cmd = Tap::App.relative_filepath(tap_command_dir, file).chomp(".rb")
|
294
|
+
commands[cmd] = file unless commands.include?(cmd)
|
295
|
+
end
|
296
|
+
|
297
|
+
commands
|
298
|
+
end
|
299
|
+
|
300
|
+
protected
|
301
|
+
|
302
|
+
def assign_paths(root, paths, *targets)
|
303
|
+
paths = paths.collect {|path| root[path]}
|
304
|
+
targets.each do |array|
|
305
|
+
paths.reverse_each do |path|
|
306
|
+
array.unshift(path)
|
307
|
+
end
|
308
|
+
array.uniq!
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
def handle_unknown_config(key, value)
|
313
|
+
raise "unknown env config: #{key}"
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|