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.
@@ -1,260 +1,240 @@
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
- module SmcGet
21
-
22
- #Packages are the main objects you will have to deal with. An instance of
23
- #class Package encapsulates all known information from a smc package file
24
- #(these files are described in the smcpak.rdoc file), and the most important
25
- #attribute of this class is +spec+, which is your direct interface to the
26
- #package’s specification by providing you with a fitting instance of class
27
- #PackageSpecification.
28
- #
29
- #Apart from inspecting existing packages, you can also use the Package class
30
- #to create new pacakges by calling the ::create method (inspecting a given
31
- #package file is possible with ::from_file). ::create expects a path to
32
- #the directoy which you want to compress into a new SMC package, validates
33
- #it against the packaging guidelines and will then either fail or do
34
- #the actual compression, outputting an instance of class Package that
35
- #(you guessed it) describes the newly created SMC package.
36
- #
37
- #==Example of building a SMC package
38
- #The following is an example that shows you how to build a basic
39
- #SMC package by use of the ::create method.
40
- #
41
- #First you have to decide how you want to name your package. If you
42
- #have decided (remember: This is a decision for life!), create a
43
- #directory named after the package, note that it isn’t allowed to
44
- #contain whitespace.
45
- #
46
- #Inside the directory, say you named it +cool+, create the following
47
- #structure:
48
- #
49
- # cool/
50
- # - cool.yml
51
- # - README.txt
52
- # levels/
53
- # music/
54
- # pixmaps/
55
- # sounds/
56
- # worlds/
57
- #
58
- #If your package doesn’t contain a specific component, e.g. sounds, you
59
- #may ommit the corresponding directory.
60
- #
61
- #Then add all the levels you want to include in the package to the +levels+
62
- #subdirectory, e.g. if you have a level named "awesome_1" and one named
63
- #"awesome_2", copy them from your personal SMC directory (usually
64
- #<b>~/.smc/levels</b>) so that your structure looks like this:
65
- #
66
- # cool/
67
- # - cool.yml
68
- # - README.txt
69
- # levels/
70
- # - awesome_1.smclvl
71
- # - awesome_2.smclvl
72
- # music/
73
- # pixmaps/
74
- # sounds/
75
- # worlds/
76
- #
77
- #Now the most important step. Open up *cool.yml* in your favourite text
78
- #editor and write the package specification. You can read about the exact
79
- #format with all available options in the smcpak.rdoc file,but for now
80
- #just write the following:
81
- #
82
- # ---
83
- # title: Cool levels
84
- # last_update: 01-01-2011 04:07:00Z
85
- # levels:
86
- # - awesome_1.smclvl
87
- # - awesome_2.smclvl
88
- # authors:
89
- # - Your Name Here
90
- # difficulty: medium
91
- # description: |
92
- # Here goes your description
93
- # which may span multiple lines.
94
- #
95
- #Of course put something appropriate into the +last_update+ field
96
- #(the format is DD-MM-YYYY hh:mm:ssZ, time zone is UTC).
97
- #
98
- #After you wrote something into your README.txt (whatever it is),
99
- #you *could* build the package the easy way with
100
- # $ cd /path/to/dir/above/cool
101
- # $ smc-get build cool
102
- #on the commandline. But I promised you to show the use of
103
- #Package.create, so instead do:
104
- # $ cd /path/to/dir/above/cool
105
- # $ ruby -Ipath/to/smcget/lib -rsmc_get -e 'SmcGet::Package.create("cool")'
106
- #Either way, you should now end up with a file called *cool.smcpak* in the
107
- #parent directory of <b>cool/</b>.
108
- class Package
109
-
110
- #A package name is considered valid if it matches this Regular
111
- #expression.
112
- VALID_PKG_NAME = /^[a-zA-Z_\-0-9]+$/
113
- #Name of the directory the levels reside in the package.
114
- LEVELS_DIR = "levels"
115
- #Name of the directory the music resides in the package.
116
- MUSIC_DIR = "music"
117
- #Name of the directory the sounds reside in the package.
118
- SOUNDS_DIR = "sounds"
119
- #Name of the dierctory the graphics reside in the pacakge.
120
- GRAPHICS_DIR = "pixmaps"
121
- #Name of the directory the worlds reside in the package.
122
- WORLDS_DIR = "worlds"
123
-
124
- #The PackageSpecification of this package.
125
- attr_reader :spec
126
- #The Pathname of the .smcpak file.
127
- attr_reader :path
128
-
129
- class << self
130
-
131
- #Creates a new Package from a local .smcpak file.
132
- #==Parameter
133
- #[file] The path to the SMC package.
134
- #==Return value
135
- #An instance of class Package.
136
- #==Example
137
- # pkg = SmcGet::Package.from_file("/home/freak/mycoolpackage.smcpak")
138
- #==Remarks
139
- #As this needs to decompress the package temporarily, this method
140
- #may take some time to complete.
141
- def from_file(file)
142
- pkg_name = File.basename(file).sub(/\.smcpak$/, "")
143
- #No spec file is provided, we therefore need to extract it from
144
- #the archive.
145
- path = PackageArchive.new(file).decompress(SmcGet.temp_dir) + pkg_name + "#{pkg_name}.yml"
146
- new(path, file)
147
- end
148
-
149
- #Validates +directory+ against the packaging guidelines and compresses it
150
- #into a .smcpak file.
151
- #==Parameter
152
- #[directory] The path to the directory you want to compress.
153
- #==Return value
154
- #An instance of this class describing the newly created package.
155
- #==Example
156
- # pkg = SmcGet::Package.create("/home/freak/mycoollevels")
157
- #==Remarks
158
- #The .smcpak file is placed in the parent
159
- #directory of +directory+, you should therefore ensure you have write
160
- #permissions for it.
161
- def create(directory)
162
- #0. Determine the names of the important files
163
- directory = Pathname.new(directory)
164
- pkg_name = directory.basename.to_s
165
- spec_file = directory + "#{pkg_name}.yml"
166
- readme = directory + "README.txt"
167
- smcpak_file = directory.parent + "#{pkg_name}.smcpak"
168
-
169
- #1. Validate the package name
170
- raise(Errors::BrokenPackageError, "Invalid package name!") unless pkg_name =~ VALID_PKG_NAME
171
-
172
- #2. Validate the package spec
173
- spec = PackageSpecification.from_file(spec_file) #Raises if necessary
174
-
175
- #3. Validate the rest of the structure
176
- $stderr.puts("Warning: No README.txt found.") unless readme.file?
177
- $stderr.puts("Warning: No levels found.") if spec.levels.empty?
178
-
179
- #4. Compress the whole thing
180
- #The process is as follows: A temporary directory is created, in which
181
- #a subdirectory that is named after the package is created. The
182
- #spec, the README and the levels, music, etc. are then copied into
183
- #that subdirectory which in turn is then compressed. The resulting
184
- #.smcpak file is copied back to the original directory’s parent dir.
185
- #After that, the mktmpdir block ends and deletes the temporary
186
- #directory.
187
- path = Dir.mktmpdir("smc-get-create-#{pkg_name}") do |tmpdir|
188
- goal_dir = Pathname.new(tmpdir) + pkg_name
189
- goal_dir.mkdir
190
-
191
- FileUtils.cp(spec_file, goal_dir)
192
- FileUtils.cp(readme, goal_dir) if readme.file? #Optional
193
- [:levels, :graphics, :music, :sounds, :worlds].each do |sym|
194
- #4.1. Create the group’s subdir
195
- dirname = const_get(:"#{sym.upcase}_DIR")
196
- goal_group_dir = goal_dir + dirname
197
- goal_group_dir.mkdir
198
- #4.2. Copy all the group’s files over to it
199
- spec[sym].each do |filename|
200
- FileUtils.cp(directory + dirname + filename, goal_group_dir)
201
- end
202
- end
203
- #4.3. actual compression
204
- PackageArchive.compress(goal_dir, smcpak_file).path
205
- end
206
- #5. Return a new instance of Package
207
- from_file(path)
208
- end
209
-
210
- end
211
-
212
- #Creates a new Package from the given specification file. You shouldn’t
213
- #use this method directly, because you would duplicate the
214
- #work the ::from_file method already does for you.
215
- #==Parameters
216
- #[spec_file] The path to the YAML specification file.
217
- #[pkg_location] The path to the SMC package.
218
- #==Return value
219
- #The newly created Package instance.
220
- #==Example
221
- # pkg = SmcGet::Package.new("/home/freak/cool.yml", "/home/freak/cool.smcpak")
222
- def initialize(spec_file, pkg_location)
223
- @spec = PackageSpecification.from_file(spec_file)
224
- @path = pkg_location
225
- end
226
-
227
- #Decompresses this package.
228
- #==Parameter
229
- #[directory] Where to extract the SMC package to. A subdirectory named after
230
- # the package is automatically created in this directory.
231
- #==Return value
232
- #The Pathname to the created subdirectory.
233
- #==Example
234
- # pkg.decompress(".") #=> /home/freak/cool
235
- def decompress(directory)
236
- PackageArchive.new(@path).decompress(directory)
237
- end
238
-
239
- #Compares two packages. They’re considered equal if their package
240
- #specifications are equal. See PackageSpecification#==.
241
- def ==(other)
242
- return false unless other.respond_to? :spec
243
- @spec == other.spec
244
- end
245
-
246
- #Shorthand for:
247
- # pkg.spec.name
248
- def to_s
249
- @spec.name
250
- end
251
-
252
- #Human-readabe description of form
253
- # #<SmcGet::Package <package name>>
254
- def inspect
255
- "#<#{self.class} #{@spec.name}>"
256
- end
257
-
258
- end
259
-
260
- end
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
+ module SmcGet
21
+
22
+ #Packages are the main objects you will have to deal with. An instance of
23
+ #class Package encapsulates all known information from a smc package file
24
+ #(these files are described in the smcpak.rdoc file), and the most important
25
+ #attribute of this class is +spec+, which is your direct interface to the
26
+ #package’s specification by providing you with a fitting instance of class
27
+ #PackageSpecification.
28
+ #
29
+ #Apart from inspecting existing packages, you can also use the Package class
30
+ #to create new pacakges by calling the ::create method (inspecting a given
31
+ #package file is possible with ::from_file). ::create expects a path to
32
+ #the directoy which you want to compress into a new SMC package, validates
33
+ #it against the packaging guidelines and will then either fail or do
34
+ #the actual compression, outputting an instance of class Package that
35
+ #(you guessed it) describes the newly created SMC package.
36
+ #
37
+ #==Example of building a SMC package
38
+ #The following is an example that shows you how to build a basic
39
+ #SMC package by use of the ::create method.
40
+ #
41
+ #First you have to decide how you want to name your package. If you
42
+ #have decided (remember: This is a decision for life!), create a
43
+ #directory named after the package, note that it isn’t allowed to
44
+ #contain whitespace.
45
+ #
46
+ #Inside the directory, say you named it +cool+, create the following
47
+ #structure:
48
+ #
49
+ # cool/
50
+ # - cool.yml
51
+ # - README.txt
52
+ # levels/
53
+ # music/
54
+ # pixmaps/
55
+ # sounds/
56
+ # worlds/
57
+ #
58
+ #If your package doesn’t contain a specific component, e.g. sounds, you
59
+ #may ommit the corresponding directory.
60
+ #
61
+ #Then add all the levels you want to include in the package to the +levels+
62
+ #subdirectory, e.g. if you have a level named "awesome_1" and one named
63
+ #"awesome_2", copy them from your personal SMC directory (usually
64
+ #<b>~/.smc/levels</b>) so that your structure looks like this:
65
+ #
66
+ # cool/
67
+ # - cool.yml
68
+ # - README.txt
69
+ # levels/
70
+ # - awesome_1.smclvl
71
+ # - awesome_2.smclvl
72
+ # music/
73
+ # pixmaps/
74
+ # sounds/
75
+ # worlds/
76
+ #
77
+ #Now the most important step. Open up *cool.yml* in your favourite text
78
+ #editor and write the package specification. You can read about the exact
79
+ #format with all available options in the smcpak.rdoc file,but for now
80
+ #just write the following:
81
+ #
82
+ # ---
83
+ # title: Cool levels
84
+ # last_update: 01-01-2011 04:07:00Z
85
+ # levels:
86
+ # - awesome_1.smclvl
87
+ # - awesome_2.smclvl
88
+ # authors:
89
+ # - Your Name Here
90
+ # difficulty: medium
91
+ # description: |
92
+ # Here goes your description
93
+ # which may span multiple lines.
94
+ #
95
+ #Of course put something appropriate into the +last_update+ field
96
+ #(the format is DD-MM-YYYY hh:mm:ssZ, time zone is UTC).
97
+ #
98
+ #After you wrote something into your README.txt (whatever it is),
99
+ #you *could* build the package the easy way with
100
+ # $ cd /path/to/dir/above/cool
101
+ # $ smc-get build cool
102
+ #on the commandline. But I promised you to show the use of
103
+ #Package.create, so instead do:
104
+ # $ cd /path/to/dir/above/cool
105
+ # $ ruby -Ipath/to/smcget/lib -rsmc_get -e 'SmcGet::Package.create("cool")'
106
+ #Either way, you should now end up with a file called *cool.smcpak* in the
107
+ #parent directory of <b>cool/</b>.
108
+ class Package
109
+
110
+ #A package name is considered valid if it matches this Regular
111
+ #expression.
112
+ VALID_PKG_NAME = /^[a-zA-Z_\-0-9]+$/
113
+ #Name of the directory the levels reside in the package.
114
+ LEVELS_DIR = "levels"
115
+ #Name of the directory the music resides in the package.
116
+ MUSIC_DIR = "music"
117
+ #Name of the directory the sounds reside in the package.
118
+ SOUNDS_DIR = "sounds"
119
+ #Name of the dierctory the graphics reside in the pacakge.
120
+ GRAPHICS_DIR = "pixmaps"
121
+ #Name of the directory the worlds reside in the package.
122
+ WORLDS_DIR = "worlds"
123
+
124
+ #The PackageSpecification of this package.
125
+ attr_reader :spec
126
+ #The Pathname of the .smcpak file.
127
+ attr_reader :path
128
+
129
+ class << self
130
+
131
+ #Creates a new Package from a local .smcpak file.
132
+ #==Parameter
133
+ #[file] The path to the SMC package.
134
+ #==Return value
135
+ #An instance of class Package.
136
+ #==Example
137
+ # pkg = SmcGet::Package.from_file("/home/freak/mycoolpackage.smcpak")
138
+ #==Remarks
139
+ #As this needs to decompress the package temporarily, this method
140
+ #may take some time to complete.
141
+ def from_file(file)
142
+ pkg_name = File.basename(file).sub(/\.smcpak$/, "")
143
+ #No spec file is provided, we therefore need to extract it from
144
+ #the archive.
145
+ path = PackageArchive.new(file).decompress(SmcGet.temp_dir) + pkg_name + "#{pkg_name}.yml"
146
+ new(path, file)
147
+ end
148
+
149
+ #Validates +directory+ against the packaging guidelines and compresses it
150
+ #into a .smcpak file.
151
+ #==Parameter
152
+ #[directory] The path to the directory you want to compress.
153
+ #==Return value
154
+ #An instance of this class describing the newly created package.
155
+ #==Example
156
+ # pkg = SmcGet::Package.create("/home/freak/mycoollevels")
157
+ #==Remarks
158
+ #The .smcpak file is placed in the parent
159
+ #directory of +directory+, you should therefore ensure you have write
160
+ #permissions for it.
161
+ def create(directory)
162
+ #0. Determine the names of the important files
163
+ directory = Pathname.new(directory)
164
+ pkg_name = directory.basename.to_s
165
+ spec_file = directory + "#{pkg_name}.yml"
166
+ readme = directory + "README.txt"
167
+ smcpak_file = directory.parent + "#{pkg_name}.smcpak"
168
+
169
+ #1. Validate the package name
170
+ raise(Errors::BrokenPackageError, "Invalid package name!") unless pkg_name =~ VALID_PKG_NAME
171
+
172
+ #2. Validate the package spec
173
+ spec = PackageSpecification.from_file(spec_file) #Raises if necessary
174
+
175
+ #3. Validate the rest of the structure
176
+ %w[levels pixmaps music sounds worlds].each do |str|
177
+ dir = directory + str
178
+ raise(Errors::BrokenPackageError, "Directory #{str} missing!") unless dir.directory?
179
+ end
180
+
181
+ #Warnings
182
+ $stderr.puts("Warning: No README.txt found.") unless readme.file?
183
+ $stderr.puts("Warning: No levels found.") if spec.levels.empty?
184
+
185
+ #4. Compress the whole thing
186
+ path = PackageArchive.compress(directory, smcpak_file).path
187
+ from_file(path)
188
+ end
189
+
190
+ end
191
+
192
+ #Creates a new Package from the given specification file. You shouldn’t
193
+ #use this method directly, because you would duplicate the
194
+ #work the ::from_file method already does for you.
195
+ #==Parameters
196
+ #[spec_file] The path to the YAML specification file.
197
+ #[pkg_location] The path to the SMC package.
198
+ #==Return value
199
+ #The newly created Package instance.
200
+ #==Example
201
+ # pkg = SmcGet::Package.new("/home/freak/cool.yml", "/home/freak/cool.smcpak")
202
+ def initialize(spec_file, pkg_location)
203
+ @spec = PackageSpecification.from_file(spec_file)
204
+ @path = pkg_location
205
+ end
206
+
207
+ #Decompresses this package.
208
+ #==Parameter
209
+ #[directory] Where to extract the SMC package to. A subdirectory named after
210
+ # the package is automatically created in this directory.
211
+ #==Return value
212
+ #The Pathname to the created subdirectory.
213
+ #==Example
214
+ # pkg.decompress(".") #=> /home/freak/cool
215
+ def decompress(directory)
216
+ PackageArchive.new(@path).decompress(directory)
217
+ end
218
+
219
+ #Compares two packages. They’re considered equal if their package
220
+ #specifications are equal. See PackageSpecification#==.
221
+ def ==(other)
222
+ return false unless other.respond_to? :spec
223
+ @spec == other.spec
224
+ end
225
+
226
+ #Shorthand for:
227
+ # pkg.spec.name
228
+ def to_s
229
+ @spec.name
230
+ end
231
+
232
+ #Human-readabe description of form
233
+ # #<SmcGet::Package <package name>>
234
+ def inspect
235
+ "#<#{self.class} #{@spec.name}>"
236
+ end
237
+
238
+ end
239
+
240
+ end