smc-get 0.2.0.beta1 → 0.3.0.beta1
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/COPYING +674 -674
- data/HISTORY.rdoc +53 -31
- data/README.rdoc +162 -162
- data/VERSION.txt +1 -1
- data/bin/smc-checksum +44 -44
- data/bin/smc-checksum~ +2 -0
- data/bin/smc-get +31 -31
- data/bin/smc-repo-conv +205 -0
- data/bin/smc-repo-conv~ +155 -0
- data/config/smc-get.yml +32 -32
- data/config/smc-get.yml~ +32 -0
- data/lib/smc_get.rb +22 -22
- data/lib/smc_get/cui.rb +325 -325
- data/lib/smc_get/cui_commands/build.rb +297 -329
- data/lib/smc_get/cui_commands/command.rb +181 -117
- data/lib/smc_get/cui_commands/getinfo.rb +91 -91
- data/lib/smc_get/cui_commands/help.rb +64 -64
- data/lib/smc_get/cui_commands/install.rb +101 -101
- data/lib/smc_get/cui_commands/list.rb +101 -101
- data/lib/smc_get/cui_commands/search.rb +106 -106
- data/lib/smc_get/cui_commands/server.rb +76 -0
- data/lib/smc_get/cui_commands/uninstall.rb +77 -80
- data/lib/smc_get/cui_commands/update.rb +107 -119
- data/lib/smc_get/cui_commands/version.rb +57 -57
- data/lib/smc_get/errors.rb +166 -140
- data/lib/smc_get/gui.rb +19 -19
- data/lib/smc_get/local_repository.rb +290 -277
- data/lib/smc_get/package.rb +240 -260
- data/lib/smc_get/package_archive.rb +186 -80
- data/lib/smc_get/package_specification.rb +257 -253
- data/lib/smc_get/remote_repository.rb +272 -272
- data/lib/smc_get/repository.rb +9 -9
- data/lib/smc_get/smc_get.rb +118 -117
- data/smcpak.rdoc +331 -331
- data/test/test_smc-get-cui.rb +122 -122
- data/test/test_smc-get-lib.rb +171 -171
- metadata +25 -22
@@ -1,272 +1,272 @@
|
|
1
|
-
#Encoding: UTF-8
|
2
|
-
################################################################################
|
3
|
-
# This file is part of smc-get.
|
4
|
-
# Copyright (C) 2010-2011 Entertaining Software, Inc.
|
5
|
-
# Copyright (C) 2011 Marvin Gülker
|
6
|
-
#
|
7
|
-
# This program is free software: you can redistribute it and/or modify
|
8
|
-
# it under the terms of the GNU General Public License as published by
|
9
|
-
# the Free Software Foundation, either version 3 of the License, or
|
10
|
-
# (at your option) any later version.
|
11
|
-
#
|
12
|
-
# This program is distributed in the hope that it will be useful,
|
13
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
-
# GNU General Public License for more details.
|
16
|
-
#
|
17
|
-
# You should have received a copy of the GNU General Public License
|
18
|
-
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
|
-
################################################################################
|
20
|
-
|
21
|
-
module SmcGet
|
22
|
-
|
23
|
-
#A RemoteRepository represents a web location from which <tt>smc-get</tt>
|
24
|
-
#is able to download packages. The structure of those repositories is
|
25
|
-
#explained in the smcpak.rdoc file in the <i>Repostories</i> section.
|
26
|
-
class RemoteRepository < Repository
|
27
|
-
|
28
|
-
#Name of the remote directory containing the <tt>.smcpak</tt> files.
|
29
|
-
PACKAGES_DIR = "packages"
|
30
|
-
#Name of the remote directory containing the packages specifications.
|
31
|
-
SPECS_DIR = "specs"
|
32
|
-
#Name of the file containg the names of all packages in this repository.
|
33
|
-
LIST_FILE = "packages.lst"
|
34
|
-
#Number of bytes to read while downloading a file.
|
35
|
-
CHUNK_SIZE = 1024
|
36
|
-
|
37
|
-
##
|
38
|
-
# :attr_reader: packages
|
39
|
-
#Returns an array of remote Packages that contains all packages
|
40
|
-
#in this repository. This is a very time-intensive operation, depending
|
41
|
-
#on how many packages the repository contains, because it downloads all
|
42
|
-
#the package specifications of all the packages. It’s not a good idea
|
43
|
-
#to call this.
|
44
|
-
|
45
|
-
#An URI object representing the repository’s URI.
|
46
|
-
attr_reader :uri
|
47
|
-
#A list of all package names (without an extension).
|
48
|
-
attr_reader :packages_list
|
49
|
-
|
50
|
-
#Creates a "new" Repository.
|
51
|
-
#==Parameters
|
52
|
-
#[uri] The URI of the repository, something like
|
53
|
-
# "\http://my-host.org/smc-repo".
|
54
|
-
#==Raises
|
55
|
-
#[InvalidRepository] The repository is either nonexistant or doesn’t obey
|
56
|
-
# the repository structure format.
|
57
|
-
#==Return value
|
58
|
-
#The newly created repository.
|
59
|
-
#==Usage
|
60
|
-
# r = Repository.new("http://myrepo.org")
|
61
|
-
# r = Repository.new("https://my-host.org/smc-repo")
|
62
|
-
# r = Repository.new("ftp://ftp.my-host.org/smc")
|
63
|
-
def initialize(uri)
|
64
|
-
@uri = URI.parse(uri)
|
65
|
-
#Download the packages list. Usually it’s small enough to fit into RAM.
|
66
|
-
begin
|
67
|
-
@packages_list = open(@uri
|
68
|
-
rescue SocketError, Errno::ECONNREFUSED, OpenURI::HTTPError => e #open-uri raises HTTPError even in case of other protocols
|
69
|
-
raise(Errors::InvalidRepository.new(@uri), e.message)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
#Downloads the given package specification from this repository and
|
74
|
-
#places it in +directory+.
|
75
|
-
#
|
76
|
-
#If the file already exists, it’s overwritten.
|
77
|
-
#==Parameters
|
78
|
-
#[spec_file] The package specification file you want to download. It must
|
79
|
-
# end with the <tt>.yml</tt> extension.
|
80
|
-
#[directory] (".") The directory where you want to download the file to.
|
81
|
-
# Created if it doesn’t exist.
|
82
|
-
#==Raises
|
83
|
-
#[NoSuchResourceError] The package name for this specification couldn’t be
|
84
|
-
# found in the repository. Note that the spec may be
|
85
|
-
# there despite of this, but packages not listed
|
86
|
-
# in the repository’s contents file are treated as if
|
87
|
-
# they weren’t there.
|
88
|
-
#==Return value
|
89
|
-
#The path to the downloaded file as a Pathname object.
|
90
|
-
#==Usage
|
91
|
-
# my_repo.fetch_spec("mypackage.yml", "/home/freak/Downloads")
|
92
|
-
#
|
93
|
-
# my_repo.fetch_spec("mypackage.yml")
|
94
|
-
def fetch_spec(spec_file, directory = ".")
|
95
|
-
directory = Pathname.new(directory)
|
96
|
-
pkg_name = spec_file.sub(/\.yml$/, "")
|
97
|
-
goal_file = directory + spec_file
|
98
|
-
|
99
|
-
unless @packages_list.include?(pkg_name)
|
100
|
-
raise(Errors::NoSuchResourceError.new(:spec, spec_file), "Package '#{pkg_name}' not found in the repository!")
|
101
|
-
end
|
102
|
-
|
103
|
-
directory.mktree unless directory.directory?
|
104
|
-
|
105
|
-
#I am quite sure that URI#merge has a bug. Example:
|
106
|
-
# uri = URI.parse("http://www.ruby-lang.org")
|
107
|
-
#Now try to append the path test/test2:
|
108
|
-
# uri2 = uri + "test" + "test2"
|
109
|
-
#What do you think contains uri2? This:
|
110
|
-
# http://www.ruby-lang.org/test2
|
111
|
-
#Something missing, eh? Even more surprising, this one works as
|
112
|
-
#expected:
|
113
|
-
# uri + "test/test2"
|
114
|
-
#The second one is the workaround I use in the following line.
|
115
|
-
open(
|
116
|
-
File.open(goal_file, "w") do |file|
|
117
|
-
file.write(tempfile.read) #Specs almost ever are small enough to fit in RAM
|
118
|
-
end
|
119
|
-
end
|
120
|
-
goal_file
|
121
|
-
end
|
122
|
-
|
123
|
-
#Downloads the given package from this repository and places it in
|
124
|
-
#+directory+. Yields the package’s total size in bytes and how many
|
125
|
-
#bytes have already been downloaded. If the size is unknown for some
|
126
|
-
#reason, +bytes_total+ is nil. For the last block call, +bytes_total+
|
127
|
-
#and +bytes_done+ are guaranteed to be equal, except if +bytes_total+
|
128
|
-
#couldn’t be determined in which case it’s still nil.
|
129
|
-
#
|
130
|
-
#If the file does already exist in +directory+, it is overwritten.
|
131
|
-
#==Parameters
|
132
|
-
#[pkg_file] The package file you want to download. It must end in
|
133
|
-
# the <tt>.smcpak</tt> extension.
|
134
|
-
#[directory] (".") The directory where you want to download the file to.
|
135
|
-
# Created if it doesn’t exist.
|
136
|
-
#==Raises
|
137
|
-
#[NoSuchPackageError] The package name for this package couldn’t be
|
138
|
-
# found in the repository. Note that the package may be
|
139
|
-
# there despite of this, but packages not listed
|
140
|
-
# in the repository’s contents file are treated as if
|
141
|
-
# they weren’t there.
|
142
|
-
#[OpenURI::HTTPError] Connection error.
|
143
|
-
#==Return value
|
144
|
-
#The path to the downloaded file as a Pathname object.
|
145
|
-
#==Usage
|
146
|
-
# my_repo.fetch_package("mypackage.smcpak", "/home/freak/downloads")
|
147
|
-
#
|
148
|
-
# my_repo.fetch_package("mypackage.smcpak") do |bytes_total, bytes_done|
|
149
|
-
# print("\rDownloaded #{bytes_done} bytes of #{bytes_total}.") if bytes_total
|
150
|
-
# end
|
151
|
-
def fetch_package(pkg_file, directory = ".")
|
152
|
-
directory = Pathname.new(directory)
|
153
|
-
pkg_name = pkg_file.sub(/\.smcpak$/, "")
|
154
|
-
goal_file = directory + pkg_file
|
155
|
-
|
156
|
-
unless @packages_list.include?(pkg_name)
|
157
|
-
raise(Errors::NoSuchPackageError.new(pkg_name), "ERROR: Package '#{pkg_name}' not found in the repository!")
|
158
|
-
end
|
159
|
-
|
160
|
-
directory.mktree unless directory.directory?
|
161
|
-
|
162
|
-
bytes_total = nil
|
163
|
-
size_proc = lambda{|content_length| bytes_total = content_length}
|
164
|
-
prog_proc = lambda{|bytes_done| yield(bytes_total, bytes_done)}
|
165
|
-
|
166
|
-
#See the source of #fetch_spec for an explanation on the obscure
|
167
|
-
#URI concatenation.
|
168
|
-
open(
|
169
|
-
#The packages may be too big for fitting into RAM, therefore we’re going
|
170
|
-
#to read and write the packages chunk by chunk. Btw. please notice me
|
171
|
-
#if you find a SMC package that’s larger than 4 GiB! I’d be curious
|
172
|
-
#about what it contains!
|
173
|
-
File.open(goal_file, "wb") do |file|
|
174
|
-
while chunk = tempfile.read(CHUNK_SIZE)
|
175
|
-
file.write(chunk)
|
176
|
-
end
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
goal_file
|
181
|
-
end
|
182
|
-
|
183
|
-
#Not implemented yet.
|
184
|
-
def install(package, &block)
|
185
|
-
raise(NotImplementedError, "Can't automatically upload to remote repositories yet!")
|
186
|
-
end
|
187
|
-
|
188
|
-
#Not implemented yet.
|
189
|
-
def uninstall(pkg_name)
|
190
|
-
raise(NotImplementedError, "Can't automatically remove from remote repositories yet!")
|
191
|
-
end
|
192
|
-
|
193
|
-
#Returns the URI of the remote repository.
|
194
|
-
def to_s
|
195
|
-
@uri.to_s
|
196
|
-
end
|
197
|
-
|
198
|
-
#See attribute.
|
199
|
-
# def packages # :nodoc:
|
200
|
-
# @packages_list.map do |pkg_name|
|
201
|
-
# Package.from_repository(self, "#{pkg_name}.yml")
|
202
|
-
# end
|
203
|
-
# end
|
204
|
-
|
205
|
-
#True if a package with the given name (without the .smcpak extension)
|
206
|
-
#exists in the repository.
|
207
|
-
def contain?(pkg)
|
208
|
-
if pkg.kind_of? Package
|
209
|
-
@packages_list.include?(pkg.spec.name)
|
210
|
-
else
|
211
|
-
@packages_list.include?(pkg_name)
|
212
|
-
end
|
213
|
-
end
|
214
|
-
alias contains? contain?
|
215
|
-
|
216
|
-
#call-seq:
|
217
|
-
# search(regexp [, *attributes ]){|pkgname|...}
|
218
|
-
#
|
219
|
-
#Searches for a specific package and yields each candidate to the
|
220
|
-
#given block.
|
221
|
-
#==Parameters
|
222
|
-
#[regexp] The Regular Expression to use as the search pattern.
|
223
|
-
#[*attributes] (<tt>[:name]</tt>) A list of all attributes to match
|
224
|
-
# the Regular Expression against (note that only
|
225
|
-
# passing :name is siginificantly faster, because
|
226
|
-
# there’s no need to download the specs).
|
227
|
-
# Possible attributes:
|
228
|
-
# * name
|
229
|
-
# * title
|
230
|
-
# * authors
|
231
|
-
# * difficulty
|
232
|
-
# * description
|
233
|
-
# * levels
|
234
|
-
# * music
|
235
|
-
# * sounds
|
236
|
-
# * graphics
|
237
|
-
# * worlds
|
238
|
-
#[pkgname] *Blockargument*. The package name (not title!) of
|
239
|
-
# a package matching the search criteria.
|
240
|
-
#==Examples
|
241
|
-
# rp.search(/cool/){|pkgname| p pkgname} #=> "cool_levels"
|
242
|
-
# rp.search(/Luiji/i, :authors){|pkgname| p pkgname} #=> All packages created by Luiji or luiji...
|
243
|
-
def search(regexp, *attributes)
|
244
|
-
attributes << :name if attributes.empty? #Default value
|
245
|
-
if attributes == [:name] #Good, no need to download all the specs
|
246
|
-
@packages_list.each{|name| yield(name) if name =~ regexp}
|
247
|
-
else #OK, so we need to download one spec after the other...
|
248
|
-
@packages_list.each do |pkgname|
|
249
|
-
spec = PackageSpecification.from_file(fetch_spec("#{pkgname}.yml", SmcGet.temp_dir))
|
250
|
-
attributes.each do |att|
|
251
|
-
case att
|
252
|
-
when :name then yield(pkgname) if spec.name =~ regexp
|
253
|
-
when :title then yield(pkgname) if spec.title =~ regexp
|
254
|
-
when :authors then yield(pkgname) if spec.authors.any?{|a| a =~ regexp}
|
255
|
-
when :difficulty then yield(pkgname) if spec.difficulty =~ regexp
|
256
|
-
when :description then yield(pkgname) if spec.description =~ regexp
|
257
|
-
when :levels then yield(pkgname) if spec.levels.any?{|l| l =~ regexp}
|
258
|
-
when :music then yield(pkgname) if spec.music.any?{|m| m =~ regexp}
|
259
|
-
when :sounds then yield(pkgname) if spec.sound.any?{|s| s =~ regexp}
|
260
|
-
when :graphics then yield(pkgname) if spec.graphics.any?{|g| g =~ regexp}
|
261
|
-
when :worlds then yield(pkgname) if spec.worlds.any?{|w| w =~ regexp}
|
262
|
-
else
|
263
|
-
$stderr.puts("Warning: Unknown attribute #{att}, ignoring it.")
|
264
|
-
end #case
|
265
|
-
end #attributes.each
|
266
|
-
end # @packages.each
|
267
|
-
end #if only :name
|
268
|
-
end #search
|
269
|
-
|
270
|
-
end #RemoteRepository
|
271
|
-
|
272
|
-
end #SmcGet
|
1
|
+
#Encoding: UTF-8
|
2
|
+
################################################################################
|
3
|
+
# This file is part of smc-get.
|
4
|
+
# Copyright (C) 2010-2011 Entertaining Software, Inc.
|
5
|
+
# Copyright (C) 2011 Marvin Gülker
|
6
|
+
#
|
7
|
+
# This program is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
################################################################################
|
20
|
+
|
21
|
+
module SmcGet
|
22
|
+
|
23
|
+
#A RemoteRepository represents a web location from which <tt>smc-get</tt>
|
24
|
+
#is able to download packages. The structure of those repositories is
|
25
|
+
#explained in the smcpak.rdoc file in the <i>Repostories</i> section.
|
26
|
+
class RemoteRepository < Repository
|
27
|
+
|
28
|
+
#Name of the remote directory containing the <tt>.smcpak</tt> files.
|
29
|
+
PACKAGES_DIR = "packages"
|
30
|
+
#Name of the remote directory containing the packages specifications.
|
31
|
+
SPECS_DIR = "specs"
|
32
|
+
#Name of the file containg the names of all packages in this repository.
|
33
|
+
LIST_FILE = "packages.lst"
|
34
|
+
#Number of bytes to read while downloading a file.
|
35
|
+
CHUNK_SIZE = 1024
|
36
|
+
|
37
|
+
##
|
38
|
+
# :attr_reader: packages
|
39
|
+
#Returns an array of remote Packages that contains all packages
|
40
|
+
#in this repository. This is a very time-intensive operation, depending
|
41
|
+
#on how many packages the repository contains, because it downloads all
|
42
|
+
#the package specifications of all the packages. It’s not a good idea
|
43
|
+
#to call this.
|
44
|
+
|
45
|
+
#An URI object representing the repository’s URI.
|
46
|
+
attr_reader :uri
|
47
|
+
#A list of all package names (without an extension).
|
48
|
+
attr_reader :packages_list
|
49
|
+
|
50
|
+
#Creates a "new" Repository.
|
51
|
+
#==Parameters
|
52
|
+
#[uri] The URI of the repository, something like
|
53
|
+
# "\http://my-host.org/smc-repo".
|
54
|
+
#==Raises
|
55
|
+
#[InvalidRepository] The repository is either nonexistant or doesn’t obey
|
56
|
+
# the repository structure format.
|
57
|
+
#==Return value
|
58
|
+
#The newly created repository.
|
59
|
+
#==Usage
|
60
|
+
# r = Repository.new("http://myrepo.org")
|
61
|
+
# r = Repository.new("https://my-host.org/smc-repo")
|
62
|
+
# r = Repository.new("ftp://ftp.my-host.org/smc")
|
63
|
+
def initialize(uri)
|
64
|
+
@uri = URI.parse(uri)
|
65
|
+
#Download the packages list. Usually it’s small enough to fit into RAM.
|
66
|
+
begin
|
67
|
+
@packages_list = open("#{@uri}/#{LIST_FILE}"){|tmpfile| tmpfile.read}.split
|
68
|
+
rescue SocketError, Errno::ECONNREFUSED, OpenURI::HTTPError => e #open-uri raises HTTPError even in case of other protocols
|
69
|
+
raise(Errors::InvalidRepository.new(@uri), e.message)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
#Downloads the given package specification from this repository and
|
74
|
+
#places it in +directory+.
|
75
|
+
#
|
76
|
+
#If the file already exists, it’s overwritten.
|
77
|
+
#==Parameters
|
78
|
+
#[spec_file] The package specification file you want to download. It must
|
79
|
+
# end with the <tt>.yml</tt> extension.
|
80
|
+
#[directory] (".") The directory where you want to download the file to.
|
81
|
+
# Created if it doesn’t exist.
|
82
|
+
#==Raises
|
83
|
+
#[NoSuchResourceError] The package name for this specification couldn’t be
|
84
|
+
# found in the repository. Note that the spec may be
|
85
|
+
# there despite of this, but packages not listed
|
86
|
+
# in the repository’s contents file are treated as if
|
87
|
+
# they weren’t there.
|
88
|
+
#==Return value
|
89
|
+
#The path to the downloaded file as a Pathname object.
|
90
|
+
#==Usage
|
91
|
+
# my_repo.fetch_spec("mypackage.yml", "/home/freak/Downloads")
|
92
|
+
#
|
93
|
+
# my_repo.fetch_spec("mypackage.yml")
|
94
|
+
def fetch_spec(spec_file, directory = ".")
|
95
|
+
directory = Pathname.new(directory)
|
96
|
+
pkg_name = spec_file.sub(/\.yml$/, "")
|
97
|
+
goal_file = directory + spec_file
|
98
|
+
|
99
|
+
unless @packages_list.include?(pkg_name)
|
100
|
+
raise(Errors::NoSuchResourceError.new(:spec, spec_file), "Package '#{pkg_name}' not found in the repository!")
|
101
|
+
end
|
102
|
+
|
103
|
+
directory.mktree unless directory.directory?
|
104
|
+
|
105
|
+
#I am quite sure that URI#merge has a bug. Example:
|
106
|
+
# uri = URI.parse("http://www.ruby-lang.org")
|
107
|
+
#Now try to append the path test/test2:
|
108
|
+
# uri2 = uri + "test" + "test2"
|
109
|
+
#What do you think contains uri2? This:
|
110
|
+
# http://www.ruby-lang.org/test2
|
111
|
+
#Something missing, eh? Even more surprising, this one works as
|
112
|
+
#expected:
|
113
|
+
# uri + "test/test2"
|
114
|
+
#The second one is the workaround I use in the following line.
|
115
|
+
open("#{@uri}/#{SPECS_DIR}/#{spec_file}") do |tempfile|
|
116
|
+
File.open(goal_file, "w") do |file|
|
117
|
+
file.write(tempfile.read) #Specs almost ever are small enough to fit in RAM
|
118
|
+
end
|
119
|
+
end
|
120
|
+
goal_file
|
121
|
+
end
|
122
|
+
|
123
|
+
#Downloads the given package from this repository and places it in
|
124
|
+
#+directory+. Yields the package’s total size in bytes and how many
|
125
|
+
#bytes have already been downloaded. If the size is unknown for some
|
126
|
+
#reason, +bytes_total+ is nil. For the last block call, +bytes_total+
|
127
|
+
#and +bytes_done+ are guaranteed to be equal, except if +bytes_total+
|
128
|
+
#couldn’t be determined in which case it’s still nil.
|
129
|
+
#
|
130
|
+
#If the file does already exist in +directory+, it is overwritten.
|
131
|
+
#==Parameters
|
132
|
+
#[pkg_file] The package file you want to download. It must end in
|
133
|
+
# the <tt>.smcpak</tt> extension.
|
134
|
+
#[directory] (".") The directory where you want to download the file to.
|
135
|
+
# Created if it doesn’t exist.
|
136
|
+
#==Raises
|
137
|
+
#[NoSuchPackageError] The package name for this package couldn’t be
|
138
|
+
# found in the repository. Note that the package may be
|
139
|
+
# there despite of this, but packages not listed
|
140
|
+
# in the repository’s contents file are treated as if
|
141
|
+
# they weren’t there.
|
142
|
+
#[OpenURI::HTTPError] Connection error.
|
143
|
+
#==Return value
|
144
|
+
#The path to the downloaded file as a Pathname object.
|
145
|
+
#==Usage
|
146
|
+
# my_repo.fetch_package("mypackage.smcpak", "/home/freak/downloads")
|
147
|
+
#
|
148
|
+
# my_repo.fetch_package("mypackage.smcpak") do |bytes_total, bytes_done|
|
149
|
+
# print("\rDownloaded #{bytes_done} bytes of #{bytes_total}.") if bytes_total
|
150
|
+
# end
|
151
|
+
def fetch_package(pkg_file, directory = ".")
|
152
|
+
directory = Pathname.new(directory)
|
153
|
+
pkg_name = pkg_file.sub(/\.smcpak$/, "")
|
154
|
+
goal_file = directory + pkg_file
|
155
|
+
|
156
|
+
unless @packages_list.include?(pkg_name)
|
157
|
+
raise(Errors::NoSuchPackageError.new(pkg_name), "ERROR: Package '#{pkg_name}' not found in the repository!")
|
158
|
+
end
|
159
|
+
|
160
|
+
directory.mktree unless directory.directory?
|
161
|
+
|
162
|
+
bytes_total = nil
|
163
|
+
size_proc = lambda{|content_length| bytes_total = content_length}
|
164
|
+
prog_proc = lambda{|bytes_done| yield(bytes_total, bytes_done)}
|
165
|
+
|
166
|
+
#See the source of #fetch_spec for an explanation on the obscure
|
167
|
+
#URI concatenation.
|
168
|
+
open("#{@uri}/#{PACKAGES_DIR}/#{pkg_file}", "rb", content_length_proc: size_proc, progress_proc: prog_proc) do |tempfile|
|
169
|
+
#The packages may be too big for fitting into RAM, therefore we’re going
|
170
|
+
#to read and write the packages chunk by chunk. Btw. please notice me
|
171
|
+
#if you find a SMC package that’s larger than 4 GiB! I’d be curious
|
172
|
+
#about what it contains!
|
173
|
+
File.open(goal_file, "wb") do |file|
|
174
|
+
while chunk = tempfile.read(CHUNK_SIZE)
|
175
|
+
file.write(chunk)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
goal_file
|
181
|
+
end
|
182
|
+
|
183
|
+
#Not implemented yet.
|
184
|
+
def install(package, &block)
|
185
|
+
raise(NotImplementedError, "Can't automatically upload to remote repositories yet!")
|
186
|
+
end
|
187
|
+
|
188
|
+
#Not implemented yet.
|
189
|
+
def uninstall(pkg_name)
|
190
|
+
raise(NotImplementedError, "Can't automatically remove from remote repositories yet!")
|
191
|
+
end
|
192
|
+
|
193
|
+
#Returns the URI of the remote repository.
|
194
|
+
def to_s
|
195
|
+
@uri.to_s
|
196
|
+
end
|
197
|
+
|
198
|
+
#See attribute.
|
199
|
+
# def packages # :nodoc:
|
200
|
+
# @packages_list.map do |pkg_name|
|
201
|
+
# Package.from_repository(self, "#{pkg_name}.yml")
|
202
|
+
# end
|
203
|
+
# end
|
204
|
+
|
205
|
+
#True if a package with the given name (without the .smcpak extension)
|
206
|
+
#exists in the repository.
|
207
|
+
def contain?(pkg)
|
208
|
+
if pkg.kind_of? Package
|
209
|
+
@packages_list.include?(pkg.spec.name)
|
210
|
+
else
|
211
|
+
@packages_list.include?(pkg_name)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
alias contains? contain?
|
215
|
+
|
216
|
+
#call-seq:
|
217
|
+
# search(regexp [, *attributes ]){|pkgname|...}
|
218
|
+
#
|
219
|
+
#Searches for a specific package and yields each candidate to the
|
220
|
+
#given block.
|
221
|
+
#==Parameters
|
222
|
+
#[regexp] The Regular Expression to use as the search pattern.
|
223
|
+
#[*attributes] (<tt>[:name]</tt>) A list of all attributes to match
|
224
|
+
# the Regular Expression against (note that only
|
225
|
+
# passing :name is siginificantly faster, because
|
226
|
+
# there’s no need to download the specs).
|
227
|
+
# Possible attributes:
|
228
|
+
# * name
|
229
|
+
# * title
|
230
|
+
# * authors
|
231
|
+
# * difficulty
|
232
|
+
# * description
|
233
|
+
# * levels
|
234
|
+
# * music
|
235
|
+
# * sounds
|
236
|
+
# * graphics
|
237
|
+
# * worlds
|
238
|
+
#[pkgname] *Blockargument*. The package name (not title!) of
|
239
|
+
# a package matching the search criteria.
|
240
|
+
#==Examples
|
241
|
+
# rp.search(/cool/){|pkgname| p pkgname} #=> "cool_levels"
|
242
|
+
# rp.search(/Luiji/i, :authors){|pkgname| p pkgname} #=> All packages created by Luiji or luiji...
|
243
|
+
def search(regexp, *attributes)
|
244
|
+
attributes << :name if attributes.empty? #Default value
|
245
|
+
if attributes == [:name] #Good, no need to download all the specs
|
246
|
+
@packages_list.each{|name| yield(name) if name =~ regexp}
|
247
|
+
else #OK, so we need to download one spec after the other...
|
248
|
+
@packages_list.each do |pkgname|
|
249
|
+
spec = PackageSpecification.from_file(fetch_spec("#{pkgname}.yml", SmcGet.temp_dir))
|
250
|
+
attributes.each do |att|
|
251
|
+
case att
|
252
|
+
when :name then yield(pkgname) if spec.name =~ regexp
|
253
|
+
when :title then yield(pkgname) if spec.title =~ regexp
|
254
|
+
when :authors then yield(pkgname) if spec.authors.any?{|a| a =~ regexp}
|
255
|
+
when :difficulty then yield(pkgname) if spec.difficulty =~ regexp
|
256
|
+
when :description then yield(pkgname) if spec.description =~ regexp
|
257
|
+
when :levels then yield(pkgname) if spec.levels.any?{|l| l =~ regexp}
|
258
|
+
when :music then yield(pkgname) if spec.music.any?{|m| m =~ regexp}
|
259
|
+
when :sounds then yield(pkgname) if spec.sound.any?{|s| s =~ regexp}
|
260
|
+
when :graphics then yield(pkgname) if spec.graphics.any?{|g| g =~ regexp}
|
261
|
+
when :worlds then yield(pkgname) if spec.worlds.any?{|w| w =~ regexp}
|
262
|
+
else
|
263
|
+
$stderr.puts("Warning: Unknown attribute #{att}, ignoring it.")
|
264
|
+
end #case
|
265
|
+
end #attributes.each
|
266
|
+
end # @packages.each
|
267
|
+
end #if only :name
|
268
|
+
end #search
|
269
|
+
|
270
|
+
end #RemoteRepository
|
271
|
+
|
272
|
+
end #SmcGet
|