revolt 0.5.1
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 +150 -0
- data/Rakefile +197 -0
- data/bin/rv_find_levels.rb +186 -0
- data/bin/rv_install_level_urls.rb +191 -0
- data/bin/rv_install_levels.rb +76 -0
- data/examples/find_rv_track.rb +17 -0
- data/examples/install_rv_track.rb +28 -0
- data/lib/revolt/args.rb +46 -0
- data/lib/revolt/config.rb +5 -0
- data/lib/revolt/exceptions.rb +34 -0
- data/lib/revolt/fetcher/file_system.rb +31 -0
- data/lib/revolt/fetcher/www.rb +117 -0
- data/lib/revolt/fetcher.rb +30 -0
- data/lib/revolt/info.rb +40 -0
- data/lib/revolt/level.rb +298 -0
- data/lib/revolt/levels.rb +362 -0
- data/lib/revolt/logger.rb +24 -0
- data/lib/revolt/package/archive/analyzer/normalized.rb +50 -0
- data/lib/revolt/package/archive/analyzer/troubled.rb +97 -0
- data/lib/revolt/package/archive/analyzer.rb +34 -0
- data/lib/revolt/package/archive/zip/browser.rb +44 -0
- data/lib/revolt/package/archive.rb +35 -0
- data/lib/revolt/package/exe.rb +10 -0
- data/lib/revolt/package/installer/archive.rb +105 -0
- data/lib/revolt/package/installer/exe.rb +10 -0
- data/lib/revolt/package.rb +64 -0
- data/lib/revolt/util/fs_browser.rb +30 -0
- data/lib/revolt/util.rb +20 -0
- data/lib/revolt.rb +12 -0
- data/test/common.rb +78 -0
- data/test/fixtures/files/nodirs_track.zip +0 -0
- data/test/fixtures/files/readme.txt +1 -0
- data/test/fixtures/files/rickyd_track.zip +0 -0
- data/test/fixtures/files/standard_multi.zip +0 -0
- data/test/fixtures/files/standard_rev_track.zip +0 -0
- data/test/fixtures/files/standard_track.zip +0 -0
- data/test/fixtures/files/zips_inside.zip +0 -0
- data/test/fixtures/rv/gfx/levid.bmp +1 -0
- data/test/fixtures/rv/gfx/levid.bmq +1 -0
- data/test/fixtures/rv/gfx/levidrev.bmp +1 -0
- data/test/fixtures/rv/gfx/levidrev.bmq +1 -0
- data/test/fixtures/rv/gfx/tEsT Level.bmp +1 -0
- data/test/fixtures/rv/levels/levid/levid.inf +1 -0
- data/test/fixtures/rv/levels/levid/levid.w +1 -0
- data/test/fixtures/rv/levels/levid/levida.bmp +1 -0
- data/test/fixtures/rv/levels/levid/readme.txt +1 -0
- data/test/fixtures/rv/levels/levidrev/levidrev.inf +1 -0
- data/test/fixtures/rv/levels/levidrev/levidrev.w +1 -0
- data/test/fixtures/rv/levels/levidrev/levidreva.bmp +1 -0
- data/test/fixtures/rv/levels/levidrev/readme.txt +1 -0
- data/test/fixtures/rv/levels/levidrev/reversed/levidrev.cam +1 -0
- data/test/fixtures/rv/levels/levidrev/reversed/levidrev.fan +1 -0
- data/test/fixtures/rv/levels/levidrev/reversed/levidrev.fin +1 -0
- data/test/fixtures/rv/levels/test lEveL/TEst level.inf +4 -0
- data/test/fixtures/rv/levels/test lEveL/TeST level.w +1 -0
- data/test/fixtures/rv/levels/test lEveL/readme.txt +1 -0
- data/test/fixtures/rv/levels/test lEveL/reversed/TEst level.inf +1 -0
- data/test/fixtures/rv/levels/test lEveL/reversed/TeST level.w +1 -0
- data/test/fixtures/rv/levels/test lEveL/reversed/readme.txt +1 -0
- data/test/fixtures/rv/levels/test lEveL/reversed/test LEVELa.bmp +1 -0
- data/test/fixtures/rv/levels/test lEveL/test LEVELa.bmp +1 -0
- data/test/tc_archive_analyzer.rb +185 -0
- data/test/tc_args.rb +55 -0
- data/test/tc_args_external.rb +55 -0
- data/test/tc_file_system_fetcher.rb +26 -0
- data/test/tc_info.rb +23 -0
- data/test/tc_level.rb +182 -0
- data/test/tc_level_installer.rb +88 -0
- data/test/tc_level_installer_external.rb +124 -0
- data/test/tc_levels.rb +68 -0
- data/test/tc_package_track_installer.rb +174 -0
- data/test/ts_base.rb +14 -0
- data/test/ts_external.rb +7 -0
- metadata +133 -0
@@ -0,0 +1,191 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
#
|
3
|
+
require 'optparse'
|
4
|
+
require 'pp'
|
5
|
+
require 'revolt'
|
6
|
+
require 'set'
|
7
|
+
|
8
|
+
|
9
|
+
def main
|
10
|
+
@cmd = CmdArguments.new(ARGV)
|
11
|
+
|
12
|
+
@summary = {
|
13
|
+
:installed => [],
|
14
|
+
:skipped => [],
|
15
|
+
:exists => [],
|
16
|
+
:error_url => [],
|
17
|
+
}
|
18
|
+
|
19
|
+
# Setup some callbacks so that progress is reported
|
20
|
+
ReVolt::global_args = REPORTING_ARGS
|
21
|
+
|
22
|
+
ReVolt::Logger::enable if @cmd[:debug]
|
23
|
+
@levels = ReVolt::Levels.at(@cmd[:base])
|
24
|
+
tmplevels = ReVolt::Levels.new(ReVolt::Util::tmpdir + 'rv_install_level')
|
25
|
+
# Delete any tmplevel directory if it existed
|
26
|
+
tmplevels.base_path.rmtree
|
27
|
+
tmplevels.create_dir_structure
|
28
|
+
|
29
|
+
puts "Enter track URLs to install. Press Ctrl+D to install."
|
30
|
+
input_open(@cmd[:input]) do |input|
|
31
|
+
input.each_line do |tracksrc|
|
32
|
+
tmplevels.install_urls tracksrc
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
puts "Installing tracks"
|
37
|
+
tmplevels.each do |level|
|
38
|
+
# Install only levels that do not exist already
|
39
|
+
if !@cmd[:force] && @levels.member?(level)
|
40
|
+
puts "Skipping installing of " + level.to_s + " because it exists"
|
41
|
+
@summary[:exists] << level
|
42
|
+
else
|
43
|
+
puts "Installing level " + level.to_s
|
44
|
+
level.move_to @levels
|
45
|
+
@summary[:installed] << level
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Output summary of installed tracks.
|
50
|
+
puts
|
51
|
+
puts "Summary"
|
52
|
+
puts "-------"
|
53
|
+
unless @summary[:installed].empty?
|
54
|
+
puts "Installed Tracks:"
|
55
|
+
@summary[:installed].each {|l| puts " #{l}"}
|
56
|
+
end
|
57
|
+
unless @summary[:skipped].empty?
|
58
|
+
puts "Likely exists (use option -f to force installing):"
|
59
|
+
@summary[:skipped].each {|(l,u)| puts " #{l} [name from URL #{u}]}"}
|
60
|
+
end
|
61
|
+
unless @summary[:exists].empty?
|
62
|
+
puts "Already exists (use option -f to force installing):"
|
63
|
+
@summary[:exists].each {|l| puts " #{l}"}
|
64
|
+
end
|
65
|
+
unless @summary[:error_url].empty?
|
66
|
+
puts "Errors installing URLs:"
|
67
|
+
@summary[:error_url].each {|(e,u)| puts " #{u}: #{e}"}
|
68
|
+
end
|
69
|
+
|
70
|
+
ReVolt::Logger::debug "Removing uninstalled tracks"
|
71
|
+
|
72
|
+
# Remove any remaining files from the temporary directory
|
73
|
+
tmplevels.each do |level|
|
74
|
+
ReVolt::Logger::debug "Removing uninstalled level " +
|
75
|
+
level.to_s + " from temporary levels"
|
76
|
+
level.delete
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Opens input file safely so that it gets closed too,
|
81
|
+
# and uses STDIN without the closing command otherwise
|
82
|
+
def input_open(input)
|
83
|
+
input = File.open(input) if input
|
84
|
+
input ||= STDIN
|
85
|
+
yield input
|
86
|
+
ensure
|
87
|
+
input.close unless input == STDIN
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
# Expects @levels instance variable
|
92
|
+
def track_installed?(url)
|
93
|
+
return false if @cmd[:force]
|
94
|
+
trackname = $1 if url =~ /dload\.php\?trackname=([^\&]+)/
|
95
|
+
return false if !trackname
|
96
|
+
|
97
|
+
urltrackname = URI::decode(trackname) # ).gsub!(/\+/, ' ')
|
98
|
+
trackname = normalize_track_name(urltrackname)
|
99
|
+
ReVolt::Logger::debug "Normalized track name to #{trackname}"
|
100
|
+
@levels.each_custom do |level|
|
101
|
+
levelname = normalize_track_name(level.name)
|
102
|
+
if trackname == levelname
|
103
|
+
ReVolt::Logger::debug "Match #{trackname} -> #{levelname}"
|
104
|
+
puts "URL probably already installed as #{level}, skipping (use -f option to force install)"
|
105
|
+
@summary[:skipped] << [level,urltrackname]
|
106
|
+
return true
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
false
|
111
|
+
end
|
112
|
+
|
113
|
+
def normalize_track_name(s)
|
114
|
+
t = s.chomp
|
115
|
+
t.downcase!
|
116
|
+
# Remove 'by someone' from the end
|
117
|
+
t.gsub!(/ +by +.*$/, '')
|
118
|
+
# Remove all special characters
|
119
|
+
t.gsub!(/[^a-z0-9]+/, '')
|
120
|
+
t
|
121
|
+
end
|
122
|
+
|
123
|
+
# Callbacks for different stages of track installing
|
124
|
+
REPORTING_ARGS = {
|
125
|
+
ReVolt::ARG_INSTALL_URL => lambda {|url|
|
126
|
+
# Often people copy-paste a link to RVZT comment section,
|
127
|
+
# so in that case automatically make a download link of it
|
128
|
+
url = url.to_s.sub(/comments.php/, 'dload.php')
|
129
|
+
puts "Installing URL #{url}"
|
130
|
+
# Only install tracks that most likely haven't already been
|
131
|
+
# installed. The track_installed? takes the URL and tries
|
132
|
+
# using a heuristic to determine if similar track is installed
|
133
|
+
track_installed?(url) ? nil : url
|
134
|
+
},
|
135
|
+
ReVolt::ARG_INSTALL_URL_EX => lambda {|e,url|
|
136
|
+
# Called if exception raised when installing url
|
137
|
+
@summary[:error_url] << [e,url]
|
138
|
+
puts "Error installing: #{e}"
|
139
|
+
},
|
140
|
+
ReVolt::ARG_FETCHER_PROGRESS => lambda {|obj,url,nread,total|
|
141
|
+
$now = Time.new().sec()
|
142
|
+
if !$last or $now - $last > 1 then
|
143
|
+
puts '%.2f%% (%d/%d bytes) downloaded' %
|
144
|
+
[(total > 0 ? nread*100/total : 0), nread, total]
|
145
|
+
$last = $now
|
146
|
+
end
|
147
|
+
},
|
148
|
+
ReVolt::ARG_FETCHER_STOP => lambda {|obj,url,total|
|
149
|
+
$last = nil
|
150
|
+
ReVolt::call_arg(ReVolt::ARG_FETCHER_PROGRESS, {}, obj, url, total, total)
|
151
|
+
}
|
152
|
+
}
|
153
|
+
|
154
|
+
class CmdArguments < Hash
|
155
|
+
def initialize(cmd)
|
156
|
+
super()
|
157
|
+
inf_matches = []
|
158
|
+
self[:base] = ReVolt::Info::path
|
159
|
+
|
160
|
+
opts = OptionParser.new do |opts|
|
161
|
+
opts.banner = "Usage: #$0 [options]\n"
|
162
|
+
opts.separator "By default the URLs are read from standard console input"
|
163
|
+
|
164
|
+
opts.separator ""
|
165
|
+
opts.separator "Options:"
|
166
|
+
|
167
|
+
opts.on('-i', '--input [FILE]',
|
168
|
+
'Reads the URLs from given file') do |value|
|
169
|
+
self[:input] = value
|
170
|
+
end
|
171
|
+
opts.on('-b', '--base [DIR]',
|
172
|
+
'RV base path. Defaults to RV installation') do |value|
|
173
|
+
self[:base] = value
|
174
|
+
end
|
175
|
+
opts.on('-f', '--force',
|
176
|
+
'Forces installing of tracks') do
|
177
|
+
self[:force] = true
|
178
|
+
end
|
179
|
+
|
180
|
+
opts.on_tail('-h', '--help',
|
181
|
+
'Display this help and exit') do
|
182
|
+
puts opts
|
183
|
+
exit(1)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
opts.parse!(cmd)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
main
|
@@ -0,0 +1,76 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
#
|
3
|
+
require 'optparse'
|
4
|
+
require 'pp'
|
5
|
+
require 'revolt'
|
6
|
+
require 'set'
|
7
|
+
|
8
|
+
|
9
|
+
def main
|
10
|
+
cmd = CmdArguments.new(ARGV)
|
11
|
+
|
12
|
+
ReVolt::Logger::enable if cmd[:debug]
|
13
|
+
levels = ReVolt::Levels.at(cmd[:base])
|
14
|
+
|
15
|
+
levelids = []
|
16
|
+
ARGV.each do |levelpackage|
|
17
|
+
puts "Installing #{levelpackage}"
|
18
|
+
levelids += levels.install(levelpackage) || []
|
19
|
+
end
|
20
|
+
puts "Installed levels: " if levelids.size > 0
|
21
|
+
levelids.each do |levelid|
|
22
|
+
level = levels[levelid]
|
23
|
+
puts " #{level}" if level
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Opens input file safely so that it gets closed too,
|
28
|
+
# and uses STDIN without the closing command otherwise
|
29
|
+
def input_open(input)
|
30
|
+
input = File.open(input) if input
|
31
|
+
input ||= STDIN
|
32
|
+
yield input
|
33
|
+
ensure
|
34
|
+
input.close unless input == STDIN
|
35
|
+
end
|
36
|
+
|
37
|
+
class CmdArguments < Hash
|
38
|
+
def initialize(cmd)
|
39
|
+
super()
|
40
|
+
inf_matches = []
|
41
|
+
self[:base] = ReVolt::Info::path
|
42
|
+
|
43
|
+
opts = OptionParser.new do |opts|
|
44
|
+
opts.banner = "Usage: #$0 [options] package1 [package2 ...]\n"
|
45
|
+
opts.separator "By default the URLs are read from standard console input"
|
46
|
+
|
47
|
+
opts.separator ""
|
48
|
+
opts.separator "Options:"
|
49
|
+
|
50
|
+
opts.on('-d', '--debug',
|
51
|
+
'Writes debugging information') do
|
52
|
+
self[:debug] = true
|
53
|
+
end
|
54
|
+
opts.on('-b', '--base [DIR]',
|
55
|
+
'RV base path. Defaults to RV installation') do |value|
|
56
|
+
self[:base] = value
|
57
|
+
end
|
58
|
+
|
59
|
+
opts.on_tail('-h', '--help',
|
60
|
+
'Display this help and exit') do
|
61
|
+
puts opts
|
62
|
+
exit(1)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
opts.parse!(cmd)
|
67
|
+
|
68
|
+
if ARGV.size <= 0
|
69
|
+
puts opts
|
70
|
+
exit(1)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
main
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'revolt'
|
2
|
+
|
3
|
+
# Very simple example of how to find a track
|
4
|
+
# with some name (case insensitive).
|
5
|
+
|
6
|
+
search_for = ARGV[0]
|
7
|
+
unless search_for
|
8
|
+
STDERR.puts "Usage: #{$0} track_name_search_pattern"
|
9
|
+
exit(1)
|
10
|
+
end
|
11
|
+
|
12
|
+
levels = ReVolt::Levels.installed
|
13
|
+
levels.each_level do |level|
|
14
|
+
if level.name.match(/#{search_for}/i)
|
15
|
+
puts "Level matched: " + level.to_s
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'revolt'
|
2
|
+
|
3
|
+
levels = ReVolt::Levels.installed
|
4
|
+
tmplevels = ReVolt::Levels.at('./tmp')
|
5
|
+
tmplevels.create_dir_structure
|
6
|
+
|
7
|
+
# Install to temporary levels dir first
|
8
|
+
STDIN.each_line do |tracksrc|
|
9
|
+
puts "Installing: " + tracksrc + " to temporary levels directory"
|
10
|
+
tmplevels.install tracksrc
|
11
|
+
end
|
12
|
+
|
13
|
+
tmplevels.each do |level|
|
14
|
+
# Install only levels that do not exist already
|
15
|
+
if levels.member? level
|
16
|
+
puts "Skipping installing of " + level.to_s + " because it exists"
|
17
|
+
else
|
18
|
+
puts "Installing level " + levels.to_s
|
19
|
+
level.move_to levels
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Remove any remaining files from the temporary directory
|
24
|
+
tmplevels.each do |level|
|
25
|
+
puts "Removing uninstalled level " + level.to_s + " from temporary levels"
|
26
|
+
level.delete
|
27
|
+
end
|
28
|
+
|
data/lib/revolt/args.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
module ReVolt
|
2
|
+
@@global_args = {}
|
3
|
+
|
4
|
+
ARG_INSTALL_URL = :install_url
|
5
|
+
ARG_INSTALL_URL_EX = :install_url_ex
|
6
|
+
ARG_FETCHER_PROGRESS = :fetcher_progress
|
7
|
+
ARG_FETCHER_START = :fetcher_start
|
8
|
+
ARG_FETCHER_STOP = :fetcher_stop
|
9
|
+
|
10
|
+
module_function
|
11
|
+
|
12
|
+
def global_args
|
13
|
+
@@global_args
|
14
|
+
end
|
15
|
+
def global_args=(o)
|
16
|
+
@@global_args = (o.is_a?(Hash) ? o : {})
|
17
|
+
end
|
18
|
+
|
19
|
+
def arg(id, args = {})
|
20
|
+
return args[id] if args.member?(id)
|
21
|
+
return @@global_args[id] if @@global_args.member?(id)
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
def call_arg(id, args, *params)
|
25
|
+
a = arg(id, args)
|
26
|
+
a.call(*params) if a
|
27
|
+
end
|
28
|
+
def call_changer_arg(id, args, *params)
|
29
|
+
a = arg(id, args)
|
30
|
+
a ? a.call(*params) : params
|
31
|
+
end
|
32
|
+
|
33
|
+
# Calls the defined callback if the block raises Runtime error
|
34
|
+
# and otherwise rethrows it
|
35
|
+
def arg_ex_watch(id, args, *rest)
|
36
|
+
begin
|
37
|
+
yield
|
38
|
+
rescue RuntimeError => e
|
39
|
+
if arg(id, args)
|
40
|
+
call_arg(id, args, e, *rest)
|
41
|
+
else
|
42
|
+
raise e
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module ReVolt
|
4
|
+
|
5
|
+
# All exceptions derived from RVException
|
6
|
+
class RVException < RuntimeError; end
|
7
|
+
|
8
|
+
# Thrown if a file is not found. The file can
|
9
|
+
# be accessed via an attribute if necessary
|
10
|
+
class FileNotFoundError < RVException
|
11
|
+
attr_reader :file
|
12
|
+
def initialize(filename)
|
13
|
+
@file = filename.to_s
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Thrown if level's .inf file was not found
|
18
|
+
# when needed.
|
19
|
+
class InfFileNotFoundError < FileNotFoundError
|
20
|
+
attr_reader :levels, :level
|
21
|
+
def initialize(levels, level, inf_file)
|
22
|
+
super inf_file
|
23
|
+
@levels, @level = levels, level
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Thrown if an unknown package was tried to be
|
28
|
+
# operated on.
|
29
|
+
class PackageUnknownError < RVException; end
|
30
|
+
# Thrown if no Fetcher could be created for
|
31
|
+
# the given source.
|
32
|
+
class FetcherNoneError < RVException; end
|
33
|
+
class InvalidLevelIdError < RVException; end
|
34
|
+
end # module ReVolt
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
require 'revolt/exceptions'
|
4
|
+
require 'revolt/logger'
|
5
|
+
|
6
|
+
module ReVolt
|
7
|
+
module Fetcher
|
8
|
+
|
9
|
+
class FileSystem
|
10
|
+
include ReVolt::Logger
|
11
|
+
|
12
|
+
attr_reader :target, :source
|
13
|
+
|
14
|
+
def initialize(id, args = {})
|
15
|
+
debug("Source id: #{id} size #{id.size}")
|
16
|
+
@source = Pathname.new(id.to_s)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Possible exceptions:
|
20
|
+
# FileNotFoundError
|
21
|
+
def run(args = {})
|
22
|
+
debug Dir['*'].join(" ")
|
23
|
+
|
24
|
+
raise ReVolt::FileNotFoundError.new(@source),
|
25
|
+
"File #{source} not found" unless File.exist?(@source.to_s) # @source.exist?
|
26
|
+
|
27
|
+
@target = @source
|
28
|
+
end
|
29
|
+
end # FileSystem
|
30
|
+
end # Fetcher
|
31
|
+
end # ReVolt
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'uri'
|
3
|
+
require 'net/http'
|
4
|
+
require 'net/https'
|
5
|
+
require 'set'
|
6
|
+
|
7
|
+
require 'revolt/exceptions'
|
8
|
+
require 'revolt/util'
|
9
|
+
require 'revolt/logger'
|
10
|
+
require 'revolt/args'
|
11
|
+
|
12
|
+
module ReVolt
|
13
|
+
module Fetcher
|
14
|
+
|
15
|
+
class WWW
|
16
|
+
include ReVolt::Logger
|
17
|
+
|
18
|
+
class TooManyRedirectionsError < ReVolt::RVException; end
|
19
|
+
|
20
|
+
attr_reader :target, :source, :final_uri
|
21
|
+
def initialize(id, args = {})
|
22
|
+
@@file_name_count = 0
|
23
|
+
@max_redirects = 3
|
24
|
+
|
25
|
+
@source = (id.is_a?(URI) ? id : URI.parse(id.to_s))
|
26
|
+
end
|
27
|
+
|
28
|
+
# Possible exceptions:
|
29
|
+
# TooManyRedirections
|
30
|
+
def run(args = {})
|
31
|
+
fetch(@source) do |resp,final_uri|
|
32
|
+
# debug "Headers: "
|
33
|
+
# resp.each {|key,val| debug "#{key}: #{val}"}
|
34
|
+
@target = ReVolt::Util::tmpdir
|
35
|
+
@target += generate_basename_from final_uri
|
36
|
+
|
37
|
+
debug "Saving to target #{@target}"
|
38
|
+
|
39
|
+
total = resp.content_length
|
40
|
+
total ||= 0
|
41
|
+
nread = 0
|
42
|
+
debug "Total size: " + total.to_s
|
43
|
+
|
44
|
+
ReVolt::call_arg(ReVolt::ARG_FETCHER_START, args,
|
45
|
+
self, @source, total)
|
46
|
+
|
47
|
+
open(@target, 'wb') do |file|
|
48
|
+
resp.read_body do |segment|
|
49
|
+
debug("%s: read %d/%d bytes read" %
|
50
|
+
[@source.to_s, nread, total])
|
51
|
+
ReVolt::call_arg(ReVolt::ARG_FETCHER_PROGRESS, args,
|
52
|
+
self, @source, nread, total)
|
53
|
+
file.syswrite segment
|
54
|
+
nread += segment.size
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
ReVolt::call_arg(ReVolt::ARG_FETCHER_STOP, args,
|
59
|
+
self, @source, nread)
|
60
|
+
|
61
|
+
debug "Saved to target #{@target}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def fetch(uri, args = {}, &block)
|
66
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
67
|
+
http.use_ssl = true if uri.scheme == 'https'
|
68
|
+
|
69
|
+
debug "Fetching #{uri}"
|
70
|
+
|
71
|
+
req = Net::HTTP::Get.new(uri.request_uri)
|
72
|
+
urls_seen = args[:urls_seen] || Set.new
|
73
|
+
http.request(req) do |resp|
|
74
|
+
if resp.is_a? Net::HTTPRedirection
|
75
|
+
debug "Is a redirection. Location: " + resp['Location']
|
76
|
+
new_loc = resp['Location']
|
77
|
+
if urls_seen.size < @max_redirects && new_loc
|
78
|
+
urls_seen << uri
|
79
|
+
new_uri = URI.parse new_loc
|
80
|
+
new_uri = uri.merge new_uri if new_uri.relative?
|
81
|
+
|
82
|
+
if urls_seen.member? new_uri
|
83
|
+
raise TooManyRedirectionsError,
|
84
|
+
"Too many redirections (max #{@max_redirects}): #{urls_seen}"
|
85
|
+
end
|
86
|
+
|
87
|
+
fetch(new_uri, args, &block)
|
88
|
+
end
|
89
|
+
else
|
90
|
+
debug "Final uri: " + uri.to_s
|
91
|
+
yield resp,uri
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def generate_basename_from(uri)
|
97
|
+
uri = URI.parse uri unless uri.is_a? URI
|
98
|
+
name = Pathname.new uri.path.downcase
|
99
|
+
name = name.basename
|
100
|
+
|
101
|
+
# If the gotten name looks safe, use it as the
|
102
|
+
# basename. Otherwise use generated sequence.
|
103
|
+
if name.to_s =~ /^[^\.][\w\.]+/
|
104
|
+
else
|
105
|
+
name = "rvfetcher" + @@file_name_count.to_s
|
106
|
+
@@file_name_count += 1
|
107
|
+
end
|
108
|
+
|
109
|
+
name
|
110
|
+
end
|
111
|
+
|
112
|
+
def to_i
|
113
|
+
'WWW Fetcher'
|
114
|
+
end
|
115
|
+
end # WWW
|
116
|
+
end # Fetcher
|
117
|
+
end # ReVolt
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'revolt/fetcher/www'
|
2
|
+
require 'revolt/fetcher/file_system'
|
3
|
+
require 'revolt/exceptions'
|
4
|
+
|
5
|
+
module ReVolt
|
6
|
+
# Internally used module that shouldn't usually be needed
|
7
|
+
# to call directly
|
8
|
+
module Fetcher
|
9
|
+
include ReVolt
|
10
|
+
|
11
|
+
module_function
|
12
|
+
|
13
|
+
# Factory method for creating a specific fetcher.
|
14
|
+
# At the moment recognizes http(s) and basically
|
15
|
+
# others are treated as files on local filesystem
|
16
|
+
def for(id, args = {})
|
17
|
+
clas = nil
|
18
|
+
case id.to_s
|
19
|
+
when /^http[s]?/
|
20
|
+
clas = WWW
|
21
|
+
when /^ftp:\/\//
|
22
|
+
raise FetcherNoneError, "No fetcher for FTP sites implemented: #{id}"
|
23
|
+
else
|
24
|
+
clas = FileSystem
|
25
|
+
end
|
26
|
+
|
27
|
+
return clas.new(id, args)
|
28
|
+
end
|
29
|
+
end # Fetcher
|
30
|
+
end # ReVolt
|
data/lib/revolt/info.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'win32/registry'
|
2
|
+
|
3
|
+
module ReVolt
|
4
|
+
|
5
|
+
# Contains functions that can be used to find
|
6
|
+
# information about the Re-Volt installation
|
7
|
+
module Info
|
8
|
+
RV_REG_KEY = 'SOFTWARE\Acclaim\Re-Volt\1.0'
|
9
|
+
RV_REG_KEY_PATH = 'SOFTWARE\Microsoft\DirectPlay\Applications\Re-Volt'
|
10
|
+
|
11
|
+
module_function
|
12
|
+
|
13
|
+
def reg_path_to_hash(key) # :nodoc:
|
14
|
+
h = {}
|
15
|
+
Win32::Registry::HKEY_LOCAL_MACHINE.open(key) do |root|
|
16
|
+
# puts "Root keyname: #{root.keyname}, hkey: #{root.class}"
|
17
|
+
root.each do |key, type, data|
|
18
|
+
h[key.to_s.downcase.to_sym] = data
|
19
|
+
# puts 'key: %s, type: %s, data: %s' % [key, type, data]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
h
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns full path of the Re-Volt base directory
|
26
|
+
def path
|
27
|
+
h = reg_path_to_hash(RV_REG_KEY_PATH)
|
28
|
+
p = Pathname.new(h[:path])
|
29
|
+
p
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns full path of the Re-Volt executable
|
33
|
+
def exe_path
|
34
|
+
h = reg_path_to_hash(RV_REG_KEY_PATH)
|
35
|
+
p = Pathname.new(h[:path])
|
36
|
+
p += h[:file]
|
37
|
+
p
|
38
|
+
end
|
39
|
+
end # Info
|
40
|
+
end # ReVolt
|