zypper 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +16 -0
- data/LICENSE +22 -0
- data/README.markdown +421 -0
- data/VERSION +1 -0
- data/lib/zypper.rb +55 -0
- data/lib/zypper/config.rb +91 -0
- data/lib/zypper/package.rb +115 -0
- data/lib/zypper/patch.rb +113 -0
- data/lib/zypper/repository.rb +35 -0
- data/lib/zypper/service.rb +19 -0
- data/lib/zypper/utils.rb +197 -0
- data/lib/zypper/version.rb +4 -0
- metadata +135 -0
data/CHANGELOG
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
0.0.9 (2012-06-26)
|
2
|
+
------------------
|
3
|
+
* Split into smaller one-task libraries
|
4
|
+
* Added plural aliases for for accessing subclasses (patch -> patches,
|
5
|
+
package -> packages, ...)
|
6
|
+
* Generic package search
|
7
|
+
* Extended Patch with applicable?() and install() methods
|
8
|
+
* Added testsuites
|
9
|
+
* Packaging into gem
|
10
|
+
|
11
|
+
0.0.1 (2012-06-20)
|
12
|
+
------------------
|
13
|
+
* Initial implementation using POpen4
|
14
|
+
* Added Services and Repositories handling
|
15
|
+
* Added Packages and Packages handling
|
16
|
+
* Added documentation
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
=====================
|
3
|
+
|
4
|
+
Copyright (c) 2012 Lukas Ocilka
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
7
|
+
this software and associated documentation files (the "Software"), to deal in
|
8
|
+
the Software without restriction, including without limitation the rights to
|
9
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
10
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
11
|
+
so, subject to the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
14
|
+
copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
22
|
+
SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,421 @@
|
|
1
|
+
# Zypper Library #
|
2
|
+
|
3
|
+
This library provides Ruby access to libzypp using the
|
4
|
+
`zypper` command.
|
5
|
+
|
6
|
+
## License ##
|
7
|
+
|
8
|
+
Distributed under the MIT license, see LICENSE file.
|
9
|
+
|
10
|
+
## Features ###
|
11
|
+
|
12
|
+
* Easy-to-use API
|
13
|
+
* Running zypper in chroot or running your system zypper over a different root directory
|
14
|
+
* Handling packages, repositories and patches
|
15
|
+
* Easy to extend
|
16
|
+
|
17
|
+
## Usage ##
|
18
|
+
|
19
|
+
Require the library
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
require "zypper"
|
23
|
+
```
|
24
|
+
|
25
|
+
Initialize new access to the library methods
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
zypper = Zypper.new()
|
29
|
+
```
|
30
|
+
|
31
|
+
Add a new repository
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
zypper.repository.add(:url => 'http://example.org/new/repo', :alias => 'Repo_at_Example_Org')
|
35
|
+
```
|
36
|
+
|
37
|
+
## Public Methods ##
|
38
|
+
|
39
|
+
### Global ###
|
40
|
+
|
41
|
+
#### Constructor ###
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
zypper = Zypper.new(parameters)
|
45
|
+
# or
|
46
|
+
config = Zypper::Config.new(parameters)
|
47
|
+
zypper = Zypper.new(config)
|
48
|
+
```
|
49
|
+
|
50
|
+
All parameters are optional, using their default value if not set.
|
51
|
+
|
52
|
+
Possible parameters in hash:
|
53
|
+
* :root => '/changed-root' - defaults to '/'
|
54
|
+
* :chroot_method => 'local' (calls local zypper with changed root) or 'chroot' (calls zypper in chroot)
|
55
|
+
* :refresh_repo => true or false - default for all newly added repositories
|
56
|
+
* :auto_agree_with_licenses => true or false - default for installing packages, applying patches...
|
57
|
+
|
58
|
+
Example:
|
59
|
+
```ruby
|
60
|
+
zypper = Zypper.new(:chroot => '/some-chroot-dir', :chroot_method => 'chroot')
|
61
|
+
```
|
62
|
+
|
63
|
+
#### Zypper Output ####
|
64
|
+
|
65
|
+
These methods work after calling all API functions:
|
66
|
+
|
67
|
+
* last_message - unparsed STDOUT of the last zypper call
|
68
|
+
* last_error_message - unparsed STDERR of the last zypper call
|
69
|
+
* last_exit_status - exit code (integer) of the last zypper call
|
70
|
+
|
71
|
+
Example:
|
72
|
+
```ruby
|
73
|
+
zypper.last_message
|
74
|
+
```
|
75
|
+
|
76
|
+
#### Zypper Version ####
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
version
|
80
|
+
|
81
|
+
# returns
|
82
|
+
{:major=>1, :minor=>3, :revision=>7}
|
83
|
+
```
|
84
|
+
|
85
|
+
#### Caches Cleanup ####
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
clean_caches
|
89
|
+
|
90
|
+
# returns
|
91
|
+
true or false
|
92
|
+
```
|
93
|
+
|
94
|
+
#### Importing All used GPG Keys ####
|
95
|
+
|
96
|
+
```ruby
|
97
|
+
auto_import_keys
|
98
|
+
|
99
|
+
# returns
|
100
|
+
true or false
|
101
|
+
```
|
102
|
+
|
103
|
+
### Repositories ###
|
104
|
+
|
105
|
+
You can access the repositories class either with
|
106
|
+
```ruby
|
107
|
+
zypper = Zypper.new
|
108
|
+
zypper.repository
|
109
|
+
# or
|
110
|
+
zypper.repositories
|
111
|
+
```
|
112
|
+
or
|
113
|
+
```ruby
|
114
|
+
Zypper::Repository.new
|
115
|
+
```
|
116
|
+
|
117
|
+
#### Listing repositories ####
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
zypper.repositories.all
|
121
|
+
|
122
|
+
# returns
|
123
|
+
[
|
124
|
+
{ "enabled"=>"1", "autorefresh"=>"1", "name"=>"SLES11-SP1-x68_64", "url"=>["http://repo/URI"],
|
125
|
+
"type"=>"rpm-md", "alias"=>"repository_alias", "gpgcheck"=>"1" },
|
126
|
+
{ ... },
|
127
|
+
...
|
128
|
+
]
|
129
|
+
```
|
130
|
+
|
131
|
+
#### Adding a Repository ####
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
zypper.repository.add(:url => 'http://repository/URI', :alias => 'repository_alias')
|
135
|
+
|
136
|
+
# returns
|
137
|
+
true or false
|
138
|
+
```
|
139
|
+
|
140
|
+
Example:
|
141
|
+
```ruby
|
142
|
+
Zypper.new.repository.add(:url => 'http://repository/URI', :alias => 'repository_alias')
|
143
|
+
# or
|
144
|
+
Zypper::Repository.new.add(:url => 'http://repository/URI', :alias => 'repository_alias')
|
145
|
+
```
|
146
|
+
|
147
|
+
#### Removing a Repository ####
|
148
|
+
|
149
|
+
```ruby
|
150
|
+
zypper.repository.remove(:alias => 'repository_alias')
|
151
|
+
|
152
|
+
# returns
|
153
|
+
true or false
|
154
|
+
```
|
155
|
+
|
156
|
+
#### Refreshing Repositories ####
|
157
|
+
|
158
|
+
```ruby
|
159
|
+
zypper.repository.refresh(parameters)
|
160
|
+
|
161
|
+
# returns
|
162
|
+
true or false
|
163
|
+
```
|
164
|
+
|
165
|
+
Possible optional parameters:
|
166
|
+
* :force - forces a complete refresh
|
167
|
+
* :force_build - forces rebuild of the database
|
168
|
+
|
169
|
+
### Services ###
|
170
|
+
|
171
|
+
You can access the services class either with
|
172
|
+
```ruby
|
173
|
+
zypper = Zypper.new
|
174
|
+
zypper.service
|
175
|
+
# or
|
176
|
+
zypper.services
|
177
|
+
```
|
178
|
+
or
|
179
|
+
```ruby
|
180
|
+
Zypper::Service.new
|
181
|
+
```
|
182
|
+
|
183
|
+
#### Listing Services ####
|
184
|
+
|
185
|
+
```ruby
|
186
|
+
zypper.services.all
|
187
|
+
```
|
188
|
+
|
189
|
+
Example:
|
190
|
+
```ruby
|
191
|
+
Zypper.new.services.all
|
192
|
+
# or
|
193
|
+
Zypper::Services.new.all
|
194
|
+
```
|
195
|
+
|
196
|
+
#### Refreshing Services ####
|
197
|
+
|
198
|
+
```ruby
|
199
|
+
zypper.services.refresh
|
200
|
+
|
201
|
+
# returns
|
202
|
+
true or false
|
203
|
+
```
|
204
|
+
|
205
|
+
### Packages ###
|
206
|
+
|
207
|
+
#### Installing Packages ####
|
208
|
+
|
209
|
+
You can access the packages class either with
|
210
|
+
```ruby
|
211
|
+
zypper = Zypper.new
|
212
|
+
zypper.package
|
213
|
+
# or
|
214
|
+
zypper.packages
|
215
|
+
```
|
216
|
+
or
|
217
|
+
```ruby
|
218
|
+
Zypper::Package.new
|
219
|
+
```
|
220
|
+
|
221
|
+
```ruby
|
222
|
+
zypper.packages.install(:packages => ['package', 'package', ...])
|
223
|
+
|
224
|
+
# returns
|
225
|
+
true or false
|
226
|
+
```
|
227
|
+
|
228
|
+
`package` string can consist of NAME[.ARCH][OP<VERSION>], where OP is one
|
229
|
+
of <, <=, =, >=, >, for example:
|
230
|
+
|
231
|
+
```ruby
|
232
|
+
zypper.package.install :packages => ['less.x86_64=424b-10.22']
|
233
|
+
```
|
234
|
+
|
235
|
+
#### Removing Packages ####
|
236
|
+
|
237
|
+
```ruby
|
238
|
+
zypper.packages.remove(:packages => ['package', 'package', ...])
|
239
|
+
|
240
|
+
# returns
|
241
|
+
true or false
|
242
|
+
```
|
243
|
+
|
244
|
+
`package` string can consist of NAME[.ARCH][OP<VERSION>], where OP is one
|
245
|
+
of <, <=, =, >=, >, for example:
|
246
|
+
|
247
|
+
```ruby
|
248
|
+
zypper.package.remove :packages => ['less.x86_64=424b-10.22']
|
249
|
+
```
|
250
|
+
|
251
|
+
#### Installed Packages ####
|
252
|
+
|
253
|
+
Lists all installed packages.
|
254
|
+
|
255
|
+
```ruby
|
256
|
+
zypper.packages.installed
|
257
|
+
|
258
|
+
# returns
|
259
|
+
[
|
260
|
+
{
|
261
|
+
:type=>"package", :status=>:installed, :summary=>"Package, Patch, Pattern, and Product Management",
|
262
|
+
:name=>"libzypp"
|
263
|
+
},
|
264
|
+
{ ... },
|
265
|
+
...
|
266
|
+
]
|
267
|
+
```
|
268
|
+
|
269
|
+
#### Available Packages ####
|
270
|
+
|
271
|
+
```ruby
|
272
|
+
zypper.packages.available
|
273
|
+
|
274
|
+
# returns
|
275
|
+
[
|
276
|
+
{
|
277
|
+
:type=>"package", :status=>:available, :summary=>"Helper that makes writing ...",
|
278
|
+
:name=>"zypp-plugin-python"
|
279
|
+
},
|
280
|
+
{ ... },
|
281
|
+
...
|
282
|
+
]
|
283
|
+
```
|
284
|
+
|
285
|
+
#### Packages Search ####
|
286
|
+
|
287
|
+
```ruby
|
288
|
+
zypper.packages.find
|
289
|
+
|
290
|
+
# returns
|
291
|
+
[
|
292
|
+
... list of packages ...
|
293
|
+
]
|
294
|
+
```
|
295
|
+
|
296
|
+
Example
|
297
|
+
```ruby
|
298
|
+
# All packages with name 'kernel-default'
|
299
|
+
zypper.packages.find(:name => 'kernel-default')
|
300
|
+
|
301
|
+
# All available packages matching zypp*
|
302
|
+
zypper.packages.find(:name => 'zypp*', :status => :available)
|
303
|
+
|
304
|
+
# All installed packages
|
305
|
+
zypper.packages.find(:status => :installed)
|
306
|
+
```
|
307
|
+
|
308
|
+
#### Package Info ####
|
309
|
+
|
310
|
+
```ruby
|
311
|
+
zypper.package.info(:package => 'package')
|
312
|
+
|
313
|
+
# Returns, e.g.
|
314
|
+
{
|
315
|
+
:status=>"not installed", :version=>"424b-10.22",
|
316
|
+
:summary=>"Text File Browser and Pager Similar to more", :arch=>"x86_64",
|
317
|
+
:repository=>"SLES11-SP1-x68_64", :size=>"266.0 KiB",
|
318
|
+
:vendor=>"SUSE LINUX Products GmbH, Nuernberg, Germany",
|
319
|
+
:name=>"less", :installed=>"No", :level=>"Level 3"
|
320
|
+
}
|
321
|
+
```
|
322
|
+
|
323
|
+
#### Package Installed? ####
|
324
|
+
|
325
|
+
```ruby
|
326
|
+
zypper.package.installed?(:package => 'package')
|
327
|
+
|
328
|
+
# returns
|
329
|
+
true or false
|
330
|
+
```
|
331
|
+
|
332
|
+
### Patches ###
|
333
|
+
|
334
|
+
You can access the patches class either with
|
335
|
+
|
336
|
+
```ruby
|
337
|
+
zypper = Zypper.new
|
338
|
+
zypper.patch
|
339
|
+
# or
|
340
|
+
zypper.patches
|
341
|
+
```
|
342
|
+
or
|
343
|
+
```ruby
|
344
|
+
Zypper::patch.new
|
345
|
+
```
|
346
|
+
|
347
|
+
#### Listing Patches ####
|
348
|
+
|
349
|
+
All known patches
|
350
|
+
|
351
|
+
```ruby
|
352
|
+
zypper.patches.all
|
353
|
+
```
|
354
|
+
|
355
|
+
#### Searching for Patches ####
|
356
|
+
|
357
|
+
```ruby
|
358
|
+
zypper.patches.find(filter_parameters)
|
359
|
+
|
360
|
+
# returns
|
361
|
+
[
|
362
|
+
{ :status=>'Needed', :category=>'Recommended', :name=>'patch-name',
|
363
|
+
:version=>'patch-version', :catalog=>"repository-name"
|
364
|
+
},
|
365
|
+
{ ... },
|
366
|
+
...
|
367
|
+
]
|
368
|
+
```
|
369
|
+
All parameters are optional and can be combined, using their default value if not set.
|
370
|
+
|
371
|
+
Possible parameters in hash:
|
372
|
+
|
373
|
+
* :status => 'Status' (see Zypper::Patch::Status class constants)
|
374
|
+
* :category => 'Category' (See Zypper::Patch::Category class constants)
|
375
|
+
* :name => 'Exact-Name'
|
376
|
+
* :version => 'Exact-Version'
|
377
|
+
* :catalog => 'Alias-of-the-repo'
|
378
|
+
|
379
|
+
Example:
|
380
|
+
```ruby
|
381
|
+
zypper.patches.all(
|
382
|
+
:status => Zypper::Patch::Status::INSTALLED,
|
383
|
+
:category => Zypper::Patch::Category::RECOMMENDED
|
384
|
+
)
|
385
|
+
```
|
386
|
+
|
387
|
+
#### Applicable Patches ####
|
388
|
+
|
389
|
+
Lists all applicable patches. All filter parameters are optional and can
|
390
|
+
be used the same as for the `find()` method.
|
391
|
+
|
392
|
+
```ruby
|
393
|
+
zypper.patches.applicable(filter_parameters)
|
394
|
+
```
|
395
|
+
|
396
|
+
#### Any Applicable Patches? ####
|
397
|
+
|
398
|
+
Returns whether there are any applicable patches present.
|
399
|
+
All filter parameters are optional and can be used the same as for the
|
400
|
+
`find()` method.
|
401
|
+
|
402
|
+
```ruby
|
403
|
+
zypper.patches.applicable?(filter_parameters)
|
404
|
+
```
|
405
|
+
|
406
|
+
#### Installed Patches
|
407
|
+
|
408
|
+
Lists all installed patches. All filter parameters are optional and can
|
409
|
+
be used the same as for the `find()` method.
|
410
|
+
|
411
|
+
```ruby
|
412
|
+
zypper.patches.installed(filter_parameters)
|
413
|
+
```
|
414
|
+
|
415
|
+
#### Install Patches ####
|
416
|
+
|
417
|
+
Installs all applicable patches.
|
418
|
+
|
419
|
+
```ruby
|
420
|
+
zypper.patches.install
|
421
|
+
```
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.2.0
|
data/lib/zypper.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'zypper/utils'
|
2
|
+
|
3
|
+
require 'zypper/repository'
|
4
|
+
require 'zypper/service'
|
5
|
+
require 'zypper/package'
|
6
|
+
require 'zypper/patch'
|
7
|
+
|
8
|
+
class Zypper
|
9
|
+
include ZypperUtils
|
10
|
+
|
11
|
+
attr_reader :repository, :service, :package, :patch
|
12
|
+
|
13
|
+
alias :repositories :repository
|
14
|
+
alias :services :service
|
15
|
+
alias :packages :package
|
16
|
+
alias :patches :patch
|
17
|
+
|
18
|
+
def initialize(params = {})
|
19
|
+
super(params)
|
20
|
+
|
21
|
+
self.repository = Zypper::Repository.new config
|
22
|
+
self.service = Zypper::Service.new config
|
23
|
+
self.package = Zypper::Package.new config
|
24
|
+
self.patch = Zypper::Patch.new config
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns the current zypper version
|
28
|
+
def version(options = {})
|
29
|
+
if (run(build_command('version', options = {})))
|
30
|
+
version_number(last_message, options)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Cleans the libzypp cache
|
35
|
+
def clean_caches(options = {})
|
36
|
+
run build_command('clean', options)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Auto-imports all GPG keys from repositories
|
40
|
+
def auto_import_keys(options = {})
|
41
|
+
previous_auto_import_gpg = config.auto_import_gpg
|
42
|
+
ret = repositories.refresh
|
43
|
+
config.auto_import_gpg = previous_auto_import_gpg
|
44
|
+
ret
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
attr_writer :repository, :service, :package, :patch
|
50
|
+
|
51
|
+
def version_number(version_string, options)
|
52
|
+
version = version_string.gsub(/[^0-9\.]/, '').split('.')
|
53
|
+
{:major => version[0].to_i, :minor => version[1].to_i, :revision => version[2].to_i}
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
class Zypper
|
5
|
+
class Config
|
6
|
+
|
7
|
+
DEFAULT_ROOT = '/'
|
8
|
+
DEFAULT_IMPORT_GPG = true
|
9
|
+
DEFAULT_REFRESH_REPO = true
|
10
|
+
DEFAULT_AUTO_AGREE_WITH_LICENSES = true
|
11
|
+
DEFAULT_CHROOT_METHOD = 'local'
|
12
|
+
|
13
|
+
CHROOT_METHOD_LOCAL = 'local'
|
14
|
+
CHROOT_METHOD_CHROOT = 'chroot'
|
15
|
+
KNOWN_CHROOT_METHODS = [CHROOT_METHOD_LOCAL, CHROOT_METHOD_CHROOT]
|
16
|
+
|
17
|
+
# Constructor
|
18
|
+
#
|
19
|
+
# Possible parameters
|
20
|
+
# (string) :root
|
21
|
+
# Defines the changed root environment, default '/'
|
22
|
+
# (boolean) :auto_import_gpg
|
23
|
+
# Automatically trust (and import) new GPG keys, default true
|
24
|
+
# (boolean) :refresh_repo
|
25
|
+
# Adds new repositories with autorefresh flag, default true
|
26
|
+
# (string) :chroot_method
|
27
|
+
# Defines which zypper is used; 'local' uses the local zypper with
|
28
|
+
# changed root directory specified as --root parameter whereas
|
29
|
+
# 'chroot' uses chroot binary and calls zypper directly in the
|
30
|
+
# :root directory. This can be ignored if changed :root is not
|
31
|
+
# defined
|
32
|
+
# (boolean :auto_agree_with_licenses
|
33
|
+
# automatically accept all licenses, otherwise such packages
|
34
|
+
# cannot be installed
|
35
|
+
def initialize(params = {})
|
36
|
+
self.root = (params[:root] || DEFAULT_ROOT)
|
37
|
+
self.chroot_method = (params[:chroot_method] || DEFAULT_CHROOT_METHOD)
|
38
|
+
|
39
|
+
@auto_import_gpg = (params[:auto_import_gpg] || DEFAULT_IMPORT_GPG)
|
40
|
+
@refresh_repo = (params[:refresh_repo] || DEFAULT_REFRESH_REPO)
|
41
|
+
@auto_agree_with_licenses = (params[:auto_agree_with_licenses] || DEFAULT_AUTO_AGREE_WITH_LICENSES)
|
42
|
+
end
|
43
|
+
|
44
|
+
attr_accessor :auto_import_gpg
|
45
|
+
|
46
|
+
attr_reader :root, :chroot_method
|
47
|
+
|
48
|
+
# Changes the current root directory, the directory must exist
|
49
|
+
def root=(new_root)
|
50
|
+
if ! File.exists? new_root
|
51
|
+
raise "Directory #{new_root} does not exist"
|
52
|
+
elsif ! File.directory? new_root
|
53
|
+
raise "#{new_root} is not a directory"
|
54
|
+
end
|
55
|
+
|
56
|
+
@root = new_root
|
57
|
+
end
|
58
|
+
|
59
|
+
# Changes the current chroot method, see constructor for possible values
|
60
|
+
def chroot_method=(new_chroot_method)
|
61
|
+
unless KNOWN_CHROOT_METHODS.include? new_chroot_method
|
62
|
+
raise "Unknown chroot method #{new_chroot_method}, possible are #{KNOWN_CHROOT_METHODS.join(', ')}"
|
63
|
+
end
|
64
|
+
|
65
|
+
@chroot_method = new_chroot_method
|
66
|
+
end
|
67
|
+
|
68
|
+
# Using chroot command
|
69
|
+
def chrooted?
|
70
|
+
chroot_method == CHROOT_METHOD_CHROOT
|
71
|
+
end
|
72
|
+
|
73
|
+
# Using zypper --root of the root is actually different
|
74
|
+
def changed_root?
|
75
|
+
root != DEFAULT_ROOT && chroot_method == CHROOT_METHOD_LOCAL
|
76
|
+
end
|
77
|
+
|
78
|
+
def auto_import_gpg?
|
79
|
+
@auto_import_gpg
|
80
|
+
end
|
81
|
+
|
82
|
+
def auto_agree_with_licenses?
|
83
|
+
@auto_agree_with_licenses
|
84
|
+
end
|
85
|
+
|
86
|
+
def refresh_repo?
|
87
|
+
@refresh_repo
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'zypper/utils'
|
2
|
+
|
3
|
+
class Zypper
|
4
|
+
class Package
|
5
|
+
include ZypperUtils
|
6
|
+
|
7
|
+
class Status
|
8
|
+
INSTALLED = :installed
|
9
|
+
AVAILABLE = :uninstalled
|
10
|
+
end
|
11
|
+
|
12
|
+
PACKAGE_STATUSES = {
|
13
|
+
'' => Status::AVAILABLE,
|
14
|
+
'i' => Status::INSTALLED,
|
15
|
+
}
|
16
|
+
|
17
|
+
# Installs packages given as parmeter
|
18
|
+
# (array) :packages
|
19
|
+
def install(options = {})
|
20
|
+
run build_command('install', options)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Removes packages given as parmeter
|
24
|
+
# (array) :packages
|
25
|
+
def remove(options = {})
|
26
|
+
run build_command('remove', options)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns hash of information on a package given as parameter
|
30
|
+
# (string) :package
|
31
|
+
def info(options = {})
|
32
|
+
if (run(build_command('info', options)))
|
33
|
+
convert_info(last_message)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# returns whether a package given as parameter is installed
|
38
|
+
# (string) :package
|
39
|
+
def installed?(options = {})
|
40
|
+
info(options).fetch(Status::INSTALLED, 'No') == 'Yes'
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns packages found using given parameters
|
44
|
+
#
|
45
|
+
# @param (Hash) of options
|
46
|
+
# (string) :name - exact name of a package
|
47
|
+
# (symbol) :status - See Zypper::Package::Status class constants
|
48
|
+
def find(options = {})
|
49
|
+
additional_options = {:cmd_options => ['--type package'], :quiet => true}
|
50
|
+
|
51
|
+
if (run (build_command('search', options.merge(additional_options))))
|
52
|
+
convert_packages(last_message)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns all installed packages
|
57
|
+
def installed(options = {})
|
58
|
+
find(options.merge(:status => Status::INSTALLED))
|
59
|
+
end
|
60
|
+
|
61
|
+
# Returns all available packages (that are not installed yet)
|
62
|
+
def available(options = {})
|
63
|
+
find(options.merge(:status => Status::AVAILABLE))
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def status(status)
|
69
|
+
return PACKAGE_STATUSES[status] if PACKAGE_STATUSES[status]
|
70
|
+
|
71
|
+
raise "Unknown package status '#{status}'"
|
72
|
+
end
|
73
|
+
|
74
|
+
# SLE11 zypper doesn't support XML output for packages
|
75
|
+
# FIXME: merge with 'convert_patches'
|
76
|
+
def convert_packages(packages)
|
77
|
+
out = []
|
78
|
+
table_index = 0
|
79
|
+
package = {}
|
80
|
+
|
81
|
+
packages.split("\n").each {|line|
|
82
|
+
table_index = table_index + 1
|
83
|
+
# Skip the first two - table header
|
84
|
+
next if table_index < 3
|
85
|
+
|
86
|
+
line.gsub!(/ +\| +/, '|')
|
87
|
+
line.gsub!(/^ +/, '')
|
88
|
+
line.gsub!(/ +$/, '')
|
89
|
+
package = line.split '|'
|
90
|
+
|
91
|
+
out.push(
|
92
|
+
:status => status(package[0]),
|
93
|
+
:name => package[1],
|
94
|
+
:summary => package[2],
|
95
|
+
:type => package[3]
|
96
|
+
)
|
97
|
+
}
|
98
|
+
|
99
|
+
out
|
100
|
+
end
|
101
|
+
|
102
|
+
def convert_info(info)
|
103
|
+
out = {}
|
104
|
+
|
105
|
+
info.split("\n").each do |line|
|
106
|
+
if /([[:alnum:]]+): (.+)/.match(line)
|
107
|
+
out[$1.downcase.to_sym] = $2
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
out
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
data/lib/zypper/patch.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'zypper/utils'
|
2
|
+
|
3
|
+
class Zypper
|
4
|
+
class Patch
|
5
|
+
class Status
|
6
|
+
NEEDED = 'Needed'
|
7
|
+
INSTALLED = 'Installed'
|
8
|
+
NOT_APPLICABLE = 'Not Applicable'
|
9
|
+
end
|
10
|
+
|
11
|
+
class Category
|
12
|
+
SECURITY = 'security'
|
13
|
+
RECOMMENDED = 'recommended'
|
14
|
+
FEATURE = 'feature'
|
15
|
+
OPTIONAL = 'optional'
|
16
|
+
end
|
17
|
+
|
18
|
+
include ZypperUtils
|
19
|
+
|
20
|
+
FILTER_OPTIONS = [:repository, :name, :version, :category, :status]
|
21
|
+
|
22
|
+
# Lists all patches
|
23
|
+
#
|
24
|
+
# @param Hash with optional key :where (Hash)
|
25
|
+
# that can consist of one or more parameters from
|
26
|
+
# :repository, :name, :version, :category, and :status.
|
27
|
+
# Logical AND is always applied for all the options present
|
28
|
+
#
|
29
|
+
# @example
|
30
|
+
# all(:status => 'Installed')
|
31
|
+
def find(options = {})
|
32
|
+
additional_options = {:quiet => true}
|
33
|
+
|
34
|
+
if (run(build_command('patches', options.merge(additional_options))))
|
35
|
+
apply_filters(convert_patches(last_message), options)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Lists all known patches
|
40
|
+
def all(options = {})
|
41
|
+
find
|
42
|
+
end
|
43
|
+
|
44
|
+
# All applicable patches
|
45
|
+
def applicable(options = {})
|
46
|
+
find(options.merge(:status => Status::NEEDED))
|
47
|
+
end
|
48
|
+
|
49
|
+
# Are there any applicable patches present?
|
50
|
+
def applicable?(options = {})
|
51
|
+
applicable(options).size > 0
|
52
|
+
end
|
53
|
+
|
54
|
+
# Installs all applicable patches
|
55
|
+
def install(options = {})
|
56
|
+
|
57
|
+
run(build_command('patch', options))
|
58
|
+
end
|
59
|
+
|
60
|
+
# All installed patches
|
61
|
+
def installed(options = {})
|
62
|
+
find(options.merge(:status => Status::INSTALLED))
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
# Current libzypp doesn't support XML output for patches
|
68
|
+
def convert_patches(patches)
|
69
|
+
out = []
|
70
|
+
table_index = 0
|
71
|
+
patch = {}
|
72
|
+
|
73
|
+
patches.split("\n").each {|line|
|
74
|
+
table_index = table_index + 1
|
75
|
+
# Skip the first two - table header
|
76
|
+
next if table_index < 3
|
77
|
+
|
78
|
+
line.gsub!(/ +\| +/, '|')
|
79
|
+
line.gsub!(/^ +/, '')
|
80
|
+
line.gsub!(/ +$/, '')
|
81
|
+
patch = line.split '|'
|
82
|
+
|
83
|
+
out.push(
|
84
|
+
:repository => patch[0],
|
85
|
+
:name => patch[1],
|
86
|
+
:version => patch[2],
|
87
|
+
:category => patch[3],
|
88
|
+
:status => patch[4]
|
89
|
+
)
|
90
|
+
}
|
91
|
+
|
92
|
+
out
|
93
|
+
end
|
94
|
+
|
95
|
+
# Filters patches according to given parameters
|
96
|
+
#
|
97
|
+
# @param (Array) patches
|
98
|
+
# @param (Hash) filters criteria, possible keys are :repository, :name, :version, :category and :status
|
99
|
+
#
|
100
|
+
# @example
|
101
|
+
# apply_patch_filters(patches, { :status => 'Needed' })
|
102
|
+
# apply_patch_filters(patches, { :version' => '1887', :repository => 'SLES11-SP1-Update' })
|
103
|
+
def apply_filters(patches = [], filters = {})
|
104
|
+
filters.each {|filter_key, filter_value|
|
105
|
+
raise "Unknown filter parameter '#{filter_key}'" unless FILTER_OPTIONS.include? filter_key
|
106
|
+
|
107
|
+
patches = patches.select{|patch| patch[filter_key] == filter_value}
|
108
|
+
}
|
109
|
+
patches
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'zypper/utils'
|
2
|
+
|
3
|
+
class Zypper
|
4
|
+
class Repository
|
5
|
+
include ZypperUtils
|
6
|
+
|
7
|
+
# Refreshes repositories
|
8
|
+
# @param (optional) options
|
9
|
+
# :force - to force the refresh
|
10
|
+
# :force_rebuild - forces rebuilding the libzypp database
|
11
|
+
def refresh(options = {})
|
12
|
+
run build_command('refresh', options)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Lists all known repositories
|
16
|
+
def all(options = {})
|
17
|
+
out = xml_run build_command('repos', options.merge(:get => XML_COMMANDS_GET))
|
18
|
+
out.fetch('repo-list', []).fetch(0, {}).fetch('repo', [])
|
19
|
+
end
|
20
|
+
|
21
|
+
# Adds a new repository defined by options
|
22
|
+
# (string) :url URL/URL
|
23
|
+
# (string) :alias
|
24
|
+
def add(options = {})
|
25
|
+
run build_command('addrepo', options)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Removes a repository defined by options
|
29
|
+
# (string) :alias
|
30
|
+
def remove(options = {})
|
31
|
+
run build_command('removerepo', options)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'zypper/utils'
|
2
|
+
|
3
|
+
class Zypper
|
4
|
+
class Service
|
5
|
+
include ZypperUtils
|
6
|
+
|
7
|
+
# Refreshes services
|
8
|
+
def refresh(options = {})
|
9
|
+
run build_command('refresh-services', options)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Lists all known services
|
13
|
+
def all(options = {})
|
14
|
+
out = xml_run build_command('services', options.merge(:get => XML_COMMANDS_GET))
|
15
|
+
out.fetch('service-list', []).fetch(0, {}).fetch('service', [])
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
data/lib/zypper/utils.rb
ADDED
@@ -0,0 +1,197 @@
|
|
1
|
+
module ZypperUtils
|
2
|
+
require 'rubygems'
|
3
|
+
require 'shellwords'
|
4
|
+
require 'popen4'
|
5
|
+
require 'xmlsimple'
|
6
|
+
|
7
|
+
require 'zypper/config'
|
8
|
+
|
9
|
+
XML_COMMANDS_GET = 'xml'
|
10
|
+
|
11
|
+
# Only getters are public
|
12
|
+
attr_reader :last_message, :last_error_message, :last_exit_status, :config
|
13
|
+
|
14
|
+
# Constructor
|
15
|
+
#
|
16
|
+
# @param either instance of Zypper::Config class
|
17
|
+
# or hash of options for new Zypper::Config class
|
18
|
+
#
|
19
|
+
# See Zypper::Config new() for more info
|
20
|
+
def initialize(params = {})
|
21
|
+
# Config is the given parameter
|
22
|
+
if (params.instance_of?(Zypper::Config))
|
23
|
+
self.config = params
|
24
|
+
# Called directly
|
25
|
+
elsif (params.is_a?(Hash))
|
26
|
+
self.config = Zypper::Config.new params
|
27
|
+
# Unknown call method
|
28
|
+
else
|
29
|
+
raise "Parameters #{params.inspect} is neither Zypper::Config nor Hash with options"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
# Setters are private
|
36
|
+
attr_writer :last_message, :last_error_message, :last_exit_status, :config
|
37
|
+
|
38
|
+
def check_mandatory_options_set(zypper_action, options, mandatory)
|
39
|
+
mandatory.each {|option|
|
40
|
+
raise "Missing '#{option}' parameter in '#{zypper_action}' action" if options[option].nil?
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
def check_mandatory_options(zypper_action, options)
|
45
|
+
case zypper_action
|
46
|
+
when 'addrepo'
|
47
|
+
check_mandatory_options_set(zypper_action, options, [:url, :alias])
|
48
|
+
# FIXME: check that :url or :alias do not contain any spaces (or special characters)
|
49
|
+
when 'removerepo'
|
50
|
+
check_mandatory_options_set(zypper_action, options, [:alias])
|
51
|
+
# FIXME: check that :url or :alias do not contain any spaces (or special characters)
|
52
|
+
when 'install'
|
53
|
+
# FIXME: check that :packages do not contain any spaces (or special characters)
|
54
|
+
check_mandatory_options_set(zypper_action, options, [:packages])
|
55
|
+
when 'remove'
|
56
|
+
# FIXME: check that :packages do not contain any spaces (or special characters)
|
57
|
+
check_mandatory_options_set(zypper_action, options, [:packages])
|
58
|
+
when 'info'
|
59
|
+
# FIXME: check that :package does not contain any spaces (or special characters)
|
60
|
+
check_mandatory_options_set(zypper_action, options, [:package])
|
61
|
+
# No checks:
|
62
|
+
# * 'search' used also just with command-line parameters but no particular
|
63
|
+
# object to search for
|
64
|
+
#
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def chrooted
|
69
|
+
config.chrooted? ? 'chroot ' + Shellwords::escape(config.root) + ' ' : ''
|
70
|
+
end
|
71
|
+
|
72
|
+
# Returns the full zypper command including chroot, zypper command, options, etc.
|
73
|
+
def build_command(zypper_action, options = {})
|
74
|
+
check_mandatory_options(zypper_action, options)
|
75
|
+
|
76
|
+
chrooted + ' zypper ' + global_options(options) + ' ' +
|
77
|
+
zypper_command(zypper_action) + ' ' + zypper_command_options(zypper_action, options)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Returns a zypper command (shell) defined by an action
|
81
|
+
def zypper_command zypper_action
|
82
|
+
case zypper_action
|
83
|
+
# version is a global option but not a command
|
84
|
+
when 'version'
|
85
|
+
''
|
86
|
+
else
|
87
|
+
zypper_action
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def escape_items(items = [])
|
92
|
+
items.collect{|package| Shellwords::escape(package)}.join(' ')
|
93
|
+
end
|
94
|
+
|
95
|
+
def escape(item = '')
|
96
|
+
Shellwords::escape(item)
|
97
|
+
end
|
98
|
+
|
99
|
+
# Returns string of command options depending on a given zypper command
|
100
|
+
# combined with provided options
|
101
|
+
def zypper_command_options(zypper_action, options = {})
|
102
|
+
ret_options = []
|
103
|
+
|
104
|
+
# Additional command-line options for a command
|
105
|
+
if options[:cmd_options]
|
106
|
+
ret_options = options[:cmd_options]
|
107
|
+
end
|
108
|
+
|
109
|
+
case zypper_action
|
110
|
+
when 'refresh'
|
111
|
+
ret_options = [
|
112
|
+
options[:force] ? '--force' : '',
|
113
|
+
options[:force_build] ? '--force-build' : '',
|
114
|
+
]
|
115
|
+
when 'addrepo'
|
116
|
+
ret_options = [
|
117
|
+
config.refresh_repo? ? '--refresh':'',
|
118
|
+
options[:url],
|
119
|
+
options[:alias],
|
120
|
+
]
|
121
|
+
when 'removerepo'
|
122
|
+
ret_options = [
|
123
|
+
options[:alias],
|
124
|
+
]
|
125
|
+
when 'install'
|
126
|
+
ret_options = [
|
127
|
+
config.auto_agree_with_licenses? ? '--auto-agree-with-licenses' : '',
|
128
|
+
escape_items(options[:packages]),
|
129
|
+
]
|
130
|
+
when 'remove'
|
131
|
+
ret_options = [
|
132
|
+
escape_items(options[:packages]),
|
133
|
+
]
|
134
|
+
when 'version'
|
135
|
+
ret_options = [
|
136
|
+
'--version',
|
137
|
+
]
|
138
|
+
when 'info'
|
139
|
+
ret_options = [
|
140
|
+
escape(options[:package]),
|
141
|
+
]
|
142
|
+
when 'search'
|
143
|
+
ret_options = [
|
144
|
+
options[:status] == Zypper::Package::Status::INSTALLED ? '--installed-only' : '',
|
145
|
+
options[:status] == Zypper::Package::Status::AVAILABLE ? '--uninstalled-only' : '',
|
146
|
+
|
147
|
+
options[:name] ? '--match-exact ' + escape(options[:name]) : '',
|
148
|
+
]
|
149
|
+
end
|
150
|
+
|
151
|
+
ret_options.join(' ')
|
152
|
+
end
|
153
|
+
|
154
|
+
# Returns string with global zypper options
|
155
|
+
def global_options(options = {})
|
156
|
+
[
|
157
|
+
(options[:quiet] ? '--quiet' : ''),
|
158
|
+
(config.changed_root? ? '--root=' + Shellwords::escape(config.root) : ''),
|
159
|
+
(options[:get] == XML_COMMANDS_GET ? '--xmlout' : ''),
|
160
|
+
'--non-interactive',
|
161
|
+
(config.auto_import_gpg? ? '--gpg-auto-import-keys' : ''),
|
162
|
+
].join(' ')
|
163
|
+
end
|
164
|
+
|
165
|
+
def xml_run(command)
|
166
|
+
xml = run(command, {:get => XML_COMMANDS_GET})
|
167
|
+
out = XmlSimple.xml_in(xml)
|
168
|
+
|
169
|
+
if !out["message"].nil?
|
170
|
+
errors = out["message"].select{|hash| hash["type"] == "error"}
|
171
|
+
self.last_error = errors.collect{|hash| hash["content"]}.join("\n")
|
172
|
+
end
|
173
|
+
|
174
|
+
out
|
175
|
+
end
|
176
|
+
|
177
|
+
# Runs a command given as argument and returns the full output
|
178
|
+
# Exit status can be acquired using last_exit_status call
|
179
|
+
def run(command, params = {})
|
180
|
+
# FIXME: it's here just for debugging
|
181
|
+
puts "DEBUG: " + command
|
182
|
+
|
183
|
+
cmd_ret = POpen4::popen4(command) do |stdout, stderr, stdin, pid|
|
184
|
+
self.last_message = stdout.read.strip
|
185
|
+
self.last_error_message = stderr.read.strip
|
186
|
+
end
|
187
|
+
|
188
|
+
last_exit_status = cmd_ret.exitstatus
|
189
|
+
|
190
|
+
if params[:get] == XML_COMMANDS_GET
|
191
|
+
last_message
|
192
|
+
else
|
193
|
+
last_exit_status == 0
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
metadata
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: zypper
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
- 0
|
10
|
+
version: 0.2.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Lukas Ocilka
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-06-26 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: popen4
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 3
|
29
|
+
segments:
|
30
|
+
- 0
|
31
|
+
version: "0"
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: xml-simple
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
hash: 3
|
43
|
+
segments:
|
44
|
+
- 0
|
45
|
+
version: "0"
|
46
|
+
type: :runtime
|
47
|
+
version_requirements: *id002
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: mocha
|
50
|
+
prerelease: false
|
51
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
hash: 3
|
57
|
+
segments:
|
58
|
+
- 0
|
59
|
+
version: "0"
|
60
|
+
type: :development
|
61
|
+
version_requirements: *id003
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rake
|
64
|
+
prerelease: false
|
65
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
hash: 3
|
71
|
+
segments:
|
72
|
+
- 0
|
73
|
+
version: "0"
|
74
|
+
type: :development
|
75
|
+
version_requirements: *id004
|
76
|
+
description: |-
|
77
|
+
Library for accessing zypper functions such as searching and
|
78
|
+
installing packages, adding and removing repositories and services. Supports
|
79
|
+
calling zypper in changed root (both with local zypper and zypper in chroot).
|
80
|
+
email: lukas.ocilka@gmail.com
|
81
|
+
executables: []
|
82
|
+
|
83
|
+
extensions: []
|
84
|
+
|
85
|
+
extra_rdoc_files: []
|
86
|
+
|
87
|
+
files:
|
88
|
+
- lib/zypper.rb
|
89
|
+
- lib/zypper/config.rb
|
90
|
+
- lib/zypper/repository.rb
|
91
|
+
- lib/zypper/utils.rb
|
92
|
+
- lib/zypper/package.rb
|
93
|
+
- lib/zypper/patch.rb
|
94
|
+
- lib/zypper/service.rb
|
95
|
+
- lib/zypper/version.rb
|
96
|
+
- LICENSE
|
97
|
+
- CHANGELOG
|
98
|
+
- README.markdown
|
99
|
+
- VERSION
|
100
|
+
homepage: https://github.com/kobliha/zypper
|
101
|
+
licenses:
|
102
|
+
- MIT
|
103
|
+
post_install_message:
|
104
|
+
rdoc_options: []
|
105
|
+
|
106
|
+
require_paths:
|
107
|
+
- lib
|
108
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
109
|
+
none: false
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
hash: 3
|
114
|
+
segments:
|
115
|
+
- 0
|
116
|
+
version: "0"
|
117
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
|
+
none: false
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
hash: 3
|
123
|
+
segments:
|
124
|
+
- 0
|
125
|
+
version: "0"
|
126
|
+
requirements: []
|
127
|
+
|
128
|
+
rubyforge_project:
|
129
|
+
rubygems_version: 1.8.15
|
130
|
+
signing_key:
|
131
|
+
specification_version: 3
|
132
|
+
summary: Library for accessing zypper
|
133
|
+
test_files: []
|
134
|
+
|
135
|
+
has_rdoc:
|