packo 0.0.1.alpha.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. data/bin/packo +78 -0
  2. data/bin/packo-base +24 -0
  3. data/bin/packo-build +24 -0
  4. data/bin/packo-db +24 -0
  5. data/bin/packo-env +24 -0
  6. data/bin/packo-files +24 -0
  7. data/bin/packo-profile +24 -0
  8. data/bin/packo-repository +24 -0
  9. data/bin/packo-select +24 -0
  10. data/lib/packo.rb +186 -0
  11. data/lib/packo/cli.rb +79 -0
  12. data/lib/packo/cli/base.rb +554 -0
  13. data/lib/packo/cli/build.rb +488 -0
  14. data/lib/packo/cli/database.rb +55 -0
  15. data/lib/packo/cli/database/definition.rb +65 -0
  16. data/lib/packo/cli/database/helpers.rb +20 -0
  17. data/lib/packo/cli/environment.rb +45 -0
  18. data/lib/packo/cli/files.rb +153 -0
  19. data/lib/packo/cli/profile.rb +31 -0
  20. data/lib/packo/cli/repository.rb +561 -0
  21. data/lib/packo/cli/repository/binary.rb +74 -0
  22. data/lib/packo/cli/repository/helpers.rb +20 -0
  23. data/lib/packo/cli/repository/repository.rb +48 -0
  24. data/lib/packo/cli/repository/source.rb +91 -0
  25. data/lib/packo/cli/repository/virtual.rb +53 -0
  26. data/lib/packo/cli/select.rb +61 -0
  27. data/lib/packo/do.rb +249 -0
  28. data/lib/packo/environment.rb +269 -0
  29. data/lib/packo/extensions.rb +70 -0
  30. data/lib/packo/flags.rb +64 -0
  31. data/lib/packo/host.rb +121 -0
  32. data/lib/packo/models.rb +171 -0
  33. data/lib/packo/models/installed_package.rb +190 -0
  34. data/lib/packo/models/installed_package/content.rb +50 -0
  35. data/lib/packo/models/installed_package/dependency.rb +39 -0
  36. data/lib/packo/models/repository.rb +209 -0
  37. data/lib/packo/models/repository/binary.rb +32 -0
  38. data/lib/packo/models/repository/binary/mirror.rb +35 -0
  39. data/lib/packo/models/repository/package.rb +73 -0
  40. data/lib/packo/models/repository/package/binary.rb +34 -0
  41. data/lib/packo/models/repository/package/binary/build.rb +36 -0
  42. data/lib/packo/models/repository/package/source.rb +36 -0
  43. data/lib/packo/models/repository/package/source/feature.rb +36 -0
  44. data/lib/packo/models/repository/package/source/flavor.rb +36 -0
  45. data/lib/packo/models/repository/package/virtual.rb +32 -0
  46. data/lib/packo/models/repository/source.rb +30 -0
  47. data/lib/packo/models/repository/virtual.rb +30 -0
  48. data/lib/packo/models/selector.rb +34 -0
  49. data/lib/packo/models/tag.rb +30 -0
  50. data/lib/packo/package.rb +239 -0
  51. data/lib/packo/package/blocker.rb +100 -0
  52. data/lib/packo/package/blockers.rb +40 -0
  53. data/lib/packo/package/dependencies.rb +40 -0
  54. data/lib/packo/package/dependency.rb +100 -0
  55. data/lib/packo/package/feature.rb +55 -0
  56. data/lib/packo/package/features.rb +105 -0
  57. data/lib/packo/package/flavor.rb +101 -0
  58. data/lib/packo/package/tags.rb +60 -0
  59. data/lib/packo/package/tags/expression.rb +130 -0
  60. data/lib/packo/package/tags/expression/group.rb +28 -0
  61. data/lib/packo/package/tags/expression/logic.rb +48 -0
  62. data/lib/packo/package/tags/expression/name.rb +28 -0
  63. data/lib/packo/profile.rb +174 -0
  64. data/lib/packo/rbuild.rb +22 -0
  65. data/lib/packo/rbuild/behaviors.rb +20 -0
  66. data/lib/packo/rbuild/behaviors/default.rb +27 -0
  67. data/lib/packo/rbuild/feature.rb +64 -0
  68. data/lib/packo/rbuild/features.rb +65 -0
  69. data/lib/packo/rbuild/flavor.rb +67 -0
  70. data/lib/packo/rbuild/module.rb +40 -0
  71. data/lib/packo/rbuild/modules.rb +27 -0
  72. data/lib/packo/rbuild/modules/building.rb +24 -0
  73. data/lib/packo/rbuild/modules/building/autotools.rb +315 -0
  74. data/lib/packo/rbuild/modules/building/cmake.rb +38 -0
  75. data/lib/packo/rbuild/modules/building/patch.rb +84 -0
  76. data/lib/packo/rbuild/modules/building/rake.rb +74 -0
  77. data/lib/packo/rbuild/modules/building/strip.rb +41 -0
  78. data/lib/packo/rbuild/modules/misc.rb +26 -0
  79. data/lib/packo/rbuild/modules/misc/fetcher.rb +177 -0
  80. data/lib/packo/rbuild/modules/misc/fetching.rb +22 -0
  81. data/lib/packo/rbuild/modules/misc/fetching/git.rb +57 -0
  82. data/lib/packo/rbuild/modules/misc/fetching/github.rb +31 -0
  83. data/lib/packo/rbuild/modules/misc/fetching/gnu.rb +59 -0
  84. data/lib/packo/rbuild/modules/misc/fetching/mercurial.rb +51 -0
  85. data/lib/packo/rbuild/modules/misc/fetching/sourceforge.rb +47 -0
  86. data/lib/packo/rbuild/modules/misc/fetching/subversion.rb +51 -0
  87. data/lib/packo/rbuild/modules/misc/fetching/wget.rb +57 -0
  88. data/lib/packo/rbuild/modules/misc/unpacker.rb +70 -0
  89. data/lib/packo/rbuild/modules/misc/unpacking.rb +23 -0
  90. data/lib/packo/rbuild/modules/misc/unpacking/lzma.rb +34 -0
  91. data/lib/packo/rbuild/modules/misc/unpacking/tar.rb +35 -0
  92. data/lib/packo/rbuild/modules/misc/unpacking/xz.rb +34 -0
  93. data/lib/packo/rbuild/modules/misc/unpacking/zip.rb +26 -0
  94. data/lib/packo/rbuild/modules/packaging.rb +20 -0
  95. data/lib/packo/rbuild/modules/packaging/pko.rb +78 -0
  96. data/lib/packo/rbuild/package.rb +281 -0
  97. data/lib/packo/rbuild/package/manifest.rb +169 -0
  98. data/lib/packo/rbuild/stages.rb +171 -0
  99. data/lib/packo/rbuild/stages/callbacks.rb +96 -0
  100. data/lib/packo/rbuild/stages/stage.rb +50 -0
  101. data/lib/packo/repository.rb +95 -0
  102. data/lib/packo/repository/binary.rb +116 -0
  103. data/lib/packo/repository/source.rb +77 -0
  104. data/lib/packo/repository/virtual.rb +66 -0
  105. data/lib/packo/system.rb +53 -0
  106. data/lib/packo/version.rb +26 -0
  107. metadata +276 -0
data/lib/packo/cli.rb ADDED
@@ -0,0 +1,79 @@
1
+ #--
2
+ # Copyleft meh. [http://meh.doesntexist.org | meh@paranoici.org]
3
+ #
4
+ # This file is part of packo.
5
+ #
6
+ # packo is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU Affero General Public License as published
8
+ # by the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # packo is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Affero General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Affero General Public License
17
+ # along with packo. If not, see <http://www.gnu.org/licenses/>.
18
+ #++
19
+
20
+ require 'thor'
21
+ require 'colorb'
22
+
23
+ class Thor
24
+ class << self
25
+ def help(shell, subcommand = false)
26
+ list = printable_tasks(true, subcommand)
27
+ Thor::Util.thor_classes_in(self).each do |klass|
28
+ list += klass.printable_tasks(false)
29
+ end
30
+
31
+ shell.say 'Commands:'
32
+ shell.print_table(list, ident: 2, truncate: true)
33
+ shell.say
34
+ class_options_help(shell)
35
+ end
36
+ end
37
+
38
+ module Base
39
+ module ClassMethods
40
+ def handle_no_task_error(task) #:nodoc:
41
+ if $thor_runner
42
+ raise UndefinedTaskError, "Could not find command #{task.inspect} in #{namespace.inspect} namespace."
43
+ else
44
+ raise UndefinedTaskError, "Could not find command #{task.inspect}."
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ module Packo
52
+
53
+ module CLI
54
+ def self.info (text)
55
+ puts "#{'*'.green.bold} #{text}"
56
+ end
57
+
58
+ def self.warn (text)
59
+ puts "#{'*'.yellow.bold} #{text}"
60
+ end
61
+
62
+ def self.fatal (text)
63
+ puts "#{'*'.red} #{text}"
64
+ end
65
+ end
66
+
67
+ end
68
+
69
+ ['INT', 'QUIT', 'ABRT', 'TERM', 'TSTP'].each {|sig|
70
+ trap sig do
71
+ if defined?(Packo::Models)
72
+ Packo::Models.transactions.each {|t| t.rollback}
73
+ end
74
+
75
+ puts 'Aborting.'
76
+
77
+ Process.exit! 0
78
+ end
79
+ }
@@ -0,0 +1,554 @@
1
+ # encoding: utf-8
2
+ #--
3
+ # Copyleft meh. [http://meh.doesntexist.org | meh@paranoici.org]
4
+ #
5
+ # This file is part of packo.
6
+ #
7
+ # packo is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Affero General Public License as published
9
+ # by the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # packo 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 Affero General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Affero General Public License
18
+ # along with packo. If not, see <http://www.gnu.org/licenses/>.
19
+ #++
20
+
21
+ require 'packo'
22
+ require 'packo/models'
23
+ require 'packo/rbuild'
24
+
25
+ module Packo; module CLI
26
+
27
+ class Base < Thor
28
+ include Thor::Actions
29
+
30
+ class_option :help, type: :boolean, desc: 'Show help usage'
31
+
32
+ desc 'install PACKAGE... [OPTIONS]', 'Install packages'
33
+ map '-i' => :install, '--install' => :install
34
+ method_option :destination, type: :string, default: System.env[:INSTALL_PATH], aliases: '-d', desc: 'Set the destination where to install the package'
35
+ method_option :inherit, type: :boolean, default: false, aliases: '-I', desc: 'Apply the passed flags to the eventual dependencies'
36
+ method_option :force, type: :boolean, default: false, aliases: '-f', desc: 'Force installation when something minor goes wrong'
37
+ method_option :ignore, type: :boolean, default: false, aliases: '-x', desc: 'Ignore the installation and do not add the package to the database'
38
+ method_option :nodeps, type: :boolean, default: false, aliases: '-N', desc: 'Ignore blockers and dependencies'
39
+ method_option :depsonly, type: :boolean, default: false, aliases: '-D', desc: 'Install only dependencies'
40
+ method_option :repository, type: :string, aliases: '-r', desc: 'Set a specific repository'
41
+ def install (*names)
42
+ type = names.last.is_a?(Symbol) ? names.pop : :both
43
+
44
+ FileUtils.mkpath options[:destination] rescue nil
45
+ FileUtils.mkpath System.env[:SELECTORS] rescue nil
46
+
47
+ binary = false
48
+
49
+ if names.last === true
50
+ manual = names.shift ? 0 : 1
51
+ else
52
+ manual = 1
53
+ end
54
+
55
+ names.each {|name|
56
+ CLI.info "Installing #{name}"
57
+
58
+ if File.extname(name).empty?
59
+ packages = nil
60
+
61
+ if System.env[:FLAVOR].include?('binary')
62
+ packages = Models.search(name, options[:repository], :binary)
63
+
64
+ if packages.empty?
65
+ CLI.warn "#{name} could not be found in the binary repositories, looking in source repositories"
66
+ packages = nil
67
+ else
68
+ binary = true
69
+ end
70
+ end
71
+
72
+ begin
73
+ if !packages
74
+ packages = Models.search(name, options[:repository], :source)
75
+
76
+ binary = false
77
+ end
78
+
79
+ names = packages.group_by {|package|
80
+ "#{package.tags}/#{package.name}"
81
+ }.map {|(name, package)| name}.uniq
82
+
83
+ if names.length > 1
84
+ CLI.fatal "More than one package matches: #{name}"
85
+ names.each {|name|
86
+ puts " #{name}"
87
+ }
88
+
89
+ exit 10
90
+ end
91
+
92
+ package = packages.sort {|a, b|
93
+ a.version <=> b.version
94
+ }.last
95
+
96
+ if !package
97
+ CLI.fatal "#{name} not found"
98
+ exit 11
99
+ end
100
+
101
+ env = Environment.new(package)
102
+
103
+ if package.repository.type == :binary && !_has(package, env)
104
+ CLI.warn 'The binary package is not available with the features you asked for, trying to build from source'
105
+ packages = nil
106
+ raise ArgumentError
107
+ end
108
+ rescue ArgumentError
109
+ retry
110
+ end
111
+
112
+ case package.repository.type
113
+ when :binary
114
+ name = "#{package.tags.to_s(true)}/#{package.name}-#{package.version}"
115
+
116
+ flavor = ''
117
+ env[:FLAVOR].split(/\s+/).reject {|f| f == 'binary'}.each {|f|
118
+ flavor << ".#{f}"
119
+ }
120
+ flavor[0, 1] = ''
121
+
122
+ features = ''
123
+ env[:FEATURES].split(/\s+/).each {|f|
124
+ features << "-#{f}"
125
+ }
126
+ features[0, 1] = ''
127
+
128
+ name << "%#{package.slot}"
129
+ name << "+#{flavor}"
130
+ name << "-#{features}"
131
+ name << ".pko"
132
+
133
+ FileUtils.mkpath(File.dirname("#{env[:TMP]}/#{name}")) rescue nil
134
+
135
+ begin
136
+ Packo.sh 'wget', '-c', '-O', "#{env[:TMP]}/#{name}", "#{_uri(package.repository)}/#{name}"
137
+ rescue RuntimeError
138
+ FileUtils.rm "#{env[:TMP]}/#{name}"
139
+ CLI.fatal "Failed to download #{name}"
140
+ exit 12
141
+ end
142
+
143
+ name = "#{env[:TMP]}/#{name}"
144
+
145
+ if (digest = _digest(package, env)) && (result = Do.digest(name)) != digest
146
+ CLI.fatal "Digest mismatch (got #{result} expected #{digest}), install this package from source, the mirror could be compromised"
147
+ exit 13
148
+ end
149
+
150
+ path = "#{env[:TMP]}/.__packo_unpacked/#{name[env[:TMP].length, name.length]}"
151
+
152
+ when :source
153
+ manifest = RBuild::Package::Manifest.parse(_manifest(package, env))
154
+
155
+ unless options[:nodeps] || System.env[:NODEPS]
156
+ manifest.blockers {|blocker|
157
+ if blocker.build? && System.has?(blocker)
158
+ CLI.fatal "#{blocker} can't be installed with #{package}"
159
+ exit 16
160
+ end
161
+ }
162
+
163
+ manifest.dependencies.each {|dependency|
164
+ if dependency.build? && !System.has?(dependency)
165
+ install(dependency.to_s, dependency.type)
166
+ end
167
+ }
168
+ end
169
+
170
+ if options[:depsonly]
171
+ exit 0
172
+ end
173
+
174
+ name = _build(package, env)
175
+
176
+ if !name
177
+ CLI.fatal "Something went wrong while trying to build #{package.to_s(:whole)}"
178
+ exit 14
179
+ end
180
+
181
+ path = "#{env[:TMP]}/.__packo_unpacked/#{package.tags.to_s(true)}/#{name[env[:TMP].length + '.__packo_build/'.length, name.length]}"
182
+ end
183
+ else
184
+ path = "#{System.env[:TMP]}/.__packo_unpacked/#{File.basename(name)}"
185
+ end
186
+
187
+ FileUtils.rm_rf path, secure: true
188
+
189
+ case File.extname(name)
190
+ when '.pko'
191
+ RBuild::Modules::Packaging::PKO.unpack(File.realpath(name), path)
192
+
193
+ manifest = RBuild::Package::Manifest.open("#{path}/manifest.xml")
194
+
195
+ else
196
+ CLI.fatal 'Unknown package type'
197
+ exit 15
198
+ end
199
+
200
+ package = Packo::Package.new(manifest.package.to_hash)
201
+
202
+ if !options[:inherit]
203
+ Environment[:FLAVOR] = Environment[:FEATURES] = ''
204
+ end
205
+
206
+ unless options[:nodeps] || System.env[:NODEPS]
207
+ manifest.blockers {|blocker|
208
+ if blocker.runtime? && System.has?(blocker)
209
+ CLI.fatal "#{blocker} can't be installed with #{package}"
210
+ exit 16
211
+ end
212
+ }
213
+
214
+ manifest.dependencies.each {|dependency|
215
+ if !System.has?(dependency) && dependency.runtime?
216
+ install(dependency.to_s, dependency.type)
217
+ end
218
+ }
219
+ end
220
+
221
+ if options[:depsonly]
222
+ exit 0
223
+ end
224
+
225
+ if System.has?(package)
226
+ uninstall(package.to_s(:whole)) rescue nil
227
+ end
228
+
229
+ manifest.selectors.each {|selector|
230
+ FileUtils.mkpath System.env[:SELECTORS]
231
+ FileUtils.cp_r "#{path}/selectors/#{selector.path}", System.env[:SELECTORS], preserve: true, remove_destination: true
232
+ Packo.sh 'packo-select', 'add', selector.name, selector.description, "#{System.env[:SELECTORS]}/#{selector.path}", silent: true
233
+ }
234
+
235
+ Models.transaction {|t|
236
+ pkg = Models::InstalledPackage.first_or_new(
237
+ tags_hashed: manifest.package.tags.hashed,
238
+ name: manifest.package.name,
239
+ slot: manifest.package.slot
240
+ )
241
+
242
+ pkg.attributes = {
243
+ repo: options[:repository],
244
+
245
+ version: manifest.package.version,
246
+ revision: manifest.package.revision,
247
+
248
+ flavor: manifest.package.flavor,
249
+ features: manifest.package.features,
250
+
251
+ description: manifest.package.description,
252
+ homepage: manifest.package.homepage,
253
+ license: manifest.package.license,
254
+
255
+ manual: manual,
256
+ type: type
257
+ }
258
+
259
+ pkg.save
260
+
261
+ manifest.package.tags.each {|tag|
262
+ pkg.tags.first_or_create(name: tag.to_s)
263
+ }
264
+
265
+ length = "#{path}/dist/".length
266
+ old = path
267
+
268
+ begin
269
+ Find.find("#{path}/dist") {|file|
270
+ next unless file[length, file.length]
271
+
272
+ type = nil
273
+ path = (options[:destination] + file[length, file.length]).cleanpath.to_s
274
+ fake = path[options[:destination].cleanpath.to_s.length, path.length] || ''
275
+ meta = nil
276
+
277
+ if !options[:force] && File.exists?(path) && !File.directory?(path)
278
+ if (tmp = _exists?(fake))
279
+ CLI.fatal "#{path} belongs to #{tmp}, use --force to overwrite"
280
+ else
281
+ CLI.fatal "#{path} doesn't belong to any package, use --force to overwrite"
282
+ end
283
+
284
+ raise RuntimeError.new 'File collision'
285
+ end
286
+
287
+ if File.directory?(file)
288
+ type = :dir
289
+
290
+ begin
291
+ FileUtils.mkpath(path)
292
+ puts "--- #{path if path != '/'}/"
293
+ rescue
294
+ puts "--- #{path if path != '/'}/".red
295
+ end
296
+ elsif File.symlink?(file)
297
+ type = :sym
298
+ meta = File.readlink(file)
299
+
300
+ begin
301
+ FileUtils.ln_sf meta, path
302
+ puts ">>> #{path} -> #{meta}".cyan.bold
303
+ rescue
304
+ puts ">>> #{path} -> #{meta}".red
305
+ end
306
+ elsif File.file?(file)
307
+ type = :obj
308
+ meta = Do.digest(file)
309
+
310
+ begin
311
+ FileUtils.cp file, path, preserve: true
312
+ puts ">>> #{path}".bold
313
+ rescue
314
+ puts ">>> #{path}".red
315
+ end
316
+ else
317
+ next
318
+ end
319
+
320
+ content = pkg.contents.first_or_create(
321
+ type: type,
322
+ path: fake
323
+ )
324
+
325
+ content.update(
326
+ meta: meta
327
+ )
328
+ }
329
+
330
+ pkg.save
331
+ rescue Exception => e
332
+ CLI.fatal 'Something went deeply wrong while installing package contents'
333
+ Packo.debug e
334
+
335
+ pkg.contents.each {|content| content.check!
336
+ path = "#{installed.model.destination}/#{content.path}".gsub(%r{/*/}, '/')
337
+
338
+ case content.type
339
+ when :obj
340
+ if File.exists?(path) && (options[:force] || content.meta == Do.digest(path))
341
+ puts "<<< #{path}".bold
342
+ FileUtils.rm_f(path) rescue nil
343
+ else
344
+ puts "=== #{path}".red
345
+ end
346
+
347
+ when :sym
348
+ if File.exists?(path) && (options[:force] || !File.exists?(path) || content.meta == File.readlink(path))
349
+ puts "<<< #{path} -> #{content.meta}".cyan.bold
350
+ FileUtils.rm_f(path) rescue nil
351
+ else
352
+ puts "=== #{path} -> #{File.readlink(path)}".red
353
+ end
354
+
355
+ when :dir
356
+ puts "--- #{path if path != '/'}/"
357
+ end
358
+ }
359
+
360
+ pkg.contents.all(type: :dir, order: [:path.desc]).each {|content|
361
+ path = "#{options[:destination]}/#{content.path}".gsub(%r{/*/}, '/')
362
+
363
+ Dir.delete(path) rescue nil
364
+ }
365
+
366
+ t.rollback
367
+
368
+ exit 17
369
+ end
370
+
371
+ if options[:ignore]
372
+ t.rollback
373
+ else
374
+ pkg.update(destination: options[:destination].cleanpath)
375
+ end
376
+ }
377
+ }
378
+ end
379
+
380
+ desc 'uninstall PACKAGE... [OPTIONS]', 'Uninstall packages'
381
+ map '-C' => :uninstall, '-R' => :uninstall, 'remove' => :uninstall
382
+ method_option :force, type: :boolean, default: false, aliases: '-f', desc: 'Force installation when something minor goes wrong'
383
+ def uninstall (*names)
384
+ names.each {|name|
385
+ packages = Models.search_installed(name)
386
+
387
+ if packages.empty?
388
+ CLI.fatal "No installed packages match #{name}"
389
+ exit 20
390
+ end
391
+
392
+ packages.each {|installed|
393
+ Models.transaction {
394
+ installed.model.contents.each {|content| content.check!
395
+ path = "#{installed.model.destination}/#{content.path}".gsub(%r{/*/}, '/')
396
+
397
+ case content.type
398
+ when :obj
399
+ if File.exists?(path) && (options[:force] || content.meta == Do.digest(path))
400
+ puts "<<< #{path}".bold
401
+ FileUtils.rm_f(path) rescue nil
402
+ else
403
+ puts "=== #{path}".red
404
+ end
405
+
406
+ when :sym
407
+ if File.exists?(path) && (options[:force] || !File.exists?(path) || content.meta == File.readlink(path))
408
+ puts "<<< #{path} -> #{content.meta}".cyan.bold
409
+ FileUtils.rm_f(path) rescue nil
410
+ else
411
+ puts "=== #{path} -> #{File.readlink(path)}".red
412
+ end
413
+
414
+ when :dir
415
+ puts "--- #{path if path != '/'}/"
416
+ end
417
+ }
418
+
419
+ installed.model.contents.all(type: :dir, order: [:path.desc]).each {|content|
420
+ path = "#{options[:destination]}/#{content.path}".gsub(%r{/*/}, '/')
421
+
422
+ Dir.delete(path) rescue nil
423
+ }
424
+
425
+ installed.model.destroy
426
+ }
427
+ }
428
+ }
429
+ end
430
+
431
+ desc 'search [EXPRESSION] [OPTIONS]', 'Search through installed packages'
432
+ map '--search' => :search, '-Ss' => :search
433
+ method_option :type, type: :string, aliases: '-t', desc: 'The repository type (binary, source, virtual)'
434
+ method_option :repository, type: :string, aliases: '-r', desc: 'Set a specific repository'
435
+ method_option :full, type: :boolean, default: false, aliases: '-F', desc: 'Include the repository that owns the package, features and flavor'
436
+ def search (expression='')
437
+ Models.search_installed(expression, options[:repository], options[:type]).group_by {|package|
438
+ "#{package.tags}/#{package.name}"
439
+ }.sort.each {|(name, packages)|
440
+ if options[:full]
441
+ packages.group_by {|package|
442
+ "#{package.repository.type}/#{package.repository.name}" rescue nil
443
+ }.each {|name, packages|
444
+ packages.group_by {|package|
445
+ "#{package.features} #{package.flavor}"
446
+ }.each {|name, packages|
447
+ print "#{"#{packages.first.tags}/" unless packages.first.tags.empty?}#{packages.first.name.bold}"
448
+
449
+ print ' ('
450
+ print packages.map {|package|
451
+ "#{package.version.to_s.red}" + (package.slot ? "%#{package.slot.to_s.blue.bold}" : '')
452
+ }.join(', ')
453
+ print ')'
454
+
455
+ print " [#{packages.first.features}]" unless packages.first.features.empty?
456
+ print " {#{packages.first.flavor}}" unless packages.first.flavor.empty?
457
+
458
+ print " <#{"#{packages.first.repository.type}/#{packages.first.repository.name}".black.bold}>" if packages.first.repository
459
+ }
460
+ }
461
+ else
462
+ print "#{packages.first.tags}/#{packages.first.name.bold} ("
463
+
464
+ print packages.map {|package|
465
+ "#{package.version.to_s.red}" + (package.slot ? "%#{package.slot.to_s.blue.bold}" : '')
466
+ }.join(', ')
467
+
468
+ print ")"
469
+ end
470
+
471
+ print "\n"
472
+ }
473
+ end
474
+
475
+ desc 'info [EXPRESSION] [OPTIONS]', 'Search through installed packages and returns detailed informations about them'
476
+ map '--info' => :info
477
+ method_option :type, type: :string, aliases: '-t', desc: 'The repository type (binary, source, virtual)'
478
+ method_option :repository, type: :string, aliases: '-r', desc: 'Set a specific repository'
479
+ def info (expression='')
480
+ Models.search_installed(expression, options[:repository], options[:type]).each {|package|
481
+ print package.name.bold
482
+ print "-#{package.version.to_s.red}"
483
+ print " {#{package.revision.yellow.bold}}" if package.revision > 0
484
+ print " (#{package.slot.to_s.blue.bold})" if package.slot
485
+ print " [#{package.tags.join(' ').magenta}]" if !package.tags.empty?
486
+ print "\n"
487
+
488
+ puts " #{'Description'.green}: #{package.description}" if package.description
489
+ puts " #{'Homepage'.green}: #{package.homepage}" if package.homepage
490
+ puts " #{'License'.green}: #{package.license}" if package.license
491
+ puts " #{'Maintainer'.green}: #{package.model.maintainer}" if package.maintainer
492
+ puts " #{'Flavor'.green}: #{package.flavor}" if package.flavor
493
+ puts " #{'Features'.green}: #{package.features}" if package.features
494
+
495
+ print "\n"
496
+ }
497
+ end
498
+
499
+ private
500
+
501
+ def _uri (repository)
502
+ Repository.first(Packo::Repository.parse(name).to_hash).URI rescue nil
503
+ end
504
+
505
+ def _build (package, env)
506
+ Do.cd {
507
+ FileUtils.rm_rf "#{System.env[:TMP]}/.__packo_build", secure: true rescue nil
508
+ FileUtils.mkpath "#{System.env[:TMP]}/.__packo_build" rescue nil
509
+
510
+ require 'packo/cli/build'
511
+
512
+ begin
513
+ System.env.sandbox(env) {
514
+ Packo::CLI::Build.start(['package', package.to_s(:whole), "--output=#{System.env[:TMP]}/.__packo_build", "--repository=#{package.repository}"])
515
+ }
516
+ rescue
517
+ end
518
+
519
+ Dir.glob("#{System.env[:TMP]}/.__packo_build/#{package.name}-#{package.version}*.pko").first
520
+ }
521
+ end
522
+
523
+ def _manifest (package, env)
524
+ tmp = Models.search(package.to_s, options[:repository])
525
+
526
+ RBuild::Package::Manifest.new(
527
+ Packo.loadPackage("#{tmp.last.repository.path}/#{tmp.last.model.data.path}", tmp.last)
528
+ ).to_s
529
+ end
530
+
531
+ def _has (package, env)
532
+ !!Models.search(package.to_s(:whole), package.repository.name, package.repository.type).find {|package|
533
+ !!package.model.data.builds.to_a.find {|build|
534
+ build.features.split(/\s+/).sort == env[:FEATURES].split(/\s+/).sort && \
535
+ build.flavor.split(/\s+/).sort == env[:FLAVOR].split(/\s+/).sort
536
+ }
537
+ }
538
+ end
539
+
540
+ def _digest (package, env)
541
+ Models.search(package, package.repository.name, :binary).find {|package|
542
+ package.model.data.builds.to_a.find {|build|
543
+ build.features.split(/\s+/).sort == env[:FEATURES].split(/\s+/).sort && \
544
+ build.flavor.split(/\s+/).sort == env[:FLAVOR].split(/\s+/).sort
545
+ }
546
+ }.model.data.digest
547
+ end
548
+
549
+ def _exists? (path)
550
+ Models::InstalledPackage::Content.first(path: path, :type.not => :dir).package rescue false
551
+ end
552
+ end
553
+
554
+ end; end