revolt 0.5.3 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +68 -5
- data/bin/rv_delete_levels.rb +121 -0
- data/bin/rv_find_levels.rb +33 -121
- data/bin/rv_info_levels.rb +118 -0
- data/bin/rv_install_level_urls.rb +2 -2
- data/bin/rv_package_levels.rb +112 -0
- data/bin/rv_rename_level.rb +139 -0
- data/lib/revolt/level.rb +45 -30
- data/lib/revolt/levels.rb +89 -12
- data/lib/revolt/package/archive/zip/browser.rb +45 -6
- data/lib/revolt/package/archive.rb +18 -0
- data/lib/revolt/package/exe.rb +13 -3
- data/lib/revolt/package.rb +13 -27
- data/lib/revolt/util/common_cmd_args.rb +44 -0
- data/lib/revolt/util/fs_browser.rb +2 -1
- data/lib/revolt/util/matcher.rb +173 -0
- data/lib/revolt.rb +3 -1
- data/test/tc_archive_analyzer.rb +2 -1
- data/test/tc_args.rb +2 -1
- data/test/tc_args_external.rb +2 -1
- data/test/tc_file_system_fetcher.rb +2 -1
- data/test/tc_info.rb +2 -1
- data/test/tc_level.rb +3 -2
- data/test/tc_level_installer.rb +50 -2
- data/test/tc_level_installer_external.rb +2 -1
- data/test/tc_level_package.rb +235 -0
- data/test/tc_levels.rb +2 -1
- metadata +13 -2
data/README
CHANGED
@@ -13,8 +13,9 @@ track management. This may extend in the future.
|
|
13
13
|
|
14
14
|
Using the library users can easily create automated
|
15
15
|
tasks. Some of the major features are:
|
16
|
-
- Install track packages from WWW server
|
17
|
-
-
|
16
|
+
- Install track packages from WWW server or local file
|
17
|
+
- Create track packages from locally installed tracks
|
18
|
+
- Move, copy, rename and delete tracks
|
18
19
|
- Search tracks with various criteria
|
19
20
|
- Create alternative track repositories
|
20
21
|
|
@@ -129,19 +130,81 @@ you can find tracks by any property defined in the tracks .inf file.
|
|
129
130
|
The easiest way to use it is to just enter the part of the name of
|
130
131
|
the track you want to find. For examples:
|
131
132
|
|
132
|
-
rv_find_levels temple
|
133
|
+
rv_find_levels.rb temple
|
133
134
|
|
134
135
|
That would search for all levels whose name contains 'temple'
|
135
136
|
(case insensitive). Another more complex example is to find
|
136
137
|
all custom tracks that can be raced in reverse mode that
|
137
138
|
have FARCLIP more than 10000:
|
138
139
|
|
139
|
-
rv_find_levels -m 'custom?,reverse?,farclip>10000'
|
140
|
-
|
140
|
+
rv_find_levels.rb -m 'custom?,reverse?,farclip>10000'
|
141
|
+
|
142
|
+
The match rules separated by ',' are AND. To create OR rules
|
143
|
+
you can specify several matching rules. For example to find
|
144
|
+
all tracks that are raceable in reverse or whose name is
|
145
|
+
'RV Temple':
|
146
|
+
|
147
|
+
rv_find_levels.rb -m 'custom?,reverse?' -m 'name=RV Temple'
|
148
|
+
|
141
149
|
Use the -h option to get more help. The output format is:
|
142
150
|
|
143
151
|
<level id> (<level name>) [<matched_attribute>=<matched_value>]
|
144
152
|
|
145
153
|
Trying it in practice should clear the syntax if that seems weird.
|
146
154
|
|
155
|
+
=== rv_info_levels.rb
|
156
|
+
Displays information about levels, such as if it's a custom
|
157
|
+
track, stock track, can be raced in reverse, or is a so called
|
158
|
+
"Full Custom" track. Also the contents INF file can be
|
159
|
+
output. The same match format can be used as for rv_find_levels.rb
|
160
|
+
|
161
|
+
For more information and options:
|
162
|
+
|
163
|
+
rv_info_levels.rb -h
|
164
|
+
|
165
|
+
=== rv_delete_levels.rb
|
166
|
+
Deletes levels. Before deleting confirms by default. Match options format
|
167
|
+
is similar as rv_find_levels.rb
|
168
|
+
|
169
|
+
For more information and options:
|
170
|
+
|
171
|
+
rv_info_levels.rb -h
|
172
|
+
|
173
|
+
|
174
|
+
=== rv_package_levels.rb
|
175
|
+
Creates packages of levels. The parameters are the
|
176
|
+
folder names of the levels to pack. From each level
|
177
|
+
a separate package is created. Matching options can
|
178
|
+
be used with -m as with rv_find_levels.rb
|
179
|
+
|
180
|
+
Example:
|
181
|
+
|
182
|
+
rv_package_levels_level.rb rvt chilled
|
183
|
+
|
184
|
+
This would create rvt.zip and chilled.zip of corresponding
|
185
|
+
levels.
|
186
|
+
|
187
|
+
For more information and options:
|
188
|
+
|
189
|
+
rv_rename_level.rb -h
|
190
|
+
|
191
|
+
=== rv_rename_level.rb
|
192
|
+
Renames a level. Changes the directory name and
|
193
|
+
necessary file names to the one specified. Confirms
|
194
|
+
by default before doing the operation.
|
195
|
+
|
196
|
+
Example:
|
197
|
+
|
198
|
+
rv_rename_level.rb USER678 global_race
|
199
|
+
|
200
|
+
The parameters must be level ids, that is, they are
|
201
|
+
the folder names of the level. The above command
|
202
|
+
would rename USER678 to global_race.
|
203
|
+
|
204
|
+
The matching parameters can be used with -m option
|
205
|
+
for the level to be renamed, but only one level
|
206
|
+
can be matched or error is produced.
|
207
|
+
|
208
|
+
For more information and options:
|
147
209
|
|
210
|
+
rv_rename_level.rb -h
|
@@ -0,0 +1,121 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
#
|
3
|
+
require 'optparse'
|
4
|
+
require 'pp'
|
5
|
+
require 'revolt'
|
6
|
+
require 'set'
|
7
|
+
|
8
|
+
def main
|
9
|
+
del_levs = []
|
10
|
+
cmd = CmdArguments.new(ARGV)
|
11
|
+
ReVolt::Logger.enable if cmd[:debug]
|
12
|
+
levels = ReVolt::Levels.at(cmd[:base])
|
13
|
+
levels.each_level do |level|
|
14
|
+
all_matches = {}
|
15
|
+
nmatches = ReVolt::Util::Matcher.multi(level, cmd[:match], all_matches)
|
16
|
+
if nmatches > 0
|
17
|
+
keyvaluestr = all_matches.map{|(k,v)|"#{k}=#{v}"}.join(', ')
|
18
|
+
del_levs << level
|
19
|
+
puts "%s [%s]" % [level.inspect, keyvaluestr]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
if del_levs.size > 0
|
24
|
+
unless cmd[:force]
|
25
|
+
puts ""
|
26
|
+
print "Delete these levels? (y/N) "
|
27
|
+
answer = STDIN.gets.chomp
|
28
|
+
if answer.downcase != 'y'
|
29
|
+
puts "Deleting not done"
|
30
|
+
exit(0)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
del_levs.each do |l, match|
|
34
|
+
puts "Deleting %s (%s)" % [l.name, l.id.to_s]
|
35
|
+
l.delete
|
36
|
+
end
|
37
|
+
else
|
38
|
+
puts "No matching levels"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
class CmdArguments < Hash
|
44
|
+
include ReVolt::Util::CommonCmdArgs
|
45
|
+
|
46
|
+
def initialize(cmd)
|
47
|
+
super()
|
48
|
+
|
49
|
+
self[:base] = ReVolt::Info::path
|
50
|
+
self[:force] = false
|
51
|
+
|
52
|
+
matchstrs = []
|
53
|
+
opts = OptionParser.new do |opts|
|
54
|
+
opts.banner = "Usage: #$0 [options] [name_match ...]\n"
|
55
|
+
opts.separator ""
|
56
|
+
opts.separator "Deletes levels. By default confirms deletion of matched levels"
|
57
|
+
opts.separator ""
|
58
|
+
opts.separator "Examples:"
|
59
|
+
opts.separator " Deletes for all tracks which name contains temple:"
|
60
|
+
opts.separator " #$0 temple"
|
61
|
+
opts.separator " Deletes tracks which farclip is more than 31000 and startgrid is 3"
|
62
|
+
opts.separator " #$0 -m 'farclip>31000,startgrid=3'"
|
63
|
+
|
64
|
+
opts.separator ""
|
65
|
+
match_help(opts)
|
66
|
+
opts.separator ""
|
67
|
+
|
68
|
+
opts.separator "Options:"
|
69
|
+
|
70
|
+
on_match(opts) do |value|
|
71
|
+
matchstrs << value
|
72
|
+
end
|
73
|
+
opts.on('-d', '--debug',
|
74
|
+
'Outputs debug information') do
|
75
|
+
self[:debug] = true
|
76
|
+
end
|
77
|
+
opts.on('-f', '--force',
|
78
|
+
'Force deletion without confirmation') do
|
79
|
+
self[:force] = true
|
80
|
+
end
|
81
|
+
|
82
|
+
on_base_path(opts) do |value|
|
83
|
+
self[:base] = value
|
84
|
+
end
|
85
|
+
|
86
|
+
opts.on_tail('-h', '--help',
|
87
|
+
'Display full help and exit') do
|
88
|
+
puts opts
|
89
|
+
|
90
|
+
exit(0)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
opts.parse!(cmd)
|
95
|
+
|
96
|
+
cmd.each do |n|
|
97
|
+
matchstrs << '%s=~%s' % ['name', n]
|
98
|
+
end
|
99
|
+
|
100
|
+
# If input file not specified, at least start date is required
|
101
|
+
if matchstrs.size == 0
|
102
|
+
puts "Error: no matches specified\n"
|
103
|
+
STDERR.puts opts.banner
|
104
|
+
exit 1
|
105
|
+
end
|
106
|
+
|
107
|
+
begin
|
108
|
+
# Create the matcher objects
|
109
|
+
self[:match] = []
|
110
|
+
for m in matchstrs
|
111
|
+
self[:match] << ReVolt::Util::Matcher.parse(m)
|
112
|
+
end
|
113
|
+
rescue ReVolt::Util::Matcher::ParseError => e
|
114
|
+
STDERR.puts e.errstr
|
115
|
+
exit(1)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
main
|
data/bin/rv_find_levels.rb
CHANGED
@@ -10,80 +10,26 @@ def main
|
|
10
10
|
ReVolt::Logger.enable if cmd[:debug]
|
11
11
|
levels = ReVolt::Levels.at(cmd[:base])
|
12
12
|
levels.each_level do |level|
|
13
|
-
|
14
|
-
nmatches =
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
# level.inf[key].send(:=~, ''/#{value}/i')) # =~ /#{value}/i
|
19
|
-
matches[op[:name]] = value # level.inf[key]
|
20
|
-
nmatches += 1
|
21
|
-
end
|
22
|
-
end
|
23
|
-
if cmd[:match].size == nmatches
|
24
|
-
keyvaluestr = matches.map{|(k,v)|"#{k}=#{v}"}.join(', ')
|
25
|
-
puts "%s [%s]" % [level.to_s, keyvaluestr]
|
13
|
+
all_matches = {}
|
14
|
+
nmatches = ReVolt::Util::Matcher.multi(level, cmd[:match], all_matches)
|
15
|
+
if nmatches > 0
|
16
|
+
keyvaluestr = all_matches.map{|(k,v)|"#{k}=#{v}"}.join(', ')
|
17
|
+
puts "%s [%s]" % [level.inspect, keyvaluestr]
|
26
18
|
end
|
27
19
|
end
|
28
20
|
end
|
29
21
|
|
30
|
-
def level_cmp_match(op, level)
|
31
|
-
return false if !level || !op
|
32
|
-
args1 = [op[:method]]
|
33
|
-
args2 = [op[:cmp], op[:expect]]
|
34
|
-
obj = level
|
35
|
-
ret_value = true
|
36
|
-
if op[:method] == :inf
|
37
|
-
lvlinfval = level.inf[op[:infkey]]
|
38
|
-
return false if !lvlinfval
|
39
|
-
obj = lvlinfval
|
40
|
-
# op[:method] = [op[:infcmp], op[:infval]]
|
41
|
-
ret_value = lvlinfval
|
42
|
-
|
43
|
-
# Check if comparing to a number (if non digits, not a number)
|
44
|
-
#ReVolt::Logger.debug("Second class: #{s.class} value: #{s}")
|
45
|
-
case
|
46
|
-
when op[:infcmp] == :=~:
|
47
|
-
ReVolt::Logger.debug("Its a regexp")
|
48
|
-
# If a regular expression, do the comparison to reg exp match's return value
|
49
|
-
obj = lvlinfval =~ /#{op[:infval]}/i
|
50
|
-
# If the return value is integer, a match was found
|
51
|
-
args1 = [:is_a?, Integer]
|
52
|
-
when !(op[:infval] =~ /[^\d]/)
|
53
|
-
ReVolt::Logger.debug("Its a number")
|
54
|
-
# If comparing to an integer
|
55
|
-
# Return false unless both comparisons to integer
|
56
|
-
return false if lvlinfval =~ /[^\d]/
|
57
|
-
# Do the comparison as integers
|
58
|
-
obj = lvlinfval.to_i
|
59
|
-
args1 = [op[:infcmp], op[:infval].to_i]
|
60
|
-
else
|
61
|
-
# obj = lvlinfval
|
62
|
-
args1 = [op[:infcmp], op[:infval]]
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
ReVolt::Logger.debug("Sending operation #{args1} to object #{obj.class} with value #{obj}")
|
67
|
-
ReVolt::Logger.debug("Args2: #{args2}") # Sending operation #{args} to object #{obj.class}")
|
68
|
-
# ret = obj.send(infcmp, infval) # *args)
|
69
|
-
# ret = (obj =~ infval)
|
70
|
-
# ReVolt::Logger.debug("Return value: #{ret}, class: #{ret.class}")
|
71
|
-
if (obj.send(*args1)).send(*args2)
|
72
|
-
ReVolt::Logger.debug("Returning value #{ret_value}")
|
73
|
-
return ret_value
|
74
|
-
end
|
75
|
-
nil
|
76
|
-
end
|
77
22
|
|
78
23
|
class CmdArguments < Hash
|
24
|
+
include ReVolt::Util::CommonCmdArgs
|
25
|
+
|
79
26
|
def initialize(cmd)
|
80
27
|
super()
|
81
28
|
|
82
|
-
inf_matches = []
|
83
29
|
self[:base] = ReVolt::Info::path
|
84
|
-
|
30
|
+
matchstrs = []
|
85
31
|
opts = OptionParser.new do |opts|
|
86
|
-
opts.banner = "Usage: #$0 [options] [name_match]\n"
|
32
|
+
opts.banner = "Usage: #$0 [options] [name_match ...]\n"
|
87
33
|
|
88
34
|
opts.separator "Examples:"
|
89
35
|
opts.separator " Searches for all tracks which name contains temple:"
|
@@ -92,92 +38,58 @@ class CmdArguments < Hash
|
|
92
38
|
opts.separator " #$0 -m 'farclip>31000,startgrid=3'"
|
93
39
|
opts.separator " All custom tracks that can be raced in reversed mode"
|
94
40
|
opts.separator " #$0 -m 'reverse?,custom?'"
|
41
|
+
opts.separator " All full custom tracks or custom tracks that can be raced in reverse"
|
42
|
+
opts.separator " #$0 -m 'full_custom?' -m 'reverse?,custom?'"
|
95
43
|
|
96
44
|
opts.separator ""
|
97
|
-
opts
|
98
|
-
opts.separator " <op> in the options can be replaced with:"
|
99
|
-
opts.separator " = equality"
|
100
|
-
opts.separator " < smaller than"
|
101
|
-
opts.separator " > larger than"
|
102
|
-
opts.separator " =~ regular expression match"
|
103
|
-
opts.separator ""
|
104
|
-
opts.separator " The match can include also the following toggles:"
|
105
|
-
opts.separator " reversed?"
|
106
|
-
opts.separator " stock?"
|
107
|
-
opts.separator " custom?"
|
108
|
-
|
45
|
+
match_help(opts)
|
109
46
|
opts.separator ""
|
110
47
|
|
111
48
|
opts.separator "Options:"
|
112
49
|
|
113
|
-
opts
|
114
|
-
|
115
|
-
# 'Match to values in level inf files') do |value|
|
116
|
-
inf_matches = value
|
50
|
+
on_match(opts) do |value|
|
51
|
+
matchstrs << value
|
117
52
|
end
|
53
|
+
|
118
54
|
opts.on('-d', '--debug',
|
119
55
|
'Outputs debug information') do
|
120
56
|
self[:debug] = true
|
121
57
|
end
|
122
|
-
|
123
|
-
|
58
|
+
|
59
|
+
on_base_path(opts) do |value|
|
124
60
|
self[:base] = value
|
125
61
|
end
|
126
62
|
|
127
63
|
opts.on_tail('-h', '--help',
|
128
|
-
'Display
|
64
|
+
'Display full help and exit') do
|
129
65
|
puts opts
|
130
|
-
|
66
|
+
|
67
|
+
exit(0)
|
131
68
|
end
|
132
69
|
end
|
133
70
|
|
134
71
|
opts.parse!(cmd)
|
135
72
|
|
136
|
-
|
137
|
-
|
73
|
+
cmd.each do |n|
|
74
|
+
matchstrs << '%s=~%s' % ['name', n]
|
138
75
|
end
|
139
76
|
|
140
77
|
# If input file not specified, at least start date is required
|
141
|
-
if
|
142
|
-
puts "Error: no matches specified"
|
143
|
-
STDERR.puts opts
|
78
|
+
if matchstrs.size == 0
|
79
|
+
puts "Error: no matches specified\n"
|
80
|
+
STDERR.puts opts.banner
|
144
81
|
exit 1
|
145
82
|
end
|
146
83
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
:
|
152
|
-
}
|
153
|
-
case keyvalue
|
154
|
-
when 'reverse?','stock?','custom?'
|
155
|
-
op.merge!({
|
156
|
-
:method => keyvalue.to_sym,
|
157
|
-
:name => keyvalue
|
158
|
-
})
|
159
|
-
else
|
160
|
-
((key,cmp,value)) = keyvalue.scan(/(\w+)(=~|<|>|=)(.+)/)
|
161
|
-
# (key, value) = keyvalue.split('=')
|
162
|
-
if key.nil?
|
163
|
-
STDERR.puts "Error: invalid match '#{keyvalue}', should be key<cmp>value"
|
164
|
-
STDERR.puts " where cmp is comparison type, one of: =,<,> or =~"
|
165
|
-
STDERR.puts " Example: name=~temple"
|
166
|
-
STDERR.puts opts
|
167
|
-
exit 1
|
168
|
-
end
|
169
|
-
|
170
|
-
cmp = '==' if cmp == '='
|
171
|
-
op.merge!({
|
172
|
-
:method => :inf,
|
173
|
-
:infkey => key.downcase.to_sym,
|
174
|
-
:infcmp => cmp.to_sym,
|
175
|
-
:infval => value,
|
176
|
-
:name => key,
|
177
|
-
})
|
178
|
-
|
84
|
+
begin
|
85
|
+
# Create the matcher objects
|
86
|
+
self[:match] = []
|
87
|
+
for m in matchstrs
|
88
|
+
self[:match] << ReVolt::Util::Matcher.parse(m)
|
179
89
|
end
|
180
|
-
|
90
|
+
rescue ReVolt::Util::Matcher::ParseError => e
|
91
|
+
STDERR.puts e.errstr
|
92
|
+
exit(1)
|
181
93
|
end
|
182
94
|
end
|
183
95
|
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
#
|
3
|
+
require 'optparse'
|
4
|
+
require 'pp'
|
5
|
+
require 'revolt'
|
6
|
+
require 'set'
|
7
|
+
|
8
|
+
def main
|
9
|
+
@cmd = CmdArguments.new(ARGV)
|
10
|
+
ReVolt::Logger.enable if @cmd[:debug]
|
11
|
+
levels = ReVolt::Levels.at(@cmd[:base])
|
12
|
+
levels.each_level do |level|
|
13
|
+
nmatches = ReVolt::Util::Matcher.multi(level, @cmd[:match])
|
14
|
+
if nmatches > 0
|
15
|
+
output_info(level)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def output_info(l)
|
21
|
+
puts "%s (%s)" % [l.name, l.id]
|
22
|
+
[
|
23
|
+
[:stock?, ' - This is a stock level'],
|
24
|
+
[:custom?, ' - This is a custom level'],
|
25
|
+
[:reverse?, ' - Can be played in reverse'],
|
26
|
+
[:full_custom?,' - Can be played in Full Custom mode']
|
27
|
+
].each do |(question, msg)|
|
28
|
+
puts msg if l.send(question)
|
29
|
+
end
|
30
|
+
|
31
|
+
if @cmd[:all]
|
32
|
+
puts "Elements from info file:"
|
33
|
+
l.inf.sort{|a,b| a.to_s <=> b.to_s}.each do |key, value|
|
34
|
+
value = l.inf[key]
|
35
|
+
puts "%-20s %s" % [key.to_s.upcase, value]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
puts ""
|
40
|
+
end
|
41
|
+
|
42
|
+
class CmdArguments < Hash
|
43
|
+
include ReVolt::Util::CommonCmdArgs
|
44
|
+
|
45
|
+
def initialize(cmd)
|
46
|
+
super()
|
47
|
+
|
48
|
+
self[:base] = ReVolt::Info::path
|
49
|
+
self[:all] = false
|
50
|
+
|
51
|
+
matchstrs = []
|
52
|
+
opts = OptionParser.new do |opts|
|
53
|
+
opts.banner = "Usage: #$0 [options] [name_match ...]\n"
|
54
|
+
opts.separator ""
|
55
|
+
opts.separator "Outputs information about matching levels from their inf file."
|
56
|
+
opts.separator ""
|
57
|
+
opts.separator "Examples:"
|
58
|
+
opts.separator " Information about levels whose name includes temple:"
|
59
|
+
opts.separator " #$0 temple"
|
60
|
+
|
61
|
+
opts.separator ""
|
62
|
+
match_help(opts)
|
63
|
+
opts.separator ""
|
64
|
+
|
65
|
+
opts.separator "Options:"
|
66
|
+
|
67
|
+
on_match(opts) do |value|
|
68
|
+
matchstrs << value
|
69
|
+
end
|
70
|
+
opts.on('-d', '--debug',
|
71
|
+
'Outputs debug information') do
|
72
|
+
self[:debug] = true
|
73
|
+
end
|
74
|
+
opts.on('-a', '--all',
|
75
|
+
'All information from the level output') do
|
76
|
+
self[:all] = true
|
77
|
+
end
|
78
|
+
|
79
|
+
on_base_path(opts) do |value|
|
80
|
+
self[:base] = value
|
81
|
+
end
|
82
|
+
|
83
|
+
opts.on_tail('-h', '--help',
|
84
|
+
'Display full help and exit') do
|
85
|
+
puts opts
|
86
|
+
|
87
|
+
exit(0)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
opts.parse!(cmd)
|
92
|
+
|
93
|
+
cmd.each do |n|
|
94
|
+
matchstrs << '%s=~%s' % ['name', n]
|
95
|
+
end
|
96
|
+
|
97
|
+
# If input file not specified, at least start date is required
|
98
|
+
if matchstrs.size == 0
|
99
|
+
puts "Error: no matches specified\n"
|
100
|
+
STDERR.puts opts.banner
|
101
|
+
exit 1
|
102
|
+
end
|
103
|
+
|
104
|
+
begin
|
105
|
+
# Create the matcher objects
|
106
|
+
self[:match] = []
|
107
|
+
for m in matchstrs
|
108
|
+
self[:match] << ReVolt::Util::Matcher.parse(m)
|
109
|
+
end
|
110
|
+
rescue ReVolt::Util::Matcher::ParseError => e
|
111
|
+
STDERR.puts e.errstr
|
112
|
+
exit(1)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
main
|
@@ -40,10 +40,10 @@ def main
|
|
40
40
|
tmplevels.each do |level|
|
41
41
|
# Install only levels that do not exist already
|
42
42
|
if !@cmd[:force] && @levels.member?(level)
|
43
|
-
puts "Skipping installing of " + level.
|
43
|
+
puts "Skipping installing of " + level.inspect + " because it exists"
|
44
44
|
@summary[:exists] << level
|
45
45
|
else
|
46
|
-
puts "Installing level " + level.
|
46
|
+
puts "Installing level " + level.inspect
|
47
47
|
level.move_to @levels
|
48
48
|
@summary[:installed] << level
|
49
49
|
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
#
|
3
|
+
require 'optparse'
|
4
|
+
require 'pp'
|
5
|
+
require 'revolt'
|
6
|
+
require 'set'
|
7
|
+
|
8
|
+
def main
|
9
|
+
pkg_levs = []
|
10
|
+
cmd = CmdArguments.new(ARGV)
|
11
|
+
ReVolt::Logger.enable if cmd[:debug]
|
12
|
+
levels = ReVolt::Levels.at(cmd[:base])
|
13
|
+
levels.each_level do |level|
|
14
|
+
all_matches = {}
|
15
|
+
nmatches = ReVolt::Util::Matcher.multi(level, cmd[:match], all_matches)
|
16
|
+
if nmatches > 0
|
17
|
+
keyvaluestr = all_matches.map{|(k,v)|"#{k}=#{v}"}.join(', ')
|
18
|
+
pkg_levs << level
|
19
|
+
puts "%s [%s]" % [level.inspect, keyvaluestr]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
if pkg_levs.size > 0
|
24
|
+
puts ''
|
25
|
+
puts "Creating packages of #{pkg_levs.size} matching levels"
|
26
|
+
pkg_levs.each do |l, match|
|
27
|
+
pkgfname = "%s.%s" % [l.id.to_s, 'zip']
|
28
|
+
puts "Creating package %s from %s" % [pkgfname, l.inspect]
|
29
|
+
l.package(pkgfname)
|
30
|
+
end
|
31
|
+
else
|
32
|
+
puts "No matching levels"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
class CmdArguments < Hash
|
38
|
+
include ReVolt::Util::CommonCmdArgs
|
39
|
+
|
40
|
+
def initialize(cmd)
|
41
|
+
super()
|
42
|
+
|
43
|
+
self[:base] = ReVolt::Info::path
|
44
|
+
self[:force] = false
|
45
|
+
|
46
|
+
matchstrs = []
|
47
|
+
opts = OptionParser.new do |opts|
|
48
|
+
opts.banner = "Usage: #$0 [options] [levelid ...]\n"
|
49
|
+
opts.separator ""
|
50
|
+
opts.separator "Creates packages of levels. Each packaged level will be"
|
51
|
+
opts.separator "named by its id"
|
52
|
+
opts.separator ""
|
53
|
+
opts.separator "Examples:"
|
54
|
+
opts.separator " Package a level that is in RV levels sub-directory temple:"
|
55
|
+
opts.separator " #$0 temple"
|
56
|
+
opts.separator " Packages all custom tracks that can be raced in reverse:"
|
57
|
+
opts.separator " #$0 -m 'custom?,reverse?'"
|
58
|
+
|
59
|
+
opts.separator ""
|
60
|
+
match_help(opts)
|
61
|
+
opts.separator ""
|
62
|
+
|
63
|
+
opts.separator "Options:"
|
64
|
+
|
65
|
+
on_match(opts) do |value|
|
66
|
+
matchstrs << value
|
67
|
+
end
|
68
|
+
opts.on('-d', '--debug',
|
69
|
+
'Outputs debug information') do
|
70
|
+
self[:debug] = true
|
71
|
+
end
|
72
|
+
|
73
|
+
on_base_path(opts) do |value|
|
74
|
+
self[:base] = value
|
75
|
+
end
|
76
|
+
|
77
|
+
opts.on_tail('-h', '--help',
|
78
|
+
'Display full help and exit') do
|
79
|
+
puts opts
|
80
|
+
|
81
|
+
exit(0)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
opts.parse!(cmd)
|
86
|
+
|
87
|
+
cmd.each do |pkgid|
|
88
|
+
matchstrs << 'id=%s' % ['name', cmd[0]]
|
89
|
+
end
|
90
|
+
|
91
|
+
# If input file not specified, at least start date is required
|
92
|
+
if matchstrs.size == 0
|
93
|
+
puts "Error: no matches specified\n"
|
94
|
+
STDERR.puts opts.banner
|
95
|
+
exit 1
|
96
|
+
end
|
97
|
+
|
98
|
+
begin
|
99
|
+
# Create the matcher objects
|
100
|
+
self[:match] = []
|
101
|
+
for m in matchstrs
|
102
|
+
self[:match] << ReVolt::Util::Matcher.parse(m)
|
103
|
+
end
|
104
|
+
rescue ReVolt::Util::Matcher::ParseError => e
|
105
|
+
STDERR.puts e.errstr
|
106
|
+
exit(1)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
main
|