scout-essentials 1.0.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.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.vimproject +78 -0
- data/Gemfile +14 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +18 -0
- data/Rakefile +47 -0
- data/VERSION +1 -0
- data/lib/scout/cmd.rb +348 -0
- data/lib/scout/concurrent_stream.rb +284 -0
- data/lib/scout/config.rb +168 -0
- data/lib/scout/exceptions.rb +77 -0
- data/lib/scout/indiferent_hash/case_insensitive.rb +30 -0
- data/lib/scout/indiferent_hash/options.rb +115 -0
- data/lib/scout/indiferent_hash.rb +96 -0
- data/lib/scout/log/color.rb +224 -0
- data/lib/scout/log/color_class.rb +269 -0
- data/lib/scout/log/fingerprint.rb +69 -0
- data/lib/scout/log/progress/report.rb +244 -0
- data/lib/scout/log/progress/util.rb +173 -0
- data/lib/scout/log/progress.rb +106 -0
- data/lib/scout/log/trap.rb +107 -0
- data/lib/scout/log.rb +441 -0
- data/lib/scout/meta_extension.rb +100 -0
- data/lib/scout/misc/digest.rb +63 -0
- data/lib/scout/misc/filesystem.rb +25 -0
- data/lib/scout/misc/format.rb +255 -0
- data/lib/scout/misc/helper.rb +31 -0
- data/lib/scout/misc/insist.rb +56 -0
- data/lib/scout/misc/monitor.rb +66 -0
- data/lib/scout/misc/system.rb +73 -0
- data/lib/scout/misc.rb +10 -0
- data/lib/scout/named_array.rb +138 -0
- data/lib/scout/open/lock/lockfile.rb +587 -0
- data/lib/scout/open/lock.rb +68 -0
- data/lib/scout/open/remote.rb +135 -0
- data/lib/scout/open/stream.rb +491 -0
- data/lib/scout/open/util.rb +244 -0
- data/lib/scout/open.rb +170 -0
- data/lib/scout/path/find.rb +204 -0
- data/lib/scout/path/tmpfile.rb +8 -0
- data/lib/scout/path/util.rb +127 -0
- data/lib/scout/path.rb +51 -0
- data/lib/scout/persist/open.rb +17 -0
- data/lib/scout/persist/path.rb +15 -0
- data/lib/scout/persist/serialize.rb +157 -0
- data/lib/scout/persist.rb +104 -0
- data/lib/scout/resource/open.rb +8 -0
- data/lib/scout/resource/path.rb +80 -0
- data/lib/scout/resource/produce/rake.rb +69 -0
- data/lib/scout/resource/produce.rb +151 -0
- data/lib/scout/resource/scout.rb +3 -0
- data/lib/scout/resource/software.rb +178 -0
- data/lib/scout/resource/util.rb +59 -0
- data/lib/scout/resource.rb +40 -0
- data/lib/scout/simple_opt/accessor.rb +54 -0
- data/lib/scout/simple_opt/doc.rb +126 -0
- data/lib/scout/simple_opt/get.rb +57 -0
- data/lib/scout/simple_opt/parse.rb +67 -0
- data/lib/scout/simple_opt/setup.rb +26 -0
- data/lib/scout/simple_opt.rb +5 -0
- data/lib/scout/tmpfile.rb +129 -0
- data/lib/scout-essentials.rb +10 -0
- data/scout-essentials.gemspec +143 -0
- data/share/color/color_names +507 -0
- data/share/color/diverging_colors.hex +12 -0
- data/share/software/install_helpers +523 -0
- data/test/scout/indiferent_hash/test_case_insensitive.rb +16 -0
- data/test/scout/indiferent_hash/test_options.rb +46 -0
- data/test/scout/log/test_color.rb +0 -0
- data/test/scout/log/test_progress.rb +108 -0
- data/test/scout/misc/test_digest.rb +30 -0
- data/test/scout/misc/test_filesystem.rb +30 -0
- data/test/scout/misc/test_insist.rb +13 -0
- data/test/scout/misc/test_system.rb +21 -0
- data/test/scout/open/test_lock.rb +52 -0
- data/test/scout/open/test_remote.rb +25 -0
- data/test/scout/open/test_stream.rb +676 -0
- data/test/scout/open/test_util.rb +73 -0
- data/test/scout/path/test_find.rb +110 -0
- data/test/scout/path/test_util.rb +22 -0
- data/test/scout/persist/test_open.rb +37 -0
- data/test/scout/persist/test_path.rb +37 -0
- data/test/scout/persist/test_serialize.rb +114 -0
- data/test/scout/resource/test_path.rb +58 -0
- data/test/scout/resource/test_produce.rb +94 -0
- data/test/scout/resource/test_software.rb +24 -0
- data/test/scout/resource/test_util.rb +38 -0
- data/test/scout/simple_opt/test_doc.rb +16 -0
- data/test/scout/simple_opt/test_get.rb +11 -0
- data/test/scout/simple_opt/test_parse.rb +10 -0
- data/test/scout/simple_opt/test_setup.rb +77 -0
- data/test/scout/test_cmd.rb +85 -0
- data/test/scout/test_concurrent_stream.rb +29 -0
- data/test/scout/test_config.rb +66 -0
- data/test/scout/test_indiferent_hash.rb +26 -0
- data/test/scout/test_log.rb +32 -0
- data/test/scout/test_meta_extension.rb +80 -0
- data/test/scout/test_misc.rb +6 -0
- data/test/scout/test_named_array.rb +43 -0
- data/test/scout/test_open.rb +146 -0
- data/test/scout/test_path.rb +54 -0
- data/test/scout/test_persist.rb +186 -0
- data/test/scout/test_resource.rb +26 -0
- data/test/scout/test_tmpfile.rb +53 -0
- data/test/test_helper.rb +50 -0
- metadata +247 -0
@@ -0,0 +1,151 @@
|
|
1
|
+
require_relative '../open'
|
2
|
+
require_relative '../tmpfile'
|
3
|
+
require_relative 'produce/rake'
|
4
|
+
|
5
|
+
module Resource
|
6
|
+
def claim(path, type, content = nil, &block)
|
7
|
+
if type == :rake
|
8
|
+
@rake_dirs ||= {}
|
9
|
+
@rake_dirs[path] = content || block
|
10
|
+
else
|
11
|
+
@resources ||= {}
|
12
|
+
@resources[path] = [type, content || block]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def rake_for(path)
|
17
|
+
@rake_dirs ||= {}
|
18
|
+
@rake_dirs.select{|dir, content|
|
19
|
+
Misc.path_relative_to(dir, path)
|
20
|
+
}.sort_by{|dir, content|
|
21
|
+
dir.length
|
22
|
+
}.last
|
23
|
+
end
|
24
|
+
|
25
|
+
def has_rake(path)
|
26
|
+
!! rake_for(path)
|
27
|
+
end
|
28
|
+
|
29
|
+
def run_rake(path, rakefile, rake_dir)
|
30
|
+
task = Misc.path_relative_to rake_dir, path
|
31
|
+
rakefile = rakefile.produce if rakefile.respond_to? :produce
|
32
|
+
rakefile = rakefile.find if rakefile.respond_to? :find
|
33
|
+
|
34
|
+
rake_dir = rake_dir.find(:user) if rake_dir.respond_to? :find
|
35
|
+
|
36
|
+
begin
|
37
|
+
if Proc === rakefile
|
38
|
+
ScoutRake.run(nil, rake_dir, task, &rakefile)
|
39
|
+
else
|
40
|
+
ScoutRake.run(rakefile, rake_dir, task)
|
41
|
+
end
|
42
|
+
rescue ScoutRake::TaskNotFound
|
43
|
+
if rake_dir.nil? or rake_dir.empty? or rake_dir == "/" or rake_dir == "./"
|
44
|
+
raise $!
|
45
|
+
end
|
46
|
+
task = File.join(File.basename(rake_dir), task)
|
47
|
+
rake_dir = File.dirname(rake_dir)
|
48
|
+
retry
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def produce(path, force = false)
|
53
|
+
case
|
54
|
+
when (@resources && @resources.include?(path))
|
55
|
+
type, content = @resources[path]
|
56
|
+
when (Path === path && @resources && @resources.include?(path.original))
|
57
|
+
type, content = @resources[path.original]
|
58
|
+
when has_rake(path)
|
59
|
+
type = :rake
|
60
|
+
rake_dir, content = rake_for(path)
|
61
|
+
rake_dir = Path.setup(rake_dir.dup, self.pkgdir, self)
|
62
|
+
else
|
63
|
+
if path !~ /\.(gz|bgz)$/
|
64
|
+
begin
|
65
|
+
produce(path.annotate(path + '.gz'), force)
|
66
|
+
rescue ResourceNotFound
|
67
|
+
begin
|
68
|
+
produce(path.annotate(path + '.bgz'), force)
|
69
|
+
rescue ResourceNotFound
|
70
|
+
raise ResourceNotFound, "Resource is missing and does not seem to be claimed: #{ self } -- #{ path } "
|
71
|
+
end
|
72
|
+
end
|
73
|
+
else
|
74
|
+
raise ResourceNotFound, "Resource is missing and does not seem to be claimed: #{ self } -- #{ path } "
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
if path.respond_to?(:find)
|
79
|
+
final_path = force ? path.find(:default) : path.find
|
80
|
+
else
|
81
|
+
final_path = path
|
82
|
+
end
|
83
|
+
|
84
|
+
if type and not File.exist?(final_path) or force
|
85
|
+
Log.medium "Producing: (#{self.to_s}) #{ final_path }"
|
86
|
+
lock_filename = TmpFile.tmp_for_file(final_path, :dir => lock_dir)
|
87
|
+
|
88
|
+
Open.lock lock_filename do
|
89
|
+
FileUtils.rm_rf final_path if force and File.exist? final_path
|
90
|
+
|
91
|
+
if ! File.exist?(final_path) || force
|
92
|
+
|
93
|
+
begin
|
94
|
+
case type
|
95
|
+
when :string
|
96
|
+
Open.sensible_write(final_path, content)
|
97
|
+
when :csv
|
98
|
+
raise "TSV/CSV Not implemented yet"
|
99
|
+
#require 'rbbt/tsv/csv'
|
100
|
+
#tsv = TSV.csv Open.open(content)
|
101
|
+
#Open.sensible_write(final_path, tsv.to_s)
|
102
|
+
when :url
|
103
|
+
options = {}
|
104
|
+
options[:noz] = true if Open.gzip?(final_path) || Open.bgzip?(final_path) || Open.zip?(final_path)
|
105
|
+
Open.sensible_write(final_path, Open.open(content, options))
|
106
|
+
when :proc
|
107
|
+
data = case content.arity
|
108
|
+
when 0
|
109
|
+
content.call
|
110
|
+
when 1
|
111
|
+
content.call final_path
|
112
|
+
end
|
113
|
+
case data
|
114
|
+
when String, IO, StringIO
|
115
|
+
Open.sensible_write(final_path, data)
|
116
|
+
when Array
|
117
|
+
Open.sensible_write(final_path, data * "\n")
|
118
|
+
when TSV
|
119
|
+
Open.sensible_write(final_path, data.dumper_stream)
|
120
|
+
when TSV::Dumper
|
121
|
+
Open.sensible_write(final_path, data.stream)
|
122
|
+
when nil
|
123
|
+
else
|
124
|
+
raise "Unkown object produced: #{Log.fingerprint data}"
|
125
|
+
end
|
126
|
+
when :rake
|
127
|
+
run_rake(path, content, rake_dir)
|
128
|
+
when :install
|
129
|
+
software_dir = self.root.software
|
130
|
+
name = File.basename(path)
|
131
|
+
Resource.install(content, name, software_dir)
|
132
|
+
set_software_env(software_dir)
|
133
|
+
else
|
134
|
+
raise "Could not produce #{ resource }. (#{ type }, #{ content })"
|
135
|
+
end
|
136
|
+
rescue
|
137
|
+
FileUtils.rm_rf final_path if File.exist? final_path
|
138
|
+
raise $!
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# After producing a file, make sure we recheck all locations, the file
|
145
|
+
# might have appeared with '.gz' extension for instance
|
146
|
+
path.instance_variable_set("@path", {})
|
147
|
+
|
148
|
+
path
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
module Resource
|
2
|
+
|
3
|
+
def self.install_helpers
|
4
|
+
File.expand_path(Scout.share.software.install_helpers.find(:lib))
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.install(content, name, software_dir = Path.setup('software'), &block)
|
8
|
+
software_dir ||= Path.setup('software')
|
9
|
+
software_dir = software_dir.find(:user) if Path === software_dir
|
10
|
+
|
11
|
+
content = block if block_given?
|
12
|
+
|
13
|
+
preamble = <<-EOF
|
14
|
+
#!/bin/bash
|
15
|
+
|
16
|
+
SOFTWARE_DIR="#{software_dir}"
|
17
|
+
|
18
|
+
INSTALL_HELPER_FILE="#{install_helpers}"
|
19
|
+
source "$INSTALL_HELPER_FILE"
|
20
|
+
EOF
|
21
|
+
|
22
|
+
content = content.call if Proc === content
|
23
|
+
|
24
|
+
name = content[:name] if Hash === content && content.include?(:name)
|
25
|
+
content =
|
26
|
+
if content =~ /git:|\.git$/
|
27
|
+
{:git => content}
|
28
|
+
else
|
29
|
+
{:src => content}
|
30
|
+
end if String === content and Open.remote?(content)
|
31
|
+
|
32
|
+
script_text =
|
33
|
+
case content
|
34
|
+
when nil
|
35
|
+
raise "No way to install #{name}"
|
36
|
+
when Path
|
37
|
+
Open.read(content)
|
38
|
+
when String
|
39
|
+
if Path.is_filename?(content) and Open.exists?(content)
|
40
|
+
Open.read(content)
|
41
|
+
else
|
42
|
+
content
|
43
|
+
end
|
44
|
+
when Hash
|
45
|
+
name = content[:name] || name
|
46
|
+
git = content[:git]
|
47
|
+
src = content[:src]
|
48
|
+
url = content[:url]
|
49
|
+
jar = content[:jar]
|
50
|
+
extra = content[:extra]
|
51
|
+
commands = content[:commands]
|
52
|
+
if git
|
53
|
+
<<-EOF
|
54
|
+
|
55
|
+
name='#{name}'
|
56
|
+
url='#{git}'
|
57
|
+
|
58
|
+
install_git "$name" "$url" #{extra}
|
59
|
+
|
60
|
+
#{commands}
|
61
|
+
EOF
|
62
|
+
elsif src
|
63
|
+
<<-EOF
|
64
|
+
|
65
|
+
name='#{name}'
|
66
|
+
url='#{src}'
|
67
|
+
|
68
|
+
install_src "$name" "$url" #{extra}
|
69
|
+
|
70
|
+
#{commands}
|
71
|
+
EOF
|
72
|
+
elsif jar
|
73
|
+
<<-EOF
|
74
|
+
|
75
|
+
name='#{name}'
|
76
|
+
url='#{jar}'
|
77
|
+
|
78
|
+
install_jar "$name" "$url" #{extra}
|
79
|
+
|
80
|
+
#{commands}
|
81
|
+
EOF
|
82
|
+
else
|
83
|
+
<<-EOF
|
84
|
+
|
85
|
+
name='#{name}'
|
86
|
+
url='#{url}'
|
87
|
+
|
88
|
+
#{commands}
|
89
|
+
EOF
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
script = preamble + "\n" + script_text
|
94
|
+
Log.debug "Installing software #{name} into #{software_dir} with script:\n" << script
|
95
|
+
CMD.cmd_log('bash', :in => script)
|
96
|
+
Resource.set_software_env(software_dir)
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.set_software_env(software_dir = Path.setup('software'))
|
100
|
+
software_dir.opt.find_all.collect{|d| d.annotate(File.dirname(d)) }.reverse.each do |software_dir|
|
101
|
+
next unless software_dir.exists?
|
102
|
+
Log.medium "Preparing software env at #{software_dir}"
|
103
|
+
|
104
|
+
software_dir = File.expand_path(software_dir)
|
105
|
+
opt_dir = File.join(software_dir, 'opt')
|
106
|
+
bin_dir = File.join(opt_dir, 'bin')
|
107
|
+
|
108
|
+
Misc.env_add 'PATH', bin_dir
|
109
|
+
|
110
|
+
FileUtils.mkdir_p opt_dir unless File.exist? opt_dir
|
111
|
+
|
112
|
+
%w(.ld-paths .c-paths .pkgconfig-paths .aclocal-paths .java-classpaths).each do |file|
|
113
|
+
filename = File.join(opt_dir, file)
|
114
|
+
begin
|
115
|
+
FileUtils.touch filename unless File.exist? filename
|
116
|
+
rescue
|
117
|
+
Log.warn("Could not touch #{ filename }")
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
Open.read(File.join opt_dir, '.c-paths').split(/\n/).each do |line|
|
122
|
+
dir = line.chomp
|
123
|
+
dir = File.join(opt_dir, dir) unless dir[0] == "/"
|
124
|
+
Misc.env_add('CPLUS_INCLUDE_PATH',dir)
|
125
|
+
Misc.env_add('C_INCLUDE_PATH',dir)
|
126
|
+
end if File.exist? File.join(opt_dir, '.c-paths')
|
127
|
+
|
128
|
+
Open.read(File.join opt_dir, '.ld-paths').split(/\n/).each do |line|
|
129
|
+
dir = line.chomp
|
130
|
+
dir = File.join(opt_dir, dir) unless dir[0] == "/"
|
131
|
+
Misc.env_add('LIBRARY_PATH',dir)
|
132
|
+
Misc.env_add('LD_LIBRARY_PATH',dir)
|
133
|
+
Misc.env_add('LD_RUN_PATH',dir)
|
134
|
+
end if File.exist? File.join(opt_dir, '.ld-paths')
|
135
|
+
|
136
|
+
Open.read(File.join opt_dir, '.pkgconfig-paths').split(/\n/).each do |line|
|
137
|
+
dir = line.chomp
|
138
|
+
dir = File.join(opt_dir, dir) unless dir[0] == "/"
|
139
|
+
Misc.env_add('PKG_CONFIG_PATH',dir)
|
140
|
+
end if File.exist? File.join(opt_dir, '.pkgconfig-paths')
|
141
|
+
|
142
|
+
Open.read(File.join opt_dir, '.aclocal-paths').split(/\n/).each do |line|
|
143
|
+
dir = line.chomp
|
144
|
+
dir = File.join(opt_dir, dir) unless dir[0] == "/"
|
145
|
+
Misc.env_add('ACLOCAL_FLAGS', "-I #{dir}", ' ')
|
146
|
+
end if File.exist? File.join(opt_dir, '.aclocal-paths')
|
147
|
+
|
148
|
+
Open.read(File.join opt_dir, '.java-classpaths').split(/\n/).each do |line|
|
149
|
+
dir = line.chomp
|
150
|
+
dir = File.join(opt_dir, dir) unless dir[0] == "/"
|
151
|
+
Misc.env_add('CLASSPATH', "#{dir}")
|
152
|
+
end if File.exist? File.join(opt_dir, '.java-classpaths')
|
153
|
+
|
154
|
+
Dir.glob(File.join opt_dir, 'jars', '*.jar').each do |file|
|
155
|
+
Misc.env_add('CLASSPATH', "#{file}")
|
156
|
+
end
|
157
|
+
|
158
|
+
if File.exist?(File.join(opt_dir, '.post_install')) and File.directory?(File.join(opt_dir, '.post_install'))
|
159
|
+
Dir.glob(File.join(opt_dir, '.post_install','*')).each do |file|
|
160
|
+
|
161
|
+
# Load exports
|
162
|
+
Open.read(file).split("\n").each do |line|
|
163
|
+
next unless line =~ /^\s*export\s+([^=]+)=(.*)/
|
164
|
+
var = $1.strip
|
165
|
+
value = $2.strip
|
166
|
+
value.sub!(/^['"]/,'')
|
167
|
+
value.sub!(/['"]$/,'')
|
168
|
+
value.gsub!(/\$[a-z_0-9]+/i){|var| ENV[var[1..-1]] }
|
169
|
+
Log.debug "Set variable export from .post_install: #{Log.fingerprint [var,value]*"="}"
|
170
|
+
ENV[var] = value
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
self.set_software_env
|
178
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Resource
|
2
|
+
def identify(path)
|
3
|
+
return path unless path.start_with?("/")
|
4
|
+
path_maps = path.path_maps if Path === path
|
5
|
+
path_maps ||= self.path_maps || Path.path_maps
|
6
|
+
path = File.expand_path(path)
|
7
|
+
path += "/" if File.directory?(path)
|
8
|
+
|
9
|
+
map_order ||= (path_maps.keys & Path.basic_map_order) + (path_maps.keys - Path.basic_map_order)
|
10
|
+
map_order -= [:current, "current"]
|
11
|
+
|
12
|
+
choices = []
|
13
|
+
map_order.uniq.each do |name|
|
14
|
+
pattern = path_maps[name]
|
15
|
+
pattern = path_maps[pattern] while Symbol === pattern
|
16
|
+
next if pattern.nil?
|
17
|
+
|
18
|
+
pattern = pattern.sub('{PWD}', Dir.pwd)
|
19
|
+
pattern = pattern.sub('{HOME}', ENV["HOME"])
|
20
|
+
if String === pattern and pattern.include?('{')
|
21
|
+
regexp = "^" + pattern
|
22
|
+
.gsub(/{(TOPLEVEL)}/,'(?<\1>[^/]+)')
|
23
|
+
.gsub(/{([^}]+)}/,'(?<\1>[^/]+)?') +
|
24
|
+
"(?:/(?<REST>.*))?/?$"
|
25
|
+
if m = path.match(regexp)
|
26
|
+
if ! m.named_captures.include?("PKGDIR") || m["PKGDIR"] == self.pkgdir
|
27
|
+
unlocated = %w(TOPLEVEL SUBPATH PATH REST).collect{|c|
|
28
|
+
m.named_captures.include?(c) ? m[c] : nil
|
29
|
+
}.compact * "/"
|
30
|
+
unlocated.gsub!(/\/+/,'/')
|
31
|
+
if self.subdir && ! self.subdir.empty?
|
32
|
+
subdir = self.subdir
|
33
|
+
subdir += "/" unless subdir.end_with?("/")
|
34
|
+
unlocated[subdir] = ""
|
35
|
+
end
|
36
|
+
choices << self.annotate(unlocated)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
identified = choices.sort_by{|s| s.length }.first
|
43
|
+
|
44
|
+
Path.setup(identified || path, self, nil, path_maps)
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.identify(path)
|
48
|
+
resource = path.pkgdir if Path === path
|
49
|
+
resource = Scout unless Resource === resource
|
50
|
+
unlocated = resource.identify path
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.relocate(path)
|
54
|
+
return path if Open.exists?(path)
|
55
|
+
unlocated = identify(path)
|
56
|
+
unlocated.find
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require_relative 'log'
|
2
|
+
require_relative 'path'
|
3
|
+
require_relative 'resource/produce'
|
4
|
+
require_relative 'resource/path'
|
5
|
+
require_relative 'resource/open'
|
6
|
+
require_relative 'resource/util'
|
7
|
+
require_relative 'resource/software'
|
8
|
+
|
9
|
+
module Resource
|
10
|
+
extend MetaExtension
|
11
|
+
extension_attr :pkgdir, :libdir, :subdir, :resources, :rake_dirs, :path_maps, :lock_dir
|
12
|
+
|
13
|
+
def self.default_lock_dir
|
14
|
+
Path.setup('tmp/produce_locks').find
|
15
|
+
end
|
16
|
+
|
17
|
+
def subdir
|
18
|
+
@subdir ||= ""
|
19
|
+
end
|
20
|
+
|
21
|
+
def lock_dir
|
22
|
+
@lock_dir ||= Resource.default_lock_dir
|
23
|
+
end
|
24
|
+
|
25
|
+
def pkgdir
|
26
|
+
@pkgdir ||= Path.default_pkgdir
|
27
|
+
end
|
28
|
+
|
29
|
+
def root
|
30
|
+
Path.setup(subdir, self, self.libdir, @path_maps)
|
31
|
+
end
|
32
|
+
|
33
|
+
def method_missing(name, prev = nil, *args)
|
34
|
+
if prev.nil?
|
35
|
+
root.send(name, *args)
|
36
|
+
else
|
37
|
+
root.send(name, prev, *args)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module SOPT
|
2
|
+
class << self
|
3
|
+
attr_writer :inputs, :input_shortcuts, :input_types, :input_descriptions, :input_defaults
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.all
|
7
|
+
@all ||= {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.shortcuts
|
11
|
+
@shortcuts ||= {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.inputs
|
15
|
+
@inputs ||= []
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.input_shortcuts
|
19
|
+
@input_shortcuts ||= {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.input_types
|
23
|
+
@input_types ||= {}
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.input_descriptions
|
27
|
+
@input_descriptions ||= {}
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.input_defaults
|
31
|
+
@input_defaults ||= {}
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.reset
|
35
|
+
@shortcuts = {}
|
36
|
+
@all = {}
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.delete_inputs(inputs)
|
40
|
+
inputs.each do |input|
|
41
|
+
input = input.to_s
|
42
|
+
self.shortcuts.delete self.input_shortcuts.delete(input)
|
43
|
+
self.inputs.delete input
|
44
|
+
self.input_types.delete input
|
45
|
+
self.input_defaults.delete input
|
46
|
+
self.input_descriptions.delete input
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.usage
|
51
|
+
puts SOPT.doc
|
52
|
+
exit 0
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require_relative '../log'
|
2
|
+
module SOPT
|
3
|
+
|
4
|
+
class << self
|
5
|
+
attr_writer :command, :summary, :synopsys, :description
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.command
|
9
|
+
@command ||= File.basename($0)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.summary
|
13
|
+
@summary ||= ""
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.synopsys
|
17
|
+
@synopsys ||= begin
|
18
|
+
"#{command} " <<
|
19
|
+
inputs.collect{|name|
|
20
|
+
"[" << input_format(name, input_types[name] || :string, input_defaults[name], input_shortcuts[name]).sub(/:$/,'') << "]"
|
21
|
+
} * " "
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.description
|
26
|
+
@description ||= "Missing"
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.input_format(name, type = nil, default = nil, short = nil)
|
30
|
+
input_str = (short.nil? or short.empty?) ? "--#{name}" : "-#{short},--#{name}"
|
31
|
+
input_str = Log.color(:blue, input_str)
|
32
|
+
extra = case type
|
33
|
+
when nil
|
34
|
+
""
|
35
|
+
when :boolean
|
36
|
+
"[=false]"
|
37
|
+
when :tsv, :text
|
38
|
+
"=<file|->"
|
39
|
+
when :array
|
40
|
+
"=<list|file|->"
|
41
|
+
else
|
42
|
+
"=<#{ type }>"
|
43
|
+
end
|
44
|
+
#extra << " (default: #{Array === default ? (default.length > 3 ? default[0..2]*", " + ', ...' : default*", " ): default})" if default != nil
|
45
|
+
extra << " (default: #{Log.fingerprint(default)})" if default != nil
|
46
|
+
input_str << Log.color(:green, extra)
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.input_array_doc(input_array)
|
50
|
+
input_array.collect do |name,type,description,default,options|
|
51
|
+
type = :string if type.nil?
|
52
|
+
|
53
|
+
name = name.to_s
|
54
|
+
shortcut, options = options, nil if String === options || Symbol === options
|
55
|
+
|
56
|
+
case options && options[:shortcut]
|
57
|
+
when FalseClass
|
58
|
+
shortcut = nil
|
59
|
+
when TrueClass, nil
|
60
|
+
shortcut = fix_shortcut(name[0], name)
|
61
|
+
else
|
62
|
+
shortcut = options[:shortcut]
|
63
|
+
end unless shortcut
|
64
|
+
|
65
|
+
shortcut = fix_shortcut(shortcut, name)
|
66
|
+
register(shortcut, name, type, description) unless self.inputs.include? name
|
67
|
+
name = SOPT.input_format(name, type.to_sym, default, shortcut )
|
68
|
+
Misc.format_definition_list_item(name, description)
|
69
|
+
end * "\n"
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.input_doc(inputs, input_types = nil, input_descriptions = nil, input_defaults = nil, input_shortcuts = nil)
|
73
|
+
type = description = default = nil
|
74
|
+
shortcut = ""
|
75
|
+
seen = []
|
76
|
+
inputs.collect do |name|
|
77
|
+
next if seen.include? name
|
78
|
+
seen << name
|
79
|
+
|
80
|
+
type = input_types[name] unless input_types.nil?
|
81
|
+
description = input_descriptions[name] unless input_descriptions.nil?
|
82
|
+
default = input_defaults[name] unless input_defaults.nil?
|
83
|
+
|
84
|
+
name = name.to_s
|
85
|
+
|
86
|
+
case input_shortcuts
|
87
|
+
when nil, FalseClass
|
88
|
+
shortcut = nil
|
89
|
+
when Hash
|
90
|
+
shortcut = input_shortcuts[name]
|
91
|
+
when TrueClass
|
92
|
+
shortcut = fix_shortcut(name[0], name)
|
93
|
+
end
|
94
|
+
|
95
|
+
type = :string if type.nil?
|
96
|
+
register(shortcut, name, type, description) unless self.inputs.include? name
|
97
|
+
|
98
|
+
name = SOPT.input_format(name, type.to_sym, default, shortcut)
|
99
|
+
Misc.format_definition_list_item(name, description)
|
100
|
+
end * "\n"
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
def self.doc
|
105
|
+
doc =<<-EOF
|
106
|
+
#{Log.color :magenta}#{command}(1) -- #{summary}
|
107
|
+
#{"=" * (command.length + summary.length + 7)}#{Log.color :reset}
|
108
|
+
|
109
|
+
EOF
|
110
|
+
|
111
|
+
if synopsys and not synopsys.empty?
|
112
|
+
doc << Log.color(:magenta, "## SYNOPSYS") << "\n\n"
|
113
|
+
doc << Log.color(:blue, synopsys) << "\n\n"
|
114
|
+
end
|
115
|
+
|
116
|
+
if description and not description.empty?
|
117
|
+
doc << Log.color(:magenta, "## DESCRIPTION") << "\n\n"
|
118
|
+
doc << Misc.format_paragraph(description) << "\n\n"
|
119
|
+
end
|
120
|
+
|
121
|
+
doc << Log.color(:magenta, "## OPTIONS") << "\n\n"
|
122
|
+
doc << input_doc(inputs, input_types, input_descriptions, input_defaults, input_shortcuts)
|
123
|
+
|
124
|
+
doc
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module SOPT
|
2
|
+
GOT_OPTIONS= IndiferentHash.setup({})
|
3
|
+
def self.current_options=(options)
|
4
|
+
@@current_options = options
|
5
|
+
end
|
6
|
+
def self.consume(args = ARGV)
|
7
|
+
i = 0
|
8
|
+
@@current_options ||= {}
|
9
|
+
while i < args.length do
|
10
|
+
current = args[i]
|
11
|
+
break if current == "--"
|
12
|
+
if m = current.match(/--?(.+?)(?:=(.+))?$/)
|
13
|
+
key = $1
|
14
|
+
value = $2
|
15
|
+
|
16
|
+
input = inputs.include?(key)? key : shortcuts[key]
|
17
|
+
|
18
|
+
if input.nil?
|
19
|
+
i += 1
|
20
|
+
next
|
21
|
+
else
|
22
|
+
args.delete_at i
|
23
|
+
end
|
24
|
+
else
|
25
|
+
i += 1
|
26
|
+
next
|
27
|
+
end
|
28
|
+
|
29
|
+
if input_types[input] == :string
|
30
|
+
value = args.delete_at(i) if value.nil?
|
31
|
+
@@current_options[input] = value
|
32
|
+
else
|
33
|
+
if value.nil? and %w(F false FALSE no).include?(args[i])
|
34
|
+
Log.warn "Boolean values are best specified as #{current}=[true|false], not #{ current } [true|false]. Token '#{args[i]}' following '#{current}' automatically assigned as value"
|
35
|
+
value = args.delete_at(i)
|
36
|
+
end
|
37
|
+
@@current_options[input] = %w(F false FALSE no).include?(value)? false : true
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
IndiferentHash.setup @@current_options
|
42
|
+
GOT_OPTIONS.merge! @@current_options
|
43
|
+
|
44
|
+
@@current_options
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.get(opt_str)
|
48
|
+
SOPT.parse(opt_str)
|
49
|
+
SOPT.consume(ARGV)
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.require(options, *parameters)
|
53
|
+
parameters.flatten.each do |parameter|
|
54
|
+
raise ParameterException, "Parameter '#{ Log.color :blue, parameter }' not given" if options[parameter].nil?
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|