revolt 0.5.3 → 0.8.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.
- 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
|