packo 0.0.1.alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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